def build_menu(self): if ConfigManager.SETTINGS[SHOW_TRAY_ICON]: # Get phrase folders to add to main menu folders = [] items = [] for folder in self.configManager.allFolders: if folder.showInTrayMenu: folders.append(folder) for item in self.configManager.allItems: if item.showInTrayMenu: items.append(item) # Construct main menu menu = popupmenu.PopupMenu(self.app.service, folders, items, False, "AutoKey") if len(items) > 0: menu.addSeparator() self.toggleAction = KToggleAction(i18n("&Enable Monitoring"), menu) self.toggleAction.connect(self.toggleAction, SIGNAL("triggered()"), self.on_enable_toggled) self.toggleAction.setChecked(self.app.service.is_running()) self.toggleAction.setEnabled(not self.app.serviceDisabled) menu.addAction(self.toggleAction) menu.addAction(KIcon("edit-clear"), i18n("&Hide Icon"), self.on_hide_icon) menu.addAction(KIcon("configure"), i18n("&Show Main Window"), self.on_configure) menu.addAction(KStandardAction.quit(self.on_quit, menu)) self.icon.setContextMenu(menu)
def create_actions(self): """Create actions for the main window.""" self.connect_action = KAction(KIcon("document-open-remote"), i18n("Connect"), self) self.fetch_action = KAction(KIcon("download"), i18n("Download"), self) self.clean_action = KAction(KIcon("trash-empty"), i18n("Clear thumbnail cache"), self) self.batch_download_action = KAction(KIcon("download"), i18n("Batch download"), self) self.pool_toggle_action = KToggleAction(KIcon("image-x-generic"), i18n("Pools"), self) self.tag_display_action = KDualAction(i18n("Show tags"), i18n("Hide tags"), self) self.tag_display_action.setIconForStates(KIcon("image-x-generic")) self.tag_display_action.setEnabled(False) # Shortcuts connect_default = KAction.ShortcutTypes(KAction.DefaultShortcut) connect_active = KAction.ShortcutTypes(KAction.ActiveShortcut) self.connect_action.setShortcut(KStandardShortcut.open()) self.fetch_action.setShortcut(KStandardShortcut.find()) self.fetch_action.setEnabled(False) self.batch_download_action.setEnabled(False) self.pool_toggle_action.setEnabled(False)
def setup_actions(self): self.touchpad_on_action = KToggleAction( i18nc('@action:inmenu', 'Touchpad on'), self.actionCollection()) self.actionCollection().addAction( 'touchpadOn', self.touchpad_on_action) self.touchpad_on_action.setGlobalShortcut( KShortcut(i18nc('Touchpad toggle shortcut', 'Ctrl+Alt+T'))) self.contextMenu().addAction(self.touchpad_on_action) self.contextMenu().addSeparator() shortcuts = self.actionCollection().addAction( KStandardAction.KeyBindings, 'shortcuts') shortcuts.triggered.connect(self.show_shortcuts_dialog) self.contextMenu().addAction(shortcuts) self.preferences_action = self.actionCollection().addAction( KStandardAction.Preferences, 'preferences') self.preferences_action.triggered.connect( self.show_configuration_dialog) self.contextMenu().addAction(self.preferences_action) help_menu = KHelpMenu(self.contextMenu(), KCmdLineArgs.aboutData()) self.contextMenu().addMenu(help_menu.menu())
class Notifier: def __init__(self, app): self.app = app self.configManager = app.configManager self.icon = KSystemTrayIcon(ConfigManager.SETTINGS[NOTIFICATION_ICON]) self.icon.connect( self.icon, SIGNAL("activated(QSystemTrayIcon::ActivationReason)"), self.on_activate) self.build_menu() self.update_tool_tip() if ConfigManager.SETTINGS[SHOW_TRAY_ICON]: self.icon.show() def update_tool_tip(self): if ConfigManager.SETTINGS[SERVICE_RUNNING]: self.icon.setToolTip(TOOLTIP_RUNNING.toString()) self.toggleAction.setChecked(True) else: self.icon.setToolTip(TOOLTIP_PAUSED.toString()) self.toggleAction.setChecked(False) def build_menu(self): if ConfigManager.SETTINGS[SHOW_TRAY_ICON]: # Get phrase folders to add to main menu folders = [] items = [] for folder in self.configManager.allFolders: if folder.showInTrayMenu: folders.append(folder) for item in self.configManager.allItems: if item.showInTrayMenu: items.append(item) # Construct main menu menu = popupmenu.PopupMenu(self.app.service, folders, items, False, "AutoKey") if len(items) > 0: menu.addSeparator() self.toggleAction = KToggleAction(i18n("&Enable Monitoring"), menu) self.toggleAction.connect(self.toggleAction, SIGNAL("triggered()"), self.on_enable_toggled) self.toggleAction.setChecked(self.app.service.is_running()) self.toggleAction.setEnabled(not self.app.serviceDisabled) menu.addAction(self.toggleAction) menu.addAction(KIcon("edit-clear"), i18n("&Hide Icon"), self.on_hide_icon) menu.addAction(KIcon("configure"), i18n("&Show Main Window"), self.on_configure) menu.addAction(KStandardAction.quit(self.on_quit, menu)) self.icon.setContextMenu(menu) def update_visible_status(self): self.icon.setVisible(ConfigManager.SETTINGS[SHOW_TRAY_ICON]) self.build_menu() def hide_icon(self): if ConfigManager.SETTINGS[SHOW_TRAY_ICON]: self.icon.hide() def notify_error(self, message): pass # ---- Signal handlers ---- def on_show_error(self): self.app.exec_in_main(self.app.show_script_error) def on_quit(self): self.app.shutdown() def on_activate(self, reason): if reason == QSystemTrayIcon.ActivationReason(QSystemTrayIcon.Trigger): self.on_configure() def on_configure(self): self.app.show_configure() def on_enable_toggled(self): if self.toggleAction.isChecked(): self.app.unpause_service() else: self.app.pause_service() def on_hide_icon(self): self.icon.hide() ConfigManager.SETTINGS[SHOW_TRAY_ICON] = False
class MainWindow(KXmlGuiWindow): CHOOSER_PLUGINS = [ # TODO reenable (radicalpage.RadicalPage, ki18n('&Radicals')), (componentpage.ComponentPage, ki18n('&Components')), (handwritingpage.HandwritingPage, ki18n('Hand&writing')), (vocabularypage.VocabularyPage, ki18n('&Vocabulary')), ] """Plugins loaded into the side panel.""" def __init__(self): QMainWindow.__init__(self) self.miniMode = False self.initialised = False # set i18n language for libeclectus setTranslationLanguage(unicode(KGlobal.locale().language())) # start rendering thread self.renderThread = renderthread.SQLRenderThread(g_app) self.connect(g_app, SIGNAL("aboutToQuit()"), self.renderThread.quit) self.renderThread.start() self.connect(self.renderThread, SIGNAL("queueEmpty"), self.queueEmpty) self.connect(self.renderThread, SIGNAL("jobEnqueued"), self.jobEnqueued) self.connect(self.renderThread, SIGNAL("jobErrorneous"), lambda jobId, classObject, method, args, param, e, stacktrace: \ showDebug(stacktrace.decode('utf8'))) self.updateDialog = update.UpdateDialog(self, self.renderThread) #self.updateDialog = None # set to None to disable updating if self.updateDialog: self.connect(self.updateDialog, SIGNAL("databaseChanged()"), lambda: self.emit(SIGNAL("databaseChanged()"))) # set up UI self.setupUi() self.setupActions() # finally build gui xmlFile = os.path.join(os.getcwd(), 'eclectusqt', 'eclectusui.rc') if os.path.exists(xmlFile): self.setupGUI(KXmlGuiWindow.StandardWindowOption( KXmlGuiWindow.Default ^ KXmlGuiWindow.StatusBar), xmlFile) else: self.setupGUI(KXmlGuiWindow.StandardWindowOption( KXmlGuiWindow.Default ^ KXmlGuiWindow.StatusBar)) self.restoreWindowState() self.setCentralWidget(self.splitterFrame) self.splitterFrame.setVisible(True) self.initialised = True if (GeneralConfig.readEntry("Show installer on startup", 'True') == 'True') and self.updateAction: self.updateAction.trigger() def setupUi(self): self.setWindowIcon(QIcon(util.getIcon('eclectus.png'))) self.splitterFrame = QtGui.QSplitter(self) self.splitterFrame.setOrientation(QtCore.Qt.Horizontal) self.characterChooser = QtGui.QToolBox(self.splitterFrame) self.characterChooser.setFrameShape(QtGui.QFrame.StyledPanel) self.dictionaryPage = dictionarypage.DictionaryPage(self, self.renderThread, PluginConfig) self.connect(self.dictionaryPage, SIGNAL('pageChanged(const QString &)'), self.slotPageChanged) # forward settingsChanged self.connect(self.dictionaryPage, SIGNAL("settingsChanged()"), lambda: self.emit(SIGNAL("settingsChanged()"))) # TODO make this modular self.connect(self.dictionaryPage, SIGNAL("vocabularyAdded(const QString &, const QString &, const QString &, const QString &)"), self.slotVocabularyAdded) self.connect(self.dictionaryPage, SIGNAL("modeChanged(bool)"), self.slotMiniMode) self.splitterFrame.addWidget(self.characterChooser) self.splitterFrame.addWidget(self.dictionaryPage) # load sidebar plugins self.plugins = [] self.vocabularyPlugin = None for classObj, heading in self.CHOOSER_PLUGINS: page = classObj(self, self.renderThread, PluginConfig) if not self.vocabularyPlugin \ and isinstance(page, vocabularypage.VocabularyPage): self.vocabularyPlugin = len(self.plugins) self.characterChooser.addItem(page, heading.toString()) self.connect(page, SIGNAL('inputReceived(const QString &)'), self.dictionaryPage.load) self.plugins.append(page) self.splitterFrame.setVisible(False) self.setCentralWidget(QLabel(i18n('Installing basic tables...'))) def setupActions(self): """Sets up all actions (signal/slot combinations).""" # standard action KStandardAction.quit(g_app.quit, self.actionCollection()) # dictionary actions self.dictionaryPage.registerGlobalActions(self.actionCollection()) # update dictionaries if self.updateDialog: self.updateAction = self.updateDialog.updateAction( self.actionCollection()) # optimise database self.updateDialog.optimiseAction(self.actionCollection()) else: self.updateAction = None # search bar self.characterCombo = KHistoryComboBox() self.characterCombo.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) font = QFont() font.setPointSize(13) self.characterCombo.setFont(font) self.characterCombo.setObjectName("characterCombo") self.connect(self.characterCombo, SIGNAL("activated(const QString &)"), self.slotCharacterComboActivated) comboAction = KAction(self) comboAction.setText(i18n("Search bar")) comboAction.setShortcut(Qt.Key_F6) self.connect(comboAction, SIGNAL("triggered()"), self.slotSearchComboActivated) comboAction.setDefaultWidget(self.characterCombo) comboAction.setWhatsThis( i18n("<html>Search bar<br/><br/>Enter character of search string</html>")) self.actionCollection().addAction("searchbar", comboAction) goUrl = self.actionCollection().addAction("go_search") goUrl.setIcon(KIcon("go-jump-locationbar")) goUrl.setText(i18n("Go")) self.connect(goUrl, SIGNAL("triggered()"), lambda: self.slotCharacterComboActivated( self.characterCombo.currentText())) goUrl.setWhatsThis( i18n("<html>Go<br /><br />Searches for the string given in the search bar.</html>")) # clear search bar action clearLocationAction = KAction(KIcon("edit-clear-locationbar-ltr"), i18n("Clear &Location Bar"), self) clearLocationAction.setShortcut(Qt.CTRL + Qt.Key_L) clearLocationAction.setWhatsThis( i18n("Clears the location bar and places the cursor inside")) self.actionCollection().addAction("clearlocationbar", clearLocationAction) self.connect(clearLocationAction, SIGNAL("triggered(bool)"), self.characterCombo.clearEditText) self.connect(clearLocationAction, SIGNAL("triggered(bool)"), self.characterCombo.setFocus) # show/hide character page self.toggleToolboxAction = KToggleAction(KIcon("view-sidetree"), i18n("Show Character Toolbox"), self) self.toggleToolboxAction.setShortcut(Qt.Key_F9) self.toggleToolboxAction.setWhatsThis( i18n("Shows and Hides the character choosing toolbox")) self.actionCollection().addAction("showtoolbox", self.toggleToolboxAction) self.connect(self.toggleToolboxAction, SIGNAL("triggered(bool)"), self.slotToggleToolbox) # auto-lookup clipboard self.autoLookupAction = KToggleAction(i18n("&Auto-Lookup"), self) self.autoLookupAction.setToolTip( i18n("Automatically look up text selected by the mouse cursor.")) self.autoLookupAction.setWhatsThis( i18n("Automatically look up text selected by the mouse cursor.")) self.actionCollection().addAction("autolookup", self.autoLookupAction) self.connect(self.autoLookupAction, SIGNAL("triggered(bool)"), self.setAutoLookup) self.autoLookupAction.setIcon( QIcon(util.getIcon('auto-lookup-selection.png'))) self.connect(QApplication.clipboard(), SIGNAL("selectionChanged()"), self.slotSelectionChanged) def restoreWindowState(self): # GUI settings history = util.readConfigString(GeneralConfig, "Url History", '')\ .split(',') self.characterCombo.insertItems(history) self.historyLength = util.readConfigInt(GeneralConfig, "History Length", 20) self.autoLookup = util.readConfigString(GeneralConfig, "Auto-Lookup clipboard", str(False)) != "False" self.autoLookupAction.setChecked(self.autoLookup) self.onlyAutoLookupCJKCharacters = util.readConfigString(GeneralConfig, "Auto-Lookup only Chinese characters", str(False)) != "False" self.splitterFrame.restoreState(QByteArray.fromBase64( str(util.readConfigString(GeneralConfig, "Splitter", "")))) self.splitterSizes = [int(i) for i \ in util.readConfigString(GeneralConfig, "Splitter sizes", "220,426").split(',')] self.toolbarOriginalState = QByteArray.fromBase64( str(util.readConfigString(GeneralConfig, "Toolbar original state", ""))) self.restoreState(self.toolbarOriginalState) self.menuBar().setVisible(True) self.characterChooser.setCurrentIndex(util.readConfigInt(GeneralConfig, "Toolbox current", 0)) visible = GeneralConfig.readEntry("Toolbox visibile", str(True)) if visible == "False": self.characterChooserOriginalVisibility = False else: self.splitterFrame.setSizes(self.splitterSizes) self.characterChooserOriginalVisibility = True self.characterChooser.setVisible( self.characterChooserOriginalVisibility) self.toggleToolboxAction.setChecked( self.characterChooserOriginalVisibility) w = util.readConfigInt(GeneralConfig, "Width", 640) h = util.readConfigInt(GeneralConfig, "Height", 420) self.defaultWindowSize = QSize(w, h) x = util.readConfigInt(GeneralConfig, "LastX", 0) y = util.readConfigInt(GeneralConfig, "LastY", 0) mini_w = util.readConfigInt(GeneralConfig, "Mini-mode Width", 400) mini_h = util.readConfigInt(GeneralConfig, "Mini-mode Height", 200) self.miniModeWindowSize = QSize(mini_w, mini_h) self.setGeometry(x, y, w, h) def queryExit(self): """ save config data before exiting """ self.emit(SIGNAL("writeSettings()")) if self.miniMode: self.miniModeWindowSize = self.size() else: self.defaultWindowSize = self.size() GeneralConfig.writeEntry("Width", str(self.defaultWindowSize.width())) GeneralConfig.writeEntry("Height", str(self.defaultWindowSize.height())) GeneralConfig.writeEntry("LastX", str(self.x())) GeneralConfig.writeEntry("LastY", str(self.y())) GeneralConfig.writeEntry("Mini-mode Width", str(self.miniModeWindowSize.width())) GeneralConfig.writeEntry("Mini-mode Height", str(self.miniModeWindowSize.height())) GeneralConfig.writeEntry("Show installer on startup", 'False') GeneralConfig.writeEntry("Url History", self.characterCombo.historyItems()[:self.historyLength]) GeneralConfig.writeEntry("Splitter", QByteArray.toBase64(self.splitterFrame.saveState())) GeneralConfig.writeEntry("Auto-Lookup clipboard", str(self.autoLookup)) GeneralConfig.writeEntry("Auto-Lookup only Chinese characters", str(self.onlyAutoLookupCJKCharacters)) # toolbox if self.characterChooser.isVisible(): self.splitterSizes = self.splitterFrame.sizes() GeneralConfig.writeEntry("Splitter sizes", ",".join( [str(i) for i in self.splitterSizes])) if not self.miniMode: self.toolbarOriginalState = self.saveState(0) GeneralConfig.writeEntry("Toolbar original state", QByteArray.toBase64(self.toolbarOriginalState)) GeneralConfig.writeEntry("Toolbox current", str(self.characterChooser.currentIndex())) GeneralConfig.writeEntry("Toolbox visibile", str(self.characterChooserOriginalVisibility)) return True def settings(self): return self.dictionaryPage.settings() def slotToggleToolbox(self, show): if not self.miniMode: self.showToolbox(show) self.characterChooserOriginalVisibility = show def showToolbox(self, show): # save / restore size as hiding makes Qt forget if self.characterChooser.isVisible(): self.splitterSizes = self.splitterFrame.sizes() else: self.splitterFrame.setSizes(self.splitterSizes) self.characterChooser.setVisible(show) def slotMiniMode(self, miniMode): self.miniMode = miniMode if not self.miniMode: # restore original state if given if self.toolbarOriginalState: self.restoreState(self.toolbarOriginalState, 0) self.menuBar().setVisible(True) self.showToolbox(self.characterChooserOriginalVisibility) self.miniModeWindowSize = self.size() self.resize(self.defaultWindowSize) else: # save original state of toolbars self.toolbarOriginalState = self.saveState(0) for toolbar in self.toolBars(): toolbar.setVisible(False) self.menuBar().setVisible(False) self.characterChooserOriginalVisibility \ = self.characterChooser.isVisible() self.showToolbox(False) self.defaultWindowSize = self.size() self.resize(self.miniModeWindowSize) # tell user what to do # TODO renable #miniModeShortcut = unicode(i18n( #self.miniModeAction.shortcut().toString())) #text = unicode(i18n("Mini-mode hides your menubar and toolbars. Press %1 again to get back to normal mode.", miniModeShortcut)) #lookupShortcut = self.lookupClipboardAction.globalShortcut()\ #.toString(QtGui.QKeySequence.NativeText) #if lookupShortcut: #text = text + "\n\n" \ #+ unicode(i18n("You may look up entries by selecting a word and pressing %1. Alternatively you can turn on auto-lookup or paste from the clipboard by pressing the middle mouse button.", #i18n(lookupShortcut))) #KMessageBox.information(self, text, i18n("Mini-mode"), #"show_mini-mode_notice") def slotCharacterComboActivated(self, inputString): self.characterCombo.addToHistory(inputString) self.dictionaryPage.load(inputString) self.dictionaryPage.setFocus() def slotSearchComboActivated(self): self.characterCombo.setFocus() self.characterCombo.lineEdit().selectAll() def setAutoLookup(self, selected): self.autoLookup = selected def slotSelectionChanged(self): if self.autoLookup: # don't auto lookup when user is editing one of our edit widgets focusWidget = QApplication.focusWidget() if focusWidget: for editWidgetCls in [kdeui.KHistoryComboBox, kdeui.KLineEdit]: if isinstance(focusWidget, editWidgetCls): return clipboardText = unicode(QApplication.clipboard().text( QClipboard.Selection).simplified()).strip() if not clipboardText or len(clipboardText) >= 20: return if (self.onlyAutoLookupCJKCharacters and not MainWindow.hasCJKCharacter(clipboardText)): return self.dictionaryPage.load(clipboardText) # make window flash in taskbar self.activateWindow() @staticmethod def hasCJKCharacter(string): """ Simple function for telling if a Chinese character or other CJK script is present. """ for char in string: if getCJKScriptClass(char) != None: return True return False def slotPageChanged(self, pageName): # dictionary page changed self.emit(SIGNAL("pageRequested(const QString &)"), pageName) # Temporarily hide default internal pageTypes if unicode(pageName).count(':'): pageType, page = unicode(pageName).split(':') if pageType in ['character', 'word']: pageName = page self.characterCombo.setEditText(pageName) # TODO mask page type def slotVocabularyAdded(self, headword, reading, translation, audio): self.emit(SIGNAL("vocabularyAdded(const QString &, const QString &, const QString &, const QString &)"), headword, reading, translation, audio) if self.vocabularyPlugin != None: self.characterChooser.setCurrentIndex(self.vocabularyPlugin) def queueEmpty(self): QApplication.restoreOverrideCursor() def jobEnqueued(self, jobId): if not QApplication.overrideCursor(): QApplication.setOverrideCursor(QCursor(Qt.BusyCursor))
def setupActions(self): """Sets up all actions (signal/slot combinations).""" # standard action KStandardAction.quit(g_app.quit, self.actionCollection()) # dictionary actions self.dictionaryPage.registerGlobalActions(self.actionCollection()) # update dictionaries if self.updateDialog: self.updateAction = self.updateDialog.updateAction( self.actionCollection()) # optimise database self.updateDialog.optimiseAction(self.actionCollection()) else: self.updateAction = None # search bar self.characterCombo = KHistoryComboBox() self.characterCombo.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) font = QFont() font.setPointSize(13) self.characterCombo.setFont(font) self.characterCombo.setObjectName("characterCombo") self.connect(self.characterCombo, SIGNAL("activated(const QString &)"), self.slotCharacterComboActivated) comboAction = KAction(self) comboAction.setText(i18n("Search bar")) comboAction.setShortcut(Qt.Key_F6) self.connect(comboAction, SIGNAL("triggered()"), self.slotSearchComboActivated) comboAction.setDefaultWidget(self.characterCombo) comboAction.setWhatsThis( i18n("<html>Search bar<br/><br/>Enter character of search string</html>")) self.actionCollection().addAction("searchbar", comboAction) goUrl = self.actionCollection().addAction("go_search") goUrl.setIcon(KIcon("go-jump-locationbar")) goUrl.setText(i18n("Go")) self.connect(goUrl, SIGNAL("triggered()"), lambda: self.slotCharacterComboActivated( self.characterCombo.currentText())) goUrl.setWhatsThis( i18n("<html>Go<br /><br />Searches for the string given in the search bar.</html>")) # clear search bar action clearLocationAction = KAction(KIcon("edit-clear-locationbar-ltr"), i18n("Clear &Location Bar"), self) clearLocationAction.setShortcut(Qt.CTRL + Qt.Key_L) clearLocationAction.setWhatsThis( i18n("Clears the location bar and places the cursor inside")) self.actionCollection().addAction("clearlocationbar", clearLocationAction) self.connect(clearLocationAction, SIGNAL("triggered(bool)"), self.characterCombo.clearEditText) self.connect(clearLocationAction, SIGNAL("triggered(bool)"), self.characterCombo.setFocus) # show/hide character page self.toggleToolboxAction = KToggleAction(KIcon("view-sidetree"), i18n("Show Character Toolbox"), self) self.toggleToolboxAction.setShortcut(Qt.Key_F9) self.toggleToolboxAction.setWhatsThis( i18n("Shows and Hides the character choosing toolbox")) self.actionCollection().addAction("showtoolbox", self.toggleToolboxAction) self.connect(self.toggleToolboxAction, SIGNAL("triggered(bool)"), self.slotToggleToolbox) # auto-lookup clipboard self.autoLookupAction = KToggleAction(i18n("&Auto-Lookup"), self) self.autoLookupAction.setToolTip( i18n("Automatically look up text selected by the mouse cursor.")) self.autoLookupAction.setWhatsThis( i18n("Automatically look up text selected by the mouse cursor.")) self.actionCollection().addAction("autolookup", self.autoLookupAction) self.connect(self.autoLookupAction, SIGNAL("triggered(bool)"), self.setAutoLookup) self.autoLookupAction.setIcon( QIcon(util.getIcon('auto-lookup-selection.png'))) self.connect(QApplication.clipboard(), SIGNAL("selectionChanged()"), self.slotSelectionChanged)
class SynaptiksNotifierItem(KStatusNotifierItem): def __init__(self, parent=None): KStatusNotifierItem.__init__(self, parent) self.setTitle('synaptiks') self.setIconByName('synaptiks') self.setCategory(KStatusNotifierItem.Hardware) self.setStatus(KStatusNotifierItem.Passive) self.setup_actions() self._config = SynaptiksTrayConfiguration(self) try: self.touchpad = Touchpad.find_first(Display.from_qt()) except Exception as error: # show an error message from synaptiks.kde.error import get_localized_error_message error_message = get_localized_error_message(error) options = KMessageBox.Options(KMessageBox.Notify | KMessageBox.AllowLink) KMessageBox.error(None, error_message, '', options) # disable all touchpad related actions for act in (self.touchpad_on_action, self.preferences_action): act.setEnabled(False) # disable synaptiks autostart, the user can still start synaptiks # manually again, if the reason of the error is fixed self._config.findItem('Autostart').setProperty(False) self._config.writeConfig() else: self.activateRequested.connect(self.show_configuration_dialog) # setup the touchpad manager self.setup_manager(self.touchpad) def setup_actions(self): self.touchpad_on_action = KToggleAction( i18nc('@action:inmenu', 'Touchpad on'), self.actionCollection()) self.actionCollection().addAction( 'touchpadOn', self.touchpad_on_action) self.touchpad_on_action.setGlobalShortcut( KShortcut(i18nc('Touchpad toggle shortcut', 'Ctrl+Alt+T'))) self.contextMenu().addAction(self.touchpad_on_action) self.contextMenu().addSeparator() shortcuts = self.actionCollection().addAction( KStandardAction.KeyBindings, 'shortcuts') shortcuts.triggered.connect(self.show_shortcuts_dialog) self.contextMenu().addAction(shortcuts) self.preferences_action = self.actionCollection().addAction( KStandardAction.Preferences, 'preferences') self.preferences_action.triggered.connect( self.show_configuration_dialog) self.contextMenu().addAction(self.preferences_action) help_menu = KHelpMenu(self.contextMenu(), KCmdLineArgs.aboutData()) self.contextMenu().addMenu(help_menu.menu()) def setup_manager(self, touchpad): self.touchpad_manager = TouchpadManager(touchpad, self) ManagerConfiguration.load(self.touchpad_manager) # transition upon touchpad_on_action self.touchpad_manager.add_touchpad_switch_action( self.touchpad_on_action) # update checked state of touchpad_on_action self.touchpad_manager.states['on'].assignProperty( self.touchpad_on_action, 'checked', True) self.touchpad_manager.states['off'].assignProperty( self.touchpad_on_action, 'checked', False) # update the overlay icon self.touchpad_manager.states['on'].entered.connect( partial(self.setOverlayIconByName, 'touchpad-off')) self.touchpad_manager.states['on'].exited.connect( partial(self.setOverlayIconByName, '')) # only show notification if the touchpad is permanently switched # off self.touchpad_manager.states['off'].entered.connect( partial(self.notify_touchpad_state, True)) self.touchpad_manager.states['off'].exited.connect( partial(self.notify_touchpad_state, False)) # and eventually start managing the touchpad self.touchpad_manager.start() def notify_touchpad_state(self, is_off=None): if is_off is None: is_off = self.touchpad.off # show a notification if is_off: event_id = 'touchpadOff' text = i18nc('touchpad switched notification', 'Touchpad switched off') else: event_id = 'touchpadOn' text = i18nc('touchpad switched notification', 'Touchpad switched on') icon = KIconLoader.global_().loadIcon('synaptiks', KIconLoader.Panel) KNotification.event(event_id, text, icon) def show_shortcuts_dialog(self): # The dialog is shown in non-modal form, and consequently must exists # even after this method returns. So we bind the dialog to the # instance to keep pythons GC out of business and manually delete the # dialog once the user closed it self.shortcuts_dialog = KShortcutsDialog( KShortcutsEditor.GlobalAction, KShortcutsEditor.LetterShortcutsDisallowed) self.shortcuts_dialog.addCollection(self.actionCollection()) # delete the dialog manually once the user closed it, to avoid some # mysterious crashes when quitting the application self.shortcuts_dialog.finished.connect( self.shortcuts_dialog.deleteLater) self.shortcuts_dialog.configure() def show_configuration_dialog(self): self.config_dialog = SynaptiksConfigDialog( self.touchpad, self.touchpad_manager, self._config) self.config_dialog.finished.connect(self.config_dialog.deleteLater) self.config_dialog.show()
def create_toolbar(self): self.toolbar = KToolBar(self, True, True) self.toolbar.setIconDimensions(16) self.toolbar.setAllowedAreas(QtCore.Qt.BottomToolBarArea) self.toolbar.setMovable(False) self.toolbar.setFloatable(False) self.toolbar.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon) self.addToolBar(QtCore.Qt.BottomToolBarArea, self.toolbar) self.toolbar.show() self.action_collection = KActionCollection(self) self.action_collection.addAssociatedWidget(self.toolbar) self.clear_live_action = self.action_collection.addAction( "clear_live_action") icon = QtGui.QIcon(":texter/images/edit-clear.png") self.clear_live_action.setIcon(icon) self.clear_live_action.setIconText("clear live") self.clear_live_action.setShortcut( KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_Q)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut)) self.save_live_action = self.action_collection.addAction( "save_live_action") icon = QtGui.QIcon(":texter/images/document-new.png") self.save_live_action.setIcon(icon) self.save_live_action.setIconText("save live") self.save_live_action.setShortcut( KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_W)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut)) self.clear_preview_action = self.action_collection.addAction( "clear_preview_action") icon = QtGui.QIcon(":texter/images/edit-clear.png") self.clear_preview_action.setIcon(icon) self.clear_preview_action.setIconText("clear preview") self.clear_preview_action.setShortcut( KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_A)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut)) self.save_preview_action = self.action_collection.addAction( "save_preview_action") icon = QtGui.QIcon(":texter/images/document-new.png") self.save_preview_action.setIcon(icon) self.save_preview_action.setIconText("save preview") self.save_preview_action.setShortcut( KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_S)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut)) self.publish_action = self.action_collection.addAction( "publish_action") icon = QtGui.QIcon(":texter/images/edit-copy.png") self.publish_action.setIcon(icon) self.publish_action.setIconText("publish") self.publish_action.setShortcutConfigurable(True) self.publish_action.setShortcut( KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_Return)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut)) self.toolbar.insertSeparator(self.publish_action) self.auto_publish_action = KToggleAction(self.action_collection) self.action_collection.addAction("auto publish", self.auto_publish_action) icon = QtGui.QIcon(":texter/images/view-refresh.png") self.auto_publish_action.setIcon(icon) self.auto_publish_action.setObjectName("auto_publish_action") self.auto_publish_action.setIconText("auto publish") self.auto_publish_action.setShortcut( KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_P)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut)) self.typer_animation_action = KToggleAction(self.action_collection) icon = QtGui.QIcon(":texter/images/media-playback-stop.png") self.typer_animation_action.setIcon(icon) self.typer_animation_action.setIconText("animate") self.typer_animation_action.setObjectName("typer_animation_action") self.typer_animation_action.setShortcut( KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_M)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut)) self.action_collection.addAction("typer_animation_action", self.typer_animation_action) self.text_editor_action = self.action_collection.addAction( "text_editor_action") icon = QtGui.QIcon(":texter/images/document-open-data.png") self.text_editor_action.setIcon(icon) self.text_editor_action.setIconText("edit") self.text_editor_action.setShortcut( KShortcut(QtGui.QKeySequence(QtCore.Qt.CTRL + QtCore.Qt.Key_O)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut)) self.toolbar.insertSeparator(self.text_editor_action) self.save_action = self.action_collection.addAction("save_action") icon = QtGui.QIcon(":texter/images/document-save.png") self.save_action.setIcon(icon) self.save_action.setIconText("save") self.save_action.setShortcut( KShortcut(QtGui.QKeySequence(QtCore.Qt.CTRL + QtCore.Qt.Key_S)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut)) self.streaming_action = KToggleAction(self.action_collection) icon = QtGui.QIcon(":texter/images/media-record.png") self.streaming_action.setIcon(icon) self.streaming_action.setIconText("stream") self.streaming_action.setObjectName("stream") self.streaming_action.setShortcut( KShortcut(QtGui.QKeySequence(QtCore.Qt.CTRL + QtCore.Qt.Key_1)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut)) self.action_collection.addAction("stream", self.streaming_action) spacer = KToolBarSpacerAction(self.action_collection) self.action_collection.addAction("1_spacer", spacer) self.previous_action = self.action_collection.addAction( "previous_action") icon = QtGui.QIcon(":texter/images/go-previous-view-page.png") self.previous_action.setIcon(icon) self.previous_action.setIconText("previous") self.previous_action.setShortcut( KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_Left)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut)) self.text_combo = KSelectAction(self.action_collection) self.text_combo.setEditable(False) icon = QtGui.QIcon(":texter/images/document-open-recent.png") self.text_combo.setIcon(icon) self.text_combo.setIconText("saved texts") self.text_combo.setObjectName("text_combo") self.action_collection.addAction("saved texts", self.text_combo) self.next_action = self.action_collection.addAction("next_action") icon = QtGui.QIcon(":texter/images/go-next-view-page.png") self.next_action.setIcon(icon) self.next_action.setIconText("next") self.next_action.setShortcut( KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_Right)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut)) self.toolbar.addSeparator() self.save_action.triggered.connect(self.slot_save) self.publish_action.triggered.connect(self.slot_publish) self.clear_live_action.triggered.connect(self.slot_clear_live) self.clear_preview_action.triggered.connect(self.slot_clear_preview) self.text_combo.triggered[int].connect(self.slot_load_preview_text) self.text_editor_action.triggered.connect(self.slot_open_dialog) self.save_live_action.triggered.connect(self.slot_save_live_text) self.save_preview_action.triggered.connect(self.slot_save_preview_text) self.streaming_action.triggered.connect(self.slot_toggle_streaming) self.auto_publish_action.toggled.connect(self.slot_auto_publish) self.typer_animation_action.toggled.connect(self.slot_toggle_animation) self.preview_size_action.triggered[QtGui.QAction].connect( self.slot_preview_font_size) self.live_size_action.triggered[QtGui.QAction].connect( self.slot_live_font_size) self.next_action.triggered.connect(self.slot_next_item) self.previous_action.triggered.connect(self.slot_previous_item) self.streaming_action.setChecked(True)
class MainWindow(KMainWindow, Ui_MainWindow, MjpegStreamingConsumerInterface): def __init__(self, args, parent=None): self.args = args #super(MainWindow, self).__init__() #PsyQtClientBase.__init__(self) KMainWindow.__init__(self, parent) self.is_streaming = False self.live_center_action = None self.preview_center_action = None self.live_size_action = None self.preview_font_action = None self.live_font_action = None self.preview_size_action = None self.default_size = 28 self.default_align_text = "format_align_center" self.preview_actions = list() self.live_actions = list() self.current = 0 self.model = TextModel(self) self.animation = TextAnimation(self) self.db_dirty = False self.is_animate = False self.fade_animation = None self.dialog = None self.current_object = None self.current_index = -1 self.is_auto_publish = False self.setupUi(self) self.win_id = self.live_text.winId() self.fps = 12.5 self.http_server = MjpegStreamingServer( (args.http_host, args.http_port), self, self.fps) self.live_text.setLineWrapMode( QtGui.QTextEdit.LineWrapMode(QtGui.QTextEdit.FixedPixelWidth)) self.live_text.setLineWrapColumnOrWidth(768) self.font = QtGui.QFont("monospace", self.default_size) self.font.setStyleHint(QtGui.QFont.TypeWriter) self.previous_action = None self.next_action = None self.publish_action = None self.auto_publish_action = None self.save_live_action = None self.save_preview_action = None self.save_action = None self.dialog_widget = None self.action_collection = None self.streaming_action = None self.text_combo = None self.clear_live_action = None self.clear_preview_action = None self.toolbar = None self.typer_animation_action = None self.text_editor_action = None self.preview_text.setFont(self.font) self.preview_text.setRichTextSupport( KRichTextWidget.RichTextSupport(0xffffffff)) self.preview_editor_collection = KActionCollection(self) self.preview_text.createActions(self.preview_editor_collection) self.live_text.setRichTextSupport( KRichTextWidget.RichTextSupport(0xffffffff)) self.live_text.setFont(self.font) self.live_editor_collection = KActionCollection(self) self.live_text.createActions(self.live_editor_collection) self.filter_editor_actions() self.create_toolbar() self.slot_load() qtapp.focusChanged.connect(self.focusChanged) self.start_streaming() self.show() timer = QtCore.QTimer() timer.start(2000) timer.timeout.connect(lambda: None) def pubdir(self): return os.path.dirname(os.path.abspath(__file__)) def getPreviewCoords(self): public_rect = self.preview_text.geometry() global_rect = QtCore.QRect(self.mapToGlobal(public_rect.topLeft()), self.mapToGlobal(public_rect.bottomRight())) return global_rect.x(), global_rect.y() def render_image(self): public_rect = self.live_text_rect() #global_rect = QtCore.QRect(self.mapToGlobal(public_rect.topLeft()), self.mapToGlobal(public_rect.bottomRight())) pixmap = QPixmap.grabWindow(self.win_id, public_rect.x() + 1, public_rect.y() + 1, 768, 576) buf = QBuffer() buf.open(QIODevice.WriteOnly) pixmap.save(buf, "JPG", 75) return buf.data() def filter_editor_actions(self): disabled_action_names = [ "action_to_plain_text", "format_painter", "direction_ltr", "direction_rtl", "format_font_family", "format_text_background_color", "format_list_style", "format_list_indent_more", "format_list_indent_less", "format_text_bold", "format_text_underline", "format_text_strikeout", "format_text_italic", "format_align_right", "manage_link", "format_text_subscript", "format_text_superscript", "insert_horizontal_rule" ] for action in self.live_editor_collection.actions(): text = str(action.objectName()) if text in disabled_action_names: action.setVisible(False) if text == self.default_align_text: self.live_center_action = action elif text == "format_font_size": self.live_size_action = action elif text == "format_font_family": self.live_font_action = action for action in self.preview_editor_collection.actions(): text = str(action.objectName()) if text in disabled_action_names: action.setVisible(False) if text == self.default_align_text: self.preview_center_action = action elif text == "format_font_size": self.preview_size_action = action elif text == "format_font_family": self.preview_font_action = action self.slot_set_preview_defaults() self.slot_set_live_defaults() def create_toolbar(self): self.toolbar = KToolBar(self, True, True) self.toolbar.setIconDimensions(16) self.toolbar.setAllowedAreas(QtCore.Qt.BottomToolBarArea) self.toolbar.setMovable(False) self.toolbar.setFloatable(False) self.toolbar.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon) self.addToolBar(QtCore.Qt.BottomToolBarArea, self.toolbar) self.toolbar.show() self.action_collection = KActionCollection(self) self.action_collection.addAssociatedWidget(self.toolbar) self.clear_live_action = self.action_collection.addAction( "clear_live_action") icon = QtGui.QIcon(":texter/images/edit-clear.png") self.clear_live_action.setIcon(icon) self.clear_live_action.setIconText("clear live") self.clear_live_action.setShortcut( KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_Q)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut)) self.save_live_action = self.action_collection.addAction( "save_live_action") icon = QtGui.QIcon(":texter/images/document-new.png") self.save_live_action.setIcon(icon) self.save_live_action.setIconText("save live") self.save_live_action.setShortcut( KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_W)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut)) self.clear_preview_action = self.action_collection.addAction( "clear_preview_action") icon = QtGui.QIcon(":texter/images/edit-clear.png") self.clear_preview_action.setIcon(icon) self.clear_preview_action.setIconText("clear preview") self.clear_preview_action.setShortcut( KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_A)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut)) self.save_preview_action = self.action_collection.addAction( "save_preview_action") icon = QtGui.QIcon(":texter/images/document-new.png") self.save_preview_action.setIcon(icon) self.save_preview_action.setIconText("save preview") self.save_preview_action.setShortcut( KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_S)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut)) self.publish_action = self.action_collection.addAction( "publish_action") icon = QtGui.QIcon(":texter/images/edit-copy.png") self.publish_action.setIcon(icon) self.publish_action.setIconText("publish") self.publish_action.setShortcutConfigurable(True) self.publish_action.setShortcut( KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_Return)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut)) self.toolbar.insertSeparator(self.publish_action) self.auto_publish_action = KToggleAction(self.action_collection) self.action_collection.addAction("auto publish", self.auto_publish_action) icon = QtGui.QIcon(":texter/images/view-refresh.png") self.auto_publish_action.setIcon(icon) self.auto_publish_action.setObjectName("auto_publish_action") self.auto_publish_action.setIconText("auto publish") self.auto_publish_action.setShortcut( KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_P)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut)) self.typer_animation_action = KToggleAction(self.action_collection) icon = QtGui.QIcon(":texter/images/media-playback-stop.png") self.typer_animation_action.setIcon(icon) self.typer_animation_action.setIconText("animate") self.typer_animation_action.setObjectName("typer_animation_action") self.typer_animation_action.setShortcut( KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_M)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut)) self.action_collection.addAction("typer_animation_action", self.typer_animation_action) self.text_editor_action = self.action_collection.addAction( "text_editor_action") icon = QtGui.QIcon(":texter/images/document-open-data.png") self.text_editor_action.setIcon(icon) self.text_editor_action.setIconText("edit") self.text_editor_action.setShortcut( KShortcut(QtGui.QKeySequence(QtCore.Qt.CTRL + QtCore.Qt.Key_O)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut)) self.toolbar.insertSeparator(self.text_editor_action) self.save_action = self.action_collection.addAction("save_action") icon = QtGui.QIcon(":texter/images/document-save.png") self.save_action.setIcon(icon) self.save_action.setIconText("save") self.save_action.setShortcut( KShortcut(QtGui.QKeySequence(QtCore.Qt.CTRL + QtCore.Qt.Key_S)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut)) self.streaming_action = KToggleAction(self.action_collection) icon = QtGui.QIcon(":texter/images/media-record.png") self.streaming_action.setIcon(icon) self.streaming_action.setIconText("stream") self.streaming_action.setObjectName("stream") self.streaming_action.setShortcut( KShortcut(QtGui.QKeySequence(QtCore.Qt.CTRL + QtCore.Qt.Key_1)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut)) self.action_collection.addAction("stream", self.streaming_action) spacer = KToolBarSpacerAction(self.action_collection) self.action_collection.addAction("1_spacer", spacer) self.previous_action = self.action_collection.addAction( "previous_action") icon = QtGui.QIcon(":texter/images/go-previous-view-page.png") self.previous_action.setIcon(icon) self.previous_action.setIconText("previous") self.previous_action.setShortcut( KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_Left)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut)) self.text_combo = KSelectAction(self.action_collection) self.text_combo.setEditable(False) icon = QtGui.QIcon(":texter/images/document-open-recent.png") self.text_combo.setIcon(icon) self.text_combo.setIconText("saved texts") self.text_combo.setObjectName("text_combo") self.action_collection.addAction("saved texts", self.text_combo) self.next_action = self.action_collection.addAction("next_action") icon = QtGui.QIcon(":texter/images/go-next-view-page.png") self.next_action.setIcon(icon) self.next_action.setIconText("next") self.next_action.setShortcut( KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_Right)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut)) self.toolbar.addSeparator() self.save_action.triggered.connect(self.slot_save) self.publish_action.triggered.connect(self.slot_publish) self.clear_live_action.triggered.connect(self.slot_clear_live) self.clear_preview_action.triggered.connect(self.slot_clear_preview) self.text_combo.triggered[int].connect(self.slot_load_preview_text) self.text_editor_action.triggered.connect(self.slot_open_dialog) self.save_live_action.triggered.connect(self.slot_save_live_text) self.save_preview_action.triggered.connect(self.slot_save_preview_text) self.streaming_action.triggered.connect(self.slot_toggle_streaming) self.auto_publish_action.toggled.connect(self.slot_auto_publish) self.typer_animation_action.toggled.connect(self.slot_toggle_animation) self.preview_size_action.triggered[QtGui.QAction].connect( self.slot_preview_font_size) self.live_size_action.triggered[QtGui.QAction].connect( self.slot_live_font_size) self.next_action.triggered.connect(self.slot_next_item) self.previous_action.triggered.connect(self.slot_previous_item) self.streaming_action.setChecked(True) def closeEvent(self, event): logger.info("closeEvent") if self.db_dirty: self.dialog = KDialog(self) self.dialog.setCaption("4.48 texter - text db not saved") label = QtGui.QLabel( "The Text database is not saved. Do you want to save before exit?", self.dialog) self.dialog.setMainWidget(label) self.dialog.setButtons( KDialog.ButtonCodes(KDialog.Ok | KDialog.Cancel)) self.dialog.okClicked.connect(self.slot_save) self.dialog.exec_() event.accept() def live_text_rect(self): return self.live_text.geometry() def stop_streaming(self): self.is_streaming = False self.http_server.stop() def start_streaming(self): self.http_server.listen(port=self.args.http_port) self.is_streaming = True def fill_combo_box(self): if self.dialog is not None: self.dialog.deleteLater() self.dialog = None self.text_combo.clear() current_row = -1 for index, list_obj in enumerate(self.model.text_db): preview, text = list_obj self.text_combo.addAction(preview) if list_obj == self.current_object: current_row = index if current_row == -1: current_row = self.current_index self.slot_load_preview_text(current_row) self.text_combo.setCurrentItem(current_row) def focusChanged(self, old, new): if new == self.preview_text: self.live_editor_collection.clearAssociatedWidgets() self.preview_editor_collection.addAssociatedWidget(self.toolbar) elif new == self.live_text: self.preview_editor_collection.clearAssociatedWidgets() self.live_editor_collection.addAssociatedWidget(self.toolbar) def slot_auto_publish(self, state): self.is_auto_publish = bool(state) def slot_toggle_animation(self, state): self.is_animate = bool(state) def slot_toggle_streaming(self): if self.is_streaming: self.stop_streaming() else: self.start_streaming() def slot_next_item(self): try: self.current = (self.text_combo.currentItem() + 1) % len( self.model.text_db) self.text_combo.setCurrentItem(self.current) self.slot_load_preview_text(self.current) except ZeroDivisionError: pass def slot_previous_item(self): try: self.current = (self.text_combo.currentItem() - 1) % len( self.model.text_db) self.text_combo.setCurrentItem(self.current) self.slot_load_preview_text(self.current) except ZeroDivisionError: pass def slot_publish(self): if self.is_animate: self.animation.start_animation(self.preview_text, self.live_text, 0) else: self.live_text.setTextOrHtml(self.preview_text.textOrHtml()) def slot_live_font_size(self, action): self.default_size = self.live_size_action.fontSize() self.slot_set_preview_defaults() self.slot_set_live_defaults() def slot_preview_font_size(self, action): self.default_size = self.preview_size_action.fontSize() self.slot_set_live_defaults() self.slot_set_preview_defaults() def slot_toggle_publish(self, state=None): if state: self.slot_publish() else: self.slot_clear_live() def slot_set_preview_defaults(self): self.preview_center_action.setChecked(True) self.preview_text.alignCenter() self.font.setPointSize(self.default_size) self.preview_text.setFontSize(self.default_size) self.preview_text.setFont(self.font) self.preview_size_action.setFontSize(self.default_size) self.preview_text.document().setDefaultFont(self.font) def slot_set_live_defaults(self): self.live_center_action.setChecked(True) self.live_text.alignCenter() self.live_text.setFontSize(self.default_size) self.live_size_action.setFontSize(self.default_size) self.live_text.document().setDefaultFont(self.font) def slot_clear_live(self): self.live_text.clear() self.slot_set_live_defaults() def slot_clear_preview(self): self.preview_text.clear() self.slot_set_preview_defaults() def slot_fade(self): if self.fade_animation.timer is None: self.fade_animation.start_animation() def slot_load_preview_text(self, index): try: preview, text = self.model.text_db[index] except IndexError: return self.preview_text.setTextOrHtml(text) if self.is_auto_publish: self.slot_publish() def slot_save_live_text(self): text = self.live_text.toHtml() preview = get_preview_text(unicode(self.live_text.toPlainText())) if not preview: return old_item = self.model.text_by_preview(preview) if old_item is not None: suffix = 1 while 1: tmp_preview = "%s_%d" % (preview, suffix) tmp = self.model.text_by_preview(tmp_preview) if tmp is None: preview = tmp_preview break else: suffix += 1 self.model.text_db.append([preview, text]) self.model.modelReset.emit() action = self.text_combo.addAction(preview) self.text_combo.setCurrentAction(action) self.db_dirty = True def slot_save_preview_text(self): text = self.preview_text.toHtml() preview = get_preview_text(unicode(self.preview_text.toPlainText())) if not preview: return old_item = self.model.text_by_preview(preview) if old_item is not None: ix, old_preview, old_text = old_item self.model.text_db[ix][1] = text else: self.model.text_db.append([preview, text]) action = self.text_combo.addAction(preview) self.model.modelReset.emit() self.text_combo.setCurrentAction(action) self.db_dirty = True def slot_save(self): path = os.path.expanduser("~/.texter") if not os.path.isdir(path): os.mkdir(path) try: f = open(os.path.join(path, "texter.db"), "w") except IOError: return else: cPickle.dump(self.model.text_db, f, cPickle.HIGHEST_PROTOCOL) self.db_dirty = False def slot_open_dialog(self): self.current_index = self.text_combo.currentItem() self.current_object = self.model.text_db[self.current_index] if self.dialog is not None: self.dialog.deleteLater() self.dialog = None self.dialog = KDialog(self) self.dialog.setButtons(KDialog.Close) self.dialog_widget = EditDialog(self.dialog) self.dialog.setMainWidget(self.dialog_widget) pos_x, pos_y = self.getPreviewCoords() self.dialog.move(pos_x, self.pos().y()) self.dialog.exec_() self.fill_combo_box() def slot_load(self): path = os.path.expanduser("~/.texter") if not os.path.isdir(path): os.mkdir(path) try: db_file = open(os.path.join(path, "texter.db")) except IOError: return try: self.model.text_db = [list(i) for i in cPickle.load(db_file)] except ValueError, error: logger.exception(error) self.fill_combo_box() self.text_combo.setCurrentItem(0) self.slot_load_preview_text(0)
class Notifier: def __init__(self, app): self.app = app self.configManager = app.configManager self.icon = KSystemTrayIcon(ConfigManager.SETTINGS[NOTIFICATION_ICON]) self.icon.connect(self.icon, SIGNAL("activated(QSystemTrayIcon::ActivationReason)"), self.on_activate) self.build_menu() self.update_tool_tip() if ConfigManager.SETTINGS[SHOW_TRAY_ICON]: self.icon.show() def update_tool_tip(self): if ConfigManager.SETTINGS[SERVICE_RUNNING]: self.icon.setToolTip(TOOLTIP_RUNNING.toString()) self.toggleAction.setChecked(True) else: self.icon.setToolTip(TOOLTIP_PAUSED.toString()) self.toggleAction.setChecked(False) def build_menu(self): if ConfigManager.SETTINGS[SHOW_TRAY_ICON]: # Get phrase folders to add to main menu folders = [] items = [] for folder in self.configManager.allFolders: if folder.showInTrayMenu: folders.append(folder) for item in self.configManager.allItems: if item.showInTrayMenu: items.append(item) # Construct main menu menu = popupmenu.PopupMenu(self.app.service, folders, items, False, "AutoKey") if len(items) > 0: menu.addSeparator() self.toggleAction = KToggleAction(i18n("&Enable Monitoring"), menu) self.toggleAction.connect(self.toggleAction, SIGNAL("triggered()"), self.on_enable_toggled) self.toggleAction.setChecked(self.app.service.is_running()) self.toggleAction.setEnabled(not self.app.serviceDisabled) menu.addAction(self.toggleAction) menu.addAction(KIcon("edit-clear"), i18n("&Hide Icon"), self.on_hide_icon) menu.addAction(KIcon("configure"), i18n("&Show Main Window"), self.on_configure) menu.addAction(KStandardAction.quit(self.on_quit, menu)) self.icon.setContextMenu(menu) def update_visible_status(self): self.icon.setVisible(ConfigManager.SETTINGS[SHOW_TRAY_ICON]) self.build_menu() def hide_icon(self): if ConfigManager.SETTINGS[SHOW_TRAY_ICON]: self.icon.hide() def notify_error(self, message): pass # ---- Signal handlers ---- def on_show_error(self): self.app.exec_in_main(self.app.show_script_error) def on_quit(self): self.app.shutdown() def on_activate(self, reason): if reason == QSystemTrayIcon.ActivationReason(QSystemTrayIcon.Trigger): self.on_configure() def on_configure(self): self.app.show_configure() def on_enable_toggled(self): if self.toggleAction.isChecked(): self.app.unpause_service() else: self.app.pause_service() def on_hide_icon(self): self.icon.hide() ConfigManager.SETTINGS[SHOW_TRAY_ICON] = False
class MainWindow(KXmlGuiWindow): "Class which displays the main Danbooru Client window." def __init__(self, *args): "Initialize a new main window." super(MainWindow, self).__init__(*args) self.cache = KPixmapCache("danbooru") self.preferences = preferences.Preferences() self.api = None self.__ratings = None self.__step = 0 self.url_list = self.preferences.boards_list self.max_retrieve = self.preferences.thumbnail_no self.statusbar = self.statusBar() self.progress = QProgressBar() self.thumbnailarea = None self.tag_dock = None self.pool_dock = None self.first_fetch_widget = None self.progress.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) # FIXME: Hackish, but how to make it small otherwise? self.progress.setMinimumSize(100, 1) self.statusbar.addPermanentWidget(self.progress) self.progress.hide() self.setup_welcome_widget() self.setup_actions() def reload_config(self): """Reload configuration after a change""" urls = self.preferences.boards_list if self.first_fetch_widget is not None: self.first_fetch_widget.setup_urls(urls) if self.thumbnailarea is not None: max_thumbnail = self.preferences.thumbnail_no max_rating = self.preferences.max_allowed_rating self.thumbnailarea.fetchwidget.limit = max_thumbnail self.thumbnailarea.fetchwidget.rating = max_rating self.thumbnailarea.fetchwidget.update_values() self.thumbnailarea.connectwidget.setup_urls(urls) self.url_list = self.preferences.boards_list self.max_retrieve = self.preferences.thumbnail_no def setup_welcome_widget(self): """Load the welcome widget at startup.""" widget = QWidget() layout = QVBoxLayout() welcome = QLabel(parent=self) pix = QPixmap(KStandardDirs.locate("appdata", "logo.png")) welcome.setPixmap(pix) welcome.setAlignment(Qt.AlignCenter) self.first_fetch_widget = connectwidget.ConnectWidget( self.preferences.boards_list, self) self.statusbar.addPermanentWidget(self.first_fetch_widget, 300) self.first_fetch_widget.connectionEstablished.connect( self.handle_connection) self.first_fetch_widget.rejected.connect(self.first_fetch_widget.hide) self.first_fetch_widget.hide() self.first_fetch_widget.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed) layout.addWidget(self.first_fetch_widget) layout.addWidget(welcome) widget.setLayout(layout) self.setCentralWidget(widget) def setup_tooltips(self): """Set tooltips for the actions.""" self.connect_action.setToolTip(i18n("Connect to a Danbooru board")) self.fetch_action.setToolTip( i18n("Fetch thumbnails from a Danbooru board")) self.batch_download_action.setToolTip(i18n("Batch download images")) def create_actions(self): """Create actions for the main window.""" self.connect_action = KAction(KIcon("document-open-remote"), i18n("Connect"), self) self.fetch_action = KAction(KIcon("download"), i18n("Download"), self) self.clean_action = KAction(KIcon("trash-empty"), i18n("Clear thumbnail cache"), self) self.batch_download_action = KAction(KIcon("download"), i18n("Batch download"), self) self.pool_toggle_action = KToggleAction(KIcon("image-x-generic"), i18n("Pools"), self) self.tag_display_action = KDualAction(i18n("Show tags"), i18n("Hide tags"), self) self.tag_display_action.setIconForStates(KIcon("image-x-generic")) self.tag_display_action.setEnabled(False) # Shortcuts connect_default = KAction.ShortcutTypes(KAction.DefaultShortcut) connect_active = KAction.ShortcutTypes(KAction.ActiveShortcut) self.connect_action.setShortcut(KStandardShortcut.open()) self.fetch_action.setShortcut(KStandardShortcut.find()) self.fetch_action.setEnabled(False) self.batch_download_action.setEnabled(False) self.pool_toggle_action.setEnabled(False) def setup_action_collection(self): """Set up the action collection by adding the actions.""" action_collection = self.actionCollection() # Addition to the action collection action_collection.addAction("connect", self.connect_action) action_collection.addAction("fetch", self.fetch_action) action_collection.addAction("clean", self.clean_action) action_collection.addAction("batchDownload", self.batch_download_action) action_collection.addAction("poolDownload", self.pool_toggle_action) action_collection.addAction("tagDisplay", self.tag_display_action) KStandardAction.quit(self.close, action_collection) KStandardAction.preferences(self.show_preferences, action_collection) action_collection.removeAction( action_collection.action("help_contents")) action_collection.actionHovered.connect(self.setup_action_tooltip) def setup_actions(self): """Set up the relevant actions, tooltips, and load the RC file.""" self.create_actions() self.setup_tooltips() self.setup_action_collection() # Connect signals self.connect_action.triggered.connect(self.connect) self.fetch_action.triggered.connect(self.get_posts) self.clean_action.triggered.connect(self.clean_cache) self.batch_download_action.triggered.connect(self.batch_download) self.pool_toggle_action.toggled.connect(self.pool_toggle) self.tag_display_action.activeChanged.connect(self.tag_display) window_options = self.StandardWindowOption(self.ToolBar | self.Keys | self.Create | self.Save | self.StatusBar) setupGUI_args = [ QSize(500, 400), self.StandardWindowOption(window_options) ] #Check first in standard locations for danbooruui.rc rc_file = KStandardDirs.locate("appdata", "danbooruui.rc") if rc_file.isEmpty(): setupGUI_args.append(os.path.join(sys.path[0], "danbooruui.rc")) else: setupGUI_args.append(rc_file) self.setupGUI(*setupGUI_args) def setup_action_tooltip(self, action): "Show statusbar help when actions are hovered." if action.isEnabled(): self.statusBar().showMessage(action.toolTip(), 2000) def setup_connections(self): """Set up connections for post and tag retrieval.""" if self.api is None: return self.api.postRetrieved.connect(self.update_progress) self.api.postDownloadFinished.connect(self.download_finished) self.api.tagRetrieved.connect(self.tag_dock.widget().add_tags) self.tag_dock.widget().itemDoubleClicked.connect( self.fetch_tagged_items) def show_preferences(self): "Show the preferences dialog." if KConfigDialog.showDialog("Preferences dialog"): return else: dialog = preferences.PreferencesDialog(self, "Preferences dialog", self.preferences) dialog.show() dialog.settingsChanged.connect(self.reload_config) def connect(self, ok): "Connect to a Danbooru board." if self.thumbnailarea is None: self.first_fetch_widget.show() else: self.thumbnailarea.connectwidget.show() def restore(self): self.statusbar.removeWidget(self.connect_widget) def handle_connection(self, connection): self.api = None self.api = connection self.api.cache = self.cache if self.pool_dock is not None: self.pool_dock.hide() self.pool_dock.widget().clear() self.pool_toggle_action.setChecked(False) if self.thumbnailarea is not None: #TODO: Investigate usability self.clear(clear_pool=True) self.thumbnailarea.clear() self.thumbnailarea.api_data = self.api self.setup_connections() else: self.first_fetch_widget.connectionEstablished.disconnect() self.first_fetch_widget.rejected.disconnect() self.statusbar.removeWidget(self.first_fetch_widget) self.setup_area() self.api.cache = self.cache self.statusBar().showMessage(i18n("Connected to %s" % self.api.url), 3000) self.fetch_action.setEnabled(True) # Set up pool widget pool_widget = poolwidget.DanbooruPoolWidget(self.api) self.pool_dock = QDockWidget("Pools", self) self.pool_dock.setObjectName("PoolDock") self.pool_dock.setAllowedAreas(Qt.BottomDockWidgetArea) self.pool_dock.setWidget(pool_widget) #self.pool_dock.setFeatures(QDockWidget.NoDockWidgetFeatures) self.addDockWidget(Qt.BottomDockWidgetArea, self.pool_dock) self.pool_dock.widget().poolDownloadRequested.connect( self.pool_prepare) self.pool_dock.hide() self.pool_toggle_action.setEnabled(True) self.clear() # Needed to show properly the stuff after connecting self.api.get_post_list(tags="", limit=self.thumbnailarea.post_limit, rating=self.preferences.max_allowed_rating, blacklist=list(self.preferences.tag_blacklist)) self.api.get_tag_list(name="", blacklist=list(self.preferences.tag_blacklist), limit=20) def get_posts(self, ok): "Get posts from the connected Danbooru board." if not self.api: return self.thumbnailarea.fetchwidget.show() def handle_fetching(self, tags, max_rating, limit): """Slot connected to the dataSent signal of the fetch widget. The widgets are set up if they don't exist, and the API is queried to do the actual downloading of tags and """ self.clear() self.thumbnailarea.fetchwidget.hide() if self.tag_dock is not None: self.tag_dock.widget().clear() self.thumbnailarea.post_limit = limit blacklist = list(self.preferences.tag_blacklist) self.api.get_post_list(tags=tags, limit=limit, rating=max_rating, blacklist=blacklist) tags = [item for item in tags if item] if not tags: # No related tags, fetch the most recent 20 tags = "" self.api.get_tag_list(name=tags, blacklist=blacklist, limit=20) else: self.api.get_related_tags(tags=tags, blacklist=blacklist) def fetch_tagged_items(self, item): """Fetch items found in the tag list widget.""" tag_name = unicode(item.text()) self.clear() blacklist = self.preferences.tag_blacklist limit = self.preferences.thumbnail_no rating = self.preferences.max_allowed_rating self.api.get_post_list(page=1, tags=[tag_name], blacklist=blacklist, limit=limit, rating=rating) self.api.get_related_tags(tags=[tag_name], blacklist=blacklist) def pool_toggle(self, checked): "Toggle the presence/absence of the pool dock." if not self.api: return if not checked: self.pool_dock.hide() else: self.pool_dock.show() def pool_prepare(self, pool_id): """Prepare the central area for pool image loading.""" if self.thumbnailarea is None: self.setup_area() else: self.clear(clear_pool=False) self.api.get_pool(pool_id, blacklist=self.preferences.tag_blacklist, rating=self.preferences.max_allowed_rating) def batch_download(self, ok): "Download images in batch." selected_items = self.thumbnailarea.selected_images() if not selected_items: return start_url = KUrl("kfiledialog:///danbooru") caption = i18n("Select a directory to save the images to") directory = KFileDialog.getExistingDirectoryUrl( start_url, self, caption) if directory.isEmpty(): return for item in selected_items: file_url = item.url_label.url() tags = item.data.tags # Make a local copy to append paths as addPath works in-place destination = KUrl(directory) file_name = KUrl(file_url).fileName() destination.addPath(file_name) job = KIO.file_copy(KUrl(file_url), destination, -1) job.setProperty("tags", QVariant(tags)) job.result.connect(self.batch_download_slot) def setup_area(self): "Set up the central widget to display thumbnails." self.thumbnailarea = thumbnailarea.DanbooruTabWidget( self.api, self.preferences, self.preferences.thumbnail_no, self) self.setCentralWidget(self.thumbnailarea) self.thumbnailarea.connectwidget.connectionEstablished.connect( self.handle_connection, type=Qt.UniqueConnection) self.thumbnailarea.connectwidget.rejected.connect( self.thumbnailarea.connectwidget.hide, type=Qt.UniqueConnection) self.thumbnailarea.fetchwidget.dataSent.connect( self.handle_fetching, type=Qt.UniqueConnection) self.thumbnailarea.fetchwidget.rejected.connect( self.thumbnailarea.fetchwidget.hide, type=Qt.UniqueConnection) # Set up tag widget blacklist = self.preferences.tag_blacklist tag_widget = tagwidget.DanbooruTagWidget(blacklist, self) self.tag_display_action.setActive(True) self.tag_display_action.setEnabled(True) self.tag_dock = QDockWidget("Similar tags", self) self.tag_dock.setObjectName("TagDock") self.tag_dock.setAllowedAreas(Qt.RightDockWidgetArea) self.tag_dock.setWidget(tag_widget) #self.tag_dock.setFeatures(QDockWidget.NoDockWidgetFeatures) self.addDockWidget(Qt.RightDockWidgetArea, self.tag_dock) self.tag_dock.hide() # Container signal-slot connections self.setup_connections() def download_finished(self): """Slot called when all the data has been completed. Clears the progress bar and resets it to 0.""" if not self.batch_download_action.isEnabled(): self.batch_download_action.setEnabled(True) self.__step = 0 self.progress.hide() def update_progress(self): "Update the progress bar." if not self.progress.isVisible(): self.progress.show() self.__step += 1 self.progress.setValue(self.__step) def clear(self, clear_pool=True): "Clear the central widget." if self.thumbnailarea is None: return self.thumbnailarea.clear() self.tag_dock.widget().clear() if clear_pool: self.pool_dock.widget().clear() self.batch_download_action.setEnabled(False) def clean_cache(self): "Purge the thumbnail cache." self.cache.discard() self.statusBar().showMessage(i18n("Thumbnail cache cleared.")) def batch_download_slot(self, job): """Slot called when doing batch download, for each file retrieved. If Nepomuk tagging is enabled, each file is tagged using the item's respective tags. """ if job.error(): job.ui().showErrorMessage() else: if self.preferences.nepomuk_enabled: tags = job.property("tags").toPyObject() #danbooru2nepomuk.tag_danbooru_item(job.destUrl().path(), # tags) def tag_display(self, state): """Display or hide the tag dock.""" if self.tag_dock is None: self.tag_display_action.setActive(False) return if state: self.tag_dock.show() else: self.tag_dock.hide()
class MainWindow(KXmlGuiWindow): "Class which displays the main Danbooru Client window." def __init__(self, *args): "Initialize a new main window." super(MainWindow, self).__init__(*args) self.cache = KPixmapCache("danbooru") self.preferences = preferences.Preferences() self.api = None self.__ratings = None self.__step = 0 self.url_list = self.preferences.boards_list self.max_retrieve = self.preferences.thumbnail_no self.statusbar = self.statusBar() self.progress = QProgressBar() self.thumbnailarea = None self.tag_dock = None self.pool_dock = None self.first_fetch_widget = None self.progress.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) # FIXME: Hackish, but how to make it small otherwise? self.progress.setMinimumSize(100, 1) self.statusbar.addPermanentWidget(self.progress) self.progress.hide() self.setup_welcome_widget() self.setup_actions() def reload_config(self): """Reload configuration after a change""" urls = self.preferences.boards_list if self.first_fetch_widget is not None: self.first_fetch_widget.setup_urls(urls) if self.thumbnailarea is not None: max_thumbnail = self.preferences.thumbnail_no max_rating = self.preferences.max_allowed_rating self.thumbnailarea.fetchwidget.limit = max_thumbnail self.thumbnailarea.fetchwidget.rating = max_rating self.thumbnailarea.fetchwidget.update_values() self.thumbnailarea.connectwidget.setup_urls(urls) self.url_list = self.preferences.boards_list self.max_retrieve = self.preferences.thumbnail_no def setup_welcome_widget(self): """Load the welcome widget at startup.""" widget = QWidget() layout = QVBoxLayout() welcome = QLabel(parent=self) pix = QPixmap(KStandardDirs.locate("appdata","logo.png")) welcome.setPixmap(pix) welcome.setAlignment(Qt.AlignCenter) self.first_fetch_widget = connectwidget.ConnectWidget( self.preferences.boards_list, self) self.statusbar.addPermanentWidget(self.first_fetch_widget, 300) self.first_fetch_widget.connectionEstablished.connect( self.handle_connection) self.first_fetch_widget.rejected.connect( self.first_fetch_widget.hide) self.first_fetch_widget.hide() self.first_fetch_widget.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed) layout.addWidget(self.first_fetch_widget) layout.addWidget(welcome) widget.setLayout(layout) self.setCentralWidget(widget) def setup_tooltips(self): """Set tooltips for the actions.""" self.connect_action.setToolTip(i18n("Connect to a Danbooru board")) self.fetch_action.setToolTip( i18n("Fetch thumbnails from a Danbooru board") ) self.batch_download_action.setToolTip(i18n("Batch download images")) def create_actions(self): """Create actions for the main window.""" self.connect_action = KAction(KIcon("document-open-remote"), i18n("Connect"), self) self.fetch_action = KAction(KIcon("download"), i18n("Download"), self) self.clean_action = KAction(KIcon("trash-empty"), i18n("Clear thumbnail cache"), self) self.batch_download_action = KAction(KIcon("download"), i18n("Batch download"), self) self.pool_toggle_action = KToggleAction(KIcon("image-x-generic"), i18n("Pools"), self) self.tag_display_action = KDualAction(i18n("Show tags"), i18n("Hide tags"), self) self.tag_display_action.setIconForStates(KIcon("image-x-generic")) self.tag_display_action.setEnabled(False) # Shortcuts connect_default = KAction.ShortcutTypes(KAction.DefaultShortcut) connect_active = KAction.ShortcutTypes(KAction.ActiveShortcut) self.connect_action.setShortcut(KStandardShortcut.open()) self.fetch_action.setShortcut(KStandardShortcut.find()) self.fetch_action.setEnabled(False) self.batch_download_action.setEnabled(False) self.pool_toggle_action.setEnabled(False) def setup_action_collection(self): """Set up the action collection by adding the actions.""" action_collection = self.actionCollection() # Addition to the action collection action_collection.addAction("connect", self.connect_action) action_collection.addAction("fetch", self.fetch_action) action_collection.addAction("clean", self.clean_action) action_collection.addAction("batchDownload", self.batch_download_action) action_collection.addAction("poolDownload", self.pool_toggle_action) action_collection.addAction("tagDisplay", self.tag_display_action) KStandardAction.quit (self.close, action_collection) KStandardAction.preferences(self.show_preferences, action_collection) action_collection.removeAction( action_collection.action("help_contents")) action_collection.actionHovered.connect(self.setup_action_tooltip) def setup_actions(self): """Set up the relevant actions, tooltips, and load the RC file.""" self.create_actions() self.setup_tooltips() self.setup_action_collection() # Connect signals self.connect_action.triggered.connect(self.connect) self.fetch_action.triggered.connect(self.get_posts) self.clean_action.triggered.connect(self.clean_cache) self.batch_download_action.triggered.connect(self.batch_download) self.pool_toggle_action.toggled.connect(self.pool_toggle) self.tag_display_action.activeChanged.connect(self.tag_display) window_options = self.StandardWindowOption(self.ToolBar| self.Keys | self.Create | self.Save | self.StatusBar) setupGUI_args = [ QSize(500, 400), self.StandardWindowOption(window_options) ] #Check first in standard locations for danbooruui.rc rc_file = KStandardDirs.locate("appdata", "danbooruui.rc") if rc_file.isEmpty(): setupGUI_args.append(os.path.join(sys.path [0], "danbooruui.rc")) else: setupGUI_args.append(rc_file) self.setupGUI(*setupGUI_args) def setup_action_tooltip(self, action): "Show statusbar help when actions are hovered." if action.isEnabled(): self.statusBar().showMessage(action.toolTip(), 2000) def setup_connections(self): """Set up connections for post and tag retrieval.""" if self.api is None: return self.api.postRetrieved.connect(self.update_progress) self.api.postDownloadFinished.connect(self.download_finished) self.api.tagRetrieved.connect(self.tag_dock.widget().add_tags) self.tag_dock.widget().itemDoubleClicked.connect( self.fetch_tagged_items) def show_preferences(self): "Show the preferences dialog." if KConfigDialog.showDialog("Preferences dialog"): return else: dialog = preferences.PreferencesDialog(self, "Preferences dialog", self.preferences) dialog.show() dialog.settingsChanged.connect(self.reload_config) def connect(self, ok): "Connect to a Danbooru board." if self.thumbnailarea is None: self.first_fetch_widget.show() else: self.thumbnailarea.connectwidget.show() def restore(self): self.statusbar.removeWidget(self.connect_widget) def handle_connection(self, connection): self.api = None self.api = connection self.api.cache = self.cache if self.pool_dock is not None: self.pool_dock.hide() self.pool_dock.widget().clear() self.pool_toggle_action.setChecked(False) if self.thumbnailarea is not None: #TODO: Investigate usability self.clear(clear_pool=True) self.thumbnailarea.clear() self.thumbnailarea.api_data = self.api self.setup_connections() else: self.first_fetch_widget.connectionEstablished.disconnect() self.first_fetch_widget.rejected.disconnect() self.statusbar.removeWidget(self.first_fetch_widget) self.setup_area() self.api.cache = self.cache self.statusBar().showMessage(i18n("Connected to %s" % self.api.url), 3000) self.fetch_action.setEnabled(True) # Set up pool widget pool_widget = poolwidget.DanbooruPoolWidget(self.api) self.pool_dock = QDockWidget("Pools", self) self.pool_dock.setObjectName("PoolDock") self.pool_dock.setAllowedAreas(Qt.BottomDockWidgetArea) self.pool_dock.setWidget(pool_widget) #self.pool_dock.setFeatures(QDockWidget.NoDockWidgetFeatures) self.addDockWidget(Qt.BottomDockWidgetArea, self.pool_dock) self.pool_dock.widget().poolDownloadRequested.connect( self.pool_prepare) self.pool_dock.hide() self.pool_toggle_action.setEnabled(True) self.clear() # Needed to show properly the stuff after connecting self.api.get_post_list(tags="", limit=self.thumbnailarea.post_limit, rating=self.preferences.max_allowed_rating, blacklist=list(self.preferences.tag_blacklist)) self.api.get_tag_list(name="",blacklist=list(self.preferences.tag_blacklist), limit=20) def get_posts(self, ok): "Get posts from the connected Danbooru board." if not self.api: return self.thumbnailarea.fetchwidget.show() def handle_fetching(self, tags, max_rating, limit): """Slot connected to the dataSent signal of the fetch widget. The widgets are set up if they don't exist, and the API is queried to do the actual downloading of tags and """ self.clear() self.thumbnailarea.fetchwidget.hide() if self.tag_dock is not None: self.tag_dock.widget().clear() self.thumbnailarea.post_limit = limit blacklist= list(self.preferences.tag_blacklist) self.api.get_post_list(tags=tags, limit=limit, rating=max_rating, blacklist=blacklist) tags = [item for item in tags if item] if not tags: # No related tags, fetch the most recent 20 tags = "" self.api.get_tag_list(name=tags,blacklist=blacklist, limit=20) else: self.api.get_related_tags(tags=tags, blacklist=blacklist) def fetch_tagged_items(self, item): """Fetch items found in the tag list widget.""" tag_name = unicode(item.text()) self.clear() blacklist = self.preferences.tag_blacklist limit = self.preferences.thumbnail_no rating = self.preferences.max_allowed_rating self.api.get_post_list(page=1, tags=[tag_name], blacklist=blacklist, limit=limit, rating=rating) self.api.get_related_tags(tags=[tag_name], blacklist=blacklist) def pool_toggle(self, checked): "Toggle the presence/absence of the pool dock." if not self.api: return if not checked: self.pool_dock.hide() else: self.pool_dock.show() def pool_prepare(self, pool_id): """Prepare the central area for pool image loading.""" if self.thumbnailarea is None: self.setup_area() else: self.clear(clear_pool=False) self.api.get_pool(pool_id, blacklist=self.preferences.tag_blacklist, rating=self.preferences.max_allowed_rating) def batch_download(self, ok): "Download images in batch." selected_items = self.thumbnailarea.selected_images() if not selected_items: return start_url = KUrl("kfiledialog:///danbooru") caption = i18n("Select a directory to save the images to") directory = KFileDialog.getExistingDirectoryUrl(start_url, self, caption) if directory.isEmpty(): return for item in selected_items: file_url = item.url_label.url() tags = item.data.tags # Make a local copy to append paths as addPath works in-place destination = KUrl(directory) file_name = KUrl(file_url).fileName() destination.addPath(file_name) job = KIO.file_copy(KUrl(file_url), destination, -1) job.setProperty("tags", QVariant(tags)) job.result.connect(self.batch_download_slot) def setup_area(self): "Set up the central widget to display thumbnails." self.thumbnailarea = thumbnailarea.DanbooruTabWidget(self.api, self.preferences, self.preferences.thumbnail_no, self) self.setCentralWidget(self.thumbnailarea) self.thumbnailarea.connectwidget.connectionEstablished.connect( self.handle_connection, type=Qt.UniqueConnection) self.thumbnailarea.connectwidget.rejected.connect( self.thumbnailarea.connectwidget.hide, type=Qt.UniqueConnection) self.thumbnailarea.fetchwidget.dataSent.connect( self.handle_fetching, type=Qt.UniqueConnection) self.thumbnailarea.fetchwidget.rejected.connect( self.thumbnailarea.fetchwidget.hide, type=Qt.UniqueConnection) # Set up tag widget blacklist = self.preferences.tag_blacklist tag_widget = tagwidget.DanbooruTagWidget(blacklist, self) self.tag_display_action.setActive(True) self.tag_display_action.setEnabled(True) self.tag_dock = QDockWidget("Similar tags", self) self.tag_dock.setObjectName("TagDock") self.tag_dock.setAllowedAreas(Qt.RightDockWidgetArea) self.tag_dock.setWidget(tag_widget) #self.tag_dock.setFeatures(QDockWidget.NoDockWidgetFeatures) self.addDockWidget(Qt.RightDockWidgetArea, self.tag_dock) self.tag_dock.hide() # Container signal-slot connections self.setup_connections() def download_finished(self): """Slot called when all the data has been completed. Clears the progress bar and resets it to 0.""" if not self.batch_download_action.isEnabled(): self.batch_download_action.setEnabled(True) self.__step = 0 self.progress.hide() def update_progress(self): "Update the progress bar." if not self.progress.isVisible(): self.progress.show() self.__step += 1 self.progress.setValue(self.__step) def clear(self, clear_pool=True): "Clear the central widget." if self.thumbnailarea is None: return self.thumbnailarea.clear() self.tag_dock.widget().clear() if clear_pool: self.pool_dock.widget().clear() self.batch_download_action.setEnabled(False) def clean_cache(self): "Purge the thumbnail cache." self.cache.discard() self.statusBar().showMessage(i18n("Thumbnail cache cleared.")) def batch_download_slot(self, job): """Slot called when doing batch download, for each file retrieved. If Nepomuk tagging is enabled, each file is tagged using the item's respective tags. """ if job.error(): job.ui().showErrorMessage() else: if self.preferences.nepomuk_enabled: tags = job.property("tags").toPyObject() #danbooru2nepomuk.tag_danbooru_item(job.destUrl().path(), # tags) def tag_display(self, state): """Display or hide the tag dock.""" if self.tag_dock is None: self.tag_display_action.setActive(False) return if state: self.tag_dock.show() else: self.tag_dock.hide()