#!/usr/bin/python
import sys
-import logging
-_moduleLogger = logging.getLogger(__name__)
sys.path.append("/opt/gonvert/lib")
import logging
import logging.handlers
-from PyQt4 import QtGui
-from PyQt4 import QtCore
+import util.qt_compat as qt_compat
+QtCore = qt_compat.QtCore
+QtGui = qt_compat.import_module("QtGui")
import constants
from util import qui_utils
import functools
import datetime
import types
+import array
+import random
def ordered_itr(collection):
yield x
+def product(*args, **kwds):
+ # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
+ # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
+ pools = map(tuple, args) * kwds.get('repeat', 1)
+ result = [[]]
+ for pool in pools:
+ result = [x+[y] for x in result for y in pool]
+ for prod in result:
+ yield tuple(prod)
+
+
def iterwhile(func, iterator):
"""
Iterate for as long as func(value) returns true.
yield queue.get_nowait()
+class BloomFilter(object):
+ """
+ http://en.wikipedia.org/wiki/Bloom_filter
+ Sources:
+ http://code.activestate.com/recipes/577684-bloom-filter/
+ http://code.activestate.com/recipes/577686-bloom-filter/
+
+ >>> from random import sample
+ >>> from string import ascii_letters
+ >>> states = '''Alabama Alaska Arizona Arkansas California Colorado Connecticut
+ ... Delaware Florida Georgia Hawaii Idaho Illinois Indiana Iowa Kansas
+ ... Kentucky Louisiana Maine Maryland Massachusetts Michigan Minnesota
+ ... Mississippi Missouri Montana Nebraska Nevada NewHampshire NewJersey
+ ... NewMexico NewYork NorthCarolina NorthDakota Ohio Oklahoma Oregon
+ ... Pennsylvania RhodeIsland SouthCarolina SouthDakota Tennessee Texas Utah
+ ... Vermont Virginia Washington WestVirginia Wisconsin Wyoming'''.split()
+ >>> bf = BloomFilter(num_bits=1000, num_probes=14)
+ >>> for state in states:
+ ... bf.add(state)
+ >>> numStatesFound = sum(state in bf for state in states)
+ >>> numStatesFound, len(states)
+ (50, 50)
+ >>> trials = 100
+ >>> numGarbageFound = sum(''.join(sample(ascii_letters, 5)) in bf for i in range(trials))
+ >>> numGarbageFound, trials
+ (0, 100)
+ """
+
+ def __init__(self, num_bits, num_probes):
+ num_words = (num_bits + 31) // 32
+ self._arr = array.array('B', [0]) * num_words
+ self._num_probes = num_probes
+
+ def add(self, key):
+ for i, mask in self._get_probes(key):
+ self._arr[i] |= mask
+
+ def union(self, bfilter):
+ if self._match_template(bfilter):
+ for i, b in enumerate(bfilter._arr):
+ self._arr[i] |= b
+ else:
+ # Union b/w two unrelated bloom filter raises this
+ raise ValueError("Mismatched bloom filters")
+
+ def intersection(self, bfilter):
+ if self._match_template(bfilter):
+ for i, b in enumerate(bfilter._arr):
+ self._arr[i] &= b
+ else:
+ # Intersection b/w two unrelated bloom filter raises this
+ raise ValueError("Mismatched bloom filters")
+
+ def __contains__(self, key):
+ return all(self._arr[i] & mask for i, mask in self._get_probes(key))
+
+ def _match_template(self, bfilter):
+ return self.num_bits == bfilter.num_bits and self.num_probes == bfilter.num_probes
+
+ def _get_probes(self, key):
+ hasher = random.Random(key).randrange
+ for _ in range(self._num_probes):
+ array_index = hasher(len(self._arr))
+ bit_index = hasher(32)
+ yield array_index, 1 << bit_index
+
+
if __name__ == "__main__":
import doctest
print doctest.testmod()
_moduleLogger = logging.getLogger(__name__)
-class AsyncLinearExecution(object):
+class AsyncTaskQueue(object):
+
+ def __init__(self, taskPool):
+ self._asyncs = []
+ self._taskPool = taskPool
+
+ def add_async(self, func):
+ self.flush()
+ a = AsyncGeneratorTask(self._taskPool, func)
+ self._asyncs.append(a)
+ return a
+
+ def flush(self):
+ self._asyncs = [a for a in self._asyncs if not a.isDone]
+
+
+class AsyncGeneratorTask(object):
def __init__(self, pool, func):
self._pool = pool
self._func = func
self._run = None
+ self._isDone = False
+
+ @property
+ def isDone(self):
+ return self._isDone
def start(self, *args, **kwds):
assert self._run is None, "Task already started"
try:
trampoline, args, kwds = self._run.send(result)
except StopIteration, e:
- pass
+ self._isDone = True
else:
self._pool.add_task(
trampoline,
try:
trampoline, args, kwds = self._run.throw(error)
except StopIteration, e:
- pass
+ self._isDone = True
else:
self._pool.add_task(
trampoline,
_QUEUE_EMPTY = object()
-class AsyncPool(object):
+class FutureThread(object):
def __init__(self):
self.__workQueue = Queue.Queue()
--- /dev/null
+#!/usr/bin/env python
+
+from __future__ import with_statement
+from __future__ import division
+
+import contextlib
+import logging
+
+import gtk
+
+
+_moduleLogger = logging.getLogger(__name__)
+
+
+@contextlib.contextmanager
+def gtk_lock():
+ gtk.gdk.threads_enter()
+ try:
+ yield
+ finally:
+ gtk.gdk.threads_leave()
+
+
+def find_parent_window(widget):
+ while True:
+ parent = widget.get_parent()
+ if isinstance(parent, gtk.Window):
+ return parent
+ widget = parent
+
+
+if __name__ == "__main__":
+ pass
+
--- /dev/null
+#!/usr/bin/env python
+
+"""
+Open Issues
+ @bug not all of a message is shown
+ @bug Buttons are too small
+"""
+
+
+import gobject
+import gtk
+import dbus
+
+
+class _NullHildonModule(object):
+ pass
+
+
+try:
+ import hildon as _hildon
+ hildon = _hildon # Dumb but gets around pyflakiness
+except (ImportError, OSError):
+ hildon = _NullHildonModule
+
+
+IS_HILDON_SUPPORTED = hildon is not _NullHildonModule
+
+
+class _NullHildonProgram(object):
+
+ def add_window(self, window):
+ pass
+
+
+def _hildon_get_app_class():
+ return hildon.Program
+
+
+def _null_get_app_class():
+ return _NullHildonProgram
+
+
+try:
+ hildon.Program
+ get_app_class = _hildon_get_app_class
+except AttributeError:
+ get_app_class = _null_get_app_class
+
+
+def _hildon_set_application_name(name):
+ gtk.set_application_name(name)
+
+
+def _null_set_application_name(name):
+ pass
+
+
+try:
+ gtk.set_application_name
+ set_application_name = _hildon_set_application_name
+except AttributeError:
+ set_application_name = _null_set_application_name
+
+
+def _fremantle_hildonize_window(app, window):
+ oldWindow = window
+ newWindow = hildon.StackableWindow()
+ if oldWindow.get_child() is not None:
+ oldWindow.get_child().reparent(newWindow)
+ app.add_window(newWindow)
+ return newWindow
+
+
+def _hildon_hildonize_window(app, window):
+ oldWindow = window
+ newWindow = hildon.Window()
+ if oldWindow.get_child() is not None:
+ oldWindow.get_child().reparent(newWindow)
+ app.add_window(newWindow)
+ return newWindow
+
+
+def _null_hildonize_window(app, window):
+ return window
+
+
+try:
+ hildon.StackableWindow
+ hildonize_window = _fremantle_hildonize_window
+except AttributeError:
+ try:
+ hildon.Window
+ hildonize_window = _hildon_hildonize_window
+ except AttributeError:
+ hildonize_window = _null_hildonize_window
+
+
+def _fremantle_hildonize_menu(window, gtkMenu):
+ appMenu = hildon.AppMenu()
+ window.set_app_menu(appMenu)
+ gtkMenu.get_parent().remove(gtkMenu)
+ return appMenu
+
+
+def _hildon_hildonize_menu(window, gtkMenu):
+ hildonMenu = gtk.Menu()
+ for child in gtkMenu.get_children():
+ child.reparent(hildonMenu)
+ window.set_menu(hildonMenu)
+ gtkMenu.destroy()
+ return hildonMenu
+
+
+def _null_hildonize_menu(window, gtkMenu):
+ return gtkMenu
+
+
+try:
+ hildon.AppMenu
+ GTK_MENU_USED = False
+ IS_FREMANTLE_SUPPORTED = True
+ hildonize_menu = _fremantle_hildonize_menu
+except AttributeError:
+ GTK_MENU_USED = True
+ IS_FREMANTLE_SUPPORTED = False
+ if IS_HILDON_SUPPORTED:
+ hildonize_menu = _hildon_hildonize_menu
+ else:
+ hildonize_menu = _null_hildonize_menu
+
+
+def _hildon_set_button_auto_selectable(button):
+ button.set_theme_size(hildon.HILDON_SIZE_AUTO_HEIGHT)
+
+
+def _null_set_button_auto_selectable(button):
+ pass
+
+
+try:
+ hildon.HILDON_SIZE_AUTO_HEIGHT
+ gtk.Button.set_theme_size
+ set_button_auto_selectable = _hildon_set_button_auto_selectable
+except AttributeError:
+ set_button_auto_selectable = _null_set_button_auto_selectable
+
+
+def _hildon_set_button_finger_selectable(button):
+ button.set_theme_size(hildon.HILDON_SIZE_FINGER_HEIGHT)
+
+
+def _null_set_button_finger_selectable(button):
+ pass
+
+
+try:
+ hildon.HILDON_SIZE_FINGER_HEIGHT
+ gtk.Button.set_theme_size
+ set_button_finger_selectable = _hildon_set_button_finger_selectable
+except AttributeError:
+ set_button_finger_selectable = _null_set_button_finger_selectable
+
+
+def _hildon_set_button_thumb_selectable(button):
+ button.set_theme_size(hildon.HILDON_SIZE_THUMB_HEIGHT)
+
+
+def _null_set_button_thumb_selectable(button):
+ pass
+
+
+try:
+ hildon.HILDON_SIZE_THUMB_HEIGHT
+ gtk.Button.set_theme_size
+ set_button_thumb_selectable = _hildon_set_button_thumb_selectable
+except AttributeError:
+ set_button_thumb_selectable = _null_set_button_thumb_selectable
+
+
+def _hildon_set_cell_thumb_selectable(renderer):
+ renderer.set_property("scale", 1.5)
+
+
+def _null_set_cell_thumb_selectable(renderer):
+ pass
+
+
+if IS_HILDON_SUPPORTED:
+ set_cell_thumb_selectable = _hildon_set_cell_thumb_selectable
+else:
+ set_cell_thumb_selectable = _null_set_cell_thumb_selectable
+
+
+def _hildon_set_pix_cell_thumb_selectable(renderer):
+ renderer.set_property("stock-size", 48)
+
+
+def _null_set_pix_cell_thumb_selectable(renderer):
+ pass
+
+
+if IS_HILDON_SUPPORTED:
+ set_pix_cell_thumb_selectable = _hildon_set_pix_cell_thumb_selectable
+else:
+ set_pix_cell_thumb_selectable = _null_set_pix_cell_thumb_selectable
+
+
+def _fremantle_show_information_banner(parent, message):
+ hildon.hildon_banner_show_information(parent, "", message)
+
+
+def _hildon_show_information_banner(parent, message):
+ hildon.hildon_banner_show_information(parent, None, message)
+
+
+def _null_show_information_banner(parent, message):
+ pass
+
+
+if IS_FREMANTLE_SUPPORTED:
+ show_information_banner = _fremantle_show_information_banner
+else:
+ try:
+ hildon.hildon_banner_show_information
+ show_information_banner = _hildon_show_information_banner
+ except AttributeError:
+ show_information_banner = _null_show_information_banner
+
+
+def _fremantle_show_busy_banner_start(parent, message):
+ hildon.hildon_gtk_window_set_progress_indicator(parent, True)
+ return parent
+
+
+def _fremantle_show_busy_banner_end(banner):
+ hildon.hildon_gtk_window_set_progress_indicator(banner, False)
+
+
+def _hildon_show_busy_banner_start(parent, message):
+ return hildon.hildon_banner_show_animation(parent, None, message)
+
+
+def _hildon_show_busy_banner_end(banner):
+ banner.destroy()
+
+
+def _null_show_busy_banner_start(parent, message):
+ return None
+
+
+def _null_show_busy_banner_end(banner):
+ assert banner is None
+
+
+try:
+ hildon.hildon_gtk_window_set_progress_indicator
+ show_busy_banner_start = _fremantle_show_busy_banner_start
+ show_busy_banner_end = _fremantle_show_busy_banner_end
+except AttributeError:
+ try:
+ hildon.hildon_banner_show_animation
+ show_busy_banner_start = _hildon_show_busy_banner_start
+ show_busy_banner_end = _hildon_show_busy_banner_end
+ except AttributeError:
+ show_busy_banner_start = _null_show_busy_banner_start
+ show_busy_banner_end = _null_show_busy_banner_end
+
+
+def _hildon_hildonize_text_entry(textEntry):
+ textEntry.set_property('hildon-input-mode', 7)
+
+
+def _null_hildonize_text_entry(textEntry):
+ pass
+
+
+if IS_HILDON_SUPPORTED:
+ hildonize_text_entry = _hildon_hildonize_text_entry
+else:
+ hildonize_text_entry = _null_hildonize_text_entry
+
+
+def _hildon_window_to_portrait(window):
+ # gtk documentation is unclear whether this does a "=" or a "|="
+ flags = hildon.PORTRAIT_MODE_SUPPORT | hildon.PORTRAIT_MODE_REQUEST
+ hildon.hildon_gtk_window_set_portrait_flags(window, flags)
+
+
+def _hildon_window_to_landscape(window):
+ # gtk documentation is unclear whether this does a "=" or a "&= ~"
+ flags = hildon.PORTRAIT_MODE_SUPPORT
+ hildon.hildon_gtk_window_set_portrait_flags(window, flags)
+
+
+def _null_window_to_portrait(window):
+ pass
+
+
+def _null_window_to_landscape(window):
+ pass
+
+
+try:
+ hildon.PORTRAIT_MODE_SUPPORT
+ hildon.PORTRAIT_MODE_REQUEST
+ hildon.hildon_gtk_window_set_portrait_flags
+
+ window_to_portrait = _hildon_window_to_portrait
+ window_to_landscape = _hildon_window_to_landscape
+except AttributeError:
+ window_to_portrait = _null_window_to_portrait
+ window_to_landscape = _null_window_to_landscape
+
+
+def get_device_orientation():
+ bus = dbus.SystemBus()
+ try:
+ rawMceRequest = bus.get_object("com.nokia.mce", "/com/nokia/mce/request")
+ mceRequest = dbus.Interface(rawMceRequest, dbus_interface="com.nokia.mce.request")
+ orientation, standState, faceState, xAxis, yAxis, zAxis = mceRequest.get_device_orientation()
+ except dbus.exception.DBusException:
+ # catching for documentation purposes that when a system doesn't
+ # support this, this is what to expect
+ raise
+
+ if orientation == "":
+ return gtk.ORIENTATION_HORIZONTAL
+ elif orientation == "":
+ return gtk.ORIENTATION_VERTICAL
+ else:
+ raise RuntimeError("Unknown orientation: %s" % orientation)
+
+
+def _hildon_hildonize_password_entry(textEntry):
+ textEntry.set_property('hildon-input-mode', 7 | (1 << 29))
+
+
+def _null_hildonize_password_entry(textEntry):
+ pass
+
+
+if IS_HILDON_SUPPORTED:
+ hildonize_password_entry = _hildon_hildonize_password_entry
+else:
+ hildonize_password_entry = _null_hildonize_password_entry
+
+
+def _hildon_hildonize_combo_entry(comboEntry):
+ comboEntry.set_property('hildon-input-mode', 1 << 4)
+
+
+def _null_hildonize_combo_entry(textEntry):
+ pass
+
+
+if IS_HILDON_SUPPORTED:
+ hildonize_combo_entry = _hildon_hildonize_combo_entry
+else:
+ hildonize_combo_entry = _null_hildonize_combo_entry
+
+
+def _null_create_seekbar():
+ adjustment = gtk.Adjustment(0, 0, 101, 1, 5, 1)
+ seek = gtk.HScale(adjustment)
+ seek.set_draw_value(False)
+ return seek
+
+
+def _fremantle_create_seekbar():
+ seek = hildon.Seekbar()
+ seek.set_range(0.0, 100)
+ seek.set_draw_value(False)
+ seek.set_update_policy(gtk.UPDATE_DISCONTINUOUS)
+ return seek
+
+
+try:
+ hildon.Seekbar
+ create_seekbar = _fremantle_create_seekbar
+except AttributeError:
+ create_seekbar = _null_create_seekbar
+
+
+def _fremantle_hildonize_scrollwindow(scrolledWindow):
+ pannableWindow = hildon.PannableArea()
+
+ child = scrolledWindow.get_child()
+ scrolledWindow.remove(child)
+ pannableWindow.add(child)
+
+ parent = scrolledWindow.get_parent()
+ if parent is not None:
+ parent.remove(scrolledWindow)
+ parent.add(pannableWindow)
+
+ return pannableWindow
+
+
+def _hildon_hildonize_scrollwindow(scrolledWindow):
+ hildon.hildon_helper_set_thumb_scrollbar(scrolledWindow, True)
+ return scrolledWindow
+
+
+def _null_hildonize_scrollwindow(scrolledWindow):
+ return scrolledWindow
+
+
+try:
+ hildon.PannableArea
+ hildonize_scrollwindow = _fremantle_hildonize_scrollwindow
+ hildonize_scrollwindow_with_viewport = _hildon_hildonize_scrollwindow
+except AttributeError:
+ try:
+ hildon.hildon_helper_set_thumb_scrollbar
+ hildonize_scrollwindow = _hildon_hildonize_scrollwindow
+ hildonize_scrollwindow_with_viewport = _hildon_hildonize_scrollwindow
+ except AttributeError:
+ hildonize_scrollwindow = _null_hildonize_scrollwindow
+ hildonize_scrollwindow_with_viewport = _null_hildonize_scrollwindow
+
+
+def _hildon_request_number(parent, title, range, default):
+ spinner = hildon.NumberEditor(*range)
+ spinner.set_value(default)
+
+ dialog = gtk.Dialog(
+ title,
+ parent,
+ gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
+ (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
+ )
+ dialog.set_default_response(gtk.RESPONSE_CANCEL)
+ dialog.get_child().add(spinner)
+
+ try:
+ dialog.show_all()
+ response = dialog.run()
+
+ if response == gtk.RESPONSE_OK:
+ return spinner.get_value()
+ elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
+ raise RuntimeError("User cancelled request")
+ else:
+ raise RuntimeError("Unrecognized response %r", response)
+ finally:
+ dialog.hide()
+ dialog.destroy()
+
+
+def _null_request_number(parent, title, range, default):
+ adjustment = gtk.Adjustment(default, range[0], range[1], 1, 5, 0)
+ spinner = gtk.SpinButton(adjustment, 0, 0)
+ spinner.set_wrap(False)
+
+ dialog = gtk.Dialog(
+ title,
+ parent,
+ gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
+ (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
+ )
+ dialog.set_default_response(gtk.RESPONSE_CANCEL)
+ dialog.get_child().add(spinner)
+
+ try:
+ dialog.show_all()
+ response = dialog.run()
+
+ if response == gtk.RESPONSE_OK:
+ return spinner.get_value_as_int()
+ elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
+ raise RuntimeError("User cancelled request")
+ else:
+ raise RuntimeError("Unrecognized response %r", response)
+ finally:
+ dialog.hide()
+ dialog.destroy()
+
+
+try:
+ hildon.NumberEditor # TODO deprecated in fremantle
+ request_number = _hildon_request_number
+except AttributeError:
+ request_number = _null_request_number
+
+
+def _hildon_touch_selector(parent, title, items, defaultIndex):
+ model = gtk.ListStore(gobject.TYPE_STRING)
+ for item in items:
+ model.append((item, ))
+
+ selector = hildon.TouchSelector()
+ selector.append_text_column(model, True)
+ selector.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
+ selector.set_active(0, defaultIndex)
+
+ dialog = hildon.PickerDialog(parent)
+ dialog.set_selector(selector)
+
+ try:
+ dialog.show_all()
+ response = dialog.run()
+
+ if response == gtk.RESPONSE_OK:
+ return selector.get_active(0)
+ elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
+ raise RuntimeError("User cancelled request")
+ else:
+ raise RuntimeError("Unrecognized response %r", response)
+ finally:
+ dialog.hide()
+ dialog.destroy()
+
+
+def _on_null_touch_selector_activated(treeView, path, column, dialog, pathData):
+ dialog.response(gtk.RESPONSE_OK)
+ pathData[0] = path
+
+
+def _null_touch_selector(parent, title, items, defaultIndex = -1):
+ parentSize = parent.get_size()
+
+ model = gtk.ListStore(gobject.TYPE_STRING)
+ for item in items:
+ model.append((item, ))
+
+ cell = gtk.CellRendererText()
+ set_cell_thumb_selectable(cell)
+ column = gtk.TreeViewColumn(title)
+ column.pack_start(cell, expand=True)
+ column.add_attribute(cell, "text", 0)
+
+ treeView = gtk.TreeView()
+ treeView.set_model(model)
+ treeView.append_column(column)
+ selection = treeView.get_selection()
+ selection.set_mode(gtk.SELECTION_SINGLE)
+ if 0 < defaultIndex:
+ selection.select_path((defaultIndex, ))
+
+ scrolledWin = gtk.ScrolledWindow()
+ scrolledWin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ scrolledWin.add(treeView)
+
+ dialog = gtk.Dialog(
+ title,
+ parent,
+ gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
+ (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
+ )
+ dialog.set_default_response(gtk.RESPONSE_CANCEL)
+ dialog.get_child().add(scrolledWin)
+ dialog.resize(parentSize[0], max(parentSize[1]-100, 100))
+
+ scrolledWin = hildonize_scrollwindow(scrolledWin)
+ pathData = [None]
+ treeView.connect("row-activated", _on_null_touch_selector_activated, dialog, pathData)
+
+ try:
+ dialog.show_all()
+ response = dialog.run()
+
+ if response == gtk.RESPONSE_OK:
+ if pathData[0] is None:
+ raise RuntimeError("No selection made")
+ return pathData[0][0]
+ elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
+ raise RuntimeError("User cancelled request")
+ else:
+ raise RuntimeError("Unrecognized response %r", response)
+ finally:
+ dialog.hide()
+ dialog.destroy()
+
+
+try:
+ hildon.PickerDialog
+ hildon.TouchSelector
+ touch_selector = _hildon_touch_selector
+except AttributeError:
+ touch_selector = _null_touch_selector
+
+
+def _hildon_touch_selector_entry(parent, title, items, defaultItem):
+ # Got a segfault when using append_text_column with TouchSelectorEntry, so using this way
+ try:
+ selector = hildon.TouchSelectorEntry(text=True)
+ except TypeError:
+ selector = hildon.hildon_touch_selector_entry_new_text()
+ defaultIndex = -1
+ for i, item in enumerate(items):
+ selector.append_text(item)
+ if item == defaultItem:
+ defaultIndex = i
+
+ dialog = hildon.PickerDialog(parent)
+ dialog.set_selector(selector)
+
+ if 0 < defaultIndex:
+ selector.set_active(0, defaultIndex)
+ else:
+ selector.get_entry().set_text(defaultItem)
+
+ try:
+ dialog.show_all()
+ response = dialog.run()
+ finally:
+ dialog.hide()
+
+ if response == gtk.RESPONSE_OK:
+ return selector.get_entry().get_text()
+ elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
+ raise RuntimeError("User cancelled request")
+ else:
+ raise RuntimeError("Unrecognized response %r", response)
+
+
+def _on_null_touch_selector_entry_entry_changed(entry, result, selection, defaultIndex):
+ custom = entry.get_text().strip()
+ if custom:
+ result[0] = custom
+ selection.unselect_all()
+ else:
+ result[0] = None
+ selection.select_path((defaultIndex, ))
+
+
+def _on_null_touch_selector_entry_entry_activated(customEntry, dialog, result):
+ dialog.response(gtk.RESPONSE_OK)
+ result[0] = customEntry.get_text()
+
+
+def _on_null_touch_selector_entry_tree_activated(treeView, path, column, dialog, result):
+ dialog.response(gtk.RESPONSE_OK)
+ model = treeView.get_model()
+ itr = model.get_iter(path)
+ if itr is not None:
+ result[0] = model.get_value(itr, 0)
+
+
+def _null_touch_selector_entry(parent, title, items, defaultItem):
+ parentSize = parent.get_size()
+
+ model = gtk.ListStore(gobject.TYPE_STRING)
+ defaultIndex = -1
+ for i, item in enumerate(items):
+ model.append((item, ))
+ if item == defaultItem:
+ defaultIndex = i
+
+ cell = gtk.CellRendererText()
+ set_cell_thumb_selectable(cell)
+ column = gtk.TreeViewColumn(title)
+ column.pack_start(cell, expand=True)
+ column.add_attribute(cell, "text", 0)
+
+ treeView = gtk.TreeView()
+ treeView.set_model(model)
+ treeView.append_column(column)
+ selection = treeView.get_selection()
+ selection.set_mode(gtk.SELECTION_SINGLE)
+
+ scrolledWin = gtk.ScrolledWindow()
+ scrolledWin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ scrolledWin.add(treeView)
+
+ customEntry = gtk.Entry()
+
+ layout = gtk.VBox()
+ layout.pack_start(customEntry, expand=False)
+ layout.pack_start(scrolledWin)
+
+ dialog = gtk.Dialog(
+ title,
+ parent,
+ gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
+ (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
+ )
+ dialog.set_default_response(gtk.RESPONSE_CANCEL)
+ dialog.get_child().add(layout)
+ dialog.resize(parentSize[0], max(parentSize[1]-100, 100))
+
+ scrolledWin = hildonize_scrollwindow(scrolledWin)
+
+ result = [None]
+ if 0 < defaultIndex:
+ selection.select_path((defaultIndex, ))
+ result[0] = defaultItem
+ else:
+ customEntry.set_text(defaultItem)
+
+ customEntry.connect("activate", _on_null_touch_selector_entry_entry_activated, dialog, result)
+ customEntry.connect("changed", _on_null_touch_selector_entry_entry_changed, result, selection, defaultIndex)
+ treeView.connect("row-activated", _on_null_touch_selector_entry_tree_activated, dialog, result)
+
+ try:
+ dialog.show_all()
+ response = dialog.run()
+
+ if response == gtk.RESPONSE_OK:
+ _, itr = selection.get_selected()
+ if itr is not None:
+ return model.get_value(itr, 0)
+ else:
+ enteredText = customEntry.get_text().strip()
+ if enteredText:
+ return enteredText
+ elif result[0] is not None:
+ return result[0]
+ else:
+ raise RuntimeError("No selection made")
+ elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
+ raise RuntimeError("User cancelled request")
+ else:
+ raise RuntimeError("Unrecognized response %r", response)
+ finally:
+ dialog.hide()
+ dialog.destroy()
+
+
+try:
+ hildon.PickerDialog
+ hildon.TouchSelectorEntry
+ touch_selector_entry = _hildon_touch_selector_entry
+except AttributeError:
+ touch_selector_entry = _null_touch_selector_entry
+
+
+if __name__ == "__main__":
+ app = get_app_class()()
+
+ label = gtk.Label("Hello World from a Label!")
+
+ win = gtk.Window()
+ win.add(label)
+ win = hildonize_window(app, win)
+ if False and IS_FREMANTLE_SUPPORTED:
+ appMenu = hildon.AppMenu()
+ for i in xrange(5):
+ b = gtk.Button(str(i))
+ appMenu.append(b)
+ win.set_app_menu(appMenu)
+ win.show_all()
+ appMenu.show_all()
+ gtk.main()
+ elif False:
+ print touch_selector(win, "Test", ["A", "B", "C", "D"], 2)
+ elif False:
+ print touch_selector_entry(win, "Test", ["A", "B", "C", "D"], "C")
+ print touch_selector_entry(win, "Test", ["A", "B", "C", "D"], "Blah")
+ elif False:
+ import pprint
+ name, value = "", ""
+ goodLocals = [
+ (name, value) for (name, value) in locals().iteritems()
+ if not name.startswith("_")
+ ]
+ pprint.pprint(goodLocals)
+ elif False:
+ import time
+ show_information_banner(win, "Hello World")
+ time.sleep(5)
+ elif False:
+ import time
+ banner = show_busy_banner_start(win, "Hello World")
+ time.sleep(5)
+ show_busy_banner_end(banner)
import contextlib
import itertools
import codecs
+from xml.sax import saxutils
import csv
try:
import cStringIO as StringIO
def utf_8_encoder(unicode_csv_data):
for line in unicode_csv_data:
yield line.encode('utf-8')
+
+
+_UNESCAPE_ENTITIES = {
+ """: '"',
+ " ": " ",
+ "'": "'",
+}
+
+
+_ESCAPE_ENTITIES = dict((v, k) for (v, k) in zip(_UNESCAPE_ENTITIES.itervalues(), _UNESCAPE_ENTITIES.iterkeys()))
+del _ESCAPE_ENTITIES[" "]
+
+
+def unescape(text):
+ plain = saxutils.unescape(text, _UNESCAPE_ENTITIES)
+ return plain
+
+
+def escape(text):
+ fancy = saxutils.escape(text, _ESCAPE_ENTITIES)
+ return fancy
@contextlib.contextmanager
+def nested_break():
+ """
+ >>> with nested_break() as mylabel:
+ ... for i in xrange(3):
+ ... print "Outer", i
+ ... for j in xrange(3):
+ ... if i == 2: raise mylabel
+ ... if j == 2: break
+ ... print "Inner", j
+ ... print "more processing"
+ Outer 0
+ Inner 0
+ Inner 1
+ Outer 1
+ Inner 0
+ Inner 1
+ Outer 2
+ """
+
+ class NestedBreakException(Exception):
+ pass
+
+ try:
+ yield NestedBreakException
+ except NestedBreakException:
+ pass
+
+
+@contextlib.contextmanager
def lexical_scope(*args):
"""
@note Source: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/520586
import logging
-from PyQt4 import QtCore
+import qt_compat
+QtCore = qt_compat.QtCore
import misc
self.exec_()
-class _ParentThread(QtCore.QObject):
-
- def __init__(self, pool):
- QtCore.QObject.__init__(self)
- self._pool = pool
-
- @QtCore.pyqtSlot(object)
- @misc.log_exception(_moduleLogger)
- def _on_task_complete(self, taskResult):
- on_success, on_error, isError, result = taskResult
- if not self._pool._isRunning:
- if isError:
- _moduleLogger.error("Masking: %s" % (result, ))
- isError = True
- result = StopIteration("Cancelling all callbacks")
- callback = on_success if not isError else on_error
- try:
- callback(result)
- except Exception:
- _moduleLogger.exception("Callback errored")
-
-
class _WorkerThread(QtCore.QObject):
- taskComplete = QtCore.pyqtSignal(object)
+ _taskComplete = qt_compat.Signal(object)
- def __init__(self, pool):
+ def __init__(self, futureThread):
QtCore.QObject.__init__(self)
- self._pool = pool
+ self._futureThread = futureThread
+ self._futureThread._addTask.connect(self._on_task_added)
+ self._taskComplete.connect(self._futureThread._on_task_complete)
- @QtCore.pyqtSlot(object)
- @misc.log_exception(_moduleLogger)
+ @qt_compat.Slot(object)
def _on_task_added(self, task):
- if not self._pool._isRunning:
+ self.__on_task_added(task)
+
+ @misc.log_exception(_moduleLogger)
+ def __on_task_added(self, task):
+ if not self._futureThread._isRunning:
_moduleLogger.error("Dropping task")
func, args, kwds, on_success, on_error = task
isError = True
taskResult = on_success, on_error, isError, result
- self.taskComplete.emit(taskResult)
-
- @QtCore.pyqtSlot()
- @misc.log_exception(_moduleLogger)
- def _on_stop_requested(self):
- self._pool._thread.quit()
+ self._taskComplete.emit(taskResult)
-class AsyncPool(QtCore.QObject):
+class FutureThread(QtCore.QObject):
- _addTask = QtCore.pyqtSignal(object)
- _stopPool = QtCore.pyqtSignal()
+ _addTask = qt_compat.Signal(object)
def __init__(self):
QtCore.QObject.__init__(self)
self._thread = QThread44()
- self._isRunning = True
- self._parent = _ParentThread(self)
+ self._isRunning = False
self._worker = _WorkerThread(self)
self._worker.moveToThread(self._thread)
- self._addTask.connect(self._worker._on_task_added)
- self._worker.taskComplete.connect(self._parent._on_task_complete)
- self._stopPool.connect(self._worker._on_stop_requested)
-
def start(self):
self._thread.start()
+ self._isRunning = True
def stop(self):
self._isRunning = False
- self._stopPool.emit()
+ self._thread.quit()
def add_task(self, func, args, kwds, on_success, on_error):
assert self._isRunning, "Task queue not started"
task = func, args, kwds, on_success, on_error
self._addTask.emit(task)
+
+ @qt_compat.Slot(object)
+ def _on_task_complete(self, taskResult):
+ self.__on_task_complete(taskResult)
+
+ @misc.log_exception(_moduleLogger)
+ def __on_task_complete(self, taskResult):
+ on_success, on_error, isError, result = taskResult
+ if not self._isRunning:
+ if isError:
+ _moduleLogger.error("Masking: %s" % (result, ))
+ isError = True
+ result = StopIteration("Cancelling all callbacks")
+ callback = on_success if not isError else on_error
+ try:
+ callback(result)
+ except Exception:
+ _moduleLogger.exception("Callback errored")
--- /dev/null
+#!/usr/bin/env python
+
+from __future__ import with_statement
+from __future__ import division
+
+#try:
+# import PySide.QtCore as _QtCore
+# QtCore = _QtCore
+# USES_PYSIDE = True
+#except ImportError:
+if True:
+ import sip
+ sip.setapi('QString', 2)
+ sip.setapi('QVariant', 2)
+ import PyQt4.QtCore as _QtCore
+ QtCore = _QtCore
+ USES_PYSIDE = False
+
+
+def _pyside_import_module(moduleName):
+ pyside = __import__('PySide', globals(), locals(), [moduleName], -1)
+ return getattr(pyside, moduleName)
+
+
+def _pyqt4_import_module(moduleName):
+ pyside = __import__('PyQt4', globals(), locals(), [moduleName], -1)
+ return getattr(pyside, moduleName)
+
+
+if USES_PYSIDE:
+ import_module = _pyside_import_module
+
+ Signal = QtCore.Signal
+ Slot = QtCore.Slot
+ Property = QtCore.Property
+else:
+ import_module = _pyqt4_import_module
+
+ Signal = QtCore.pyqtSignal
+ Slot = QtCore.pyqtSlot
+ Property = QtCore.pyqtProperty
+
+
+if __name__ == "__main__":
+ pass
+
import math
import logging
-from PyQt4 import QtGui
-from PyQt4 import QtCore
+import qt_compat
+QtCore = qt_compat.QtCore
+QtGui = qt_compat.import_module("QtGui")
import misc as misc_utils
class QPieButton(QtGui.QWidget):
- activated = QtCore.pyqtSignal(int)
- highlighted = QtCore.pyqtSignal(int)
- canceled = QtCore.pyqtSignal()
- aboutToShow = QtCore.pyqtSignal()
- aboutToHide = QtCore.pyqtSignal()
+ activated = qt_compat.Signal(int)
+ highlighted = qt_compat.Signal(int)
+ canceled = qt_compat.Signal()
+ aboutToShow = qt_compat.Signal()
+ aboutToHide = qt_compat.Signal()
BUTTON_RADIUS = 24
DELAY = 250
class QPieMenu(QtGui.QWidget):
- activated = QtCore.pyqtSignal(int)
- highlighted = QtCore.pyqtSignal(int)
- canceled = QtCore.pyqtSignal()
- aboutToShow = QtCore.pyqtSignal()
- aboutToHide = QtCore.pyqtSignal()
+ activated = qt_compat.Signal(int)
+ highlighted = qt_compat.Signal(int)
+ canceled = qt_compat.Signal()
+ aboutToShow = qt_compat.Signal()
+ aboutToHide = qt_compat.Signal()
def __init__(self, parent = None):
QtGui.QWidget.__init__(self, parent)
import os
import warnings
-from PyQt4 import QtGui
+import qt_compat
+QtGui = qt_compat.import_module("QtGui")
import qtpie
import datetime
import logging
-from PyQt4 import QtCore
-from PyQt4 import QtGui
+import qt_compat
+QtCore = qt_compat.QtCore
+QtGui = qt_compat.import_module("QtGui")
import misc
class QErrorLog(QtCore.QObject):
- messagePushed = QtCore.pyqtSignal()
- messagePopped = QtCore.pyqtSignal()
+ messagePushed = qt_compat.Signal()
+ messagePopped = qt_compat.Signal()
def __init__(self):
QtCore.QObject.__init__(self)
self._errorLog.messagePushed.connect(self._on_message_pushed)
self._errorLog.messagePopped.connect(self._on_message_popped)
- self._icons = {
- ErrorMessage.LEVEL_BUSY:
- get_theme_icon(
- #("process-working", "view-refresh", "general_refresh", "gtk-refresh")
- ("view-refresh", "general_refresh", "gtk-refresh", )
- ).pixmap(32, 32),
- ErrorMessage.LEVEL_INFO:
- get_theme_icon(
- ("dialog-information", "general_notes", "gtk-info")
- ).pixmap(32, 32),
- ErrorMessage.LEVEL_ERROR:
- get_theme_icon(
- ("dialog-error", "app_install_error", "gtk-dialog-error")
- ).pixmap(32, 32),
- }
+ self._icons = None
self._severityLabel = QtGui.QLabel()
self._severityLabel.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
self._message.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
self._message.setWordWrap(True)
- closeIcon = get_theme_icon(("window-close", "general_close", "gtk-close"), self._SENTINEL_ICON)
- if closeIcon is not self._SENTINEL_ICON:
- self._closeLabel = QtGui.QPushButton(closeIcon, "")
- else:
- self._closeLabel = QtGui.QPushButton("X")
- self._closeLabel.clicked.connect(self._on_close)
+ self._closeLabel = None
self._controlLayout = QtGui.QHBoxLayout()
self._controlLayout.addWidget(self._severityLabel, 1, QtCore.Qt.AlignCenter)
self._controlLayout.addWidget(self._message, 1000)
- self._controlLayout.addWidget(self._closeLabel, 1, QtCore.Qt.AlignCenter)
self._widget = QtGui.QWidget()
self._widget.setLayout(self._controlLayout)
return self._widget
def _show_error(self):
+ if self._icons is None:
+ self._icons = {
+ ErrorMessage.LEVEL_BUSY:
+ get_theme_icon(
+ #("process-working", "view-refresh", "general_refresh", "gtk-refresh")
+ ("view-refresh", "general_refresh", "gtk-refresh", )
+ ).pixmap(32, 32),
+ ErrorMessage.LEVEL_INFO:
+ get_theme_icon(
+ ("dialog-information", "general_notes", "gtk-info")
+ ).pixmap(32, 32),
+ ErrorMessage.LEVEL_ERROR:
+ get_theme_icon(
+ ("dialog-error", "app_install_error", "gtk-dialog-error")
+ ).pixmap(32, 32),
+ }
+ if self._closeLabel is None:
+ closeIcon = get_theme_icon(("window-close", "general_close", "gtk-close"), self._SENTINEL_ICON)
+ if closeIcon is not self._SENTINEL_ICON:
+ self._closeLabel = QtGui.QPushButton(closeIcon, "")
+ else:
+ self._closeLabel = QtGui.QPushButton("X")
+ self._closeLabel.clicked.connect(self._on_close)
+ self._controlLayout.addWidget(self._closeLabel, 1, QtCore.Qt.AlignCenter)
error = self._errorLog.peek_message()
self._message.setText(error.message)
self._severityLabel.setPixmap(self._icons[error.level])
self._widget.show()
- @QtCore.pyqtSlot()
- @QtCore.pyqtSlot(bool)
+ @qt_compat.Slot()
+ @qt_compat.Slot(bool)
@misc.log_exception(_moduleLogger)
def _on_close(self, checked = False):
self._errorLog.pop()
- @QtCore.pyqtSlot()
+ @qt_compat.Slot()
@misc.log_exception(_moduleLogger)
def _on_message_pushed(self):
self._show_error()
- @QtCore.pyqtSlot()
+ @qt_compat.Slot()
@misc.log_exception(_moduleLogger)
def _on_message_popped(self):
if len(self._errorLog) == 0:
doc.documentLayout().draw(painter, ctx)
painter.restore()
- def setWidth(self, width):
- # @bug we need to be emitting sizeHintChanged but it requires an index
+ def setWidth(self, width, model):
+ if self._width == width:
+ return
self._width = width
+ for c in xrange(model.rowCount()):
+ cItem = model.item(c, 0)
+ for r in xrange(model.rowCount()):
+ rItem = cItem.child(r, 0)
+ rIndex = model.indexFromItem(rItem)
+ self.sizeHintChanged.emit(rIndex)
+ return
def sizeHint(self, option, index):
newOption = QtGui.QStyleOptionViewItemV4(option)
return size
+class QSignalingMainWindow(QtGui.QMainWindow):
+
+ closed = qt_compat.Signal()
+ hidden = qt_compat.Signal()
+ shown = qt_compat.Signal()
+ resized = qt_compat.Signal()
+
+ def __init__(self, *args, **kwd):
+ QtGui.QMainWindow.__init__(*((self, )+args), **kwd)
+
+ def closeEvent(self, event):
+ val = QtGui.QMainWindow.closeEvent(self, event)
+ self.closed.emit()
+ return val
+
+ def hideEvent(self, event):
+ val = QtGui.QMainWindow.hideEvent(self, event)
+ self.hidden.emit()
+ return val
+
+ def showEvent(self, event):
+ val = QtGui.QMainWindow.showEvent(self, event)
+ self.shown.emit()
+ return val
+
+ def resizeEvent(self, event):
+ val = QtGui.QMainWindow.resizeEvent(self, event)
+ self.resized.emit()
+ return val
+
+def set_current_index(selector, itemText, default = 0):
+ for i in xrange(selector.count()):
+ if selector.itemText(i) == itemText:
+ selector.setCurrentIndex(i)
+ break
+ else:
+ itemText.setCurrentIndex(default)
+
+
def _null_set_stackable(window, isStackable):
pass
set_stackable = _null_set_stackable
-def _null_set_autorient(window, isStackable):
+def _null_set_autorient(window, doAutoOrient):
pass
-def _maemo_set_autorient(window, isStackable):
- window.setAttribute(QtCore.Qt.WA_Maemo5AutoOrientation, isStackable)
+def _maemo_set_autorient(window, doAutoOrient):
+ window.setAttribute(QtCore.Qt.WA_Maemo5AutoOrientation, doAutoOrient)
try:
def _maemo_set_window_orientation(window, orientation):
if orientation == QtCore.Qt.Vertical:
- oldHint = QtCore.Qt.WA_Maemo5LandscapeOrientation
- newHint = QtCore.Qt.WA_Maemo5PortraitOrientation
+ window.setAttribute(QtCore.Qt.WA_Maemo5LandscapeOrientation, False)
+ window.setAttribute(QtCore.Qt.WA_Maemo5PortraitOrientation, True)
elif orientation == QtCore.Qt.Horizontal:
- oldHint = QtCore.Qt.WA_Maemo5PortraitOrientation
- newHint = QtCore.Qt.WA_Maemo5LandscapeOrientation
- window.setAttribute(oldHint, False)
- window.setAttribute(newHint, True)
+ window.setAttribute(QtCore.Qt.WA_Maemo5LandscapeOrientation, True)
+ window.setAttribute(QtCore.Qt.WA_Maemo5PortraitOrientation, False)
+ elif orientation is None:
+ window.setAttribute(QtCore.Qt.WA_Maemo5LandscapeOrientation, False)
+ window.setAttribute(QtCore.Qt.WA_Maemo5PortraitOrientation, False)
+ else:
+ raise RuntimeError("Unknown orientation: %r" % orientation)
try:
import logging
-from PyQt4 import QtGui
-from PyQt4 import QtCore
+import qt_compat
+QtCore = qt_compat.QtCore
+QtGui = qt_compat.import_module("QtGui")
from util import qui_utils
from util import misc as misc_utils
class ApplicationWrapper(object):
+ DEFAULT_ORIENTATION = "Default"
+ AUTO_ORIENTATION = "Auto"
+ LANDSCAPE_ORIENTATION = "Landscape"
+ PORTRAIT_ORIENTATION = "Portrait"
+
def __init__(self, qapp, constants):
self._constants = constants
self._qapp = qapp
self._fullscreenAction.setShortcut(QtGui.QKeySequence("CTRL+Enter"))
self._fullscreenAction.toggled.connect(self._on_toggle_fullscreen)
+ self._orientation = self.DEFAULT_ORIENTATION
self._orientationAction = QtGui.QAction(None)
- self._orientationAction.setText("Orientation")
+ self._orientationAction.setText("Next Orientation")
self._orientationAction.setCheckable(True)
self._orientationAction.setShortcut(QtGui.QKeySequence("CTRL+o"))
- self._orientationAction.toggled.connect(self._on_toggle_orientation)
+ self._orientationAction.triggered.connect(self._on_next_orientation)
self._logAction = QtGui.QAction(None)
self._logAction.setText("Log")
self._idleDelay = QtCore.QTimer()
self._idleDelay.setSingleShot(True)
self._idleDelay.setInterval(0)
- self._idleDelay.timeout.connect(lambda: self._mainWindow.start())
+ self._idleDelay.timeout.connect(self._on_delayed_start)
self._idleDelay.start()
def load_settings(self):
return self._orientationAction
@property
+ def orientation(self):
+ return self._orientation
+
+ @property
def logAction(self):
return self._logAction
def quitAction(self):
return self._quitAction
+ def set_orientation(self, orientation):
+ self._orientation = orientation
+ self._mainWindow.update_orientation(self._orientation)
+
+ @classmethod
+ def _next_orientation(cls, current):
+ return {
+ cls.DEFAULT_ORIENTATION: cls.AUTO_ORIENTATION,
+ cls.AUTO_ORIENTATION: cls.LANDSCAPE_ORIENTATION,
+ cls.LANDSCAPE_ORIENTATION: cls.PORTRAIT_ORIENTATION,
+ cls.PORTRAIT_ORIENTATION: cls.DEFAULT_ORIENTATION,
+ }[current]
+
def _close_windows(self):
if self._mainWindow is not None:
self.save_settings()
self._mainWindow = None
@misc_utils.log_exception(_moduleLogger)
+ def _on_delayed_start(self):
+ self._mainWindow.start()
+
+ @misc_utils.log_exception(_moduleLogger)
def _on_app_quit(self, checked = False):
if self._mainWindow is not None:
self.save_settings()
self._mainWindow.set_fullscreen(checked)
@misc_utils.log_exception(_moduleLogger)
- def _on_toggle_orientation(self, checked = False):
+ def _on_next_orientation(self, checked = False):
with qui_utils.notify_error(self._errorLog):
- self._mainWindow.set_orientation(checked)
+ self.set_orientation(self._next_orientation(self._orientation))
@misc_utils.log_exception(_moduleLogger)
def _on_about(self, checked = True):
centralWidget.setLayout(self._superLayout)
centralWidget.setContentsMargins(0, 0, 0, 0)
- self._window = QtGui.QMainWindow(parent)
+ self._window = qui_utils.QSignalingMainWindow(parent)
self._window.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
qui_utils.set_stackable(self._window, True)
self._window.setCentralWidget(centralWidget)
def window(self):
return self._window
+ @property
+ def windowOrientation(self):
+ geom = self._window.size()
+ if geom.width() <= geom.height():
+ return QtCore.Qt.Vertical
+ else:
+ return QtCore.Qt.Horizontal
+
+ @property
+ def idealWindowOrientation(self):
+ if self._app.orientation == self._app.AUTO_ORIENTATION:
+ windowOrientation = self.windowOrientation
+ elif self._app.orientation == self._app.DEFAULT_ORIENTATION:
+ windowOrientation = qui_utils.screen_orientation()
+ elif self._app.orientation == self._app.LANDSCAPE_ORIENTATION:
+ windowOrientation = QtCore.Qt.Horizontal
+ elif self._app.orientation == self._app.PORTRAIT_ORIENTATION:
+ windowOrientation = QtCore.Qt.Vertical
+ else:
+ raise RuntimeError("Bad! No %r for you" % self._app.orientation)
+ return windowOrientation
+
def walk_children(self):
return ()
pass
def show(self):
- self.set_fullscreen(self._app.fullscreenAction.isChecked())
self._window.show()
for child in self.walk_children():
child.show()
+ self.set_fullscreen(self._app.fullscreenAction.isChecked())
def hide(self):
for child in self.walk_children():
self._window.hide()
def set_fullscreen(self, isFullscreen):
- if isFullscreen:
- self._window.showFullScreen()
- else:
- self._window.showNormal()
+ if self._window.isVisible():
+ if isFullscreen:
+ self._window.showFullScreen()
+ else:
+ self._window.showNormal()
for child in self.walk_children():
child.set_fullscreen(isFullscreen)
- def set_orientation(self, isPortrait):
- if isPortrait:
+ def update_orientation(self, orientation):
+ if orientation == self._app.DEFAULT_ORIENTATION:
+ qui_utils.set_autorient(self.window, False)
+ qui_utils.set_window_orientation(self.window, None)
+ elif orientation == self._app.AUTO_ORIENTATION:
+ qui_utils.set_autorient(self.window, True)
+ qui_utils.set_window_orientation(self.window, None)
+ elif orientation == self._app.LANDSCAPE_ORIENTATION:
+ qui_utils.set_autorient(self.window, False)
+ qui_utils.set_window_orientation(self.window, QtCore.Qt.Horizontal)
+ elif orientation == self._app.PORTRAIT_ORIENTATION:
+ qui_utils.set_autorient(self.window, False)
qui_utils.set_window_orientation(self.window, QtCore.Qt.Vertical)
else:
- qui_utils.set_window_orientation(self.window, QtCore.Qt.Horizontal)
+ raise RuntimeError("Unknown orientation: %r" % orientation)
for child in self.walk_children():
- child.set_orientation(isPortrait)
+ child.update_orientation(orientation)
@misc_utils.log_exception(_moduleLogger)
- def _on_child_close(self):
+ def _on_child_close(self, obj = None):
raise NotImplementedError("Booh")
@misc_utils.log_exception(_moduleLogger)
self.__files[path]=nfiles
+ def __getitem__(self, k):
+ return self.__files[k]
+
def __delitem__(self, k):
del self.__files[k]