class SetDialog(QDialog): def __init__(self, parent=None): QDialog.__init__(self,parent) winsettings('setdialog', self) vbox = QVBoxLayout() self._previndex = 0 self.setscombo = QComboBox() setlabel = QLabel('&Sets') setlabel.setBuddy(self.setscombo) vbox.addWidget(setlabel) comboadd = QToolButton() comboadd.setIcon(QIcon(':/filenew.png')) comboadd.setToolTip('Add set') self.connect(comboadd, SIGNAL('clicked()'), self.addSet) hbox = QHBoxLayout() hbox.addWidget(self.setscombo) hbox.addWidget(comboadd) vbox.addLayout(hbox) conditions = QLabel('&Conditions') vbox.addWidget(conditions) self.listbox = ListBox() conditions.setBuddy(self.listbox) listbuttons = ListButtons() listhbox = QHBoxLayout() listhbox.addWidget(self.listbox) listhbox.addLayout(listbuttons) vbox.addLayout(listhbox) label = QLabel('Retrieve values via: ') self.maintag = QComboBox() self.maintag.addItems(['artist', 'title', 'genre', 'album', 'year']) maintaghbox = QHBoxLayout() maintaghbox.addWidget(label) maintaghbox.addWidget(self.maintag) maintaghbox.addStretch() vbox.addLayout(maintaghbox) dispformat = QLabel('Display Format') vbox.addWidget(dispformat) self.texts = [QLineEdit(), QLineEdit()] t = ['Original', 'Duplicates'] for i, text in enumerate(self.texts): label = QLabel(t[i]) label.setBuddy(text) dispbox = QHBoxLayout() dispbox.addWidget(label) dispbox.addWidget(text) vbox.addLayout(dispbox) okcancel = OKCancel() vbox.addLayout(okcancel) self.connect(okcancel, SIGNAL('ok'), self.okClicked) self.connect(okcancel, SIGNAL('cancel'), self.cancelClicked) self.setLayout(vbox) self.fill(loadsets()) listbuttons.connectToWidget(self) def addSet(self): def gettext(): (text, ok) = QInputDialog.getText (self, 'puddletag', 'Enter a name' 'for the set', QLineEdit.Normal) if ok: if self.setscombo.findText(text) > -1: QMessageBox.information (self, 'puddletag', 'The name entered already exists.') return gettext() return text text = gettext() if text: self.setscombo.addItem(text) self._sets.append([unicode(text), ['', ''], []]) self.setscombo.setCurrentIndex(self.setscombo.count() - 1) def fill(self, sets): if not sets: return self._sets = sets self.setscombo.clear() self.setscombo.addItems([z[0] for z in sets]) self.currentSet = sets[0] self.setscombo.setCurrentIndex(0) self.connect(self.setscombo, SIGNAL('currentIndexChanged (int)'), self.changeSet) def _setCurrentSet(self, s): [text.setText(disp) for text, disp in zip(self.texts, s[1])] self.listbox.clear() [self.listbox.addItem(alg.pprint()) for alg in s[2]] index = self.maintag.findText(s[3]) if index > -1: self.maintag.setCurrentIndex(index) else: self.maintag.addItem(s[3]) self.maintag.setCurrentIndex(self.maintag.count() - 1) def _getCurrentSet(self): return self._sets[self.setscombo.currentIndex()] currentSet = property(_getCurrentSet, _setCurrentSet) def changeSet(self, index): i = self._previndex prevset = {'setname': self._sets[i][0], 'disp': [unicode(text.text()) for text in self.texts], 'algs': self._sets[i][2], 'maintag': unicode(self.maintag.currentText())} self._sets[i][1] = prevset['disp'] self._sets[i][2] = prevset['algs'] self._sets[i][3] = prevset['maintag'] saveset(**prevset) self.currentSet = self._sets[index] self._previndex = index def add(self): win = AlgWin(self) win.setModal(True) self.connect(win, SIGNAL('okClicked'), self.addBuddy) win.show() def addBuddy(self, alg): self.listbox.addItem(alg.pprint()) self.currentSet[2].append(alg) def edit(self): win = AlgWin(self, self.currentSet[2][self.listbox.currentRow()]) win.setModal(True) self.connect(win, SIGNAL('okClicked'), self.editBuddy) win.show() def editBuddy(self, alg): self.listbox.item(self.listbox.currentRow()).setText(alg.pprint()) self._sets[self._previndex][2][self.listbox.currentRow()] = alg def moveUp(self): self.listbox.moveUp(self.currentSet[2]) def moveDown(self): self.listbox.moveDown(self.currentSet[2]) def remove(self): del(self.currentSet[2][self.listbox.currentRow()]) self.listbox.takeItem(self.listbox.currentRow()) def okClicked(self): i = self.setscombo.currentIndex() prevset = {'setname': self._sets[i][0], 'disp': [unicode(text.text()) for text in self.texts], 'algs': self._sets[i][2], 'maintag': unicode(self.maintag.currentText())} saveset(**prevset) self.close() self.emit(SIGNAL('setAvailable'), *self.currentSet) def cancelClicked(self): self.close()
class MassTagEdit(QDialog): def __init__(self, tag_sources, profiles=None, parent = None): super(MassTagEdit, self).__init__(parent) self.setWindowTitle(translate('Profile Config', 'Configure Mass Tagging Profiles')) winsettings('masstag_edit', self) self.listbox = ListBox() self.tag_sources = tag_sources okcancel = OKCancel() okcancel.ok.setDefault(True) self.buttonlist = ListButtons() connect = lambda control, signal, slot: self.connect( control, SIGNAL(signal), slot) connect(okcancel, "ok" , self.okClicked) connect(okcancel, "cancel",self.close) connect(self.buttonlist, "add", self.addClicked) connect(self.buttonlist, "edit", self.editClicked) connect(self.buttonlist, "moveup", self.moveUp) connect(self.buttonlist, "movedown", self.moveDown) connect(self.buttonlist, "remove", self.remove) connect(self.buttonlist, "duplicate", self.dupClicked) connect(self.listbox, "itemDoubleClicked (QListWidgetItem *)", self.editClicked) connect(self.listbox, "currentRowChanged(int)", self.enableListButtons) self.enableListButtons(self.listbox.currentRow()) layout = QVBoxLayout() self.setLayout(layout) layout.addWidget(QLabel(translate('Profile Config', 'Masstagging Profiles'))) list_layout = QHBoxLayout() list_layout.addWidget(self.listbox, 1) list_layout.addLayout(self.buttonlist) layout.addLayout(list_layout) layout.addLayout(okcancel) if profiles is not None: self.setProfiles(profiles) def addClicked(self): win = MTProfileEdit(self.tag_sources, parent=self) win.setModal(True) self.connect(win, SIGNAL('profileChanged'), self.addProfile) win.show() def addProfile(self, profile): row = self.listbox.count() self.listbox.addItem(profile.name) self._profiles.append(profile) def dupClicked(self): row = self.listbox.currentRow() if row == -1: return win = MTProfileEdit(self.tag_sources, deepcopy(self._profiles[row]), self) win.setModal(True) self.connect(win, SIGNAL('profileChanged'), self.addProfile) win.show() def editClicked(self, item=None): if item: row = self.listbox.row(item) else: row = self.listbox.currentRow() if row == -1: return win = MTProfileEdit(self.tag_sources, self._profiles[row], self) win.setModal(True) self.connect(win, SIGNAL('profileChanged'), partial(self.replaceProfile, row)) win.show() def enableListButtons(self, val): if val == -1: [button.setEnabled(False) for button in self.buttonlist.widgets[1:]] else: [button.setEnabled(True) for button in self.buttonlist.widgets[1:]] def loadProfiles(self, dirpath=PROFILEDIR): profiles = load_all_mtps(dirpath, self.tag_sources) self.setProfiles(filter(None, profiles)) def moveDown(self): self.listbox.moveDown(self._profiles) def moveUp(self): self.listbox.moveUp(self._profiles) def okClicked(self): self.emit(SIGNAL('profilesChanged'), self._profiles) self.saveProfiles(PROFILEDIR, self._profiles) self.close() def remove(self): row = self.listbox.currentRow() if row == -1: return del(self._profiles[row]) self.listbox.takeItem(row) def replaceProfile(self, row, profile): self._profiles[row] = profile self.listbox.item(row).setText(profile.name) def saveProfiles(self, dirpath, profiles): filenames = {} order = [] for profile in profiles: filename = profile.name + u'.mtp' i = 0 while filename in filenames: filename = u'%s_%d%s' % (profile.name, i, u'.mtp') i += 1 filenames[filename] = profile order.append(profile.name) files = glob.glob(os.path.join(dirpath, '*.mtp')) for f in files: if f not in filenames: try: os.remove(f) except EnvironmentError: pass for filename, profile in filenames.items(): save_mtp(profile, os.path.join(dirpath, filename)) f = open(os.path.join(dirpath, 'order'), 'w') f.write(u'\n'.join(order)) f.close() def setProfiles(self, profiles): self._profiles = profiles for profile in self._profiles: self.listbox.addItem(profile.name)
class SettingsWin(QFrame): def __init__(self, parent = None, cenwid = None, status=None): QFrame.__init__(self, parent) self.title = translate('Settings', "Patterns") connect = lambda c, signal, s: self.connect(c, SIGNAL(signal), s) self.setFrameStyle(QFrame.Box) self.listbox = ListBox() self.listbox.setSelectionMode(self.listbox.ExtendedSelection) buttons = ListButtons() self.listbox.addItems(status['patterns']) hbox = QHBoxLayout() hbox.addWidget(self.listbox) self.setLayout(hbox) vbox = QVBoxLayout() sortlistbox = QPushButton(translate("Pattern Settings", '&Sort')) self._sortOrder = Qt.AscendingOrder connect(sortlistbox, 'clicked()', self._sortListBox) vbox.addWidget(sortlistbox) vbox.addLayout(buttons) vbox.addStretch() hbox.addLayout(vbox) connect(buttons, "add", self.addPattern) connect(buttons, "edit", self.editItem) buttons.duplicate.setVisible(False) self.listbox.connectToListButtons(buttons) self.listbox.editButton = buttons.edit connect(self.listbox, 'itemDoubleClicked(QListWidgetItem *)', self._doubleClicked) def _sortListBox(self): if self._sortOrder == Qt.AscendingOrder: self.listbox.sortItems(Qt.DescendingOrder) self._sortOrder = Qt.DescendingOrder else: self.listbox.sortItems(Qt.AscendingOrder) self._sortOrder = Qt.AscendingOrder def saveSettings(self): patterns = [unicode(self.listbox.item(row).text()) for row in xrange(self.listbox.count())] cparser = PuddleConfig() cparser.setSection('editor', 'patterns', patterns) def addPattern(self): l = self.listbox.item patterns = [unicode(l(z).text()) for z in range(self.listbox.count())] row = self.listbox.currentRow() if row < 0: row = 0 (text, ok) = QInputDialog().getItem(self, 'puddletag', translate("Pattern Settings", 'Enter a pattern'), patterns, row) if ok: self.listbox.clearSelection() self.listbox.addItem(text) self.listbox.setCurrentRow(self.listbox.count() - 1) def _doubleClicked(self, item): self.editItem() def editItem(self, row=None): if row is None: row = self.listbox.currentRow() l = self.listbox.item patterns = [unicode(l(z).text()) for z in range(self.listbox.count())] (text, ok) = QInputDialog().getItem (self, 'puddletag', translate("Pattern Settings", 'Enter a pattern'), patterns, row) if ok: item = l(row) item.setText(text) self.listbox.setItemSelected(item, True) def applySettings(self, control): item = self.listbox.item patterns = [item(row).text() for row in xrange(self.listbox.count())] control.setItems(patterns)
class ShortcutEditor(QDialog): def __init__(self, load=False, parent=None, buttons=False): super(ShortcutEditor, self).__init__(parent) self._names = [] self._hotkeys = [] self._listbox = ListBox() listbuttons = ListButtons() listbuttons.insertStretch(0) self.connect(listbuttons, SIGNAL('add'), self._addShortcut) self.connect(listbuttons, SIGNAL('edit'), self._editShortcut) self.connect(listbuttons, SIGNAL('duplicate'), self._duplicate) self.connect(self._listbox, SIGNAL('itemDoubleClicked (QListWidgetItem *)'), self._editShortcut) self._listbox.connectToListButtons(listbuttons) hbox = QHBoxLayout() hbox.addLayout(create_buddy('Shortcuts', self._listbox, QVBoxLayout())) hbox.addLayout(listbuttons) okcancel = OKCancel() vbox = QVBoxLayout() vbox.addLayout(hbox) if buttons: vbox.addLayout(okcancel) self.setLayout(vbox) self.connect(okcancel, SIGNAL('ok'), self.okClicked) self.connect(okcancel, SIGNAL('cancel'), self.close) if load: self.loadSettings() def _addShortcut(self): shortcuts = get_shortcuts().difference(self._hotkeys).union( i.shortcut for i in self._listbox.items() if i.shortcut) win = Editor('Add Shortcut', u'', self._actions, self.names(), shortcuts, self) win.setModal(True) self.connect(win, SIGNAL('actionChanged'), self.addShortcut) win.show() def addShortcut(self, name, filenames, shortcut=u'', select=True): item = QListWidgetItem(name) item.actionName = name item.filenames = filenames[::] item.shortcut = shortcut self._listbox.addItem(item) if select: self._listbox.setCurrentItem(item, QItemSelectionModel.ClearAndSelect) def applySettings(self, control=None): from puddlestuff.puddletag import remove_shortcuts, add_shortcuts remove_shortcuts('&Actions', self._names) f = open(FILENAME, 'w') f.close() cparser = PuddleConfig(FILENAME) for i, item in enumerate(self._listbox.items()): section = SHORTCUT_SECTION + unicode(i) cparser.set(section, NAME, item.actionName) cparser.set(section, FILENAMES, item.filenames) from puddlestuff.mainwin.funcs import applyaction shortcuts = create_action_shortcuts(applyaction, control) for item, shortcut in zip(self._listbox.items(), shortcuts): if item.shortcut: shortcut.setShortcut(item.shortcut) add_shortcuts('&Actions', shortcuts, save=True) def okClicked(self): self.applySettings() self.close() def _duplicate(self): try: item = self._listbox.selectedItems()[0] except IndexError: return shortcuts = get_shortcuts().difference(self._hotkeys).union( i.shortcut for i in self._listbox.items() if i.shortcut) win = Editor('Duplicate Shortcut', u'', self._actions, self.names(), shortcuts, self) win.setAttrs(item.actionName, self._actions, item.filenames, u'') win.setModal(True) self.connect(win, SIGNAL('actionChanged'), self.addShortcut) win.show() def _editShortcut(self): try: item = self._listbox.selectedItems()[0] except IndexError: return shortcuts = get_shortcuts().difference(self._hotkeys).union( i.shortcut for i in self._listbox.items() if i.shortcut) names = self.names() names.remove(item.actionName) win = Editor('Edit Shortcut', item.shortcut, self._actions, names, shortcuts, self) win.setAttrs(item.actionName, self._actions, item.filenames, item.shortcut) win.setModal(True) self.connect(win, SIGNAL('actionChanged'), partial(self.editShortcut, item)) win.show() def editShortcut(self, item, name, filenames, shortcut): item.actionName = name item.filenames = filenames[::] item.shortcut = shortcut item.setText(name) def loadSettings(self, filename=None, actions=None): self._names = [] self._hotkeys = [] if filename is None: filename = os.path.join(ACTIONDIR, 'action_shortcuts') self._listbox.clear() cparser = PuddleConfig(filename) if actions is None: self._actions = load_actions() else: self._actions = actions from puddlestuff.puddletag import status if status['actions']: shortcuts = dict( (unicode(a.text()), unicode(a.shortcut().toString())) for a in status['actions']) else: shortcuts = {} for section in sorted(cparser.sections()): if section.startswith('Shortcut'): name = cparser.get(section, NAME, 'Default') self._names.append(name) filenames = cparser.get(section, FILENAMES, []) shortcut = shortcuts.get(name, u'') self.addShortcut(name, filenames, shortcut, select=False) self._hotkeys.append(shortcut) def names(self): return [item.actionName for item in self._listbox.items()]
class MTProfileEdit(QDialog): def __init__(self, tag_sources, profile=None, parent=None): super(MTProfileEdit, self).__init__(parent) self.setWindowTitle(translate('Profile Editor', 'Edit Masstagging Profile')) winsettings('masstag_profile', self) self._configs = [] self.tag_sources = tag_sources self._tsps = [] self._name = QLineEdit(translate('Profile Editor', 'Masstagging Profile')) self._desc = QLineEdit() self.listbox = ListBox() self.okcancel = OKCancel() self.okcancel.ok.setDefault(True) self.buttonlist = ListButtons() self.pattern = QLineEdit('%artist% - %album%/%track% - %title%') self.pattern.setToolTip(translate('Profile Editor', "<p>If no tag information is found in a file, " "the tags retrieved using this pattern will be used instead.</p>")) self.albumBound = QSpinBox() self.albumBound.setRange(0,100) self.albumBound.setValue(70) self.albumBound.setToolTip(translate('Profile Editor', "<p>The artist and album fields will be used in " "determining whether an album matches the retrieved one. " "Each field will be compared using a fuzzy matching algorithm. " "If the resulting average match percentage is greater " "or equal than what you specify here it'll be " "considered to match.</p>")) self.matchFields = QLineEdit('artist, title') self.matchFields.setToolTip(translate('Profile Editor', '<p>The fields listed here will be used in ' 'determining whether a file matches a retrieved track. ' 'Each field will be compared using a fuzzy matching ' 'algorithm. If the resulting average match ' 'percentage is greater than the "Minimum Percentage" ' 'it\'ll be considered to match.</p>')) self.trackBound = QSpinBox() self.trackBound.setRange(0,100) self.trackBound.setValue(80) self.jfdi = QCheckBox(translate('Profile Editor', 'Brute force unmatched files.')) self.jfdi.setToolTip(translate('Profile Editor', "<p>Check to enable brute forcing matches. " " If a proper match isn't found for a file, " 'the files will get sorted by filename, ' 'the retrieved tag sources by filename and ' 'corresponding (unmatched) tracks will matched.</p>')) self.existing = QCheckBox(translate('Profile Editor', 'Update empty fields only.')) self.grid = QGridLayout() self.setLayout(self.grid) self.grid.addLayout(create_buddy( translate('Profile Editor', '&Name:'), self._name), 0, 0, 1, 2) self.grid.addLayout(create_buddy( translate('Profile Editor', '&Description'), self._desc), 1, 0, 1, 2) self.grid.addWidget(self.listbox, 2, 0) self.grid.setRowStretch(2, 1) self.grid.addLayout(self.buttonlist, 2, 1) self.grid.addLayout(create_buddy(translate('Profile Editor', 'Pattern to match filenames against.'), self.pattern, QVBoxLayout()), 3, 0, 1, 2) self.grid.addLayout(create_buddy(translate('Profile Editor', 'Minimum percentage required for album matches.'), self.albumBound), 4, 0, 1, 2) self.grid.addLayout(create_buddy(translate('Profile Editor', 'Match tracks using fields: '), self.matchFields, QVBoxLayout()), 5, 0, 1, 2) self.grid.addLayout(create_buddy(translate('Profile Editor', 'Minimum percentage required for track match.'), self.trackBound), 6, 0, 1, 2) self.grid.addWidget(self.jfdi, 7, 0, 1, 2) self.grid.addWidget(self.existing, 8, 0, 1, 2) self.grid.addLayout(self.okcancel, 9, 0, 1, 2) connect = lambda control, signal, slot: self.connect( control, SIGNAL(signal), slot) connect(self.okcancel, "ok" , self.okClicked) connect(self.okcancel, "cancel",self.close) connect(self.buttonlist, "add", self.addClicked) connect(self.buttonlist, "edit", self.editClicked) connect(self.buttonlist, "moveup", self.moveUp) connect(self.buttonlist, "movedown", self.moveDown) connect(self.buttonlist, "remove", self.remove) connect(self.buttonlist, "duplicate", self.dupClicked) connect(self.listbox, "itemDoubleClicked (QListWidgetItem *)", self.editClicked) connect(self.listbox, "currentRowChanged(int)", self.enableListButtons) if profile is not None: self.setProfile(profile) self.enableListButtons(self.listbox.currentRow()) def addClicked(self): win = TSProfileEdit(self.tag_sources, None, self) win.setModal(True) self.connect(win, SIGNAL('profileChanged'), self.addTSProfile) win.show() def addTSProfile(self, profile): row = self.listbox.count() self.listbox.addItem(profile.tag_source.name) self._tsps.append(profile) def dupClicked(self): row = self.listbox.currentRow() if row == -1: return win = TSProfileEdit(self.tag_sources, self._tsps[row], self) win.setModal(True) self.connect(win, SIGNAL('profileChanged'), self.addTSProfile) win.show() def editClicked(self, item=None): if item: row = self.listbox.row(item) else: row = self.listbox.currentRow() if row == -1: return win = TSProfileEdit(self.tag_sources, self._tsps[row], self) win.setModal(True) self.connect(win, SIGNAL('profileChanged'), partial(self.replaceTSProfile, row)) win.show() def replaceTSProfile(self, row, profile): self._tsps[row] = profile self.listbox.item(row).setText(profile.tag_source.name) def enableListButtons(self, val): if val == -1: [button.setEnabled(False) for button in self.buttonlist.widgets[1:]] else: [button.setEnabled(True) for button in self.buttonlist.widgets[1:]] def moveDown(self): self.listbox.moveDown(self._tsps) def moveUp(self): self.listbox.moveUp(self._tsps) def okClicked(self): fields = [z.strip() for z in unicode(self.matchFields.text()).split(u',')] mtp = MassTagProfile(unicode(self._name.text()), unicode(self._desc.text()), fields, None, unicode(self.pattern.text()), self._tsps, self.albumBound.value() / 100.0, self.trackBound.value() / 100.0, self.jfdi.isChecked(), self.existing.isChecked(), u'') self.emit(SIGNAL('profileChanged'), mtp) self.close() def remove(self): row = self.listbox.currentRow() if row == -1: return del(self._tsps[row]) self.listbox.takeItem(row) def setProfile(self, profile): self._tsps = [tsp for tsp in profile.profiles if tsp.tag_source] [self.listbox.addItem(tsp.tag_source.name) for tsp in self._tsps] self.albumBound.setValue(profile.album_bound * 100) self.pattern.setText(profile.file_pattern) self.matchFields.setText(u', '.join(profile.fields)) self.trackBound.setValue(profile.track_bound * 100) self.jfdi.setChecked(profile.jfdi) self._name.setText(profile.name) self._desc.setText(profile.desc) self.existing.setChecked(profile.leave_existing)
class ButtonsAndList(QFrame): def __init__(self, parent=None, title=u'', add_text=ADD_TEXT, help_text=u''): QFrame.__init__(self, parent) self.title = title connect = lambda c, signal, s: self.connect(c, SIGNAL(signal), s) self.setFrameStyle(QFrame.Box) self.listbox = ListBox() self.listbox.setSelectionMode(self.listbox.ExtendedSelection) buttons = ListButtons() hbox = QHBoxLayout() hbox.addWidget(self.listbox) vbox = QVBoxLayout() sortlistbox = QPushButton(translate("Defaults", '&Sort')) self._sortOrder = Qt.AscendingOrder connect(sortlistbox, 'clicked()', self._sortListBox) vbox.addWidget(sortlistbox) vbox.addLayout(buttons) vbox.addStretch() hbox.addLayout(vbox) if help_text: label = QLabel(help_text) layout = QVBoxLayout() layout.addWidget(label) layout.addLayout(hbox, 1) self.setLayout(layout) else: self.setLayout(hbox) connect(buttons, "add", self.addItem) connect(buttons, "edit", self.editItem) buttons.duplicate.setVisible(False) self.listbox.connectToListButtons(buttons) self.listbox.editButton = buttons.edit connect(self.listbox, 'itemDoubleClicked(QListWidgetItem *)', self._doubleClicked) self.addText = add_text def _doubleClicked(self, item): self.editItem() def _sortListBox(self): if self._sortOrder == Qt.AscendingOrder: self.listbox.sortItems(Qt.DescendingOrder) self._sortOrder = Qt.DescendingOrder else: self.listbox.sortItems(Qt.AscendingOrder) self._sortOrder = Qt.AscendingOrder def addItem(self): l = self.listbox.item patterns = [unicode(l(z).text()) for z in range(self.listbox.count())] row = self.listbox.currentRow() if row < 0: row = 0 (text, ok) = QInputDialog().getItem(self, 'puddletag', self.addText, patterns, row) if ok: self.listbox.clearSelection() self.listbox.addItem(text) self.listbox.setCurrentRow(self.listbox.count() - 1) def addItems(self, items): self.listbox.addItems(items) def editItem(self, row=None): if row is None: row = self.listbox.currentRow() l = self.listbox.item patterns = [unicode(l(z).text()) for z in range(self.listbox.count())] (text, ok) = QInputDialog().getItem(self, 'puddletag', self.addText, patterns, row) if ok: item = l(row) item.setText(text) self.listbox.setItemSelected(item, True) def getItems(self): return [item.text() for item in self.listbox.items()]
class Editor(QDialog): def __init__(self, title='Add Action', shortcut=u'', actions=None, names=None, shortcuts=None, parent=None): super(Editor, self).__init__(parent) self.setWindowTitle(title) self._items = {} self._name = QLineEdit('Name') if shortcut and shortcut in shortcuts: shortcuts.remove(shortcut) self._shortcut = puddleobjects.ShortcutEditor(shortcuts) self._shortcut.setText(shortcut) clear = QPushButton(translate('Shortcuts', '&Clear')) self.connect(clear, SIGNAL('clicked()'), self._shortcut.clear) if names is None: names = [] self._names = names self._actionList = ListBox() self.connect(self._actionList, SIGNAL('itemDoubleClicked (QListWidgetItem *)'), self._addAction) self._newActionList = ListBox() listbuttons = ListButtons() listbuttons.duplicate.hide() listbuttons.insertStretch(0) self.connect(listbuttons, SIGNAL('add'), self._addAction) self._newActionList.connectToListButtons(listbuttons) okcancel = OKCancel() self.connect(okcancel, SIGNAL('ok'), self.okClicked) self.connect(okcancel, SIGNAL('cancel'), self.close) self._ok = okcancel.ok self.connect(self._name, SIGNAL('textChanged(const QString)'), self.enableOk) scut_status = QLabel('') self.connect( self._shortcut, SIGNAL('validityChanged'), lambda v: scut_status.setText(u'') if v or (not self._shortcut.text()) else scut_status.setText( translate('Shortcuts', "Invalid shortcut sequence."))) okcancel.insertWidget(0, scut_status) hbox = QHBoxLayout() hbox.addLayout( create_buddy('Actions', self._actionList, QVBoxLayout()), 1) hbox.addLayout(listbuttons, 0) hbox.addLayout( create_buddy('Actions to run for shortcut', self._newActionList, QVBoxLayout()), 1) layout = QVBoxLayout() layout.addLayout(create_buddy('Shortcut &Name: ', self._name)) scut_layout = create_buddy('&Keyboard Shortcut: ', self._shortcut) scut_layout.addWidget(clear) layout.addLayout(scut_layout) layout.addLayout(hbox) layout.addLayout(okcancel) self.setLayout(layout) if actions: self.setActions(actions) def _addAction(self, item=None): if item is None: for item in self._actionList.selectedItems(): self._addAction(item) return new_item = QListWidgetItem(item) new_item._action = item._action self._newActionList.addItem(new_item) self._newActionList.setCurrentItem(new_item, QItemSelectionModel.ClearAndSelect) def enableOk(self, text): if not text or text in self._names: self._ok.setEnabled(False) else: self._ok.setEnabled(True) def okClicked(self): alist = self._newActionList items = map(alist.item, xrange(alist.count())) actions = [item._action[1] for item in items] self.emit( SIGNAL('actionChanged'), unicode(self._name.text()), actions, unicode(self._shortcut.text()) if self._shortcut.valid else u'') self.close() def setActions(self, actions): self._actionList.clear() self._actions = [] for funcs, name, filename in actions: item = QListWidgetItem(name) item.setToolTip(u'\n'.join([func.description() for func in funcs])) item._action = [name, filename] self._actionList.addItem(item) def setName(self, name): self._name.setText(name) def setAttrs(self, name, actions, filenames, shortcut=u''): names = dict([(z[2], z[1]) for z in actions]) self.setActions(actions) self.setName(name) self._newActionList.clear() self.setShortcut(shortcut) if filenames: for filename in filenames: item = QListWidgetItem( names.get(filename, translate('Shortcuts', '(Deleted)'))) item._action = [names.get(filename, u''), filename] self._newActionList.addItem(item) def setShortcut(self, text): self._shortcut.setText(text)
class SettingsWin(QFrame): def __init__(self, parent=None, cenwid=None, status=None): QFrame.__init__(self, parent) self.title = translate('Settings', "Patterns") connect = lambda c, signal, s: self.connect(c, SIGNAL(signal), s) self.setFrameStyle(QFrame.Box) self.listbox = ListBox() self.listbox.setSelectionMode(self.listbox.ExtendedSelection) buttons = ListButtons() self.listbox.addItems(status['patterns']) hbox = QHBoxLayout() hbox.addWidget(self.listbox) self.setLayout(hbox) vbox = QVBoxLayout() sortlistbox = QPushButton(translate("Pattern Settings", '&Sort')) self._sortOrder = Qt.AscendingOrder connect(sortlistbox, 'clicked()', self._sortListBox) vbox.addWidget(sortlistbox) vbox.addLayout(buttons) vbox.addStretch() hbox.addLayout(vbox) connect(buttons, "add", self.addPattern) connect(buttons, "edit", self.editItem) buttons.duplicate.setVisible(False) self.listbox.connectToListButtons(buttons) self.listbox.editButton = buttons.edit connect(self.listbox, 'itemDoubleClicked(QListWidgetItem *)', self._doubleClicked) def _sortListBox(self): if self._sortOrder == Qt.AscendingOrder: self.listbox.sortItems(Qt.DescendingOrder) self._sortOrder = Qt.DescendingOrder else: self.listbox.sortItems(Qt.AscendingOrder) self._sortOrder = Qt.AscendingOrder def saveSettings(self): patterns = [ unicode(self.listbox.item(row).text()) for row in xrange(self.listbox.count()) ] cparser = PuddleConfig() cparser.setSection('editor', 'patterns', patterns) def addPattern(self): l = self.listbox.item patterns = [unicode(l(z).text()) for z in range(self.listbox.count())] row = self.listbox.currentRow() if row < 0: row = 0 (text, ok) = QInputDialog().getItem( self, 'puddletag', translate("Pattern Settings", 'Enter a pattern'), patterns, row) if ok: self.listbox.clearSelection() self.listbox.addItem(text) self.listbox.setCurrentRow(self.listbox.count() - 1) def _doubleClicked(self, item): self.editItem() def editItem(self, row=None): if row is None: row = self.listbox.currentRow() l = self.listbox.item patterns = [unicode(l(z).text()) for z in range(self.listbox.count())] (text, ok) = QInputDialog().getItem( self, 'puddletag', translate("Pattern Settings", 'Enter a pattern'), patterns, row) if ok: item = l(row) item.setText(text) self.listbox.setItemSelected(item, True) def applySettings(self, control): item = self.listbox.item patterns = [item(row).text() for row in xrange(self.listbox.count())] control.setItems(patterns)
class ShortcutEditor(QDialog): def __init__(self, load=False, parent=None, buttons=False): super(ShortcutEditor, self).__init__(parent) self._names = [] self._hotkeys = [] self._listbox = ListBox() listbuttons = ListButtons() listbuttons.insertStretch(0) self.connect(listbuttons, SIGNAL('add'), self._addShortcut) self.connect(listbuttons, SIGNAL('edit'), self._editShortcut) self.connect(listbuttons, SIGNAL('duplicate'), self._duplicate) self.connect(self._listbox, SIGNAL('itemDoubleClicked (QListWidgetItem *)'), self._editShortcut) self._listbox.connectToListButtons(listbuttons) hbox = QHBoxLayout() hbox.addLayout(create_buddy('Shortcuts', self._listbox, QVBoxLayout())) hbox.addLayout(listbuttons) okcancel = OKCancel() vbox = QVBoxLayout() vbox.addLayout(hbox) if buttons: vbox.addLayout(okcancel) self.setLayout(vbox) self.connect(okcancel, SIGNAL('ok'), self.okClicked) self.connect(okcancel, SIGNAL('cancel'), self.close) if load: self.loadSettings() def _addShortcut(self): shortcuts = get_shortcuts().difference(self._hotkeys).union( i.shortcut for i in self._listbox.items() if i.shortcut) win = Editor('Add Shortcut', u'', self._actions, self.names(), shortcuts, self) win.setModal(True) self.connect(win, SIGNAL('actionChanged'), self.addShortcut) win.show() def addShortcut(self, name, filenames, shortcut=u'', select=True): item = QListWidgetItem(name) item.actionName = name item.filenames = filenames[::] item.shortcut = shortcut self._listbox.addItem(item) if select: self._listbox.setCurrentItem(item, QItemSelectionModel.ClearAndSelect) def applySettings(self, control = None): from puddlestuff.puddletag import remove_shortcuts, add_shortcuts remove_shortcuts('&Actions', self._names) f = open(FILENAME, 'w') f.close() cparser = PuddleConfig(FILENAME) for i, item in enumerate(self._listbox.items()): section = SHORTCUT_SECTION + unicode(i) cparser.set(section, NAME, item.actionName) cparser.set(section, FILENAMES, item.filenames) from puddlestuff.mainwin.funcs import applyaction shortcuts = create_action_shortcuts(applyaction, control) for item, shortcut in zip(self._listbox.items(), shortcuts): if item.shortcut: shortcut.setShortcut(item.shortcut) add_shortcuts('&Actions', shortcuts, save=True) def okClicked(self): self.applySettings() self.close() def _duplicate(self): try: item = self._listbox.selectedItems()[0] except IndexError: return shortcuts = get_shortcuts().difference(self._hotkeys).union( i.shortcut for i in self._listbox.items() if i.shortcut) win = Editor('Duplicate Shortcut', u'', self._actions, self.names(), shortcuts, self) win.setAttrs(item.actionName, self._actions, item.filenames, u'') win.setModal(True) self.connect(win, SIGNAL('actionChanged'), self.addShortcut) win.show() def _editShortcut(self): try: item = self._listbox.selectedItems()[0] except IndexError: return shortcuts = get_shortcuts().difference(self._hotkeys).union( i.shortcut for i in self._listbox.items() if i.shortcut) names = self.names() names.remove(item.actionName) win = Editor('Edit Shortcut', item.shortcut, self._actions, names, shortcuts, self) win.setAttrs(item.actionName, self._actions, item.filenames, item.shortcut) win.setModal(True) self.connect(win, SIGNAL('actionChanged'), partial(self.editShortcut, item)) win.show() def editShortcut(self, item, name, filenames, shortcut): item.actionName = name item.filenames = filenames[::] item.shortcut = shortcut item.setText(name) def loadSettings(self, filename=None, actions=None): self._names = [] self._hotkeys = [] if filename is None: filename = os.path.join(ACTIONDIR, 'action_shortcuts') self._listbox.clear() cparser = PuddleConfig(filename) if actions is None: self._actions = load_actions() else: self._actions = actions from puddlestuff.puddletag import status if status['actions']: shortcuts = dict((unicode(a.text()), unicode(a.shortcut().toString())) for a in status['actions']) else: shortcuts = {} for section in sorted(cparser.sections()): if section.startswith('Shortcut'): name = cparser.get(section, NAME, 'Default') self._names.append(name) filenames = cparser.get(section, FILENAMES, []) shortcut = shortcuts.get(name, u'') self.addShortcut(name, filenames, shortcut, select=False) self._hotkeys.append(shortcut) def names(self): return [item.actionName for item in self._listbox.items()]
class Editor(QDialog): def __init__(self, title='Add Action', shortcut=u'', actions=None, names=None, shortcuts=None, parent=None): super(Editor, self).__init__(parent) self.setWindowTitle(title) self._items = {} self._name = QLineEdit('Name') if shortcut and shortcut in shortcuts: shortcuts.remove(shortcut) self._shortcut = puddleobjects.ShortcutEditor(shortcuts) self._shortcut.setText(shortcut) clear = QPushButton(translate('Shortcuts', '&Clear')) self.connect(clear, SIGNAL('clicked()'), self._shortcut.clear) if names is None: names = [] self._names = names self._actionList = ListBox() self.connect(self._actionList, SIGNAL('itemDoubleClicked (QListWidgetItem *)'), self._addAction) self._newActionList = ListBox() listbuttons = ListButtons() listbuttons.duplicate.hide() listbuttons.insertStretch(0) self.connect(listbuttons, SIGNAL('add'), self._addAction) self._newActionList.connectToListButtons(listbuttons) okcancel = OKCancel() self.connect(okcancel, SIGNAL('ok'), self.okClicked) self.connect(okcancel, SIGNAL('cancel'), self.close) self._ok = okcancel.ok self.connect(self._name, SIGNAL('textChanged(const QString)'), self.enableOk) scut_status = QLabel('') self.connect(self._shortcut, SIGNAL('validityChanged'), lambda v: scut_status.setText(u'') if v or (not self._shortcut.text()) else scut_status.setText(translate('Shortcuts', "Invalid shortcut sequence."))) okcancel.insertWidget(0, scut_status) hbox = QHBoxLayout() hbox.addLayout( create_buddy('Actions', self._actionList, QVBoxLayout()), 1) hbox.addLayout(listbuttons, 0) hbox.addLayout(create_buddy('Actions to run for shortcut', self._newActionList, QVBoxLayout()), 1) layout = QVBoxLayout() layout.addLayout(create_buddy('Shortcut &Name: ', self._name)) scut_layout = create_buddy('&Keyboard Shortcut: ', self._shortcut) scut_layout.addWidget(clear) layout.addLayout(scut_layout) layout.addLayout(hbox) layout.addLayout(okcancel) self.setLayout(layout) if actions: self.setActions(actions) def _addAction(self, item=None): if item is None: for item in self._actionList.selectedItems(): self._addAction(item) return new_item = QListWidgetItem(item) new_item._action = item._action self._newActionList.addItem(new_item) self._newActionList.setCurrentItem(new_item, QItemSelectionModel.ClearAndSelect) def enableOk(self, text): if not text or text in self._names: self._ok.setEnabled(False) else: self._ok.setEnabled(True) def okClicked(self): alist = self._newActionList items = map(alist.item, xrange(alist.count())) actions = [item._action[1] for item in items] self.emit(SIGNAL('actionChanged'), unicode(self._name.text()), actions, unicode(self._shortcut.text()) if self._shortcut.valid else u'') self.close() def setActions(self, actions): self._actionList.clear() self._actions = [] for funcs, name, filename in actions: item = QListWidgetItem(name) item.setToolTip(u'\n'.join([func.description() for func in funcs])) item._action = [name, filename] self._actionList.addItem(item) def setName(self, name): self._name.setText(name) def setAttrs(self, name, actions, filenames, shortcut=u''): names = dict([(z[2], z[1]) for z in actions]) self.setActions(actions) self.setName(name) self._newActionList.clear() self.setShortcut(shortcut) if filenames: for filename in filenames: item = QListWidgetItem(names.get(filename, translate('Shortcuts', '(Deleted)'))) item._action = [names.get(filename, u''), filename] self._newActionList.addItem(item) def setShortcut(self, text): self._shortcut.setText(text)
class ButtonsAndList(QFrame): def __init__(self, parent=None, title=u'', add_text=ADD_TEXT, help_text=u''): QFrame.__init__(self, parent) self.title = title connect = lambda c, signal, s: self.connect(c, SIGNAL(signal), s) self.setFrameStyle(QFrame.Box) self.listbox = ListBox() self.listbox.setSelectionMode(self.listbox.ExtendedSelection) buttons = ListButtons() hbox = QHBoxLayout() hbox.addWidget(self.listbox) vbox = QVBoxLayout() sortlistbox = QPushButton(translate("Defaults", '&Sort')) self._sortOrder = Qt.AscendingOrder connect(sortlistbox, 'clicked()', self._sortListBox) vbox.addWidget(sortlistbox) vbox.addLayout(buttons) vbox.addStretch() hbox.addLayout(vbox) if help_text: label = QLabel(help_text) layout = QVBoxLayout() layout.addWidget(label) layout.addLayout(hbox, 1) self.setLayout(layout) else: self.setLayout(hbox) connect(buttons, "add", self.addItem) connect(buttons, "edit", self.editItem) buttons.duplicate.setVisible(False) self.listbox.connectToListButtons(buttons) self.listbox.editButton = buttons.edit connect(self.listbox, 'itemDoubleClicked(QListWidgetItem *)', self._doubleClicked) self.addText = add_text def _doubleClicked(self, item): self.editItem() def _sortListBox(self): if self._sortOrder == Qt.AscendingOrder: self.listbox.sortItems(Qt.DescendingOrder) self._sortOrder = Qt.DescendingOrder else: self.listbox.sortItems(Qt.AscendingOrder) self._sortOrder = Qt.AscendingOrder def addItem(self): l = self.listbox.item patterns = [unicode(l(z).text()) for z in range(self.listbox.count())] row = self.listbox.currentRow() if row < 0: row = 0 (text, ok) = QInputDialog().getItem(self, 'puddletag', self.addText, patterns, row) if ok: self.listbox.clearSelection() self.listbox.addItem(text) self.listbox.setCurrentRow(self.listbox.count() - 1) def addItems(self, items): self.listbox.addItems(items) def editItem(self, row=None): if row is None: row = self.listbox.currentRow() l = self.listbox.item patterns = [unicode(l(z).text()) for z in range(self.listbox.count())] (text, ok) = QInputDialog().getItem (self, 'puddletag', self.addText, patterns, row) if ok: item = l(row) item.setText(text) self.listbox.setItemSelected(item, True) def getItems(self): return [item.text() for item in self.listbox.items()]