aboutsummaryrefslogtreecommitdiffstats
path: root/mvc/signals.py
diff options
context:
space:
mode:
authorJesús Eduardo <heckyel@hyperbola.info>2017-09-11 17:47:17 -0500
committerJesús Eduardo <heckyel@hyperbola.info>2017-09-11 17:47:17 -0500
commit14738704ede6dfa6ac79f362a9c1f7f40f470cdc (patch)
tree31c83bdd188ae7b64d7169974d6f066ccfe95367 /mvc/signals.py
parenteb1896583afbbb622cadcde1a24e17173f61904f (diff)
downloadlibrevideoconverter-14738704ede6dfa6ac79f362a9c1f7f40f470cdc.tar.lz
librevideoconverter-14738704ede6dfa6ac79f362a9c1f7f40f470cdc.tar.xz
librevideoconverter-14738704ede6dfa6ac79f362a9c1f7f40f470cdc.zip
rename mvc at lvc
Diffstat (limited to 'mvc/signals.py')
-rw-r--r--mvc/signals.py299
1 files changed, 0 insertions, 299 deletions
diff --git a/mvc/signals.py b/mvc/signals.py
deleted file mode 100644
index 2f64dc9..0000000
--- a/mvc/signals.py
+++ /dev/null
@@ -1,299 +0,0 @@
-# @Base: Miro - an RSS based video player application
-# Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011
-# Participatory Culture Foundation
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-#
-# In addition, as a special exception, the copyright holders give
-# permission to link the code of portions of this program with the OpenSSL
-# library.
-#
-# You must obey the GNU General Public License in all respects for all of
-# the code used other than OpenSSL. If you modify file(s) with this
-# exception, you may extend this exception to your version of the file(s),
-# but you are not obligated to do so. If you do not wish to do so, delete
-# this exception statement from your version. If you delete this exception
-# statement from all source files in the program, then also delete it here.
-
-"""signals.py
-
-GObject-like signal handling for Miro.
-"""
-
-import itertools
-import logging
-import sys
-import weakref
-
-class NestedSignalError(StandardError):
- pass
-
-class WeakMethodReference:
- """Used to handle weak references to a method.
-
- We can't simply keep a weak reference to method itself, because there
- almost certainly aren't any other references to it. Instead we keep a
- weak reference to the object, it's class and the unbound method. This
- gives us enough info to recreate the bound method when we need it.
- """
-
- def __init__(self, method):
- self.object = weakref.ref(method.im_self)
- self.func = weakref.ref(method.im_func)
- # don't create a weak reference to the class. That only works for
- # new-style classes. It's highly unlikely the class will ever need to
- # be garbage collected anyways.
- self.cls = method.im_class
-
- def __call__(self):
- func = self.func()
- if func is None: return None
- obj = self.object()
- if obj is None: return None
- return func.__get__(obj, self.cls)
-
-class Callback:
- def __init__(self, func, extra_args):
- self.func = func
- self.extra_args = extra_args
-
- def invoke(self, obj, args):
- return self.func(obj, *(args + self.extra_args))
-
- def compare_function(self, func):
- return self.func == func
-
- def is_dead(self):
- return False
-
-class WeakCallback:
- def __init__(self, method, extra_args):
- self.ref = WeakMethodReference(method)
- self.extra_args = extra_args
-
- def compare_function(self, func):
- return self.ref() == func
-
- def invoke(self, obj, args):
- callback = self.ref()
- if callback is not None:
- return callback(obj, *(args + self.extra_args))
- else:
- return None
-
- def is_dead(self):
- return self.ref() is None
-
-class SignalEmitter(object):
- def __init__(self, *signal_names):
- self.signal_callbacks = {}
- self.id_generator = itertools.count()
- self._currently_emitting = set()
- self._frozen = False
- for name in signal_names:
- self.create_signal(name)
-
- def freeze_signals(self):
- self._frozen = True
-
- def thaw_signals(self):
- self._frozen = False
-
- def create_signal(self, name):
- self.signal_callbacks[name] = {}
-
- def get_callbacks(self, signal_name):
- try:
- return self.signal_callbacks[signal_name]
- except KeyError:
- raise KeyError("Signal: %s doesn't exist" % signal_name)
-
- def _check_already_connected(self, name, func):
- for callback in self.get_callbacks(name).values():
- if callback.compare_function(func):
- raise ValueError("signal %s already connected to %s" %
- (name, func))
-
- def connect(self, name, func, *extra_args):
- """Connect a callback to a signal. Returns an callback handle that
- can be passed into disconnect().
-
- If func is already connected to the signal, then a ValueError will be
- raised.
- """
- self._check_already_connected(name, func)
- id_ = self.id_generator.next()
- callbacks = self.get_callbacks(name)
- callbacks[id_] = Callback(func, extra_args)
- return (name, id_)
-
- def connect_weak(self, name, method, *extra_args):
- """Connect a callback weakly. Callback must be a method of some
- object. We create a weak reference to the method, so that the
- connection doesn't keep the object from being garbage collected.
-
- If method is already connected to the signal, then a ValueError will be
- raised.
- """
- self._check_already_connected(name, method)
- if not hasattr(method, 'im_self'):
- raise TypeError("connect_weak must be called with object methods")
- id_ = self.id_generator.next()
- callbacks = self.get_callbacks(name)
- callbacks[id_] = WeakCallback(method, extra_args)
- return (name, id_)
-
- def disconnect(self, callback_handle):
- """Disconnect a signal. callback_handle must be the return value from
- connect() or connect_weak().
- """
- callbacks = self.get_callbacks(callback_handle[0])
- if callback_handle[1] in callbacks:
- del callbacks[callback_handle[1]]
- else:
- logging.warning(
- "disconnect called but callback_handle not in the callback")
-
- def disconnect_all(self):
- for signal in self.signal_callbacks:
- self.signal_callbacks[signal] = {}
-
- def emit(self, name, *args):
- if self._frozen:
- return
- if name in self._currently_emitting:
- raise NestedSignalError("Can't emit %s while handling %s" %
- (name, name))
- self._currently_emitting.add(name)
- try:
- callback_returned_true = self._run_signal(name, args)
- finally:
- self._currently_emitting.discard(name)
- self.clear_old_weak_references()
- return callback_returned_true
-
- def _run_signal(self, name, args):
- callback_returned_true = False
- try:
- self_callback = getattr(self, 'do_' + name.replace('-', '_'))
- except AttributeError:
- pass
- else:
- if self_callback(*args):
- callback_returned_true = True
- if not callback_returned_true:
- for callback in self.get_callbacks(name).values():
- if callback.invoke(self, args):
- callback_returned_true = True
- break
- return callback_returned_true
-
- def clear_old_weak_references(self):
- for callback_map in self.signal_callbacks.values():
- for id_ in callback_map.keys():
- if callback_map[id_].is_dead():
- del callback_map[id_]
-
-class SystemSignals(SignalEmitter):
- """System wide signals for Miro. These can be accessed from the singleton
- object signals.system. Signals include:
-
- "error" - A problem occurred in Miro. The frontend should let the user
- know this happened, hopefully with a nice dialog box or something that
- lets the user report the error to bugzilla.
-
- Arguments:
- - report -- string that can be submitted to the bug tracker
- - exception -- Exception object (can be None)
-
- "startup-success" - The startup process is complete. The frontend should
- wait for this signal to show the UI to the user.
-
- No arguments.
-
- "startup-failure" - The startup process fails. The frontend should inform
- the user that this happened and quit.
-
- Arguments:
- - summary -- Short, user-friendly, summary of the problem
- - description -- Longer explanation of the problem
-
- "shutdown" - The backend has shutdown. The event loop is stopped at this
- point.
-
- No arguments.
-
- "update-available" - A new version of LibreVideoConverter is available.
-
- Arguments:
- - rssItem -- The RSS item for the latest version (in sparkle
- appcast format).
-
- "new-dialog" - The backend wants to display a dialog to the user.
-
- Arguments:
- - dialog -- The dialog to be displayed.
-
- "theme-first-run" - A theme was used for the first time
-
- Arguments:
- - theme -- The name of the theme.
-
- "videos-added" -- Videos were added via the singleclick module.
- Arguments:
- - view -- A database view than contains the videos.
-
- "download-complete" -- A download was completed.
- Arguments:
- - item -- an Item of class Item.
-
- """
- def __init__(self):
- SignalEmitter.__init__(self, 'error', 'startup-success',
- 'startup-failure', 'shutdown',
- 'update-available', 'new-dialog',
- 'theme-first-run', 'videos-added',
- 'download-complete')
-
- def shutdown(self):
- self.emit('shutdown')
-
- def update_available(self, latest):
- self.emit('update-available', latest)
-
- def new_dialog(self, dialog):
- self.emit('new-dialog', dialog)
-
- def theme_first_run(self, theme):
- self.emit('theme-first-run', theme)
-
- def videos_added(self, view):
- self.emit('videos-added', view)
-
- def download_complete(self, item):
- self.emit('download-complete', item)
-
- def failed_exn(self, when, details=None):
- self.failed(when, with_exception=True, details=details)
-
- def failed(self, when, with_exception=False, details=None):
- """Used to emit the error signal. Formats a nice crash report."""
- if with_exception:
- exc_info = sys.exc_info()
- else:
- exc_info = None
- logging.error('%s: %s' % (when, details), exc_info=exc_info)
-
-system = SystemSignals()