class Shortcuts(preferences.Page): def __init__(self, dialog): super(Shortcuts, self).__init__(dialog) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.scheme = SchemeSelector(self) layout.addWidget(self.scheme) self.tree = QTreeWidget(self) self.tree.setHeaderLabels([_("Command"), _("Shortcut")]) self.tree.setRootIsDecorated(False) self.tree.setColumnCount(2) self.tree.setAllColumnsShowFocus(True) self.tree.setAnimated(True) layout.addWidget(self.tree) self.edit = QPushButton(icons.get("preferences-desktop-keyboard-shortcuts"), '') layout.addWidget(self.edit) # signals self.scheme.currentChanged.connect(self.slotSchemeChanged) self.scheme.changed.connect(self.changed) self.tree.currentItemChanged.connect(self.slotCurrentItemChanged) self.tree.itemDoubleClicked.connect(self.editCurrentItem) self.edit.clicked.connect(self.editCurrentItem) # make a dict of all actions with the actions as key and the names as # value, with the collection prepended (for loading/saving) win = dialog.parent() allactions = {} for collection in actioncollectionmanager.manager(win).actionCollections(): for name, action in collection.actions().items(): allactions[action] = (collection, name) # keep a list of actions not in the menu structure left = allactions.keys() def add_actions(menuitem, actions): """Add actions to a QTreeWidgetItem.""" for a in actions: if a.menu(): item = build_menu_item(a) if item.childCount(): menuitem.addChild(item) elif a in left: left.remove(a) menuitem.addChild(ShortcutItem(a, *allactions[a])) menuitem.setFlags(Qt.ItemIsEnabled) # disable selection def build_menu_item(action): """Return a QTreeWidgetItem with children for all the actions in the submenu.""" menuitem = QTreeWidgetItem() text = qutil.removeAccelelator(action.text()) menuitem.setText(0, _("Menu {name}").format(name=text)) add_actions(menuitem, action.menu().actions()) return menuitem # present the actions nicely ordered as in the menus for a in win.menuBar().actions(): menuitem = build_menu_item(a) if menuitem.childCount(): self.tree.addTopLevelItem(menuitem) # sort leftover actions left.sort(key=lambda i: i.text()) # show actions that are left, grouped by collection titlegroups = {} for a in left[:]: # copy collection, name = allactions[a] if collection.title(): titlegroups.setdefault(collection.title(), []).append(a) left.remove(a) for title in sorted(titlegroups): item = QTreeWidgetItem(["{0}:".format(title)]) for a in titlegroups[title]: item.addChild(ShortcutItem(a, *allactions[a])) self.tree.addTopLevelItem(item) item.setFlags(Qt.ItemIsEnabled) # disable selection # show other actions that were not in the menus item = QTreeWidgetItem([_("Other commands:")]) for a in left: if a.text() and not a.menu(): item.addChild(ShortcutItem(a, *allactions[a])) if item.childCount(): self.tree.addTopLevelItem(item) item.setFlags(Qt.ItemIsEnabled) # disable selection self.tree.expandAll() item = self.tree.topLevelItem(0).child(0) if _lastaction: # find the previously selected item for i in self.items(): if i.name == _lastaction: item = i break self.tree.setCurrentItem(item) self.tree.resizeColumnToContents(0) def items(self): """Yield all the items in the actions tree.""" def children(item): for i in range(item.childCount()): c = item.child(i) if c.childCount(): for c1 in children(c): yield c1 else: yield c for c in children(self.tree.invisibleRootItem()): yield c def saveSettings(self): self.scheme.saveSettings("shortcut_scheme", "shortcut_schemes", "shortcuts") for item in self.items(): for scheme in self.scheme.schemes(): item.save(scheme) item.clearSettings() item.switchScheme(self.scheme.currentScheme()) def loadSettings(self): self.scheme.loadSettings("shortcut_scheme", "shortcut_schemes") # clear the settings in all the items for item in self.items(): item.clearSettings() item.switchScheme(self.scheme.currentScheme()) def slotSchemeChanged(self): """Called when the Scheme combobox is changed by the user.""" for item in self.items(): item.switchScheme(self.scheme.currentScheme()) def slotCurrentItemChanged(self, item): if isinstance(item, ShortcutItem): self.edit.setText( _("&Edit Shortcut for \"{name}\"").format(name=item.text(0))) self.edit.setEnabled(True) global _lastaction _lastaction = item.name else: self.edit.setText(_("(no shortcut)")) self.edit.setEnabled(False) def editCurrentItem(self): item = self.tree.currentItem() if not isinstance(item, ShortcutItem): return try: dlg = self._editdialog except AttributeError: dlg = self._editdialog = ShortcutEditDialog(self) scheme = self.scheme.currentScheme() action = item.action(scheme) default = item.defaultShortcuts() if dlg.editAction(action, default): shortcuts = action.shortcuts() # check for conflicts conflicting = [] for i in self.items(): if i is not item: for s1, s2 in itertools.product(i.shortcuts(scheme), shortcuts): if s1.matches(s2) or s2.matches(s1): conflicting.append(i) if conflicting: # show a question dialog msg = [_("This shortcut conflicts with the following command:", "This shortcut conflicts with the following commands:", len(conflicting))] msg.append('<br/>'.join(i.text(0) for i in conflicting)) msg.append(_("Remove the shortcut from that command?", "Remove the shortcut from those commands?", len(conflicting))) msg = '<p>{0}</p>'.format('</p><p>'.join(msg)) res = QMessageBox.warning(self, _("Shortcut Conflict"), msg, QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel) if res == QMessageBox.Yes: # remove from conflicting for i in conflicting: l = i.shortcuts(scheme) for s1 in list(l): # copy for s2 in shortcuts: if s1.matches(s2) or s2.matches(s1): l.remove(s1) i.setShortcuts(l, scheme) elif res == QMessageBox.No: # remove from ourselves for i in conflicting: for s1 in list(shortcuts): # copy for s2 in i.shortcuts(scheme): if s1.matches(s2) or s2.matches(s1): shortcuts.remove(s1) else: return # cancelled # store the shortcut item.setShortcuts(shortcuts, scheme) self.changed.emit()
def __init__(self, dialog): super(Shortcuts, self).__init__(dialog) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.scheme = SchemeSelector(self) layout.addWidget(self.scheme) self.tree = QTreeWidget(self) self.tree.setHeaderLabels([_("Command"), _("Shortcut")]) self.tree.setRootIsDecorated(False) self.tree.setColumnCount(2) self.tree.setAllColumnsShowFocus(True) self.tree.setAnimated(True) layout.addWidget(self.tree) self.edit = QPushButton(icons.get("preferences-desktop-keyboard-shortcuts"), '') layout.addWidget(self.edit) # signals self.scheme.currentChanged.connect(self.slotSchemeChanged) self.scheme.changed.connect(self.changed) self.tree.currentItemChanged.connect(self.slotCurrentItemChanged) self.tree.itemDoubleClicked.connect(self.editCurrentItem) self.edit.clicked.connect(self.editCurrentItem) # make a dict of all actions with the actions as key and the names as # value, with the collection prepended (for loading/saving) win = dialog.parent() allactions = {} for collection in actioncollectionmanager.manager(win).actionCollections(): for name, action in collection.actions().items(): allactions[action] = (collection, name) # keep a list of actions not in the menu structure left = allactions.keys() def add_actions(menuitem, actions): """Add actions to a QTreeWidgetItem.""" for a in actions: if a.menu(): item = build_menu_item(a) if item.childCount(): menuitem.addChild(item) elif a in left: left.remove(a) menuitem.addChild(ShortcutItem(a, *allactions[a])) menuitem.setFlags(Qt.ItemIsEnabled) # disable selection def build_menu_item(action): """Return a QTreeWidgetItem with children for all the actions in the submenu.""" menuitem = QTreeWidgetItem() text = qutil.removeAccelelator(action.text()) menuitem.setText(0, _("Menu {name}").format(name=text)) add_actions(menuitem, action.menu().actions()) return menuitem # present the actions nicely ordered as in the menus for a in win.menuBar().actions(): menuitem = build_menu_item(a) if menuitem.childCount(): self.tree.addTopLevelItem(menuitem) # sort leftover actions left.sort(key=lambda i: i.text()) # show actions that are left, grouped by collection titlegroups = {} for a in left[:]: # copy collection, name = allactions[a] if collection.title(): titlegroups.setdefault(collection.title(), []).append(a) left.remove(a) for title in sorted(titlegroups): item = QTreeWidgetItem(["{0}:".format(title)]) for a in titlegroups[title]: item.addChild(ShortcutItem(a, *allactions[a])) self.tree.addTopLevelItem(item) item.setFlags(Qt.ItemIsEnabled) # disable selection # show other actions that were not in the menus item = QTreeWidgetItem([_("Other commands:")]) for a in left: if a.text() and not a.menu(): item.addChild(ShortcutItem(a, *allactions[a])) if item.childCount(): self.tree.addTopLevelItem(item) item.setFlags(Qt.ItemIsEnabled) # disable selection self.tree.expandAll() item = self.tree.topLevelItem(0).child(0) if _lastaction: # find the previously selected item for i in self.items(): if i.name == _lastaction: item = i break self.tree.setCurrentItem(item) self.tree.resizeColumnToContents(0)
class Shortcuts(preferences.Page): def __init__(self, dialog): super(Shortcuts, self).__init__(dialog) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.scheme = SchemeSelector(self) layout.addWidget(self.scheme) self.tree = QTreeWidget(self) self.tree.setHeaderLabels([_("Command"), _("Shortcut")]) self.tree.setRootIsDecorated(False) self.tree.setColumnCount(2) self.tree.setAllColumnsShowFocus(True) self.tree.setAnimated(True) layout.addWidget(self.tree) self.edit = QPushButton( icons.get("preferences-desktop-keyboard-shortcuts"), '') layout.addWidget(self.edit) # signals self.scheme.currentChanged.connect(self.slotSchemeChanged) self.scheme.changed.connect(self.changed) self.tree.currentItemChanged.connect(self.slotCurrentItemChanged) self.tree.itemDoubleClicked.connect(self.editCurrentItem) self.edit.clicked.connect(self.editCurrentItem) # make a dict of all actions with the actions as key and the names as # value, with the collection prepended (for loading/saving) win = dialog.parent() allactions = {} for collection in actioncollectionmanager.manager( win).actionCollections(): for name, action in collection.actions().items(): allactions[action] = (collection, name) # keep a list of actions not in the menu structure left = list(allactions.keys()) def add_actions(menuitem, actions): """Add actions to a QTreeWidgetItem.""" for a in actions: if a.menu(): item = build_menu_item(a) if item.childCount(): menuitem.addChild(item) elif a in left: left.remove(a) menuitem.addChild(ShortcutItem(a, *allactions[a])) menuitem.setFlags(Qt.ItemIsEnabled) # disable selection def build_menu_item(action): """Return a QTreeWidgetItem with children for all the actions in the submenu.""" menuitem = QTreeWidgetItem() text = qutil.removeAccelerator(action.text()) menuitem.setText(0, _("Menu {name}").format(name=text)) add_actions(menuitem, action.menu().actions()) return menuitem # present the actions nicely ordered as in the menus for a in win.menuBar().actions(): menuitem = build_menu_item(a) if menuitem.childCount(): self.tree.addTopLevelItem(menuitem) # sort leftover actions left.sort(key=lambda i: i.text()) # show actions that are left, grouped by collection titlegroups = {} for a in left[:]: # copy collection, name = allactions[a] if collection.title(): titlegroups.setdefault(collection.title(), []).append(a) left.remove(a) for title in sorted(titlegroups): item = QTreeWidgetItem(["{0}:".format(title)]) for a in titlegroups[title]: item.addChild(ShortcutItem(a, *allactions[a])) self.tree.addTopLevelItem(item) item.setFlags(Qt.ItemIsEnabled) # disable selection # show other actions that were not in the menus item = QTreeWidgetItem([_("Other commands:")]) for a in left: if a.text() and not a.menu(): item.addChild(ShortcutItem(a, *allactions[a])) if item.childCount(): self.tree.addTopLevelItem(item) item.setFlags(Qt.ItemIsEnabled) # disable selection self.tree.expandAll() item = self.tree.topLevelItem(0).child(0) if _lastaction: # find the previously selected item for i in self.items(): if i.name == _lastaction: item = i break self.tree.setCurrentItem(item) self.tree.resizeColumnToContents(0) def items(self): """Yield all the items in the actions tree.""" def children(item): for i in range(item.childCount()): c = item.child(i) if c.childCount(): for c1 in children(c): yield c1 else: yield c for c in children(self.tree.invisibleRootItem()): yield c def item(self, collection, name): for item in self.items(): if item.collection.name == collection and item.name == name: return item def saveSettings(self): self.scheme.saveSettings("shortcut_scheme", "shortcut_schemes", "shortcuts") for item in self.items(): for scheme in self.scheme.schemes(): item.save(scheme) item.clearSettings() item.switchScheme(self.scheme.currentScheme()) def loadSettings(self): self.scheme.loadSettings("shortcut_scheme", "shortcut_schemes") # clear the settings in all the items for item in self.items(): item.clearSettings() item.switchScheme(self.scheme.currentScheme()) def slotSchemeChanged(self): """Called when the Scheme combobox is changed by the user.""" for item in self.items(): item.switchScheme(self.scheme.currentScheme()) def slotCurrentItemChanged(self, item): if isinstance(item, ShortcutItem): self.edit.setText( _("&Edit Shortcut for \"{name}\"").format(name=item.text(0))) self.edit.setEnabled(True) global _lastaction _lastaction = item.name else: self.edit.setText(_("(no shortcut)")) self.edit.setEnabled(False) def import_(self, filename): from . import import_export import_export.importShortcut(filename, self, self.scheme) def export(self, name, filename): from . import import_export try: import_export.exportShortcut(self, self.scheme.currentScheme(), name, filename) except (IOError, OSError) as e: QMessageBox.critical( self, _("Error"), _("Can't write to destination:\n\n{url}\n\n{error}").format( url=filename, error=e.strerror)) def findShortcutConflict(self, shortcut): """Find the possible shortcut conflict and return the conflict name.""" if shortcut: item = self.tree.currentItem() if not isinstance(item, ShortcutItem): return None scheme = self.scheme.currentScheme() for i in self.items(): a = i.action(scheme) if i != item and a.shortcuts(): for s1 in a.shortcuts(): if s1.matches(shortcut) or shortcut.matches(s1): return qutil.removeAccelerator(a.text()) return None def editCurrentItem(self): item = self.tree.currentItem() if not isinstance(item, ShortcutItem): return dlg = ShortcutEditDialog(self, self.findShortcutConflict) scheme = self.scheme.currentScheme() action = item.action(scheme) default = item.defaultShortcuts() or None if dlg.editAction(action, default): shortcuts = action.shortcuts() # check for conflicts conflicting = [] for i in self.items(): if i is not item: for s1, s2 in itertools.product(i.shortcuts(scheme), shortcuts): if s1.matches(s2) or s2.matches(s1): conflicting.append(i) if conflicting: for i in conflicting: l = i.shortcuts(scheme) for s1 in list(l): # copy for s2 in shortcuts: if s1.matches(s2) or s2.matches(s1): l.remove(s1) i.setShortcuts(l, scheme) # store the shortcut item.setShortcuts(shortcuts, scheme) self.changed.emit()
def __init__(self, dialog): super(Shortcuts, self).__init__(dialog) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.scheme = SchemeSelector(self) layout.addWidget(self.scheme) self.tree = QTreeWidget(self) self.tree.setHeaderLabels([_("Command"), _("Shortcut")]) self.tree.setRootIsDecorated(False) self.tree.setColumnCount(2) self.tree.setAllColumnsShowFocus(True) self.tree.setAnimated(True) layout.addWidget(self.tree) self.edit = QPushButton( icons.get("preferences-desktop-keyboard-shortcuts"), '') layout.addWidget(self.edit) # signals self.scheme.currentChanged.connect(self.slotSchemeChanged) self.scheme.changed.connect(self.changed) self.tree.currentItemChanged.connect(self.slotCurrentItemChanged) self.tree.itemDoubleClicked.connect(self.editCurrentItem) self.edit.clicked.connect(self.editCurrentItem) # make a dict of all actions with the actions as key and the names as # value, with the collection prepended (for loading/saving) win = dialog.parent() allactions = {} for collection in actioncollectionmanager.manager( win).actionCollections(): for name, action in collection.actions().items(): allactions[action] = (collection, name) # keep a list of actions not in the menu structure left = list(allactions.keys()) def add_actions(menuitem, actions): """Add actions to a QTreeWidgetItem.""" for a in actions: if a.menu(): item = build_menu_item(a) if item.childCount(): menuitem.addChild(item) elif a in left: left.remove(a) menuitem.addChild(ShortcutItem(a, *allactions[a])) menuitem.setFlags(Qt.ItemIsEnabled) # disable selection def build_menu_item(action): """Return a QTreeWidgetItem with children for all the actions in the submenu.""" menuitem = QTreeWidgetItem() text = qutil.removeAccelerator(action.text()) menuitem.setText(0, _("Menu {name}").format(name=text)) add_actions(menuitem, action.menu().actions()) return menuitem # present the actions nicely ordered as in the menus for a in win.menuBar().actions(): menuitem = build_menu_item(a) if menuitem.childCount(): self.tree.addTopLevelItem(menuitem) # sort leftover actions left.sort(key=lambda i: i.text()) # show actions that are left, grouped by collection titlegroups = {} for a in left[:]: # copy collection, name = allactions[a] if collection.title(): titlegroups.setdefault(collection.title(), []).append(a) left.remove(a) for title in sorted(titlegroups): item = QTreeWidgetItem(["{0}:".format(title)]) for a in titlegroups[title]: item.addChild(ShortcutItem(a, *allactions[a])) self.tree.addTopLevelItem(item) item.setFlags(Qt.ItemIsEnabled) # disable selection # show other actions that were not in the menus item = QTreeWidgetItem([_("Other commands:")]) for a in left: if a.text() and not a.menu(): item.addChild(ShortcutItem(a, *allactions[a])) if item.childCount(): self.tree.addTopLevelItem(item) item.setFlags(Qt.ItemIsEnabled) # disable selection self.tree.expandAll() item = self.tree.topLevelItem(0).child(0) if _lastaction: # find the previously selected item for i in self.items(): if i.name == _lastaction: item = i break self.tree.setCurrentItem(item) self.tree.resizeColumnToContents(0)
def __init__(self, dialog): super(FontsColors, self).__init__(dialog) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.scheme = SchemeSelector(self) layout.addWidget(self.scheme) self.printScheme = QCheckBox() layout.addWidget(self.printScheme) hbox = QHBoxLayout() self.tree = QTreeWidget(self) self.tree.setHeaderHidden(True) self.tree.setAnimated(True) self.stack = QStackedWidget(self) hbox.addWidget(self.tree) hbox.addWidget(self.stack) layout.addLayout(hbox) hbox = QHBoxLayout() self.fontLabel = QLabel() self.fontChooser = QFontComboBox() self.fontSize = QDoubleSpinBox() self.fontSize.setRange(6.0, 32.0) self.fontSize.setSingleStep(0.5) self.fontSize.setDecimals(1) hbox.addWidget(self.fontLabel) hbox.addWidget(self.fontChooser, 1) hbox.addWidget(self.fontSize) layout.addLayout(hbox) # add the items to our list self.baseColorsItem = i = QTreeWidgetItem() self.tree.addTopLevelItem(i) self.defaultStylesItem = i = QTreeWidgetItem() self.tree.addTopLevelItem(i) self.defaultStyles = {} for name in textformats.defaultStyles: self.defaultStyles[name] = i = QTreeWidgetItem() self.defaultStylesItem.addChild(i) i.name = name self.defaultStylesItem.setExpanded(True) self.allStyles = {} for group, styles in textformats.allStyles: i = QTreeWidgetItem() children = {} self.allStyles[group] = (i, children) self.tree.addTopLevelItem(i) i.group = group for name in styles: j = QTreeWidgetItem() j.name = name i.addChild(j) children[name] = j self.baseColorsWidget = BaseColors(self) self.customAttributesWidget = CustomAttributes(self) self.emptyWidget = QWidget(self) self.stack.addWidget(self.baseColorsWidget) self.stack.addWidget(self.customAttributesWidget) self.stack.addWidget(self.emptyWidget) self.tree.currentItemChanged.connect(self.currentItemChanged) self.tree.setCurrentItem(self.baseColorsItem) self.scheme.currentChanged.connect(self.currentSchemeChanged) self.scheme.changed.connect(self.changed) self.baseColorsWidget.changed.connect(self.baseColorsChanged) self.customAttributesWidget.changed.connect(self.customAttributesChanged) self.fontChooser.currentFontChanged.connect(self.fontChanged) self.fontSize.valueChanged.connect(self.fontChanged) self.printScheme.clicked.connect(self.printSchemeChanged) app.translateUI(self)
class FontsColors(preferences.Page): def __init__(self, dialog): super(FontsColors, self).__init__(dialog) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.scheme = SchemeSelector(self) layout.addWidget(self.scheme) self.printScheme = QCheckBox() layout.addWidget(self.printScheme) hbox = QHBoxLayout() self.tree = QTreeWidget(self) self.tree.setHeaderHidden(True) self.tree.setAnimated(True) self.stack = QStackedWidget(self) hbox.addWidget(self.tree) hbox.addWidget(self.stack) layout.addLayout(hbox) hbox = QHBoxLayout() self.fontLabel = QLabel() self.fontChooser = QFontComboBox() self.fontSize = QDoubleSpinBox() self.fontSize.setRange(6.0, 32.0) self.fontSize.setSingleStep(0.5) self.fontSize.setDecimals(1) hbox.addWidget(self.fontLabel) hbox.addWidget(self.fontChooser, 1) hbox.addWidget(self.fontSize) layout.addLayout(hbox) # add the items to our list self.baseColorsItem = i = QTreeWidgetItem() self.tree.addTopLevelItem(i) self.defaultStylesItem = i = QTreeWidgetItem() self.tree.addTopLevelItem(i) self.defaultStyles = {} for name in textformats.defaultStyles: self.defaultStyles[name] = i = QTreeWidgetItem() self.defaultStylesItem.addChild(i) i.name = name self.defaultStylesItem.setExpanded(True) self.allStyles = {} for group, styles in textformats.allStyles: i = QTreeWidgetItem() children = {} self.allStyles[group] = (i, children) self.tree.addTopLevelItem(i) i.group = group for name in styles: j = QTreeWidgetItem() j.name = name i.addChild(j) children[name] = j self.baseColorsWidget = BaseColors(self) self.customAttributesWidget = CustomAttributes(self) self.emptyWidget = QWidget(self) self.stack.addWidget(self.baseColorsWidget) self.stack.addWidget(self.customAttributesWidget) self.stack.addWidget(self.emptyWidget) self.tree.currentItemChanged.connect(self.currentItemChanged) self.tree.setCurrentItem(self.baseColorsItem) self.scheme.currentChanged.connect(self.currentSchemeChanged) self.scheme.changed.connect(self.changed) self.baseColorsWidget.changed.connect(self.baseColorsChanged) self.customAttributesWidget.changed.connect(self.customAttributesChanged) self.fontChooser.currentFontChanged.connect(self.fontChanged) self.fontSize.valueChanged.connect(self.fontChanged) self.printScheme.clicked.connect(self.printSchemeChanged) app.translateUI(self) def translateUI(self): self.printScheme.setText(_("Use this scheme for printing")) self.fontLabel.setText(_("Font:")) self.baseColorsItem.setText(0, _("Base Colors")) self.defaultStylesItem.setText(0, _("Default Styles")) self.defaultStyleNames = defaultStyleNames() self.allStyleNames = allStyleNames() for name in textformats.defaultStyles: self.defaultStyles[name].setText(0, self.defaultStyleNames[name]) for group, styles in textformats.allStyles: self.allStyles[group][0].setText(0, self.allStyleNames[group][0]) for name in styles: self.allStyles[group][1][name].setText(0, self.allStyleNames[group][1][name]) def currentItemChanged(self, item, previous): if item is self.baseColorsItem: self.stack.setCurrentWidget(self.baseColorsWidget) elif not item.parent(): self.stack.setCurrentWidget(self.emptyWidget) else: data = self.data[self.scheme.currentScheme()] w = self.customAttributesWidget self.stack.setCurrentWidget(w) toptext = None if item.parent() is self.defaultStylesItem: # default style w.setTitle(item.text(0)) w.setTristate(False) w.setTextFormat(data.defaultStyles[item.name]) else: # specific style of specific group group, name = item.parent().group, item.name w.setTitle("{0}: {1}".format(item.parent().text(0), item.text(0))) inherit = textformats.inherits[group].get(name) if inherit: toptext = _("(Inherits: {name})").format(name=self.defaultStyleNames[inherit]) w.setTristate(bool(inherit)) w.setTextFormat(data.allStyles[group][name]) w.setTopText(toptext) def currentSchemeChanged(self): scheme = self.scheme.currentScheme() if scheme not in self.data: self.data[scheme] = textformats.TextFormatData(scheme) self.updateDisplay() if self.tree.currentItem(): self.currentItemChanged(self.tree.currentItem(), None) with util.signalsBlocked(self.printScheme): self.printScheme.setChecked(scheme == self._printScheme) def fontChanged(self): data = self.data[self.scheme.currentScheme()] data.font = self.fontChooser.currentFont() data.font.setPointSizeF(self.fontSize.value()) self.updateDisplay() self.changed.emit() def printSchemeChanged(self): if self.printScheme.isChecked(): self._printScheme = self.scheme.currentScheme() else: self._printScheme = None self.changed.emit() def updateDisplay(self): data = self.data[self.scheme.currentScheme()] with util.signalsBlocked(self.fontChooser, self.fontSize): self.fontChooser.setCurrentFont(data.font) self.fontSize.setValue(data.font.pointSizeF()) with util.signalsBlocked(self): # update base colors for name in textformats.baseColors: self.baseColorsWidget.color[name].setColor(data.baseColors[name]) # update base colors for whole treewidget p = QApplication.palette() p.setColor(QPalette.Base, data.baseColors["background"]) p.setColor(QPalette.Text, data.baseColors["text"]) p.setColor(QPalette.Highlight, data.baseColors["selectionbackground"]) p.setColor(QPalette.HighlightedText, data.baseColors["selectiontext"]) self.tree.setPalette(p) def setItemTextFormat(item, f): font = QFont(data.font) if f.hasProperty(QTextFormat.ForegroundBrush): item.setForeground(0, f.foreground().color()) else: item.setForeground(0, data.baseColors["text"]) if f.hasProperty(QTextFormat.BackgroundBrush): item.setBackground(0, f.background().color()) else: item.setBackground(0, QBrush()) font.setWeight(f.fontWeight()) font.setItalic(f.fontItalic()) font.setUnderline(f.fontUnderline()) item.setFont(0, font) # update looks of default styles for name in textformats.defaultStyles: setItemTextFormat(self.defaultStyles[name], data.defaultStyles[name]) # update looks of all the specific styles for group, styles in textformats.allStyles: children = self.allStyles[group][1] for name in styles: inherit = textformats.inherits[group].get(name) f = QTextCharFormat(data.defaultStyles[inherit]) if inherit else QTextCharFormat() f.merge(data.allStyles[group][name]) setItemTextFormat(children[name], f) def baseColorsChanged(self, name): # keep data up to date with base colors data = self.data[self.scheme.currentScheme()] data.baseColors[name] = self.baseColorsWidget.color[name].color() self.updateDisplay() self.changed.emit() def customAttributesChanged(self): item = self.tree.currentItem() if not item or not item.parent(): return data = self.data[self.scheme.currentScheme()] if item.parent() is self.defaultStylesItem: # a default style has been changed data.defaultStyles[item.name] = self.customAttributesWidget.textFormat() else: # a specific style has been changed group, name = item.parent().group, item.name data.allStyles[group][name] = self.customAttributesWidget.textFormat() self.updateDisplay() self.changed.emit() def loadSettings(self): self.data = {} # holds all data with scheme as key self._printScheme = QSettings().value("printer_scheme", "default") self.scheme.loadSettings("editor_scheme", "editor_schemes") def saveSettings(self): self.scheme.saveSettings("editor_scheme", "editor_schemes", "fontscolors") for scheme in self.scheme.schemes(): if scheme in self.data: self.data[scheme].save(scheme) if self._printScheme: QSettings().setValue("printer_scheme", self._printScheme) else: QSettings().remove("printer_scheme")
def __init__(self, dialog): super(FontsColors, self).__init__(dialog) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.scheme = SchemeSelector(self) layout.addWidget(self.scheme) self.printScheme = QCheckBox() layout.addWidget(self.printScheme) hbox = QHBoxLayout() self.tree = QTreeWidget(self) self.tree.setHeaderHidden(True) self.tree.setAnimated(True) self.stack = QStackedWidget(self) hbox.addWidget(self.tree) hbox.addWidget(self.stack) layout.addLayout(hbox) hbox = QHBoxLayout() self.fontLabel = QLabel() self.fontChooser = QFontComboBox() self.fontSize = QDoubleSpinBox() self.fontSize.setRange(6.0, 32.0) self.fontSize.setSingleStep(0.5) self.fontSize.setDecimals(1) hbox.addWidget(self.fontLabel) hbox.addWidget(self.fontChooser, 1) hbox.addWidget(self.fontSize) layout.addLayout(hbox) # add the items to our list self.baseColorsItem = i = QTreeWidgetItem() self.tree.addTopLevelItem(i) self.defaultStylesItem = i = QTreeWidgetItem() self.tree.addTopLevelItem(i) self.defaultStyles = {} for name in textformats.defaultStyles: self.defaultStyles[name] = i = QTreeWidgetItem() self.defaultStylesItem.addChild(i) i.name = name self.defaultStylesItem.setExpanded(True) self.allStyles = {} for group, styles in ly.colorize.default_mapping(): i = QTreeWidgetItem() children = {} self.allStyles[group] = (i, children) self.tree.addTopLevelItem(i) i.group = group for name, base, clss in styles: j = QTreeWidgetItem() j.name = name j.base = base i.addChild(j) children[name] = j self.baseColorsWidget = BaseColors(self) self.customAttributesWidget = CustomAttributes(self) self.emptyWidget = QWidget(self) self.stack.addWidget(self.baseColorsWidget) self.stack.addWidget(self.customAttributesWidget) self.stack.addWidget(self.emptyWidget) self.tree.currentItemChanged.connect(self.currentItemChanged) self.tree.setCurrentItem(self.baseColorsItem) self.scheme.currentChanged.connect(self.currentSchemeChanged) self.scheme.changed.connect(self.changed) self.baseColorsWidget.changed.connect(self.baseColorsChanged) self.customAttributesWidget.changed.connect( self.customAttributesChanged) self.fontChooser.currentFontChanged.connect(self.fontChanged) self.fontSize.valueChanged.connect(self.fontChanged) self.printScheme.clicked.connect(self.printSchemeChanged) app.translateUI(self)
class FontsColors(preferences.Page): def __init__(self, dialog): super(FontsColors, self).__init__(dialog) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.scheme = SchemeSelector(self) layout.addWidget(self.scheme) self.printScheme = QCheckBox() layout.addWidget(self.printScheme) hbox = QHBoxLayout() self.tree = QTreeWidget(self) self.tree.setHeaderHidden(True) self.tree.setAnimated(True) self.stack = QStackedWidget(self) hbox.addWidget(self.tree) hbox.addWidget(self.stack) layout.addLayout(hbox) hbox = QHBoxLayout() self.fontLabel = QLabel() self.fontChooser = QFontComboBox() self.fontSize = QDoubleSpinBox() self.fontSize.setRange(6.0, 32.0) self.fontSize.setSingleStep(0.5) self.fontSize.setDecimals(1) hbox.addWidget(self.fontLabel) hbox.addWidget(self.fontChooser, 1) hbox.addWidget(self.fontSize) layout.addLayout(hbox) # add the items to our list self.baseColorsItem = i = QTreeWidgetItem() self.tree.addTopLevelItem(i) self.defaultStylesItem = i = QTreeWidgetItem() self.tree.addTopLevelItem(i) self.defaultStyles = {} for name in textformats.defaultStyles: self.defaultStyles[name] = i = QTreeWidgetItem() self.defaultStylesItem.addChild(i) i.name = name self.defaultStylesItem.setExpanded(True) self.allStyles = {} for group, styles in ly.colorize.default_mapping(): i = QTreeWidgetItem() children = {} self.allStyles[group] = (i, children) self.tree.addTopLevelItem(i) i.group = group for name, base, clss in styles: j = QTreeWidgetItem() j.name = name j.base = base i.addChild(j) children[name] = j self.baseColorsWidget = BaseColors(self) self.customAttributesWidget = CustomAttributes(self) self.emptyWidget = QWidget(self) self.stack.addWidget(self.baseColorsWidget) self.stack.addWidget(self.customAttributesWidget) self.stack.addWidget(self.emptyWidget) self.tree.currentItemChanged.connect(self.currentItemChanged) self.tree.setCurrentItem(self.baseColorsItem) self.scheme.currentChanged.connect(self.currentSchemeChanged) self.scheme.changed.connect(self.changed) self.baseColorsWidget.changed.connect(self.baseColorsChanged) self.customAttributesWidget.changed.connect( self.customAttributesChanged) self.fontChooser.currentFontChanged.connect(self.fontChanged) self.fontSize.valueChanged.connect(self.fontChanged) self.printScheme.clicked.connect(self.printSchemeChanged) app.translateUI(self) def translateUI(self): self.printScheme.setText(_("Use this scheme for printing")) self.fontLabel.setText(_("Font:")) self.baseColorsItem.setText(0, _("Base Colors")) self.defaultStylesItem.setText(0, _("Default Styles")) self.defaultStyleNames = defaultStyleNames() self.allStyleNames = allStyleNames() for name in textformats.defaultStyles: self.defaultStyles[name].setText(0, self.defaultStyleNames[name]) for group, styles in ly.colorize.default_mapping(): self.allStyles[group][0].setText(0, self.allStyleNames[group][0]) for name, base, clss in styles: self.allStyles[group][1][name].setText( 0, self.allStyleNames[group][1][name]) def currentItemChanged(self, item, previous): if item is self.baseColorsItem: self.stack.setCurrentWidget(self.baseColorsWidget) elif not item.parent(): self.stack.setCurrentWidget(self.emptyWidget) else: data = self.data[self.scheme.currentScheme()] w = self.customAttributesWidget self.stack.setCurrentWidget(w) toptext = None if item.parent() is self.defaultStylesItem: # default style w.setTitle(item.text(0)) w.setTristate(False) w.setTextFormat(data.defaultStyles[item.name]) else: # specific style of specific group group, name = item.parent().group, item.name w.setTitle("{0}: {1}".format(item.parent().text(0), item.text(0))) inherit = item.base if inherit: toptext = _("(Inherits: {name})").format( name=self.defaultStyleNames[inherit]) w.setTristate(bool(inherit)) w.setTextFormat(data.allStyles[group][name]) w.setTopText(toptext) def currentSchemeChanged(self): scheme = self.scheme.currentScheme() if scheme not in self.data: self.data[scheme] = textformats.TextFormatData(scheme) self.updateDisplay() if self.tree.currentItem(): self.currentItemChanged(self.tree.currentItem(), None) with qutil.signalsBlocked(self.printScheme): self.printScheme.setChecked(scheme == self._printScheme) def fontChanged(self): data = self.data[self.scheme.currentScheme()] data.font = self.fontChooser.currentFont() data.font.setPointSizeF(self.fontSize.value()) self.updateDisplay() self.changed.emit() def printSchemeChanged(self): if self.printScheme.isChecked(): self._printScheme = self.scheme.currentScheme() else: self._printScheme = None self.changed.emit() def addSchemeData(self, scheme, tfd): self.data[scheme] = tfd def currentSchemeData(self): return self.data[self.scheme.currentScheme()] def updateDisplay(self): data = self.data[self.scheme.currentScheme()] with qutil.signalsBlocked(self.fontChooser, self.fontSize): self.fontChooser.setCurrentFont(data.font) self.fontSize.setValue(data.font.pointSizeF()) with qutil.signalsBlocked(self): # update base colors for name in textformats.baseColors: self.baseColorsWidget.color[name].setColor( data.baseColors[name]) # update base colors for whole treewidget p = QApplication.palette() p.setColor(QPalette.Base, data.baseColors['background']) p.setColor(QPalette.Text, data.baseColors['text']) p.setColor(QPalette.Highlight, data.baseColors['selectionbackground']) p.setColor(QPalette.HighlightedText, data.baseColors['selectiontext']) self.tree.setPalette(p) def setItemTextFormat(item, f): font = QFont(data.font) if f.hasProperty(QTextFormat.ForegroundBrush): item.setForeground(0, f.foreground().color()) else: item.setForeground(0, data.baseColors['text']) if f.hasProperty(QTextFormat.BackgroundBrush): item.setBackground(0, f.background().color()) else: item.setBackground(0, QBrush()) font.setWeight(f.fontWeight()) font.setItalic(f.fontItalic()) font.setUnderline(f.fontUnderline()) item.setFont(0, font) # update looks of default styles for name in textformats.defaultStyles: setItemTextFormat(self.defaultStyles[name], data.defaultStyles[name]) # update looks of all the specific styles for group, styles in ly.colorize.default_mapping(): children = self.allStyles[group][1] for name, inherit, clss in styles: f = QTextCharFormat(data.defaultStyles[inherit] ) if inherit else QTextCharFormat() f.merge(data.allStyles[group][name]) setItemTextFormat(children[name], f) def baseColorsChanged(self, name): # keep data up to date with base colors data = self.data[self.scheme.currentScheme()] data.baseColors[name] = self.baseColorsWidget.color[name].color() self.updateDisplay() self.changed.emit() def customAttributesChanged(self): item = self.tree.currentItem() if not item or not item.parent(): return data = self.data[self.scheme.currentScheme()] if item.parent() is self.defaultStylesItem: # a default style has been changed data.defaultStyles[ item.name] = self.customAttributesWidget.textFormat() else: # a specific style has been changed group, name = item.parent().group, item.name data.allStyles[group][ name] = self.customAttributesWidget.textFormat() self.updateDisplay() self.changed.emit() def import_(self, filename): from . import import_export import_export.importTheme(filename, self, self.scheme) def export(self, name, filename): from . import import_export try: import_export.exportTheme(self, name, filename) except (IOError, OSError) as e: QMessageBox.critical( self, _("Error"), _("Can't write to destination:\n\n{url}\n\n{error}").format( url=filename, error=e.strerror)) def loadSettings(self): self.data = {} # holds all data with scheme as key self._printScheme = QSettings().value("printer_scheme", "default", str) self.scheme.loadSettings("editor_scheme", "editor_schemes") def saveSettings(self): self.scheme.saveSettings("editor_scheme", "editor_schemes", "fontscolors") for scheme in self.scheme.schemes(): if scheme in self.data: self.data[scheme].save(scheme) if self._printScheme: QSettings().setValue("printer_scheme", self._printScheme) else: QSettings().remove("printer_scheme")
class Shortcuts(preferences.Page): def __init__(self, dialog): super(Shortcuts, self).__init__(dialog) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.scheme = SchemeSelector(self) layout.addWidget(self.scheme) self.searchEntry = LineEdit() self.searchEntry.setPlaceholderText(_("Search...")) layout.addWidget(self.searchEntry) self.tree = QTreeWidget(self) self.tree.setHeaderLabels([_("Command"), _("Shortcut")]) self.tree.setRootIsDecorated(False) self.tree.setColumnCount(2) self.tree.setAllColumnsShowFocus(True) self.tree.setAnimated(True) layout.addWidget(self.tree) self.edit = QPushButton(icons.get("preferences-desktop-keyboard-shortcuts"), '') layout.addWidget(self.edit) # signals self.searchEntry.textChanged.connect(self.updateFilter) self.scheme.currentChanged.connect(self.slotSchemeChanged) self.scheme.changed.connect(self.changed) self.tree.currentItemChanged.connect(self.slotCurrentItemChanged) self.tree.itemDoubleClicked.connect(self.editCurrentItem) self.edit.clicked.connect(self.editCurrentItem) # make a dict of all actions with the actions as key and the names as # value, with the collection prepended (for loading/saving) win = dialog.parent() allactions = {} for collection in actioncollectionmanager.manager(win).actionCollections(): for name, action in collection.actions().items(): allactions[action] = (collection, name) # keep a list of actions not in the menu structure left = list(allactions.keys()) def add_actions(menuitem, actions): """Add actions to a QTreeWidgetItem.""" for a in actions: if a.menu(): item = build_menu_item(a) if item.childCount(): menuitem.addChild(item) elif a in left: left.remove(a) menuitem.addChild(ShortcutItem(a, *allactions[a])) menuitem.setFlags(Qt.ItemIsEnabled) # disable selection def build_menu_item(action): """Return a QTreeWidgetItem with children for all the actions in the submenu.""" menuitem = QTreeWidgetItem() text = qutil.removeAccelerator(action.text()) menuitem.setText(0, _("Menu {name}").format(name=text)) add_actions(menuitem, action.menu().actions()) return menuitem # present the actions nicely ordered as in the menus for a in win.menuBar().actions(): menuitem = build_menu_item(a) if menuitem.childCount(): self.tree.addTopLevelItem(menuitem) # sort leftover actions left.sort(key=lambda i: i.text()) # show actions that are left, grouped by collection titlegroups = {} for a in left[:]: # copy collection, name = allactions[a] if collection.title(): titlegroups.setdefault(collection.title(), []).append(a) left.remove(a) for title in sorted(titlegroups): item = QTreeWidgetItem(["{0}:".format(title)]) for a in titlegroups[title]: item.addChild(ShortcutItem(a, *allactions[a])) self.tree.addTopLevelItem(item) item.setFlags(Qt.ItemIsEnabled) # disable selection # show other actions that were not in the menus item = QTreeWidgetItem([_("Other commands:")]) for a in left: if a.text() and not a.menu(): item.addChild(ShortcutItem(a, *allactions[a])) if item.childCount(): self.tree.addTopLevelItem(item) item.setFlags(Qt.ItemIsEnabled) # disable selection self.tree.expandAll() item = self.tree.topLevelItem(0).child(0) if _lastaction: # find the previously selected item for i in self.items(): if i.name == _lastaction: item = i break self.tree.setCurrentItem(item) self.tree.resizeColumnToContents(0) def items(self): """Yield all the items in the actions tree.""" def children(item): for i in range(item.childCount()): c = item.child(i) if c.childCount(): for c1 in children(c): yield c1 else: yield c for c in children(self.tree.invisibleRootItem()): yield c def item(self, collection, name): for item in self.items(): if item.collection.name == collection and item.name == name: return item def saveSettings(self): self.scheme.saveSettings("shortcut_scheme", "shortcut_schemes", "shortcuts") for item in self.items(): for scheme in self.scheme.schemes(): item.save(scheme) item.clearSettings() item.switchScheme(self.scheme.currentScheme()) def loadSettings(self): self.scheme.loadSettings("shortcut_scheme", "shortcut_schemes") # clear the settings in all the items for item in self.items(): item.clearSettings() item.switchScheme(self.scheme.currentScheme()) def slotSchemeChanged(self): """Called when the Scheme combobox is changed by the user.""" for item in self.items(): item.switchScheme(self.scheme.currentScheme()) def slotCurrentItemChanged(self, item): if isinstance(item, ShortcutItem): self.edit.setText( _("&Edit Shortcut for \"{name}\"").format(name=item.text(0))) self.edit.setEnabled(True) global _lastaction _lastaction = item.name else: self.edit.setText(_("(no shortcut)")) self.edit.setEnabled(False) def import_(self, filename): from . import import_export import_export.importShortcut(filename, self, self.scheme) def export(self, name, filename): from . import import_export try: import_export.exportShortcut(self, self.scheme.currentScheme(), name, filename) except (IOError, OSError) as e: QMessageBox.critical(self, _("Error"), _( "Can't write to destination:\n\n{url}\n\n{error}").format( url=filename, error=e.strerror)) def findShortcutConflict(self, shortcut): """Find the possible shortcut conflict and return the conflict name.""" if shortcut: item = self.tree.currentItem() if not isinstance(item, ShortcutItem): return None scheme = self.scheme.currentScheme() for i in self.items(): a = i.action(scheme) if i != item and a.shortcuts(): for s1 in a.shortcuts(): if s1.matches(shortcut) or shortcut.matches(s1): return qutil.removeAccelerator(a.text()) return None def editCurrentItem(self): item = self.tree.currentItem() if not isinstance(item, ShortcutItem): return dlg = ShortcutEditDialog(self, self.findShortcutConflict) scheme = self.scheme.currentScheme() action = item.action(scheme) default = item.defaultShortcuts() or None if dlg.editAction(action, default): shortcuts = action.shortcuts() # check for conflicts conflicting = [] for i in self.items(): if i is not item: for s1, s2 in itertools.product(i.shortcuts(scheme), shortcuts): if s1.matches(s2) or s2.matches(s1): conflicting.append(i) if conflicting: for i in conflicting: l = i.shortcuts(scheme) for s1 in list(l): # copy for s2 in shortcuts: if s1.matches(s2) or s2.matches(s1): l.remove(s1) i.setShortcuts(l, scheme) # store the shortcut item.setShortcuts(shortcuts, scheme) self.changed.emit() def updateFilter(self): """Called when the search text changes.""" search = self.searchEntry.text() scheme = self.scheme.currentScheme() def hidechildren(item): hideparent = True for n in range(item.childCount()): c = item.child(n) if c.childCount(): # submenu item if hidechildren(c): c.setHidden(True) else: c.setHidden(False) c.setExpanded(True) hideparent = False elif isinstance(c, ShortcutItem): # shortcut item, should be the case if c.matches(scheme, search): c.setHidden(False) hideparent = False else: c.setHidden(True) return hideparent hidechildren(self.tree.invisibleRootItem())