Exemplo n.º 1
0
class TorrentviewTestCase(unittest.TestCase):

    def setUp(self):  # NOQA
        pass

    def tearDown(self):  # NOQA
        pass

    def test_torrentview_columns(self):
        self.mainwindow = MainWindow()
        self.torrentview = TorrentView()
        self.torrentdetails = TorrentDetails()
        self.menubar = MenuBar()

        default_column_index = ['filter', 'torrent_id', 'dirty', '#', 'Name', 'Size', 'Downloaded', 'Uploaded', 'Progress', 'Seeders', 'Peers', 'Seeders/Peers', 'Down Speed', 'Up Speed', 'Down Limit', 'Up Limit', 'ETA', 'Ratio', 'Avail', 'Added', 'Tracker', 'Save Path']
        default_liststore_columns = [bool, str, bool, int, str, str, gobject.TYPE_UINT64, gobject.TYPE_UINT64, gobject.TYPE_UINT64, float, str, int, int, int, int, float, float, float, float, float, int, float, float, float, str, str, str]

        self.assertEquals(self.torrentview.column_index, default_column_index)
        self.assertEquals(self.torrentview.liststore_columns, default_liststore_columns)

        self.assertEquals(self.torrentview.columns["Save Path"].column_indices, [26])

        # Add a text column
        test_col = "Test column"
        self.torrentview.add_text_column(test_col, status_field=["label"])
        self.assertEquals(len(self.torrentview.liststore_columns), 28)
        self.assertEquals(len(self.torrentview.column_index), 23)
        self.assertEquals(self.torrentview.column_index[-1], test_col)
        self.assertEquals(self.torrentview.columns[test_col].column_indices, [27])

        # Add a second text column
        test_col2 = "Test column2"
        self.torrentview.add_text_column(test_col2, status_field=["label2"])
        self.assertEquals(len(self.torrentview.liststore_columns), 29)
        self.assertEquals(len(self.torrentview.column_index), 24)
        self.assertEquals(self.torrentview.column_index[-1], test_col2)
        self.assertEquals(self.torrentview.columns[test_col2].column_indices, [28])

        # Remove column
        self.torrentview.remove_column(test_col)
        self.assertEquals(len(self.torrentview.liststore_columns), 28)
        self.assertEquals(len(self.torrentview.column_index), 23)
        self.assertEquals(self.torrentview.column_index[-1], test_col2)
        self.assertEquals(self.torrentview.columns[test_col2].column_indices, [27])

        # Add a column with multiple column types
        test_col3 = "Test column3"
        self.torrentview.add_progress_column(test_col3, status_field=["progress", "label3"], col_types=[float, str])
        self.assertEquals(len(self.torrentview.liststore_columns), 30)
        self.assertEquals(len(self.torrentview.column_index), 24)
        self.assertEquals(self.torrentview.column_index[-1], test_col3)
        self.assertEquals(self.torrentview.columns[test_col3].column_indices, [28, 29])

        # Remove multiple column-types column
        self.torrentview.remove_column(test_col3)
        self.assertEquals(len(self.torrentview.liststore_columns), 28)
        self.assertEquals(len(self.torrentview.column_index), 23)
        self.assertEquals(self.torrentview.column_index[-1], test_col2)
        self.assertEquals(self.torrentview.columns[test_col2].column_indices, [27])
Exemplo n.º 2
0
    def set_up(self):
        if libs_available is False:
            raise unittest.SkipTest('GTKUI dependencies not available')

        common.set_tmp_config_dir()
        # MainWindow loads this config file, so lets make sure it contains the defaults
        ConfigManager('gtkui.conf', defaults=DEFAULT_PREFS)
        self.mainwindow = MainWindow()
        self.torrentview = TorrentView()
        self.torrentdetails = TorrentDetails()
        self.menubar = MenuBar()
Exemplo n.º 3
0
    def test_write(self):
        """
        writing to a file-like object; need this for webui.

        Not strictly a unit test, but tests if calls do not fail...
        """
        from deluge.ui.gtkui.gtkui import DEFAULT_PREFS
        from deluge.ui.gtkui.preferences import Preferences
        from deluge.ui.gtkui.mainwindow import MainWindow
        from deluge.configmanager import ConfigManager
        from deluge.ui.gtkui.pluginmanager import PluginManager
        from deluge.ui.gtkui.torrentdetails import TorrentDetails
        from deluge.ui.gtkui.torrentview import TorrentView
        from deluge.plugins.Stats.deluge.plugins.stats import graph, gtkui

        ConfigManager('gtkui.conf', defaults=DEFAULT_PREFS)

        self.plugins = PluginManager()
        MainWindow()
        TorrentView()
        TorrentDetails()
        Preferences()

        class FakeFile(object):
            def __init__(self):
                self.data = []

            def write(self, data):
                self.data.append(data)

        stats_gtkui = gtkui.GtkUI('test_stats')
        stats_gtkui.enable()
        yield stats_gtkui.graphs_tab.update()

        g = stats_gtkui.graphs_tab.graph
        g.add_stat('download_rate', color=graph.green)
        g.add_stat('upload_rate', color=graph.blue)
        g.set_left_axis(formatter=fspeed, min=10240)

        surface = g.draw(900, 150)
        file_like = FakeFile()
        surface.write_to_png(file_like)
        data = b''.join(file_like.data)
        with open('file_like.png', 'wb') as _file:
            _file.write(data)
Exemplo n.º 4
0
class TorrentviewTestCase(BaseTestCase):

    default_column_index = ['filter', 'torrent_id', 'dirty', '#',
                            'Name',
                            'Size', 'Downloaded', 'Uploaded', 'Remaining',
                            'Progress',
                            'Seeds', 'Peers', 'Seeds:Peers',
                            'Down Speed', 'Up Speed', 'Down Limit', 'Up Limit',
                            'ETA', 'Ratio', 'Avail',
                            'Added', 'Completed', 'Complete Seen',
                            'Tracker', 'Download Folder', 'Owner', 'Shared']
    default_liststore_columns = [bool, str, bool, int,
                                 str, str,  # Name
                                 TYPE_UINT64, TYPE_UINT64, TYPE_UINT64, TYPE_UINT64,
                                 float, str,  # Progress
                                 int, int, int, int, float,  # Seeds, Peers
                                 int, int, float, float,
                                 int, float, float,  # ETA, Ratio, Avail
                                 int, int, int,
                                 str, str,  # Tracker
                                 str, str,
                                 bool]  # shared

    def set_up(self):
        if libs_available is False:
            raise unittest.SkipTest('GTKUI dependencies not available')

        common.set_tmp_config_dir()
        # MainWindow loads this config file, so lets make sure it contains the defaults
        ConfigManager('gtkui.conf', defaults=DEFAULT_PREFS)
        self.mainwindow = MainWindow()
        self.torrentview = TorrentView()
        self.torrentdetails = TorrentDetails()
        self.menubar = MenuBar()

    def tear_down(self):
        return component.shutdown()

    def test_torrentview_columns(self):

        self.assertEqual(self.torrentview.column_index, TorrentviewTestCase.default_column_index)
        self.assertEqual(self.torrentview.liststore_columns, TorrentviewTestCase.default_liststore_columns)
        self.assertEqual(self.torrentview.columns['Download Folder'].column_indices, [29])

    def test_add_column(self):

        # Add a text column
        test_col = 'Test column'
        self.torrentview.add_text_column(test_col, status_field=['label'])
        self.assertEqual(len(self.torrentview.liststore_columns),
                         len(TorrentviewTestCase.default_liststore_columns) + 1)
        self.assertEqual(len(self.torrentview.column_index),
                         len(TorrentviewTestCase.default_column_index) + 1)
        self.assertEqual(self.torrentview.column_index[-1], test_col)
        self.assertEqual(self.torrentview.columns[test_col].column_indices, [32])

    def test_add_columns(self):

        # Add a text column
        test_col = 'Test column'
        self.torrentview.add_text_column(test_col, status_field=['label'])

        # Add a second text column
        test_col2 = 'Test column2'
        self.torrentview.add_text_column(test_col2, status_field=['label2'])

        self.assertEqual(len(self.torrentview.liststore_columns),
                         len(TorrentviewTestCase.default_liststore_columns) + 2)
        self.assertEqual(len(self.torrentview.column_index),
                         len(TorrentviewTestCase.default_column_index) + 2)
        # test_col
        self.assertEqual(self.torrentview.column_index[-2], test_col)
        self.assertEqual(self.torrentview.columns[test_col].column_indices, [32])

        # test_col2
        self.assertEqual(self.torrentview.column_index[-1], test_col2)
        self.assertEqual(self.torrentview.columns[test_col2].column_indices, [33])

    def test_remove_column(self):

        # Add and remove text column
        test_col = 'Test column'
        self.torrentview.add_text_column(test_col, status_field=['label'])
        self.torrentview.remove_column(test_col)

        self.assertEqual(len(self.torrentview.liststore_columns), len(TorrentviewTestCase.default_liststore_columns))
        self.assertEqual(len(self.torrentview.column_index), len(TorrentviewTestCase.default_column_index))
        self.assertEqual(self.torrentview.column_index[-1], TorrentviewTestCase.default_column_index[-1])
        self.assertEqual(self.torrentview.columns[TorrentviewTestCase.default_column_index[-1]].column_indices, [31])

    def test_remove_columns(self):

        # Add two columns
        test_col = 'Test column'
        self.torrentview.add_text_column(test_col, status_field=['label'])
        test_col2 = 'Test column2'
        self.torrentview.add_text_column(test_col2, status_field=['label2'])

        # Remove test_col
        self.torrentview.remove_column(test_col)
        self.assertEqual(len(self.torrentview.liststore_columns),
                         len(TorrentviewTestCase.default_liststore_columns) + 1)
        self.assertEqual(len(self.torrentview.column_index),
                         len(TorrentviewTestCase.default_column_index) + 1)
        self.assertEqual(self.torrentview.column_index[-1], test_col2)
        self.assertEqual(self.torrentview.columns[test_col2].column_indices, [32])

        # Remove test_col2
        self.torrentview.remove_column(test_col2)
        self.assertEqual(len(self.torrentview.liststore_columns), len(TorrentviewTestCase.default_liststore_columns))
        self.assertEqual(len(self.torrentview.column_index), len(TorrentviewTestCase.default_column_index))
        self.assertEqual(self.torrentview.column_index[-1], TorrentviewTestCase.default_column_index[-1])
        self.assertEqual(self.torrentview.columns[TorrentviewTestCase.default_column_index[-1]].column_indices, [31])

    def test_add_remove_column_multiple_types(self):

        # Add a column with multiple column types
        test_col3 = 'Test column3'
        self.torrentview.add_progress_column(test_col3, status_field=['progress', 'label3'], col_types=[float, str])
        self.assertEqual(len(self.torrentview.liststore_columns),
                         len(TorrentviewTestCase.default_liststore_columns) + 2)
        self.assertEqual(len(self.torrentview.column_index),
                         len(TorrentviewTestCase.default_column_index) + 1)
        self.assertEqual(self.torrentview.column_index[-1], test_col3)
        self.assertEqual(self.torrentview.columns[test_col3].column_indices, [32, 33])

        # Remove multiple column-types column
        self.torrentview.remove_column(test_col3)

        self.assertEqual(len(self.torrentview.liststore_columns), len(TorrentviewTestCase.default_liststore_columns))
        self.assertEqual(len(self.torrentview.column_index), len(TorrentviewTestCase.default_column_index))
        self.assertEqual(self.torrentview.column_index[-1], TorrentviewTestCase.default_column_index[-1])
        self.assertEqual(self.torrentview.columns[TorrentviewTestCase.default_column_index[-1]].column_indices, [31])
Exemplo n.º 5
0
    def test_torrentview_columns(self):
        self.mainwindow = MainWindow()
        self.torrentview = TorrentView()
        self.torrentdetails = TorrentDetails()
        self.menubar = MenuBar()

        default_column_index = [
            'filter', 'torrent_id', 'dirty', '#', 'Name', 'Size', 'Downloaded',
            'Uploaded', 'Progress', 'Seeders', 'Peers', 'Seeders/Peers',
            'Down Speed', 'Up Speed', 'Down Limit', 'Up Limit', 'ETA', 'Ratio',
            'Avail', 'Added', 'Tracker', 'Save Path'
        ]
        default_liststore_columns = [
            bool, str, bool, int, str, str, gobject.TYPE_UINT64,
            gobject.TYPE_UINT64, gobject.TYPE_UINT64, float, str, int, int,
            int, int, float, float, float, float, float, int, float, float,
            float, str, str, str
        ]

        self.assertEquals(self.torrentview.column_index, default_column_index)
        self.assertEquals(self.torrentview.liststore_columns,
                          default_liststore_columns)

        self.assertEquals(self.torrentview.columns["Save Path"].column_indices,
                          [26])

        # Add a text column
        test_col = "Test column"
        self.torrentview.add_text_column(test_col, status_field=["label"])
        self.assertEquals(len(self.torrentview.liststore_columns), 28)
        self.assertEquals(len(self.torrentview.column_index), 23)
        self.assertEquals(self.torrentview.column_index[-1], test_col)
        self.assertEquals(self.torrentview.columns[test_col].column_indices,
                          [27])

        # Add a second text column
        test_col2 = "Test column2"
        self.torrentview.add_text_column(test_col2, status_field=["label2"])
        self.assertEquals(len(self.torrentview.liststore_columns), 29)
        self.assertEquals(len(self.torrentview.column_index), 24)
        self.assertEquals(self.torrentview.column_index[-1], test_col2)
        self.assertEquals(self.torrentview.columns[test_col2].column_indices,
                          [28])

        # Remove column
        self.torrentview.remove_column(test_col)
        self.assertEquals(len(self.torrentview.liststore_columns), 28)
        self.assertEquals(len(self.torrentview.column_index), 23)
        self.assertEquals(self.torrentview.column_index[-1], test_col2)
        self.assertEquals(self.torrentview.columns[test_col2].column_indices,
                          [27])

        # Add a column with multiple column types
        test_col3 = "Test column3"
        self.torrentview.add_progress_column(
            test_col3,
            status_field=["progress", "label3"],
            col_types=[float, str])
        self.assertEquals(len(self.torrentview.liststore_columns), 30)
        self.assertEquals(len(self.torrentview.column_index), 24)
        self.assertEquals(self.torrentview.column_index[-1], test_col3)
        self.assertEquals(self.torrentview.columns[test_col3].column_indices,
                          [28, 29])

        # Remove multiple column-types column
        self.torrentview.remove_column(test_col3)
        self.assertEquals(len(self.torrentview.liststore_columns), 28)
        self.assertEquals(len(self.torrentview.column_index), 23)
        self.assertEquals(self.torrentview.column_index[-1], test_col2)
        self.assertEquals(self.torrentview.columns[test_col2].column_indices,
                          [27])
Exemplo n.º 6
0
    def __init__(self, args):
        # Setup gtkbuilder/glade translation
        setup_translations(setup_gettext=False, setup_pygtk=True)

        # Setup signals
        def on_die(*args):
            log.debug('OS signal "die" caught with args: %s', args)
            reactor.stop()

        if windows_check():
            from win32api import SetConsoleCtrlHandler
            SetConsoleCtrlHandler(on_die, True)
            log.debug('Win32 "die" handler registered')
        elif osx_check() and WINDOWING == 'quartz':
            import gtkosx_application
            self.osxapp = gtkosx_application.gtkosx_application_get()
            self.osxapp.connect('NSApplicationWillTerminate', on_die)
            log.debug('OSX quartz "die" handler registered')

        # Set process name again to fix gtk issue
        setproctitle(getproctitle())

        # Attempt to register a magnet URI handler with gconf, but do not overwrite
        # if already set by another program.
        associate_magnet_links(False)

        # Make sure gtkui.conf has at least the defaults set
        self.config = ConfigManager('gtkui.conf', DEFAULT_PREFS)

        # Make sure the gtkui state folder has been created
        if not os.path.exists(os.path.join(get_config_dir(), 'gtkui_state')):
            os.makedirs(os.path.join(get_config_dir(), 'gtkui_state'))

        # Set language
        if self.config['language'] is not None:
            set_language(self.config['language'])

        # Start the IPC Interface before anything else.. Just in case we are
        # already running.
        self.queuedtorrents = QueuedTorrents()
        self.ipcinterface = IPCInterface(args.torrents)

        # Initialize gdk threading
        threads_init()

        # We make sure that the UI components start once we get a core URI
        client.set_disconnect_callback(self.__on_disconnect)

        self.trackericons = TrackerIcons()
        self.sessionproxy = SessionProxy()
        # Initialize various components of the gtkui
        self.mainwindow = MainWindow()
        self.menubar = MenuBar()
        self.toolbar = ToolBar()
        self.torrentview = TorrentView()
        self.torrentdetails = TorrentDetails()
        self.sidebar = SideBar()
        self.filtertreeview = FilterTreeView()
        self.preferences = Preferences()
        self.systemtray = SystemTray()
        self.statusbar = StatusBar()
        self.addtorrentdialog = AddTorrentDialog()

        if osx_check() and WINDOWING == 'quartz':
            def nsapp_open_file(osxapp, filename):
                # Ignore command name which is raised at app launch (python opening main script).
                if filename == sys.argv[0]:
                    return True
                process_args([filename])
            self.osxapp.connect('NSApplicationOpenFile', nsapp_open_file)
            from deluge.ui.gtkui.menubar_osx import menubar_osx
            menubar_osx(self, self.osxapp)
            self.osxapp.ready()

        # Initalize the plugins
        self.plugins = PluginManager()

        # Show the connection manager
        self.connectionmanager = ConnectionManager()

        # Setup RPC stats logging
        # daemon_bps: time, bytes_sent, bytes_recv
        self.daemon_bps = (0, 0, 0)
        self.rpc_stats = LoopingCall(self.log_rpc_stats)
        self.closing = False

        # Twisted catches signals to terminate, so have it call a pre_shutdown method.
        reactor.addSystemEventTrigger('before', 'gtkui_close', self.close)

        def gtkui_sigint_handler(num, frame):
            log.debug('SIGINT signal caught, firing event: gtkui_close')
            reactor.callLater(0, reactor.fireSystemEvent, 'gtkui_close')

        signal.signal(signal.SIGINT, gtkui_sigint_handler)
Exemplo n.º 7
0
class GtkUI(object):
    def __init__(self, args):
        # Setup gtkbuilder/glade translation
        setup_translations(setup_gettext=False, setup_pygtk=True)

        # Setup signals
        def on_die(*args):
            log.debug('OS signal "die" caught with args: %s', args)
            reactor.stop()

        if windows_check():
            from win32api import SetConsoleCtrlHandler
            SetConsoleCtrlHandler(on_die, True)
            log.debug('Win32 "die" handler registered')
        elif osx_check() and WINDOWING == 'quartz':
            import gtkosx_application
            self.osxapp = gtkosx_application.gtkosx_application_get()
            self.osxapp.connect('NSApplicationWillTerminate', on_die)
            log.debug('OSX quartz "die" handler registered')

        # Set process name again to fix gtk issue
        setproctitle(getproctitle())

        # Attempt to register a magnet URI handler with gconf, but do not overwrite
        # if already set by another program.
        associate_magnet_links(False)

        # Make sure gtkui.conf has at least the defaults set
        self.config = ConfigManager('gtkui.conf', DEFAULT_PREFS)

        # Make sure the gtkui state folder has been created
        if not os.path.exists(os.path.join(get_config_dir(), 'gtkui_state')):
            os.makedirs(os.path.join(get_config_dir(), 'gtkui_state'))

        # Set language
        if self.config['language'] is not None:
            set_language(self.config['language'])

        # Start the IPC Interface before anything else.. Just in case we are
        # already running.
        self.queuedtorrents = QueuedTorrents()
        self.ipcinterface = IPCInterface(args.torrents)

        # Initialize gdk threading
        threads_init()

        # We make sure that the UI components start once we get a core URI
        client.set_disconnect_callback(self.__on_disconnect)

        self.trackericons = TrackerIcons()
        self.sessionproxy = SessionProxy()
        # Initialize various components of the gtkui
        self.mainwindow = MainWindow()
        self.menubar = MenuBar()
        self.toolbar = ToolBar()
        self.torrentview = TorrentView()
        self.torrentdetails = TorrentDetails()
        self.sidebar = SideBar()
        self.filtertreeview = FilterTreeView()
        self.preferences = Preferences()
        self.systemtray = SystemTray()
        self.statusbar = StatusBar()
        self.addtorrentdialog = AddTorrentDialog()

        if osx_check() and WINDOWING == 'quartz':
            def nsapp_open_file(osxapp, filename):
                # Ignore command name which is raised at app launch (python opening main script).
                if filename == sys.argv[0]:
                    return True
                process_args([filename])
            self.osxapp.connect('NSApplicationOpenFile', nsapp_open_file)
            from deluge.ui.gtkui.menubar_osx import menubar_osx
            menubar_osx(self, self.osxapp)
            self.osxapp.ready()

        # Initalize the plugins
        self.plugins = PluginManager()

        # Show the connection manager
        self.connectionmanager = ConnectionManager()

        # Setup RPC stats logging
        # daemon_bps: time, bytes_sent, bytes_recv
        self.daemon_bps = (0, 0, 0)
        self.rpc_stats = LoopingCall(self.log_rpc_stats)
        self.closing = False

        # Twisted catches signals to terminate, so have it call a pre_shutdown method.
        reactor.addSystemEventTrigger('before', 'gtkui_close', self.close)

        def gtkui_sigint_handler(num, frame):
            log.debug('SIGINT signal caught, firing event: gtkui_close')
            reactor.callLater(0, reactor.fireSystemEvent, 'gtkui_close')

        signal.signal(signal.SIGINT, gtkui_sigint_handler)

    def start(self):
        reactor.callWhenRunning(self._on_reactor_start)

        # Initialize gdk threading
        threads_enter()
        reactor.run()
        # Reactor no longer running so async callbacks (Deferreds) cannot be
        # processed after this point.
        threads_leave()

    def shutdown(self, *args, **kwargs):
        log.debug('GTKUI shutting down...')
        # Shutdown all components
        if client.is_standalone:
            return component.shutdown()

    @defer.inlineCallbacks
    def close(self):
        if self.closing:
            return
        self.closing = True
        # Make sure the config is saved.
        self.config.save()
        # Ensure columns state is saved
        self.torrentview.save_state()
        # Shut down components
        yield self.shutdown()

        # The gtk modal dialogs (e.g. Preferences) can prevent the application
        # quitting, so force exiting by destroying MainWindow. Must be done here
        # to avoid hanging when quitting with SIGINT (CTRL-C).
        self.mainwindow.window.destroy()

        reactor.stop()

        # Restart the application after closing if MainWindow restart attribute set.
        if component.get('MainWindow').restart:
            os.execv(sys.argv[0], sys.argv)

    def log_rpc_stats(self):
        """Log RPC statistics for thinclient mode."""
        if not client.connected():
            return

        t = time.time()
        recv = client.get_bytes_recv()
        sent = client.get_bytes_sent()
        delta_time = t - self.daemon_bps[0]
        delta_sent = sent - self.daemon_bps[1]
        delta_recv = recv - self.daemon_bps[2]
        self.daemon_bps = (t, sent, recv)
        sent_rate = fspeed(delta_sent / delta_time)
        recv_rate = fspeed(delta_recv / delta_time)
        log.debug('RPC: Sent %s (%s) Recv %s (%s)', fsize(sent), sent_rate, fsize(recv), recv_rate)

    def _on_reactor_start(self):
        log.debug('_on_reactor_start')
        self.mainwindow.first_show()

        if not self.config['standalone']:
            return self._start_thinclient()

        err_msg = ''
        try:
            client.start_standalone()
        except DaemonRunningError:
            err_msg = _('A Deluge daemon (deluged) is already running.\n'
                        'To use Standalone mode, stop local daemon and restart Deluge.')
        except ImportError as ex:
            if 'No module named libtorrent' in ex.message:
                err_msg = _('Only Thin Client mode is available because libtorrent is not installed.\n'
                            'To use Standalone mode, please install libtorrent package.')
            else:
                log.exception(ex)
                err_msg = _('Only Thin Client mode is available due to unknown Import Error.\n'
                            'To use Standalone mode, please see logs for error details.')
        except Exception as ex:
            log.exception(ex)
            err_msg = _('Only Thin Client mode is available due to unknown Import Error.\n'
                        'To use Standalone mode, please see logs for error details.')
        else:
            component.start()
            return

        def on_dialog_response(response):
            """User response to switching mode dialog."""
            if response == RESPONSE_YES:
                # Turning off standalone
                self.config['standalone'] = False
                self._start_thinclient()
            else:
                # User want keep Standalone Mode so just quit.
                self.mainwindow.quit()

        # An error occurred so ask user to switch from Standalone to Thin Client mode.
        err_msg += '\n\n' + _('Continue in Thin Client mode?')
        d = YesNoDialog(_('Change User Interface Mode'), err_msg).run()
        d.addCallback(on_dialog_response)

    def _start_thinclient(self):
        """Start the gtkui in thinclient mode"""
        if log.isEnabledFor(logging.DEBUG):
            self.rpc_stats.start(10)

        # Check to see if we need to start the localhost daemon
        if self.config['autostart_localhost']:
            def on_localhost_status(status_info, port):
                if status_info[1] == 'Offline':
                    log.debug('Autostarting localhost: %s', host_config[0:3])
                    self.connectionmanager.start_daemon(port, get_config_dir())

            for host_config in self.connectionmanager.hostlist.config['hosts']:
                if host_config[1] in LOCALHOST:
                    d = self.connectionmanager.hostlist.get_host_status(host_config[0])
                    d.addCallback(on_localhost_status, host_config[2])
                    break

        # Autoconnect to a host
        if self.config['autoconnect']:
            for host_config in self.connectionmanager.hostlist.config['hosts']:
                host_id, host, port, user, __ = host_config
                if host_id == self.config['autoconnect_host_id']:
                    log.debug('Trying to connect to %s@%s:%s', user, host, port)
                    self.connectionmanager._connect(host_id, try_counter=6)
                    break

        if self.config['show_connection_manager_on_start']:
            # Dialog is blocking so call last.
            self.connectionmanager.show()

    def __on_disconnect(self):
        """
        Called when disconnected from the daemon.  We basically just stop all
        the components here.
        """
        self.daemon_bps = (0, 0, 0)
        component.stop()
Exemplo n.º 8
0
    def __init__(self, args):
        # Setup gtkbuilder/glade translation
        setup_translations(setup_gettext=False, setup_pygtk=True)

        # Setup signals
        def on_die(*args):
            log.debug('OS signal "die" caught with args: %s', args)
            reactor.stop()

        if windows_check():
            from win32api import SetConsoleCtrlHandler

            SetConsoleCtrlHandler(on_die, True)
            log.debug('Win32 "die" handler registered')
        elif osx_check() and WINDOWING == 'quartz':
            import gtkosx_application

            self.osxapp = gtkosx_application.gtkosx_application_get()
            self.osxapp.connect('NSApplicationWillTerminate', on_die)
            log.debug('OSX quartz "die" handler registered')

        # Set process name again to fix gtk issue
        setproctitle(getproctitle())

        # Attempt to register a magnet URI handler with gconf, but do not overwrite
        # if already set by another program.
        associate_magnet_links(False)

        # Make sure gtkui.conf has at least the defaults set
        self.config = ConfigManager('gtkui.conf', DEFAULT_PREFS)

        # Make sure the gtkui state folder has been created
        if not os.path.exists(os.path.join(get_config_dir(), 'gtkui_state')):
            os.makedirs(os.path.join(get_config_dir(), 'gtkui_state'))

        # Set language
        if self.config['language'] is not None:
            set_language(self.config['language'])

        # Start the IPC Interface before anything else.. Just in case we are
        # already running.
        self.queuedtorrents = QueuedTorrents()
        self.ipcinterface = IPCInterface(args.torrents)

        # Initialize gdk threading
        threads_init()

        # We make sure that the UI components start once we get a core URI
        client.set_disconnect_callback(self.__on_disconnect)

        self.trackericons = TrackerIcons()
        self.sessionproxy = SessionProxy()
        # Initialize various components of the gtkui
        self.mainwindow = MainWindow()
        self.menubar = MenuBar()
        self.toolbar = ToolBar()
        self.torrentview = TorrentView()
        self.torrentdetails = TorrentDetails()
        self.sidebar = SideBar()
        self.filtertreeview = FilterTreeView()
        self.preferences = Preferences()
        self.systemtray = SystemTray()
        self.statusbar = StatusBar()
        self.addtorrentdialog = AddTorrentDialog()

        if osx_check() and WINDOWING == 'quartz':

            def nsapp_open_file(osxapp, filename):
                # Ignore command name which is raised at app launch (python opening main script).
                if filename == sys.argv[0]:
                    return True
                process_args([filename])

            self.osxapp.connect('NSApplicationOpenFile', nsapp_open_file)
            from deluge.ui.gtkui.menubar_osx import menubar_osx

            menubar_osx(self, self.osxapp)
            self.osxapp.ready()

        # Initalize the plugins
        self.plugins = PluginManager()

        # Show the connection manager
        self.connectionmanager = ConnectionManager()

        # Setup RPC stats logging
        # daemon_bps: time, bytes_sent, bytes_recv
        self.daemon_bps = (0, 0, 0)
        self.rpc_stats = LoopingCall(self.log_rpc_stats)
        self.closing = False

        # Twisted catches signals to terminate, so have it call a pre_shutdown method.
        reactor.addSystemEventTrigger('before', 'gtkui_close', self.close)

        def gtkui_sigint_handler(num, frame):
            log.debug('SIGINT signal caught, firing event: gtkui_close')
            reactor.callLater(0, reactor.fireSystemEvent, 'gtkui_close')

        signal.signal(signal.SIGINT, gtkui_sigint_handler)
Exemplo n.º 9
0
class GtkUI(object):
    def __init__(self, args):
        # Setup gtkbuilder/glade translation
        setup_translations(setup_gettext=False, setup_pygtk=True)

        # Setup signals
        def on_die(*args):
            log.debug('OS signal "die" caught with args: %s', args)
            reactor.stop()

        if windows_check():
            from win32api import SetConsoleCtrlHandler

            SetConsoleCtrlHandler(on_die, True)
            log.debug('Win32 "die" handler registered')
        elif osx_check() and WINDOWING == 'quartz':
            import gtkosx_application

            self.osxapp = gtkosx_application.gtkosx_application_get()
            self.osxapp.connect('NSApplicationWillTerminate', on_die)
            log.debug('OSX quartz "die" handler registered')

        # Set process name again to fix gtk issue
        setproctitle(getproctitle())

        # Attempt to register a magnet URI handler with gconf, but do not overwrite
        # if already set by another program.
        associate_magnet_links(False)

        # Make sure gtkui.conf has at least the defaults set
        self.config = ConfigManager('gtkui.conf', DEFAULT_PREFS)

        # Make sure the gtkui state folder has been created
        if not os.path.exists(os.path.join(get_config_dir(), 'gtkui_state')):
            os.makedirs(os.path.join(get_config_dir(), 'gtkui_state'))

        # Set language
        if self.config['language'] is not None:
            set_language(self.config['language'])

        # Start the IPC Interface before anything else.. Just in case we are
        # already running.
        self.queuedtorrents = QueuedTorrents()
        self.ipcinterface = IPCInterface(args.torrents)

        # Initialize gdk threading
        threads_init()

        # We make sure that the UI components start once we get a core URI
        client.set_disconnect_callback(self.__on_disconnect)

        self.trackericons = TrackerIcons()
        self.sessionproxy = SessionProxy()
        # Initialize various components of the gtkui
        self.mainwindow = MainWindow()
        self.menubar = MenuBar()
        self.toolbar = ToolBar()
        self.torrentview = TorrentView()
        self.torrentdetails = TorrentDetails()
        self.sidebar = SideBar()
        self.filtertreeview = FilterTreeView()
        self.preferences = Preferences()
        self.systemtray = SystemTray()
        self.statusbar = StatusBar()
        self.addtorrentdialog = AddTorrentDialog()

        if osx_check() and WINDOWING == 'quartz':

            def nsapp_open_file(osxapp, filename):
                # Ignore command name which is raised at app launch (python opening main script).
                if filename == sys.argv[0]:
                    return True
                process_args([filename])

            self.osxapp.connect('NSApplicationOpenFile', nsapp_open_file)
            from deluge.ui.gtkui.menubar_osx import menubar_osx

            menubar_osx(self, self.osxapp)
            self.osxapp.ready()

        # Initalize the plugins
        self.plugins = PluginManager()

        # Show the connection manager
        self.connectionmanager = ConnectionManager()

        # Setup RPC stats logging
        # daemon_bps: time, bytes_sent, bytes_recv
        self.daemon_bps = (0, 0, 0)
        self.rpc_stats = LoopingCall(self.log_rpc_stats)
        self.closing = False

        # Twisted catches signals to terminate, so have it call a pre_shutdown method.
        reactor.addSystemEventTrigger('before', 'gtkui_close', self.close)

        def gtkui_sigint_handler(num, frame):
            log.debug('SIGINT signal caught, firing event: gtkui_close')
            reactor.callLater(0, reactor.fireSystemEvent, 'gtkui_close')

        signal.signal(signal.SIGINT, gtkui_sigint_handler)

    def start(self):
        reactor.callWhenRunning(self._on_reactor_start)

        # Initialize gdk threading
        threads_enter()
        reactor.run()
        # Reactor no longer running so async callbacks (Deferreds) cannot be
        # processed after this point.
        threads_leave()

    def shutdown(self, *args, **kwargs):
        log.debug('GTKUI shutting down...')
        # Shutdown all components
        if client.is_standalone:
            return component.shutdown()

    @defer.inlineCallbacks
    def close(self):
        if self.closing:
            return
        self.closing = True
        # Make sure the config is saved.
        self.config.save()
        # Ensure columns state is saved
        self.torrentview.save_state()
        # Shut down components
        yield self.shutdown()

        # The gtk modal dialogs (e.g. Preferences) can prevent the application
        # quitting, so force exiting by destroying MainWindow. Must be done here
        # to avoid hanging when quitting with SIGINT (CTRL-C).
        self.mainwindow.window.destroy()

        reactor.stop()

        # Restart the application after closing if MainWindow restart attribute set.
        if component.get('MainWindow').restart:
            os.execv(sys.argv[0], sys.argv)

    def log_rpc_stats(self):
        """Log RPC statistics for thinclient mode."""
        if not client.connected():
            return

        t = time.time()
        recv = client.get_bytes_recv()
        sent = client.get_bytes_sent()
        delta_time = t - self.daemon_bps[0]
        delta_sent = sent - self.daemon_bps[1]
        delta_recv = recv - self.daemon_bps[2]
        self.daemon_bps = (t, sent, recv)
        sent_rate = fspeed(delta_sent / delta_time)
        recv_rate = fspeed(delta_recv / delta_time)
        log.debug(
            'RPC: Sent %s (%s) Recv %s (%s)',
            fsize(sent),
            sent_rate,
            fsize(recv),
            recv_rate,
        )

    def _on_reactor_start(self):
        log.debug('_on_reactor_start')
        self.mainwindow.first_show()

        if not self.config['standalone']:
            return self._start_thinclient()

        err_msg = ''
        try:
            client.start_standalone()
        except DaemonRunningError:
            err_msg = _(
                'A Deluge daemon (deluged) is already running.\n'
                'To use Standalone mode, stop local daemon and restart Deluge.'
            )
        except ImportError as ex:
            if 'No module named libtorrent' in ex.message:
                err_msg = _(
                    'Only Thin Client mode is available because libtorrent is not installed.\n'
                    'To use Standalone mode, please install libtorrent package.'
                )
            else:
                log.exception(ex)
                err_msg = _(
                    'Only Thin Client mode is available due to unknown Import Error.\n'
                    'To use Standalone mode, please see logs for error details.'
                )
        except Exception as ex:
            log.exception(ex)
            err_msg = _(
                'Only Thin Client mode is available due to unknown Import Error.\n'
                'To use Standalone mode, please see logs for error details.'
            )
        else:
            component.start()
            return

        def on_dialog_response(response):
            """User response to switching mode dialog."""
            if response == RESPONSE_YES:
                # Turning off standalone
                self.config['standalone'] = False
                self._start_thinclient()
            else:
                # User want keep Standalone Mode so just quit.
                self.mainwindow.quit()

        # An error occurred so ask user to switch from Standalone to Thin Client mode.
        err_msg += '\n\n' + _('Continue in Thin Client mode?')
        d = YesNoDialog(_('Change User Interface Mode'), err_msg).run()
        d.addCallback(on_dialog_response)

    def _start_thinclient(self):
        """Start the gtkui in thinclient mode"""
        if log.isEnabledFor(logging.DEBUG):
            self.rpc_stats.start(10)

        # Check to see if we need to start the localhost daemon
        if self.config['autostart_localhost']:

            def on_localhost_status(status_info, port):
                if status_info[1] == 'Offline':
                    log.debug('Autostarting localhost: %s', host_config[0:3])
                    self.connectionmanager.start_daemon(port, get_config_dir())

            for host_config in self.connectionmanager.hostlist.config['hosts']:
                if host_config[1] in LOCALHOST:
                    d = self.connectionmanager.hostlist.get_host_status(host_config[0])
                    d.addCallback(on_localhost_status, host_config[2])
                    break

        # Autoconnect to a host
        if self.config['autoconnect']:
            for host_config in self.connectionmanager.hostlist.config['hosts']:
                host_id, host, port, user, __ = host_config
                if host_id == self.config['autoconnect_host_id']:
                    log.debug('Trying to connect to %s@%s:%s', user, host, port)
                    self.connectionmanager._connect(host_id, try_counter=6)
                    break

        if self.config['show_connection_manager_on_start']:
            # Dialog is blocking so call last.
            self.connectionmanager.show()

    def __on_disconnect(self):
        """
        Called when disconnected from the daemon.  We basically just stop all
        the components here.
        """
        self.daemon_bps = (0, 0, 0)
        component.stop()