def update_mru_menu_items(mru_file_list: List[str], mru_menu: QMenu, file_open_action: Callable[[str], None], current_file_name: str, clear_all_actions: Callable[[None], None] = None): # look for a separator below the item list act_separator = None act_clear = None for act in mru_menu.actions(): if act.isSeparator(): act_separator = act elif act.data() == 'clearall': act_clear = act if act_clear and act_separator: break if not act_separator: act_separator = mru_menu.addSeparator() if not act_clear: if clear_all_actions: act_clear = mru_menu.addAction('Clear all') act_clear.setData('clearall') act_clear.triggered.connect(clear_all_actions) act_clear.setVisible(len(mru_file_list) > 0) else: act_clear.setVisible(clear_all_actions is not None and len(mru_file_list) > 0) action_idx = -1 home_dir = os.path.expanduser('~') for idx, file_name in enumerate(mru_file_list): if file_name.find(home_dir) == 0: short_file_name = '~' + file_name[len(home_dir):] else: short_file_name = file_name action_idx += 1 if action_idx < len(mru_menu.actions()) and not mru_menu.actions()[action_idx].isSeparator(): act = mru_menu.actions()[action_idx] act.setText(short_file_name) else: act = QAction(short_file_name, mru_menu) mru_menu.insertAction(act_separator, act) act.triggered.disconnect() act.triggered.connect(partial(file_open_action, file_name)) act.setVisible(True) act.setCheckable(True) if file_name == current_file_name: act.setChecked(True) else: act.setChecked(False) # hide all unused actions action_idx += 1 for idx in range(action_idx, len(mru_menu.actions())): act = mru_menu.actions()[idx] if not (act.isSeparator() or act.data() == 'clearall'): act.setVisible(False) mru_menu.update()
def setup_languages(menu: QMenu, callback: Callable): s = settings.Setting_Custom_Language_LANGUAGE languages = { "English": ("en", _translate("LanguageSelection", "English")), "German": ("de", _translate("LanguageSelection", "German")), "Italian": ("it", _translate("LanguageSelection", "Italian")) } menu.clear() def on_language_change(loc): s.value = loc callback() for english, _tuple in languages.items(): action = menu.addAction(_translate("LanguageSelection", english)) action.setIconVisibleInMenu(True) action.setCheckable(True) action.setChecked(s.value == _tuple[0]) action.triggered.connect(lambda a, loc=_tuple[0], f=on_language_change: f(loc)) # If language is something other than 'en', 'de', 'it' if menu.actions() and all(not v.isChecked() for v in menu.actions()): s.value = "en" callback()
def __showContextMenu(self): """ Private slot to show the context menu. """ menu = QMenu() act = menu.addAction(self.tr("Object blocked by ClickToFlash")) font = act.font() font.setBold(True) act.setFont(font) menu.addAction( self.tr("Show information about object"), self.__showInfo) menu.addSeparator() menu.addAction(self.tr("Load"), self.__load) menu.addAction(self.tr("Delete object"), self.__hideAdBlocked) menu.addSeparator() host = self.__url.host() add = menu.addAction( self.tr("Add '{0}' to Whitelist").format(host), self.__addToWhitelist) remove = menu.addAction( self.tr("Remove '{0}' from Whitelist").format(host), self.__removeFromWhitelist) onWhitelist = self.__plugin.onWhitelist(host) add.setEnabled(not onWhitelist) remove.setEnabled(onWhitelist) menu.addSeparator() menu.addAction(self.tr("Configure Whitelist"), self.__configure) menu.actions()[0].setEnabled(False) menu.exec_(QCursor.pos())
def __showContextMenu(self): """ Private slot to show the context menu. """ menu = QMenu() act = menu.addAction(self.tr("Object blocked by ClickToFlash")) font = act.font() font.setBold(True) act.setFont(font) menu.addAction(self.tr("Show information about object"), self.__showInfo) menu.addSeparator() menu.addAction(self.tr("Load"), self.__load) menu.addAction(self.tr("Delete object"), self.__hideAdBlocked) menu.addSeparator() host = self.__url.host() add = menu.addAction( self.tr("Add '{0}' to Whitelist").format(host), self.__addToWhitelist) remove = menu.addAction( self.tr("Remove '{0}' from Whitelist").format(host), self.__removeFromWhitelist) onWhitelist = self.__plugin.onWhitelist(host) add.setEnabled(not onWhitelist) remove.setEnabled(onWhitelist) menu.addSeparator() menu.addAction(self.tr("Configure Whitelist"), self.__configure) menu.actions()[0].setEnabled(False) menu.exec_(QCursor.pos())
class SettingsMenuView(QMenu): """This class represents the settings menu of the main menu bar""" def __init__(self, parent: QWidget): super().__init__(parent) self.addAction("", self.__open_global_options) self.__settings_window: ConfigView = None ManagerModel.init_config() self.__language_menu = QMenu("", self) self.addMenu(self.__language_menu) # Add languages here self.__language_menu.addAction(LanguageAction(self, QLocale.German)) self.__language_menu.addAction(LanguageAction(self, QLocale.English)) Translator.language_changed.signal.connect(self.__update_text) self.__update_text() def __update_text(self): self.setTitle(Translator.tr("Einstellungen")) self.actions()[0].setText(Translator.tr("Globale Einstellungen")) self.__language_menu.setTitle(Translator.tr("Sprache")) self.__language_menu.actions()[0].setText(Translator.tr("Deutsch")) self.__language_menu.actions()[1].setText(Translator.tr("Englisch")) def __open_global_options(self): self.__settings_window = ConfigView("Globales", ManagerModel.get_settings())
def show(position, panel, link, cursor): """Shows a context menu. position: The global position to pop up panel: The music view panel, giving access to mainwindow and view widget link: a popplerqt5 LinkBrowse instance or None cursor: a QTextCursor instance or None """ m = QMenu(panel) # selection? -> Copy if panel.widget().view.surface().hasSelection(): if panel.widget().view.surface().selectedText(): m.addAction(panel.actionCollection.music_copy_text) m.addAction(panel.actionCollection.music_copy_image) if cursor: a = m.addAction(icons.get("document-edit"), _("Edit in Place")) @a.triggered.connect def edit(): import editinplace editinplace.edit(panel.widget(), cursor, position) elif link: a = m.addAction(icons.get("window-new"), _("Open Link in &New Window")) @a.triggered.connect def open_in_browser(): import helpers helpers.openUrl(QUrl(link.url())) a = m.addAction(icons.get("edit-copy"), _("Copy &Link")) @a.triggered.connect def copy_link(): QApplication.clipboard().setText(link.url()) # no actions yet? insert Fit Width/Height if not m.actions(): m.addAction(panel.actionCollection.music_fit_width) m.addAction(panel.actionCollection.music_fit_height) m.addAction(panel.actionCollection.music_zoom_original) m.addSeparator() m.addAction(panel.actionCollection.music_sync_cursor) # help m.addSeparator() a = m.addAction(icons.get("help-contents"), _("Help")) @a.triggered.connect def help(): import userguide userguide.show("musicview") # show it! if m.actions(): m.exec_(position) m.deleteLater()
def show(position, panel, link, cursor): """Shows a context menu. position: The global position to pop up panel: The music view panel, giving access to mainwindow and view widget link: a popplerqt5 LinkBrowse instance or None cursor: a QTextCursor instance or None """ m = QMenu(panel) # selection? -> Copy if panel.widget().view.surface().hasSelection(): if panel.widget().view.surface().selectedText(): m.addAction(panel.actionCollection.music_copy_text) m.addAction(panel.actionCollection.music_copy_image) if cursor: a = m.addAction(icons.get("document-edit"), _("Edit in Place")) @a.triggered.connect def edit(): import editinplace editinplace.edit(panel.widget(), cursor, position) elif link: a = m.addAction(icons.get("window-new"), _("Open Link in &New Window")) @a.triggered.connect def open_in_browser(): import helpers helpers.openUrl(QUrl(link.url())) a = m.addAction(icons.get("edit-copy"), _("Copy &Link")) @a.triggered.connect def copy_link(): QApplication.clipboard().setText(link.url()) # no actions yet? insert Fit Width/Height if not m.actions(): m.addAction(panel.actionCollection.music_fit_width) m.addAction(panel.actionCollection.music_fit_height) m.addAction(panel.actionCollection.music_zoom_original) m.addSeparator() m.addAction(panel.actionCollection.music_sync_cursor) # help m.addSeparator() a = m.addAction(icons.get("help-contents"), _("Help")) @a.triggered.connect def help(): import userguide userguide.show("musicview") # show it! if m.actions(): m.exec_(position) m.deleteLater()
def find_action(menu: QMenu, actionText): actions = menu.actions() for act in actions: currText = act.text() if actionText in currText: return act return None
def _show_menu(self, pos): item = self.itemAt(pos) menu = QMenu() self.set_menu_actions(item, menu) copy_address = None if isinstance(item, MemoryAddressWidget): if len(menu.actions()) > 0: menu.addSeparator() jump_to_address = menu.addAction('Jump to pointer') dump = menu.addAction('Dump binary') menu.addSeparator() copy_address = menu.addAction('Copy address') action = menu.exec_(self.mapToGlobal(pos)) if action: if not self.on_menu_action(action.data(), item): return if isinstance(item, MemoryAddressWidget): if action == copy_address: pyperclip.copy(hex(item.get_address())) elif action == jump_to_address: self.app.get_memory_panel().read_memory( ptr=item.get_address(), length=item.get_size(), base=item.get_base_address()) elif action == dump: self.app.get_dwarf().dump_memory(ptr=item.get_address(), length=item.get_size())
def updatePlotPersoButton(self): menu = QMenu(self.mw) menus = [] for i in [self.tr("Main"), self.tr("Secondary"), self.tr("Minor")]: m = QMenu(i, menu) menus.append(m) menu.addMenu(m) mpr = QSignalMapper(menu) for i in range(self.mw.mdlCharacter.rowCount()): a = QAction(self.mw.mdlCharacter.name(i), menu) a.setIcon(self.mw.mdlCharacter.icon(i)) a.triggered.connect(mpr.map) mpr.setMapping(a, int(self.mw.mdlCharacter.ID(i))) imp = toInt(self.mw.mdlCharacter.importance(i)) menus[2 - imp].addAction(a) # Disabling empty menus for m in menus: if not m.actions(): m.setEnabled(False) mpr.mapped.connect(self.addPlotPerso) self.mw.btnAddPlotPerso.setMenu(menu)
def slotShowContextMenu(self, pos): hit = self.webview.page().currentFrame().hitTestContent(pos) menu = QMenu() if hit.linkUrl().isValid(): a = self.webview.pageAction(QWebPage.CopyLinkToClipboard) a.setIcon(icons.get("edit-copy")) a.setText(_("Copy &Link")) menu.addAction(a) menu.addSeparator() a = menu.addAction(icons.get("window-new"), _("Open Link in &New Window")) a.triggered.connect( (lambda url: lambda: self.slotNewWindow(url))(hit.linkUrl())) else: if hit.isContentSelected(): a = self.webview.pageAction(QWebPage.Copy) a.setIcon(icons.get("edit-copy")) a.setText(_("&Copy")) menu.addAction(a) menu.addSeparator() a = menu.addAction(icons.get("window-new"), _("Open Document in &New Window")) a.triggered.connect((lambda url: lambda: self.slotNewWindow(url))( self.webview.url())) if menu.actions(): menu.exec_(self.webview.mapToGlobal(pos))
def customContextMenu(self, position): '''show context menu''' # group at cursor position index = self.indexAt(position) if not index.isValid(): return # init context menu menu = QMenu() if not self.sourceModel.isDefaultGroup(index): menu.addAction(self.tr("Create Group"), self.slot_insertRow) menu.addAction(self.tr("Create Sub-Group"), self.slot_insertChild) menu.addSeparator() menu.addAction(self.tr("Empty Group"), self.slot_emptyGroup) menu.addAction(self.tr("Remove Group"), self.slot_removeRow) else: key = index.siblingAtColumn(GroupModel.KEY).data() if key == GroupModel.ALLGROUPS: menu.addAction(self.tr("Create Group"), self.slot_insertRow) if key == GroupModel.TRASH: trash = menu.addAction(self.tr("Empty Trash"), lambda: self.emptyTrash.emit(key)) # no items in trash if '(' not in index.siblingAtColumn(GroupModel.NAME).data(): trash.setEnabled(False) if menu.actions(): menu.exec_(self.viewport().mapToGlobal(position))
def updatePlotPersoButton(self): menu = QMenu(self.mw) menus = [] for i in [self.tr("Main"), self.tr("Secondary"), self.tr("Minor")]: m = QMenu(i, menu) menus.append(m) menu.addMenu(m) mpr = QSignalMapper(menu) for i in range(self.mw.mdlCharacter.rowCount()): a = QAction(self.mw.mdlCharacter.name(i), menu) a.setIcon(self.mw.mdlCharacter.icon(i)) a.triggered.connect(mpr.map) mpr.setMapping(a, int(self.mw.mdlCharacter.ID(i))) imp = toInt(self.mw.mdlCharacter.importance(i)) menus[2 - imp].addAction(a) # Disabling empty menus for m in menus: if not m.actions(): m.setEnabled(False) mpr.mapped.connect(self.addPlotPerso) self.mw.btnAddPlotPerso.setMenu(menu)
def _show_menu(self, pos): item = self.itemAt(pos) menu = QMenu() search = None if isinstance(item, MemoryAddressWidget): sym = self.app.dwarf.dwarf_api('getSymbolByAddress', item.get_address()) if sym is not None: if sym['name'] == '' or sym['name'] is None: sym['name'] = sym['address'] sym_action = menu.addAction('%s (%s)' % (sym['name'], sym['moduleName'])) sym_action.setEnabled(False) menu.addSeparator() else: if self.is_search_enabled(): search = menu.addAction('Search') menu.addSeparator() self.set_menu_actions(item, menu) copy_address = None if isinstance(item, MemoryAddressWidget): if len(menu.actions()) > 0: menu.addSeparator() if self.app.dwarf.dwarf_api('isAddressWatched', item.get_address()): watcher = menu.addAction('Remove memory watcher') else: watcher = menu.addAction('Add memory watcher') jump_to_address = menu.addAction('Jump to pointer') dump = menu.addAction('Dump binary') menu.addSeparator() copy_address = menu.addAction('Copy address') action = menu.exec_(self.mapToGlobal(pos)) if action: if search is not None and action == search: self.search() if not self.on_menu_action(action.data(), item): return if isinstance(item, MemoryAddressWidget): if action == copy_address: pyperclip.copy(hex(item.get_address())) elif action == watcher: if self.app.dwarf.dwarf_api('isAddressWatched', item.get_address()): self.app.dwarf.remove_watcher(item.get_address()) else: self.app.dwarf.add_watcher(item.get_address()) elif action == jump_to_address: self.app.memory_panal.read_memory( ptr=item.get_address(), length=item.get_size(), base=item.get_base_address()) elif action == dump: self.app.dwarf.dump_memory(ptr=item.get_address(), length=item.get_size())
class Window(QWidget): def __init__(self, *args, **kwargs): super(Window, self).__init__(*args, **kwargs) layout = QVBoxLayout(self) self.labelInfo = QLabel(self) self.button = QPushButton('带按钮的菜单', self) layout.addWidget(self.labelInfo) layout.addWidget(self.button) # 添加菜单 self._initMenu() def _initMenu(self): # 创建菜单 self._menu = QMenu(self.button) # 替换menu的鼠标释放事件达到选择性不关闭菜单 self._menu.mouseReleaseEvent = self._menu_mouseReleaseEvent self._menu.addAction('菜单1', self._checkAction) self._menu.addAction('菜单2', self._checkAction) self._menu.addAction( QAction('菜单3', self._menu, triggered=self._checkAction)) action = QAction('菜单4', self._menu, triggered=self._checkAction) # 添加自定义的属性,判断该属性可以关闭菜单 action.setProperty('canHide', True) self._menu.addAction(action) for action in self._menu.actions(): # 循环设置可勾选 action.setCheckable(True) self.button.setMenu(self._menu) def _menu_mouseReleaseEvent(self, event): action = self._menu.actionAt(event.pos()) if not action: # 没有找到action就交给QMenu自己处理 return QMenu.mouseReleaseEvent(self._menu, event) if action.property('canHide'): # 如果有该属性则给菜单自己处理 return QMenu.mouseReleaseEvent(self._menu, event) # 找到了QAction则只触发Action action.activate(action.Trigger) def _checkAction(self): # 三个action都响应该函数 self.labelInfo.setText('\n'.join([ '{}\t选中:{}'.format(action.text(), action.isChecked()) for action in self._menu.actions() ]))
def _on_menu_about_to_show(log_api: LogApi, menu: QMenu) -> None: window = _window_from_menu(menu) window.setProperty("focused-widget", window.focusWidget()) for action in menu.actions(): if getattr(action, "commands", None): enabled = False with log_api.exception_guard(): enabled = all(cmd.is_enabled for cmd in action.commands) action.setEnabled(enabled)
def customContextMenu(self, position): '''show context menu''' # menus on items menu = QMenu() indexes = self.selectionModel().selectedRows(ItemModel.GROUP) if indexes: # actions on index # group of current item gid = indexes[0].data() # tags of current item tids = self.selectionModel().selectedRows(ItemModel.TAGS)[0].data() if gid != self.groupView.model().UNREFERENCED: # open source path menu.addAction(self.tr("Open Reference"), self.slot_navigateTo) menu.addSeparator() # menus on groups move = QMenu(self.tr('Move to Group')) groups = self.rootGroup()[self.groupView.model().CHILDREN] self.setupCascadeGroupMenu(move, groups, gid) if move.actions(): menu.addMenu(move) menu.addSeparator() # menus on tags addTag = QMenu(self.tr("Attach Tags")) delTag = QMenu(self.tr("Remove Tags")) self.setupTagsMenu(menu, addTag, delTag, tids) menu.addSeparator() # remove items to trash trash = self.groupView.model().TRASH if gid != trash: menu.addAction(self.tr("Move to Trash"), partial(self.slot_moveToGroup, trash)) else: menu.addAction(self.tr("Delete"), self.slot_deleteItems) else: # create item menu.addAction(self.tr("New Item"), partial(self.slot_appendRows, True)) menu.addAction(self.tr("Import Items"), partial(self.slot_appendRows, False)) menu.addSeparator() menu.addAction(self.tr("Find Duplicated"), self.slot_findDuplicatedItems) menu.addAction(self.tr("Find Unreferenced"), self.slot_findUnreferencedItems) menu.exec_(self.viewport().mapToGlobal(position))
def menu_sessions(parent): m = QMenu(parent) m.setTitle(_('menu title', '&Session')) m.triggered.connect(slot_session_action) import sessions for name in sessions.sessionNames(): a = m.addAction(name.replace('&', '&&')) a.setObjectName(name) qutil.addAccelerators(m.actions()) return m
def open_file_menu(self, event): menu = QMenu(self.sender()) if self.process.status not in ('ERROR', 'Aborted', 'Filesize Error'): menu.addAction('Open folder', self.open_file) if self.url is not None: menu.addAction('Copy URL', lambda: to_clipboard(self.url)) if not menu.actions(): return menu.exec(QCursor.pos())
def menu_file_open_recent(parent): m = QMenu(parent) m.setTitle(_("Open &Recent")) m.triggered.connect(slot_file_open_recent_action) import recentfiles for url in recentfiles.urls(): f = url.toLocalFile() dirname, basename = os.path.split(f) text = "{0} ({1})".format(basename, util.homify(dirname)) m.addAction(text).url = url qutil.addAccelerators(m.actions()) return m
def createStandardContextMenu(self): popup_menu = QTextEdit.createStandardContextMenu(self) if not self.spellcheck: return popup_menu # Select the word under the cursor. # But only if there is no selection (otherwise it's impossible to select more text to copy/cut) cursor = self.textCursor() if not cursor.hasSelection(): cursor.select(QTextCursor.WordUnderCursor) self.setTextCursor(cursor) # Check if the selected word is misspelled and offer spelling # suggestions if it is. if cursor.hasSelection(): text = str(cursor.selectedText()) valid = self._dict.check(text) selectedWord = cursor.selectedText() if not valid: spell_menu = QMenu(self.tr('Spelling Suggestions'), self) spell_menu.setIcon(F.themeIcon("spelling")) for word in self._dict.suggest(text): action = self.SpellAction(word, spell_menu) action.correct.connect(self.correctWord) spell_menu.addAction(action) # Only add the spelling suggests to the menu if there are # suggestions. if len(spell_menu.actions()) != 0: popup_menu.insertSeparator(popup_menu.actions()[0]) # Adds: add to dictionary addAction = QAction(self.tr("&Add to dictionary"), popup_menu) addAction.setIcon(QIcon.fromTheme("list-add")) addAction.triggered.connect(self.addWordToDict) addAction.setData(selectedWord) popup_menu.insertAction(popup_menu.actions()[0], addAction) # Adds: suggestions popup_menu.insertMenu(popup_menu.actions()[0], spell_menu) # popup_menu.insertSeparator(popup_menu.actions()[0]) # If word was added to custom dict, give the possibility to remove it elif valid and self._dict.is_added(selectedWord): popup_menu.insertSeparator(popup_menu.actions()[0]) # Adds: remove from dictionary rmAction = QAction(self.tr("&Remove from custom dictionary"), popup_menu) rmAction.setIcon(QIcon.fromTheme("list-remove")) rmAction.triggered.connect(self.rmWordFromDict) rmAction.setData(selectedWord) popup_menu.insertAction(popup_menu.actions()[0], rmAction) return popup_menu
class QV(QtWidgets.QGraphicsView): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.view_menu = QMenu(self) self.create_actions() def create_actions(self): act = create_action(self.view_menu, "Zoom in", slot=self.on_zoom_in, shortcut=QKeySequence("+"), shortcut_context=Qt.WidgetShortcut) self.view_menu.addAction(act) act = create_action(self.view_menu, "Zoom out", slot=self.on_zoom_out, shortcut=QKeySequence("-"), shortcut_context=Qt.WidgetShortcut) self.view_menu.addAction(act) self.addActions(self.view_menu.actions()) def on_zoom_in(self): if not self.scene(): return self.scale(1.5, 1.5) def on_zoom_out(self): if not self.scene(): return self.scale(1.0 / 1.5, 1.0 / 1.5) def drawBackground(self, painter, rect): gr = rect.toRect() start_x = gr.left() + Settings.WIDTH - (gr.left() % Settings.WIDTH) start_y = gr.top() + Settings.HEIGHT - (gr.top() % Settings.HEIGHT) painter.save() painter.setPen(QtGui.QColor(60, 70, 80).lighter(90)) painter.setOpacity(0.7) for x in range(start_x, gr.right(), Settings.WIDTH): painter.drawLine(x, gr.top(), x, gr.bottom()) for y in range(start_y, gr.bottom(), Settings.HEIGHT): painter.drawLine(gr.left(), y, gr.right(), y) painter.restore() super().drawBackground(painter, rect)
def setup_menu_window_title(menu: QMenu, callback: Callable): s = settings.Setting_Custom_Appearance_General_WINDOW_TITLE def set_window_title(idx_): s.value = idx_ callback() group = QActionGroup(menu) for idx, action in enumerate(menu.actions()): action.setChecked(idx == s.value) action.triggered.connect(lambda x, a=idx, f=set_window_title: f(a)) group.addAction(action)
def createStandardContextMenu(self): popup_menu = QTextEdit.createStandardContextMenu(self) if not self.spellcheck: return popup_menu # Select the word under the cursor. # But only if there is no selection (otherwise it's impossible to select more text to copy/cut) cursor = self.textCursor() if not cursor.hasSelection(): cursor.select(QTextCursor.WordUnderCursor) self.setTextCursor(cursor) # Check if the selected word is misspelled and offer spelling # suggestions if it is. if self._dict and cursor.hasSelection(): text = str(cursor.selectedText()) valid = self._dict.check(text) selectedWord = cursor.selectedText() if not valid: spell_menu = QMenu(self.tr('Spelling Suggestions'), self) spell_menu.setIcon(F.themeIcon("spelling")) for word in self._dict.suggest(text): action = self.SpellAction(word, spell_menu) action.correct.connect(self.correctWord) spell_menu.addAction(action) # Only add the spelling suggests to the menu if there are # suggestions. if len(spell_menu.actions()) != 0: popup_menu.insertSeparator(popup_menu.actions()[0]) # Adds: add to dictionary addAction = QAction(self.tr("&Add to dictionary"), popup_menu) addAction.setIcon(QIcon.fromTheme("list-add")) addAction.triggered.connect(self.addWordToDict) addAction.setData(selectedWord) popup_menu.insertAction(popup_menu.actions()[0], addAction) # Adds: suggestions popup_menu.insertMenu(popup_menu.actions()[0], spell_menu) # popup_menu.insertSeparator(popup_menu.actions()[0]) # If word was added to custom dict, give the possibility to remove it elif valid and self._dict.is_added(selectedWord): popup_menu.insertSeparator(popup_menu.actions()[0]) # Adds: remove from dictionary rmAction = QAction(self.tr("&Remove from custom dictionary"), popup_menu) rmAction.setIcon(QIcon.fromTheme("list-remove")) rmAction.triggered.connect(self.rmWordFromDict) rmAction.setData(selectedWord) popup_menu.insertAction(popup_menu.actions()[0], rmAction) return popup_menu
def createToolButton(actionNamesList, parent=None): try: menu = QMenu(parent) for an in actionNamesList: addAction(menu, an, parent) actions = [a for a in menu.actions()] tb = QToolButton() tb.setDefaultAction(actions[0]) tb.setMenu(menu) tb.setPopupMode(QToolButton.MenuButtonPopup) menu.triggered.connect(tb.setDefaultAction) return tb except Exception as e: info(e)
def _customContextMenuRequested(self, pos): ''' @param: pos QPoint ''' menu = QMenu() menu.addAction(QIcon.fromTheme('document-open'), _('Open File'), self.__openFile) menu.addAction(_('Open Folder'), self._openFolder) menu.addSeparator() menu.addAction(QIcon.fromTheme('edit-copy'), _('Copy Download Link'), self._copyDownloadLink) menu.addSeparator() menu.addAction(QIcon.fromTheme('process-stop'), _('Cancel downloading'), self._stop).setEnabled(self._downloading) menu.addAction(QIcon.fromTheme('list-remove'), _('Remove From List'), self._clear).setEnabled(not self._downloading) if self._downloading or self._ui.downloadInfo.text().startswith(_('Cancelled')) or \ self._ui.downloadInfo.text().startswith(_('Error')): menu.actions()[0].setEnabled(False) menu.exec_(self.mapToGlobal(pos))
def table_Strat_context_menu(event_star): root_menu = QMenu(table_Equip) this_item = table_Strat.itemAt(event_star.pos()) dis_gear = this_item.__dict__[STR_TW_GEAR] eq_row = None for rew in range(0, table_Equip.rowCount()): if dis_gear is table_Equip.item(rew, 0).__dict__[STR_TW_GEAR]: eq_row = table_Equip.item(rew, 0) give_menu_downgrade(root_menu, event_star, eq_row) for akshon in root_menu.actions(): akshon.triggered.connect(lambda: frmObj.cmdStrat_go.click()) root_menu.exec_(event_star.globalPos())
def insert_new_action(menu: QMenu, text: str, index: int): actionsList = menu.actions() if index >= len(actionsList): if text: return menu.addAction(text) return menu.addSeparator() indexAction = actionsList[index] if text: newAction = QAction(text, menu) menu.insertAction(indexAction, newAction) else: newAction = QAction(menu) newAction.setSeparator(True) menu.insertAction(indexAction, newAction) return newAction
class PopupWidget(QPushButton): def __init__(self, label, elements, checklist, parent=None): super(PopupWidget, self).__init__(parent) self.parent = parent self.setText(label) self.menu = QMenu(self) self.checklist = checklist for i in range(0, len(elements)): Action = QAction(elements[i], self.menu) Action.triggered.connect(lambda chk, item=i: self.open_spectral(item)) self.menu.addAction(Action) def mouseReleaseEvent(self, event): self.menu.exec_(event.globalPos()) def open_spectral(self, index): self.parent.open_spectral(index) def getChecklist(self): mlen = len(self.menu.actions()) checklist = np.zeros(mlen) for i in range(0, mlen): checklist[i] = self.menu.actions()[i].isChecked() return checklist
def check_index_widget_menu(self, index: QModelIndex, menu: QMenu): item = self.itemFromIndex(index) if item is not None: gw = self.itemWidget(item, self.get_header_index(HEADER_NAME)) if isinstance(gw, GearWidget): if len(menu.actions()) > 0: menu.addSeparator() action_downgrade = QAction('Downgrade', menu) action_downgrade.triggered.connect( lambda: self.frmMain.downgrade(gw)) menu.addAction(action_downgrade) action_upgrade = QAction('Upgrade', menu) action_upgrade.triggered.connect( lambda: self.frmMain.simulate_success_gear( gw.gear, this_item=gw.parent_widget)) menu.addAction(action_upgrade)
def translate_text_widget_menu(menu: QtW.QMenu): """Translates the text of each action from the given text widget’s context menu.""" keys = [ 'menu_common.undo_item', 'menu_common.redo_item', 'menu_common.cut_item', 'menu_common.copy_item', 'menu_common.paste_item', 'menu_common.delete_item', 'menu_common.select_all_item', ] i = 0 for action in menu.actions(): if not action.isSeparator(): shortcut = action.text().split('\t')[1] if '\t' in action.text() else '' action.setText(_t(keys[i]) + '\t' + shortcut) i += 1
def createToolButton(self, actionNamesList, parent=None): try: if len(actionNamesList) == 0: return if actionNamesList[0].lower() == 'combo:': del actionNamesList[0] return GtoToolCombo(self.gtomain, actionNamesList, None) menu = QMenu(parent) for an in actionNamesList: self.addAction(menu, an, parent) actions = [a for a in menu.actions()] tb = QToolButton() tb.setDefaultAction(actions[0]) tb.setMenu(menu) tb.setPopupMode(QToolButton.MenuButtonPopup) menu.triggered.connect(tb.setDefaultAction) return tb except Exception as e: self.info.err(e)
def _show_menu(self, pos): item = self.itemAt(pos) menu = QMenu() self.set_menu_actions(item, menu) copy_address = None if isinstance(item, MemoryAddressWidget): if len(menu.actions()) > 0: menu.addSeparator() copy_address = menu.addAction('Copy address') action = menu.exec_(self.mapToGlobal(pos)) if action: if not self.on_menu_action(action.data(), item): return if isinstance(item, MemoryAddressWidget): if action == copy_address: pyperclip.copy(hex(item.get_address()))
def menu_file_new_from_template(parent): m = QMenu(parent) m.setTitle(_("New from &Template")) m.triggered.connect(slot_file_new_from_template_action) from snippet import model, actions, snippets groups = {} for name in sorted(model.model().names()): variables = snippets.get(name).variables group = variables.get('template') if group: action = actions.action(name, m) if action: groups.setdefault(group, []).append(action) for group in sorted(groups): for action in groups[group]: m.addAction(action) m.addSeparator() qutil.addAccelerators(m.actions()) return m
def __init__(self): # We need this to load the GUI super(mapEditorWindow, self).__init__() uic.loadUi(os.path.join(GUI_FOLDER, 'mapEditor.ui'), self) # Defining radio buttons self.brushRadio.setText('Brush') self.rectangleRadio.setText('Rectangle') # A button for filling the whole map with a tile self.fillButton.setText('Fill Map') # Let's also define labels self.columnLabel.setText('Columns: -') self.rowLabel.setText('Rows: -') # This should take the brush as the default self.brushRadio.setChecked(True) # I will instance this here because I f****d up self.triggerEditorInstance = triggerEditorWindow() # A Tool Button for loading tilemaps and stuff self.toolButton.setPopupMode(2) # Since I don't know how to load this stuff properly, I'll improvise. menu = QMenu() actions = ['Load Tilemap', 'Load map', 'Triggers', 'Save Map', 'Load Old Map'] for i in actions: menu.addAction(i) del(actions) menuActions = menu.actions() self.loadTmAction = menuActions[0] self.loadMapAction = menuActions[1] self.triggersAction = menuActions[2] self.saveMap = menuActions[3] self.pickOldMapAction = menuActions[4] self.toolButton.setMenu(menu) self.toolButton.setArrowType(Qt.DownArrow) self.tileMapFlag = False self.mapFileFlag = False # Signals self.loadTmAction.triggered.connect(self.pickTilemap) self.loadMapAction.triggered.connect(self.pickMap) self.triggersAction.triggered.connect(self.triggerEditor) self.saveMap.triggered.connect(self.saveMapFile) self.pickOldMapAction.triggered.connect(self.pickOldMap) self.mapFileViewer.itemSelectionChanged.connect(self.paint)
def slotShowContextMenu(self, pos): hit = self.webview.page().currentFrame().hitTestContent(pos) menu = QMenu() if hit.linkUrl().isValid(): a = self.webview.pageAction(QWebPage.CopyLinkToClipboard) a.setIcon(icons.get("edit-copy")) a.setText(_("Copy &Link")) menu.addAction(a) menu.addSeparator() a = menu.addAction(icons.get("window-new"), _("Open Link in &New Window")) a.triggered.connect((lambda url: lambda: self.slotNewWindow(url))(hit.linkUrl())) else: if hit.isContentSelected(): a = self.webview.pageAction(QWebPage.Copy) a.setIcon(icons.get("edit-copy")) a.setText(_("&Copy")) menu.addAction(a) menu.addSeparator() a = menu.addAction(icons.get("window-new"), _("Open Document in &New Window")) a.triggered.connect((lambda url: lambda: self.slotNewWindow(url))(self.webview.url())) if menu.actions(): menu.exec_(self.webview.mapToGlobal(pos))
def contextMenuEvent(self, event): popup_menu = self.createStandardContextMenu() # color: rgb(154, 190, 154); menu_style = "QMenu { background-color: rgb(38,38,38);selection-color: black; selection-background-color: grey;}" popup_menu.setStyleSheet(menu_style) # Select the word under the cursor. cursor = self.textCursor() cursor.select(QTextCursor.WordUnderCursor) self.setTextCursor(cursor) # Check if the selected word is misspelled and offer spelling # suggestions if it is. if enchant and self.dict: if self.textCursor().hasSelection(): text = str(self.textCursor().selectedText()) if self.dict.check(text): self.gotoHelp = QAction('Goto in Help', self) self.gotoHelp.triggered.connect(self.showInHelpFile) popup_menu.insertAction(popup_menu.actions()[0], self.gotoHelp) popup_menu.insertSeparator(popup_menu.actions()[1]) if not self.dict.check(text): spell_menu = QMenu(QCoreApplication.translate('app', 'Spelling Suggestions'), self) spell_menu.setStyleSheet(menu_style) for word in self.dict.suggest(text): # print('word is ',word) action = SpellAction(word, spell_menu) action.correct.connect(self.correctWord) spell_menu.addAction(action) # Only add the spelling suggests to the menu if there are # suggestions. if len(spell_menu.actions()) != 0: popup_menu.insertSeparator(popup_menu.actions()[0]) popup_menu.insertMenu(popup_menu.actions()[0], spell_menu) # FIXME: add change dict and disable spellcheck options popup_menu.exec_(event.globalPos())
class Navigation(QWidget): """ Navigation class definition. Provide a combobox to switch on each opened directories and display it into a tree view Provide 2 useful function (to use in alter module): - add_action(name, shortcut, callback) - callback take 2 arguments : file_info and parent - add_separator() """ SETTINGS_DIRECTORIES = 'navigation_dirs' SETTINGS_CURRENT_DIR = 'navigation_current_dir' onFileItemActivated = pyqtSignal(QFileInfo, name="onFileItemActivated") onDirItemActivated = pyqtSignal(QFileInfo, name="onDirItemActivated") def __init__(self, parent=None): super(Navigation, self).__init__(parent) self.setObjectName("Navigation") self.layout = QVBoxLayout(self) self.layout.setSpacing(0) self.layout.setContentsMargins(0,0,0,0) self.menu_button = QPushButton('Select directory', self) self.menu_button.setFlat(True) # self.menu_button.clicked.connect(self.on_menu_button_clicked) self.menu = QMenu(self) self.menu_button.setMenu(self.menu) self.menu_directories = QMenu(self) self.menu_directories.setTitle('Directories') self.menu_add_action( 'Open directory', self.open_directory, None, QKeySequence.Open) self.menu_add_separator() self.menu_add_action('Refresh', self.reset, None, QKeySequence.Refresh) # @TODO invoke_all self.menu_add_separator() self.menu.addMenu(self.menu_directories) self.tree = QTreeView(self) self.model = FileSystemModel(self) self.tree.setModel(self.model) self.tree.setColumnHidden(1, True) self.tree.setColumnHidden(2, True) self.tree.setColumnHidden(3, True) self.tree.setHeaderHidden(True) # only to expand directory or activated with one click self.tree.clicked.connect(self.on_item_clicked) # else, for file use activated signal self.tree.activated.connect(self.on_item_activated) self.tree.setContextMenuPolicy(Qt.CustomContextMenu) self.tree.customContextMenuRequested.connect(self.on_context_menu) self.widgets = collections.OrderedDict() self.widgets['menu_button'] = self.menu_button self.widgets['tree'] = self.tree # @ToDo: Alter.invoke_all('add_widget', self.widgets) for name, widget in self.widgets.items(): if name == 'menu_button': self.layout.addWidget(widget, 0, Qt.AlignLeft) else: self.layout.addWidget(widget) self.context_menu = QMenu(self) self.add_action('New file', QKeySequence.New, FileSystemHelper.new_file) self.add_action('New Directory', '', FileSystemHelper.new_directory) self.add_separator() self.add_action('Rename', '', FileSystemHelper.rename) self.add_action('Copy', QKeySequence.Copy, FileSystemHelper.copy) self.add_action('Cut', QKeySequence.Cut, FileSystemHelper.cut) self.add_action('Paste', QKeySequence.Paste, FileSystemHelper.paste) self.add_separator() self.add_action('Delete', QKeySequence.Delete, FileSystemHelper.delete) # @ToDo Alter.invoke_all('navigation_add_action', self) #restore previous session and data dirs = ModuleManager.core['settings'].Settings.value( self.SETTINGS_DIRECTORIES, None, True) for directory_path in dirs: name = os.path.basename(directory_path) self.menu_add_directory(name, directory_path) current_dir = ModuleManager.core['settings'].Settings.value( self.SETTINGS_CURRENT_DIR, '') if current_dir: for action in self.menu_directories.actions(): if action.data() == current_dir: action.trigger() self.menu_button.setFocusPolicy(Qt.NoFocus) self.menu_button.setFocusProxy(self.tree) def reset(self, file_info): self.model.beginResetModel() current_dir = ModuleManager.core['settings'].Settings.value( self.SETTINGS_CURRENT_DIR, '') if current_dir: for action in self.menu_directories.actions(): if action.data() == current_dir: action.trigger() def on_menu_button_clicked(self): pos = self.mapToGlobal(self.menu_button.pos()) menu_width = self.menu.sizeHint().width() pos.setY(pos.y() + self.menu_button.height()) # pos.setX(pos.x() + self.menu_button.width() - menu_width) if len(self.menu.actions()) > 0: self.menu.exec(pos) def menu_add_action(self, name, callback, data=None, shortcut=None, icon=None): action = QAction(name, self) if icon: action.setIcon(icon) if shortcut: action.setShortcut(shortcut) action.setShortcutContext(Qt.WidgetWithChildrenShortcut) if data: action.setData(data) action.triggered.connect(callback) self.addAction(action) self.menu.addAction(action) def menu_add_directory(self, name, data): action = QAction(name, self) action.setData(data) action.triggered.connect(self.on_menu_action_triggered) self.menu_directories.addAction(action) return action def menu_add_separator(self): self.menu.addSeparator() def add_action(self, name, shortcut, callback, icon = None): """ Ajoute une action au context menu et au widget navigation lui même. Créer une fonction à la volé pour fournir des arguments aux fonctions associé aux actions. """ action = QAction(name, self) if icon: action.setIcon(icon) action.setShortcut(shortcut) action.setShortcutContext(Qt.WidgetWithChildrenShortcut) action.triggered.connect(self.__wrapper(callback)) self.addAction(action) self.context_menu.addAction(action) def add_separator(self): """Simple abstraction of self.context_menu.addSeparator()""" self.context_menu.addSeparator() def __wrapper(self, callback): def __new_function(): """ __new_function représente la forme de tous les callbacks connecté à une action pour pouvoir utiliser les raccourcis en même temps que le menu contextuel. """ action = self.sender() file_info = action.data() if not file_info: indexes = self.tree.selectedIndexes() if indexes: model_index = indexes[0] file_info = self.model.fileInfo(model_index) callback(file_info, self) elif action.shortcut() == QKeySequence.New: file_info = self.model.fileInfo(self.tree.rootIndex()) callback(file_info, self) else: callback(file_info, self) action.setData(None) return __new_function def question(self, text, informative_text = None): message_box = QMessageBox(self) message_box.setText(text) if informative_text: message_box.setInformativeText(informative_text) message_box.setStandardButtons( QMessageBox.No | QMessageBox.Yes) message_box.setDefaultButton(QMessageBox.No) return message_box.exec() def on_context_menu(self, point): model_index = self.tree.indexAt(point) file_info = self.model.fileInfo(model_index) # pour chaque action on met a jour les data (file_info) # puis on altère les actions (ex enabled) for action in self.context_menu.actions(): if not action.isSeparator(): action.setData(file_info) action.setEnabled(model_index.isValid()) if action.shortcut() == QKeySequence.New: action.setEnabled(True) if not model_index.isValid(): file_info = self.model.fileInfo(self.tree.rootIndex()) action.setData(file_info) if action.shortcut() == QKeySequence.Paste: enable = FileSystemHelper.ready() and model_index.isValid() action.setEnabled(enable) if action.shortcut() == QKeySequence.Delete: # remove directory only if is an empty directory if model_index.isValid() and file_info.isDir(): path = file_info.absoluteFilePath() # QDir(path).count() always contains '.' and '..' action.setEnabled(QDir(path).count() == 2) # @ToDo #Alter.invoke_all( # 'navigation_on_menu_action', # model_index, file_info, action, self) if len(self.context_menu.actions()) > 0: self.context_menu.exec(self.tree.mapToGlobal(point)) # reset action data, sinon y a des problèmes dans _new_function for action in self.context_menu.actions(): action.setData(None) def on_item_activated(self, index): qFileInfo = self.model.fileInfo(index) if qFileInfo.isDir(): self.onDirItemActivated.emit(qFileInfo) else: self.onFileItemActivated.emit(qFileInfo) def on_item_clicked(self, index): qFileInfo = self.model.fileInfo(index) if qFileInfo.isDir(): self.onDirItemActivated.emit(qFileInfo) self.tree.setExpanded(index, not self.tree.isExpanded(index)) else: self.onFileItemActivated.emit(qFileInfo) def open_directory(self): project = ModuleManager.core['settings'].Settings.value( self.SETTINGS_CURRENT_DIR, '') path = QFileDialog.getExistingDirectory(self, "Open Directory", project) if path: name = os.path.basename(path) action = self.menu_add_directory(name, path) self.save_directories_path() action.trigger() def on_menu_action_triggered(self): action = self.sender() path = action.data() if path: self.model.setRootPath(path) self.tree.setRootIndex(self.model.index(path)) self.menu_button.setText(os.path.basename(path)) self.save_current_dir(path) def save_directories_path(self): ModuleManager.core['settings'].Settings.set_value( self.SETTINGS_DIRECTORIES, [action.data() for action in self.menu_directories.actions()] ) def save_current_dir(self, path): ModuleManager.core['settings'].Settings.set_value( self.SETTINGS_CURRENT_DIR, path )
class EditorWidget(QWidget): def __init__(self, file_info, parent=None): super(EditorWidget, self).__init__(parent) self.parent = parent self.file_info = file_info self.v_box = QVBoxLayout(self) self.v_box.setSpacing(0) self.v_box.setContentsMargins(0, 0, 0, 0) self.status_bar = StatusBar(self) self.editor = Editor(self.file_info, self) self.editor.modificationChanged[bool].connect( self.on_modification_changed) self.editor.cursorPositionChanged.connect(self.on_cursor_changed) self.v_box.addWidget(self.editor) self.v_box.addWidget(self.status_bar) self.setLayout(self.v_box) self.status_bar.menu_button.clicked.connect( self.on_menu_button_clicked) self.menu = QMenu(self) self.add_action(self.tr('Save'), 'ctrl+s', self.editor.save) self.add_separator() self.add_action( self.tr('Zoom in'), QKeySequence.ZoomIn, self.editor.zoomIn, wrapped=False ) self.add_action( self.tr('Zoom out'), QKeySequence.ZoomOut, self.editor.zoomOut, wrapped=False ) self.add_action( self.tr('Zoom reset'), 'ctrl+0', self.editor.zoom_reset ) self.add_action( self.tr('Indent current line'), 'ctrl+i', self.editor.indent_current_line ) self.add_action( self.tr('Unindent current line'), 'ctrl+shift+i', self.editor.unindent_current_line ) self.add_separator() self.add_action( self.tr('Auto close brackets and quotes'), 'ctrl+alt+a', EditorHelper.auto_close_brackets_quotes, checkable=True, checked=ModuleManager.core['settings'].Settings.value( EditorHelper.SETTINGS_AUTO_CLOSE_BRACKETS, 'true' ) ) self.add_action( self.tr('Use tabs to indent/unindent'), 'ctrl+shift+alt+&', EditorHelper.use_tabs_to_indent, checkable=True, checked=ModuleManager.core['settings'].Settings.value( EditorHelper.SETTINGS_USE_TABS_TO_INDENT, 'true' ) ) self.add_action( self.tr('Comment/Uncomment line(s)'), 'ctrl+e', self.editor.comment_lines ) self.setFocusPolicy(Qt.NoFocus) self.setFocusProxy(self.editor) Alter.invoke_all('editor_widget_init', self) def on_modification_changed(self, modified): if self.parent: self.parent.on_current_modified(modified) def on_cursor_changed(self, line, index): self.status_bar.showMessage( self.tr("Line {0}, column {1}".format(line + 1, index)) ) def on_menu_button_clicked(self): pos = self.status_bar.mapToGlobal(self.status_bar.menu_button.pos()) menu_size = self.menu.sizeHint() menu_height = menu_size.height() menu_width = menu_size.width() pos.setY(pos.y() - menu_height) pos.setX(pos.x() - menu_width + self.status_bar.menu_button.width()) if len(self.menu.actions()) > 0: self.menu.exec(pos) def add_action(self, name, shortcut, callback, **kwargs): """ Ajoute une action au context menu et au widget navigation lui même. Créer une fonction à la volé pour fournir des arguments aux fonctions associé aux actions. """ action = QAction(name, self) if 'icon' in kwargs: action.setIcon(kwargs['icon']) if 'checkable' in kwargs and kwargs['checkable']: action.setCheckable(True) if 'checked' in kwargs: checked = True if kwargs['checked'] == 'true' else False action.setChecked( checked ) action.setShortcut(shortcut) action.setShortcutContext(Qt.WidgetWithChildrenShortcut) if 'wrapped' in kwargs and kwargs['wrapped'] is False: action.triggered.connect(callback) else: action.triggered.connect(self.__wrapper(callback)) self.addAction(action) self.menu.addAction(action) def add_separator(self): """Simple abstraction of self.context_menu.addSeparator()""" self.menu.addSeparator() def __wrapper(self, callback): def __new_function(): """ __new_function représente la forme de tous les callbacks connecté à une action pour pouvoir utiliser les raccourcis en même temps que le menu contextuel. """ action = self.sender() callback(self, action) return __new_function
class AbstractViewerContextMenu(QObject): """Base class for viewers' context menus. It provides the template method pattern to generate the menu. Subclasses can override individual parts of the menu this way.""" def __init__(self, panel): self._panel = panel self._actionCollection = panel.actionCollection self._surface = None self._menu = QMenu(self._panel) def surface(self): """Return the (cached) surface""" result = self._surface or self._panel.widget().view.surface() return result def addSeparator(self): """Add a separator to the menu.""" self._menu.addSeparator() def addCopyImageAction(self): """Add action to copy image if available""" if self.surface().hasSelection(): self._menu.addAction(self._actionCollection.viewer_copy_image) def addEditInPlaceAction(self, cursor, position): """Add action to edit snippet if on a textedit link""" a = self._menu.addAction(icons.get("document-edit"), _("Edit in Place")) @a.triggered.connect def edit(): import editinplace editinplace.edit(self._panel.widget(), cursor, position) def addLinkAction(self, link): """Add action if on an arbitrary link""" m = self._menu a = m.addAction(icons.get("window-new"), _("Open Link in &New Window")) @a.triggered.connect def open_in_browser(): import helpers helpers.openUrl(QUrl(link.url())) a = m.addAction(icons.get("edit-copy"), _("Copy &Link")) @a.triggered.connect def copy_link(): QApplication.clipboard().setText(link.url()) def addCursorLinkActions(self): """Add actions if on a textedit or arbitrary link""" if self._cursor: self.addEditInPlaceAction(self._cursor, self._position) elif self._link: self.addLinkAction(self._link) def addShowActions(self): """Adds a submenu giving access to the (other) opened viewer documents""" mds = self._actionCollection.viewer_document_select docs = mds.viewdocs() document_actions = {} multi_docs = len(docs) > 1 if self._panel.widget().currentViewdoc(): current_doc_filename = self._panel.widget().currentViewdoc().filename() m = self._menu sm = QMenu(m) sm.setTitle(_("Show...")) sm.setEnabled(multi_docs) ag = QActionGroup(m) ag.triggered.connect(self._panel.slotShowViewdoc) for d in docs: action = QAction(sm) action.setText(d.name()) action._document_filename = d.filename() # TODO: Tooltips aren't shown by Qt (it seems) action.setToolTip(d.filename()) action.setCheckable(True) action.setChecked(d.filename() == current_doc_filename) ag.addAction(action) sm.addAction(action) m.addSeparator() m.addMenu(sm) def addOpenCloseActions(self): """Add actions to close documents. This is not implemented in the base class""" m = self._menu ac = self._actionCollection m.addAction(ac.viewer_open) docs = self._actionCollection.viewer_document_select.viewdocs() if docs: sm = QMenu(m) sm.setTitle(_("Close...")) m.addMenu(sm) sm.addAction(ac.viewer_close) multi_docs = len(docs) > 1 ac.viewer_close_other.setEnabled(multi_docs) ac.viewer_close_all.setEnabled(multi_docs) sm.addAction(ac.viewer_close_other) sm.addAction(ac.viewer_close_all) def addReloadAction(self): """Add action to reload document.""" current_document = self._panel.widget().currentViewdoc() if current_document: m = self._menu ac = self._actionCollection m.addAction(ac.viewer_reload) def addZoomActions(self): """Add actions to zoom the viewer""" m = self._menu m.addSeparator() sm = QMenu(m) sm.setTitle(_("Zoom")) m.addMenu(sm) ac = self._actionCollection sm.addAction(ac.viewer_fit_width) sm.addAction(ac.viewer_fit_height) sm.addAction(ac.viewer_fit_both) sm.addSeparator() sm.addAction(ac.viewer_zoom_in) sm.addAction(ac.viewer_zoom_out) sm.addAction(ac.viewer_zoom_original) def addSynchronizeAction(self): """Add an action telling the viewer to always try syncing with the input editor.""" m = self._menu ac = self._actionCollection m.addAction(ac.viewer_sync_cursor) def addShowToolbarAction(self): """Add action to toggle the visibility of the viewer's toolbar""" m = self._menu ac = self._actionCollection m.addAction(ac.viewer_show_toolbar) def addHelpAction(self): """Add help menu item""" m = self._menu ac = self._actionCollection m.addSeparator() m.addAction(ac.viewer_help) def show(self, position, link, cursor, methods = None): """Build the panel's context menu dynamically. Implements the template method pattern to allow subclasses to override each step. If methods passes a list of methods these will be called instead to construct the menu, making it possible to change order or add methods not available in the base class.""" self._position = position self._link = link self._cursor = cursor self._menu.clear() if not methods: # Actions affecting the current link(selection) self.addCopyImageAction() self.addCursorLinkActions() # Actions affecting the currently opened documents self.addShowActions() self.addOpenCloseActions() self.addReloadAction() # Actions affecting the viewer's state self.addZoomActions() self.addSynchronizeAction() self.addShowToolbarAction() else: for m in methods: m() # The help action is added always self.addHelpAction() # show it! if self._menu.actions(): self._menu.exec_(position)
class FontWindow(BaseMainWindow): def __init__(self, font, parent=None): super().__init__(parent) self._font = None self._settingsWindow = None self._infoWindow = None self._featuresWindow = None self._metricsWindow = None self._groupsWindow = None menuBar = self.menuBar() fileMenu = QMenu(self.tr("&File"), self) fileMenu.addAction(self.tr("&New…"), self.newFile, QKeySequence.New) fileMenu.addAction( self.tr("&Open…"), self.openFile, QKeySequence.Open) # recent files self.recentFilesMenu = QMenu(self.tr("Open &Recent"), self) for i in range(MAX_RECENT_FILES): action = QAction(self.recentFilesMenu) action.setVisible(False) action.triggered.connect(self.openRecentFile) self.recentFilesMenu.addAction(action) self.updateRecentFiles() fileMenu.addMenu(self.recentFilesMenu) fileMenu.addAction(self.tr("&Import…"), self.importFile) fileMenu.addSeparator() fileMenu.addAction(self.tr("&Save"), self.saveFile, QKeySequence.Save) fileMenu.addAction( self.tr("Save &As…"), self.saveFileAs, QKeySequence.SaveAs) fileMenu.addAction(self.tr("&Export…"), self.exportFile) fileMenu.addAction(self.tr("&Reload From Disk"), self.reloadFile) fileMenu.addAction(self.tr("E&xit"), self.close, QKeySequence.Quit) menuBar.addMenu(fileMenu) editMenu = QMenu(self.tr("&Edit"), self) self._undoAction = editMenu.addAction( self.tr("&Undo"), self.undo, QKeySequence.Undo) self._redoAction = editMenu.addAction( self.tr("&Redo"), self.redo, QKeySequence.Redo) editMenu.addSeparator() self.markColorMenu = QMenu(self.tr("&Flag Color"), self) self.updateMarkColors() editMenu.addMenu(self.markColorMenu) cut = editMenu.addAction(self.tr("C&ut"), self.cut, QKeySequence.Cut) copy = editMenu.addAction( self.tr("&Copy"), self.copy, QKeySequence.Copy) copyComponent = editMenu.addAction( self.tr("Copy &As Component"), self.copyAsComponent, "Ctrl+Alt+C") paste = editMenu.addAction( self.tr("&Paste"), self.paste, QKeySequence.Paste) self._clipboardActions = (cut, copy, copyComponent, paste) editMenu.addSeparator() editMenu.addAction(self.tr("&Settings…"), self.settings) menuBar.addMenu(editMenu) fontMenu = QMenu(self.tr("&Font"), self) fontMenu.addAction( self.tr("&Add Glyphs…"), self.addGlyphs, "Ctrl+G") fontMenu.addAction( self.tr("Font &Info"), self.fontInfo, "Ctrl+Alt+I") fontMenu.addAction( self.tr("Font &Features"), self.fontFeatures, "Ctrl+Alt+F") fontMenu.addSeparator() fontMenu.addAction(self.tr("&Sort…"), self.sortGlyphs) menuBar.addMenu(fontMenu) pythonMenu = QMenu(self.tr("&Python"), self) pythonMenu.addAction( self.tr("&Scripting Window"), self.scripting, "Ctrl+Alt+R") pythonMenu.addAction( self.tr("&Output Window"), self.outputWindow, "Ctrl+Alt+O") menuBar.addMenu(pythonMenu) windowMenu = QMenu(self.tr("&Windows"), self) action = windowMenu.addAction( self.tr("&Inspector"), self.inspector, "Ctrl+I") # XXX: we're getting duplicate shortcut when we spawn a new window... action.setShortcutContext(Qt.ApplicationShortcut) windowMenu.addAction( self.tr("&Metrics Window"), self.metrics, "Ctrl+Alt+S") windowMenu.addAction( self.tr("&Groups Window"), self.groups, "Ctrl+Alt+G") menuBar.addMenu(windowMenu) helpMenu = QMenu(self.tr("&Help"), self) helpMenu.addAction(self.tr("&About"), self.about) helpMenu.addAction( self.tr("About &Qt"), QApplication.instance().aboutQt) menuBar.addMenu(helpMenu) cellSize = 56 self.glyphCellView = GlyphCellView(self) self.glyphCellView.glyphActivated.connect(self._glyphActivated) self.glyphCellView.glyphsDropped.connect(self._orderChanged) self.glyphCellView.selectionChanged.connect(self._selectionChanged) self.glyphCellView.setAcceptDrops(True) self.glyphCellView.setCellRepresentationName("TruFont.GlyphCell") self.glyphCellView.setCellSize(cellSize) self.glyphCellView.setFocus() self.cellSizeSlider = QSlider(Qt.Horizontal, self) self.cellSizeSlider.setMinimum(32) self.cellSizeSlider.setMaximum(116) self.cellSizeSlider.setFixedWidth(.9 * self.cellSizeSlider.width()) self.cellSizeSlider.setValue(cellSize) self.cellSizeSlider.valueChanged.connect(self._sliderCellSizeChanged) self.selectionLabel = QLabel(self) statusBar = self.statusBar() statusBar.addPermanentWidget(self.cellSizeSlider) statusBar.addWidget(self.selectionLabel) self.setFont_(font) if font is not None: self.setCurrentFile(font.path) app = QApplication.instance() app.dispatcher.addObserver( self, "_preferencesChanged", "preferencesChanged") app.dispatcher.addObserver(self, "_fontSaved", "fontSaved") self._updateGlyphActions() self.setCentralWidget(self.glyphCellView) self.setWindowTitle() self.resize(605, 430) # -------------- # Custom methods # -------------- def font_(self): return self._font def setFont_(self, font): if self._font is not None: self._font.removeObserver(self, "Font.Changed") self._font.removeObserver(self, "Font.GlyphOrderChanged") self._font.removeObserver(self, "Font.SortDescriptorChanged") self._font = font if font is None: return self._updateGlyphsFromGlyphOrder() font.addObserver(self, "_fontChanged", "Font.Changed") font.addObserver( self, "_glyphOrderChanged", "Font.GlyphOrderChanged") font.addObserver( self, "_sortDescriptorChanged", "Font.SortDescriptorChanged") def maybeSaveBeforeExit(self): if self._font.dirty: currentFont = self.windowTitle()[3:] body = self.tr("Do you want to save the changes you made " "to “{}”?").format(currentFont) closeDialog = QMessageBox( QMessageBox.Question, None, body, QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel, self) closeDialog.setInformativeText( self.tr("Your changes will be lost if you don’t save them.")) closeDialog.setModal(True) ret = closeDialog.exec_() if ret == QMessageBox.Save: self.saveFile() return True elif ret == QMessageBox.Discard: return True return False return True # ------------- # Notifications # ------------- # app def _fontSaved(self, notification): if notification.data["font"] != self._font: return path = notification.data["path"] self.setCurrentFile(path) self.setWindowModified(False) def _preferencesChanged(self, notification): self.updateMarkColors() # widgets def _sliderCellSizeChanged(self): cellSize = self.cellSizeSlider.value() self.glyphCellView.setCellSize(cellSize) QToolTip.showText(QCursor.pos(), str(cellSize), self) def _glyphActivated(self, glyph): glyphWindow = GlyphWindow(glyph, self) glyphWindow.show() def _orderChanged(self): # TODO: reimplement when we start showing glyph subsets glyphs = self.glyphCellView.glyphs() self._font.glyphOrder = [glyph.name for glyph in glyphs] def _selectionChanged(self): # currentGlyph lastSelectedGlyph = self.glyphCellView.lastSelectedGlyph() app = QApplication.instance() app.setCurrentGlyph(lastSelectedGlyph) # selection text # TODO: this should probably be internal to the label selection = self.glyphCellView.selection() if selection is not None: count = len(selection) if count == 1: glyph = self.glyphCellView.glyphsForIndexes(selection)[0] text = "%s " % glyph.name else: text = "" if count: text = self.tr("{0}(%n selected)".format(text), n=count) else: text = "" self.selectionLabel.setText(text) # actions self._updateGlyphActions() # defcon def _fontChanged(self, notification): font = notification.object self.setWindowModified(font.dirty) def _glyphOrderChanged(self, notification): self._updateGlyphsFromGlyphOrder() def _updateGlyphsFromGlyphOrder(self): font = self._font glyphOrder = font.glyphOrder if glyphOrder: glyphs = [] for glyphName in glyphOrder: if glyphName in font: glyphs.append(font[glyphName]) if len(glyphs) < len(font): # if some glyphs in the font are not present in the glyph # order, loop again to add them at the end for glyph in font: if glyph not in glyphs: glyphs.append(glyph) font.disableNotifications(observer=self) font.glyphOrder = [glyph.name for glyph in glyphs] font.enableNotifications(observer=self) else: glyphs = list(font) font.disableNotifications(observer=self) font.glyphOrder = [glyph.name for glyph in glyphs] font.enableNotifications(observer=self) self.glyphCellView.setGlyphs(glyphs) def _sortDescriptorChanged(self, notification): font = notification.object descriptors = notification.data["newValue"] if descriptors[0]["type"] == "glyphSet": glyphNames = descriptors[0]["glyphs"] else: glyphNames = font.unicodeData.sortGlyphNames( font.keys(), descriptors) font.glyphOrder = glyphNames # ------------ # Menu methods # ------------ # File def newFile(self): QApplication.instance().newFile() def openFile(self): path, _ = QFileDialog.getOpenFileName( self, self.tr("Open File"), '', platformSpecific.fileFormat ) if path: QApplication.instance().openFile(path) def openRecentFile(self): fontPath = self.sender().toolTip() QApplication.instance().openFile(fontPath) def saveFile(self, path=None, ufoFormatVersion=3): if path is None and self._font.path is None: self.saveFileAs() else: if path is None: path = self._font.path self._font.save(path, ufoFormatVersion) def saveFileAs(self): fileFormats = OrderedDict([ (self.tr("UFO Font version 3 {}").format("(*.ufo)"), 3), (self.tr("UFO Font version 2 {}").format("(*.ufo)"), 2), ]) # TODO: switch to directory on platforms that need it dialog = QFileDialog( self, self.tr("Save File"), None, ";;".join(fileFormats.keys())) dialog.setAcceptMode(QFileDialog.AcceptSave) ok = dialog.exec_() if ok: nameFilter = dialog.selectedNameFilter() path = dialog.selectedFiles()[0] self.saveFile(path, fileFormats[nameFilter]) self.setWindowTitle() # return ok def importFile(self): # TODO: systematize this fileFormats = ( self.tr("OpenType Font file {}").format("(*.otf *.ttf)"), self.tr("Type1 Font file {}").format("(*.pfa *.pfb)"), self.tr("ttx Font file {}").format("(*.ttx)"), self.tr("WOFF Font file {}").format("(*.woff)"), self.tr("All supported files {}").format( "(*.otf *.pfa *.pfb *.ttf *.ttx *.woff)"), self.tr("All files {}").format("(*.*)"), ) path, _ = QFileDialog.getOpenFileName( self, self.tr("Import File"), None, ";;".join(fileFormats), fileFormats[-2]) if path: font = TFont() try: font.extract(path) except Exception as e: errorReports.showCriticalException(e) return window = FontWindow(font) window.show() def exportFile(self): path, _ = QFileDialog.getSaveFileName( self, self.tr("Export File"), None, self.tr("OpenType PS font {}").format("(*.otf)")) if path: try: self._font.export(path) except Exception as e: errorReports.showCriticalException(e) def reloadFile(self): font = self._font if font.path is None: return font.reloadInfo() font.reloadKerning() font.reloadGroups() font.reloadFeatures() font.reloadLib() font.reloadGlyphs(font.keys()) self.setWindowModified(False) # Edit def undo(self): glyph = self.glyphCellView.lastSelectedGlyph() glyph.undo() def redo(self): glyph = self.glyphCellView.lastSelectedGlyph() glyph.redo() def markColor(self): color = self.sender().data() if color is not None: color = color.getRgbF() glyphs = self.glyphCellView.glyphs() for index in self.glyphCellView.selection(): glyph = glyphs[index] glyph.markColor = color def cut(self): self.copy() glyphs = self.glyphCellView.glyphs() for index in self.glyphCellView.selection(): glyph = glyphs[index] glyph.clear() def copy(self): glyphs = self.glyphCellView.glyphs() pickled = [] for index in sorted(self.glyphCellView.selection()): pickled.append(glyphs[index].serialize( blacklist=("name", "unicode") )) clipboard = QApplication.clipboard() mimeData = QMimeData() mimeData.setData("application/x-trufont-glyph-data", pickle.dumps(pickled)) clipboard.setMimeData(mimeData) def copyAsComponent(self): glyphs = self.glyphCellView.glyphs() pickled = [] for index in self.glyphCellView.selection(): glyph = glyphs[index] componentGlyph = glyph.__class__() componentGlyph.width = glyph.width component = componentGlyph.instantiateComponent() component.baseGlyph = glyph.name pickled.append(componentGlyph.serialize()) clipboard = QApplication.clipboard() mimeData = QMimeData() mimeData.setData("application/x-trufont-glyph-data", pickle.dumps(pickled)) clipboard.setMimeData(mimeData) def paste(self): clipboard = QApplication.clipboard() mimeData = clipboard.mimeData() if mimeData.hasFormat("application/x-trufont-glyph-data"): data = pickle.loads(mimeData.data( "application/x-trufont-glyph-data")) selection = self.glyphCellView.selection() glyphs = self.glyphCellView.glyphsForIndexes(selection) if len(data) == len(glyphs): for pickled, glyph in zip(data, glyphs): # XXX: prune glyph.prepareUndo() glyph.deserialize(pickled) def settings(self): if self._settingsWindow is not None and \ self._settingsWindow.isVisible(): self._settingsWindow.raise_() else: self._settingsWindow = SettingsWindow(self) self._settingsWindow.show() # Font def fontInfo(self): # If a window is already opened, bring it to the front, else spawn one. # TODO: see about using widget.setAttribute(Qt.WA_DeleteOnClose) # otherwise it seems we're just leaking memory after each close... # (both raise_ and show allocate memory instead of using the hidden # widget it seems) if self._infoWindow is not None and self._infoWindow.isVisible(): self._infoWindow.raise_() else: self._infoWindow = FontInfoWindow(self._font, self) self._infoWindow.show() def fontFeatures(self): # TODO: see up here if self._featuresWindow is not None and self._featuresWindow.isVisible( ): self._featuresWindow.raise_() else: self._featuresWindow = FontFeaturesWindow(self._font, self) self._featuresWindow.show() def addGlyphs(self): glyphs = self.glyphCellView.glyphs() newGlyphNames, params, ok = AddGlyphsDialog.getNewGlyphNames( self, glyphs) if ok: sortFont = params.pop("sortFont") for name in newGlyphNames: glyph = self._font.newStandardGlyph(name, **params) if glyph is not None: glyphs.append(glyph) self.glyphCellView.setGlyphs(glyphs) if sortFont: # TODO: when the user add chars from a glyphSet and no others, # should we try to sort according to that glyphSet? # The above would probably warrant some rearchitecturing. # kick-in the sort mechanism self._font.sortDescriptor = self._font.sortDescriptor def sortGlyphs(self): sortDescriptor, ok = SortDialog.getDescriptor( self, self._font.sortDescriptor) if ok: self._font.sortDescriptor = sortDescriptor # Python def scripting(self): app = QApplication.instance() if not hasattr(app, 'scriptingWindow'): app.scriptingWindow = ScriptingWindow() app.scriptingWindow.show() elif app.scriptingWindow.isVisible(): app.scriptingWindow.raise_() else: app.scriptingWindow.show() def outputWindow(self): app = QApplication.instance() if app.outputWindow.isVisible(): app.outputWindow.raise_() else: app.outputWindow.show() # Windows def inspector(self): app = QApplication.instance() if not hasattr(app, 'inspectorWindow'): app.inspectorWindow = InspectorWindow() app.inspectorWindow.show() elif app.inspectorWindow.isVisible(): # TODO: do this only if the widget is user-visible, otherwise the # key press feels as if it did nothing # toggle app.inspectorWindow.close() else: app.inspectorWindow.show() def metrics(self): # TODO: see up here if self._metricsWindow is not None and self._metricsWindow.isVisible(): self._metricsWindow.raise_() else: self._metricsWindow = MetricsWindow(self._font, parent=self) self._metricsWindow.show() # TODO: default string kicks-in on the window before this. Figure out # how to make a clean interface selection = self.glyphCellView.selection() if selection: glyphs = self.glyphCellView.glyphsForIndexes(selection) self._metricsWindow.setGlyphs(glyphs) def groups(self): # TODO: see up here if self._groupsWindow is not None and self._groupsWindow.isVisible(): self._groupsWindow.raise_() else: self._groupsWindow = GroupsWindow(self._font, self) self._groupsWindow.show() # About def about(self): name = QApplication.applicationName() domain = QApplication.organizationDomain() text = self.tr( "<h3>About {n}</h3>" "<p>{n} is a cross-platform, modular typeface design " "application.</p><p>{n} is built on top of " "<a href='http://ts-defcon.readthedocs.org/en/ufo3/'>defcon</a> " "and includes scripting support " "with a <a href='http://robofab.com/'>robofab</a>-like API.</p>" "<p>Version {} {} – Python {}.").format( __version__, gitShortHash, platform.python_version(), n=name) if domain: text += self.tr("<br>See <a href='http://{d}'>{d}</a> for more " "information.</p>").format(d=domain) else: text += "</p>" QMessageBox.about(self, self.tr("About {}").format(name), text) # update methods def setCurrentFile(self, path): if path is None: return recentFiles = settings.recentFiles() if path in recentFiles: recentFiles.remove(path) recentFiles.insert(0, path) while len(recentFiles) > MAX_RECENT_FILES: del recentFiles[-1] settings.setRecentFiles(recentFiles) for window in QApplication.topLevelWidgets(): if isinstance(window, FontWindow): window.updateRecentFiles() def updateRecentFiles(self): recentFiles = settings.recentFiles() count = min(len(recentFiles), MAX_RECENT_FILES) actions = self.recentFilesMenu.actions() for index, recentFile in enumerate(recentFiles[:count]): action = actions[index] shortName = os.path.basename(recentFile.rstrip(os.sep)) action.setText(shortName) action.setToolTip(recentFile) action.setVisible(True) for index in range(count, MAX_RECENT_FILES): actions[index].setVisible(False) self.recentFilesMenu.setEnabled(len(recentFiles)) def updateMarkColors(self): entries = settings.readMarkColors() self.markColorMenu.clear() pixmap = QPixmap(24, 24) none = self.markColorMenu.addAction("None", self.markColor) none.setData(None) for name, color in entries.items(): action = self.markColorMenu.addAction(name, self.markColor) pixmap.fill(color) action.setIcon(QIcon(pixmap)) action.setData(color) def _updateGlyphActions(self): currentGlyph = self.glyphCellView.lastSelectedGlyph() # disconnect eventual signal of previous glyph self._undoAction.disconnect() self._undoAction.triggered.connect(self.undo) self._redoAction.disconnect() self._redoAction.triggered.connect(self.redo) # now update status if currentGlyph is None: self._undoAction.setEnabled(False) self._redoAction.setEnabled(False) else: undoManager = currentGlyph.undoManager self._undoAction.setEnabled(currentGlyph.canUndo()) undoManager.canUndoChanged.connect(self._undoAction.setEnabled) self._redoAction.setEnabled(currentGlyph.canRedo()) undoManager.canRedoChanged.connect(self._redoAction.setEnabled) # and other actions for action in self._clipboardActions: action.setEnabled(currentGlyph is not None) self.markColorMenu.setEnabled(currentGlyph is not None) # ---------- # Qt methods # ---------- def showEvent(self, event): app = QApplication.instance() data = dict( font=self._font, window=self, ) app.postNotification("fontWindowWillOpen", data) super().showEvent(event) app.postNotification("fontWindowOpened", data) def closeEvent(self, event): ok = self.maybeSaveBeforeExit() if ok: app = QApplication.instance() data = dict( font=self._font, window=self, ) app.postNotification("fontWindowWillClose", data) self._font.removeObserver(self, "Font.Changed") app = QApplication.instance() app.dispatcher.removeObserver(self, "preferencesChanged") app.dispatcher.removeObserver(self, "fontSaved") event.accept() else: event.ignore() def event(self, event): if event.type() == QEvent.WindowActivate: app = QApplication.instance() app.setCurrentMainWindow(self) lastSelectedGlyph = self.glyphCellView.lastSelectedGlyph() if lastSelectedGlyph is not None: app.setCurrentGlyph(lastSelectedGlyph) return super().event(event) def setWindowTitle(self, title=None): if title is None: if self._font.path is not None: title = os.path.basename(self._font.path.rstrip(os.sep)) else: title = self.tr("Untitled.ufo") super().setWindowTitle("[*]{}".format(title))
class AceEditor(QWidget): """ Embbeded Ace javascript web editor """ def __init__(self, file_info, parent=None): super(AceEditor, self).__init__(parent) self.parent = parent self.file_info = file_info self.editor_actions = {} self.language = EditorHelper.lang_from_file_info(file_info) self.editor = Ace(self.file_info, self) self.status_bar = StatusBar(self) self.editor.modificationChanged.connect( self.modification_changed) self.editor.cursorPositionChanged.connect(self.on_cursor_changed) self.v_box = QVBoxLayout(self) self.v_box.setSpacing(0) self.v_box.setContentsMargins(0, 0, 0, 0) self.v_box.addWidget(self.editor, 1) self.v_box.addWidget(self.status_bar, 0) self.setLayout(self.v_box) self.status_bar.menu_button.clicked.connect( self.on_menu_button_clicked) self.menu = QMenu(self) self.add_action('Save', 'ctrl+s', self.editor.save) self.add_separator() self.add_action( 'Show hidden', 'ctrl+i', self.editor.toggle_hidden,checkable=True ) self.add_action( 'Use soft tabs', 'ctrl+shift+alt+s', self.editor.toggle_soft_tabs, checkable=True ) self.setFocusPolicy(Qt.NoFocus) self.setFocusProxy(self.editor) Alter.invoke_all('editor_widget_init', self) @pyqtSlot(bool, name='modificationChanged') def modification_changed(self, b): if self.parent: self.parent.on_current_modified(b) @pyqtSlot(int, int, name='cursorPositionChanged') def on_cursor_changed(self, line, index): self.status_bar.showMessage( self.tr("Line {0}, column {1}".format(line + 1, index)) ) def on_menu_button_clicked(self): pos = self.status_bar.mapToGlobal(self.status_bar.menu_button.pos()) menu_size = self.menu.sizeHint() menu_height = menu_size.height() menu_width = menu_size.width() pos.setY(pos.y() - menu_height) pos.setX(pos.x() - menu_width + self.status_bar.menu_button.width()) if len(self.menu.actions()) > 0: self.menu.exec(pos) def add_action(self, name, shortcut, callback, **kwargs): """ Ajoute une action au context menu et au widget navigation lui même. Créer une fonction à la volé pour fournir des arguments aux fonctions associé aux actions. """ action = QAction(self.tr(name), self) if 'icon' in kwargs: action.setIcon(kwargs['icon']) if 'checkable' in kwargs and kwargs['checkable']: action.setCheckable(True) if 'checked' in kwargs: checked = True if kwargs['checked'] == 'true' else False action.setChecked( checked ) action.setShortcut(shortcut) action.setShortcutContext(Qt.WidgetWithChildrenShortcut) if 'wrapped' in kwargs and kwargs['wrapped'] is False: action.triggered.connect(callback) else: action.triggered.connect(self.__wrapper(callback)) self.addAction(action) self.menu.addAction(action) self.editor_actions[name] = action def add_separator(self): """Simple abstraction of self.context_menu.addSeparator()""" self.menu.addSeparator() def __wrapper(self, callback): def __new_function(): """ __new_function représente la forme de tous les callbacks connecté à une action pour pouvoir utiliser les raccourcis en même temps que le menu contextuel. """ action = self.sender() callback(self, action) return __new_function
class MainWindow(QMainWindow, Ui_MainWindow, WindowState): ROLE = 'main' def __init__(self, engine, use_qt_notifications): super(MainWindow, self).__init__() self.setupUi(self) if hasattr(self, 'setUnifiedTitleAndToolBarOnMac'): self.setUnifiedTitleAndToolBarOnMac(True) self._engine = engine self._active_dialogs = {} self._dialog_class = { 'about' : AboutDialog, 'configuration' : ConfigWindow, } all_actions = find_menu_actions(self.menubar) # Dictionaries. self.dictionaries = self.scroll_area.widget() self.dictionaries.add_translation.connect(self._add_translation) self.dictionaries.setFocus() edit_menu = all_actions['menu_Edit'].menu() edit_menu.addAction(self.dictionaries.action_Undo) edit_menu.addSeparator() edit_menu.addMenu(self.dictionaries.menu_AddDictionaries) edit_menu.addAction(self.dictionaries.action_EditDictionaries) edit_menu.addAction(self.dictionaries.action_RemoveDictionaries) edit_menu.addSeparator() edit_menu.addAction(self.dictionaries.action_MoveDictionariesUp) edit_menu.addAction(self.dictionaries.action_MoveDictionariesDown) # Tray icon. self._trayicon = TrayIcon() self._trayicon.enable() self._trayicon.clicked.connect(self._engine.toggle_output) if use_qt_notifications: handler = NotificationHandler() handler.emitSignal.connect(self._trayicon.log) log.add_handler(handler) popup_menu = QMenu() for action_name in ( 'action_ToggleOutput', 'action_Reconnect', '', 'menu_Tools', '', 'action_Configure', '', 'menu_Help', '', 'action_Show', 'action_Quit', ): if action_name: popup_menu.addAction(all_actions[action_name]) else: popup_menu.addSeparator() self._trayicon.set_menu(popup_menu) engine.signal_connect('machine_state_changed', self._trayicon.update_machine_state) engine.signal_connect('quit', self.on_quit) self.action_Quit.triggered.connect(engine.quit) # Populate tools bar/menu. tools_menu = all_actions['menu_Tools'].menu() # Toolbar popup menu for selecting which tools are shown. self.toolbar_menu = QMenu() self.toolbar.setContextMenuPolicy(Qt.CustomContextMenu) self.toolbar.customContextMenuRequested.connect( lambda: self.toolbar_menu.popup(QCursor.pos()) ) for tool_plugin in registry.list_plugins('gui.qt.tool'): tool = tool_plugin.obj action_parameters = [] if tool.ICON is not None: icon = tool.ICON # Internal QT resources start with a `:`. if not icon.startswith(':'): icon = resource_filename(icon) action_parameters.append(QIcon(icon)) action_parameters.append(tool.TITLE) toolbar_action = None for parent in (tools_menu, self.toolbar, self.toolbar_menu): action = parent.addAction(*action_parameters) action.setObjectName(tool_plugin.name) if tool.__doc__ is not None: action.setToolTip(tool.__doc__) if tool.SHORTCUT is not None: action.setShortcut(QKeySequence.fromString(tool.SHORTCUT)) if parent == self.toolbar_menu: action.setCheckable(True) action.setChecked(True) assert toolbar_action is not None action.toggled.connect(toolbar_action.setVisible) else: if parent == self.toolbar: toolbar_action = action action.triggered.connect(partial(self._activate_dialog, tool_plugin.name, args=())) self._dialog_class[tool_plugin.name] = tool engine.signal_connect('output_changed', self.on_output_changed) # Machine. self.machine_type.addItems( _(plugin.name) for plugin in registry.list_plugins('machine') ) engine.signal_connect('config_changed', self.on_config_changed) engine.signal_connect('machine_state_changed', lambda machine, state: self.machine_state.setText(_(state.capitalize())) ) self.restore_state() # Commands. engine.signal_connect('add_translation', partial(self._add_translation, manage_windows=True)) engine.signal_connect('focus', self._focus) engine.signal_connect('configure', partial(self._configure, manage_windows=True)) engine.signal_connect('lookup', partial(self._activate_dialog, 'lookup', manage_windows=True)) # Load the configuration (but do not start the engine yet). if not engine.load_config(): self.on_configure() # Apply configuration settings. config = self._engine.config self.machine_type.setCurrentText(config['machine_type']) self._configured = False self.dictionaries.on_config_changed(config) self.set_visible(not config['start_minimized']) # Start the engine. engine.start() def set_visible(self, visible): if visible: self.show() else: if self._trayicon.is_enabled(): self.hide() else: self.showMinimized() def _activate_dialog(self, name, args=(), manage_windows=False): if manage_windows: previous_window = wmctrl.GetForegroundWindow() dialog = self._active_dialogs.get(name) if dialog is None: dialog_class = self._dialog_class[name] dialog = self._active_dialogs[name] = dialog_class(self._engine, *args) dialog.setWindowIcon(self.windowIcon()) def on_finished(): del self._active_dialogs[name] dialog.deleteLater() if manage_windows: wmctrl.SetForegroundWindow(previous_window) dialog.finished.connect(on_finished) dialog.show() dialog.activateWindow() dialog.raise_() def _add_translation(self, dictionary=None, manage_windows=False): if not dictionary: dictionary = None self._activate_dialog('add_translation', args=(dictionary,), manage_windows=manage_windows) def _focus(self): self.set_visible(True) self.activateWindow() self.raise_() def _configure(self, manage_windows=False): self._activate_dialog('configuration', manage_windows=manage_windows) def _lookup(self, manage_windows=False): self._activate_dialog('lookup', manage_windows=manage_windows) def _restore_state(self, settings): if settings.contains('hidden_toolbar_tools'): hidden_toolbar_tools = json.loads(settings.value('hidden_toolbar_tools')) for action in self.toolbar_menu.actions(): if action.objectName() in hidden_toolbar_tools: action.setChecked(False) def _save_state(self, settings): hidden_toolbar_tools = set() for action in self.toolbar_menu.actions(): if not action.isChecked(): hidden_toolbar_tools.add(action.objectName()) settings.setValue('hidden_toolbar_tools', json.dumps(list(sorted(hidden_toolbar_tools)))) def on_config_changed(self, config_update): if 'machine_type' in config_update: self.machine_type.setCurrentText(config_update['machine_type']) if not self._configured: self._configured = True if config_update.get('show_suggestions_display', False): self._activate_dialog('suggestions') if config_update.get('show_stroke_display', False): self._activate_dialog('paper_tape') def on_machine_changed(self, machine_type): self._engine.config = { 'machine_type': machine_type } def on_output_changed(self, enabled): self._trayicon.update_output(enabled) self.output_enable.setChecked(enabled) self.output_disable.setChecked(not enabled) self.action_ToggleOutput.setChecked(enabled) def on_toggle_output(self, enabled): self._engine.output = enabled def on_enable_output(self): self.on_toggle_output(True) def on_disable_output(self): self.on_toggle_output(False) def on_configure(self): self._configure() def on_reconnect(self): self._engine.reset_machine() def on_manage_dictionaries(self): self._activate_dialog('dictionary_manager') def on_about(self): self._activate_dialog('about') def on_quit(self): for dialog in list(self._active_dialogs.values()): dialog.close() self.save_state() self._trayicon.disable() self.hide() QCoreApplication.quit() def on_show(self): self._focus() def closeEvent(self, event): self.hide() if not self._trayicon.is_enabled(): self._engine.quit() event.ignore()
def __init__(self, activateCallback, parent=None): if app.devicePixelRatio() == 2: icon = QtGui.QIcon(basedir+'Assets/aether-black-tray.svg') iconActive = QtGui.QIcon(basedir+'Assets/aether-white-tray.svg') else: icon = QtGui.QIcon(basedir+'Assets/aether-black-tray.png') iconActive = QtGui.QIcon(basedir+'Assets/aether-white-tray.png') QSystemTrayIcon.__init__(self, icon, parent) menu = QMenu(parent) if globals.appIsPaused: menu.addAction('Aether is paused.').setDisabled(True) else: menu.addAction('Aether is connected.').setDisabled(True) globalStatusMenuItem = menu.actions()[0] menu.addSeparator() # 1 if globals.appIsPaused: menu.addAction('Resume') else: menu.addAction('Pause') togglePauseMenuItem = menu.actions()[2] def togglePause(): if globals.appIsPaused: globals.appIsPaused = False togglePauseMenuItem.setText('Pause') globalStatusMenuItem.setText('Aether is connected.') else: globals.appIsPaused = True togglePauseMenuItem.setText('Resume') globalStatusMenuItem.setText('Aether is paused.') togglePauseMenuItem.triggered.connect(togglePause) if not globals.appStartedAtBoot: menu.addAction('Show Aether') else: menu.addAction('Hide Aether') global toggleVisibilityMenuItem toggleVisibilityMenuItem = menu.actions()[3] def toggleVisibility(): if parent.isHidden(): parent.show() toggleVisibilityMenuItem.setText('Hide Aether') else: parent.close() toggleVisibilityMenuItem.setText('Show Aether') toggleVisibilityMenuItem.triggered.connect(toggleVisibility) menu.addAction('Email the developer') emailDevMenuItem = menu.actions()[4] def emailDev(): mailInitialiser = \ QUrl('mailto:[email protected]' '?subject=Feedback for Aether' '&body=<i><br><br>Hello there! Thanks for taking time to give feedback, I really appreciate it. ' 'If you are having problems, please right click on Aether.app on your Applications folder, ' 'click Show Package Contents, go to Contents/MacOS/Logs and attach the network.log file there to ' 'this email. <br><br>' 'You can delete this text before sending.' '<br><br>You can find my PGP key here:</i> ' 'http://pgp.mit.edu:11371/pks/lookup?search=Burak+Nehbit') QtGui.QDesktopServices.openUrl(mailInitialiser) emailDevMenuItem.triggered.connect(emailDev) menu.addSeparator() # 5 menu.addAction('Quit') quitAppMenuItem = menu.actions()[6] # This is below reactor.run to allow access from other places outside main. def quitApp(): # This is buggy... if parent.reactor.threadpool is not None: parent.reactor.threadpool.stop() parent.close() parent.reactor.stop() app.quit() sys.exit() quitAppMenuItem.triggered.connect(quitApp) self.setContextMenu(menu) self.setIcon(icon) self.activated.connect(lambda r: activateCallback(self, r)) def changeIconToActiveState(): self.setIcon(iconActive) def changeIconToPassiveState(): self.setIcon(icon) menu.aboutToShow.connect(changeIconToActiveState) menu.aboutToHide.connect(changeIconToPassiveState)
class TabWidget(QTabWidget): """ TabWidget class definition """ currentChangedFileInfo = pyqtSignal(QFileInfo) def __init__(self, parent=None): super(TabWidget, self).__init__(parent) self.tabBar().installEventFilter(self) self.setTabsClosable(True) self.setMovable(True) self.setFocusPolicy(Qt.NoFocus) self.icon_modified = QIcon('images/is-modified.png') self.icon_not_modified = QIcon('images/is-not-modified.png') self.tabCloseRequested.connect(self.on_tab_closed) nav_icon = QIcon('images/navigation-menu.png') self.menu_button = QPushButton('', self) self.menu_button.setIcon(nav_icon) self.menu_button.setFlat(True) self.menu_button.clicked.connect(self.on_menu_button_clicked) self.menu_button.setObjectName('TabWidgetMenuButton') self.menu_button.setToolTip('Menu with useful actions') self.setCornerWidget(self.menu_button, Qt.TopRightCorner) self.menu = QMenu(self) self.add_action('Remove current tab', 'ctrl+w', TabWidgetHelper.remove) self.add_action( 'Remove all tab', 'ctrl+shift+w', TabWidgetHelper.remove_all) self.add_separator() self.add_action('Next Tab', QKeySequence.NextChild, TabWidgetHelper.next_tab) self.add_action('Previous Tab', QKeySequence.PreviousChild, TabWidgetHelper.previous_tab) self.add_separator() self.add_action('Open file', QKeySequence.Open, TabWidgetHelper.open_file) Alter.invoke_all('tab_widget_add_action', self) self.currentChanged[int].connect(self.on_current_changed) def eventFilter(self, o, event): if o == self.tabBar() and event.type() == QEvent.MouseButtonPress: if event.button() == Qt.MidButton: index = self.tabBar().tabAt(event.pos()) if index != -1: self.on_tab_closed(index) return True return super(TabWidget, self).eventFilter(o, event) def on_current_changed(self, index): if index != -1: widget = self.widget(index) self.setFocusProxy(widget) self.setFocus(Qt.TabFocusReason) self.currentChangedFileInfo.emit(widget.file_info) # the function name must be equal to signal name. # decorator because reduce the amount of memory used and is slightly faster @pyqtSlot(QFileInfo) def onFileItemActivated(self, file_info): Alter.invoke_all('tab_widget_add_tab', self, file_info) def add_tab(self, cls, file_info, force_open=False): #if file is already open index, i = -1, 0 while not force_open and i < self.count() and index == -1: if self.widget(i).file_info == file_info: index = i i += 1 if index == -1: index = self.addTab( cls(file_info, self), self.icon_not_modified, file_info.fileName() ) self.setCurrentIndex(index) self.setFocus(True) def on_menu_button_clicked(self): pos = self.mapToGlobal(self.menu_button.pos()) menu_width = self.menu.sizeHint().width() pos.setY(pos.y() + self.menu_button.height()) pos.setX(pos.x() + self.menu_button.width() - menu_width) if len(self.menu.actions()) > 0: self.menu.exec(pos) def on_tab_closed(self, index): widget = self.widget(index) self.removeTab(index) # remove the widget for real widget.deleteLater() del widget def add_action(self, name, shortcut, callback, icon = None): """ Ajoute une action au context menu et au widget lui même. Créer une fonction à la volé pour fournir des arguments aux fonctions associé aux actions. """ action = QAction(name, self) if icon: action.setIcon(icon) action.setShortcut(shortcut) action.setShortcutContext(Qt.WidgetWithChildrenShortcut) action.triggered.connect(self.__wrapper(callback)) self.addAction(action) self.menu.addAction(action) def add_separator(self): """Simple abstraction of self.context_menu.addSeparator()""" self.menu.addSeparator() def __wrapper(self, callback): def __new_function(): """ __new_function représente la forme de tous les callbacks connecté à une action pour pouvoir utiliser les raccourcis en même temps que le menu contextuel. """ callback(self) return __new_function def on_current_modified(self, modified): icon = self.icon_modified if modified else self.icon_not_modified index = self.currentIndex() self.tabBar().setTabIcon(index, icon)
class SystemTrayIcon(QSystemTrayIcon): def __init__(self, basedir, app, parent=None): self.basedir = basedir if globals.PLATFORM == 'OSX': if app.devicePixelRatio() == 2: self.icon = QtGui.QIcon(basedir+'Assets/aether-black-tray.svg') self.iconActive = QtGui.QIcon(basedir+'Assets/aether-white-tray.svg') self.iconHighlight = QtGui.QIcon(self.basedir+'Assets/aether-blue-tray.svg') else: self.icon = QtGui.QIcon(basedir+'Assets/aether-black-tray.png') self.iconActive = QtGui.QIcon(basedir+'Assets/aether-white-tray.png') self.iconHighlight = QtGui.QIcon(self.basedir+'Assets/aether-blue-tray.png') elif globals.PLATFORM == 'LNX': self.icon = QtGui.QIcon(basedir+'Assets/aether-white-tray.png') self.iconActive = self.icon self.iconHighlight = self.icon elif globals.PLATFORM == 'WIN': self.icon = QtGui.QIcon(basedir+'Assets/aether-black-tray-win.svg') self.iconActive = self.icon self.iconHighlight = self.icon else: pass QSystemTrayIcon.__init__(self, self.icon, parent) self.menu = QMenu(parent) if globals.appIsPaused: self.menu.addAction('Aether is paused.').setDisabled(True) else: self.menu.addAction('Aether is connected.').setDisabled(True) globalStatusMenuItem = self.menu.actions()[0] self.menu.addSeparator() # 1 self.menu.addAction('You have no replies.').setDisabled(True) self.messagesMenuItem = self.menu.actions()[2] def goToMessages(): self.messagesMenuItem.setText('You have no replies.') self.messagesMenuItem.setDisabled(True) if parent.isHidden(): parent.show() parent.raise_() jsString = \ ("firstFrameScope = angular.element(document.getElementById('first-frame-contents')).scope();" "firstFrameScope.repliesButtonClick();" "firstFrameScope.$apply();" ) self.webView.JSContext(jsString) # reach out to jscontext and # Here, I need to call qtwebkit and tell it to open messages. self.messagesMenuItem.triggered.connect(goToMessages) self.menu.addSeparator() # 3 if globals.appIsPaused: self.menu.addAction('Resume') else: self.menu.addAction('Pause') self.togglePauseMenuItem = self.menu.actions()[4] def togglePause(): if globals.appIsPaused: globals.appIsPaused = False self.togglePauseMenuItem.setText('Pause') globalStatusMenuItem.setText('Aether is connected.') else: globals.appIsPaused = True self.togglePauseMenuItem.setText('Resume') self.globalStatusMenuItem.setText('Aether is paused.') self.togglePauseMenuItem.triggered.connect(togglePause) if not globals.appStartedAtBoot: self.menu.addAction('Show Aether') else: self.menu.addAction('Hide Aether') self.toggleVisibilityMenuItem = self.menu.actions()[5] def toggleVisibility(): if parent.isHidden(): parent.show() parent.raise_() # if globals.PLATFORM == 'OSX': # globals.raiseAndFocusApp() #FIXME BEFORE RELEASE self.toggleVisibilityMenuItem.setText('Hide Aether') else: parent.hide() parent.lower() self.toggleVisibilityMenuItem.setText('Show Aether') self.toggleVisibilityMenuItem.triggered.connect(toggleVisibility) self.menu.addAction('Email the developer') self.emailDevMenuItem = self.menu.actions()[6] def emailDev(): mailInitialiser = \ QUrl('mailto:[email protected]' '?subject=Feedback for Aether' '&body=<i><br><br>Hello there! Thanks for taking time to give feedback, I really appreciate it. ' 'If you are having problems, please right click on Aether.app on your Applications folder, ' 'click Show Package Contents, go to Contents/MacOS/Logs and attach the network.log file there to ' 'this email. <br><br>' 'You can delete this text before sending.' '<br><br>You can find my PGP key here:</i> ' 'http://pgp.mit.edu:11371/pks/lookup?search=Burak+Nehbit') QtGui.QDesktopServices.openUrl(mailInitialiser) self.emailDevMenuItem.triggered.connect(emailDev) self.menu.addSeparator() # 5 self.menu.addAction('Quit') self.quitAppMenuItem = self.menu.actions()[8] # This is below reactor.run to allow access from other places outside main. def quitApp(): # This is buggy... # if parent.reactor.threadpool is not None: # parent.reactor.threadpool.stop() # parent.close() print('firing kill app on prot instance') self.protInstance.killApp() # def finishExit(): # parent.reactor.stop() # app.quit() # sys.exit() # d.addCallback(finishExit) self.quitAppMenuItem.triggered.connect(quitApp) self.setContextMenu(self.menu) self.setIcon(self.icon) def changeIconToActiveState(): self.setIcon(self.iconActive) def changeIconToPassiveState(): self.setIcon(self.icon) self.menu.aboutToShow.connect(changeIconToActiveState) self.menu.aboutToHide.connect(changeIconToPassiveState) if globals.PLATFORM == 'WIN': def showOnLeftClick(reason): if reason == self.Trigger: toggleVisibility() # I hate that Python doesn't have anonymous functions. self.activated.connect(showOnLeftClick) def lightUpIcon(self): self.setIcon(self.iconHighlight) self.messagesMenuItem.setText('New replies available.') self.messagesMenuItem.setDisabled(False) self.toggleVisibilityMenuItem.setText('Hide Aether') def makeIconGoDark(self): self.setIcon(self.icon) self.messagesMenuItem.setText('You have no replies.') self.messagesMenuItem.setDisabled(True)
def contextMenuEvent(self, event): """ Creates two context menus: 1. no modifier -> spellchecker & clear emnu 2. ctrl modifier -> Text change & Insert symbol """ contextMenu = self.createStandardContextMenu() spellMenu = True if (QApplication.keyboardModifiers() & Qt.ControlModifier): spellMenu = False self.clearAction = QAction(self.tr("Clear"), contextMenu) contextMenu.addSeparator() contextMenu.addAction(self.clearAction) if not len(self.toPlainText()): self.clearAction.setEnabled(False) self.clearAction.triggered.connect(self.clear) if not spellMenu: textOpsMenu = QMenu(self.tr("Text change...")) removeEOLAction = QAction(self.tr("Join lines"), textOpsMenu, ) textOpsMenu.addAction(removeEOLAction) removeEOLAction.triggered.connect(self.removeEOL) textOpsMenu.addSeparator() toUppercaseAction = QAction(self.tr("to UPPERCASE"), textOpsMenu) textOpsMenu.addAction(toUppercaseAction) toUppercaseAction.triggered.connect(self.toUppercase) toLowercaseAction = QAction(self.tr("to lowercase"), textOpsMenu) textOpsMenu.addAction(toLowercaseAction) toLowercaseAction.triggered.connect(self.toLowercase) toTitleAction = QAction(self.tr("to Title"), textOpsMenu) textOpsMenu.addAction(toTitleAction) toTitleAction.triggered.connect(self.toTitlecase) toCapsAction = QAction(self.tr("to Capitalize"), textOpsMenu) textOpsMenu.addAction(toCapsAction) toCapsAction.triggered.connect(self.toCaps) contextMenu.insertSeparator(contextMenu.actions()[0]) contextMenu.insertMenu(contextMenu.actions()[0], textOpsMenu) insertSymbolMenu = QMenu(self.tr("Insert symbol...")) settings_symbols = settings.get('editor:symbols') if settings_symbols: self.symbols = settings_symbols.split('\n') for symbol in self.symbols: action = SpellAction(symbol, insertSymbolMenu) action.correct.connect( self.insertSymbol) insertSymbolMenu.addAction(action) contextMenu.insertMenu(contextMenu.actions()[0], insertSymbolMenu) if not self.textCursor().hasSelection() and spellMenu: # Select the word under the cursor for spellchecker cursor = self.textCursor() cursor.select(QTextCursor.WordUnderCursor) self.setTextCursor(cursor) text = self.textCursor().selectedText() #TODO: put to configuration list of ignored starting/ending chars # remove u"„" from selection if text.startswith(u"„") or text.startswith(u"“"): text = text[1:] selectionEnd = cursor.selectionEnd() cursor.setPosition(cursor.position() - len(text)) cursor.setPosition(selectionEnd, QTextCursor.KeepAnchor) self.setTextCursor(cursor) # remove u"”" from selection if text.endswith(u"”") or text.startswith(u"“"): selectionEnd = cursor.selectionEnd() cursor.setPosition(cursor.position() - len(text)) cursor.setPosition(selectionEnd - 1, QTextCursor.KeepAnchor) text = text[:-1] self.setTextCursor(cursor) # Check if the selected word is misspelled and offer spelling # suggestions if it is. if self.textCursor().hasSelection(): if not self.dict.check(text): spell_menu = QMenu(self.tr("Spelling Suggestions")) addWordAcction = QAction(self.tr('Add word...'), spell_menu) addWordAcction.triggered.connect(self.addWord) spell_menu.addAction(addWordAcction) for word in self.dict.suggest(text): action = SpellAction(word, spell_menu) action.correct.connect(self.changeText) spell_menu.addAction(action) contextMenu.insertSeparator(contextMenu.actions()[1]) contextMenu.insertMenu(contextMenu.actions()[0], spell_menu) # Only add the spelling suggests to the menu if there are # suggestions. if len(spell_menu.actions()) != 1: spell_menu.insertSeparator(spell_menu.actions()[1]) contextMenu.exec_(event.globalPos()) event.accept()
class SystemTrayIcon(QSystemTrayIcon): def __init__(self, basedir, app, parent=None): if PLATFORM == 'OSX': if app.devicePixelRatio() == 2: self.icon = QtGui.QIcon(BASEDIR+'Assets/aether-black-tray.svg') self.iconActive = QtGui.QIcon(BASEDIR+'Assets/aether-white-tray.svg') self.iconHighlight = QtGui.QIcon(BASEDIR+'Assets/aether-blue-tray.svg') else: self.icon = QtGui.QIcon(BASEDIR+'Assets/aether-black-tray.png') self.iconActive = QtGui.QIcon(BASEDIR+'Assets/aether-white-tray.png') self.iconHighlight = QtGui.QIcon(BASEDIR+'Assets/aether-blue-tray.png') elif PLATFORM == 'WIN': self.icon = QtGui.QIcon(BASEDIR+'Assets/aether-white-tray-win.svg') self.iconActive = self.icon self.iconHighlight = QtGui.QIcon(BASEDIR+'Assets/aether-green-tray-win.svg') else: pass QSystemTrayIcon.__init__(self, self.icon, parent) self.menu = QMenu(parent) if globals.appIsPaused: self.menu.addAction('Paused').setDisabled(True) else: self.menu.addAction('Online').setDisabled(True) self.globalStatusMenuItem = self.menu.actions()[0] self.menu.addSeparator() # 1 self.menu.addAction('You have no replies.').setDisabled(True) self.messagesMenuItem = self.menu.actions()[2] def goToMessages(): self.messagesMenuItem.setText('You have no replies.') self.messagesMenuItem.setDisabled(True) parent.show() parent.raise_() jsString = \ ("firstFrameScope = angular.element(document.getElementById('first-frame-contents')).scope();" "firstFrameScope.repliesButtonClick();" "firstFrameScope.$apply();" ) self.webView.JSContext(jsString) # reach out to jscontext and # Here, I need to call qtwebkit and tell it to open messages. self.messagesMenuItem.triggered.connect(goToMessages) self.menu.addSeparator() # 3 if globals.appIsPaused: self.menu.addAction('Resume') else: self.menu.addAction('Pause') self.togglePauseMenuItem = self.menu.actions()[4] def togglePause(): if globals.appIsPaused: globals.appIsPaused = False self.togglePauseMenuItem.setText('Pause') self.globalStatusMenuItem.setText('Online') else: globals.appIsPaused = True self.togglePauseMenuItem.setText('Resume') self.globalStatusMenuItem.setText('Paused') self.togglePauseMenuItem.triggered.connect(togglePause) self.menu.addAction('Show Aether') self.toggleVisibilityMenuItem = self.menu.actions()[5] def makeVisible(): parent.show() parent.raise_() if PLATFORM == 'OSX': globals.raiseAndFocusApp() self.toggleVisibilityMenuItem.triggered.connect(makeVisible) self.menu.addAction('Email the developer') self.emailDevMenuItem = self.menu.actions()[6] def emailDev(): mailInitialiser = \ QUrl('mailto:[email protected]' '?subject=Feedback for Aether' '&body=Hello there! Thanks for taking time to give feedback, I really appreciate it. ' 'If you are having problems, please follow the directions at www.getaether.net/sending_logs, ' 'and send me the produced logs. Thanks! You can delete this text before sending. ' 'You can find my PGP key here: pgp.mit.edu:11371/pks/lookup?search=Burak+Nehbit') QtGui.QDesktopServices.openUrl(mailInitialiser) self.emailDevMenuItem.triggered.connect(emailDev) self.menu.addSeparator() # 5 self.menu.addAction('Settings') self.settingsMenuItem = self.menu.actions()[8] def goToSettings(): self.settingsMenuItem.setText('Settings') self.settingsMenuItem.setDisabled(False) if parent.isHidden(): parent.show() parent.raise_() jsString = \ ("firstFrameScope = angular.element(document.getElementById('first-frame-contents')).scope();" "firstFrameScope.settingsButtonClick();" "firstFrameScope.$apply();" ) self.webView.JSContext(jsString) self.settingsMenuItem.triggered.connect(goToSettings) self.menu.addSeparator() # 6 self.menu.addAction('Quit Aether') self.quitAppMenuItem = self.menu.actions()[10] # This is below reactor.run to allow access from other places outside main. def quitApp(): # This is buggy... if parent.reactor.threadpool is not None: parent.reactor.threadpool.stop() parent.close() parent.reactor.stop() app.quit() sys.exit() # self.protInstance.killApp() # def finishExit(): # parent.reactor.stop() # app.quit() # sys.exit() # d.addCallback(finishExit) self.quitAppMenuItem.triggered.connect(quitApp) self.setContextMenu(self.menu) self.setIcon(self.icon) def changeIconToActiveState(): self.setIcon(self.iconActive) def changeIconToPassiveState(): self.setIcon(self.icon) self.menu.aboutToShow.connect(changeIconToActiveState) self.menu.aboutToHide.connect(changeIconToPassiveState) if PLATFORM == 'WIN': def showOnLeftClick(reason): if reason == self.Trigger: makeVisible() # I hate that Python doesn't have anonymous functions. self.activated.connect(showOnLeftClick) def lightUpIcon(self): self.setIcon(self.iconHighlight) self.messagesMenuItem.setText('New replies available.') self.messagesMenuItem.setDisabled(False) def makeIconGoDark(self): self.setIcon(self.icon) self.messagesMenuItem.setText('You have no replies.') self.messagesMenuItem.setDisabled(True)