X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=src%2Fejpi_qt.py;h=3210ec73ec4f3c7d23607271ed4a3eda6361acd1;hb=60a1e27f154a516ce3de1045f0550a54de342cc7;hp=02cb3c227ec9e099b578c16464bc29e9e57dbe91;hpb=9624884bd83d80899e8a0484f8031fa1e4a7dde5;p=ejpi diff --git a/src/ejpi_qt.py b/src/ejpi_qt.py index 02cb3c2..3210ec7 100755 --- a/src/ejpi_qt.py +++ b/src/ejpi_qt.py @@ -9,15 +9,16 @@ import simplejson import string import logging -from PyQt4 import QtGui from PyQt4 import QtCore +from PyQt4 import QtGui import constants -import maeqt from util import misc as misc_utils -from libraries import qtpie -from libraries import qtpieboard +from util import qui_utils +from util import qwrappers +from util import qtpie +from util import qtpieboard import plugin_utils import history import qhistory @@ -26,45 +27,13 @@ import qhistory _moduleLogger = logging.getLogger(__name__) -IS_MAEMO = True - - -PLUGIN_SEARCH_PATHS = [ - os.path.join(os.path.dirname(__file__), "plugins/"), -] - - -class Calculator(object): +class Calculator(qwrappers.ApplicationWrapper): def __init__(self, app): - self._app = app self._recent = [] self._hiddenCategories = set() self._hiddenUnits = {} - self._clipboard = QtGui.QApplication.clipboard() - self._mainWindow = None - - self._fullscreenAction = QtGui.QAction(None) - self._fullscreenAction.setText("Fullscreen") - self._fullscreenAction.setCheckable(True) - self._fullscreenAction.setShortcut(QtGui.QKeySequence("CTRL+Enter")) - self._fullscreenAction.toggled.connect(self._on_toggle_fullscreen) - - self._logAction = QtGui.QAction(None) - self._logAction.setText("Log") - self._logAction.setShortcut(QtGui.QKeySequence("CTRL+l")) - self._logAction.triggered.connect(self._on_log) - - self._quitAction = QtGui.QAction(None) - self._quitAction.setText("Quit") - self._quitAction.setShortcut(QtGui.QKeySequence("CTRL+q")) - self._quitAction.triggered.connect(self._on_quit) - - self._app.lastWindowClosed.connect(self._on_app_quit) - self.load_settings() - - self._mainWindow = MainWindow(None, self) - self._mainWindow.window.destroyed.connect(self._on_child_close) + qwrappers.ApplicationWrapper.__init__(self, app, constants) def load_settings(self): try: @@ -77,129 +46,46 @@ class Calculator(object): _moduleLogger.info("Settings were corrupt") settings = {} + isPortraitDefault = qui_utils.screen_orientation() == QtCore.Qt.Vertical self._fullscreenAction.setChecked(settings.get("isFullScreen", False)) + self._orientationAction.setChecked(settings.get("isPortrait", isPortraitDefault)) def save_settings(self): settings = { "isFullScreen": self._fullscreenAction.isChecked(), + "isPortrait": self._orientationAction.isChecked(), } with open(constants._user_settings_, "w") as settingsFile: simplejson.dump(settings, settingsFile) @property - def fullscreenAction(self): - return self._fullscreenAction - - @property - def logAction(self): - return self._logAction - - @property - def quitAction(self): - return self._quitAction + def dataPath(self): + return self._dataPath - def _close_windows(self): - if self._mainWindow is not None: - self._mainWindow.window.destroyed.disconnect(self._on_child_close) - self._mainWindow.close() - self._mainWindow = None - - @misc_utils.log_exception(_moduleLogger) - def _on_app_quit(self, checked = False): - self.save_settings() - - @misc_utils.log_exception(_moduleLogger) - def _on_child_close(self, obj = None): - self._mainWindow = None + def _new_main_window(self): + return MainWindow(None, self) @misc_utils.log_exception(_moduleLogger) - def _on_toggle_fullscreen(self, checked = False): - for window in self._walk_children(): - window.set_fullscreen(checked) - - @misc_utils.log_exception(_moduleLogger) - def _on_log(self, checked = False): - with open(constants._user_logpath_, "r") as f: - logLines = f.xreadlines() - log = "".join(logLines) - self._clipboard.setText(log) - - @misc_utils.log_exception(_moduleLogger) - def _on_quit(self, checked = False): - self._close_windows() - - -class QErrorDisplay(object): - - def __init__(self): - self._messages = [] - - icon = QtGui.QIcon.fromTheme("gtk-dialog-error") - self._severityIcon = icon.pixmap(32, 32) - self._severityLabel = QtGui.QLabel() - self._severityLabel.setPixmap(self._severityIcon) - - self._message = QtGui.QLabel() - self._message.setText("Boo") - - icon = QtGui.QIcon.fromTheme("gtk-close") - self._closeIcon = icon.pixmap(32, 32) - self._closeLabel = QtGui.QLabel() - self._closeLabel.setPixmap(self._closeIcon) - - self._controlLayout = QtGui.QHBoxLayout() - self._controlLayout.addWidget(self._severityLabel) - self._controlLayout.addWidget(self._message) - self._controlLayout.addWidget(self._closeLabel) - - self._topLevelLayout = QtGui.QHBoxLayout() - - @property - def toplevel(self): - return self._topLevelLayout - - def push_message(self, message): - self._messages.append(message) - if 1 == len(self._messages): - self._show_message(message) - - def push_exception(self): - userMessage = str(sys.exc_info()[1]) - _moduleLogger.exception(userMessage) - self.push_message(userMessage) - - def pop_message(self): - del self._messages[0] - if 0 == len(self._messages): - self._hide_message() - else: - self._message.setText(self._messages[0]) - - def _on_close(self, *args): - self.pop_message() - - def _show_message(self, message): - self._message.setText(message) - self._topLevelLayout.addLayout(self._controlLayout) - - def _hide_message(self): - self._message.setText("") - self._topLevelLayout.removeItem(self._controlLayout) + def _on_about(self, checked = True): + raise NotImplementedError("Booh") class QValueEntry(object): def __init__(self): self._widget = QtGui.QLineEdit("") - self._widget.setInputMethodHints(QtCore.Qt.ImhPreferNumbers) - self._actualEntryDisplay = "" + qui_utils.mark_numbers_preferred(self._widget) @property def toplevel(self): return self._widget + @property + def entry(self): + return self._widget + def get_value(self): - value = self._actualEntryDisplay.strip() + value = str(self._widget.text()).strip() if any( 0 < value.find(whitespace) for whitespace in string.whitespace @@ -215,7 +101,6 @@ class QValueEntry(object): for whitespace in string.whitespace ): raise ValueError('Invalid input "%s"' % value) - self._actualEntryDisplay = value self._widget.setText(value) def append(self, value): @@ -237,75 +122,57 @@ class QValueEntry(object): value = property(get_value, set_value, clear) -class MainWindow(object): +class MainWindow(qwrappers.WindowWrapper): _plugin_search_paths = [ - "/opt/epi/lib/plugins/", - "/usr/lib/ejpi/plugins/", os.path.join(os.path.dirname(__file__), "plugins/"), ] _user_history = "%s/history.stack" % constants._data_path_ def __init__(self, parent, app): - self._app = app - - self._historyView = qhistory.QCalcHistory() - - self._errorDisplay = QErrorDisplay() + qwrappers.WindowWrapper.__init__(self, parent, app) + self._window.setWindowTitle("%s" % constants.__pretty_app_name__) + self._freezer = qwrappers.AutoFreezeWindowFeature(self._app, self._window) + self._historyView = qhistory.QCalcHistory(self._app.errorLog) self._userEntry = QValueEntry() + self._userEntry.entry.returnPressed.connect(self._on_push) + self._userEntryLayout = QtGui.QHBoxLayout() + self._userEntryLayout.setContentsMargins(0, 0, 0, 0) + self._userEntryLayout.addWidget(self._userEntry.toplevel, 10) self._controlLayout = QtGui.QVBoxLayout() - self._controlLayout.addLayout(self._errorDisplay.toplevel) - self._controlLayout.addWidget(self._historyView.toplevel) - self._controlLayout.addWidget(self._userEntry.toplevel) + self._controlLayout.setContentsMargins(0, 0, 0, 0) + self._controlLayout.addWidget(self._historyView.toplevel, 1000) + self._controlLayout.addLayout(self._userEntryLayout, 0) - self._pluginKeyboardSpot = QtGui.QVBoxLayout() - self._inputLayout = QtGui.QVBoxLayout() - self._inputLayout.addLayout(self._pluginKeyboardSpot) + self._keyboardTabs = QtGui.QTabWidget() - self._layout = QtGui.QHBoxLayout() self._layout.addLayout(self._controlLayout) - self._layout.addLayout(self._inputLayout) + self._layout.addWidget(self._keyboardTabs) - centralWidget = QtGui.QWidget() - centralWidget.setLayout(self._layout) + self._copyItemAction = QtGui.QAction(None) + self._copyItemAction.setText("Copy") + self._copyItemAction.setShortcut(QtGui.QKeySequence("CTRL+c")) + self._copyItemAction.triggered.connect(self._on_copy) - self._window = QtGui.QMainWindow(parent) - self._window.setAttribute(QtCore.Qt.WA_DeleteOnClose, True) - maeqt.set_autorient(self._window, True) - maeqt.set_stackable(self._window, True) - self._window.setWindowTitle("%s" % constants.__pretty_app_name__) - self._window.setCentralWidget(centralWidget) - self._window.destroyed.connect(self._on_close_window) + self._pasteItemAction = QtGui.QAction(None) + self._pasteItemAction.setText("Paste") + self._pasteItemAction.setShortcut(QtGui.QKeySequence("CTRL+v")) + self._pasteItemAction.triggered.connect(self._on_paste) self._closeWindowAction = QtGui.QAction(None) self._closeWindowAction.setText("Close") self._closeWindowAction.setShortcut(QtGui.QKeySequence("CTRL+w")) self._closeWindowAction.triggered.connect(self._on_close_window) - if IS_MAEMO: - #fileMenu = self._window.menuBar().addMenu("&File") - - #viewMenu = self._window.menuBar().addMenu("&View") - - self._window.addAction(self._closeWindowAction) - self._window.addAction(self._app.quitAction) - self._window.addAction(self._app.fullscreenAction) - else: - fileMenu = self._window.menuBar().addMenu("&Units") - fileMenu.addAction(self._closeWindowAction) - fileMenu.addAction(self._app.quitAction) - - viewMenu = self._window.menuBar().addMenu("&View") - viewMenu.addAction(self._app.fullscreenAction) - - self._window.addAction(self._app.logAction) + self._window.addAction(self._copyItemAction) + self._window.addAction(self._pasteItemAction) self._constantPlugins = plugin_utils.ConstantPluginManager() self._constantPlugins.add_path(*self._plugin_search_paths) - for pluginName in ["Builtin", "Trigonometry", "Computer", "Alphabet"]: + for pluginName in ["Builtins", "Trigonometry", "Computer", "Alphabet"]: try: pluginId = self._constantPlugins.lookup_plugin(pluginName) self._constantPlugins.enable_plugin(pluginId) @@ -314,7 +181,7 @@ class MainWindow(object): self._operatorPlugins = plugin_utils.OperatorPluginManager() self._operatorPlugins.add_path(*self._plugin_search_paths) - for pluginName in ["Builtin", "Trigonometry", "Computer", "Alphabet"]: + for pluginName in ["Builtins", "Trigonometry", "Computer", "Alphabet"]: try: pluginId = self._operatorPlugins.lookup_plugin(pluginName) self._operatorPlugins.enable_plugin(pluginId) @@ -327,7 +194,7 @@ class MainWindow(object): self._history = history.RpnCalcHistory( self._historyView, - self._userEntry, self._errorDisplay, + self._userEntry, self._app.errorLog, self._constantPlugins.constants, self._operatorPlugins.operators ) self._load_history() @@ -340,57 +207,55 @@ class MainWindow(object): self._handler.register_command_handler("clear", self._on_entry_clear) # Main keyboard - builtinKeyboardId = self._keyboardPlugins.lookup_plugin("Builtin") - self._keyboardPlugins.enable_plugin(builtinKeyboardId) - self._builtinPlugin = self._keyboardPlugins.keyboards["Builtin"].construct_keyboard() - self._builtinKeyboard = self._builtinPlugin.setup(self._history, self._handler) - self._inputLayout.addLayout(self._builtinKeyboard.toplevel) + entryKeyboardId = self._keyboardPlugins.lookup_plugin("Entry") + self._keyboardPlugins.enable_plugin(entryKeyboardId) + entryPlugin = self._keyboardPlugins.keyboards["Entry"].construct_keyboard() + entryKeyboard = entryPlugin.setup(self._history, self._handler) + self._userEntryLayout.addWidget(entryKeyboard.toplevel) # Plugins + self.enable_plugin(self._keyboardPlugins.lookup_plugin("Builtins")) self.enable_plugin(self._keyboardPlugins.lookup_plugin("Trigonometry")) self.enable_plugin(self._keyboardPlugins.lookup_plugin("Computer")) self.enable_plugin(self._keyboardPlugins.lookup_plugin("Alphabet")) - self._set_plugin_kb(0) - self.set_fullscreen(self._app.fullscreenAction.isChecked()) - self._window.show() + self._scrollTimer = QtCore.QTimer() + self._scrollTimer.setInterval(0) + self._scrollTimer.setSingleShot(True) + self._scrollTimer.timeout.connect(self._on_delayed_scroll_to_bottom) + self._scrollTimer.start() - @property - def window(self): - return self._window + self.set_fullscreen(self._app.fullscreenAction.isChecked()) + self.set_orientation(self._app.orientationAction.isChecked()) def walk_children(self): return () - def show(self): - self._window.show() - for child in self.walk_children(): - child.show() - - def hide(self): - for child in self.walk_children(): - child.hide() - self._window.hide() - - def close(self): - for child in self.walk_children(): - child.window.destroyed.disconnect(self._on_child_close) - child.close() - self._window.close() - - def set_fullscreen(self, isFullscreen): - if isFullscreen: - self._window.showFullScreen() + def set_orientation(self, isPortrait): + qwrappers.WindowWrapper.set_orientation(self, isPortrait) + if isPortrait: + defaultLayoutOrientation = QtGui.QBoxLayout.TopToBottom + #tabPosition = QtGui.QTabWidget.South + tabPosition = QtGui.QTabWidget.West else: - self._window.showNormal() - for child in self.walk_children(): - child.set_fullscreen(isFullscreen) + defaultLayoutOrientation = QtGui.QBoxLayout.LeftToRight + tabPosition = QtGui.QTabWidget.North + self._layout.setDirection(defaultLayoutOrientation) + self._keyboardTabs.setTabPosition(tabPosition) def enable_plugin(self, pluginId): self._keyboardPlugins.enable_plugin(pluginId) pluginData = self._keyboardPlugins.plugin_info(pluginId) pluginName = pluginData[0] plugin = self._keyboardPlugins.keyboards[pluginName].construct_keyboard() + relIcon = self._keyboardPlugins.keyboards[pluginName].icon + for iconPath in self._keyboardPlugins.keyboards[pluginName].iconPaths: + absIconPath = os.path.join(iconPath, relIcon) + if os.path.exists(absIconPath): + icon = QtGui.QIcon(absIconPath) + break + else: + icon = None pluginKeyboard = plugin.setup(self._history, self._handler) self._activeKeyboards.append({ @@ -398,15 +263,14 @@ class MainWindow(object): "plugin": plugin, "pluginKeyboard": pluginKeyboard, }) + if icon is None: + self._keyboardTabs.addTab(pluginKeyboard.toplevel, pluginName) + else: + self._keyboardTabs.addTab(pluginKeyboard.toplevel, icon, "") - def _set_plugin_kb(self, pluginIndex): - plugin = self._activeKeyboards[pluginIndex] - # @todo self._pluginButton.set_label(plugin["pluginName"]) - - for i in xrange(self._pluginKeyboardSpot.count()): - self._pluginKeyboardSpot.removeItem(self._pluginKeyboardSpot.itemAt(i)) - pluginKeyboard = plugin["pluginKeyboard"] - self._pluginKeyboardSpot.addItem(pluginKeyboard.toplevel) + def close(self): + qwrappers.WindowWrapper.close(self) + self._save_history() def _load_history(self): serialized = [] @@ -429,34 +293,59 @@ class MainWindow(object): f.write("%s\n" % line) @misc_utils.log_exception(_moduleLogger) + def _on_delayed_scroll_to_bottom(self): + with qui_utils.notify_error(self._app.errorLog): + self._historyView.scroll_to_bottom() + + @misc_utils.log_exception(_moduleLogger) + def _on_child_close(self, something = None): + with qui_utils.notify_error(self._app.errorLog): + self._child = None + + @misc_utils.log_exception(_moduleLogger) + def _on_copy(self, *args): + with qui_utils.notify_error(self._app.errorLog): + eqNode = self._historyView.peek() + resultNode = eqNode.simplify() + self._app._clipboard.setText(str(resultNode)) + + @misc_utils.log_exception(_moduleLogger) + def _on_paste(self, *args): + with qui_utils.notify_error(self._app.errorLog): + result = str(self._app._clipboard.text()) + self._userEntry.append(result) + + @misc_utils.log_exception(_moduleLogger) def _on_entry_direct(self, keys, modifiers): - if "shift" in modifiers: - keys = keys.upper() - self._userEntry.append(keys) + with qui_utils.notify_error(self._app.errorLog): + if "shift" in modifiers: + keys = keys.upper() + self._userEntry.append(keys) @misc_utils.log_exception(_moduleLogger) def _on_push(self, *args): - self._history.push_entry() + with qui_utils.notify_error(self._app.errorLog): + self._history.push_entry() @misc_utils.log_exception(_moduleLogger) def _on_unpush(self, *args): - self._historyStore.unpush() + with qui_utils.notify_error(self._app.errorLog): + self._historyView.unpush() @misc_utils.log_exception(_moduleLogger) def _on_entry_backspace(self, *args): - self._userEntry.pop() + with qui_utils.notify_error(self._app.errorLog): + self._userEntry.pop() @misc_utils.log_exception(_moduleLogger) def _on_entry_clear(self, *args): - self._userEntry.clear() + with qui_utils.notify_error(self._app.errorLog): + self._userEntry.clear() @misc_utils.log_exception(_moduleLogger) def _on_clear_all(self, *args): - self._history.clear() - - @misc_utils.log_exception(_moduleLogger) - def _on_close_window(self, checked = True): - self._save_history() + with qui_utils.notify_error(self._app.errorLog): + self._history.clear() def run():