summaryrefslogtreecommitdiffstats
path: root/deluge/plugins/Scheduler/deluge_scheduler/gtkui.py
diff options
context:
space:
mode:
Diffstat (limited to 'deluge/plugins/Scheduler/deluge_scheduler/gtkui.py')
-rw-r--r--deluge/plugins/Scheduler/deluge_scheduler/gtkui.py356
1 files changed, 356 insertions, 0 deletions
diff --git a/deluge/plugins/Scheduler/deluge_scheduler/gtkui.py b/deluge/plugins/Scheduler/deluge_scheduler/gtkui.py
new file mode 100644
index 0000000..16222c8
--- /dev/null
+++ b/deluge/plugins/Scheduler/deluge_scheduler/gtkui.py
@@ -0,0 +1,356 @@
+#
+# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
+#
+# Basic plugin template created by:
+# Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com>
+# Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com>
+#
+# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
+# the additional special exception to link portions of this program with the OpenSSL library.
+# See LICENSE for more details.
+#
+
+import logging
+
+from gi.repository import Gdk, Gtk
+
+import deluge.component as component
+from deluge.plugins.pluginbase import Gtk3PluginBase
+from deluge.ui.client import client
+
+from .common import get_resource
+
+log = logging.getLogger(__name__)
+
+DAYS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
+
+
+class SchedulerSelectWidget(Gtk.DrawingArea):
+ def __init__(self, hover):
+ super().__init__()
+ self.set_events(
+ Gdk.EventMask.BUTTON_PRESS_MASK
+ | Gdk.EventMask.BUTTON_RELEASE_MASK
+ | Gdk.EventMask.POINTER_MOTION_MASK
+ | Gdk.EventMask.LEAVE_NOTIFY_MASK
+ )
+
+ self.connect('draw', self.draw)
+ self.connect('button_press_event', self.mouse_down)
+ self.connect('button_release_event', self.mouse_up)
+ self.connect('motion_notify_event', self.mouse_hover)
+ self.connect('leave_notify_event', self.mouse_leave)
+
+ self.colors = [
+ [115 / 255, 210 / 255, 22 / 255],
+ [237 / 255, 212 / 255, 0 / 255],
+ [204 / 255, 0 / 255, 0 / 255],
+ ]
+ self.button_state = [[0] * 7 for dummy in range(24)]
+
+ self.start_point = [0, 0]
+ self.hover_point = [-1, -1]
+ self.hover_label = hover
+ self.hover_days = DAYS
+ self.mouse_press = False
+ self.set_size_request(350, 150)
+
+ def set_button_state(self, state):
+ self.button_state = []
+ for s in state:
+ self.button_state.append(list(s))
+ log.debug(self.button_state)
+
+ # redraw the whole thing
+ def draw(self, widget, context):
+ width = widget.get_allocated_width()
+ height = widget.get_allocated_height()
+ context.rectangle(0, 0, width, height)
+ context.clip()
+
+ for y in range(7):
+ for x in range(24):
+ context.set_source_rgba(
+ self.colors[self.button_state[x][y]][0],
+ self.colors[self.button_state[x][y]][1],
+ self.colors[self.button_state[x][y]][2],
+ 0.5,
+ )
+ context.rectangle(
+ width * (6 * x / 145 + 1 / 145),
+ height * (6 * y / 43 + 1 / 43),
+ 6 * width / 145,
+ 5 * height / 43,
+ )
+ context.fill_preserve()
+ context.set_source_rgba(0, 0, 0, 0.7)
+ context.set_line_width(1)
+ context.stroke()
+
+ # coordinates --> which box
+ def get_point(self, event):
+ width = self.get_allocated_width()
+ height = self.get_allocated_height()
+ x = int((event.x - width * 0.5 / 145) / (6 * width / 145))
+ y = int((event.y - height * 0.5 / 43) / (6 * height / 43))
+
+ if x > 23:
+ x = 23
+ elif x < 0:
+ x = 0
+ if y > 6:
+ y = 6
+ elif y < 0:
+ y = 0
+
+ return [x, y]
+
+ # mouse down
+ def mouse_down(self, widget, event):
+ self.mouse_press = True
+ self.start_point = self.get_point(event)
+
+ # if the same box -> change it
+ def mouse_up(self, widget, event):
+ self.mouse_press = False
+ end_point = self.get_point(event)
+
+ # change color on mouseclick depending on the button
+ if end_point[0] is self.start_point[0] and end_point[1] is self.start_point[1]:
+ if event.button == 1:
+ self.button_state[end_point[0]][end_point[1]] += 1
+ if self.button_state[end_point[0]][end_point[1]] > 2:
+ self.button_state[end_point[0]][end_point[1]] = 0
+ elif event.button == 3:
+ self.button_state[end_point[0]][end_point[1]] -= 1
+ if self.button_state[end_point[0]][end_point[1]] < 0:
+ self.button_state[end_point[0]][end_point[1]] = 2
+ self.queue_draw()
+
+ # if box changed and mouse is pressed draw all boxes from start point to end point
+ # set hover text etc..
+ def mouse_hover(self, widget, event):
+ if self.get_point(event) != self.hover_point:
+ self.hover_point = self.get_point(event)
+
+ self.hover_label.set_text(
+ self.hover_days[self.hover_point[1]]
+ + ' '
+ + str(self.hover_point[0])
+ + ':00 - '
+ + str(self.hover_point[0])
+ + ':59'
+ )
+
+ if self.mouse_press:
+ points = [
+ [self.hover_point[0], self.start_point[0]],
+ [self.hover_point[1], self.start_point[1]],
+ ]
+
+ for x in range(min(points[0]), max(points[0]) + 1):
+ for y in range(min(points[1]), max(points[1]) + 1):
+ self.button_state[x][y] = self.button_state[
+ self.start_point[0]
+ ][self.start_point[1]]
+
+ self.queue_draw()
+
+ # clear hover text on mouse leave
+ def mouse_leave(self, widget, event):
+ self.hover_label.set_text('')
+ self.hover_point = [-1, -1]
+
+
+class GtkUI(Gtk3PluginBase):
+ def enable(self):
+ self.create_prefs_page()
+
+ component.get('PluginManager').register_hook(
+ 'on_apply_prefs', self.on_apply_prefs
+ )
+ component.get('PluginManager').register_hook(
+ 'on_show_prefs', self.on_show_prefs
+ )
+ self.statusbar = component.get('StatusBar')
+ self.status_item = self.statusbar.add_item(
+ image=get_resource('green.svg'),
+ text='',
+ callback=self.on_status_item_clicked,
+ tooltip='Scheduler',
+ )
+
+ def on_state_deferred(state):
+ self.state = state
+ self.on_scheduler_event(state)
+
+ self.on_show_prefs()
+
+ client.scheduler.get_state().addCallback(on_state_deferred)
+ client.register_event_handler('SchedulerEvent', self.on_scheduler_event)
+
+ def disable(self):
+ component.get('Preferences').remove_page(_('Scheduler'))
+ # Reset statusbar dict.
+ self.statusbar.config_value_changed_dict[
+ 'max_download_speed'
+ ] = self.statusbar._on_max_download_speed
+ self.statusbar.config_value_changed_dict[
+ 'max_upload_speed'
+ ] = self.statusbar._on_max_upload_speed
+ # Remove statusbar item.
+ self.statusbar.remove_item(self.status_item)
+ del self.status_item
+
+ component.get('PluginManager').deregister_hook(
+ 'on_apply_prefs', self.on_apply_prefs
+ )
+ component.get('PluginManager').deregister_hook(
+ 'on_show_prefs', self.on_show_prefs
+ )
+
+ def on_apply_prefs(self):
+ log.debug('applying prefs for Scheduler')
+ config = {}
+ config['low_down'] = self.spin_download.get_value()
+ config['low_up'] = self.spin_upload.get_value()
+ config['low_active'] = self.spin_active.get_value_as_int()
+ config['low_active_down'] = self.spin_active_down.get_value_as_int()
+ config['low_active_up'] = self.spin_active_up.get_value_as_int()
+ config['button_state'] = self.scheduler_select.button_state
+ client.scheduler.set_config(config)
+
+ def on_show_prefs(self):
+ def on_get_config(config):
+ log.debug('config: %s', config)
+ self.scheduler_select.set_button_state(config['button_state'])
+ self.spin_download.set_value(config['low_down'])
+ self.spin_upload.set_value(config['low_up'])
+ self.spin_active.set_value(config['low_active'])
+ self.spin_active_down.set_value(config['low_active_down'])
+ self.spin_active_up.set_value(config['low_active_up'])
+
+ client.scheduler.get_config().addCallback(on_get_config)
+
+ def on_scheduler_event(self, state):
+ self.state = state
+ self.status_item.set_image_from_file(get_resource(self.state.lower() + '.svg'))
+ if self.state == 'Yellow':
+ # Prevent func calls in Statusbar if the config changes.
+ self.statusbar.config_value_changed_dict.pop('max_download_speed', None)
+ self.statusbar.config_value_changed_dict.pop('max_upload_speed', None)
+ try:
+ self.statusbar._on_max_download_speed(self.spin_download.get_value())
+ self.statusbar._on_max_upload_speed(self.spin_upload.get_value())
+ except AttributeError:
+ # Skip error due to Plugin being enabled before statusbar items created on startup.
+ pass
+ else:
+ self.statusbar.config_value_changed_dict[
+ 'max_download_speed'
+ ] = self.statusbar._on_max_download_speed
+ self.statusbar.config_value_changed_dict[
+ 'max_upload_speed'
+ ] = self.statusbar._on_max_upload_speed
+
+ def update_config_values(config):
+ try:
+ self.statusbar._on_max_download_speed(config['max_download_speed'])
+ self.statusbar._on_max_upload_speed(config['max_upload_speed'])
+ except AttributeError:
+ # Skip error due to Plugin being enabled before statusbar items created on startup.
+ pass
+
+ client.core.get_config_values(
+ ['max_download_speed', 'max_upload_speed']
+ ).addCallback(update_config_values)
+
+ def on_status_item_clicked(self, widget, event):
+ component.get('Preferences').show('Scheduler')
+
+ # Configuration dialog
+ def create_prefs_page(self):
+ # Select Widget
+ hover = Gtk.Label()
+ self.scheduler_select = SchedulerSelectWidget(hover)
+
+ vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, spacing=5)
+ hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, spacing=5)
+ vbox_days = Gtk.Box.new(Gtk.Orientation.VERTICAL, spacing=0)
+ for day in DAYS:
+ vbox_days.pack_start(Gtk.Label(day, xalign=0), True, False, 0)
+ hbox.pack_start(vbox_days, False, False, 15)
+ hbox.pack_start(self.scheduler_select, True, True, 0)
+ frame = Gtk.Frame()
+ label = Gtk.Label()
+ label.set_markup(_('<b>Schedule</b>'))
+ frame.set_label_widget(label)
+ frame.set_shadow_type(Gtk.ShadowType.NONE)
+ frame.set_margin_left(15)
+ frame.add(hbox)
+
+ vbox.pack_start(frame, False, False, 0)
+ vbox.pack_start(hover, False, False, 0)
+
+ table = Gtk.Table(5, 2)
+ table.set_margin_left(15)
+
+ label = Gtk.Label(_('Download Limit:'))
+ label.set_alignment(0.0, 0.6)
+ table.attach_defaults(label, 0, 1, 0, 1)
+ self.spin_download = Gtk.SpinButton()
+ self.spin_download.set_numeric(True)
+ self.spin_download.set_range(-1.0, 99999.0)
+ self.spin_download.set_increments(1, 10)
+ table.attach_defaults(self.spin_download, 1, 2, 0, 1)
+
+ label = Gtk.Label(_('Upload Limit:'))
+ label.set_alignment(0.0, 0.6)
+ table.attach_defaults(label, 0, 1, 1, 2)
+ self.spin_upload = Gtk.SpinButton()
+ self.spin_upload.set_numeric(True)
+ self.spin_upload.set_range(-1.0, 99999.0)
+ self.spin_upload.set_increments(1, 10)
+ table.attach_defaults(self.spin_upload, 1, 2, 1, 2)
+
+ label = Gtk.Label(_('Active Torrents:'))
+ label.set_alignment(0.0, 0.6)
+ table.attach_defaults(label, 0, 1, 2, 3)
+ self.spin_active = Gtk.SpinButton()
+ self.spin_active.set_numeric(True)
+ self.spin_active.set_range(-1, 9999)
+ self.spin_active.set_increments(1, 10)
+ table.attach_defaults(self.spin_active, 1, 2, 2, 3)
+
+ label = Gtk.Label(_('Active Downloading:'))
+ label.set_alignment(0.0, 0.6)
+ table.attach_defaults(label, 0, 1, 3, 4)
+ self.spin_active_down = Gtk.SpinButton()
+ self.spin_active_down.set_numeric(True)
+ self.spin_active_down.set_range(-1, 9999)
+ self.spin_active_down.set_increments(1, 10)
+ table.attach_defaults(self.spin_active_down, 1, 2, 3, 4)
+
+ label = Gtk.Label(_('Active Seeding:'))
+ label.set_alignment(0.0, 0.6)
+ table.attach_defaults(label, 0, 1, 4, 5)
+ self.spin_active_up = Gtk.SpinButton()
+ self.spin_active_up.set_numeric(True)
+ self.spin_active_up.set_range(-1, 9999)
+ self.spin_active_up.set_increments(1, 10)
+ table.attach_defaults(self.spin_active_up, 1, 2, 4, 5)
+
+ eventbox = Gtk.EventBox()
+ eventbox.add(table)
+ frame = Gtk.Frame()
+ label = Gtk.Label()
+ label.set_markup(_('<b>Slow Settings</b>'))
+ label.modify_bg(Gtk.StateFlags.NORMAL, Gdk.color_parse('#EDD400'))
+ frame.set_label_widget(label)
+ frame.set_margin_left(15)
+ frame.set_border_width(2)
+ frame.add(eventbox)
+ vbox.pack_start(frame, False, False, 0)
+
+ vbox.show_all()
+ component.get('Preferences').add_page(_('Scheduler'), vbox)