class ArgumentWidget(QWidget): def __init__(self, argument, parent=None): super(ArgumentWidget, self).__init__(parent) self.layout = QHBoxLayout() self.layout.setContentsMargins(1, 0, 1, 1) self.setLayout(self.layout) label = QLabel(argument) self._label = label self._component_id = None self.layout.addWidget(label) self.editor = QLineEdit() self.editor.setReadOnly(True) try: self.editor.setPlaceholderText("Drag a component from above") except AttributeError: # feature added in Qt 4.7 pass self.layout.addWidget(self.editor) self.setAcceptDrops(True) @property def component_id(self): return self._component_id @component_id.setter def component_id(self, cid): self._component_id = cid self.editor.setText(str(cid)) @property def label(self): return self._label.text() @label.setter def label(self, label): self._label.setText(label) @property def editor_text(self): return self.editor.text() def clear(self): self.component_id = None self.editor.clear() def dragEnterEvent(self, event): if event.mimeData().hasFormat('application/py_instance'): event.accept() else: event.ignore() def dropEvent(self, event): obj = event.mimeData().data('application/py_instance') if not isinstance(obj, core.data.ComponentID): return self.component_id = obj
class ReportExportOptionsDialog(QDialog): def __init__(self, exportContent=False): QDialog.__init__(self) self.setWindowTitle(self.tr("Export options")) self.reportManager = ReportManager() layout = QVBoxLayout() self.extractContentCheckBox = QCheckBox(self.tr("E&xtract content")) if exportContent: self.extractContentCheckBox.setChecked(True) else: self.extractContentCheckBox.setChecked(False) layout.addWidget(self.extractContentCheckBox) directoryPathLayout = QHBoxLayout() pathLabel = QLabel(self.tr("Report extraction path :")) self.pathLineEdit = QLineEdit(self.reportManager.export_path) self.pathLineEdit.setReadOnly(True) pathButton = QPushButton("...") self.connect(pathButton, SIGNAL("clicked()"), self.askPath) directoryPathLayout.addWidget(pathLabel) directoryPathLayout.addWidget(self.pathLineEdit) directoryPathLayout.addWidget(pathButton) layout.addLayout(directoryPathLayout) buttonLayout = QHBoxLayout() self.buttonOk = QPushButton("O&k") self.connect(self.buttonOk, SIGNAL("clicked()"), self.accept) self.buttonCancel = QPushButton("C&ancel") self.connect(self.buttonCancel, SIGNAL("clicked()"), self.reject) buttonLayout.addWidget(self.buttonOk) buttonLayout.addWidget(self.buttonCancel) layout.addLayout(buttonLayout) self.setLayout(layout) def askPath(self): directory = QFileDialog.getExistingDirectory( self, self.tr("Report extraction directory"), self.reportManager.export_path) if len(directory): directory = os.path.join(str(directory.toUtf8()), 'dff-report') self.pathLineEdit.clear() self.pathLineEdit.insert(directory) self.reportManager.setExportPath(directory) def exportContent(self): if self.extractContentCheckBox.isChecked(): return True else: return False
class LilyPondDocumentVersion(SettingsGroup): def __init__(self, page): super(LilyPondDocumentVersion, self).__init__(i18n("LilyPond version number to use for new documents"), page) grid = QGridLayout(self) grid.setSpacing(0) self.versionOptions = {} self.customVersion = QLineEdit(textChanged=page.changed) def changed(dummy): page.changed() self.customVersion.setEnabled(self.versionOptions["custom"].isChecked()) for title, name in ( (i18n("Use version number of installed LilyPond"), "lilypond"), (i18n("Use version number of last convert-ly rule"), "convert-ly"), (i18n("Use custom version number:"), "custom"), ): self.versionOptions[name] = QRadioButton(title, toggled=changed) self.customVersion.setToolTip(i18n("Enter a valid LilyPond version number, e.g. 2.12.0")) self.versionOptions["custom"].clicked.connect(lambda: self.customVersion.setFocus()) grid.addWidget(self.versionOptions["lilypond"], 0, 0, 1, 2) grid.addWidget(self.versionOptions["convert-ly"], 1, 0, 1, 2) grid.addWidget(self.versionOptions["custom"], 2, 0, 1, 1) grid.addWidget(self.customVersion, 2, 1, 1, 1) def defaults(self): self.customVersion.clear() self.versionOptions["lilypond"].setChecked(True) def loadSettings(self): conf = config("preferences") self.customVersion.setText(conf.readEntry("custom version", "")) name = conf.readEntry("default version", "") if name not in self.versionOptions: name = "lilypond" self.versionOptions[name].setChecked(True) def saveSettings(self): conf = config("preferences") conf.writeEntry("custom version", self.customVersion.text()) for name, widget in self.versionOptions.items(): if widget.isChecked(): conf.writeEntry("default version", name) break
class embeddedTerminal(QWidget): def __init__(self): QWidget.__init__(self) self._processes = [] self.banned_words = ['exit', 'prohibido'] self.resize(800, 600) self.terminal = QWidget(self) layout = QVBoxLayout(self) layout.addWidget(self.terminal) self.kill_tmux() # self._start_process('tmux', ['new', '-s', 'npy']) # self._start_process('tmux', ['detach-client', '-s', 'npy']) # self._start_process('xterm', # ['-geometry', '640x480+0+0', '-into', str(self.terminal.winId()), # '-e', 'tmux', 'new', '-s', 'npy']) self._start_process('xterm', ['-fa', 'Monospace', '-fs', '14', '-geometry', '640x480+0+0', '-into', str(self.terminal.winId()), '-e', 'tmux', 'new', '-s', 'npy']) self.textBox = QLineEdit(self) self.button = QPushButton('run-in-terminal') self.textBox.returnPressed.connect(self.button.click) layout.addWidget(self.textBox) layout.addWidget(self.button) self.textBox.setFocus() self.button.clicked.connect( lambda: self.run_command(self.textBox.text())) self.button.setAutoDefault(True) def _start_process(self, prog, args): child = QProcess() self._processes.append(child) child.start(prog, args) def run_command(self, command): if command not in self.banned_words: self._start_process( 'tmux', ['send-keys', '-t', 'npy:0', command, 'Enter']) self.textBox.clear() def closeEvent(self, event): self.kill_tmux() event.accept() def kill_tmux(self): self._start_process('tmux', ['kill-server'])
class NumberFormatDlg(QDialog): def __init__(self, format, callback, parent=None): super(NumberFormatDlg, self).__init__(parent) punctuationRe = QRegExp(r"[ ,;:.]") thousandsLabel = QLabel("&Thousands separator") self.thousandsEdit = QLineEdit(format["thousandsseparator"]) thousandsLabel.setBuddy(self.thousandsEdit) self.thousandsEdit.setMaxLength(1) self.thousandsEdit.setValidator(QRegExpValidator( punctuationRe, self)) decimalMarkerLabel = QLabel("Decimal &marker") self.decimalMarkerEdit = QLineEdit(format["decimalmarker"]) decimalMarkerLabel.setBuddy(self.decimalMarkerEdit) self.decimalMarkerEdit.setMaxLength(1) self.decimalMarkerEdit.setValidator(QRegExpValidator( punctuationRe, self)) self.decimalMarkerEdit.setInputMask("X") decimalPlacesLabel = QLabel("&Decimal places") self.decimalPlacesSpinBox = QSpinBox() decimalPlacesLabel.setBuddy(self.decimalPlacesSpinBox) self.decimalPlacesSpinBox.setRange(0, 6) self.decimalPlacesSpinBox.setValue(format["decimalplaces"]) self.redNegativesCheckBox = QCheckBox("&Red negative numbers") self.redNegativesCheckBox.setChecked(format["rednegatives"]) self.format = format self.callback = callback grid = QGridLayout() grid.addWidget(thousandsLabel, 0, 0) grid.addWidget(self.thousandsEdit, 0, 1) grid.addWidget(decimalMarkerLabel, 1, 0) grid.addWidget(self.decimalMarkerEdit, 1, 1) grid.addWidget(decimalPlacesLabel, 2, 0) grid.addWidget(self.decimalPlacesSpinBox, 2, 1) grid.addWidget(self.redNegativesCheckBox, 3, 0, 1, 2) self.setLayout(grid) self.connect(self.thousandsEdit, SIGNAL("textEdited(QString)"), self.checkAndFix) self.connect(self.decimalMarkerEdit, SIGNAL("textEdited(QString)"), self.checkAndFix) self.connect(self.decimalPlacesSpinBox, SIGNAL("valueChanged(int)"), self.apply) self.connect(self.redNegativesCheckBox, SIGNAL("toggled(bool)"), self.apply) self.setWindowTitle("Set Number Format (`Live')") def checkAndFix(self): thousands = unicode(self.thousandsEdit.text()) decimal = unicode(self.decimalMarkerEdit.text()) if thousands == decimal: self.thousandsEdit.clear() self.thousandsEdit.setFocus() if len(decimal) == 0: self.decimalMarkerEdit.setText(".") self.decimalMarkerEdit.selectAll() self.decimalMarkerEdit.setFocus() self.apply() def apply(self): self.format["thousandsseparator"] = ( unicode(self.thousandsEdit.text())) self.format["decimalmarker"] = ( unicode(self.decimalMarkerEdit.text())) self.format["decimalplaces"] = ( self.decimalPlacesSpinBox.value()) self.format["rednegatives"] = ( self.redNegativesCheckBox.isChecked()) self.callback()
class QPyShell(QWidget): """QPyShell - a Qt based python command shell based on code.InteractiveInterpreter. Because it catches stdout and stderr there can be only one active instance of this class. Make sure initInterpreter() and exitInterpreter() is called! """ activeInstance = None def __init__(self, parent=None): QWidget.__init__(self, parent) if parent: self.standalone = False else: self.standalone = True self.setWindowTitle(QCoreApplication.translate("QPyShell", "QPyShell - a simple python shell widget for Qt")) self.mainLayout = QVBoxLayout(self) self.outputBrowser = QTextEdit(self) self.outputBrowser.setMinimumSize(QSize(100,100)) self.outputBrowser.setReadOnly(True) self.mainLayout.addWidget(self.outputBrowser) self.clLayout = QHBoxLayout() self.mainLayout.addLayout(self.clLayout) self.promptLabel = QLabel() self.promptLabel.setText(">>>") self.clLayout.addWidget(self.promptLabel) self.lineInput = QLineEdit() self.lineInput.setToolTip(QCoreApplication.translate('QPyShell', 'The python commandline: enter code her')) self.clLayout.addWidget(self.lineInput) self.enterButton = QToolButton(self) self.enterButton.setText(QCoreApplication.translate("QPyShell", "Enter")) self.enterButton.setToolTip(QCoreApplication.translate('QPyShell', 'This button or [Enter] executes the command')) self.enterButton.setIcon(QIcon(QPixmap(enterXPM))) self.clLayout.addWidget(self.enterButton) self.clLayout.addSpacing(8) self.clearButton = QToolButton(self) self.clearButton.setText(QCoreApplication.translate("QPyShell", "Clear")) self.clearButton.setToolTip(QCoreApplication.translate('QPyShell', 'Clear the output window')) self.clearButton.setIcon(QIcon(QPixmap(clearXPM))) self.clLayout.addWidget(self.clearButton) self.saveButton = QToolButton(self) self.saveButton.setText(QCoreApplication.translate("QPyShell", "Save ...")) self.saveButton.setToolTip(QCoreApplication.translate('QPyShell', 'Save the contents of the output window')) self.saveButton.setIcon(QIcon(QPixmap(saveXPM))) self.clLayout.addWidget(self.saveButton) self.printButton = QToolButton(self) self.printButton.setText(QCoreApplication.translate("QPyShell", "Print")) self.printButton.setToolTip(QCoreApplication.translate('QPyShell', 'Print the contents of the output window')) self.printButton.setIcon(QIcon(QPixmap(printXPM))) self.clLayout.addWidget(self.printButton) self.history = [] self.historyFile = None self.history_i = -1 self.cmdBuffer = [] self.showCompletionLimit = 100 self.interpreter = None self.old_displayhook = None self.cursor = QTextCursor(self.outputBrowser.document()) self.outputBrowser.setTextCursor(self.cursor) self.outputBrowser.append(greeting) self.setTabOrder(self.lineInput, self.outputBrowser) self.setTabOrder(self.outputBrowser, self.enterButton) self.setTabOrder(self.enterButton, self.saveButton) self.setTabOrder(self.saveButton, self.clearButton) self.connect(self.enterButton, SIGNAL("pressed()"), self.run) self.connect(self.saveButton, SIGNAL("pressed()"), self.saveContents) self.connect(self.printButton, SIGNAL("pressed()"), self.printContents) self.connect(self.clearButton, SIGNAL("pressed()"), self.outputBrowser.clear) def initInterpreter(self, loc=None, greet=greeting, historyFile=None): if QPyShell.activeInstance: raise Exception(QCoreApplication.translate("QPyShell", "QPyShell: There can be only one highlander... sorry, I mean one active QPyShell widget!")) QPyShell.activeInstance = self self.loadHistoryFile(historyFile) self.interpreter = InteractiveInterpreter(loc) self.completer = Completer(loc) self.old_stdout = sys.stdout self.old_stderr = sys.stderr sys.stdout = DummyFileW(self.write) sys.stderr = sys.stdout # there's a strange problem with gettext and interactive interpreters # gettext's "_"" will be overwritten by the standard sys.displayhook... self.old_displayhook = sys.displayhook sys.displayhook = mydisplayhook def loadHistoryFile(self, historyFile): self.historyFile = historyFile if historyFile and os.path.exists(historyFile): lines = open(historyFile, 'r').read().split(os.linesep) self.history = [l for l in lines if not l.startswith('#')] def saveHistoryFile(self): if self.historyFile: h = self.history if len(h) > 100: h = h[:100] h.insert(0, unicode(QCoreApplication.translate('QPyShell', '# this is the command history of the QPyShell'))) open(self.historyFile, 'w').write(os.linesep.join(h)) def exitInterpreter(self, loc=None): sys.stdout = self.old_stdout sys.stderr = self.old_stderr self.saveHistoryFile() del self.interpreter self.interpreter = None sys.displayhook = self.old_displayhook QPyShell.ativeInstance = None def run(self): if not self.interpreter: raise Exception(QCoreApplication.translate("QPyShell", "No interpreter found! You need to call QPyShell.initInterpreter() first!")) line = unicode(self.lineInput.text()) self.lineInput.clear() if line: if (not self.history) or line != self.history[0]: # no consecutive identical entries self.history.insert(0, line) self.history_i = -1 self.cursor.movePosition(QTextCursor.End) if not self.cmdBuffer: self.cursor.insertHtml('<br><b>|>>> %s</b><br>' % formatPyLine(line)) else: self.cursor.insertHtml('<br><b>|. . . %s</b><br>' % formatPyLine(line)) self.cursor.movePosition(QTextCursor.End) self.outputBrowser.ensureCursorVisible() self.cmdBuffer.append(line) more = self.interpreter.runsource('\n'.join(self.cmdBuffer)) if more: self.promptLabel.setText('...') else: self.cmdBuffer = [] self.promptLabel.setText('>>>') def appendHtml(self, txt): self.cursor.movePosition(QTextCursor.End) self.cursor.insertHtml(txt) self.cursor.movePosition(QTextCursor.End) self.outputBrowser.ensureCursorVisible() def appendText(self, txt): self.cursor.movePosition(QTextCursor.End) self.outputBrowser.insertPlainText(txt) self.cursor.movePosition(QTextCursor.End) self.outputBrowser.ensureCursorVisible() write = appendText def keyPressEvent(self, event): key = event.key() mod = event.modifiers() if key == Qt.Key_Up and self.history: self.history_i = min(self.history_i+1, len(self.history)-1) self.lineInput.setText(self.history[self.history_i]) elif key == Qt.Key_Down and self.history: self.history_i = max(self.history_i-1, -1) if self.history_i >= 0: self.lineInput.setText(self.history[self.history_i]) else: self.lineInput.setText('') elif key == Qt.Key_Enter or key == Qt.Key_Return: if mod & Qt.ShiftModifier: self.complete() else: self.run() elif key == Qt.Key_Escape: txt, r = QInputDialog.getItem(self, QCoreApplication.translate("QPyShell", "Command line history"), QCoreApplication.translate("QPyShell", "Please select a history item:"), self.history, 0, False) if r and txt: self.lineInput.setText(txt) elif self.standalone and key == Qt.Key_Print: self.printContents() elif self.standalone and key == Qt.Key_Q and (mod & Qt.ControlModifier): self.close() else: QWidget.keyPressEvent(self, event) def closeEvent(self, event): if self.standalone: self.exitInterpreter() QWidget.closeEvent(self, event) def printContents(self, printer=None): if not printer: printer = QPrinter() dialog = QPrintDialog(printer, self) dialog.setWindowTitle(QCoreApplication.translate("QPyShell", "Print Document")) if dialog.exec_() != QDialog.Accepted: return self.outputBrowser.document().print_(printer) def saveContents(self, fileName=None): if not fileName: fileTypes = {'Text':('txt',), 'HTML':('htm', 'html')} filters = ';;'.join(['%s (%s)' % (k, ' '.join(['*.'+e for e in v])) for k, v in fileTypes.items()]) dlg = QFileDialog(self, QCoreApplication.translate('QPyShell', 'Select name of file to save'), os.getcwd(), filters) dlg.setFileMode(QFileDialog.AnyFile) dlg.setAcceptMode(QFileDialog.AcceptSave) if dlg.exec_() != QDialog.Accepted: return tmp = unicode(dlg.selectedFilter()) fileType = tmp[:tmp.find('(')-1] dlg.setDefaultSuffix(fileTypes[fileType][0]) files = dlg.selectedFiles() if not files: return fileName = unicode(files[0]) if fileType == 'Text': txt = self.outputBrowser.toPlainText() elif fileType == 'HTML': txt = self.outputBrowser.toHtml() else: raise IOError('Unknown FileType: %s' % fileType) try: open(fileName, 'w').write(txt) except IOError: QMessageBox.critical(self, QCoreApplication.translate('QPyShell', 'Could not save file!'), QCoreApplication.translate('QPyShell', 'Writing failed! Make sure you have write permissions!')) def complete(self): """ a very simple, quick and dirty completion of identifiers in the namespace """ # FIXME: fertig machen! txt = unicode(self.lineInput.text()) cur = self.lineInput.cursorPosition() s = cur while s>0 and txt[s-1] in identChars: s -= 1 try: completions = self.completer.matches(txt[s:cur]) except: return if not completions: return n_comp = len(completions) if n_comp == 1: comp = completions.pop() self.lineInput.insert(comp[cur-s:]) elif n_comp < self.showCompletionLimit: tmp = list(completions) tmp.sort() self.appendHtml('<font color="#0000ff">[%s]</font>' % ', '.join(tmp)) # get common prefix ... stolen from the python cookbook pref = tmp[0][:([min([x[0]==elem for elem in x]) for x in zip(*tmp)]+[0]).index(0)] if len(pref) > (cur-s): self.lineInput.insert(pref[cur-s:]) else: self.appendHtml(unicode(QCoreApplication.translate("QPyShell", '<font color="#0000ff">[Too many completions: %d]</font>')) % n_comp)
class MyWidget(QWidget): def __init__(self): super(MyWidget, self).__init__() self.i = 0 self.setup_window() t = threading.Thread(target=self.setup_networking) t.start() def setup_window(self): self.setWindowTitle("Chat app") self.setGeometry(100, 100, 400, 300) self.layout = QVBoxLayout(self) self.setLayout(self.layout) self.label = QLabel(self) self.textbox = QLineEdit(self) self.textbox.setReadOnly(True) self.layout2 = QHBoxLayout(self) self.chathistory = QTextEdit(self) self.chathistory.setReadOnly(True) self.widget2 = QWidget() self.widget2.setLayout(self.layout2) self.layout.addWidget(self.textbox) self.layout.addWidget(self.chathistory) self.layout2.addWidget(self.label) self.layout.addWidget(self.widget2) #first it'll try to be client and fail. So it will be server. Next time it'll be client # # t3=threading.Thread(target=self.be_client) # t3.start() # t4=threading.Thread(target=self.be_server) # t4.start() def setup_networking(self): try: self.be_client() except: print "unable to connect as client, opening server mode:\n" self.be_server() self.textbox.setReadOnly(False) t2 = threading.Thread(target=self.recv_message) t2.start() self.textbox.returnPressed.connect( self.send_message) #if they press enter, then call send_message fn # self.isclosed = False #doesnt work def be_client(self): host = '127.0.0.1' port = 5000 self.s = socket.socket() print "client socket opened" self.i = t(self.i, True) self.s.connect((host, port)) self.label.setText("<connected>") def be_server(self): host = '127.0.0.1' port = 5000 self.ss = socket.socket() print "temp sock open" self.i = t(self.i, True) self.ss.bind((host, port)) self.ss.listen(1) self.label.setText("<waiting to be connected>") self.s, self.address = self.ss.accept( ) #address is ip address of what tries to connect self.ss.close() print "temp client socket closed" self.i = t(self.i, False) self.label.setText("<connected>") def send_message(self): message = self.textbox.text() if message != "": self.chathistory.append("Sent: " + str(message)) self.s.send(message) self.textbox.clear() else: t2 = threading.Thread(target=self.recv_message) t2.start() sys.stdout.flush() def loner(self): self.label.setText("<Connection Lost>") print "socket closed" self.s.close() self.i = t(self.i, False) print "^should be zero" self.textbox.setReadOnly(True) self.be_server() self.textbox.setReadOnly(False) t2 = threading.Thread(target=self.recv_message) t2.start() def recv_message(self): # try: #so it doesn't keep saying socket.timeout on console if 1 == 1: data = self.s.recv(1024) # print self.isclosed # if self.isclosed is True: #gonna send a blank message when u close window # self.label.setText("<connection closed>") # print "got here" if data == "<close command>": print "Cmnd received" self.loner() # self.label.setText("<Connection Lost>") # print "socket closed" # self.i = t(self.i, False) # print "^should be zero" # self.s.close() # self.textbox.setReadOnly(True) # self.setup_networking() else: self.chathistory.append("Recieved: " + str(data)) sys.stdout.flush() # except socket.timeout: #we dont want it to keep saying it on the console # pass # except socket.error: #when it closes, need to make a new socket # self.s = socket.socket() def closeEvent(self, e): self.s.send("<close command>") print "cmd sent" print "closed window" #self.isclosed=True print "socket closed" self.i = t(self.i, False) print "^ should be zero" self.s.close()
class MainWindow(QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setWindowTitle('Address Book') self.resize(704, 459) self.db_file = self.database_file() self.db = database.Database(self.db_file) dialog = dialogs.UserPanelDlg(self) if dialog.exec_(): self.user = dialog.user else: self.close() self.categComboBox = QComboBox() self.cont_numLabel = QLabel() self.contactsListWidget = QListWidget() self.searchLineEdit = QLineEdit() widgets = ((QLabel('Category:'), self.categComboBox), (self.cont_numLabel, None), (self.contactsListWidget,), (QLabel('Search:'), self.searchLineEdit)) vlayout1 = QVBoxLayout() for i in widgets: hlayout = pyqttools.add_to_layout(QHBoxLayout(), i) vlayout1.addLayout(hlayout) addToolButton = QToolButton() addToolButton.setIcon(QIcon(':addcontact.jpeg')) addToolButton.setIconSize(QSize(45, 45)) self.showLabel = QLabel() self.showLabel.setFrameShape(QFrame.StyledPanel) self.showLabel.setAlignment(Qt.AlignLeading|Qt.AlignLeft|Qt.AlignTop) self.editButton = QPushButton('Edit') self.delButton = QPushButton('Delete') widgets = ((None, addToolButton, None), (self.showLabel,), (None, self.editButton, self.delButton)) vlayout2 = QVBoxLayout() for i in widgets: hlayout = pyqttools.add_to_layout(QHBoxLayout(), i) vlayout2.addLayout(hlayout) f_layout = pyqttools.add_to_layout(QHBoxLayout(), (vlayout1, vlayout2)) Widget = QWidget() Widget.setLayout(f_layout) self.setCentralWidget(Widget) self.statusBar = self.statusBar() self.userLabel = QLabel() self.statusBar.addPermanentWidget(self.userLabel) c_action = pyqttools.create_action panelAction = c_action(self, 'User panel', triggered=self.user_panel) quitAction = c_action(self, 'Quit', 'Ctrl+Q',triggered=self.close) add_contactAction = c_action(self, 'Add contact', 'Ctrl+N', triggered=self.add_contact) delete_allAction = c_action(self, 'Delete all contacts', triggered=self.delete_all) delete_categAction = c_action(self, 'Delete categories', triggered=self.delete_categories) backupAction = c_action(self, 'Backup', triggered=self.backup) restoreAction = c_action(self, 'Restore', triggered=self.restore) aboutAction = c_action(self, 'About', 'Ctrl+?', triggered=self.about) fileMenu = self.menuBar().addMenu('File') contactsMenu = self.menuBar().addMenu('Contacts') deleteMenu = self.menuBar().addMenu(self.tr('Delete')) backupMenu = self.menuBar().addMenu(self.tr('Backup')) helpMenu = self.menuBar().addMenu('Help') pyqttools.add_actions(fileMenu, [panelAction, None, quitAction]) pyqttools.add_actions(contactsMenu, [add_contactAction]) pyqttools.add_actions(deleteMenu,[delete_allAction,delete_categAction]) pyqttools.add_actions(backupMenu, [backupAction, restoreAction]) pyqttools.add_actions(helpMenu, [aboutAction]) addToolButton.clicked.connect(self.add_contact) self.editButton.clicked.connect(self.edit_contact) self.delButton.clicked.connect(self.delete_contact) self.categComboBox.currentIndexChanged.connect(self.fill_ListWidget) self.contactsListWidget.currentRowChanged.connect(self.show_contact) self.searchLineEdit.textEdited.connect(self.search) self.fill_categComboBox() self.refresh_userLabel() def fill_categComboBox(self): categories = ['All'] categories.extend([i[1] for i in self.db.get_categories(self.user)]) self.categComboBox.currentIndexChanged.disconnect(self.fill_ListWidget) self.categComboBox.clear() self.categComboBox.addItems(categories) self.categComboBox.currentIndexChanged.connect(self.fill_ListWidget) self.fill_ListWidget() def fill_ListWidget(self): self.showLabel.clear() self.contactsListWidget.clear() if self.categComboBox.currentIndex() != 0: self.searchLineEdit.clear() category = self.categComboBox.currentText() if category == 'All': contacts = self.db.get_all_contacts(self.user) else: categ_id = self.db.get_category_id(category, self.user) if categ_id is None: return contacts = self.db.get_contacts(categ_id) for i in contacts: self.contactsListWidget.addItem(MyListItem(i[1]+' '+i[2], i[0])) self.contactsListWidget.setCurrentRow(0) self.refresh_contacts_number() self.set_buttons_enabled() def refresh_userLabel(self): self.userLabel.setText('User: '******'Contacts Numer: {0}'.format(self.contactsListWidget.count()) self.cont_numLabel.setText(text) def set_buttons_enabled(self): enable = bool(self.contactsListWidget) self.editButton.setEnabled(enable) self.delButton.setEnabled(enable) def user_panel(self): dialog = dialogs.UserPanelDlg(self) if dialog.exec_(): self.user = dialog.user self.fill_categComboBox() self.refresh_userLabel() def show_contact(self): try: _id = self.contactsListWidget.currentItem()._id except AttributeError: return _id, name, surname, mail, address, tel, categ_id = \ self.db.get_contact_from_id(_id)[0] category = self.db.get_category_from_id(categ_id) text = '' data = (name, surname, mail, address, tel, category) labs = ('Name', 'Surname', 'e-mail', 'Address', 'Telephone', 'Category') for i, y in zip(labs, data): text += '''<p style=\' margin-top:0px; margin-bottom:0px; \'> <span style=\' font-weight:600;\'>{0}:</span> {1} </p>\n'''\ .format(i, y) self.showLabel.setText(text) def add_contact(self): categories = [i[1] for i in self.db.get_categories(self.user)] dialog = dialogs.AddorEditContactDlg(categories) if dialog.exec_(): data = dialog.values if data[-1] not in categories: self.db.addto_categories(data[-1], self.user) categ_id = self.db.get_category_id(data[-1], self.user) data[-1] = categ_id self.db.addto_contacts(data) self.fill_categComboBox() def edit_contact(self): _id = self.contactsListWidget.currentItem()._id data = list(self.db.get_contact_from_id(_id)[0]) categ = self.db.get_category_from_id(data[-1]) data[-1] = categ categories = [i[1] for i in self.db.get_categories(self.user)] dialog = dialogs.AddorEditContactDlg(categories, True, data) if dialog.exec_(): new_data = dialog.values if new_data[-1] not in categories: self.db.addto_categories(new_data[-1], self.user) categ_id = self.db.get_category_id(new_data[-1], self.user) new_data[-1] = categ_id self.db.edit_contact(new_data, _id) self.fill_categComboBox() def delete_contact(self): reply = QMessageBox.question(self, 'Address Book - Delete Contact', 'Are you sure that you want to delete this contact?', QMessageBox.Yes|QMessageBox.Cancel) if reply == QMessageBox.Yes: _id = self.contactsListWidget.currentItem()._id self.db.delete_contact(_id) self.fill_ListWidget() def delete_all(self): reply = QMessageBox.question(self, 'Address Book - Delete Contact', 'Are you sure that you want to delete all contacts?', QMessageBox.Yes|QMessageBox.Cancel) if reply == QMessageBox.Yes: self.db.delete_all_contacts() self.fill_ListWidget() def delete_categories(self): categories = [i[1] for i in self.db.get_categories(self.user)] dialogs.DelCategoriesDlg(categories, self).exec_() self.fill_categComboBox() def search(self): self.categComboBox.setCurrentIndex(0) self.showLabel.clear() self.contactsListWidget.clear() txt = self.searchLineEdit.text() if all(i == ' ' for i in txt): self.fill_ListWidget() return must_appear = [] contacts = self.db.get_all_contacts(self.user) if not ' ' in txt: for i in contacts: if txt.lower() in i[1].lower() or txt.lower() in i[2].lower(): must_appear.append(i) else: try: first, last = txt.split() except ValueError: return for i in contacts: _bool = bool(first.lower() in i[1].lower() or first.lower() in i[2].lower() or last.lower() in i[1].lower() or last.lower() in i[2].lower()) if _bool: must_appear.append(i) for i in must_appear: item = MyListItem(i[1] + ' ' + i[2], i[0]) self.contactsListWidget.addItem(item) self.contactsListWidget.setCurrentRow(0) self.refresh_contacts_number() self.set_buttons_enabled() def backup(self): fname = QFileDialog.getSaveFileName(self,'Address Book - Backup','.db') if fname: try: shutil.copy(self.db_file, fname) except IOError: pass def restore(self): reply = QMessageBox.question(self, 'Address Book - Restore', 'All current contacts will be deleted.\nAre you sure that you want' ' to continue?', QMessageBox.Yes|QMessageBox.Cancel) if reply == QMessageBox.Yes: fname = QFileDialog.getOpenFileName(self, 'Address Book - Restore') if fname: msg = 'Succesful restore!' try: os.remove(self.db_file) shutil.copy(fname, self.db_file) except (OSError, IOError): msg = 'Restore failed!' QMessageBox.information(self, 'Addess Book - Restore', msg) self.db = database.Database(self.db_file) self.fill_categComboBox() def database_file(self): _file = 'addressbook.db' if not platform.platform().startswith('Windows'): folder = os.getenv('HOME') + os.sep + '.addressbook' if not os.path.exists(folder): os.mkdir(folder) _file = folder + os.sep + _file return _file def about(self): link = 'http://wiki.ubuntu-gr.org/Address%20Book' QMessageBox.about(self, self.tr('About') + ' FF Multi Converter', '''<b> Address Book {0} </b> <p>Gui application to organize your contacts! <p>Copyright © 2012 Ilias Stamatis <br>License: GNU GPL3 <p><a href='{1}'>http://wiki.ubuntu-gr.org/Address Book</a> <p>Python {2} - Qt {3} - PyQt {4} on {5}''' .format(__version__, link, platform.python_version()[:5], QT_VERSION_STR, PYQT_VERSION_STR, platform.system())) def close(self): self.db.close() sys.exit()
class bookDiag(QDialog): def __init__(self, parent): QDialog.__init__(self) self.setWindowTitle("Add bookmark entry") self.init(parent) self.initShape() def init(self, parent): self.bookmark = parent self.heditor = self.bookmark.heditor def createButtons(self): self.buttonbox = QDialogButtonBox() self.buttonbox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) self.connect(self.buttonbox, SIGNAL("accepted()"), self.accept) self.connect(self.buttonbox, SIGNAL("rejected()"), self.reject) return self.buttonbox def initShape(self): self.grid = QGridLayout() decoration = self.createDecoration() wButton = self.createButtons() wInfos = self.createInformations() self.grid.addWidget(decoration, 0, 0) self.grid.addWidget(wInfos, 1, 0) self.grid.addWidget(wButton, 2, 0) self.setLayout(self.grid) def createDecoration(self): self.deco = QWidget() self.hdeco = QHBoxLayout() pixlabel = QLabel() pix = QPixmap(":bookmark.png") pixlabel.setPixmap(pix) booklabel = QLabel("Add a description to this entry") self.hdeco.addWidget(pixlabel) self.hdeco.addWidget(booklabel) self.deco.setLayout(self.hdeco) return self.deco def createInformations(self): self.info = QWidget() self.igrid = QGridLayout() addressLabel = QLabel("Address: ") self.address = QLineEdit() self.address.setReadOnly(True) lend = QLabel("Length (dec): ") self.lendec = QLineEdit() self.lendec.setReadOnly(True) lenh = QLabel("Length (hex): ") self.lenhex = QLineEdit() self.lenhex.setReadOnly(True) deslabel = QLabel("Description: ") self.description = QLineEdit() hvlabel = QLabel("Hex value:") self.hexvalue = QLineEdit() self.hexvalue.setReadOnly(True) avlabel = QLabel("Ascii value:") self.asciivalue = QLineEdit() self.asciivalue.setReadOnly(True) self.igrid.addWidget(addressLabel, 0, 0, Qt.AlignLeft) self.igrid.addWidget(self.address, 0, 1, Qt.AlignLeft) self.igrid.addWidget(lend, 1, 0, Qt.AlignLeft) self.igrid.addWidget(self.lendec, 1, 1, Qt.AlignLeft) self.igrid.addWidget(lenh, 2, 0, Qt.AlignLeft) self.igrid.addWidget(self.lenhex, 2, 1, Qt.AlignLeft) self.igrid.addWidget(hvlabel, 3, 0, Qt.AlignLeft) self.igrid.addWidget(self.hexvalue, 3, 1, Qt.AlignLeft) self.igrid.addWidget(avlabel, 4, 0, Qt.AlignLeft) self.igrid.addWidget(self.asciivalue, 4, 1, Qt.AlignLeft) self.igrid.addWidget(deslabel, 5, 0, Qt.AlignLeft) self.igrid.addWidget(self.description, 5, 1, Qt.AlignLeft) self.info.setLayout(self.igrid) return self.info def cleanInformations(self): self.address.clear() self.lendec.clear() self.lenhex.clear() self.hexvalue.clear() self.asciivalue.clear() self.description.clear() def setInformations(self): self.cleanInformations() if self.heditor.decimalview: add = "%.2d" % self.heditor.selection.startoffset else: add = "0x" add += "%.2x" % self.heditor.selection.startoffset self.address.insert(add) if self.heditor.selection.length > 0: len = self.heditor.selection.length else: len = 1 tolendec = "%.1d" % len self.lendec.insert(tolendec) tolenhex = "0x" tolenhex += "%.1X" % len self.lenhex.insert(tolenhex) hval = self.heditor.readHexValue(self.heditor.selection.offset, len) self.hexvalue.insert(hval) aval = self.heditor.readAsciiValue(self.heditor.selection.offset, len) self.asciivalue.insert(aval)
class DefaultAttributeHandler(QGroupBox, AbstractAttributeHandler): def __init__(self, attribute, values, parent=None): QGroupBox.__init__(self, attribute, parent) self._attribute = attribute self._current_items = [] self._defaults = {} self._inputField = None self._inputFieldType = None self._insertIndex = -1 self._insertAtEnd = False self._shortcuts = {} # Setup GUI self._layout = FloatingLayout() self.setLayout(self._layout) self._buttons = {} # Add interface elements self.updateValues(values) def focusInputField(self, selectInput=True): if self._inputField is not None: if selectInput: self._inputField.selectAll() self._inputField.setFocus(Qt.ShortcutFocusReason) def addShortcut(self, shortcut, widget, value): if widget is not None: if shortcut not in self._shortcuts: sc = QShortcut(QKeySequence(shortcut), self) self._shortcuts[shortcut] = sc if isinstance(widget, QPushButton): sc.activated.connect(bind(lambda w: w.click() if not w.isChecked() else None, widget)) elif isinstance(widget, QLineEdit): sc.activated.connect(self.focusInputField) else: raise ImproperlyConfigured("Shortcut '%s' defined more than once" % shortcut) else: raise ImproperlyConfigured("Shortcut '%s' defined for value '%s' which is hidden" % (shortcut, value)) def updateValues(self, values): if isinstance(values, type): self.addInputField(values) else: for val in values: v = val shortcut = None widget = None # Handle the case of the value being a 2-tuple consisting of (value, shortcut) if type(val) is tuple or type(val) is list: if len(val) == 2: v = val[0] shortcut = val[1] else: raise ImproperlyConfigured("Values must be types, strings, numbers, or tuples of length 2: '%s'" % str(val)) # Handle the case where value is a Python type if isinstance(v, type): if v is float or v is int or v is str: self.addInputField(v) widget = self._inputField else: raise ImproperlyConfigured("Input field with type '%s' not supported" % v) # * marks the position where buttons for new values will be insered elif val == "*" or val == "<*": self._insertIndex = self._layout.count() elif val == "*>": self._insertIndex = self._layout.count() self._insertAtEnd = True # Add the value button else: self.addValue(v) widget = self._buttons[v] # If defined, add the specified shortcut if shortcut is not None: self.addShortcut(shortcut, widget, v) def defaults(self): return self._defaults def autoAddEnabled(self): return self._insertIndex >= 0 def onInputFieldReturnPressed(self): val = str(self._inputField.text()) self.addValue(val, True) for item in self._current_items: item[self._attribute] = val self.updateButtons() self.updateInputField() self._inputField.clearFocus() def addInputField(self, _type): if self._inputField is None: self._inputFieldType = _type self._inputField = QLineEdit() if _type is float: self._inputField.setValidator(QDoubleValidator()) elif _type is int: self._inputField.setValidator(QIntValidator()) self._layout.addWidget(self._inputField) self._inputField.returnPressed.connect(self.onInputFieldReturnPressed) elif self._inputFieldType is not _type: raise ImproperlyConfigured("Input field for attribute '%s' configured twice with different types %s != %s"\ % (self._attribute, self._inputFieldType, _type)) def addValue(self, v, autoAddValue=False): if v in self._buttons: return if autoAddValue and self._insertIndex < 0: return button = QPushButton(v, self) button.setFlat(True) button.setCheckable(True) self._buttons[v] = button if autoAddValue: self._layout.insertWidget(self._insertIndex, button) if self._insertAtEnd: self._insertIndex += 1 else: self._layout.addWidget(button) button.clicked.connect(bind(self.onButtonClicked, v)) def reset(self): self._current_items = [] for v, button in self._buttons.items(): button.setChecked(False) button.setFlat(True) def getSelectedValues(self): return set([str(item[self._attribute]) for item in self._current_items if self._attribute in item and item[self._attribute] is not None]) def updateInputField(self): if self._inputField is not None: self._inputField.clear() selected_values = self.getSelectedValues() if len(selected_values) > 1: self._inputField.setPlaceholderText(", ".join(selected_values)) elif len(selected_values) == 1: it = iter(selected_values) self._inputField.setText(next(it)) def updateButtons(self): selected_values = self.getSelectedValues() for val, button in self._buttons.items(): if val in selected_values: if len(selected_values) > 1: button.setFlat(False) button.setChecked(False) else: button.setFlat(True) button.setChecked(True) else: button.setFlat(True) button.setChecked(False) def setItems(self, items, showItemClasses=False): self.reset() if showItemClasses: title = ", ".join(set([item['class'] for item in items])) self.setTitle(self._attribute + " (" + title + ")") else: self.setTitle(self._attribute) self._current_items = items self.updateButtons() self.updateInputField() def onButtonClicked(self, val): attr = self._attribute LOG.debug("Button %s: %s clicked" % (attr, val)) button = self._buttons[val] # Update model item for item in self._current_items: if button.isChecked(): item[attr] = val else: item[attr] = None # Unpress all other buttons for v, but in self._buttons.items(): but.setFlat(True) if but is not button: but.setChecked(False) # Update input field self.updateInputField()
class IgnoredExceptionsViewer(QWidget): " Implements the client exceptions viewer for a debugger " def __init__(self, parent=None): QWidget.__init__(self, parent) self.__createPopupMenu() self.__createLayout() self.__ignored = [] self.__currentItem = None GlobalData().project.projectChanged.connect(self.__onProjectChanged) if Settings().showIgnoredExcViewer == False: self.__onShowHide(True) return def __createPopupMenu(self): " Creates the popup menu " self.__excptMenu = QMenu() self.__removeMenuItem = self.__excptMenu.addAction( PixmapCache().getIcon('ignexcptdel.png'), "Remove from ignore list", self.__onRemoveFromIgnore) return def __createLayout(self): " Creates the widget layout " verticalLayout = QVBoxLayout(self) verticalLayout.setContentsMargins(0, 0, 0, 0) verticalLayout.setSpacing(0) self.headerFrame = QFrame() self.headerFrame.setFrameStyle(QFrame.StyledPanel) self.headerFrame.setAutoFillBackground(True) headerPalette = self.headerFrame.palette() headerBackground = headerPalette.color(QPalette.Background) headerBackground.setRgb(min(headerBackground.red() + 30, 255), min(headerBackground.green() + 30, 255), min(headerBackground.blue() + 30, 255)) headerPalette.setColor(QPalette.Background, headerBackground) self.headerFrame.setPalette(headerPalette) self.headerFrame.setFixedHeight(24) self.__excptLabel = QLabel("Ignored exception types") expandingSpacer = QSpacerItem(10, 10, QSizePolicy.Expanding) fixedSpacer = QSpacerItem(3, 3) self.__showHideButton = QToolButton() self.__showHideButton.setAutoRaise(True) self.__showHideButton.setIcon(PixmapCache().getIcon('less.png')) self.__showHideButton.setFixedSize(20, 20) self.__showHideButton.setToolTip("Hide ignored exceptions list") self.__showHideButton.setFocusPolicy(Qt.NoFocus) self.__showHideButton.clicked.connect(self.__onShowHide) headerLayout = QHBoxLayout() headerLayout.setContentsMargins(1, 1, 1, 1) headerLayout.addSpacerItem(fixedSpacer) headerLayout.addWidget(self.__excptLabel) headerLayout.addSpacerItem(expandingSpacer) headerLayout.addWidget(self.__showHideButton) self.headerFrame.setLayout(headerLayout) self.exceptionsList = QTreeWidget(self) self.exceptionsList.setSortingEnabled(False) self.exceptionsList.setAlternatingRowColors(True) self.exceptionsList.setRootIsDecorated(False) self.exceptionsList.setItemsExpandable(True) self.exceptionsList.setUniformRowHeights(True) self.exceptionsList.setSelectionMode(QAbstractItemView.SingleSelection) self.exceptionsList.setSelectionBehavior(QAbstractItemView.SelectRows) self.exceptionsList.setItemDelegate(NoOutlineHeightDelegate(4)) self.exceptionsList.setContextMenuPolicy(Qt.CustomContextMenu) self.exceptionsList.customContextMenuRequested.connect( self.__showContextMenu) self.exceptionsList.itemSelectionChanged.connect( self.__onSelectionChanged) self.exceptionsList.setHeaderLabels(["Exception type"]) self.__excTypeEdit = QLineEdit() self.__excTypeEdit.setFixedHeight(26) self.__excTypeEdit.textChanged.connect(self.__onNewFilterChanged) self.__excTypeEdit.returnPressed.connect(self.__onAddExceptionFilter) self.__addButton = QPushButton("Add") # self.__addButton.setFocusPolicy( Qt.NoFocus ) self.__addButton.setEnabled(False) self.__addButton.clicked.connect(self.__onAddExceptionFilter) expandingSpacer2 = QWidget() expandingSpacer2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.__removeButton = QAction(PixmapCache().getIcon('delitem.png'), "Remove selected exception type", self) self.__removeButton.triggered.connect(self.__onRemoveFromIgnore) self.__removeButton.setEnabled(False) fixedSpacer1 = QWidget() fixedSpacer1.setFixedWidth(5) self.__removeAllButton = QAction( PixmapCache().getIcon('ignexcptdelall.png'), "Remove all the exception types", self) self.__removeAllButton.triggered.connect(self.__onRemoveAllFromIgnore) self.__removeAllButton.setEnabled(False) self.toolbar = QToolBar() self.toolbar.setOrientation(Qt.Horizontal) self.toolbar.setMovable(False) self.toolbar.setAllowedAreas(Qt.TopToolBarArea) self.toolbar.setIconSize(QSize(16, 16)) self.toolbar.setFixedHeight(28) self.toolbar.setContentsMargins(0, 0, 0, 0) self.toolbar.addWidget(expandingSpacer2) self.toolbar.addAction(self.__removeButton) self.toolbar.addWidget(fixedSpacer1) self.toolbar.addAction(self.__removeAllButton) addLayout = QHBoxLayout() addLayout.setContentsMargins(1, 1, 1, 1) addLayout.setSpacing(1) addLayout.addWidget(self.__excTypeEdit) addLayout.addWidget(self.__addButton) verticalLayout.addWidget(self.headerFrame) verticalLayout.addWidget(self.toolbar) verticalLayout.addWidget(self.exceptionsList) verticalLayout.addLayout(addLayout) return def clear(self): " Clears the content " self.exceptionsList.clear() self.__excTypeEdit.clear() self.__addButton.setEnabled(False) self.__ignored = [] self.__currentItem = None self.__updateTitle() return def __onShowHide(self, startup=False): " Triggered when show/hide button is clicked " if startup or self.exceptionsList.isVisible(): self.exceptionsList.setVisible(False) self.__excTypeEdit.setVisible(False) self.__addButton.setVisible(False) self.__removeButton.setVisible(False) self.__removeAllButton.setVisible(False) self.__showHideButton.setIcon(PixmapCache().getIcon('more.png')) self.__showHideButton.setToolTip("Show ignored exceptions list") self.__minH = self.minimumHeight() self.__maxH = self.maximumHeight() self.setMinimumHeight(self.headerFrame.height()) self.setMaximumHeight(self.headerFrame.height()) Settings().showIgnoredExcViewer = False else: self.exceptionsList.setVisible(True) self.__excTypeEdit.setVisible(True) self.__addButton.setVisible(True) self.__removeButton.setVisible(True) self.__removeAllButton.setVisible(True) self.__showHideButton.setIcon(PixmapCache().getIcon('less.png')) self.__showHideButton.setToolTip("Hide ignored exceptions list") self.setMinimumHeight(self.__minH) self.setMaximumHeight(self.__maxH) Settings().showIgnoredExcViewer = True return def __onSelectionChanged(self): " Triggered when the current item is changed " selected = list(self.exceptionsList.selectedItems()) if selected: self.__currentItem = selected[0] self.__removeButton.setEnabled(True) else: self.__currentItem = None self.__removeButton.setEnabled(False) return def __showContextMenu(self, coord): " Shows the frames list context menu " contextItem = self.exceptionsList.itemAt(coord) if contextItem is not None: self.__currentItem = contextItem self.__excptMenu.popup(QCursor.pos()) return def __updateTitle(self): " Updates the section title " count = self.exceptionsList.topLevelItemCount() if count == 0: self.__excptLabel.setText("Ignored exception types") else: self.__excptLabel.setText("Ignored exception types (total: " + str(count) + ")") self.__removeAllButton.setEnabled(count != 0) return def __onProjectChanged(self, what): " Triggered when a project is changed " if what != CodimensionProject.CompleteProject: return self.clear() project = GlobalData().project if project.isLoaded(): self.__ignored = list(project.ignoredExcpt) else: self.__ignored = list(Settings().ignoredExceptions) for exceptionType in self.__ignored: item = QTreeWidgetItem(self.exceptionsList) item.setText(0, exceptionType) self.__updateTitle() return def __onNewFilterChanged(self, text): " Triggered when the text is changed " text = str(text).strip() if text == "": self.__addButton.setEnabled(False) return if " " in text: self.__addButton.setEnabled(False) return if text in self.__ignored: self.__addButton.setEnabled(False) return self.__addButton.setEnabled(True) return def __onAddExceptionFilter(self): " Adds an item into the ignored exceptions list " text = self.__excTypeEdit.text().strip() self.addExceptionFilter(text) def addExceptionFilter(self, excType): " Adds a new item into the ignored exceptions list " if excType == "": return if " " in excType: return if excType in self.__ignored: return item = QTreeWidgetItem(self.exceptionsList) item.setText(0, excType) project = GlobalData().project if project.isLoaded(): project.addExceptionFilter(excType) else: Settings().addExceptionFilter(excType) self.__ignored.append(excType) self.__updateTitle() return def __onRemoveFromIgnore(self): " Removes an item from the ignored exception types list " if self.__currentItem is None: return text = self.__currentItem.text(0) # Find the item index and remove it index = 0 while True: if self.exceptionsList.topLevelItem(index).text(0) == text: self.exceptionsList.takeTopLevelItem(index) break index += 1 project = GlobalData().project if project.isLoaded(): project.deleteExceptionFilter(text) else: Settings().deleteExceptionFilter(text) self.__ignored.remove(text) self.__updateTitle() return def __onRemoveAllFromIgnore(self): " Triggered when all the ignored exceptions should be deleted " self.clear() project = GlobalData().project if project.isLoaded(): project.setExceptionFilters([]) else: Settings().setExceptionFilters([]) return def isIgnored(self, exceptionType): " Returns True if this exception type should be ignored " return exceptionType in self.__ignored
class SettingsManager(QDialog): def __init__(self, num, n, parent=None): super(SettingsManager, self).__init__(parent) #main self.par = n title = Settingz().positions(num) self.titleID = title['id'] self.titleIDx = str(title['id']) + 'x' self.titlePage = title['page'] self.titleName = title['name'] self.titleSub = title['subID'] self.titleIcon = title['icon'] self.pagetitle = self.titlePage self.sessionMain = 0 #stylesheet stylesheet = Valid().background() + Valid().font() treeStyleSheet = Valid().treez() self.groupBox1 = QGroupBox(self.titleName) self.groupBox2 = QGroupBox('Add') #items self.tree = QTreeWidget() self.tree.setHeaderLabel("Choose " + self.titleName) self.tree.headerItem().setText(0, 'Name') self.tree.headerItem().setText(1, 'Abbrv.') self.tree.setStyleSheet(treeStyleSheet) self.makeTree() self.tree.setMinimumHeight(250) self.tree.clicked.connect(lambda: self.getSelection()) self.tree.itemClicked.connect(lambda state: self.getChecked(state)) #buttons #add nImg = Buttons().addButton() self.pb = QPushButton() self.pb.setFlat(True) self.pb.setIcon(QIcon(nImg)) self.pb.setMaximumHeight(30) self.pb.setMaximumWidth(30) nImg1 = Buttons().closeButton() self.pb1 = QPushButton() self.pb1.setFlat(True) self.pb1.setIcon(QIcon(nImg1)) self.pb1.setMaximumHeight(30) self.pb1.setMaximumWidth(30) nImg2 = Buttons().editButton() self.pb2 = QPushButton() self.pb2.setFlat(True) self.pb2.setIcon(QIcon(nImg2)) self.pb2.setMaximumHeight(30) self.pb2.setMaximumWidth(30) nImg3 = Buttons().deleteButton() self.pb3 = QPushButton() self.pb3.setFlat(True) self.pb3.setIcon(QIcon(nImg3)) self.pb3.setMaximumHeight(30) self.pb3.setMaximumWidth(30) nImg4 = Buttons().saveButton() self.pb4 = QPushButton() self.pb4.setFlat(True) self.pb4.setIcon(QIcon(nImg4)) self.pb4.setMaximumHeight(30) self.pb4.setMaximumWidth(30) nImg5 = Buttons().resetButton() self.pb5 = QPushButton() self.pb5.setFlat(True) self.pb5.setIcon(QIcon(nImg5)) self.pb5.setMaximumHeight(30) self.pb5.setMaximumWidth(30) nImg6 = Buttons().closeButton() self.pb6 = QPushButton() self.pb6.setFlat(True) self.pb6.setIcon(QIcon(nImg6)) self.pb6.setMaximumHeight(30) self.pb6.setMaximumWidth(30) nImg7 = Buttons().addButton() self.pb7 = QPushButton() self.pb7.setFlat(True) self.pb7.setIcon(QIcon(nImg7)) self.pb7.setMaximumHeight(30) self.pb7.setMaximumWidth(30) hbo = QHBoxLayout() hbo.addStretch() hbo.addWidget(self.pb1) hbo.addWidget(self.pb3) hbo.addWidget(self.pb2) hbo.addWidget(self.pb7) vbo = QVBoxLayout() vbo.addWidget(self.tree) vbo.addLayout(hbo) self.l1 = QLabel("Name") self.le1 = QLineEdit() self.le1.setObjectName("name") vals1 = Valid().fullText() self.le1.setValidator(vals1) self.le1.setPlaceholderText("Lowercase max 25 letters") self.l2 = QLabel("Abbrv") self.le2 = QLineEdit() self.le2.setObjectName("abbrv") vals2 = Valid().limitText() self.le2.setValidator(vals2) self.le2.setPlaceholderText("Lowercase max 5 letters") FormLayout = QFormLayout() FormLayout.addRow(self.l1, self.le1) FormLayout.addRow(self.l2, self.le2) Hlayout1 = QHBoxLayout() Hlayout1.addStretch() Hlayout1.addWidget(self.pb6) Hlayout1.addWidget(self.pb5) Hlayout1.addWidget(self.pb4) Hlayout1.addWidget(self.pb) Vlayout1 = QVBoxLayout() Vlayout1.addLayout(FormLayout) Vlayout1.addLayout(Hlayout1) self.groupBox1.setLayout(vbo) self.groupBox2.setLayout(Vlayout1) self.groupBox2.hide() self.connect(self.pb, SIGNAL("clicked()"), lambda: self.button_add()) #add self.connect(self.pb1, SIGNAL("clicked()"), lambda: self.button_close()) #close self.connect(self.pb2, SIGNAL("clicked()"), lambda: self.button_edit()) #edit self.connect(self.pb3, SIGNAL("clicked()"), lambda: self.button_delete()) #delete self.connect(self.pb4, SIGNAL("clicked()"), lambda: self.button_save()) #save self.connect(self.pb5, SIGNAL("clicked()"), lambda: self.button_reset()) #reset self.pb4.hide() self.pb7.hide() grid = QGridLayout() grid.addWidget(self.groupBox1, 0, 0) grid.addWidget(self.groupBox2, 1, 0) self.setLayout(grid) self.setStyleSheet(stylesheet) self.setWindowIcon(QIcon(self.titleIcon)) self.setWindowTitle(self.pagetitle) def makeTree(self): self.tree.clear() arr = Valid().pullData('datas', '', {'pubID': self.titleID}) self.hold_data = {} self.hold_mdata = {} self.hold_data_add = {} self.hold_data_add_item = {} if self.titleSub and self.titleSub > 0: if arr and len(arr) > 0: for val in arr: ch = Valid().pullData('datas', '', {'subID': val['id']}) child = QTreeWidgetItem(self.tree) child.setFlags(child.flags() | Qt.ItemIsUserCheckable) child.setText(0, str(val['name']).upper()) child.setText(1, str(val['abbrv']).upper()) self.hold_data[val['id']] = child self.hold_mdata[val['id']] = child if (val['active'] == 0): child.setCheckState(0, Qt.Checked) else: child.setCheckState(0, Qt.Unchecked) for va in ch: child1 = QTreeWidgetItem(child) child1.setFlags(child1.flags() | Qt.ItemIsUserCheckable) child1.setText(0, str(va['name']).upper()) child1.setText(1, str(va['abbrv']).upper()) self.hold_data[va['id']] = child1 if (va['active'] == 0): child1.setCheckState(0, Qt.Checked) else: child1.setCheckState(0, Qt.Unchecked) child1 = QTreeWidgetItem(child) child1.setFlags(child1.flags() | Qt.ItemIsUserCheckable) child1.setText(0, 'Add New Item') self.hold_data_add_item[val['id']] = child1 else: if arr and len(arr) > 0: for val in arr: child = QTreeWidgetItem(self.tree) child.setFlags(child.flags() | Qt.ItemIsUserCheckable) child.setText(0, str(val['name']).upper()) child.setText(1, str(val['abbrv']).upper()) self.hold_data[val['id']] = child if (val['active'] == 0): child.setCheckState(0, Qt.Checked) else: child.setCheckState(0, Qt.Unchecked) child = QTreeWidgetItem(self.tree) child.setFlags(child.flags() | Qt.ItemIsUserCheckable) child.setText(0, 'Add New') self.hold_data_add['addnew'] = child def getChecked(self, a): g = Db() for i in self.hold_data: if self.hold_data[i].checkState(0) == Qt.Checked: g.update('datas', {'active': 0}, {'id': i}) else: g.update('datas', {'active': 1}, {'id': i}) if self.titleID == 1: #if class was changed only reload class menu on main window self.par.menuStudent() self.par.dropdownStudent() def getSelected(self): r = None k = None for i in self.hold_data: if self.hold_data[i].isSelected(): r = i for j in self.hold_mdata: if self.hold_mdata[j].isSelected(): k = j if r and r > 0: if r == k: self.sessionMain = r else: self.sessionMain = 0 self.groupBox2.show() return r else: self.groupBox2.hide() def getSelection(self): self.le1.clear() self.le2.clear() if self.hold_data_add['addnew'].isSelected(): self.sessionMain = 0 self.groupBox2.setTitle('Add New') self.groupBox2.show() else: r = None for i in self.hold_data_add_item: if self.hold_data_add_item[i].isSelected(): r = i if r: self.sessionMain = r g = Db() v = g.selectn('datas', '', 1, {'id': r}) vname = str(v['name']).upper() self.groupBox2.setTitle('ADD ' + str(vname) + ' ITEM') self.groupBox2.show() else: self.groupBox2.setTitle('Add') self.groupBox2.hide() def setActive(self): g = Db() for i in self.hold_data: if self.hold_data[i].checkState(0) == Qt.Checked: g.update('datas', {'active': 0}, {'id': i}) else: g.update('datas', {'active': 1}, {'id': i}) def button_add(self): s1 = self.le1.text() s2 = self.le2.text() g = Db() try: if (len(s1) > 0) and (len(s2) > 0): if self.sessionMain == 0: y = { 'name': s1.lower(), 'abbrv': s2.lower(), 'pubID': self.titleID, 'active': 0 } else: y = { 'name': s1.lower(), 'abbrv': s2.lower(), 'subID': self.sessionMain, 'pubID': self.titleIDx, 'active': 0 } g.insert('datas', y) self.makeTree() self.button_reset() if self.titleID == 1: #if class was changed only relod class menu on main window self.par.menuStudent() self.par.dropdownStudent() else: pass except: pass def button_save(self): row = self.editrow s1 = self.le1.text() s2 = self.le2.text() g = Db() try: if (len(s1) > 0) and (len(s2) > 0) and row and row > 0: y = {'name': s1.lower(), 'abbrv': s2.lower(), 'active': 0} z = {'id': row} g.update('datas', y, z) self.makeTree() self.button_reset() if self.titleID == 1: #if class was changed only relod class menu on main window self.par.menuStudent() self.par.dropdownStudent() else: pass except: pass def button_delete(self): row = self.getSelected() g = Db() try: if row and row > 0: y = {'abbrv': '', 'active': 2} z = {'id': row} g.update('datas', y, z) self.makeTree() else: pass except: pass def button_reset(self): self.le1.clear() self.le2.clear() self.groupBox2.setTitle('Add') self.groupBox2.hide() self.pb.show() self.pb4.hide() self.sessionMain = 0 def button_edit(self): row = self.getSelected() self.sessionMain = 0 if row: self.groupBox2.setTitle('Edit') self.editrow = row g = Db() data = g.selectn('datas', '', 1, {'id': row}) if self.titleID == data['pubID']: self.sessionMain = 1 else: self.sessionMain = 0 try: self.le1.setText(data['name']) except: self.le1.setText('') try: self.le2.setText(data['abbrv']) except: self.le2.setText('') self.pb.hide() self.pb4.show() def button_close(self): self.close()
class SpreadSheet(QMainWindow): dateFormats = ["dd/M/yyyy", "yyyy/M/dd", "dd.MM.yyyy"] currentDateFormat = dateFormats[0] def __init__(self, rows, cols, parent = None): super(SpreadSheet, self).__init__(parent) self.toolBar = QToolBar() self.addToolBar(self.toolBar) self.formulaInput = QLineEdit() self.cellLabel = QLabel(self.toolBar) self.cellLabel.setMinimumSize(80, 0) self.toolBar.addWidget(self.cellLabel) self.toolBar.addWidget(self.formulaInput) self.table = QTableWidget(rows, cols, self) for c in range(cols): character = chr(ord('A') + c) self.table.setHorizontalHeaderItem(c, QTableWidgetItem(character)) self.table.setItemPrototype(self.table.item(rows - 1, cols - 1)) self.table.setItemDelegate(SpreadSheetDelegate(self)) self.createActions() self.updateColor(0) self.setupMenuBar() self.setupContents() self.setupContextMenu() self.setCentralWidget(self.table) self.statusBar() self.table.currentItemChanged.connect(self.updateStatus) self.table.currentItemChanged.connect(self.updateColor) self.table.currentItemChanged.connect(self.updateLineEdit) self.table.itemChanged.connect(self.updateStatus) self.formulaInput.returnPressed.connect(self.returnPressed) self.table.itemChanged.connect(self.updateLineEdit) self.setWindowTitle("Spreadsheet") def createActions(self): self.cell_sumAction = QAction("Sum", self) self.cell_sumAction.triggered.connect(self.actionSum) self.cell_addAction = QAction("&Add", self) self.cell_addAction.setShortcut(Qt.CTRL | Qt.Key_Plus) self.cell_addAction.triggered.connect(self.actionAdd) self.cell_subAction = QAction("&Subtract", self) self.cell_subAction.setShortcut(Qt.CTRL | Qt.Key_Minus) self.cell_subAction.triggered.connect(self.actionSubtract) self.cell_mulAction = QAction("&Multiply", self) self.cell_mulAction.setShortcut(Qt.CTRL | Qt.Key_multiply) self.cell_mulAction.triggered.connect(self.actionMultiply) self.cell_divAction = QAction("&Divide", self) self.cell_divAction.setShortcut(Qt.CTRL | Qt.Key_division) self.cell_divAction.triggered.connect(self.actionDivide) self.fontAction = QAction("Font...", self) self.fontAction.setShortcut(Qt.CTRL | Qt.Key_F) self.fontAction.triggered.connect(self.selectFont) self.colorAction = QAction(QIcon(QPixmap(16, 16)), "Background &Color...", self) self.colorAction.triggered.connect(self.selectColor) self.clearAction = QAction("Clear", self) self.clearAction.setShortcut(Qt.Key_Delete) self.clearAction.triggered.connect(self.clear) self.aboutSpreadSheet = QAction("About Spreadsheet", self) self.aboutSpreadSheet.triggered.connect(self.showAbout) self.exitAction = QAction("E&xit", self) self.exitAction.setShortcut(QKeySequence.Quit) self.exitAction.triggered.connect(QApplication.instance().quit) self.printAction = QAction("&Print", self) self.printAction.setShortcut(QKeySequence.Print) self.printAction.triggered.connect(self.print_) self.firstSeparator = QAction(self) self.firstSeparator.setSeparator(True) self.secondSeparator = QAction(self) self.secondSeparator.setSeparator(True) def setupMenuBar(self): self.fileMenu = self.menuBar().addMenu("&File") self.dateFormatMenu = self.fileMenu.addMenu("&Date format") self.dateFormatGroup = QActionGroup(self) for f in self.dateFormats: action = QAction(f, self, checkable=True, triggered=self.changeDateFormat) self.dateFormatGroup.addAction(action) self.dateFormatMenu.addAction(action) if f == self.currentDateFormat: action.setChecked(True) self.fileMenu.addAction(self.printAction) self.fileMenu.addAction(self.exitAction) self.cellMenu = self.menuBar().addMenu("&Cell") self.cellMenu.addAction(self.cell_addAction) self.cellMenu.addAction(self.cell_subAction) self.cellMenu.addAction(self.cell_mulAction) self.cellMenu.addAction(self.cell_divAction) self.cellMenu.addAction(self.cell_sumAction) self.cellMenu.addSeparator() self.cellMenu.addAction(self.colorAction) self.cellMenu.addAction(self.fontAction) self.menuBar().addSeparator() self.aboutMenu = self.menuBar().addMenu("&Help") self.aboutMenu.addAction(self.aboutSpreadSheet) def changeDateFormat(self): action = self.sender() oldFormat = self.currentDateFormat newFormat = self.currentDateFormat = action.text() for row in range(self.table.rowCount()): item = self.table.item(row, 1) date = QDate.fromString(item.text(), oldFormat) item.setText(date.toString(newFormat)) def updateStatus(self, item): if item and item == self.table.currentItem(): self.statusBar().showMessage(item.data(Qt.StatusTipRole).toString(), 1000) self.cellLabel.setText("Cell: (%s)" % encode_pos(self.table.row(item), self.table.column(item))) def updateColor(self, item): pixmap = QPixmap(16, 16) color = QColor() if item: color = item.backgroundColor() if not color.isValid(): color = self.palette().base().color() painter = QPainter(pixmap) painter.fillRect(0, 0, 16, 16, color) lighter = color.lighter() painter.setPen(lighter) # light frame painter.drawPolyline(QPoint(0, 15), QPoint(0, 0), QPoint(15, 0)) painter.setPen(color.darker()) # dark frame painter.drawPolyline(QPoint(1, 15), QPoint(15, 15), QPoint(15, 1)) painter.end() self.colorAction.setIcon(QIcon(pixmap)) def updateLineEdit(self, item): if item != self.table.currentItem(): return if item: self.formulaInput.setText(item.data(Qt.EditRole).toString()) else: self.formulaInput.clear() def returnPressed(self): text = self.formulaInput.text() row = self.table.currentRow() col = self.table.currentColumn() item = self.table.item(row, col) if not item: self.table.setItem(row, col, SpreadSheetItem(text)) else: item.setData(Qt.EditRole, text) self.table.viewport().update() def selectColor(self): item = self.table.currentItem() color = item and QColor(item.background()) or self.table.palette().base().color() color = QColorDialog.getColor(color, self) if not color.isValid(): return selected = self.table.selectedItems() if not selected: return for i in selected: i and i.setBackground(color) self.updateColor(self.table.currentItem()) def selectFont(self): selected = self.table.selectedItems() if not selected: return font, ok = QFontDialog.getFont(self.font(), self) if not ok: return for i in selected: i and i.setFont(font) def runInputDialog(self, title, c1Text, c2Text, opText, outText, cell1, cell2, outCell): rows = [] cols = [] for r in range(self.table.rowCount()): rows.append(str(r + 1)) for c in range(self.table.columnCount()): cols.append(chr(ord('A') + c)) addDialog = QDialog(self) addDialog.setWindowTitle(title) group = QGroupBox(title, addDialog) group.setMinimumSize(250, 100) cell1Label = QLabel(c1Text, group) cell1RowInput = QComboBox(group) c1Row, c1Col = decode_pos(cell1) cell1RowInput.addItems(rows) cell1RowInput.setCurrentIndex(c1Row) cell1ColInput = QComboBox(group) cell1ColInput.addItems(cols) cell1ColInput.setCurrentIndex(c1Col) operatorLabel = QLabel(opText, group) operatorLabel.setAlignment(Qt.AlignHCenter) cell2Label = QLabel(c2Text, group) cell2RowInput = QComboBox(group) c2Row, c2Col = decode_pos(cell2) cell2RowInput.addItems(rows) cell2RowInput.setCurrentIndex(c2Row) cell2ColInput = QComboBox(group) cell2ColInput.addItems(cols) cell2ColInput.setCurrentIndex(c2Col) equalsLabel = QLabel("=", group) equalsLabel.setAlignment(Qt.AlignHCenter) outLabel = QLabel(outText, group) outRowInput = QComboBox(group) outRow, outCol = decode_pos(outCell) outRowInput.addItems(rows) outRowInput.setCurrentIndex(outRow) outColInput = QComboBox(group) outColInput.addItems(cols) outColInput.setCurrentIndex(outCol) cancelButton = QPushButton("Cancel", addDialog) cancelButton.clicked.connect(addDialog.reject) okButton = QPushButton("OK", addDialog) okButton.setDefault(True) okButton.clicked.connect(addDialog.accept) buttonsLayout = QHBoxLayout() buttonsLayout.addStretch(1) buttonsLayout.addWidget(okButton) buttonsLayout.addSpacing(10) buttonsLayout.addWidget(cancelButton) dialogLayout = QVBoxLayout(addDialog) dialogLayout.addWidget(group) dialogLayout.addStretch(1) dialogLayout.addItem(buttonsLayout) cell1Layout = QHBoxLayout() cell1Layout.addWidget(cell1Label) cell1Layout.addSpacing(10) cell1Layout.addWidget(cell1ColInput) cell1Layout.addSpacing(10) cell1Layout.addWidget(cell1RowInput) cell2Layout = QHBoxLayout() cell2Layout.addWidget(cell2Label) cell2Layout.addSpacing(10) cell2Layout.addWidget(cell2ColInput) cell2Layout.addSpacing(10) cell2Layout.addWidget(cell2RowInput) outLayout = QHBoxLayout() outLayout.addWidget(outLabel) outLayout.addSpacing(10) outLayout.addWidget(outColInput) outLayout.addSpacing(10) outLayout.addWidget(outRowInput) vLayout = QVBoxLayout(group) vLayout.addItem(cell1Layout) vLayout.addWidget(operatorLabel) vLayout.addItem(cell2Layout) vLayout.addWidget(equalsLabel) vLayout.addStretch(1) vLayout.addItem(outLayout) if addDialog.exec_(): cell1 = cell1ColInput.currentText() + cell1RowInput.currentText() cell2 = cell2ColInput.currentText() + cell2RowInput.currentText() outCell = outColInput.currentText() + outRowInput.currentText() return True, cell1, cell2, outCell return False, None, None, None def actionSum(self): row_first = 0 row_last = 0 row_cur = 0 col_first = 0 col_last = 0 col_cur = 0 selected = self.table.selectedItems() if selected: first = selected[0] last = selected[-1] row_first = self.table.row(first) row_last = self.table.row(last) col_first = self.table.column(first) col_last = self.table.column(last) current = self.table.currentItem() if current: row_cur = self.table.row(current) col_cur = self.table.column(current) cell1 = encode_pos(row_first, col_first) cell2 = encode_pos(row_last, col_last) out = encode_pos(row_cur, col_cur) ok, cell1, cell2, out = self.runInputDialog("Sum cells", "First cell:", "Last cell:", u"\N{GREEK CAPITAL LETTER SIGMA}", "Output to:", cell1, cell2, out) if ok: row, col = decode_pos(out) self.table.item(row, col).setText("sum %s %s" % (cell1, cell2)) def actionMath_helper(self, title, op): cell1 = "C1" cell2 = "C2" out = "C3" current = self.table.currentItem() if current: out = encode_pos(self.table.currentRow(), self.table.currentColumn()) ok, cell1, cell2, out = self.runInputDialog(title, "Cell 1", "Cell 2", op, "Output to:", cell1, cell2, out) if ok: row, col = decode_pos(out) self.table.item(row, col).setText("%s %s %s" % (op, cell1, cell2)) def actionAdd(self): self.actionMath_helper("Addition", "+") def actionSubtract(self): self.actionMath_helper("Subtraction", "-") def actionMultiply(self): self.actionMath_helper("Multiplication", "*") def actionDivide(self): self.actionMath_helper("Division", "/") def clear(self): for i in self.table.selectedItems(): i.setText("") def setupContextMenu(self): self.addAction(self.cell_addAction) self.addAction(self.cell_subAction) self.addAction(self.cell_mulAction) self.addAction(self.cell_divAction) self.addAction(self.cell_sumAction) self.addAction(self.firstSeparator) self.addAction(self.colorAction) self.addAction(self.fontAction) self.addAction(self.secondSeparator) self.addAction(self.clearAction) self.setContextMenuPolicy(Qt.ActionsContextMenu) def setupContents(self): titleBackground = QColor(Qt.lightGray) titleFont = self.table.font() titleFont.setBold(True) # column 0 self.table.setItem(0, 0, SpreadSheetItem("Item")) self.table.item(0, 0).setBackground(titleBackground) self.table.item(0, 0).setToolTip("This column shows the purchased item/service") self.table.item(0, 0).setFont(titleFont) self.table.setItem(1, 0, SpreadSheetItem("AirportBus")) self.table.setItem(2, 0, SpreadSheetItem("Flight (Munich)")) self.table.setItem(3, 0, SpreadSheetItem("Lunch")) self.table.setItem(4, 0, SpreadSheetItem("Flight (LA)")) self.table.setItem(5, 0, SpreadSheetItem("Taxi")) self.table.setItem(6, 0, SpreadSheetItem("Dinner")) self.table.setItem(7, 0, SpreadSheetItem("Hotel")) self.table.setItem(8, 0, SpreadSheetItem("Flight (Oslo)")) self.table.setItem(9, 0, SpreadSheetItem("Total:")) self.table.item(9, 0).setFont(titleFont) self.table.item(9, 0).setBackground(Qt.lightGray) # column 1 self.table.setItem(0, 1, SpreadSheetItem("Date")) self.table.item(0, 1).setBackground(titleBackground) self.table.item(0, 1).setToolTip("This column shows the purchase date, double click to change") self.table.item(0, 1).setFont(titleFont) self.table.setItem(1, 1, SpreadSheetItem("15/6/2006")) self.table.setItem(2, 1, SpreadSheetItem("15/6/2006")) self.table.setItem(3, 1, SpreadSheetItem("15/6/2006")) self.table.setItem(4, 1, SpreadSheetItem("21/5/2006")) self.table.setItem(5, 1, SpreadSheetItem("16/6/2006")) self.table.setItem(6, 1, SpreadSheetItem("16/6/2006")) self.table.setItem(7, 1, SpreadSheetItem("16/6/2006")) self.table.setItem(8, 1, SpreadSheetItem("18/6/2006")) self.table.setItem(9, 1, SpreadSheetItem()) self.table.item(9, 1).setBackground(Qt.lightGray) # column 2 self.table.setItem(0, 2, SpreadSheetItem("Price")) self.table.item(0, 2).setBackground(titleBackground) self.table.item(0, 2).setToolTip("This column shows the price of the purchase") self.table.item(0, 2).setFont(titleFont) self.table.setItem(1, 2, SpreadSheetItem("150")) self.table.setItem(2, 2, SpreadSheetItem("2350")) self.table.setItem(3, 2, SpreadSheetItem("-14")) self.table.setItem(4, 2, SpreadSheetItem("980")) self.table.setItem(5, 2, SpreadSheetItem("5")) self.table.setItem(6, 2, SpreadSheetItem("120")) self.table.setItem(7, 2, SpreadSheetItem("300")) self.table.setItem(8, 2, SpreadSheetItem("1240")) self.table.setItem(9, 2, SpreadSheetItem()) self.table.item(9, 2).setBackground(Qt.lightGray) # column 3 self.table.setItem(0, 3, SpreadSheetItem("Currency")) self.table.item(0, 3).setBackgroundColor(titleBackground) self.table.item(0, 3).setToolTip("This column shows the currency") self.table.item(0, 3).setFont(titleFont) self.table.setItem(1, 3, SpreadSheetItem("NOK")) self.table.setItem(2, 3, SpreadSheetItem("NOK")) self.table.setItem(3, 3, SpreadSheetItem("EUR")) self.table.setItem(4, 3, SpreadSheetItem("EUR")) self.table.setItem(5, 3, SpreadSheetItem("USD")) self.table.setItem(6, 3, SpreadSheetItem("USD")) self.table.setItem(7, 3, SpreadSheetItem("USD")) self.table.setItem(8, 3, SpreadSheetItem("USD")) self.table.setItem(9, 3, SpreadSheetItem()) self.table.item(9,3).setBackground(Qt.lightGray) # column 4 self.table.setItem(0, 4, SpreadSheetItem("Ex. Rate")) self.table.item(0, 4).setBackground(titleBackground) self.table.item(0, 4).setToolTip("This column shows the exchange rate to NOK") self.table.item(0, 4).setFont(titleFont) self.table.setItem(1, 4, SpreadSheetItem("1")) self.table.setItem(2, 4, SpreadSheetItem("1")) self.table.setItem(3, 4, SpreadSheetItem("8")) self.table.setItem(4, 4, SpreadSheetItem("8")) self.table.setItem(5, 4, SpreadSheetItem("7")) self.table.setItem(6, 4, SpreadSheetItem("7")) self.table.setItem(7, 4, SpreadSheetItem("7")) self.table.setItem(8, 4, SpreadSheetItem("7")) self.table.setItem(9, 4, SpreadSheetItem()) self.table.item(9,4).setBackground(Qt.lightGray) # column 5 self.table.setItem(0, 5, SpreadSheetItem("NOK")) self.table.item(0, 5).setBackground(titleBackground) self.table.item(0, 5).setToolTip("This column shows the expenses in NOK") self.table.item(0, 5).setFont(titleFont) self.table.setItem(1, 5, SpreadSheetItem("* C2 E2")) self.table.setItem(2, 5, SpreadSheetItem("* C3 E3")) self.table.setItem(3, 5, SpreadSheetItem("* C4 E4")) self.table.setItem(4, 5, SpreadSheetItem("* C5 E5")) self.table.setItem(5, 5, SpreadSheetItem("* C6 E6")) self.table.setItem(6, 5, SpreadSheetItem("* C7 E7")) self.table.setItem(7, 5, SpreadSheetItem("* C8 E8")) self.table.setItem(8, 5, SpreadSheetItem("* C9 E9")) self.table.setItem(9, 5, SpreadSheetItem("sum F2 F9")) self.table.item(9,5).setBackground(Qt.lightGray) def showAbout(self): QMessageBox.about(self, "About Spreadsheet", """ <HTML> <p><b>This demo shows use of <c>QTableWidget</c> with custom handling for individual cells.</b></p> <p>Using a customized table item we make it possible to have dynamic output in different cells. The content that is implemented for this particular demo is: <ul> <li>Adding two cells.</li> <li>Subtracting one cell from another.</li> <li>Multiplying two cells.</li> <li>Dividing one cell with another.</li> <li>Summing the contents of an arbitrary number of cells.</li> </HTML> """) def print_(self): pass
class SVNPluginPropsDialog(QDialog): " SVN plugin properties dialog " def __init__(self, plugin, client, path, parent=None): QDialog.__init__(self, parent) self.__plugin = plugin self.__client = client self.__path = path self.__createLayout() self.setWindowTitle("SVN Properties of " + path) self.__populate() self.__propsView.setFocus() return def __populate(self): " Populate the properties list " # Get the currently selected name selectedName = None selected = list(self.__propsView.selectedItems()) if selected: selectedName = str(selected[0].text(0)) self.__propsView.clear() properties = readProperties(self.__client, self.__path) if properties: for itemPath, itemProps in properties: if self.__path == itemPath or \ self.__path == itemPath + os.path.sep: for name, value in itemProps.iteritems(): name = str(name).strip() value = str(value).strip() newItem = QTreeWidgetItem([name, value]) self.__propsView.addTopLevelItem(newItem) self.__resizePropsView() self.__sortPropsView() if selectedName: index = 0 for index in xrange(0, self.__propsView.topLevelItemCount()): item = self.__propsView.topLevelItem(index) if selectedName == item.text(0): item.setSelected(True) return def __resizePropsView(self): " Resizes the properties table " self.__propsView.header().setStretchLastSection(True) self.__propsView.header().resizeSections(QHeaderView.ResizeToContents) return def __sortPropsView(self): " Sorts the properties table " self.__propsView.sortItems( self.__propsView.sortColumn(), self.__propsView.header().sortIndicatorOrder()) return def __createLayout(self): " Creates the dialog layout " self.resize(640, 480) self.setSizeGripEnabled(True) vboxLayout = QVBoxLayout(self) hLayout = QHBoxLayout() self.__propsView = QTreeWidget() self.__propsView.setAlternatingRowColors(True) self.__propsView.setRootIsDecorated(False) self.__propsView.setItemsExpandable(False) self.__propsView.setSortingEnabled(True) self.__propsView.setItemDelegate(NoOutlineHeightDelegate(4)) self.__propsView.itemSelectionChanged.connect( self.__propsSelectionChanged) propsViewHeader = QTreeWidgetItem(["Property Name", "Property Value"]) self.__propsView.setHeaderItem(propsViewHeader) self.__propsView.header().setSortIndicator(0, Qt.DescendingOrder) hLayout.addWidget(self.__propsView) self.__delButton = QToolButton() self.__delButton.setText("Delete") self.__delButton.setFocusPolicy(Qt.NoFocus) self.__delButton.setEnabled(False) self.__delButton.clicked.connect(self.__onDel) hLayout.addWidget(self.__delButton, 0, Qt.AlignBottom) vboxLayout.addLayout(hLayout) # Set property part setGroupbox = QGroupBox(self) setGroupbox.setTitle("Set Property") setLayout = QGridLayout(setGroupbox) setLayout.addWidget(QLabel("Name"), 0, 0, Qt.AlignTop | Qt.AlignRight) setLayout.addWidget(QLabel("Value"), 1, 0, Qt.AlignTop | Qt.AlignRight) self.__nameEdit = QLineEdit() self.__nameEdit.textChanged.connect(self.__nameChanged) setLayout.addWidget(self.__nameEdit, 0, 1) self.__valueEdit = QTextEdit() self.__valueEdit.setAcceptRichText(False) self.__valueEdit.textChanged.connect(self.__valueChanged) metrics = QFontMetrics(self.__valueEdit.font()) rect = metrics.boundingRect("X") self.__valueEdit.setFixedHeight(rect.height() * 4 + 5) setLayout.addWidget(self.__valueEdit, 1, 1) self.__setButton = QToolButton() self.__setButton.setText("Set") self.__setButton.setFocusPolicy(Qt.NoFocus) self.__setButton.setEnabled(False) self.__setButton.clicked.connect(self.__onSet) setLayout.addWidget(self.__setButton, 1, 2, Qt.AlignBottom | Qt.AlignHCenter) sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( setGroupbox.sizePolicy().hasHeightForWidth()) setGroupbox.setSizePolicy(sizePolicy) vboxLayout.addWidget(setGroupbox) # Buttons at the bottom buttonBox = QDialogButtonBox(self) buttonBox.setOrientation(Qt.Horizontal) buttonBox.setStandardButtons(QDialogButtonBox.Ok) buttonBox.button(QDialogButtonBox.Ok).setDefault(True) buttonBox.accepted.connect(self.close) vboxLayout.addWidget(buttonBox) return def __onSet(self): " Triggered when propery set is clicked " name = self.__nameEdit.text().strip() value = self.__valueEdit.toPlainText().strip() try: commitInfo = self.__client.propset(name, value, self.__path) if commitInfo: logging.info(str(commitInfo)) self.__populate() self.__plugin.notifyPathChanged(self.__path) self.__nameEdit.clear() self.__valueEdit.clear() self.__propsView.setFocus() except pysvn.ClientError, exc: message = exc.args[0] logging.error(message) return except Exception, exc: logging.error(str(exc)) return
class SessionEditor(QDialog): def __init__(self, parent=None): super(SessionEditor, self).__init__(parent) self.setWindowModality(Qt.WindowModal) layout = QVBoxLayout() self.setLayout(layout) grid = QGridLayout() layout.addLayout(grid) self.name = QLineEdit() self.nameLabel = l = QLabel() l.setBuddy(self.name) grid.addWidget(l, 0, 0) grid.addWidget(self.name, 0, 1) self.autosave = QCheckBox() grid.addWidget(self.autosave, 1, 1) self.basedir = widgets.urlrequester.UrlRequester() self.basedirLabel = l = QLabel() l.setBuddy(self.basedir) grid.addWidget(l, 2, 0) grid.addWidget(self.basedir, 2, 1) self.inclPaths = ip = QGroupBox(self, checkable=True, checked=False) ipLayout = QVBoxLayout() ip.setLayout(ipLayout) self.replPaths = QCheckBox() ipLayout.addWidget(self.replPaths) self.replPaths.toggled.connect(self.toggleReplace) self.include = widgets.listedit.FilePathEdit() self.include.listBox.setDragDropMode(QAbstractItemView.InternalMove) ipLayout.addWidget(self.include) grid.addWidget(ip, 3, 1) self.revt = QPushButton(self) self.clear = QPushButton(self) self.revt.clicked.connect(self.revertPaths) self.clear.clicked.connect(self.clearPaths) self.include.layout().addWidget(self.revt, 5, 1) self.include.layout().addWidget(self.clear, 6, 1) layout.addWidget(widgets.Separator()) self.buttons = b = QDialogButtonBox(self) layout.addWidget(b) b.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) b.accepted.connect(self.accept) b.rejected.connect(self.reject) userguide.addButton(b, "sessions") app.translateUI(self) def translateUI(self): self.nameLabel.setText(_("Name:")) self.autosave.setText( _("Always save the list of documents in this session")) self.basedirLabel.setText(_("Base directory:")) self.inclPaths.setTitle(_("Use session specific include path")) self.replPaths.setText(_("Replace global path")) self.replPaths.setToolTip( _("When checked, paths in LilyPond preferences are not included.")) self.revt.setText(_("Copy global path")) self.revt.setToolTip( _("Add and edit the path from LilyPond preferences.")) self.clear.setText(_("Clear")) self.clear.setToolTip(_("Remove all paths.")) def load(self, name): settings = sessions.sessionGroup(name) self.autosave.setChecked(settings.value("autosave", True, bool)) self.basedir.setPath(settings.value("basedir", "", type(""))) self.include.setValue( qsettings.get_string_list(settings, "include-path")) self.inclPaths.setChecked(settings.value("set-paths", False, bool)) self.replPaths.setChecked(settings.value("repl-paths", False, bool)) if not self.replPaths.isChecked(): self.addDisabledGenPaths() self.revt.setEnabled(False) # more settings here def fetchGenPaths(self): """Fetch paths from general preferences.""" return qsettings.get_string_list(QSettings(), "lilypond_settings/include_path") def addDisabledGenPaths(self): """Add global paths, but set as disabled.""" genPaths = self.fetchGenPaths() for p in genPaths: i = QListWidgetItem(p, self.include.listBox) i.setFlags(Qt.NoItemFlags) def toggleReplace(self): """Called when user changes setting for replace of global paths.""" if self.replPaths.isChecked(): items = self.include.items() for i in items: if not (i.flags() & Qt.ItemIsEnabled): #is not enabled self.include.listBox.takeItem(self.include.listBox.row(i)) self.revt.setEnabled(True) else: self.addDisabledGenPaths() self.revt.setEnabled(False) def revertPaths(self): """Add global paths (for edit).""" genPaths = self.fetchGenPaths() for p in genPaths: i = QListWidgetItem(p, self.include.listBox) def clearPaths(self): """Remove all active paths.""" items = self.include.items() for i in items: if i.flags() & Qt.ItemIsEnabled: self.include.listBox.takeItem(self.include.listBox.row(i)) def save(self, name): settings = sessions.sessionGroup(name) settings.setValue("autosave", self.autosave.isChecked()) settings.setValue("basedir", self.basedir.path()) settings.setValue("set-paths", self.inclPaths.isChecked()) settings.setValue("repl-paths", self.replPaths.isChecked()) path = [ i.text() for i in self.include.items() if i.flags() & Qt.ItemIsEnabled ] settings.setValue("include-path", path) # more settings here def defaults(self): self.autosave.setChecked(True) self.basedir.setPath('') self.inclPaths.setChecked(False) self.replPaths.setChecked(False) self.addDisabledGenPaths() self.revt.setEnabled(False) # more defaults here def edit(self, name=None): self._originalName = name if name: caption = _("Edit session: {name}").format(name=name) self.name.setText(name) self.load(name) else: caption = _("Edit new session") self.name.clear() self.name.setFocus() self.defaults() self.setWindowTitle(app.caption(caption)) if self.exec_(): # name changed? name = self.name.text() if self._originalName and name != self._originalName: sessions.renameSession(self._originalName, name) self.save(name) return name def done(self, result): if not result or self.validate(): super(SessionEditor, self).done(result) def validate(self): """Checks if the input is acceptable. If this method returns True, the dialog is accepted when OK is clicked. Otherwise a messagebox could be displayed, and the dialog will remain visible. """ name = self.name.text().strip() self.name.setText(name) if not name: self.name.setFocus() QMessageBox.warning(self, app.caption(_("Warning")), _("Please enter a session name.")) if self._originalName: self.name.setText(self._originalName) return False elif name == '-': self.name.setFocus() QMessageBox.warning( self, app.caption(_("Warning")), _("Please do not use the name '{name}'.".format(name="-"))) return False elif self._originalName != name and name in sessions.sessionNames(): self.name.setFocus() box = QMessageBox( QMessageBox.Warning, app.caption(_("Warning")), _("Another session with the name {name} already exists.\n\n" "Do you want to overwrite it?").format(name=name), QMessageBox.Discard | QMessageBox.Cancel, self) box.button(QMessageBox.Discard).setText(_("Overwrite")) result = box.exec_() if result != QMessageBox.Discard: return False return True
class TalkDetailsWidget(QWidget): def __init__(self, parent=None): super(TalkDetailsWidget, self).__init__(parent) self.layout = QGridLayout() self.setLayout(self.layout) self.buttonLayout = QHBoxLayout() saveIcon = QIcon.fromTheme("document-save") self.saveButton = QPushButton('Save Talk') self.saveButton.setIcon(saveIcon) self.buttonLayout.addWidget(self.saveButton) self.layout.addLayout(self.buttonLayout, 0, 1, 1, 1) self.titleLabel = QLabel('Title') self.titleLineEdit = QLineEdit() self.presenterLabel = QLabel('Presenter') self.presenterLineEdit = QLineEdit() self.layout.addWidget(self.titleLabel, 1, 0, 1, 1) self.layout.addWidget(self.titleLineEdit, 1, 1, 1, 1) self.layout.addWidget(self.presenterLabel, 1, 2, 1, 1) self.layout.addWidget(self.presenterLineEdit, 1, 3, 1, 1) self.eventLabel = QLabel('Event') self.eventLineEdit = QLineEdit() self.categoryLabel = QLabel('Category') self.categoryLineEdit = QLineEdit() self.layout.addWidget(self.eventLabel, 2, 0, 1, 1) self.layout.addWidget(self.eventLineEdit, 2, 1, 1, 1) self.layout.addWidget(self.categoryLabel, 2, 2, 1, 1) self.layout.addWidget(self.categoryLineEdit, 2, 3, 1, 1) self.roomLabel = QLabel('Room') self.roomLineEdit = QLineEdit() self.dateLayout = QHBoxLayout() self.dateLabel = QLabel('Date') self.dateEdit = QDateEdit() currentDate = QDate() self.dateEdit.setDate(currentDate.currentDate()) self.dateEdit.setCalendarPopup(True) self.layout.addWidget(self.roomLabel, 3, 0, 1, 1) self.layout.addWidget(self.roomLineEdit, 3, 1, 1, 1) self.dateLayout.addWidget(self.dateEdit) self.layout.addWidget(self.dateLabel, 3, 2, 1, 1) self.layout.addLayout(self.dateLayout, 3, 3, 1, 1) self.startTimeLayout = QHBoxLayout() self.startTimeLabel = QLabel('Start Time') self.startTimeEdit = QTimeEdit() self.startTimeLayout.addWidget(self.startTimeEdit) self.endTimeLayout = QHBoxLayout() self.endTimeLabel = QLabel('End Time') self.endTimeEdit = QTimeEdit() self.endTimeLayout.addWidget(self.endTimeEdit) self.layout.addWidget(self.startTimeLabel, 4, 0, 1, 1) self.layout.addLayout(self.startTimeLayout, 4, 1, 1, 1) self.layout.addWidget(self.endTimeLabel, 4, 2, 1, 1) self.layout.addLayout(self.endTimeLayout, 4, 3, 1, 1) self.descriptionLabel = QLabel('Description') self.descriptionLabel.setAlignment(Qt.AlignTop) self.descriptionTextEdit = QPlainTextEdit() self.layout.addWidget(self.descriptionLabel, 5, 0, 1, 1) self.layout.addWidget(self.descriptionTextEdit, 5, 1, 1, 3) def enable_input_fields(self): self.titleLineEdit.setPlaceholderText("Enter Talk Title") self.presenterLineEdit.setPlaceholderText("Enter Presenter Name") self.categoryLineEdit.setPlaceholderText("Enter Category Type") self.eventLineEdit.setPlaceholderText("Enter Event Name") self.roomLineEdit.setPlaceholderText("Enter Room Location") self.titleLineEdit.setEnabled(True) self.presenterLineEdit.setEnabled(True) self.categoryLineEdit.setEnabled(True) self.eventLineEdit.setEnabled(True) self.roomLineEdit.setEnabled(True) self.dateEdit.setEnabled(True) self.startTimeEdit.setEnabled(True) self.endTimeEdit.setEnabled(True) self.descriptionTextEdit.setEnabled(True) def disable_input_fields(self): self.titleLineEdit.setPlaceholderText("") self.presenterLineEdit.setPlaceholderText("") self.categoryLineEdit.setPlaceholderText("") self.eventLineEdit.setPlaceholderText("") self.roomLineEdit.setPlaceholderText("") self.titleLineEdit.setEnabled(False) self.presenterLineEdit.setEnabled(False) self.categoryLineEdit.setEnabled(False) self.eventLineEdit.setEnabled(False) self.roomLineEdit.setEnabled(False) self.dateEdit.setEnabled(False) self.startTimeEdit.setEnabled(False) self.endTimeEdit.setEnabled(False) self.descriptionTextEdit.setEnabled(False) def clear_input_fields(self): self.titleLineEdit.clear() self.presenterLineEdit.clear() self.categoryLineEdit.clear() self.eventLineEdit.clear() self.roomLineEdit.clear() self.descriptionTextEdit.clear()
class MainWindow(QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.fnames = [] # list of file names to be converted self.office_listener_started = False self.parse_cla() addQPB = QPushButton(self.tr('Add')) delQPB = QPushButton(self.tr('Delete')) clearQPB = QPushButton(self.tr('Clear')) vlayout1 = utils.add_to_layout('v', addQPB, delQPB, clearQPB, None) self.filesList = utils.FilesList() self.filesList.setSelectionMode(QAbstractItemView.ExtendedSelection) hlayout1 = utils.add_to_layout('h', self.filesList, vlayout1) outputQL = QLabel(self.tr('Output folder:')) self.toQLE = QLineEdit() self.toQLE.setReadOnly(True) self.toQTB = QToolButton() self.toQTB.setText('...') hlayout2 = utils.add_to_layout('h', outputQL, self.toQLE, self.toQTB) self.audiovideo_tab = AudioVideoTab(self) self.image_tab = ImageTab(self) self.document_tab = DocumentTab(self) self.tabs = [self.audiovideo_tab, self.image_tab, self.document_tab] tab_names = [ self.tr('Audio/Video'), self.tr('Images'), self.tr('Documents') ] self.tabWidget = QTabWidget() for num, tab in enumerate(tab_names): self.tabWidget.addTab(self.tabs[num], tab) self.tabWidget.setCurrentIndex(0) self.origQCB = QCheckBox( self.tr('Save each file in the same\nfolder as input file')) self.deleteQCB = QCheckBox(self.tr('Delete original')) convertQPB = QPushButton(self.tr('&Convert')) hlayout3 = utils.add_to_layout('h', self.origQCB, self.deleteQCB, None) hlayout4 = utils.add_to_layout('h', None, convertQPB) final_layout = utils.add_to_layout('v', hlayout1, self.tabWidget, hlayout2, hlayout3, hlayout4) self.dependenciesQL = QLabel() self.statusBar().addPermanentWidget(self.dependenciesQL, stretch=1) widget = QWidget() widget.setLayout(final_layout) self.setCentralWidget(widget) openAction = utils.create_action(self, self.tr('Open'), QKeySequence.Open, None, self.tr('Open a file'), self.add_files) convertAction = utils.create_action(self, self.tr('Convert'), 'Ctrl+C', None, self.tr('Convert files'), self.start_conversion) quitAction = utils.create_action(self, self.tr('Quit'), 'Ctrl+Q', None, self.tr('Quit'), self.close) edit_presetsAction = utils.create_action(self, self.tr('Edit Presets'), 'Ctrl+P', None, self.tr('Edit Presets'), self.open_dialog_presets) importAction = utils.create_action(self, self.tr('Import'), None, None, self.tr('Import presets'), self.import_presets) exportAction = utils.create_action(self, self.tr('Export'), None, None, self.tr('Export presets'), self.export_presets) resetAction = utils.create_action(self, self.tr('Reset'), None, None, self.tr('Reset presets'), self.reset_presets) syncAction = utils.create_action(self, self.tr('Synchronize'), None, None, self.tr('Synchronize presets'), self.sync_presets) removeoldAction = utils.create_action(self, self.tr('Remove old'), None, None, self.tr('Remove old presets'), self.removeold_presets) clearallAction = utils.create_action(self, self.tr('Clear All'), None, None, self.tr('Clear form'), self.clear_all) preferencesAction = utils.create_action(self, self.tr('Preferences'), 'Alt+Ctrl+P', None, self.tr('Preferences'), self.open_dialog_preferences) trackerAction = utils.create_action( self, 'Issue tracker', None, None, None, lambda: webbrowser.open( "https://github.com/Ilias95/FF-Multi-Converter/issues")) wikiAction = utils.create_action( self, 'Wiki', None, None, None, lambda: webbrowser.open( "https://github.com/Ilias95/FF-Multi-Converter/wiki")) ffmpegdocAction = utils.create_action( self, 'FFmpeg ' + self.tr('documentation'), None, None, None, lambda: webbrowser.open("https://www.ffmpeg.org/documentation.html" )) imagemagickdocAction = utils.create_action( self, 'ImageMagick ' + self.tr('documentation'), None, None, None, lambda: webbrowser.open( "http://www.imagemagick.org/script/convert.php")) aboutAction = utils.create_action(self, self.tr('About'), 'Ctrl+?', None, self.tr('About'), self.open_dialog_about) fileMenu = self.menuBar().addMenu(self.tr('File')) editMenu = self.menuBar().addMenu(self.tr('Edit')) presetsMenu = self.menuBar().addMenu(self.tr('Presets')) helpMenu = self.menuBar().addMenu(self.tr('Help')) utils.add_actions(fileMenu, [openAction, convertAction, None, quitAction]) utils.add_actions(presetsMenu, [ edit_presetsAction, importAction, exportAction, resetAction, None, syncAction, removeoldAction ]) utils.add_actions(editMenu, [clearallAction, None, preferencesAction]) utils.add_actions(helpMenu, [ trackerAction, wikiAction, None, ffmpegdocAction, imagemagickdocAction, None, aboutAction ]) self.filesList.dropped.connect(self.add_files_dropped) addQPB.clicked.connect(self.add_files) delQPB.clicked.connect(self.delete_files) clearQPB.clicked.connect(self.clear_fileslist) self.tabWidget.currentChanged.connect( lambda: self.tabs[0].moreQPB.setChecked(False)) self.origQCB.toggled.connect( lambda: self.toQLE.setEnabled(not self.origQCB.isChecked())) self.toQTB.clicked.connect(self.open_dir) convertQPB.clicked.connect(convertAction.triggered) del_shortcut = QShortcut(self) del_shortcut.setKey(Qt.Key_Delete) del_shortcut.activated.connect(self.delete_files) self.setWindowTitle('FF Multi Converter') QTimer.singleShot(0, self.check_for_dependencies) QTimer.singleShot(0, self.load_settings) QTimer.singleShot(0, self.audiovideo_tab.set_default_command) QTimer.singleShot(0, self.image_tab.set_default_command) QTimer.singleShot(0, self.update_filesList) def parse_cla(self): """Parse command line arguments.""" for i in QCoreApplication.argv()[1:]: i = os.path.abspath(i) if os.path.isfile(i): self.fnames.append(i) else: print("ffmulticonverter: {0}: Not a file".format(i)) def check_for_dependencies(self): """ Check if each one of the program dependencies are installed and update self.dependenciesQL with the appropriate message. """ self.vidconverter = None if utils.is_installed('ffmpeg'): self.vidconverter = 'ffmpeg' elif utils.is_installed('avconv'): self.vidconverter = 'avconv' self.unoconv = utils.is_installed('unoconv') self.imagemagick = utils.is_installed('convert') missing = [] if self.vidconverter is None: missing.append('ffmpeg/avconv') if not self.unoconv: missing.append('unoconv') if not self.imagemagick: missing.append('imagemagick') if missing: missing = ', '.join(missing) status = self.tr('Missing dependencies:') + ' ' + missing self.dependenciesQL.setText(status) def load_settings(self, onstart=True): """ Load settings values. onstart -- True means that this is the first time the method called, usually when program beggins """ def get_str_value(settings, name): value = settings.value(name) if value is not None: return value return '' settings = QSettings() self.overwrite_existing = utils.str_to_bool( get_str_value(settings, 'overwrite_existing')) self.default_output = get_str_value(settings, 'default_output') self.prefix = get_str_value(settings, 'prefix') self.suffix = get_str_value(settings, 'suffix') defcmd = get_str_value(settings, 'default_command') extraformats_video = get_str_value(settings, 'extraformats') videocodecs = settings.value('videocodecs') audiocodecs = settings.value('audiocodecs') defcmd_image = get_str_value(settings, 'default_command_image') extraformats_image = get_str_value(settings, 'extraformats_image') if videocodecs is None: videocodecs = "\n".join(config.video_codecs) settings.setValue('videocodecs', videocodecs) if audiocodecs is None: audiocodecs = "\n".join(config.audio_codecs) settings.setValue('audiocodecs', audiocodecs) if defcmd: self.default_command = defcmd else: self.default_command = config.default_ffmpeg_cmd if defcmd_image: self.default_command_image = defcmd_image else: self.default_command_image = config.default_imagemagick_cmd self.audiovideo_tab.fill_video_comboboxes(videocodecs, audiocodecs, extraformats_video) self.image_tab.fill_extension_combobox(extraformats_image) if onstart: self.toQLE.setText(self.default_output) def current_tab(self): """Return the corresponding object of the selected tab.""" for i in self.tabs: if self.tabs.index(i) == self.tabWidget.currentIndex(): return i def update_filesList(self): """Clear self.filesList and add to it all items of self.fname.""" self.filesList.clear() for i in self.fnames: self.filesList.addItem(i) def add_files(self): """ Get file names using a standard Qt dialog. Append to self.fnames each file name that not already exists and update self.filesList. """ # Create lists holding file formats extension. # To be passed in QFileDialog.getOpenFileNames(). all_files = '*' audiovideo_files = ' '.join( ['*.' + i for i in self.audiovideo_tab.formats]) img_formats = self.image_tab.formats[:] img_formats.extend(self.image_tab.extra_img) image_files = ' '.join(['*.' + i for i in img_formats]) document_files = ' '.join( ['*.' + i for i in self.document_tab.formats]) formats = [all_files, audiovideo_files, image_files, document_files] strings = [ self.tr('All Files'), self.tr('Audio/Video Files'), self.tr('Image Files'), self.tr('Document Files') ] filters = '' for string, extensions in zip(strings, formats): filters += string + ' ({0});;'.format(extensions) filters = filters[:-2] # remove last ';;' fnames = QFileDialog.getOpenFileNames( self, 'FF Multi Converter - ' + self.tr('Choose File'), config.home, filters) if fnames: for i in fnames: if not i in self.fnames: self.fnames.append(i) self.update_filesList() def add_files_dropped(self, links): """ Append to self.fnames each file name that not already exists and update self.filesList. """ for path in links: if os.path.isfile(path) and not path in self.fnames: self.fnames.append(path) self.update_filesList() def delete_files(self): """ Get selectedItems of self.filesList, remove them from self.fnames and update the filesList. """ items = self.filesList.selectedItems() if items: for i in items: self.fnames.remove(i.text()) self.update_filesList() def clear_fileslist(self): """Make self.fnames empty and update self.filesList.""" self.fnames = [] self.update_filesList() def clear_all(self): """Clear all values of graphical widgets.""" self.toQLE.clear() self.origQCB.setChecked(False) self.deleteQCB.setChecked(False) self.clear_fileslist() self.audiovideo_tab.clear() self.image_tab.clear() def open_dir(self): """ Get a directory name using a standard QtDialog and update self.toQLE with dir's name. """ if self.toQLE.isEnabled(): output = QFileDialog.getExistingDirectory( self, 'FF Multi Converter - ' + self.tr('Choose output destination'), config.home) if output: self.toQLE.setText(output) def import_presets(self): presets_dlgs.ShowPresets().import_presets() def export_presets(self): presets_dlgs.ShowPresets().export_presets() def reset_presets(self): presets_dlgs.ShowPresets().reset() def sync_presets(self): presets_dlgs.ShowPresets().synchronize() def removeold_presets(self): presets_dlgs.ShowPresets().remove_old() def ok_to_continue(self): """ Check if everything is ok to continue with conversion. Check if: - At least one file has given for conversion. - An output folder has given. - Output folder exists. Return False if an error arises, else True. """ try: if not self.fnames: raise ValidationError( self.tr('You must add at least one file to convert!')) elif not self.origQCB.isChecked() and not self.toQLE.text(): raise ValidationError( self.tr('You must choose an output folder!')) elif (not self.origQCB.isChecked() and not os.path.exists(self.toQLE.text())): raise ValidationError( self.tr('Output folder does not exists!')) if not self.current_tab().ok_to_continue(): return False return True except ValidationError as e: QMessageBox.warning(self, 'FF Multi Converter - ' + self.tr('Error!'), str(e)) return False def get_output_extension(self): """Extract the desired output file extension from GUI and return it.""" tab = self.current_tab() if tab.name == 'AudioVideo': ext_to = self.audiovideo_tab.extQCB.currentText() elif tab.name == 'Images': ext_to = tab.extQCB.currentText() else: ext_to = tab.convertQCB.currentText().split()[-1] return '.' + ext_to def start_conversion(self): """ Extract the appropriate information from GUI and call the Progress dialog with the suitable argumens. """ if not self.ok_to_continue(): return tab = self.current_tab() if tab.name == 'Documents' and not self.office_listener_started: utils.start_office_listener() self.office_listener_started = True ext_to = self.get_output_extension() _list = utils.create_paths_list(self.fnames, ext_to, self.prefix, self.suffix, self.toQLE.text(), self.origQCB.isChecked(), self.overwrite_existing) dialog = progress.Progress(_list, tab, self.deleteQCB.isChecked(), self) dialog.show() def open_dialog_preferences(self): """Open the preferences dialog.""" dialog = preferences_dlg.Preferences(self) if dialog.exec_(): self.load_settings(onstart=False) def open_dialog_presets(self): """Open the presets dialog.""" dialog = presets_dlgs.ShowPresets(self) dialog.exec_() def open_dialog_about(self): """Call the about dialog with the appropriate values.""" msg = self.tr('Convert among several file types to other formats') msg = textwrap.fill(msg, 54).replace('\n', '<br>') text = '''<b> FF Multi Converter {0} </b> <p>{1} <p><a href="{2}">FF Multi Converter - Home Page</a> <p>Copyright © 2011-2015 {3} <br>License: {4} <p>Python {5} - Qt {6} - PyQt {7} on {8}'''\ .format(ffmc.__version__, msg, ffmc.__url__, ffmc.__author__, ffmc.__license__, platform.python_version()[:5], QT_VERSION_STR, PYQT_VERSION_STR, platform.system()) image = ':/ffmulticonverter.png' authors = '{0} <{1}>\n\n'.format(ffmc.__author__, ffmc.__author_email__) authors += 'Contributors:\nPanagiotis Mavrogiorgos' translators = [] for i in config.translators: translators.append('{0}\n {1}'.format(i[0], i[1])) translators = '\n\n'.join(translators) dialog = about_dlg.AboutDialog(text, image, authors, translators, self) dialog.exec_()
class MainWindow(QWidget): def __init__(self): super(MainWindow, self).__init__() self.createServer() self.configureWindow() self.createUi() self.readConfig() self.loginName = '' for cmd in self.config['autorun']: self.evalCmd(cmd) def configureWindow(self): self.setWindowTitle('Simple Chat Program') self.resize(700, 600) self.center() def readConfig(self): self.config = { 'friends': [], 'autorun': [], 'receiveDirectory': 'received', } path = os.path.join(mydir, 'config.json') try: with open(path, 'r') as f: self.config.update(json.load(f)) except IOError: self.buf.error('Cannot read configuration file %s.' % path) except ValueError: self.buf.error('Configuration file %s contains errors.' % path) rdir = self.config['receiveDirectory'] if os.path.isabs(rdir): self.receiveDirectory = rdir else: self.receiveDirectory = os.path.join(mydir, rdir) def createUi(self): main = QHBoxLayout() console = QVBoxLayout() self.buf = TextBrowser() self.buf.setFontFamily('monospace') self.buf.setFocusPolicy(Qt.NoFocus) console.addWidget(self.buf) self.command_line = QLineEdit() console.addWidget(self.command_line) main.addLayout(console, 1) self.tab = QTabWidget() self.tab.setTabsClosable(True) self.peers = {} main.addWidget(self.tab, 3) self.setLayout(main) self.command_line.returnPressed.connect(self.onCommand) self.tab.tabCloseRequested.connect(self.onTabCloseRequested) def createServer(self): self.server = QTcpServer() if not self.server.listen(port=PEER_PORT): QMessageBox.critical( self, "Server Error", "Cannot start server. Port %d seems in use." % PEER_PORT) sys.exit(1) self.server.newConnection.connect(self.onNewConnection) def center(self): qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) def addPage(self, socket): addr = socket.peerAddress() page = ChatWindow(socket, addr) self.peers[addr] = page self.tab.addTab(page, addr.toString()) def newActive(self, peer, resolve=True): if resolve and peer in self.config['friends']: self.buf.info('%s is in friends list, querying...' % peer) def cb(res): if res == 'n': self.buf.error('%s is offline' % peer) elif res[0].isdigit(): self.buf.info('%s has IP address %s' % (peer, res)) self.newActive(res, False) else: self.buf.error('status of %s is unknown' % peer) self.talkToCentral('q%s' % peer, u'query', r'', cb, False) return socket = QTcpSocket() socket.connectToHost(peer, PEER_PORT) def onConnected(): self.buf.info('Connected to %s' % peer) self.addPage(socket) def onError(): self.buf.error('Error communicating with %s: %s' % ( peer, socket.errorString())) socket.connected.connect(onConnected) socket.error.connect(onError) self.buf.info('Reaching out to %s...' % peer) def talkToCentral(self, msg, name, pattern, cb=None, successMsg=True): Name = name.title() socket = QTcpSocket() socket.connectToHost(CENTRAL_ADDR, CENTRAL_PORT) def onConnected(): socket.write(msg) def onReadyRead(): response = str(socket.readAll()) if re.match(pattern, response): if successMsg: self.buf.info(u'%s successful.' % Name) if cb: cb(response) else: self.buf.error(u'%s failed, server said %s.' % (Name, repr(response))) socket.close() socket.readyRead.connect(onReadyRead) def onError(): self.buf.error(u'Error %s: %s' % (name, urepr(socket.errorString()))) socket.connected.connect(onConnected) socket.error.connect(onError) def login(self, obj): name, sep, passwd = obj.partition(' ') def cb(res): self.loginName = name self.talkToCentral('%s_%s' % (name, passwd), u'login', r'^lol$', cb) def logout(self): if not self.loginName: self.buf.error(u'Not logged in') return def cb(res): self.loginName = '' self.talkToCentral('logout%s' % self.loginName, u'logout', r'^loo$', cb) def queryOne(self, p): def cb(res): if res == 'n': self.buf.info('%s: offline' % p) elif res[0].isdigit(): self.buf.info('%s: online, %s' % (p, res)) else: self.buf.info('%s: unknown' % p) self.talkToCentral('q%s' % p, u'query', r'', cb, False) def query(self, obj): if obj: self.queryOne(obj) else: for p in self.config['friends']: self.queryOne(p) def evalCmd(self, command): if len(command) == 0: return if command[0] != u'/': self.buf.info(u"%s taken as implicit /talk" % urepr(command)) command = u'/talk ' + command verb, sep, obj = command[1:].partition(' ') if verb in (u't', u'talk'): self.newActive(obj) elif verb in (u'h', u'help'): self.buf.info(COMMANDS_HELP) elif verb == u'login': self.login(obj) elif verb == u'logout': self.logout() elif verb in (u'q', u'query'): self.query(obj) else: self.buf.error(u'Unknown command %s.' % urepr(verb)) def onCommand(self): self.evalCmd(unicode(self.command_line.text())) self.command_line.clear() readBufSize = 1024 text_msg_pattern = re.compile(r'^T(\d+) (.*)$', re.S) file_msg_pattern = re.compile(r'^F(\d+) ([^/]+)/(.*)$', re.S) def onNewConnection(self): socket = self.server.nextPendingConnection() def onReadyRead(): addr = socket.peerAddress() if addr not in self.peers: self.addPage(socket) addr_s = addr.toString() payload = str(socket.read(self.readBufSize)) if payload[0] == 'T': payload_m = re.match(self.text_msg_pattern, payload) if not payload_m: self.buf.error('Bad text message from %s' % addr_s) return size = int(payload_m.group(1)) segments = [payload_m.group(2)] remain = size - len(segments[0]) while remain > 0: payload = str(socket.read(remain)) if len(payload) <= 0: self.buf.error('Incomplete text message from %s' ' - need %d more bytes' % (addr_s, remain)) break segments.append(payload) remain -= len(payload) self.peers[addr].buf.feed(''.join(segments)) elif payload[0] == 'F': payload_m = re.match(self.file_msg_pattern, payload) if not payload_m: self.buf.error('Bad file message from %s: %s' % (addr_s, repr(payload))) return size = int(payload_m.group(1)) bname = payload_m.group(2) rdir = self.receiveDirectory path = os.path.join(rdir, bname) with open(path, 'wb') as f: segment = payload_m.group(3) f.write(segment) remain = size - len(segment) while remain > 0: segment = str(socket.read( min(remain, self.readBufSize))) if len(segment) <= 0: self.buf.error('Incomplete file message from %s' ' - need %d more bytes' % (addr_s, remain)) break f.write(segment) remain -= len(segment) self.buf.info('File %s from %s saved at %s' % (repr(bname), addr_s, rdir)) else: self.buf.error('Bad message from %s: unknown type ' '"%s"' % (addr.toString(), payload[0])) socket.readyRead.connect(onReadyRead) def onTabCloseRequested(self, idx): page = self.tab.widget(idx) self.tab.removeTab(idx) page.close() page.deleteLater()
class SessionsManager(QDialog): def __init__(self, n, parent=None): super(SessionsManager, self).__init__(parent) self.par = n #main title = Settingz().positions(30) self.titleID = title['id'] self.titlePage = title['page'] self.titleName = title['name'] self.titleSub = title['subID'] self.titleIcon = title['icon'] self.pagetitle = self.titlePage #stylesheet stylesheet = Valid().background() + Valid().font() treeStyleSheet = Valid().treez() self.groupBox1 = QGroupBox(self.titleName) self.groupBox2 = QGroupBox('Add') #items self.tree = QTreeWidget() self.tree.setHeaderLabel("Choose " + self.titleName) #tree.setItemDelegate(Delegate()) self.tree.setItemDelegate(Delegates()) self.tree.headerItem().setText(0, 'Name') self.tree.setStyleSheet(treeStyleSheet) self.makeTree() self.tree.setMinimumHeight(250) self.tree.clicked.connect(lambda: self.getSelection()) self.tree.itemClicked.connect(lambda state: self.getChecked(state)) #buttons #add nImg = Buttons().addButton() self.pb = QPushButton() self.pb.setFlat(True) self.pb.setIcon(QIcon(nImg)) self.pb.setMaximumHeight(30) self.pb.setMaximumWidth(30) nImg1 = Buttons().closeButton() self.pb1 = QPushButton() self.pb1.setFlat(True) self.pb1.setIcon(QIcon(nImg1)) self.pb1.setMaximumHeight(30) self.pb1.setMaximumWidth(30) nImg2 = Buttons().editButton() self.pb2 = QPushButton() self.pb2.setFlat(True) self.pb2.setIcon(QIcon(nImg2)) self.pb2.setMaximumHeight(30) self.pb2.setMaximumWidth(30) nImg3 = Buttons().deleteButton() self.pb3 = QPushButton() self.pb3.setFlat(True) self.pb3.setIcon(QIcon(nImg3)) self.pb3.setMaximumHeight(30) self.pb3.setMaximumWidth(30) nImg4 = Buttons().saveButton() self.pb4 = QPushButton() self.pb4.setFlat(True) self.pb4.setIcon(QIcon(nImg4)) self.pb4.setMaximumHeight(30) self.pb4.setMaximumWidth(30) nImg5 = Buttons().resetButton() self.pb5 = QPushButton() self.pb5.setFlat(True) self.pb5.setIcon(QIcon(nImg5)) self.pb5.setMaximumHeight(30) self.pb5.setMaximumWidth(30) nImg6 = Buttons().closeButton() self.pb6 = QPushButton() self.pb6.setFlat(True) self.pb6.setIcon(QIcon(nImg6)) self.pb6.setMaximumHeight(30) self.pb6.setMaximumWidth(30) nImg7 = Buttons().addButton() self.pb7 = QPushButton() self.pb7.setFlat(True) self.pb7.setIcon(QIcon(nImg7)) self.pb7.setMaximumHeight(30) self.pb7.setMaximumWidth(30) hbo = QHBoxLayout() hbo.addStretch() hbo.addWidget(self.pb1) hbo.addWidget(self.pb3) hbo.addWidget(self.pb2) hbo.addWidget(self.pb7) vbo = QVBoxLayout() vbo.addWidget(self.tree) vbo.addLayout(hbo) self.l1 = QLabel("Name") self.le1 = QLineEdit() self.le1.setObjectName("name") vals1 = Valid().fullNum() self.le1.setValidator(vals1) self.le1.setPlaceholderText("Lowercase max 25 letters") self.fromLbl = QLabel("Starts") self.toLbl = QLabel("Ends") self.fromData = QDateEdit() self.toData = QDateEdit() currentDate = QDate() self.fromData.setDate(currentDate.currentDate()) self.fromData.setCalendarPopup(True) self.toData.setDate(currentDate.currentDate()) self.toData.setCalendarPopup(True) FormLayout = QFormLayout() FormLayout.addRow(self.l1, self.le1) FormLayout.addRow(self.fromLbl, self.fromData) FormLayout.addRow(self.toLbl, self.toData) Hlayout1 = QHBoxLayout() Hlayout1.addStretch() Hlayout1.addWidget(self.pb6) Hlayout1.addWidget(self.pb5) Hlayout1.addWidget(self.pb4) Hlayout1.addWidget(self.pb) Vlayout1 = QVBoxLayout() Vlayout1.addLayout(FormLayout) Vlayout1.addLayout(Hlayout1) self.groupBox1.setLayout(vbo) self.groupBox2.setLayout(Vlayout1) self.groupBox2.hide() self.connect(self.pb, SIGNAL("clicked()"), lambda: self.button_add()) #add self.connect(self.pb1, SIGNAL("clicked()"), lambda: self.button_close()) #close self.connect(self.pb2, SIGNAL("clicked()"), lambda: self.button_edit()) #edit self.connect(self.pb3, SIGNAL("clicked()"), lambda: self.button_delete()) #delete self.connect(self.pb4, SIGNAL("clicked()"), lambda: self.button_save()) #save self.connect(self.pb5, SIGNAL("clicked()"), lambda: self.button_reset()) #reset self.pb4.hide() self.pb7.hide() grid = QGridLayout() grid.addWidget(self.groupBox1, 0, 0) grid.addWidget(self.groupBox2, 1, 0) self.setLayout(grid) self.setStyleSheet(stylesheet) self.setWindowIcon(QIcon(self.titleIcon)) self.setWindowTitle(self.pagetitle) def makeTree(self): self.tree.clear() arr = Db().selectn('session', '', 5) self.hold_data = {} self.hold_mdata = {} self.hold_data_add = {} self.hold_data_add_item = {} current = time.time() if self.titleSub and self.titleSub > 0: if arr and len(arr) > 0: for val in arr: ch = Valid().pullData('terms', '', {'sessionID': val['id']}) child = QTreeWidgetItem(self.tree) child.setIcon(0, QIcon('icons.cfolder.png')) try: ts = int(float(val['start_date'])) except: ts = int(current) ts = datetime.utcfromtimestamp(ts).strftime('%d-%m-%Y') try: ts1 = int(float(val['end_date'])) except: ts1 = int(current) ts1 = datetime.utcfromtimestamp(ts1).strftime('%d-%m-%Y') child.setText( 0, str(val['name']).upper() + " - " + ts + " " + ts1) self.hold_mdata[val['id']] = child for va in ch: child1 = QTreeWidgetItem(child) child1.setFlags(child1.flags() | Qt.ItemIsUserCheckable) try: ts2 = int(float(va['start_date'])) except: ts2 = int(current) ts2 = datetime.utcfromtimestamp(ts2).strftime( '%d-%m-%Y') try: ts3 = int(float(va['end_date'])) except: ts3 = int(current) ts3 = datetime.utcfromtimestamp(ts3).strftime( '%d-%m-%Y') child1.setText( 0, str(va['name']).upper() + " " + ts2 + " " + ts3) self.hold_data[va['id']] = child1 if (va['active'] == 1): child1.setCheckState(0, Qt.Checked) else: child1.setCheckState(0, Qt.Unchecked) child1 = QTreeWidgetItem(child) child1.setFlags(child1.flags() | Qt.ItemIsUserCheckable) child1.setText(0, 'Add New Term') self.hold_data_add_item[val['id']] = child1 else: if arr and len(arr) > 0: for val in arr: child = QTreeWidgetItem(self.tree) child.setFlags(child.flags() | Qt.ItemIsUserCheckable) child.setText(0, str(val['name']).upper()) child.setText(1, str(val['abbrv']).upper()) self.hold_data[val['id']] = child if (val['active'] == 0): child.setCheckState(0, Qt.Checked) else: child.setCheckState(0, Qt.Unchecked) child = QTreeWidgetItem(self.tree) child.setFlags(child.flags() | Qt.ItemIsUserCheckable) child.setText(0, 'Add New Session') self.hold_data_add['addnew'] = child def getChecked(self, a): arr_hold = [] g = Db() for i in self.hold_data: if self.hold_data[i].checkState(0) == Qt.Checked: arr_hold.append(i) self.hold_data[i].setCheckState(0, Qt.Checked) g.update('terms', {'active': 0}, {'active': 1}) g.update('terms', {'active': 1}, {'id': i}) tt = g.selectn('terms', '', 1, {'id': i}) g.update('session', {'active': 0}, {'active': 1}) g.update('session', {'active': 1}, {'id': tt['sessionID']}) g.selectn('session', '', 1, {'id': tt['sessionID']}) else: self.hold_data[i].setCheckState(0, Qt.Unchecked) self.reloadTerm() def reloadTerm(self): session = self.par.activeTerm() activeTerm = str(session[1]) + ' SESSION ' + str(session[3]) + ' TERM' self.par.majorSession = session[2] self.par.lbl.setText(activeTerm) def getSelected(self): r = False self.sessionMain = False for i in self.hold_mdata: if self.hold_mdata[i].isSelected(): r = i if r and r > 0: self.groupBox2.show() self.sessionMain = True return r else: for i in self.hold_data: if self.hold_data[i].isSelected(): r = i if r and r > 0: self.sessionMain = False self.groupBox2.show() return r else: self.groupBox2.hide() def getSession(self): self.sessionID = None for i in self.hold_data_session: if self.hold_data_session[i].isSelected(): r = i if r and r > 0: self.sessionID = r def getSelection(self): self.le1.clear() currentDate = QDate() self.fromData.setDate(currentDate.currentDate()) self.toData.setDate(currentDate.currentDate()) self.sessionMain = False if self.hold_data_add['addnew'].isSelected(): self.groupBox2.setTitle('Add New') self.groupBox2.show() self.sessionMain = True self.sessionID = False else: self.sessionMain = False r = None for i in self.hold_data_add_item: if self.hold_data_add_item[i].isSelected(): r = i if r: g = Db() v = g.selectn('session', '', 1, {'id': r}) vname = str(v['name']).upper() + ' Session' self.groupBox2.setTitle('ADD ' + str(vname) + ' Term') self.sessionID = r self.groupBox2.show() else: self.groupBox2.setTitle('Add') self.sessionID = False self.groupBox2.hide() def setActive(self): g = Db() for i in self.hold_data: if self.hold_data[i].checkState(0) == Qt.Checked: g.update('datas', {'active': 0}, {'id': i}) else: g.update('datas', {'active': 1}, {'id': i}) def button_add(self): s1 = self.le1.text() _datef = self.fromData.date().toPyDate() _datef = time.mktime(_datef.timetuple()) _datee = self.toData.date().toPyDate() _datee = time.mktime(_datee.timetuple()) g = Db() if self.sessionID and self.sessionID > 0: try: if (len(s1) > 0): y = { 'name': s1.lower(), 'start_date': _datef, 'sessionID': self.sessionID, 'end_date': _datee, 'active': 0 } z = g.insert('terms', y) if z and z > 0: g.createClass(z) g.createSubject(z) g.createFee(z) g.createPay(z) g.createResult(z) g.createAffective(z) g.createPsychomoto(z) self.makeTree() self.button_reset() self.par.menuSession() self.par.dropdownSession() else: pass except: pass else: try: if (len(s1) > 0): y = { 'name': s1.lower(), 'start_date': _datef, 'end_date': _datee, 'active': 0 } z = g.insert('session', y) if z and z > 0: g.createExpenses(z) g.createStores(z) g.createAwards(z) g.createConducts(z) g.createMails(z) g.createMedicals(z) self.makeTree() self.button_reset() self.par.menuSession() self.par.dropdownSession() else: pass except: pass def button_save(self): row = self.editrow s1 = self.le1.text() _datef = self.fromData.date().toPyDate() _datef = time.mktime(_datef.timetuple()) _datee = self.toData.date().toPyDate() _datee = time.mktime(_datee.timetuple()) g = Db() if (len(s1) > 0) and row and row > 0: if self.sessionID and self.sessionID > 0: try: if (len(s1) > 0): y = { 'name': s1.lower(), 'start_date': _datef, 'sessionID': self.sessionID, 'end_date': _datee, 'active': 0 } k = {'id': row} g.update('terms', y, k) z = row if z and z > 0: g.createClass(z) g.createSubject(z) g.createFee(z) g.createPay(z) g.createResult(z) g.createAffective(z) g.createPsychomoto(z) self.makeTree() self.button_reset() self.par.menuSession() self.par.dropdownSession() else: pass except: pass else: try: if (len(s1) > 0): y = { 'name': s1.lower(), 'start_date': _datef, 'end_date': _datee, 'active': 0 } k = {'id': row} g.update('session', y, k) z = row if z and z > 0: g.createExpenses(z) g.createStores(z) g.createAwards(z) g.createConducts(z) g.createMails(z) g.createMedicals(z) self.makeTree() self.button_reset() self.par.menuSession() self.par.dropdownSession() else: pass except: pass def button_delete(self): row = self.getSelected() g = Db() try: if row and row > 0: y = {'abbrv': '', 'active': 2} z = {'id': row} g.update('datas', y, z) self.makeTree() else: pass except: pass def button_reset(self): self.le1.clear() currentDate = QDate() self.fromData.setDate(currentDate.currentDate()) self.toData.setDate(currentDate.currentDate()) self.groupBox2.setTitle('Add') self.groupBox2.hide() self.pb.show() self.pb4.hide() def button_edit(self): row = self.getSelected() currentDate = QDate() if row: self.editrow = row g = Db() if self.sessionMain: data = g.selectn('session', '', 1, {'id': row}) data_name = str(data['name']) self.groupBox2.setTitle('Edit') self.sessionID = False else: data = g.selectn('terms', '', 1, {'id': row}) data_sess = g.selectn('session', '', 1, {'id': data['sessionID']}) data_name = str(data['name']) self.sessionID = data['sessionID'] self.groupBox2.setTitle('Edit ' + str(data_sess['name'])) try: self.le1.setText(data_name) except: self.le1.setText('') try: self.fromData.setDate(data['start_date']) except: self.fromData.setDate(currentDate.currentDate()) try: self.toData.setDate(data['end_date']) except: self.toData.setDate(currentDate.currentDate()) self.pb.hide() self.pb4.show() def button_close(self): self.close()
class EditorDialog(KPageDialog): """A dialog to edit properties of a session. You can subclass this to add more settings to a session config dialog. Add more pages in the __init__() method, and inherit the validate() method to check the input if necessary. Implement the load and save methods to load and save the settings. """ def __init__(self, manager): super(EditorDialog, self).__init__(manager.mainwin) self.mainwin = manager.mainwin self.sm = manager self.setButtons(KDialog.ButtonCode( KDialog.Help | KDialog.Ok | KDialog.Cancel)) self.setFaceType(KPageDialog.List) self.setHelp("sessions") # First page with name and auto-save option page = QWidget(self) item = self.firstPage = self.addPage(page, i18n("Session")) item.setHeader(i18n("Properties of this session")) item.setIcon(KIcon("configure")) layout = QGridLayout(page) l = QLabel(i18n("Name:")) self.name = QLineEdit() l.setBuddy(self.name) layout.addWidget(l, 0, 0) layout.addWidget(self.name, 0, 1) self.autosave = QCheckBox(i18n( "Always save the list of documents in this session")) layout.addWidget(self.autosave, 1, 1) l = QLabel(i18n("Base directory:")) self.basedir = KUrlRequester() self.basedir.setMode(KFile.Mode( KFile.Directory | KFile.ExistingOnly | KFile.LocalOnly)) l.setBuddy(self.basedir) layout.addWidget(l, 2, 0) layout.addWidget(self.basedir, 2, 1) def edit(self, name=None): """Edit the named or new (if not given) session.""" # load the session self._originalName = name if name: self.setCaption(i18n("Edit session: %1", name)) self.name.setText(name) conf = self.sm.config(name) self.autosave.setChecked(conf.readEntry("autosave", True)) self.basedir.setUrl(KUrl(conf.readPathEntry("basedir", ""))) self.loadSessionConfig(conf) else: self.setCaption(i18n("Edit new session")) self.name.clear() self.name.setFocus() self.autosave.setChecked(True) self.basedir.setUrl(KUrl()) self.loadSessionDefaults() self.setCurrentPage(self.firstPage) if self.exec_(): # save name = self.name.text() if self._originalName and name != self._originalName: self.sm.renameSession(self._originalName, name) conf = self.sm.config(name) conf.writeEntry("autosave", self.autosave.isChecked()) conf.writePathEntry("basedir", self.basedir.url().path()) self.saveSessionConfig(conf) return name def done(self, result): if not result or self.validate(): super(EditorDialog, self).done(result) def validate(self): """Checks if the input is acceptable. If this method returns True, the dialog is accepted when OK is clicked. Otherwise a messagebox could be displayed, and the dialog will remain visible. """ # strip off whitespace name = self.name.text().strip() self.name.setText(name) if not name: self.setCurrentPage(self.firstPage) self.name.setFocus() KMessageBox.error(self, i18n("Please enter a session name.")) if self._originalName: self.name.setText(self._originalName) return False if name == 'none': self.setCurrentPage(self.firstPage) self.name.setFocus() KMessageBox.error(self, i18n( "Please do not use the name '%1'.", "none")) return False if '&' in name: self.setCurrentPage(self.firstPage) self.name.setFocus() KMessageBox.error(self, i18n( "Please do not use the ampersand (&) character " "in a session name.")) return False if self._originalName != name and name in self.sm.names(): self.setCurrentPage(self.firstPage) self.name.setFocus() if KMessageBox.warningContinueCancel(self, i18n( "Another session with the name %1 exists already.\n\n" "Do you want to overwrite it?", name), None, KStandardGuiItem.overwrite(), KStandardGuiItem.cancel(), "session_overwrite") == KMessageBox.Cancel: return False return True def loadSessionDefaults(self): """Implement to set defaults for your new session.""" pass def loadSessionConfig(self, conf): """Implement to load settings from the config group for this session.""" pass def saveSessionConfig(self, conf): """Implement to save settings to the config group for this session.""" pass
class NotificationWidget(QWidget): """Widget for notification phone numbers""" def __init__(self, name, default, parent=None): """ Initialise layout. Arguments: name - Name of the widget default - Default value for the widget parent - Parent widget Returns: None """ super(NotificationWidget, self).__init__(parent) # Global content self.name = name self.default = default if self.default == 'choose': self.edit = QComboBox(self) else: self.edit = QLineEdit(self.name, self) self.edit.setReadOnly(True) self.check_box = QCheckBox(self.name, self) # Event self.check_box.stateChanged.connect(self._change_state) # Layout layout = QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.check_box) layout.addWidget(self.edit) self.edit.setEnabled(False) # Default if self.default == 'choose': pass else: self.edit.setText(default) # Object name self.edit.setObjectName('noti_edit') self.check_box.setObjectName('noti_check') self.exceptions = [] @pyqtSlot() def _change_state(self): """ Change enable state of the edit Arguments: None Returns: None """ self.edit.setEnabled(self.check_box.isChecked()) def add_exceptions(self, name): """ Add a person to the exception list and dont send notification anymore. Arguments: name - Name of the person Returns: None """ self.exceptions.append(name) def update_combo_email(self, users): """ Update the combo boxes. Arguments: users - User dictionary Returns: None """ if self.default == 'choose': items = [ '@ {0}'.format(key) for key in users if '@ {0}'.format(key) not in self.exceptions ] self.edit.addItems(sorted(items)) def update_combo_telegram(self, users): """ Update the combo boxes. Arguments: users - User dictionary Returns: None """ if self.default == 'choose': items = [ 'T {0}'.format(key) for key in users if 'T {0}'.format(key) not in self.exceptions ] self.edit.addItems(sorted(items)) def clear_combo(self): """ Remove all users from the combo box. Arguments: None Returns: None """ if self.default == 'choose': self.edit.clear() def get_settings(self): """ Get text of the currently selected combo item. Arguments: None Returns: Settings dictionary """ settings = {} if self.default == 'choose': settings[self.name] = '{0}\t{1}'.format(self.edit.currentText(), self.check_box.isChecked()) else: settings[self.name] = '{0}\t{1}'.format(self.edit.text(), self.check_box.isChecked()) return settings def set_settings(self, name, state): """ Set currently selected combo item in text. Arguments: name - Name of the person that should be currently selected. state - State of the person (True/False;Enables/Disables) Returns: None """ self.check_box.setChecked(bool(state == 'True')) if self.default == 'choose': index = self.edit.findText(name) self.edit.setCurrentIndex(index) else: self.edit.setText(name)
class TplRow(QWidget): def __init__(self, parent = None, _id = 0): super(TplRow, self).__init__(parent) self.id = _id self.setLayout(QHBoxLayout()) self.idLabel = QLabel(self) self.beginEdit = QDateTimeEdit(self) self.beginEdit.setCalendarPopup(True) self.endEdit = QDateTimeEdit(self) self.endEdit.setCalendarPopup(True) self.timeDiff = ClickLabel(self) self.descriptionEdit = QLineEdit(self) self.noteEdit = QLineEdit(self) self.delButton = QPushButton(self) self.delButton.setText('X') self.layout().addWidget(self.idLabel) self.layout().addWidget(self.beginEdit) self.layout().addWidget(self.endEdit) self.layout().addWidget(self.timeDiff) self.layout().addWidget(self.descriptionEdit) self.layout().addWidget(self.noteEdit) self.layout().addWidget(self.delButton) self.layout().setContentsMargins(2,2,2,2) self.connect(self.descriptionEdit, SIGNAL('editingFinished ()'), self.notify) self.connect(self.noteEdit, SIGNAL('editingFinished ()'), self.notify) self.connect(self.beginEdit, SIGNAL('editingFinished ()'), self.notify) self.connect(self.endEdit, SIGNAL('editingFinished ()'), self.notify) self.connect(self.delButton, SIGNAL('clicked()'), self.delete) self.connect(self.timeDiff, SIGNAL('clicked()'), self.onTimeDiff) def set(self, tpl): self.idLabel.setText(str(tpl[0])) self.beginEdit.setDateTime(QDateTime.fromTime_t(tpl[1])) self.endEdit.setDateTime(QDateTime.fromTime_t(tpl[2])) self.timeDiff.setText( self.mkDiff( tpl[1], tpl[2] ) ) self.descriptionEdit.setText(str(tpl[3])) self.noteEdit.setText(str(tpl[4])) def get(self): tpl = [] tpl.append(int(self.idLabel.text())) tpl.append(self.beginEdit.dateTime().toTime_t()) tpl.append(self.endEdit.dateTime().toTime_t()) tpl.append(self.descriptionEdit.text()) tpl.append(self.noteEdit.text()) return tpl def clear(self): self.beginEdit.clear() self.endEdit.clear() self.timeDiff.clear() self.descriptionEdit.clear() self.noteEdit.clear() self.idLabel.clear() def mkDiff(self, begin, end): return '%4d' % ceil( float( end - begin ) / 60 ) @pyqtSlot() def onTimeDiff(self): self.parent().parent().parent().statusBar.showMessage( '%s copied to clipboard.' % self.timeDiff.text() ) self.parent().clipboard.setText( str(self.timeDiff.text()).strip() ) @pyqtSlot() def delete(self): if self.idLabel.text(): if QMessageBox.question(self, 'delete ?', 'really delete id %s ?' % self.idLabel.text(), QMessageBox.Yes|QMessageBox.No, QMessageBox.No) == QMessageBox.Yes: self.emit(SIGNAL('del(int)'), self.id) @pyqtSlot() def notify(self): if self.idLabel.text(): self.timeDiff.setText( self.mkDiff( self.beginEdit.dateTime().toTime_t(), self.endEdit.dateTime().toTime_t() ) ) self.emit(SIGNAL('valueChanged(int)'), self.id)
class ImageTab(QWidget): def __init__(self, parent): super(ImageTab, self).__init__(parent) self.parent = parent self.name = 'Images' self.formats = config.image_formats self.extra_img = config.image_extra_formats validator = QRegExpValidator(QRegExp(r'^[1-9]\d*'), self) converttoQL = QLabel(self.tr('Convert to:')) self.extQCB = QComboBox() self.extQCB.addItems(self.formats) commandQL = QLabel(self.tr('Extra options:')) self.commandQLE = QLineEdit() hlayout2 = utils.add_to_layout('h', converttoQL, self.extQCB, commandQL, self.commandQLE) sizeQL = QLabel('<html><p align="center">' + self.tr('Image Size:') + '</p></html>') self.widthQLE = utils.create_LineEdit((50, 16777215), validator, 4) self.heightQLE = utils.create_LineEdit((50, 16777215), validator, 4) label = QLabel('<html><p align="center">x</p></html>') label.setMaximumWidth(25) hlayout1 = utils.add_to_layout('h', self.widthQLE, label, self.heightQLE) sizelayout = utils.add_to_layout('v', sizeQL, hlayout1) self.imgaspectQChB = QCheckBox(self.tr("Maintain aspect ratio")) self.autocropQChB = QCheckBox(self.tr("Auto-crop")) vlayout = utils.add_to_layout('v', self.imgaspectQChB, self.autocropQChB) rotateQL = QLabel("<html><div align='center'>" + self.tr("Rotate") + ":</div><br>(" + self.tr("degrees - clockwise") + ")</html>") self.rotateQLE = utils.create_LineEdit((100, 16777215), validator, 3) self.vflipQChB = QCheckBox(self.tr('Vertical flip')) self.hflipQChB = QCheckBox(self.tr('Horizontal flip')) vlayout2 = utils.add_to_layout('v', self.vflipQChB, self.hflipQChB) hlayout3 = utils.add_to_layout('h', sizelayout, vlayout, rotateQL, self.rotateQLE, vlayout2, None) final_layout = utils.add_to_layout('v', hlayout2, hlayout3) self.setLayout(final_layout) def clear(self): """Clear self.widthQLE and self.heightQLE.""" self.widthQLE.clear() self.heightQLE.clear() self.commandQLE.clear() self.rotateQLE.clear() self.imgaspectQChB.setChecked(False) self.autocropQChB.setChecked(False) self.vflipQChB.setChecked(False) self.hflipQChB.setChecked(False) def fill_extension_combobox(self, extraformats): extraformats = [i for i in extraformats.split("\n") ] if extraformats else [] self.extQCB.clear() self.extQCB.addItems(sorted(self.formats + extraformats)) def ok_to_continue(self): """ Check if everything is ok with imagetab to continue conversion. Check if: - ImageMagick is missing. - Either none or both size lineEdits are active at a time. Return True if all tests pass, else False. """ width = self.widthQLE.text() height = self.heightQLE.text() if not self.parent.imagemagick: QMessageBox.warning( self, 'FF Multi Converter - ' + self.tr('Error!'), self. tr('ImageMagick is not installed.\nYou will ' 'not be able to convert image files until you install it.')) return False if (width and not height) or (not width and height): QMessageBox.warning(self, 'FF Multi Converter - ' + self.tr('Error!'), self.tr('The size LineEdit may not be empty.')) if width and not height: self.heightQLE.setFocus() else: self.widthQLE.setFocus() return False return True def set_default_command(self): """Set the default value to self.commandQLE.""" self.clear() self.commandQLE.setText(self.parent.default_command_image)
class ShowPresets(QDialog): def __init__(self, parent=None): super(ShowPresets, self).__init__(parent) self.original_presets_file = '/usr/share/ffmulticonverter/presets.xml' self.config_folder = os.getenv('HOME') + '/.config/ffmulticonverter/' self.current_presets_file = self.config_folder + 'presets.xml' self.presListWidget = QListWidget() labelLabel = QLabel(self.tr('Preset label')) self.labelLineEdit = QLineEdit() self.labelLineEdit.setReadOnly(True) commandLabel = QLabel(self.tr('Preset command line parameters')) self.commandLineEdit = QLineEdit() self.commandLineEdit.setReadOnly(True) extLabel = QLabel(self.tr('Output file extension')) self.extLineEdit = QLineEdit() self.extLineEdit.setReadOnly(True) addButton = QPushButton(self.tr('Add')) self.deleteButton = QPushButton(self.tr('Delete')) self.delete_allButton = QPushButton(self.tr('Delete all')) self.editButton = QPushButton(self.tr('Edit')) okButton = QPushButton(self.tr('OK')) okButton.setDefault(True) spc1 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) spc2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) grid = pyqttools.add_to_grid(QGridLayout(), [self.delete_allButton, addButton, spc1, None], [self.deleteButton, self.editButton, spc2, okButton]) final_layout = pyqttools.add_to_layout(QVBoxLayout(), self.presListWidget, labelLabel, self.labelLineEdit, commandLabel, self.commandLineEdit, extLabel, self.extLineEdit, grid) self.setLayout(final_layout) okButton.clicked.connect(self.accept) self.presListWidget.currentRowChanged.connect(self.show_preset) addButton.clicked.connect(self.add_preset) self.deleteButton.clicked.connect(self.delete_preset) self.delete_allButton.clicked.connect(self.delete_all_presets) self.editButton.clicked.connect(self.edit_preset) self.resize(410, 410) self.setWindowTitle(self.tr('Edit Presets')) QTimer.singleShot(0, self.load_xml) QTimer.singleShot(0, self.fill_presListWidget) def load_xml(self): """Load xml tree and set xml root.""" try: self.tree = etree.parse(self.current_presets_file) except (etree.ParseError, IOError): try: self.tree = etree.parse(self.original_presets_file) except IOError: # when program is not installed self.tree = etree.parse('../share/presets.xml') if not os.path.exists(self.config_folder): os.makedirs(self.config_folder) self.root = self.tree.getroot() def set_buttons_clear_lineEdits(self): """Enable or disable button's and clear lineEdits.""" enable = bool(self.presListWidget) self.editButton.setEnabled(enable) self.deleteButton.setEnabled(enable) self.delete_allButton.setEnabled(enable) if not enable: self.labelLineEdit.clear() self.commandLineEdit.clear() self.extLineEdit.clear() def fill_presListWidget(self): """Clear self.presListWidget and to it presets' tags.""" self.presListWidget.clear() for i in sorted([y.tag for y in self.root]): elem = self.root.find(i) self.presListWidget.addItem(MyListItem(i, elem)) self.presListWidget.setCurrentRow(0) self.set_buttons_clear_lineEdits() def show_preset(self): """Fill LineEdits with current xml element's values.""" try: xml_elem = self.presListWidget.currentItem().xml_element except AttributeError: return self.labelLineEdit.setText(xml_elem[0].text) self.commandLineEdit.setText(xml_elem[1].text) self.commandLineEdit.home(False) self.extLineEdit.setText(xml_elem[2].text) def add_preset(self): """Open AddorEditPreset() dialog and add a preset xml root.""" dialog = AddorEditPreset(None, False, self) if dialog.exec_(): element = etree.Element(dialog.name_text) label = etree.Element('label') label.text = dialog.label_text command = etree.Element('params') command.text = dialog.command_text ext = etree.Element('extension') ext.text = dialog.ext_text category = etree.Element('category') category.text = 'Scattered' for num, elem in enumerate([label, command, ext, category]): element.insert(num, elem) index = sorted([i.tag for i in self.root] + [dialog.name_text])\ .index(dialog.name_text) self.root.insert(index, element) self.save_tree() self.fill_presListWidget() def delete_preset(self): """ Ask user wether he wants to delete the selected preset. If so, delete the preset from xml root. """ try: xml_elem = self.presListWidget.currentItem().xml_element except AttributeError: return reply = QMessageBox.question(self, 'FF Multi Converter - ' + self.tr( 'Delete Preset'), self.tr('Are you sure that you want to delete ' 'the %1 preset?').arg(xml_elem.tag), QMessageBox.Yes|QMessageBox.Cancel) if reply == QMessageBox.Yes: self.root.remove(xml_elem) self.save_tree() self.fill_presListWidget() def delete_all_presets(self): """ Ask user if he wants to delete all presets. If so, clear xml root. """ reply = QMessageBox.question(self, 'FF Multi Converter - ' + self.tr( 'Delete Preset'), self.tr('Are you sure that you want to delete ' 'all presets?'), QMessageBox.Yes|QMessageBox.Cancel) if reply == QMessageBox.Yes: self.root.clear() self.save_tree() self.fill_presListWidget() def edit_preset(self): """Call the AddorEditPreset() dialog and update xml element's values.""" elem = self.presListWidget.currentItem().xml_element dialog = AddorEditPreset(elem, True) if dialog.exec_(): elem.tag = dialog.name_text elem[0].text = dialog.label_text elem[1].text = dialog.command_text elem[2].text = dialog.ext_text self.save_tree() self.fill_presListWidget() def save_tree(self): """Save xml tree.""" with open(self.current_presets_file, 'w') as _file: try: etree.ElementTree(self.root).write(_file) except: pass def import_presets(self): """Import an xml tree.""" title = 'FF Multi Converter - Import' reply = QMessageBox.question(self, title, self.tr('All current ' 'presets will be deleted.\nAre you sure that you want to ' 'continue?'), QMessageBox.Yes|QMessageBox.Cancel) if reply == QMessageBox.Yes: fname = QFileDialog.getOpenFileName(self, title) if fname: msg = 'Succesful import!' try: self.tree = etree.parse(fname) except: msg = 'Import failed!' else: self.root = self.tree.getroot() self.save_tree() QMessageBox.information(self, title, msg) def export_presets(self): """Export the xml tree.""" fname = QFileDialog.getSaveFileName(self, 'FF Multi Converter - Export presets','.xml') if fname: self.load_xml() with open(fname, 'w') as _file: try: etree.ElementTree(self.root).write(_file) except: pass def reset(self): """Import the default xml tree.""" reply = QMessageBox.question(self, 'FF Multi Converter - ' + self.tr( 'Delete Preset'), self.tr('Are you sure that you want to restore ' 'the default presets?'), QMessageBox.Yes|QMessageBox.Cancel) if reply == QMessageBox.Yes: if os.path.exists(self.current_presets_file): os.remove(self.current_presets_file) def accept(self): """ Save current xml element's values in order to be used from main program and close (accept) dialog. """ self.the_command = None if self.presListWidget: self.the_command = self.presListWidget.currentItem()\ .xml_element[1].text self.the_extension = self.presListWidget.currentItem()\ .xml_element[2].text QDialog.accept(self)
class ExportCSVDialog(QDialog): def __init__(self, parent, nodes, selectedAttributes): #current column QDialog.__init__(self, parent) self.nodes = nodes self.exportPath = os.path.join(os.path.expanduser("~"), "dff.csv") self.attributes = selectedAttributes self.split = False self.dialogLayout = QVBoxLayout() self.setLayout(self.dialogLayout) self.setPathEdit() self.setAttributesSelection() self.setSplitCheckBox() self.setButtons() def setButtons(self): self.dialogButtonsLayout = QHBoxLayout() self.dialogButtonsBox = QDialogButtonBox() self.dialogButtonsBox.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.connect(self.dialogButtonsBox, SIGNAL("accepted()"), self.accept) self.connect(self.dialogButtonsBox, SIGNAL("rejected()"), self.reject) self.dialogButtonsLayout.addWidget(self.dialogButtonsBox) self.dialogLayout.addLayout(self.dialogButtonsLayout) def setSplitCheckBox(self): self.splitCheckBox = QCheckBox("Split file every 65536 lines") self.connect(self.splitCheckBox, SIGNAL("stateChanged(int)"), self.setSplit) self.dialogLayout.addWidget(self.splitCheckBox) def setSplit(self, state): if state: self.split = True else: self.split = False def setAttributesSelection(self): self.attributesSelectionLayout = QHBoxLayout() self.attributesSelectionLabel = QLabel(self.tr("Choose CSV column :")) attributesSelectionButton = QPushButton("...") self.attributesSelectionLayout.addWidget(self.attributesSelectionLabel) self.attributesSelectionLayout.addWidget(attributesSelectionButton) self.dialogLayout.addLayout(self.attributesSelectionLayout) self.connect(attributesSelectionButton, SIGNAL("clicked()"), self.askColumn) def askColumn(self): #if timeline node selectAttributesWizard = SelectAttributesWizard( self.parent().model(), self.attributes, self.parent().model().defaultAttributes() ) # need model by default for list check and defalt atributs, 'current selected file as steel a meaning' rather always parse list ? , use attribute selector ? if selectAttributesWizard.exec_( ) == 1: #get choosen attribtes iand set to list # if iret == 1: self.attributes = selectAttributesWizard.getSelectedAttributes() def setPathEdit(self): self.exportPathLayout = QHBoxLayout() self.exportPathLabel = QLabel(self.tr("Path of csv file:")) self.exportPathLineEdit = QLineEdit(self.exportPath) self.exportPathLineEdit.setReadOnly(True) exportPathButton = QPushButton("...") self.exportPathLayout.addWidget(self.exportPathLabel) self.exportPathLayout.addWidget(self.exportPathLineEdit) self.exportPathLayout.addWidget(exportPathButton) self.dialogLayout.addLayout(self.exportPathLayout) self.connect(exportPathButton, SIGNAL("clicked()"), self.askExportPath) def askExportPath(self): newPath = QFileDialog().getSaveFileName(self, self.tr("CSV path"), self.exportPath) if len(newPath): self.exportPath = unicode(newPath.toUtf8(), 'utf-8') self.exportPathLineEdit.clear() self.exportPathLineEdit.insert(self.exportPath) def accept(self): #XXX thread me self.exportCSV() QDialog.accept(self) #show advancement in widget (next) def exportCSV(self): try: csv = CSV() ##if not self.timeLineButton.isChecked(): csv.exportNodes(self.exportPath, self.nodes, self.attributes, self.split) except Exception as e: msg = QMessageBox(self) msg.setWindowTitle(self.tr("Export to CSV error")) msg.setText(self.tr("An issue occured while exporting to CSV")) msg.setIcon(QMessageBox.Warning) msg.setDetailedText(str(e)) msg.setStandardButtons(QMessageBox.Ok) ret = msg.exec_()
class PasswordEnter(QDialog): def __init__(self, title = '', parent = None, mode = 1): QDialog.__init__(self, parent) self.prnt = parent self.mode = mode self.tr = self.prnt.tr self.Sound = self.prnt.Parent.sound self.Keyring = self.prnt.Keyring self.title = QLabel(self.tr._translate(title)) self.title.setAlignment(Qt.AlignHCenter) self.passwrd = QLineEdit() self.passwrd.setMaxLength(BLOCK_SIZE) self.passwrd.setPlaceholderText(self.tr._translate("Enter Password")) self.passwrd.setEchoMode(QLineEdit.Password) self.passwrd.setToolTip(self.tr._translate("Enter Password")) if self.mode : self.confirm = QLineEdit() self.confirm.setMaxLength(BLOCK_SIZE) self.confirm.setPlaceholderText(self.tr._translate("Confirm Password")) self.confirm.setEchoMode(QLineEdit.Password) self.confirm.setToolTip(self.tr._translate("Confirm it")) self._layout = QVBoxLayout() self._layout.addWidget(self.title) self._layout.addWidget(self.passwrd) if self.mode : self._layout.addWidget(self.confirm) self.ok = QPushButton(QIcon.fromTheme("dialog-ok"), "", self) self.cancel = QPushButton(QIcon.fromTheme("dialog-cancel"), "", self) self.buttonLayout = QHBoxLayout() self.buttonLayout.addWidget(self.ok) self.buttonLayout.addWidget(self.cancel) self._layout.addItem(self.buttonLayout) self.setLayout(self._layout) if self.mode : self.ok.clicked.connect(self.checkCorrectOfPassword) else : self.ok.clicked.connect(self.returnPassword) self.cancel.clicked.connect(self.clearEnterFields) QTimer.singleShot(100, self.moveToTrayIcon) def moveToTrayIcon(self): self.move(self.prnt.Parent.mapToGlobal(self.prnt.Parent.trayIconMenu.pos())) def checkCorrectOfPassword(self): if self.confirm.text() == self.passwrd.text() and \ not self.confirm.text().isEmpty() : self.Keyring.create_Keyring(self.passwrd.text()) self.Sound.Complete.play() QMessageBox.information(self, \ self.tr._translate("Create Keyring"), \ self.tr._translate("Keyring created."), \ 1) self.clearEnterFields() self.prnt.saveData() self.close() else : self.Sound.Attention.play() QMessageBox.information(self, \ self.tr._translate("Create Keyring"), \ self.tr._translate("Passwords mismatch or empty"), \ 1) self.clearEnterFields() def clearEnterFields(self): self.passwrd.clear() if self.mode : self.confirm.clear() def returnPassword(self): if not self.passwrd.text().isEmpty() : self.prnt.Keyring.password = to_unicode(self.passwrd.text()) self.clearEnterFields() self.close() else : self.Sound.Attention.play() QMessageBox.information(self, \ self.tr._translate("Enter Password"), \ self.tr._translate("Passwords empty"), \ 1) def closeEvent(self, ev): ev.ignore() if not self.prnt.Parent.isVisible() : self.prnt.Parent.show() self.prnt.Parent.autoHide(3) if self.prnt.Parent.isMinimized() : self.prnt.Parent.showNormal() self.done(0)
class GroupsModify(PyDialog): """ +--------------------------+ | Groups : Modify | +--------------------------+ | | | Name xxx Default | | Coords xxx Default | | Elements xxx Default | | Color xxx Default | | Add xxx Add | | Remove xxx Remove | | | | Set OK Cancel | +--------------------------+ """ def __init__(self, data, win_parent=None, group_active='main'): self.win_parent = win_parent PyDialog.__init__(self, data, win_parent) #QDialog.__init__(self, win_parent) #self.win_parent = win_parent #self.out_data = data #print(data) self.keys = [group.name for key, group in sorted(iteritems(data))] self.active_key = self.keys.index(group_active) group_obj = data[self.active_key] name = group_obj.name self.imain = 0 self.nrows = len(self.keys) self._default_name = group_obj.name self._default_elements = group_obj.element_str self.elements_pound = group_obj.elements_pound self.table = QListWidget(parent=None) self.table.clear() self.table.addItems(self.keys) # table self.setWindowTitle('Groups: Modify') self.create_widgets() self.create_layout() self.set_connections() self.on_set_as_main() #self.show() def create_widgets(self): # Name self.name = QLabel("Name:") self.name_set = QPushButton("Set") self.name_edit = QLineEdit(str(self._default_name).strip()) self.name_button = QPushButton("Default") # elements self.elements = QLabel("Element IDs:") self.elements_edit = QLineEdit(str(self._default_elements).strip()) self.elements_button = QPushButton("Default") # add self.add = QLabel("Add:") self.add_edit = QLineEdit(str('')) self.add_button = QPushButton("Add") # remove self.remove = QLabel("Remove:") self.remove_edit = QLineEdit(str('')) self.remove_button = QPushButton("Remove") # applies a unique implicitly self.eids = parse_patran_syntax(str(self._default_elements), pound=self.elements_pound) # closing #self.apply_button = QPushButton("Apply") self.ok_button = QPushButton("Close") #self.cancel_button = QPushButton("Cancel") self.set_as_main_button = QPushButton("Set As Main") self.create_group_button = QPushButton('Create New Group') self.delete_group_button = QPushButton('Delete Group') self.name.setEnabled(False) self.name_set.setEnabled(False) self.name_edit.setEnabled(False) self.name_button.setEnabled(False) self.elements.setEnabled(False) self.elements_button.setEnabled(False) self.elements_edit.setEnabled(False) self.add.setEnabled(False) self.add_button.setEnabled(False) self.add_edit.setEnabled(False) self.remove.setEnabled(False) self.remove_button.setEnabled(False) self.remove_edit.setEnabled(False) self.delete_group_button.setEnabled(False) #self.apply_button.setEnabled(False) #self.ok_button.setEnabled(False) def create_layout(self): grid = QGridLayout() grid.addWidget(self.name, 0, 0) grid.addWidget(self.name_edit, 0, 1) grid.addWidget(self.name_set, 0, 2) grid.addWidget(self.name_button, 0, 3) grid.addWidget(self.elements, 2, 0) grid.addWidget(self.elements_edit, 2, 1) grid.addWidget(self.elements_button, 2, 2) grid.addWidget(self.add, 4, 0) grid.addWidget(self.add_edit, 4, 1) grid.addWidget(self.add_button, 4, 2) grid.addWidget(self.remove, 5, 0) grid.addWidget(self.remove_edit, 5, 1) grid.addWidget(self.remove_button, 5, 2) ok_cancel_box = QHBoxLayout() #ok_cancel_box.addWidget(self.apply_button) ok_cancel_box.addWidget(self.ok_button) #ok_cancel_box.addWidget(self.cancel_button) main_create_delete = QHBoxLayout() main_create_delete.addWidget(self.set_as_main_button) main_create_delete.addWidget(self.create_group_button) main_create_delete.addWidget(self.delete_group_button) vbox = QVBoxLayout() vbox.addWidget(self.table) vbox.addLayout(grid) vbox.addLayout(main_create_delete) vbox.addStretch() vbox.addLayout(ok_cancel_box) self.setLayout(vbox) def on_set_name(self): name = str(self.name_edit.text()).strip() if name not in self.keys: self.name_edit.setStyleSheet("QLineEdit{background: white;}") group = self.out_data[self.active_key] group.name = name self.keys[self.active_key] = name self.recreate_table() elif name != self.keys[self.active_key]: self.name_edit.setStyleSheet("QLineEdit{background: red;}") elif name == self.keys[self.active_key]: self.name_edit.setStyleSheet("QLineEdit{background: white;}") def set_connections(self): self.name_set.clicked.connect(self.on_set_name) self.name_button.clicked.connect(self.on_default_name) self.elements_button.clicked.connect(self.on_default_elements) self.add_button.clicked.connect(self.on_add) self.remove_button.clicked.connect(self.on_remove) self.table.itemClicked.connect(self.on_update_active_key) self.ok_button.clicked.connect(self.on_ok) self.set_as_main_button.clicked.connect(self.on_set_as_main) self.create_group_button.clicked.connect(self.on_create_group) self.delete_group_button.clicked.connect(self.on_delete_group) def on_create_group(self): irow = self.nrows new_key = 'Group %s' % irow while new_key in self.keys: irow += 1 new_key = 'Group %s' % irow irow = self.nrows self.keys.append(new_key) group = Group(new_key, element_str='', elements_pound=self.elements_pound, editable=True) self.out_data[irow] = group self.table.reset() self.table.addItems(self.keys) self.nrows += 1 #---------------------------------- # update internal parameters #self.out_data = items if self.imain > self.active_key: self.imain += 1 #make the new group the default self.active_key = self.nrows - 1 self.keys = [ group.name for key, group in sorted(iteritems(self.out_data)) ] self.recreate_table() def recreate_table(self): # update gui self.table.clear() self.table.addItems(self.keys) item = self.table.item(self.imain) bold = QtGui.QFont() bold.setBold(True) bold.setItalic(True) item.setFont(bold) self.table.update() # update key name = self.keys[self.active_key] self._update_active_key_by_name(name) def on_delete_group(self): if self.active_key == 0: return #self.deleted_groups.add(self.imain) items = {} j = 0 for i, key in sorted(iteritems(self.out_data)): if i != self.active_key: items[j] = key j += 1 # update internal parameters self.out_data = items if self.imain >= self.active_key: self.imain = max(0, self.imain - 1) self.active_key = max(0, self.active_key - 1) self.nrows -= 1 self.keys = [group.name for key, group in sorted(iteritems(items))] self.recreate_table() # update key name = self.keys[self.active_key] self._update_active_key_by_name(name) def on_set_as_main(self): bold = QtGui.QFont() bold.setBold(True) bold.setItalic(True) normal = QtGui.QFont() normal.setBold(False) normal.setItalic(False) obj = self.table.item(self.imain) obj.setFont(normal) self.imain = self.active_key obj = self.table.item(self.imain) obj.setFont(bold) group = self.out_data[self.imain] self._default_elements = group.element_str self._default_name = group.name if self.win_parent is not None: # we're not testing the menu self.win_parent.post_group(group) def closeEvent(self, event): self.out_data['close'] = True event.accept() def on_add(self): eids, is_valid = self.check_patran_syntax(self.add_edit, pound=self.elements_pound) #adict, is_valid = self.check_patran_syntax_dict(self.add_edit) if not is_valid: #self.add_edit.setStyleSheet("QLineEdit{background: red;}") return self.eids = unique(hstack([self.eids, eids])) #self.eids = _add(adict, ['e', 'elem', 'element'], self.eids) #self.cids = _add(adict, ['c', 'cid', 'coord'], self.cids) self._apply_cids_eids() self.add_edit.clear() self.add_edit.setStyleSheet("QLineEdit{background: white;}") def _apply_cids_eids(self): #ctext = _get_collapsed_text(self.cids) etext = _get_collapsed_text(self.eids) #self.coords_edit.setText(str(ctext.lstrip())) self.elements_edit.setText(str(etext.lstrip())) self.out_data[self.active_key].element_ids = self.eids def on_remove(self): eids, is_valid = self.check_patran_syntax(self.remove_edit) #adict, is_valid = self.check_patran_syntax_dict(self.remove_edit) if not is_valid: #self.remove_edit.setStyleSheet("QLineEdit{background: red;}") return #self.eids = _remove(adict, ['e', 'elem', 'element'], self.eids) #self.cids = _remove(adict, ['c', 'cid', 'coord'], self.cids) self.eids = setdiff1d(self.eids, eids) self._apply_cids_eids() self.remove_edit.clear() self.remove_edit.setStyleSheet("QLineEdit{background: white;}") def on_default_name(self): name = str(self._default_name) self.name_edit.setText(name) self.name_edit.setStyleSheet("QLineEdit{background: white;}") def on_default_elements(self): element_str = str(self._default_elements) self.elements_edit.setText(element_str) self.elements_edit.setStyleSheet("QLineEdit{background: white;}") group = self.out_data[self.active_key] group.element_str = element_str @staticmethod def check_name(cell): text = str(cell.text()).strip() if len(text): cell.setStyleSheet("QLineEdit{background: white;}") return text, True else: cell.setStyleSheet("QLineEdit{background: red;}") return None, False if self._default_name != text: if self._default_name in self.out_data: cell.setStyleSheet("QLineEdit{background: white;}") return text, True else: cell.setStyleSheet("QLineEdit{background: red;}") return None, False def on_validate(self): name, flag0 = self.check_name(self.name_edit) elements, flag1 = self.check_patran_syntax(self.elements_edit, pound=self.elements_pound) #coords_value, flag2 = self.check_patran_syntax(self.coords_edit, #pound=self.coords_pound) if flag0 and flag1: self._default_name = name self._default_elements = self.eids self.out_data['clicked_ok'] = True self.out_data['close'] = True return True return False def on_apply(self, force=False): passed = self.on_validate() if passed or force: self.win_parent.on_modify_group(self.out_data) def on_ok(self): passed = self.on_validate() if passed: self.out_data['close'] = True self.out_data['clicked_ok'] = True self.out_data['clicked_cancel'] = False self.close() #self.destroy() def on_cancel(self): self.out_data['close'] = True self.out_data['clicked_cancel'] = True self.close() def on_update_active_key(self, index): self.update_active_key(index) #str(index.text()) def update_active_key(self, index): #old_obj = self.out_data[self.imain] name = str(index.text()) self._update_active_key_by_name(name) def _update_active_key_by_name(self, name): if name in self.keys: self.active_key = self.keys.index(name) else: # we (hopefully) just removed a row #self.active_key = self.keys[self.active_key] pass self.name_edit.setText(name) obj = self.out_data[self.active_key] self.eids = parse_patran_syntax(obj.element_str, pound=obj.elements_pound) self._default_elements = obj.element_str self._default_name = name self._apply_cids_eids() self.set_as_main_button.setEnabled(True) if name in ['main', 'anti-main']: self.name.setEnabled(False) self.name_set.setEnabled(False) self.name_edit.setEnabled(False) self.name_button.setEnabled(False) self.elements.setEnabled(False) self.elements_button.setEnabled(False) self.elements_edit.setEnabled(False) self.add.setEnabled(False) self.add_button.setEnabled(False) self.add_edit.setEnabled(False) self.remove.setEnabled(False) self.remove_button.setEnabled(False) self.remove_edit.setEnabled(False) self.delete_group_button.setEnabled(False) if name == 'anti-main': self.set_as_main_button.setEnabled(False) #self.apply_button.setEnabled(False) #self.ok_button.setEnabled(False) else: self.name.setEnabled(True) self.name_set.setEnabled(True) self.name_edit.setEnabled(True) self.name_button.setEnabled(True) self.elements.setEnabled(True) self.elements_button.setEnabled(True) self.add.setEnabled(True) self.add_button.setEnabled(True) self.add_edit.setEnabled(True) self.remove.setEnabled(True) self.remove_button.setEnabled(True) self.remove_edit.setEnabled(True) self.delete_group_button.setEnabled(True)
class ShowPresets(QDialog): def __init__(self, parent=None): super(ShowPresets, self).__init__(parent) self.original_presets_file = '/usr/share/ffmulticonverter/presets.xml' self.config_folder = os.getenv('HOME') + '/.config/ffmulticonverter/' self.current_presets_file = self.config_folder + 'presets.xml' self.presListWidget = QListWidget() labelLabel = QLabel(self.tr('Preset label')) self.labelLineEdit = QLineEdit() self.labelLineEdit.setReadOnly(True) commandLabel = QLabel(self.tr('Preset command line parameters')) self.commandLineEdit = QLineEdit() self.commandLineEdit.setReadOnly(True) extLabel = QLabel(self.tr('Output file extension')) self.extLineEdit = QLineEdit() self.extLineEdit.setReadOnly(True) addButton = QPushButton(self.tr('Add')) self.deleteButton = QPushButton(self.tr('Delete')) self.delete_allButton = QPushButton(self.tr('Delete all')) self.editButton = QPushButton(self.tr('Edit')) searchLabel = QLabel(self.tr('Search')) self.searchLineEdit = QLineEdit() okButton = QPushButton(self.tr('OK')) okButton.setDefault(True) spc1 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) spc2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) spc3 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) grid = pyqttools.add_to_grid( QGridLayout(), [self.delete_allButton, addButton, spc1], [self.deleteButton, self.editButton, spc2]) hlayout = pyqttools.add_to_layout(QHBoxLayout(), searchLabel, self.searchLineEdit, None, okButton) final_layout = pyqttools.add_to_layout( QVBoxLayout(), self.presListWidget, labelLabel, self.labelLineEdit, commandLabel, self.commandLineEdit, extLabel, self.extLineEdit, grid, spc3, hlayout) self.setLayout(final_layout) okButton.clicked.connect(self.accept) self.presListWidget.currentRowChanged.connect(self.show_preset) addButton.clicked.connect(self.add_preset) self.deleteButton.clicked.connect(self.delete_preset) self.delete_allButton.clicked.connect(self.delete_all_presets) self.editButton.clicked.connect(self.edit_preset) self.searchLineEdit.textEdited.connect(self.search) del_shortcut = QShortcut(self) del_shortcut.setKey(Qt.Key_Delete) del_shortcut.activated.connect(self.delete_preset) self.resize(430, 480) self.setWindowTitle(self.tr('Edit Presets')) QTimer.singleShot(0, self.load_xml) QTimer.singleShot(0, self.fill_presListWidget) def load_xml(self): """Load xml tree and set xml root.""" try: self.tree = etree.parse(self.current_presets_file) except (etree.ParseError, IOError): try: self.tree = etree.parse(self.original_presets_file) except IOError: # when program is not installed self.tree = etree.parse('../share/presets.xml') if not os.path.exists(self.config_folder): os.makedirs(self.config_folder) self.root = self.tree.getroot() def set_buttons_clear_lineEdits(self): """Enable or disable button's and clear lineEdits.""" enable = bool(self.presListWidget) self.editButton.setEnabled(enable) self.deleteButton.setEnabled(enable) self.delete_allButton.setEnabled(enable) if not enable: self.labelLineEdit.clear() self.commandLineEdit.clear() self.extLineEdit.clear() def fill_presListWidget(self): """Clear self.presListWidget and to it presets' tags.""" self.presListWidget.clear() for i in sorted([y.tag for y in self.root]): elem = self.root.find(i) self.presListWidget.addItem(MyListItem(i, elem)) self.presListWidget.setCurrentRow(0) self.set_buttons_clear_lineEdits() self.searchLineEdit.clear() def show_preset(self): """Fill LineEdits with current xml element's values.""" try: xml_elem = self.presListWidget.currentItem().xml_element except AttributeError: return self.labelLineEdit.setText(xml_elem[0].text) self.commandLineEdit.setText(xml_elem[1].text) self.commandLineEdit.home(False) self.extLineEdit.setText(xml_elem[2].text) def add_preset(self): """Open AddorEditPreset() dialog and add a preset xml root.""" dialog = AddorEditPreset(None, False, self) if dialog.exec_(): element = etree.Element(dialog.name_text) label = etree.Element('label') label.text = dialog.label_text command = etree.Element('params') command.text = dialog.command_text ext = etree.Element('extension') ext.text = dialog.ext_text category = etree.Element('category') category.text = 'Scattered' for num, elem in enumerate([label, command, ext, category]): element.insert(num, elem) index = sorted([i.tag for i in self.root] + [dialog.name_text])\ .index(dialog.name_text) self.root.insert(index, element) self.save_tree() self.fill_presListWidget() def delete_preset(self): """ Ask user wether he wants to delete the selected preset. If so, delete the preset from xml root. """ try: xml_elem = self.presListWidget.currentItem().xml_element except AttributeError: return reply = QMessageBox.question( self, 'FF Multi Converter - ' + self.tr('Delete Preset'), self.tr('Are you sure that you want to delete ' 'the %1 preset?').arg(xml_elem.tag), QMessageBox.Yes | QMessageBox.Cancel) if reply == QMessageBox.Yes: self.root.remove(xml_elem) self.save_tree() self.fill_presListWidget() def delete_all_presets(self): """ Ask user if he wants to delete all presets. If so, clear xml root. """ reply = QMessageBox.question( self, 'FF Multi Converter - ' + self.tr('Delete Preset'), self.tr('Are you sure that you want to delete ' 'all presets?'), QMessageBox.Yes | QMessageBox.Cancel) if reply == QMessageBox.Yes: self.root.clear() self.save_tree() self.fill_presListWidget() def edit_preset(self): """Call the AddorEditPreset() dialog and update xml element's values.""" elem = self.presListWidget.currentItem().xml_element dialog = AddorEditPreset(elem, True) if dialog.exec_(): elem.tag = dialog.name_text elem[0].text = dialog.label_text elem[1].text = dialog.command_text elem[2].text = dialog.ext_text self.save_tree() self.fill_presListWidget() def search(self): """ Search for keywords in presets data. Show a preset only if its tag, label or extension matches any of search string's tokens. """ txt = str(self.searchLineEdit.text()).strip().lower() if not txt: self.fill_presListWidget() return self.presListWidget.clear() for i in txt.split(' '): for p in sorted([y.tag for y in self.root]): elem = self.root.find(p) if (i.strip() and (i in elem.tag.lower() or i in elem[0].text.lower() or i in elem[2].text.lower())): self.presListWidget.addItem(MyListItem(p, elem)) self.presListWidget.setCurrentRow(0) self.set_buttons_clear_lineEdits() def save_tree(self): """Save xml tree.""" with open(self.current_presets_file, 'w') as _file: try: etree.ElementTree(self.root).write(_file) except: pass def import_presets(self): """Import an xml tree.""" title = 'FF Multi Converter - Import' reply = QMessageBox.question( self, title, self.tr('All current ' 'presets will be deleted.\nAre you sure that you want to ' 'continue?'), QMessageBox.Yes | QMessageBox.Cancel) if reply == QMessageBox.Yes: fname = QFileDialog.getOpenFileName(self, title) if fname: msg = self.tr('Succesful import!') try: self.tree = etree.parse(fname) except: msg = self.tr('Import failed!') else: self.root = self.tree.getroot() self.save_tree() QMessageBox.information(self, title, msg) def export_presets(self): """Export the xml tree.""" fname = QFileDialog.getSaveFileName( self, 'FF Multi Converter - Export presets', '.xml') if fname: self.load_xml() with open(fname, 'w') as _file: try: etree.ElementTree(self.root).write(_file) except: pass def reset(self): """Import the default xml tree.""" reply = QMessageBox.question( self, 'FF Multi Converter - ' + self.tr('Delete Preset'), self.tr('Are you sure that you want to restore ' 'the default presets?'), QMessageBox.Yes | QMessageBox.Cancel) if reply == QMessageBox.Yes: if os.path.exists(self.current_presets_file): os.remove(self.current_presets_file) def synchronize(self): """ Synchronize current presets with default presets. For each preset in default presets: - if not contained in current presets, add it to current presets - if has the same name with some preset in current presets but different attributes, then add this preset to current presets and add an '__OLD' suffix to matching preset's name """ reply = QMessageBox.question( self, 'FF Multi Converter - ' + self.tr('Presets Synchronization'), self. tr('Current presets and default ' 'presets will be merged. Are you sure that you want to continue?' ), QMessageBox.Yes | QMessageBox.Cancel) if not reply == QMessageBox.Yes: return def_tree = etree.parse(self.original_presets_file) def_root = def_tree.getroot() self.load_xml() for i in def_root: for n, y in enumerate(self.root): if i.tag == y.tag: if not (i[0].text == y[0].text and i[1].text == y[1].text and i[2].text == y[2].text): # copy element and change its name elem = etree.Element(y.tag) label = etree.Element('label') label.text = i[0].text command = etree.Element('params') command.text = i[1].text ext = etree.Element('extension') ext.text = i[2].text elem.insert(0, label) elem.insert(1, command) elem.insert(2, ext) y.tag = y.tag + '__OLD' self.root.insert(n + 1, elem) break else: # preset not found index = sorted([x.tag for x in self.root] + [i.tag]).index(i.tag) self.root.insert(index, i) self.save_tree() def remove_old(self): """Remove those xml elements which their tags has an __OLD prefix.""" reply = QMessageBox.question( self, 'FF Multi Converter - ' + self.tr('Remove old presets'), self.tr( 'All presets with an __OLD prefix ' 'will be deleted. Are you sure that you want to continue?'), QMessageBox.Yes | QMessageBox.Cancel) if not reply == QMessageBox.Yes: return self.load_xml() for i in self.root: if i.tag.endswith('__OLD'): self.root.remove(i) self.save_tree() def accept(self): """ Save current xml element's values in order to be used from main program and close (accept) dialog. """ self.the_command = None if self.presListWidget: self.the_command = self.presListWidget.currentItem()\ .xml_element[1].text self.the_extension = self.presListWidget.currentItem()\ .xml_element[2].text QDialog.accept(self)
class SessionEditor(QDialog): def __init__(self, parent=None): super(SessionEditor, self).__init__(parent) self.setWindowModality(Qt.WindowModal) layout = QVBoxLayout() self.setLayout(layout) grid = QGridLayout() layout.addLayout(grid) self.name = QLineEdit() self.nameLabel = l = QLabel() l.setBuddy(self.name) grid.addWidget(l, 0, 0) grid.addWidget(self.name, 0, 1) self.autosave = QCheckBox() grid.addWidget(self.autosave, 1, 1) self.basedir = widgets.urlrequester.UrlRequester() self.basedirLabel = l = QLabel() l.setBuddy(self.basedir) grid.addWidget(l, 2, 0) grid.addWidget(self.basedir, 2, 1) layout.addWidget(widgets.Separator()) self.buttons = b = QDialogButtonBox(self) layout.addWidget(b) b.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) b.accepted.connect(self.accept) b.rejected.connect(self.reject) userguide.addButton(b, "sessions") app.translateUI(self) def translateUI(self): self.nameLabel.setText(_("Name:")) self.autosave.setText( _("Always save the list of documents in this session")) self.basedirLabel.setText(_("Base directory:")) def load(self, name): settings = sessions.sessionGroup(name) self.autosave.setChecked(settings.value("autosave", True, bool)) self.basedir.setPath(settings.value("basedir", "", type(""))) # more settings here def save(self, name): settings = sessions.sessionGroup(name) settings.setValue("autosave", self.autosave.isChecked()) settings.setValue("basedir", self.basedir.path()) # more settings here def defaults(self): self.autosave.setChecked(True) self.basedir.setPath('') # more defaults here def edit(self, name=None): self._originalName = name if name: caption = _("Edit session: {name}").format(name=name) self.name.setText(name) self.load(name) else: caption = _("Edit new session") self.name.clear() self.name.setFocus() self.defaults() self.setWindowTitle(app.caption(caption)) if self.exec_(): # name changed? name = self.name.text() if self._originalName and name != self._originalName: sessions.renameSession(self._originalName, name) self.save(name) return name def done(self, result): if not result or self.validate(): super(SessionEditor, self).done(result) def validate(self): """Checks if the input is acceptable. If this method returns True, the dialog is accepted when OK is clicked. Otherwise a messagebox could be displayed, and the dialog will remain visible. """ name = self.name.text().strip() self.name.setText(name) if not name: self.name.setFocus() QMessageBox.warning(self, app.caption(_("Warning")), _("Please enter a session name.")) if self._originalName: self.name.setText(self._originalName) return False elif name == '-': self.name.setFocus() QMessageBox.warning( self, app.caption(_("Warning")), _("Please do not use the name '{name}'.".format(name="-"))) return False elif self._originalName != name and name in sessions.sessionNames(): self.name.setFocus() box = QMessageBox( QMessageBox.Warning, app.caption(_("Warning")), _("Another session with the name {name} already exists.\n\n" "Do you want to overwrite it?").format(name=name), QMessageBox.Discard | QMessageBox.Cancel, self) box.button(QMessageBox.Discard).setText(_("Overwrite")) result = box.exec_() if result != QMessageBox.Discard: return False return True
class LinkInput(QDialog): def __init__(self, cfg, parent = None): QDialog.__init__(self) self.setParent(parent) self.setWindowFlags(Qt.Dialog) self.setWindowTitle(self.tr('manage links')) self.setModal(1) self.config = cfg self.modified = [] self.links = self.config.loadLinks() self.typeSelect = QComboBox(self) self.plugins = classdirPlugins() plugs = self.plugins.classes() self.typeSelect.addItems(['generic'] + plugs) self.nameSelect = QComboBox(self) self.nameSelect.addItems([l for l in self.links]) self.connect(self.nameSelect, SIGNAL('currentIndexChanged(int)'), self.onNameSelectChange) self.lUserName = QLabel(self.tr('userName'), self) self.lPass = QLabel(self.tr('password'), self) self.lUrl = QLabel(self.tr('Url'), self) self.lType = QLabel(self.tr('widgetType'), self) self.lWidgetName = QLabel(self.tr('widgetName'), self) self.name = QLineEdit(self) self.urlEdit = QLineEdit() self.passwd = QLineEdit(self) self.passwd.setEchoMode(QLineEdit.Password) self.connect(self.typeSelect , SIGNAL('activated(int)') , self.onChange) self.connect(self.urlEdit , SIGNAL('textEdited(QString)') , self.onChange) self.connect(self.name , SIGNAL('textEdited(QString)') , self.onChange) self.connect(self.passwd , SIGNAL('textEdited(QString)') , self.onChange) self.newButton = QPushButton(self.tr('&new'), self) self.delButton = QPushButton(self.tr('&del'), self) self.savButton = QPushButton(self.tr('&save'), self) self.finButton = QPushButton(self.tr('&finish'), self) self.defFont = QFont() self.connect(self.newButton, SIGNAL('clicked()'), self.onNewClick) self.connect(self.delButton, SIGNAL('clicked()'), self.onDelClick) self.connect(self.savButton, SIGNAL('clicked()'), self.onSavClick) self.connect(self.finButton, SIGNAL('clicked()'), self.onFinClick) self.layout = QGridLayout(self) self.layout.addWidget(self.lWidgetName , 0 , 0) self.layout.addWidget(self.lType , 2 , 0) self.layout.addWidget(self.lUrl , 3 , 0) self.layout.addWidget(self.lUserName , 4 , 0) self.layout.addWidget(self.lPass , 5 , 0) self.layout.addWidget(self.nameSelect , 0 , 1) self.layout.addWidget(self.typeSelect , 2 , 1) self.layout.addWidget(self.urlEdit , 3 , 1) self.layout.addWidget(self.name , 4 , 1) self.layout.addWidget(self.passwd , 5 , 1) self.layout.addWidget(self.newButton , 1 , 2) self.layout.addWidget(self.delButton , 2 , 2) self.layout.addWidget(self.savButton , 3 , 2) self.layout.addWidget(self.finButton , 4 , 2) self.setMinimumWidth(500) self.nameSelect.setCurrentIndex(self.nameSelect.count()-1) def onChange(self): self.savButton.setFont(QFont(self.defFont.defaultFamily(), -1, QFont.Bold)) def onSavClick(self): if self.urlEdit.text().isEmpty(): self.urlEdit.setText(self.tr("insert URL here")) self.urlEdit.selectAll() else: u = QUrl() u.setUrl(self.urlEdit.text()) if not u.scheme(): u.setScheme('http') u.setUserName(self.name.text()) u.setPassword(self.passwd.text()) self.config.saveLink(self.nameSelect.currentText(), { 'type' : self.typeSelect.currentText(), 'data' : u.toString()}) #self.links = self.config.loadLinks() self.savButton.setFont(QFont()) self.modified.append(str(self.nameSelect.currentText())) def onNewClick(self): inp = StringInput([l for l in self.links], self) if inp.exec_(): self.name.clear() self.passwd.clear() self.urlEdit.clear() self.nameSelect.addItem(inp.getVal()) self.nameSelect.setCurrentIndex(self.nameSelect.findText(inp.getVal())) def onDelClick(self): if QMessageBox( QMessageBox.Question, self.tr('del_link'), self.tr('ask_del_link %1 ?').arg(self.nameSelect.currentText()), QMessageBox.Yes | QMessageBox.No, self).exec_() == QMessageBox.Yes: if not self.config.delLink(self.nameSelect.currentText()): print(('link "%s" not deleted !' % self.nameSelect.currentText())) self.links = self.config.loadLinks() self.nameSelect.removeItem(self.nameSelect.currentIndex()) def onFinClick(self): self.accept() def onNameSelectChange(self): try: l = self.links[str(self.nameSelect.currentText())] u = QUrl(l['data']) self.name.setText(u.userName()) self.passwd.setText(u.password()) self.urlEdit.setText(u.toString(QUrl.RemoveUserInfo)) self.typeSelect.setCurrentIndex(self.typeSelect.findText(l['type'])) except Exception as e: #print e pass def modifiedWidgets(self): return set(self.modified)
class ImageTab(QWidget): def __init__(self, parent): super(ImageTab, self).__init__(parent) self.parent = parent self.name = 'Images' self.formats = [ 'bmp', 'cgm', 'dpx', 'emf', 'eps', 'fpx', 'gif', 'jbig', 'jng', 'jpeg', 'mrsid', 'p7', 'pdf', 'picon', 'png', 'ppm', 'psd', 'rad', 'tga', 'tif','webp', 'xpm' ] self.extra_img = [ 'bmp2', 'bmp3', 'dib', 'epdf', 'epi', 'eps2', 'eps3', 'epsf', 'epsi', 'icon', 'jpe', 'jpg', 'pgm', 'png24', 'png32', 'pnm', 'ps', 'ps2', 'ps3', 'sid', 'tiff' ] validator = QRegExpValidator(QRegExp(r'^[1-9]\d*'), self) converttoQL = QLabel(self.tr('Convert to:')) self.extQCB = QComboBox() self.extQCB.addItems(self.formats) commandQL = QLabel(self.tr('Extra options:')) self.commandQLE = QLineEdit() hlayout2 = utils.add_to_layout( 'h', converttoQL, self.extQCB, commandQL, self.commandQLE) sizeQL = QLabel( '<html><p align="center">' + self.tr('Image Size:') + '</p></html>') self.widthQLE = utils.create_LineEdit((50, 16777215), validator, 4) self.heightQLE = utils.create_LineEdit((50, 16777215), validator, 4) label = QLabel('<html><p align="center">x</p></html>') label.setMaximumWidth(25) hlayout1 = utils.add_to_layout('h', self.widthQLE, label,self.heightQLE) sizelayout = utils.add_to_layout('v', sizeQL, hlayout1) self.imgaspectQChB = QCheckBox(self.tr("Maintain aspect ratio")) self.autocropQChB = QCheckBox(self.tr("Auto-crop")) vlayout = utils.add_to_layout('v', self.imgaspectQChB,self.autocropQChB) rotateQL = QLabel( "<html><div align='center'>" + self.tr("Rotate") + ":</div><br>(" + self.tr("degrees - clockwise") + ")</html>") self.rotateQLE = utils.create_LineEdit((100, 16777215), validator, 3) self.vflipQChB = QCheckBox("Vertical flip") self.hflipQChB = QCheckBox("Horizontal flip") vlayout2 = utils.add_to_layout('v', self.vflipQChB, self.hflipQChB) hlayout3 = utils.add_to_layout( 'h', sizelayout, vlayout, rotateQL, self.rotateQLE, vlayout2, None) final_layout = utils.add_to_layout('v', hlayout2, hlayout3) self.setLayout(final_layout) def clear(self): """Clear self.widthQLE and self.heightQLE.""" self.widthQLE.clear() self.heightQLE.clear() self.commandQLE.clear() self.rotateQLE.clear() self.imgaspectQChB.setChecked(False) self.autocropQChB.setChecked(False) self.vflipQChB.setChecked(False) self.hflipQChB.setChecked(False) def ok_to_continue(self): """ Check if everything is ok with imagetab to continue conversion. Check if: - ImageMagick is missing. - Either none or both size lineEdits are active at a time. Return True if all tests pass, else False. """ width = self.widthQLE.text() height = self.heightQLE.text() if not self.parent.imagemagick: QMessageBox.warning(self, 'FF Multi Converter - ' + self.tr( 'Error!'), self.tr('ImageMagick is not installed.\nYou will ' 'not be able to convert image files until you install it.')) return False if (width and not height) or (not width and height): QMessageBox.warning(self, 'FF Multi Converter - ' + self.tr( 'Error!'), self.tr('The size LineEdit may not be empty.')) if width and not height: self.heightQLE.setFocus() else: self.widthQLE.setFocus() return False return True
class bookDiag(QDialog): def __init__(self, parent): QDialog.__init__(self) self.setWindowTitle("Add bookmark entry") self.init(parent) self.initShape() def init(self, parent): self.bookmark = parent self.heditor = self.bookmark.heditor def createButtons(self): self.buttonbox = QDialogButtonBox() self.buttonbox.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok) self.connect(self.buttonbox, SIGNAL("accepted()"),self.accept) self.connect(self.buttonbox, SIGNAL("rejected()"),self.reject) return self.buttonbox def initShape(self): self.grid = QGridLayout() decoration = self.createDecoration() wButton = self.createButtons() wInfos = self.createInformations() self.grid.addWidget(decoration, 0, 0) self.grid.addWidget(wInfos, 1, 0) self.grid.addWidget(wButton, 2, 0) self.setLayout(self.grid) def createDecoration(self): self.deco = QWidget() self.hdeco = QHBoxLayout() pixlabel = QLabel() pix = QPixmap(":bookmark.png") pixlabel.setPixmap(pix) booklabel = QLabel("Add a description to this entry") self.hdeco.addWidget(pixlabel) self.hdeco.addWidget(booklabel) self.deco.setLayout(self.hdeco) return self.deco def createInformations(self): self.info = QWidget() self.igrid = QGridLayout() addressLabel = QLabel("Address: ") self.address = QLineEdit() self.address.setReadOnly(True) lend = QLabel("Length (dec): ") self.lendec = QLineEdit() self.lendec.setReadOnly(True) lenh = QLabel("Length (hex): ") self.lenhex = QLineEdit() self.lenhex.setReadOnly(True) deslabel = QLabel("Description: ") self.description = QLineEdit() hvlabel = QLabel("Hex value:") self.hexvalue = QLineEdit() self.hexvalue.setReadOnly(True) avlabel = QLabel("Ascii value:") self.asciivalue = QLineEdit() self.asciivalue.setReadOnly(True) self.igrid.addWidget(addressLabel, 0, 0, Qt.AlignLeft) self.igrid.addWidget(self.address, 0, 1, Qt.AlignLeft) self.igrid.addWidget(lend, 1, 0, Qt.AlignLeft) self.igrid.addWidget(self.lendec, 1, 1, Qt.AlignLeft) self.igrid.addWidget(lenh, 2, 0, Qt.AlignLeft) self.igrid.addWidget(self.lenhex, 2, 1, Qt.AlignLeft) self.igrid.addWidget(hvlabel, 3, 0, Qt.AlignLeft) self.igrid.addWidget(self.hexvalue, 3, 1, Qt.AlignLeft) self.igrid.addWidget(avlabel, 4, 0, Qt.AlignLeft) self.igrid.addWidget(self.asciivalue, 4, 1, Qt.AlignLeft) self.igrid.addWidget(deslabel, 5, 0, Qt.AlignLeft) self.igrid.addWidget(self.description, 5, 1, Qt.AlignLeft) self.info.setLayout(self.igrid) return self.info def cleanInformations(self): self.address.clear() self.lendec.clear() self.lenhex.clear() self.hexvalue.clear() self.asciivalue.clear() self.description.clear() def setInformations(self): self.cleanInformations() if self.heditor.decimalview: add = "%.2d" % self.heditor.selection.startoffset else: add = "0x" add += "%.2x" % self.heditor.selection.startoffset self.address.insert(add) if self.heditor.selection.length > 0: len = self.heditor.selection.length else: len = 1 tolendec = "%.1d" % len self.lendec.insert(tolendec) tolenhex = "0x" tolenhex += "%.1X" % len self.lenhex.insert(tolenhex) hval = self.heditor.readHexValue(self.heditor.selection.offset, len) self.hexvalue.insert(hval) aval = self.heditor.readAsciiValue(self.heditor.selection.offset, len) self.asciivalue.insert(aval)
class LoginDlg(QDialog): """login dialog for server""" def __init__(self): """self.servers is a list of tuples containing server and last playername""" QDialog.__init__(self, None) self.setWindowTitle(m18n('Login') + ' - Kajongg') self.setupUi() localName = m18nc('kajongg name for local game server', Query.localServerName) self.servers = Query( 'select url,lastname from server order by lasttime desc').records servers = [ m18nc('kajongg name for local game server', x[0]) for x in self.servers ] # the first server combobox item should be default: either the last used server # or localName for autoPlay if localName not in servers: servers.append(localName) if 'kajongg.org' not in servers: servers.append('kajongg.org') demoHost = Options.host or localName if demoHost in servers: servers.remove( demoHost ) # we want a unique list, it will be re-used for all following games servers.insert( 0, demoHost) # in this process but they will not be autoPlay self.cbServer.addItems(servers) self.passwords = Query( 'select url, p.name, passwords.password from passwords, player p ' 'where passwords.player=p.id').records Players.load() self.cbServer.editTextChanged.connect(self.serverChanged) self.cbUser.editTextChanged.connect(self.userChanged) self.serverChanged() StateSaver(self) def returns(self, dummyButton=None): """maybe we should return an class ServerConnection""" return (self.useSocket, self.url, self.username, self.__defineRuleset()) def setupUi(self): """create all Ui elements but do not fill them""" buttonBox = KDialogButtonBox(self) buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) # Ubuntu 11.10 unity is a bit strange - without this, it sets focus on # the cancel button (which it shows on the left). I found no obvious # way to use setDefault and setAutoDefault for fixing this. buttonBox.button(QDialogButtonBox.Ok).setFocus(True) buttonBox.accepted.connect(self.accept) buttonBox.rejected.connect(self.reject) vbox = QVBoxLayout(self) self.grid = QFormLayout() self.cbServer = QComboBox() self.cbServer.setEditable(True) self.grid.addRow(m18n('Game server:'), self.cbServer) self.cbUser = QComboBox() self.cbUser.setEditable(True) self.grid.addRow(m18n('Username:'******'Password:'******'kajongg', 'Ruleset:'), self.cbRuleset) vbox.addLayout(self.grid) vbox.addWidget(buttonBox) pol = QSizePolicy() pol.setHorizontalPolicy(QSizePolicy.Expanding) self.cbUser.setSizePolicy(pol) def serverChanged(self, dummyText=None): """the user selected a different server""" records = Query( 'select player.name from player, passwords ' 'where passwords.url=? and passwords.player = player.id', list([self.url])).records players = list(x[0] for x in records) preferPlayer = Options.player if preferPlayer: if preferPlayer in players: players.remove(preferPlayer) players.insert(0, preferPlayer) self.cbUser.clear() self.cbUser.addItems(players) if not self.cbUser.count(): user = KUser() if os.name == 'nt' else KUser(os.geteuid()) self.cbUser.addItem(user.fullName() or user.loginName()) if not preferPlayer: userNames = [x[1] for x in self.servers if x[0] == self.url] if userNames: userIdx = self.cbUser.findText(userNames[0]) if userIdx >= 0: self.cbUser.setCurrentIndex(userIdx) showPW = self.url != Query.localServerName self.grid.labelForField(self.edPassword).setVisible(showPW) self.edPassword.setVisible(showPW) self.grid.labelForField(self.cbRuleset).setVisible( not showPW and not Options.ruleset) self.cbRuleset.setVisible(not showPW and not Options.ruleset) if not showPW: self.cbRuleset.clear() if Options.ruleset: self.cbRuleset.items = [Options.ruleset] else: self.cbRuleset.items = Ruleset.selectableRulesets(self.url) def __defineRuleset(self): """find out what ruleset to use""" if Options.ruleset: return Options.ruleset elif Internal.autoPlay or bool(Options.host): return Ruleset.selectableRulesets()[0] else: return self.cbRuleset.current def userChanged(self, text): """the username has been changed, lookup password""" if text == '': self.edPassword.clear() return passw = None for entry in self.passwords: if entry[0] == self.url and entry[1] == unicode(text): passw = entry[2] if passw: self.edPassword.setText(passw) else: self.edPassword.clear() @property def url(self): """abstracts the url of the dialog""" return english(unicode(self.cbServer.currentText())) @property def host(self): """abstracts the host of the dialog""" return self.url.partition(':')[0] @property def useSocket(self): """do we use socket for current host?""" return self.host == Query.localServerName @property def port(self): """abstracts the port of the dialog""" try: return int(self.url.partition(':')[2]) except ValueError: return Options.defaultPort() @property def username(self): """abstracts the username of the dialog""" return unicode(self.cbUser.currentText()) @property def password(self): """abstracts the password of the dialog""" return unicode(self.edPassword.text()) @password.setter def password(self, password): """abstracts the password of the dialog""" self.edPassword.setText(password) def updateServerInfoInDatabase(self): """we are online. Update table server.""" lasttime = datetime.datetime.now().replace(microsecond=0).isoformat() url = english(self.url) # use unique name for Local Game with Transaction(): serverKnown = Query( 'update server set lastname=?,lasttime=? where url=?', list([self.username, lasttime, url])).rowcount() == 1 if not serverKnown: Query( 'insert into server(url,lastname,lasttime) values(?,?,?)', list([url, self.username, lasttime])) # needed if the server knows our name but our local data base does not: Players.createIfUnknown(self.username) playerId = Players.allIds[self.username] with Transaction(): if Query( 'update passwords set password=? where url=? and player=?', list([self.password, url, playerId])).rowcount() == 0: Query( 'insert into passwords(url,player,password) values(?,?,?)', list([url, playerId, self.password]))
class ImageTab(QWidget): def __init__(self, parent): super(ImageTab, self).__init__(parent) self.parent = parent self.name = 'Images' self.formats = config.image_formats self.extra_img = config.image_extra_formats validator = QRegExpValidator(QRegExp(r'^[1-9]\d*'), self) converttoQL = QLabel(self.tr('Convert to:')) self.extQCB = QComboBox() self.extQCB.addItems(self.formats) commandQL = QLabel(self.tr('Extra options:')) self.commandQLE = QLineEdit() hlayout2 = utils.add_to_layout( 'h', converttoQL, self.extQCB, commandQL, self.commandQLE) sizeQL = QLabel( '<html><p align="center">' + self.tr('Image Size:') + '</p></html>') self.widthQLE = utils.create_LineEdit((50, 16777215), validator, 4) self.heightQLE = utils.create_LineEdit((50, 16777215), validator, 4) label = QLabel('<html><p align="center">x</p></html>') label.setMaximumWidth(25) hlayout1 = utils.add_to_layout('h', self.widthQLE, label,self.heightQLE) sizelayout = utils.add_to_layout('v', sizeQL, hlayout1) self.imgaspectQChB = QCheckBox(self.tr("Maintain aspect ratio")) self.autocropQChB = QCheckBox(self.tr("Auto-crop")) vlayout = utils.add_to_layout('v', self.imgaspectQChB,self.autocropQChB) rotateQL = QLabel( "<html><div align='center'>" + self.tr("Rotate") + ":</div><br>(" + self.tr("degrees - clockwise") + ")</html>") self.rotateQLE = utils.create_LineEdit((100, 16777215), validator, 3) self.vflipQChB = QCheckBox(self.tr('Vertical flip')) self.hflipQChB = QCheckBox(self.tr('Horizontal flip')) vlayout2 = utils.add_to_layout('v', self.vflipQChB, self.hflipQChB) hlayout3 = utils.add_to_layout( 'h', sizelayout, vlayout, rotateQL, self.rotateQLE, vlayout2, None) final_layout = utils.add_to_layout('v', hlayout2, hlayout3) self.setLayout(final_layout) def clear(self): """Clear self.widthQLE and self.heightQLE.""" self.widthQLE.clear() self.heightQLE.clear() self.commandQLE.clear() self.rotateQLE.clear() self.imgaspectQChB.setChecked(False) self.autocropQChB.setChecked(False) self.vflipQChB.setChecked(False) self.hflipQChB.setChecked(False) def fill_extension_combobox(self, extraformats): extraformats = [i for i in extraformats.split("\n")] if extraformats else [] self.extQCB.clear() self.extQCB.addItems(sorted(self.formats + extraformats)) def ok_to_continue(self): """ Check if everything is ok with imagetab to continue conversion. Check if: - ImageMagick is missing. - Either none or both size lineEdits are active at a time. Return True if all tests pass, else False. """ width = self.widthQLE.text() height = self.heightQLE.text() if not self.parent.imagemagick: QMessageBox.warning(self, 'FF Multi Converter - ' + self.tr( 'Error!'), self.tr('ImageMagick is not installed.\nYou will ' 'not be able to convert image files until you install it.')) return False if (width and not height) or (not width and height): QMessageBox.warning(self, 'FF Multi Converter - ' + self.tr( 'Error!'), self.tr('The size LineEdit may not be empty.')) if width and not height: self.heightQLE.setFocus() else: self.widthQLE.setFocus() return False return True def set_default_command(self): """Set the default value to self.commandQLE.""" self.clear() self.commandQLE.setText(self.parent.default_command_image)
class ComboCheckBox(QComboBox): def __init__(self, itemdicts): # items==[str,str...] super(ComboCheckBox, self).__init__() self.itemdict = itemdicts self.items = self.itemdict.keys() self.items.insert(0, u'全部') self.row_num = len(self.items) self.Selectedrow_num = 0 self.qCheckBox = [] self.qLineEdit = QLineEdit() self.qLineEdit.setReadOnly(True) self.qListWidget = QListWidget() self.addQCheckBox(0) self.qCheckBox[0].stateChanged.connect(self.All) for i in range(1, self.row_num): self.addQCheckBox(i) self.qCheckBox[i].stateChanged.connect(self.show) self.setModel(self.qListWidget.model()) self.setView(self.qListWidget) self.setLineEdit(self.qLineEdit) self.show() # self.qListWidget.setAlternatingRowColors(True) # self.qLineEdit.setAlternatingRowColors(True) # self.qLineEdit.setStyleSheet("background-color:transparen ") # self.qListWidget.setStyleSheet("background-color:#ee3333 ") def addQCheckBox(self, i): self.qCheckBox.append(QCheckBox()) qItem = QListWidgetItem(self.qListWidget) self.qCheckBox[i].setText(self.items[i]) if i > 0 and self.itemdict[self.items[i]] == "1": self.qCheckBox[i].setChecked(True) self.qListWidget.setItemWidget(qItem, self.qCheckBox[i]) def Selectlist(self): Outputlist = [] for i in range(1, self.row_num): if self.qCheckBox[i].isChecked() == True: Outputlist.append(self.qCheckBox[i].text()) self.Selectedrow_num = len(Outputlist) return Outputlist def show(self): show = '' Outputlist = self.Selectlist() self.qLineEdit.setReadOnly(False) self.qLineEdit.clear() for i in Outputlist: show += i + ';' if self.Selectedrow_num == 0: self.qCheckBox[0].setCheckState(0) elif self.Selectedrow_num == self.row_num - 1: self.qCheckBox[0].setCheckState(2) else: self.qCheckBox[0].setCheckState(1) self.qLineEdit.setText(show) self.qLineEdit.setReadOnly(True) def All(self, state): if state == 2: for i in range(1, self.row_num): self.qCheckBox[i].setChecked(True) elif state == 1: if self.Selectedrow_num == 0: self.qCheckBox[0].setCheckState(2) elif state == 0: self.clear() def clear(self): for i in range(self.row_num): self.qCheckBox[i].setChecked(False)
class CommandWindow(QFrame): """Miow main window """ def __init__(self, parent=None): super(CommandWindow, self).__init__(parent) self.parent = parent self.setWindowFlags(QtCore.Qt.Popup) self.setFont(QFont("Monospace", 14)) self.setMinimumWidth(400) self.setMinimumHeight(300) self.setGeometry(0, 0, 600, 300) # create widgets layout = QVBoxLayout(self) self.line_edit = QLineEdit(self) layout.addWidget(self.line_edit) self.list_widget = QListWidget(self) self.list_widget.currentItemChanged.connect(self.on_current_item_changed) layout.addWidget(self.list_widget) layout.setStretchFactor(self.list_widget, 15) layout.setMargin(0) layout.setSpacing(0) layout.setContentsMargins(0,0,0,0) self.setLayout(layout) self.line_edit.setFocus() self.full_command = QPlainTextEdit(self) self.full_command.setFont(QFont("Monospace", 8)) size_policy = self.full_command.sizePolicy() size_policy.setVerticalPolicy(QSizePolicy.Ignored) self.full_command.setSizePolicy(size_policy) layout.addWidget(self.full_command) layout.setStretchFactor(self.full_command, 3) layout2 = QHBoxLayout(self) self.weight = QLabel(self) self.weight.setFont(QFont("Monospace", 8)) size_policy = self.weight.sizePolicy() size_policy.setVerticalPolicy(QSizePolicy.Ignored) self.weight.setSizePolicy(size_policy) layout2.addWidget(self.weight) layout2.setStretchFactor(self.weight, 1) self.labels = QLabel(self) self.labels.setFont(QFont("Monospace", 8)) size_policy = self.labels.sizePolicy() size_policy.setVerticalPolicy(QSizePolicy.Ignored) self.labels.setSizePolicy(size_policy) layout2.addWidget(self.labels) layout2.setStretchFactor(self.labels, 8) layout.addLayout(layout2) layout.setStretchFactor(layout2, 1) self.line_edit.textChanged.connect(self.on_text_changed) self.list_widget.itemDoubleClicked.connect(self.on_item_double_clicked) self.event_selected_command = Event() def show_hide(self, context): if self.isVisible() == False or context is not None: self.command_list = self.parent.get_command_list(context) self.filter_commands("") self.show() else: self.hide() def showEvent(self, event): geom = self.frameGeometry() self.line_edit.setFocus() self.line_edit.clear() #parent_widget = self.parentWidget() if self.parent: geom.moveCenter(QtCore.QPoint(self.parent.pos().x()+self.parent.width()/2, self.parent.pos().y()+self.parent.height()/3)) self.setGeometry(geom) super(QFrame, self).showEvent(event) def _get_command_from_text(self, text): for command_text, tags, weight, command in self.command_list: if command_text == text: return command return None def _get_full_command_from_text(self, text): for command_text, tags, weight, command in self.command_list: if command_text == text: return (command_text, tags, weight, command) return None def keyPressEvent(self, event): if event.type() == QEvent.KeyPress: key_event = QKeyEvent(event) if(key_event.key() == Qt.Key_Down or key_event.key() == Qt.Key_Up): return self.list_widget.keyPressEvent(event) elif((event.key() == Qt.Key_Enter or event.key() == Qt.Key_Return) and self.list_widget.currentItem()>=0): self.hide() self.event_selected_command(str(self.full_command.toPlainText())) return super(CommandWindow, self).keyPressEvent(event) def on_item_double_clicked(self, item): self.hide() self.event_selected_command(str(self.full_command.toPlainText())) def on_current_item_changed(self, prev, current): if(self.list_widget.currentItem()): command_text, tags, weight, command = self._get_full_command_from_text( self.list_widget.currentItem().text()) self.full_command.setPlainText(command) self.labels.setText(tags) self.weight.setText(str(weight)) else: self.full_command.setPlainText("") self.labels.setText("") self.weight.setText("") def filter_commands(self, text): self.list_widget.clear() text = str(text).upper() def get_item_map_def0(_map, key): if(key in _map): return _map[key] else: return 0. def get_command_matches(command_list, words): result_map = {} for command, tags, _, _ in command_list: for word in words: located_command_weight = 1 located_tag_weight = 0.3 if word == '': located_command_weight = 0. located_tag_weight = 0. if command.upper().find(word) != -1: result_map[command] = (get_item_map_def0(result_map, command) - located_command_weight) for tag in tags.split(" "): if tag.upper().find(word) != -1: result_map[command] = (get_item_map_def0(result_map, command) - located_tag_weight) for command, _, current_weight, _ in command_list: if command in result_map: result_map[command] -= current_weight return sorted(result_map, key=result_map.get) words = str(text).strip().split(" ") matches_map = get_command_matches(self.command_list, words) for command in matches_map: self.list_widget.addItem(command) self.list_widget.setCurrentRow(0) def on_text_changed(self, text): self.filter_commands(text)
class LigneCommande(QWidget): u"""Un TextCtrl muni d'un historique et associé à un bouton pour valider. On peut personnaliser le texte du bouton (via `texte="Mon texte"`), ou même directement le bouton, en utilisant `bouton=...`. """ def __init__(self, parent, longueur = 500, texte = None, bouton = None, action = (lambda *args, **kw: True), afficher_bouton = True, legende = None): self.parent = parent self.action = action QWidget.__init__(self, parent) sizer = QHBoxLayout() self.texte = QLineEdit() self.texte.setMinimumWidth(longueur) if bouton is None: self.bouton = QPushButton('OK' if texte is None else texte) else: self.bouton = bouton self.bouton.setVisible(afficher_bouton) self.bouton.clicked.connect(self.valider) if legende is not None: sizer.addWidget(QLabel(legende, self)) sizer.addWidget(self.texte) sizer.addWidget(self.bouton) self.setLayout(sizer) self.initialiser() def initialiser(self): self.historique = [] self.position = None self.setFocus() self.clear() def text(self): return self.texte.text() def setText(self, value): self.texte.setText(value) def setFocus(self): self.texte.setFocus() def clear(self): self.texte.clear() def getSelection(self): if self.texte.hasSelectedText(): start = self.texte.selectionStart() length = len(self.texte.selectedText()) end = start + length else: start = end = self.texte.cursorPosition() return start, end def cursorPosition(self): return self.texte.cursorPosition() def setCursorPosition(self, num): return self.texte.setCursorPosition(num) def insert(self, texte): self.texte.insert(texte) def setSelection(self, deb, fin): self.texte.setSelection(deb, fin) def setToolTip(self, tip): self.texte.setToolTip(tip) def valider(self, **kw): # kw: shift|alt|meta|control=True|False' commande = unicode(self.text()) self.position = None if commande: self.historique.append(commande) elif self.historique: # Appuyer une deuxième fois sur [Entrée] permet de répéter l'action précédente. commande = self.historique[-1] self.action(commande, **kw) def keyPressEvent(self, event): key = event.key() commande = self.text() if key == Qt.Key_Up and self.historique: # On remonte dans l'historique (-> entrées plus anciennes) if self.position is None: # cas d'une commande en cours d'édition : if commande: if commande != self.historique[-1]: # on enregistre la commande en cours self.historique.append(commande) self.position = len(self.historique) - 1 else: self.position = len(self.historique) if self.position > 0: self.position -= 1 self.texte.setText(self.historique[self.position]) elif key == Qt.Key_Down and self.historique: # On redescend dans l'historique (-> entrées plus récentes) if self.position is None or self.position == len(self.historique) - 1: if commande and commande != self.historique[-1]: self.historique.append(commande) self.texte.clear() self.position = len(self.historique) elif self.position < len(self.historique) - 1: self.position += 1 self.texte.setText(self.historique[self.position]) elif key in (Qt.Key_Enter, Qt.Key_Return): modifiers = event.modifiers() kw = {'shift': modifiers & Qt.ShiftModifier, 'alt': modifiers & Qt.AltModifier, 'meta': modifiers & Qt.MetaModifier, 'control': modifiers & Qt.ControlModifier, } self.valider(**kw) else: self.position = None
class ChatWindow(QWidget): def __init__(self, socket, addr): super(ChatWindow, self).__init__() self.socket = socket self.addr = addr self.setupSocket() self.createUi() def setupSocket(self): self.socket.disconnected.connect(self.onDisconnected) self.socket.error.connect(self.onError) def createUi(self): vbox = QVBoxLayout() self.buf = TextBrowser(self.addr.toString()) self.buf.setFontFamily('Monospace') self.buf.setFocusPolicy(Qt.NoFocus) vbox.addWidget(self.buf, 1) hbox_send = QHBoxLayout() self.send_text = QLineEdit() hbox_send.addWidget(self.send_text, 1) self.send_button = QPushButton("Send") self.send_file_button = QPushButton("Send File") hbox_send.addWidget(self.send_button) hbox_send.addWidget(self.send_file_button) vbox.addLayout(hbox_send) self.setLayout(vbox) self.send_text.returnPressed.connect(self.onSend) self.send_button.clicked.connect(self.onSend) self.send_file_button.clicked.connect(self.onSendFile) def onSend(self): text = unicode(self.send_text.text()) encoded = text.encode(TEXT_ENCODING) header = 'T%d ' % len(encoded) payload = header + encoded if self.socket.write(payload) < len(payload): self.buf.error('Failed to send message %s' % urepr(text)) self.send_text.clear() sendFileBufSize = 1024 def onSendFile(self): path = str(QFileDialog.getOpenFileName()) if not os.path.exists(path): if len(path) == 0: self.buf.info('File sending cancelled.') else: self.buf.error("File %s doesn't exist." % path) return size = os.path.getsize(path) bname = os.path.basename(path)[:512] header = 'F%d %s/' % (size, bname) if len(header) > self.sendFileBufSize: raise ChatException("Header too long, give up") with open(path, 'rb') as f: buf = header + f.read(self.sendFileBufSize - len(header)) while len(buf) > 0: if self.socket.write(buf) < len(buf): self.buf.error('Failed to send file %s' % bname) break buf = f.read(self.sendFileBufSize) def onConnected(self): self.buf.info('Connected to peer %s.' % unicode(self.peer.toString())) def onDisconnected(self): self.buf.info('Peer went offline.') def onError(self): self.buf.error('Something went wrong with the connection.')
class ChatWindow(QWidget): """a widget for showing chat messages""" def __init__(self, table=None, game=None): super(ChatWindow, self).__init__(None) self.table = table or game.client.table self.table.chatWindow = self title = m18n('Chat on table %1 at %2', self.table.tableid, self.table.client.connection.url) self.setObjectName('chatWindow') self.setWindowTitle(title + ' - kajongg') self.messageView = ChatView() self.messageView.setModel(ChatModel()) self.messageView.setFocusPolicy(Qt.NoFocus) self.messageView.setShowGrid(False) self.messageView.setWordWrap(False) self.messageView.setSelectionMode(QAbstractItemView.NoSelection) if Debug.modelTest: self.debugModelTest = ModelTest(self.messageView.model(), self.messageView) self.edit = QLineEdit() layout = QVBoxLayout() layout.addWidget(self.messageView) layout.addWidget(self.edit) self.setLayout(layout) self.edit.returnPressed.connect(self.sendLine) self.edit.setFocus() self.show() StateSaver(self) def show(self): """not only show but also restore and raise""" self.activateWindow() self.setWindowState(self.windowState() & ~Qt.WindowMinimized) self.raise_() QWidget.show(self) def isVisible(self): """not only visible but also not minimized""" return QWidget.isVisible( self) and not self.windowState() & Qt.WindowMinimized def kill(self): """hide and null on table""" print('chat.kill for %s on table %s' % (self, self.table)) self.hide() self.table.chatWindow = None def sendLine(self, line=None, isStatusMessage=False): """send line to others. Either the edited line or parameter line.""" if line is None: line = unicode(self.edit.text()) self.edit.clear() if line: if Debug.chat: logDebug('sending line %s to others' % line) msg = ChatMessage(self.table.tableid, self.table.client.name, line, isStatusMessage) self.table.client.sendChat(msg).addErrback(self.chatError) def chatError(self, result): """tableList may already have gone away""" if self.table.client.tableList: self.table.client.tableList.tableError(result) def leave(self): """leaving the chat""" # TODO: send "left" message self.hide() def receiveLine(self, chatLine): """show a new line in protocol""" self.show() self.messageView.model().appendLines(chatLine) for row in range(self.messageView.model().rowCount()): self.messageView.setRowHeight( row, self.messageView.fontMetrics().height()) self.messageView.resizeColumnsToContents() self.messageView.scrollToBottom()
class MainWindow(QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) # main window dimensions self.main_width = 780 self.main_height = 510 self.main_fixed_height = 684 self.default_command = config.default_ffmpeg_cmd self.fnames = list() # list of file names to be converted self.docconv = False # True when a documents conversion is running self.parse_cla() addQPB = QPushButton(self.tr('Add')) delQPB = QPushButton(self.tr('Delete')) clearQPB = QPushButton(self.tr('Clear')) vlayout1 = utils.add_to_layout('v', addQPB, delQPB, clearQPB, None) self.filesList = utils.FilesList() self.filesList.setSelectionMode(QAbstractItemView.ExtendedSelection) hlayout1 = utils.add_to_layout('h', self.filesList, vlayout1) outputQL = QLabel(self.tr('Output folder:')) self.toQLE = QLineEdit() self.toQLE.setReadOnly(True) self.toQTB = QToolButton() self.toQTB.setText('...') hlayout2 = utils.add_to_layout('h', outputQL, self.toQLE, self.toQTB) self.audiovideo_tab = AudioVideoTab(self) self.image_tab = ImageTab(self) self.document_tab = DocumentTab(self) self.tabs = [self.audiovideo_tab, self.image_tab, self.document_tab] tab_names = [self.tr('Audio/Video'), self.tr('Images'), self.tr('Documents')] self.tabWidget = QTabWidget() for num, tab in enumerate(tab_names): self.tabWidget.addTab(self.tabs[num], tab) self.tabWidget.setCurrentIndex(0) self.origQCB = QCheckBox( self.tr('Save each file in the same\nfolder as input file')) self.deleteQCB = QCheckBox(self.tr('Delete original')) convertQPB = QPushButton(self.tr('&Convert')) hlayout3 = utils.add_to_layout('h', self.origQCB, self.deleteQCB, None) hlayout4 = utils.add_to_layout('h', None, convertQPB) final_layout = utils.add_to_layout( 'v', hlayout1, self.tabWidget, hlayout2, hlayout3, hlayout4) self.dependenciesQL = QLabel() self.statusBar().addPermanentWidget(self.dependenciesQL, stretch=1) widget = QWidget() widget.setLayout(final_layout) self.setCentralWidget(widget) openAction = utils.create_action( self, self.tr('Open'), QKeySequence.Open, None, self.tr('Open a file'), self.add_files ) convertAction = utils.create_action( self, self.tr('Convert'), 'Ctrl+C', None, self.tr('Convert files'), self.start_conversion ) quitAction = utils.create_action( self, self.tr('Quit'), 'Ctrl+Q', None, self.tr('Quit'), self.close ) edit_presetsAction = utils.create_action( self, self.tr('Edit Presets'), 'Ctrl+P', None, self.tr('Edit Presets'), self.presets ) importAction = utils.create_action( self, self.tr('Import'), None, None, self.tr('Import presets'), self.import_presets ) exportAction = utils.create_action( self, self.tr('Export'), None, None, self.tr('Export presets'), self.export_presets ) resetAction = utils.create_action( self, self.tr('Reset'), None, None, self.tr('Reset presets'), self.reset_presets ) syncAction = utils.create_action( self, self.tr('Synchronize'), None, None, self.tr('Synchronize presets'), self.sync_presets ) removeoldAction = utils.create_action( self, self.tr('Remove old'), None, None, self.tr('Remove old presets'), self.removeold_presets ) clearallAction = utils.create_action( self, self.tr('Clear All'), None, None, self.tr('Clear form'), self.clear_all ) preferencesAction = utils.create_action( self, self.tr('Preferences'), 'Alt+Ctrl+P', None, self.tr('Preferences'), self.preferences ) aboutAction = utils.create_action( self, self.tr('About'), 'Ctrl+?', None, self.tr('About'), self.about ) fileMenu = self.menuBar().addMenu(self.tr('File')) editMenu = self.menuBar().addMenu(self.tr('Edit')) presetsMenu = self.menuBar().addMenu(self.tr('Presets')) helpMenu = self.menuBar().addMenu(self.tr('Help')) utils.add_actions( fileMenu, [openAction, convertAction, None, quitAction]) utils.add_actions( presetsMenu, [edit_presetsAction, importAction, exportAction, resetAction, None, syncAction, removeoldAction] ) utils.add_actions(editMenu, [clearallAction, None, preferencesAction]) utils.add_actions(helpMenu, [aboutAction]) self.filesList.dropped.connect(self.url_dropped) addQPB.clicked.connect(self.add_files) delQPB.clicked.connect(self.delete_files) clearQPB.clicked.connect(self.clear_fileslist) self.tabWidget.currentChanged.connect( lambda: self.tabs[0].moreQPB.setChecked(False)) self.origQCB.clicked.connect( lambda: self.toQLE.setEnabled(not self.origQCB.isChecked())) self.toQTB.clicked.connect(self.open_dir) convertQPB.clicked.connect(convertAction.triggered) del_shortcut = QShortcut(self) del_shortcut.setKey(Qt.Key_Delete) del_shortcut.activated.connect(self.delete_files) self.resize(self.main_width, self.main_height) self.setWindowTitle('FF Multi Converter') QTimer.singleShot(0, self.check_for_dependencies) QTimer.singleShot(0, self.load_settings) QTimer.singleShot(0, self.audiovideo_tab.set_default_command) QTimer.singleShot(0, self.update_filesList) def parse_cla(self): """Parse command line arguments.""" for i in QCoreApplication.argv()[1:]: i = os.path.abspath(i) if os.path.isfile(i): self.fnames.append(i) else: print("ffmulticonverter: {0}: Not a file".format(i)) def load_settings(self): """Load settings values.""" def get_str_value(settings, name): value = settings.value(name) if value is not None: return value return '' settings = QSettings() self.overwrite_existing = utils.str_to_bool( get_str_value(settings, 'overwrite_existing')) self.avconv_prefered = utils.str_to_bool( get_str_value(settings, 'avconv_prefered')) self.default_output = get_str_value(settings, 'default_output') self.prefix = get_str_value(settings, 'prefix') self.suffix = get_str_value(settings, 'suffix') defcmd = get_str_value(settings, 'default_command') videocodecs = get_str_value(settings, 'videocodecs') audiocodecs = get_str_value(settings, 'audiocodecs') extraformats = get_str_value(settings, 'extraformats') if defcmd: self.default_command = defcmd self.toQLE.setText(self.default_output) self.audiovideo_tab.fill_video_comboboxes( videocodecs, audiocodecs, extraformats) def current_tab(self): """Return the corresponding object of the selected tab.""" for i in self.tabs: if self.tabs.index(i) == self.tabWidget.currentIndex(): return i def update_filesList(self): """Clear self.filesList and add to it all items of self.fname.""" self.filesList.clear() for i in self.fnames: self.filesList.addItem(i) def url_dropped(self, links): """ Append to self.fnames each file name that not already exists and update self.filesList. """ for url in links: if os.path.isfile(url) and not url in self.fnames: self.fnames.append(url) self.update_filesList() def add_files(self): """ Get file names using a standard Qt dialog. Append to self.fnames each file name that not already exists and update self.filesList. """ # Create lists holding file formats extension. # To be passed in QFileDialog.getOpenFileNames(). all_files = '*' audiovideo_files = ' '.join( ['*.'+i for i in self.audiovideo_tab.formats]) img_formats = self.image_tab.formats[:] img_formats.extend(self.image_tab.extra_img) image_files = ' '.join(['*.'+i for i in img_formats]) document_files = ' '.join(['*.'+i for i in self.document_tab.formats]) formats = [all_files, audiovideo_files, image_files, document_files] strings = [self.tr('All Files'), self.tr('Audio/Video Files'), self.tr('Image Files'), self.tr('Document Files')] filters = '' for string, extensions in zip(strings, formats): filters += string + ' ({0});;'.format(extensions) filters = filters[:-2] # remove last ';;' fnames = QFileDialog.getOpenFileNames(self, 'FF Multi Converter - ' + self.tr('Choose File'), config.home, filters) if fnames: for i in fnames: if not i in self.fnames: self.fnames.append(i) self.update_filesList() def delete_files(self): """ Get selectedItems of self.filesList, remove them from self.fnames and update the filesList. """ items = self.filesList.selectedItems() if items: for i in items: self.fnames.remove(i.text()) self.update_filesList() def clear_fileslist(self): """Make self.fnames empty and update self.filesList.""" self.fnames = [] self.update_filesList() def clear_all(self): """Clear all values of graphical widgets.""" self.toQLE.clear() self.origQCB.setChecked(False) self.deleteQCB.setChecked(False) self.clear_fileslist() self.audiovideo_tab.clear() self.image_tab.clear() def open_dir(self): """ Get a directory name using a standard QtDialog and update self.toQLE with dir's name. """ if self.toQLE.isEnabled(): output = QFileDialog.getExistingDirectory( self, 'FF Multi Converter - ' + self.tr('Choose output destination'), config.home) if output: self.toQLE.setText(output) def preferences(self): """Open the preferences dialog.""" dialog = preferences_dlg.Preferences(self) if dialog.exec_(): self.load_settings() def presets(self): """Open the presets dialog.""" dialog = presets_dlgs.ShowPresets(self) dialog.exec_() def import_presets(self): presets_dlgs.ShowPresets().import_presets() def export_presets(self): presets_dlgs.ShowPresets().export_presets() def reset_presets(self): presets_dlgs.ShowPresets().reset() def sync_presets(self): presets_dlgs.ShowPresets().synchronize() def removeold_presets(self): presets_dlgs.ShowPresets().remove_old() def ok_to_continue(self): """ Check if everything is ok to continue with conversion. Check if: - At least one file has given for conversion. - An output folder has given. - Output folder exists. Return False if an error arises, else True. """ try: if not self.fnames: raise ValidationError( self.tr('You must add at least one file to convert!')) elif not self.origQCB.isChecked() and not self.toQLE.text(): raise ValidationError( self.tr('You must choose an output folder!')) elif (not self.origQCB.isChecked() and not os.path.exists(self.toQLE.text())): raise ValidationError(self.tr('Output folder does not exists!')) if not self.current_tab().ok_to_continue(): return False return True except ValidationError as e: QMessageBox.warning( self, 'FF Multi Converter - ' + self.tr('Error!'), str(e)) return False def output_ext(self): """Extract the desired output file extension from GUI and return it.""" tab = self.current_tab() if tab.name == 'AudioVideo': ext_to = self.audiovideo_tab.extQCB.currentText() elif tab.name == 'Images': ext_to = tab.extQCB.currentText() else: ext_to = tab.convertQCB.currentText().split()[-1] return '.' + ext_to def start_conversion(self): """ Extract the appropriate information from GUI and call the Progress dialog with the suitable argumens. """ if not self.ok_to_continue(): return ext_to = self.output_ext() _list = utils.create_paths_list( self.fnames, ext_to, self.prefix, self.suffix, self.toQLE.text(), self.origQCB.isChecked(), self.overwrite_existing ) tab = self.current_tab() if tab.name == 'Documents': self.docconv = True dialog = progress.Progress( _list, tab, self.deleteQCB.isChecked(), self) dialog.show() def check_for_dependencies(self): """ Check if each one of the program dependencies are installed and update self.dependenciesQL with the appropriate message. """ self.ffmpeg = utils.is_installed('ffmpeg') self.avconv = utils.is_installed('avconv') self.unoconv = utils.is_installed('unoconv') self.imagemagick = utils.is_installed('convert') missing = [] if not self.ffmpeg and not self.avconv: missing.append('ffmpeg/avconv') if not self.unoconv: missing.append('unoconv') if not self.imagemagick: missing.append('imagemagick') if missing: missing = ', '.join(missing) status = self.tr('Missing dependencies:') + ' ' + missing self.dependenciesQL.setText(status) def about(self): """Call the about dialog with the appropriate values.""" msg = self.tr('Convert among several file types to other extensions') msg = textwrap.fill(msg, 54).replace('\n', '<br>') text = '''<b> FF Multi Converter {0} </b> <p>{1} <p><a href="{2}">FF Multi Converter - Home Page</a> <p>Copyright © 2011-2014 {3} <br>License: {4} <p>Python {5} - Qt {6} - PyQt {7} on {8}'''\ .format(ffmc.__version__, msg, ffmc.__url__, ffmc.__author__, ffmc.__license__, platform.python_version()[:5], QT_VERSION_STR, PYQT_VERSION_STR, platform.system()) image = ':/ffmulticonverter.png' authors = '{0} <{1}>\n\n'.format(ffmc.__author__, ffmc.__author_email__) authors += 'Contributors:\nPanagiotis Mavrogiorgos' transl_list = [['[bg] Bulgarian', 'Vasil Blagoev'], ['[cs] Czech', 'Petr Simacek'], ['[de_DE] German (Germany)', 'Stefan Wilhelm'], ['[el] Greek', 'Ilias Stamatis'], ['[es] Spanish', 'Miguel Ángel Rodríguez Muíños'], ['[fr] French', 'Rémi Mercier' '\n Lebarhon'], ['[gl] Galician', 'Miguel Anxo Bouzada'], ['[gl_ES] Galician (Spain)', 'Miguel Anxo Bouzada'], ['[hu] Hungarian', 'Farkas Norbert'], ['[it] Italian', 'Fabio Boccaletti'], ['[ms_MY] Malay (Malaysia)', 'abuyop'], ['[pl_PL] Polish (Poland)', 'Lukasz Koszy' '\n Piotr Surdacki'], ['[pt] Portuguese', 'Sérgio Marques'], ['[pt_BR] Portuguese (Brasil)', 'José Humberto A Melo'], ['[ro_RO] Romanian (Romania)', 'Angelescu Constantin'], ['[ru] Russian', 'Andrew Lapshin'], ['[tu] Turkish', 'Tayfun Kayha'], ['[vi] Vietnamese', 'Anh Phan'], ['[zh_CN] Chinese (China)', 'Dianjin Wang'], ['[zh_TW] Chinese (Taiwan)', 'Taijuin Lee'], ] translators = [] for i in transl_list: translators.append('{0}\n {1}'.format(i[0], i[1])) translators = '\n\n'.join(translators) dialog = about_dlg.AboutDialog(text, image, authors, translators, self) dialog.exec_()
class AudioVideoTab(QWidget): def __init__(self, parent): super(AudioVideoTab, self).__init__(parent) self.parent = parent self.name = 'AudioVideo' self.formats = ['3gp', 'aac', 'ac3', 'afc', 'aiff', 'amr', 'asf', 'au', 'avi', 'dvd', 'flac', 'flv', 'mka', 'mkv', 'mmf', 'mov', 'mp3', 'mp4', 'mpg', 'ogg', 'ogv', 'psp', 'rm', 'spx', 'vob', 'wav', 'webm', 'wma', 'wmv'] self.extra_formats = ['aifc', 'm2t', 'm4a', 'm4v', 'mp2', 'mpeg', 'ra', 'ts'] nochange = self.tr('No Change') frequency_values = [nochange, '22050', '44100', '48000'] bitrate_values = [nochange, '32', '96', '112', '128', '160', '192', '256', '320'] pattern = QRegExp(r'^[1-9]\d*') validator = QRegExpValidator(pattern, self) converttoLabel = QLabel(self.tr('Convert to:')) self.extComboBox = QComboBox() self.extComboBox.addItems(self.formats + [self.tr('Other')]) self.extComboBox.setMinimumWidth(130) self.extLineEdit = QLineEdit() self.extLineEdit.setMaximumWidth(85) self.extLineEdit.setEnabled(False) hlayout1 = pyqttools.add_to_layout(QHBoxLayout(), converttoLabel, None, self.extComboBox, self.extLineEdit) commandLabel = QLabel(self.tr('Command:')) self.commandLineEdit = QLineEdit() self.presetButton = QPushButton(self.tr('Preset')) self.defaultButton = QPushButton(self.tr('Default')) hlayout2 = pyqttools.add_to_layout(QHBoxLayout(), commandLabel, self.commandLineEdit, self.presetButton, self.defaultButton) sizeLabel = QLabel(self.tr('Video Size:')) aspectLabel = QLabel(self.tr('Aspect:')) frameLabel = QLabel(self.tr('Frame Rate (fps):')) bitrateLabel = QLabel(self.tr('Video Bitrate (kbps):')) self.widthLineEdit = pyqttools.create_LineEdit((50, 16777215), validator, 4) self.heightLineEdit = pyqttools.create_LineEdit((50, 16777215), validator,4) label = QLabel('x') layout1 = pyqttools.add_to_layout(QHBoxLayout(), self.widthLineEdit, label, self.heightLineEdit) self.aspect1LineEdit = pyqttools.create_LineEdit((35, 16777215), validator,2) self.aspect2LineEdit = pyqttools.create_LineEdit((35, 16777215), validator,2) label = QLabel(':') layout2 = pyqttools.add_to_layout(QHBoxLayout(), self.aspect1LineEdit, label, self.aspect2LineEdit) self.frameLineEdit = pyqttools.create_LineEdit(None, validator, 4) self.bitrateLineEdit = pyqttools.create_LineEdit(None, validator, 6) labels = [sizeLabel, aspectLabel, frameLabel, bitrateLabel] widgets = [layout1, layout2, self.frameLineEdit, self.bitrateLineEdit] videosettings_layout = QHBoxLayout() for a, b in zip(labels, widgets): text = a.text() a.setText('<html><p align="center">{0}</p></html>'.format(text)) layout = pyqttools.add_to_layout(QVBoxLayout(), a, b) videosettings_layout.addLayout(layout) freqLabel = QLabel(self.tr('Frequency (Hz):')) chanLabel = QLabel(self.tr('Channels:')) bitrateLabel = QLabel(self.tr('Audio Bitrate (kbps):')) self.freqComboBox = QComboBox() self.freqComboBox.addItems(frequency_values) self.chan1RadioButton = QRadioButton('1') self.chan1RadioButton.setMaximumSize(QSize(51, 16777215)) self.chan2RadioButton = QRadioButton('2') self.chan2RadioButton.setMaximumSize(QSize(51, 16777215)) self.group = QButtonGroup() self.group.addButton(self.chan1RadioButton) self.group.addButton(self.chan2RadioButton) spcr1 = QSpacerItem(40, 20, QSizePolicy.Preferred, QSizePolicy.Minimum) spcr2 = QSpacerItem(40, 20, QSizePolicy.Preferred, QSizePolicy.Minimum) chanlayout = pyqttools.add_to_layout(QHBoxLayout(), spcr1, self.chan1RadioButton, self.chan2RadioButton, spcr2) self.audio_bitrateComboBox = QComboBox() self.audio_bitrateComboBox.addItems(bitrate_values) labels = [freqLabel, chanLabel, bitrateLabel] widgets = [self.freqComboBox, chanlayout, self.audio_bitrateComboBox] audiosettings_layout = QHBoxLayout() for a, b in zip(labels, widgets): text = a.text() a.setText('<html><p align="center">{0}</p></html>'.format(text)) layout = pyqttools.add_to_layout(QVBoxLayout(), a, b) audiosettings_layout.addLayout(layout) hidden_layout = pyqttools.add_to_layout(QVBoxLayout(), videosettings_layout, audiosettings_layout) line = QFrame() line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) self.moreButton = QPushButton(QApplication.translate('Tab', 'More')) self.moreButton.setSizePolicy(QSizePolicy(QSizePolicy.Fixed)) self.moreButton.setCheckable(True) hlayout3 = pyqttools.add_to_layout(QHBoxLayout(), line, self.moreButton) self.frame = QFrame() self.frame.setLayout(hidden_layout) self.frame.hide() final_layout = pyqttools.add_to_layout(QVBoxLayout(), hlayout1, hlayout2, hlayout3, self.frame) self.setLayout(final_layout) self.presetButton.clicked.connect(self.choose_preset) self.defaultButton.clicked.connect(self.set_default_command) self.moreButton.toggled.connect(self.frame.setVisible) self.moreButton.toggled.connect(self.resize_parent) self.extComboBox.currentIndexChanged.connect( lambda: self.extLineEdit.setEnabled( self.extComboBox.currentIndex() == len(self.formats))) self.widthLineEdit.textChanged.connect( lambda: self.command_elements_change('size')) self.heightLineEdit.textChanged.connect( lambda: self.command_elements_change('size')) self.aspect1LineEdit.textChanged.connect( lambda: self.command_elements_change('aspect')) self.aspect2LineEdit.textChanged.connect( lambda: self.command_elements_change('aspect')) self.frameLineEdit.textChanged.connect( lambda: self.command_elements_change('frames')) self.bitrateLineEdit.textChanged.connect( lambda: self.command_elements_change('video_bitrate')) self.freqComboBox.currentIndexChanged.connect( lambda: self.command_elements_change('frequency')) self.audio_bitrateComboBox.currentIndexChanged.connect( lambda: self.command_elements_change('audio_bitrate')) self.chan1RadioButton.clicked.connect( lambda: self.command_elements_change('channels1')) self.chan2RadioButton.clicked.connect( lambda: self.command_elements_change('channels2')) def resize_parent(self): """Resize MainWindow.""" height = MAIN_FIXED_HEIGHT if self.frame.isVisible() else MAIN_HEIGHT self.parent.setMinimumSize(MAIN_WIDTH, height) self.parent.resize(MAIN_WIDTH, height) def clear(self): """Clear all values of graphical widgets.""" lines = [self.commandLineEdit, self.widthLineEdit, self.heightLineEdit, self.aspect1LineEdit, self.aspect2LineEdit, self.frameLineEdit, self.bitrateLineEdit, self.extLineEdit] for i in lines: i.clear() self.freqComboBox.setCurrentIndex(0) self.audio_bitrateComboBox.setCurrentIndex(0) self.group.setExclusive(False) self.chan1RadioButton.setChecked(False) self.chan2RadioButton.setChecked(False) self.group.setExclusive(True) # setExclusive(False) in order to be able to uncheck checkboxes and # then setExclusive(True) so only one radio button can be set def ok_to_continue(self): """ Check if everything is ok with audiovideotab to continue conversion. Check if: - Either ffmpeg or avconv are installed. - Desired extension is valid. - self.commandLineEdit is empty. Return True if all tests pass, else False. """ if not self.parent.ffmpeg and not self.parent.avconv: QMessageBox.warning(self, 'FF Multi Converter - ' + self.tr( 'Error!'), self.tr('Neither ffmpeg nor avconv are installed.' '\nYou will not be able to convert audio/video files until you' ' install one of them.')) return False if self.extLineEdit.isEnabled(): text = str(self.extLineEdit.text()).strip() if len(text.split()) != 1 or text[0] == '.': QMessageBox.warning(self, 'FF Multi Converter - ' + self.tr( 'Error!'), self.tr('Extension must be one word and must ' 'not start with a dot.')) self.extLineEdit.selectAll() self.extLineEdit.setFocus() return False if not self.commandLineEdit.text(): QMessageBox.warning(self, 'FF Multi Converter - ' + self.tr( 'Error!'), self.tr('The command LineEdit may not be empty.')) self.commandLineEdit.setFocus() return False return True def set_default_command(self): """Set the default value to self.commandLineEdit.""" self.clear() self.commandLineEdit.setText(self.parent.default_command) def choose_preset(self): """ Open the presets dialog and update self.commandLineEdit, self.extComboBox and self.extLineEdit with the appropriate values. """ dialog = presets_dlgs.ShowPresets() if dialog.exec_() and dialog.the_command is not None: self.commandLineEdit.setText(dialog.the_command) self.commandLineEdit.home(False) find = self.extComboBox.findText(dialog.the_extension) if find >= 0: self.extComboBox.setCurrentIndex(find) else: self.extComboBox.setCurrentIndex(len(self.formats)) self.extLineEdit.setText(dialog.the_extension) def remove_consecutive_spaces(self, string): """Remove any consecutive spaces from a string and return it.""" temp = string string = '' for i in temp.split(): if i: string += i + ' ' return string[:-1] def command_elements_change(self, widget): """Fill self.commandLineEdit with the appropriate command parameters.""" command = str(self.commandLineEdit.text()) if widget == 'size': text1 = self.widthLineEdit.text() text2 = self.heightLineEdit.text() if (text1 or text2) and not (text1 and text2): return f = re.sub(r'^.*(-s\s+\d+x\d+).*$', r'\1', command) if re.match(r'^.*(-s\s+\d+x\d+).*$', f): command = command.replace(f, '').strip() if text1 and text2: command += ' -s {0}x{1}'.format(text1, text2) elif widget == 'aspect': text1 = self.aspect1LineEdit.text() text2 = self.aspect2LineEdit.text() if (text1 or text2) and not (text1 and text2): return f = re.sub(r'^.*(-aspect\s+\d+:\d+).*$', r'\1', command) if re.match(r'^.*(-aspect\s+\d+:\d+).*$', f): command = command.replace(f, '').strip() if text1 and text2: command += ' -aspect {0}:{1}'.format(text1, text2) elif widget == 'frames': text = self.frameLineEdit.text() f = re.sub(r'^.*(-r\s+\d+).*$', r'\1', command) if re.match(r'^.*(-r\s+\d+).*$', f): command = command.replace(f, '').strip() if text: command += ' -r {0}'.format(text) elif widget == 'video_bitrate': text = self.bitrateLineEdit.text() f = re.sub(r'^.*(-b\s+\d+k).*$', r'\1', command) if re.match(r'^.*(-b\s+\d+k).*$', f): command = command.replace(f, '') if text: command += ' -b {0}k'.format(text) command = command.replace('-sameq', '').strip() elif widget == 'frequency': text = self.freqComboBox.currentText() f = re.sub(r'^.*(-ar\s+\d+).*$', r'\1', command) if re.match(r'^.*(-ar\s+\d+).*$', f): command = command.replace(f, '').strip() if text != 'No Change': command += ' -ar {0}'.format(text) elif widget == 'audio_bitrate': text = self.audio_bitrateComboBox.currentText() f = re.sub(r'^.*(-ab\s+\d+k).*$', r'\1', command) if re.match(r'^.*(-ab\s+\d+k).*$', f): command = command.replace(f, '').strip() if text != 'No Change': command += ' -ab {0}k'.format(text) elif widget in ('channels1', 'channels2'): text = self.chan1RadioButton.text() if widget == 'channels1' \ else self.chan2RadioButton.text() f = re.sub(r'^.*(-ac\s+\d+).*$', r'\1', command) if re.match(r'^.*(-ac\s+\d+).*$', f): command = command.replace(f, '').strip() command += ' -ac {0}'.format(text) self.commandLineEdit.clear() self.commandLineEdit.setText(self.remove_consecutive_spaces(command))
class MainWindow(QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.home = os.getenv('HOME') self.fnames = list() # list of file names to be converted self.docconv = False # True when a documents conversion is running # parse command line arguments for i in QCoreApplication.argv()[1:]: i = codecs.utf_8_decode(os.path.abspath(i))[0] if os.path.isfile(i): self.fnames.append(i) else: print("ffmulticonverter: {0}: Not a file".format(i)) addButton = QPushButton(self.tr('Add')) delButton = QPushButton(self.tr('Delete')) clearButton = QPushButton(self.tr('Clear')) vlayout1 = pyqttools.add_to_layout(QVBoxLayout(), addButton, delButton, clearButton, None) self.filesList = FilesList() self.filesList.setSelectionMode(QAbstractItemView.ExtendedSelection) hlayout1 = pyqttools.add_to_layout(QHBoxLayout(), self.filesList, vlayout1) output_label = QLabel(self.tr('Output folder:')) self.toLineEdit = QLineEdit() self.toLineEdit.setReadOnly(True) self.toToolButton = QToolButton() self.toToolButton.setText('...') hlayout2 = pyqttools.add_to_layout(QHBoxLayout(), output_label, self.toLineEdit, self.toToolButton) self.audiovideo_tab = AudioVideoTab(self) self.image_tab = ImageTab(self) self.document_tab = DocumentTab(self) self.tabs = [self.audiovideo_tab, self.image_tab, self.document_tab] tab_names = [self.tr('Audio/Video'), self.tr('Images'), self.tr('Documents')] self.TabWidget = QTabWidget() for num, tab in enumerate(tab_names): self.TabWidget.addTab(self.tabs[num], tab) self.TabWidget.setCurrentIndex(0) self.origCheckBox = QCheckBox( self.tr('Save each file in the same\nfolder as input file')) self.deleteCheckBox = QCheckBox(self.tr('Delete original')) self.convertPushButton = QPushButton(self.tr('&Convert')) hlayout3 = pyqttools.add_to_layout(QHBoxLayout(), self.origCheckBox, self.deleteCheckBox, None) hlayout4 = pyqttools.add_to_layout(QHBoxLayout(), None, self.convertPushButton) final_layout = pyqttools.add_to_layout(QVBoxLayout(), hlayout1, self.TabWidget, hlayout2, hlayout3, hlayout4) self.statusBar = self.statusBar() self.dependenciesLabel = QLabel() self.statusBar.addPermanentWidget(self.dependenciesLabel, stretch=1) Widget = QWidget() Widget.setLayout(final_layout) self.setCentralWidget(Widget) c_act = pyqttools.create_action openAction = c_act(self, self.tr('Open'), QKeySequence.Open, None, self.tr('Open a file'), self.add_files) convertAction = c_act(self, self.tr('Convert'), 'Ctrl+C', None, self.tr('Convert files'), self.start_conversion) quitAction = c_act(self, self.tr('Quit'), 'Ctrl+Q', None, self.tr('Quit'), self.close) edit_presetsAction = c_act(self, self.tr('Edit Presets'), 'Ctrl+P', None, self.tr('Edit Presets'), self.presets) importAction = c_act(self, self.tr('Import'), None, None, self.tr('Import presets'), self.import_presets) exportAction = c_act(self, self.tr('Export'), None, None, self.tr('Export presets'), self.export_presets) resetAction = c_act(self, self.tr('Reset'), None, None, self.tr('Reset presets'), self.reset_presets) syncAction = c_act(self, self.tr('Synchronize'), None, None, self.tr('Synchronize presets'), self.sync_presets) removeoldAction = c_act(self, self.tr('Remove old'), None, None, self.tr('Remove old presets'), self.removeold_presets) clearallAction = c_act(self, self.tr('Clear All'), None, None, self.tr('Clear form'), self.clear_all) preferencesAction = c_act(self, self.tr('Preferences'), 'Alt+Ctrl+P', None, self.tr('Preferences'), self.preferences) aboutAction = c_act(self, self.tr('About'), 'Ctrl+?', None, self.tr('About'), self.about) fileMenu = self.menuBar().addMenu(self.tr('File')) editMenu = self.menuBar().addMenu(self.tr('Edit')) presetsMenu = self.menuBar().addMenu(self.tr('Presets')) helpMenu = self.menuBar().addMenu(self.tr('Help')) pyqttools.add_actions(fileMenu, [openAction, convertAction, None, quitAction]) pyqttools.add_actions(presetsMenu, [edit_presetsAction, importAction, exportAction, resetAction, None, syncAction, removeoldAction]) pyqttools.add_actions(editMenu, [clearallAction, None, preferencesAction]) pyqttools.add_actions(helpMenu, [aboutAction]) self.filesList.dropped.connect(self.url_dropped) addButton.clicked.connect(self.add_files) delButton.clicked.connect(self.delete_files) clearButton.clicked.connect(self.clear_fileslist) self.TabWidget.currentChanged.connect(lambda: self.tabs[0].moreButton.setChecked(False)) self.origCheckBox.clicked.connect(lambda: self.toLineEdit.setEnabled(not self.origCheckBox.isChecked())) self.toToolButton.clicked.connect(self.open_dir) self.convertPushButton.clicked.connect(convertAction.triggered) del_shortcut = QShortcut(self) del_shortcut.setKey(Qt.Key_Delete) del_shortcut.activated.connect(self.delete_files) self.resize(MAIN_WIDTH, MAIN_HEIGHT) self.setWindowTitle('FF Multi Converter') QTimer.singleShot(0, self.check_for_dependencies) QTimer.singleShot(0, self.load_settings) QTimer.singleShot(0, self.audiovideo_tab.set_default_command) QTimer.singleShot(0, self.update_filesList) def load_settings(self): """Load settings values.""" settings = QSettings() self.overwrite_existing = settings.value('overwrite_existing').toBool() self.default_output = unicode( settings.value('default_output').toString()) self.prefix = unicode(settings.value('prefix').toString()) self.suffix = unicode(settings.value('suffix').toString()) self.avconv_prefered = settings.value('avconv_prefered').toBool() self.default_command = unicode( settings.value('default_command').toString()) if not self.default_command: self.default_command = DEFAULT_COMMAND self.toLineEdit.setText(self.default_output) def current_tab(self): """Return the corresponding object of the selected tab.""" for i in self.tabs: if self.tabs.index(i) == self.TabWidget.currentIndex(): return i def update_filesList(self): """Clear self.filesList and add to it all items of self.fname.""" self.filesList.clear() for i in self.fnames: self.filesList.addItem(i) def url_dropped(self, links): """ Append to self.fnames each file name that not already exists and update self.filesList. """ for url in links: if os.path.isfile(url) and not url in self.fnames: self.fnames.append(url) self.update_filesList() def add_files(self): """ Get file names using a standard Qt dialog. Append to self.fnames each file name that not already exists and update self.filesList. """ # Create lists holding file formats extension. # To be passed in QFileDialog.getOpenFileNames(). all_files = '*' audiovideo_files = ' '.join( ['*.'+i for i in self.audiovideo_tab.formats]) img_formats = self.image_tab.formats[:] img_formats.extend(self.image_tab.extra_img) image_files = ' '.join(['*.'+i for i in img_formats]) document_files = ' '.join(['*.'+i for i in self.document_tab.formats]) formats = [all_files, audiovideo_files, image_files, document_files] strings = [self.tr('All Files'), self.tr('Audio/Video Files'), self.tr('Image Files'), self.tr('Document Files')] filters = '' for string, extensions in zip(strings, formats): filters += string + ' ({0});;'.format(extensions) filters = filters[:-2] # remove last ';;' fnames = QFileDialog.getOpenFileNames(self, 'FF Multi Converter - ' + self.tr('Choose File'), self.home, filters) if fnames: for i in fnames: if not i in self.fnames: self.fnames.append(unicode(i)) self.update_filesList() def delete_files(self): """ Get selectedItems of self.filesList, remove them from self.fnames and update the filesList. """ items = self.filesList.selectedItems() if items: for i in items: self.fnames.remove(unicode(i.text())) self.update_filesList() def clear_fileslist(self): """Make self.fnames empty and update self.filesList.""" self.fnames = [] self.update_filesList() def clear_all(self): """Clear all values of graphical widgets.""" self.toLineEdit.clear() self.origCheckBox.setChecked(False) self.deleteCheckBox.setChecked(False) self.clear_fileslist() self.audiovideo_tab.clear() self.image_tab.clear() def open_dir(self): """ Get a directory name using a standard QtDialog and update self.toLineEdit with dir's name. """ if self.toLineEdit.isEnabled(): output = QFileDialog.getExistingDirectory(self, 'FF Multi Converter - ' + self.tr('Choose output destination'), self.home) #output = unicode(output) if output: self.toLineEdit.setText(output) def preferences(self): """Open the preferences dialog.""" dialog = preferences_dlg.Preferences(self) if dialog.exec_(): self.load_settings() def presets(self): """Open the presets dialog.""" dialog = presets_dlgs.ShowPresets(self) dialog.exec_() def import_presets(self): presets_dlgs.ShowPresets().import_presets() def export_presets(self): presets_dlgs.ShowPresets().export_presets() def reset_presets(self): presets_dlgs.ShowPresets().reset() def sync_presets(self): presets_dlgs.ShowPresets().synchronize() def removeold_presets(self): presets_dlgs.ShowPresets().remove_old() def ok_to_continue(self): """ Check if everything is ok to continue with conversion. Check if: - At least one file has given for conversion. - An output folder has given. - Output folder exists. Return False if an error arises, else True. """ try: if not self.fnames: raise ValidationError(self.tr( 'You must add at least one file to convert!')) elif not self.origCheckBox.isChecked() and not self.toLineEdit.text(): raise ValidationError(self.tr( 'You must choose an output folder!')) elif (not self.origCheckBox.isChecked() and not os.path.exists(unicode(self.toLineEdit.text()))): raise ValidationError(self.tr('Output folder does not exists!')) if not self.current_tab().ok_to_continue(): return False return True except ValidationError as e: QMessageBox.warning(self, 'FF Multi Converter - ' + \ self.tr('Error!'), unicode(e)) return False def output_ext(self): """Extract the desired output file extension from GUI and return it.""" tab = self.current_tab() if tab.name == 'AudioVideo': if self.audiovideo_tab.extLineEdit.isEnabled(): ext_to = self.audiovideo_tab.extLineEdit.text() else: ext_to = self.audiovideo_tab.extComboBox.currentText() elif tab.name == 'Images': ext_to = tab.extComboBox.currentText() else: ext_to = str(tab.convertComboBox.currentText()).split()[-1] return str('.' + ext_to) def create_paths_list(self, files_list, ext_to, prefix, suffix, output, orig_dir, overwrite_existing): """ Keyword arguments: files_list -- list with files to be converted ext_to -- the extension to which each file must be converted to prefix -- string that will be added as a prefix to all filenames suffix -- string that will be added as a suffix to all filenames output -- the output folder orig_dir -- if True, each file will be saved at its original directory else, files will be saved at output overwrite_existing -- if False, a '~' will be added as prefix to filenames Create and return a list with dicts. Each dict will have only one key and one corresponding value. Key will be a file to be converted and it's value will be the name of the new converted file. Example list: [{"/foo/bar.png" : "/foo/bar.bmp"}, {"/f/bar2.png" : "/f/bar2.bmp"}] """ assert ext_to.startswith('.'), 'ext_to must start with a dot (.)' conversion_list = [] dummy = [] for _file in files_list: _dir, name = os.path.split(_file) y = prefix + os.path.splitext(name)[0] + suffix + ext_to if orig_dir: y = _dir + '/' + y else: y = output + '/' + y if not overwrite_existing: while os.path.exists(y) or y in dummy: _dir2, _name2 = os.path.split(y) y = _dir2 + '/~' + _name2 dummy.append(y) # Add quotations to paths in order to avoid error in special # cases such as spaces or special characters. _file = '"' + _file + '"' y = '"' + y + '"' _dict = {} _dict[_file] = y conversion_list.append(_dict) return conversion_list def start_conversion(self): """ Extract the appropriate information from GUI and call the Progress dialog with the suitable argumens. """ if not self.ok_to_continue(): return ext_to = self.output_ext() _list = self.create_paths_list(self.fnames, ext_to, self.prefix, self.suffix, unicode(self.toLineEdit.text()), self.origCheckBox.isChecked(), self.overwrite_existing) tab = self.current_tab() cmd = '' size = str('') mntaspect = False if tab.name == 'AudioVideo': cmd = tab.commandLineEdit.text() elif tab.name == 'Images': width = tab.widthLineEdit.text() if width: height = tab.heightLineEdit.text() size = str('{0}x{1}'.format(width, height)) mntaspect = tab.aspectCheckBox.isChecked() else: self.docconv = True dialog = progress.Progress(_list, tab.name, cmd, not self.avconv_prefered, size, mntaspect, self.deleteCheckBox.isChecked(), self) dialog.show() def is_installed(self, program): """Return True if program appears in user's PATH var, else False.""" for path in os.getenv('PATH').split(os.pathsep): fpath = os.path.join(path, program) if os.path.exists(fpath) and os.access(fpath, os.X_OK): return True return False def check_for_dependencies(self): """ Check if each one of the program dependencies are installed and update self.dependenciesLabel with the appropriate message. """ self.ffmpeg = self.is_installed('ffmpeg') self.avconv = self.is_installed('avconv') self.unoconv = self.is_installed('unoconv') self.pmagick = True try: # We tried to import PythonMagick earlier. # If that raises an error it means that PythonMagick is not # available on the system. PythonMagick except NameError: self.pmagick = False missing = [] if not self.ffmpeg and not self.avconv: missing.append('FFmpeg/avconv') if not self.unoconv: missing.append('unoconv') if not self.pmagick: missing.append('PythonMagick') if missing: missing = ', '.join(missing) status = self.tr('Missing dependencies:') + ' ' + missing self.dependenciesLabel.setText(status) def about(self): """Call the about dialog with the appropriate values.""" link = 'http://sites.google.com/site/ffmulticonverter/' msg = self.tr('Convert among several file types to other extensions') if len(msg) > 54: # break line if msg is too long to fit the window nmsg = '' for n, w in enumerate(msg.split(' ')): if len(nmsg) > 54: break nmsg += w + ' ' nmsg += '<br>' + msg[len(nmsg):] msg = nmsg text = '''<b> FF Multi Converter {0} </b> <p>{1} <p><a href="{2}">FF Multi Converter - Home Page</a> <p>Copyright © 2011-2013 Ilias Stamatis <br>License: GNU GPL3 <p>Python {3} - Qt {4} - PyQt {5} on {6}'''\ .format(__version__, msg, link, platform.python_version()[:5], QT_VERSION_STR, PYQT_VERSION_STR, platform.system()) image = ':/ffmulticonverter.png' authors = 'Ilias Stamatis <*****@*****.**>\n\n' authors += 'Contributors:\nPanagiotis Mavrogiorgos' transl_list = [['[bg] Bulgarian', 'Vasil Blagoev'], ['[cs] Czech', 'Petr Simacek'], ['[de_DE] German (Germany)', 'Stefan Wilhelm'], ['[el] Greek', 'Ilias Stamatis'], ['[fr] French', 'Rémi Mercier' '\n Lebarhon'], ['[hu] Hungarian', 'Farkas Norbert'], ['[it] Italian', 'Fabio Boccaletti'], ['[pl_PL] Polish (Poland)', 'Lukasz Koszy' '\n Piotr Surdacki'], ['[pt] Portuguese', 'Sérgio Marques'], ['[pt_BR] Portuguese (Brasil)', 'José Humberto A Melo'], ['[ru] Russian', 'Andrew Lapshin'], ['[tu] Turkish', 'Tayfun Kayha'], ['[zh_CN] Chinese (China)', 'Dianjin Wang']] translators = '' for i in transl_list: translators += '{0}\n {1}\n\n'.format(i[0], i[1]) translators = translators[:-2] dialog = about_dlg.AboutDialog(text, image, authors, translators, self) dialog.exec_()
class MyForm(QWidget): def __init__(self): QWidget.__init__(self) # setGeometry(x_pos, y_pos, width, height) self.setGeometry(100, 150, 500, 460) self.readSettings() self.setWindowTitle(APPNAME + ' ' + VERSION + " - " + self.chanells_path ) self.icon_path = get_icon_resource(imgdata_png_main) # self.icon_path = os.path.join(os.path.dirname(sys.argv[0]), 'chanchan.ico') self.icon = QIcon(self.icon_path) self.setWindowIcon(self.icon) self.chanells = None self.chanells_all = None self.num_channels = 0 # the player subprocess process self.proc = None self.proc_sopcast = None self.is_sopcast = False self.is_playlist = False self.on_top = False self.cache_size = CACHE_SIZE_DEFAULT if not self.haveSeenFirstTime: copy_default_playlist() self.haveSeenFirstTime = True # saving settings should be done in closeEvent() instead! # settings = QSettings(QSettings.IniFormat, QSettings.UserScope, "xh", "chanchan") # settings.setValue("seen_first_time", QVariant(self.haveSeenFirstTime)) # settings.sync() # use a grid layout for the widgets grid = QGridLayout() # bind the button click to a function reference # new connect style, needs PyQt 4.5+ ###btn_load.clicked.connect(self.load_channels_data) btn_play = QPushButton("&Play") btn_play.setToolTip("Click to play selected stream") btn_play.clicked.connect(self.on_button_play) btn_kill = QPushButton("&Stop") btn_kill.setToolTip("Click to stop current player") btn_kill.clicked.connect(self.kill_proc) self.listbox = QListWidget() # new connect style, needs PyQt 4.5+ self.listbox.clicked.connect(self.on_select) self.listbox.doubleClicked.connect(self.on_double_click) # attach right-click handler self.listbox.setContextMenuPolicy(Qt.ActionsContextMenu) #self.listbox.setContextMenuPolicy(Qt.CustomContextMenu) #http://talk.maemo.org/showthread.php?t=64034 self.actionCopyUrl = QAction("Copy URL", self.listbox) self.connect(self.actionCopyUrl, SIGNAL("triggered()"), self.copy_to_clipboard) self.actionPlay = QAction("Play", self.listbox) self.actionPlay.setShortcut("Ctrl+P") self.actionRestartPlayer = QAction("Restart SopPlayer", self.listbox) self.actionReloadChannels = QAction("Reload List", self.listbox) self.actionEditChannels = QAction("Edit Playlist", self.listbox) self.actionEditChannels.setShortcut("Ctrl+E") self.actionOpenChannelsFile = QAction("Open Playlist File", self.listbox) self.actionEditSource = QAction("Edit Source", self.listbox) self.actionAbout = QAction("About %s" % APPNAME, self.listbox) self.actionQuit = QAction("Quit", self) self.actionQuit.setShortcut("Ctrl+Q") self.search = QLineEdit() self.connect(self.search, SIGNAL("textChanged(QString)"), self.on_search_text_change) # clear button self.clear_button = QToolButton() self.clear_button.setIcon(get_icon_resource(imgdata_png_clear)) self.clear_button.setIconSize(QSize(16, 16)) self.clear_button.setCursor(Qt.ArrowCursor) self.clear_button.setAutoRaise(True) self.clear_button.setEnabled(False) # self.main_layout.addWidget(self.clear_button) self.connect(self.clear_button, SIGNAL("clicked()"), self.clear_search_text) self.listbox.addAction(self.actionPlay) self.listbox.addAction(self.actionRestartPlayer) self.listbox.addAction(self.actionCopyUrl) self.listbox.addAction(self.actionOpenChannelsFile) self.listbox.addAction(self.actionReloadChannels) self.listbox.addAction(self.actionEditChannels) self.listbox.addAction(self.actionEditSource) self.listbox.addAction(self.actionAbout) self.addAction(self.actionQuit) self.connect(self.actionPlay, SIGNAL("triggered()"), self.on_double_click) self.connect(self.actionRestartPlayer, SIGNAL("triggered()"), self.restart_sopplayer) self.connect(self.actionReloadChannels, SIGNAL("triggered()"), lambda: self.load_channels_data(self.chanells_path)) self.connect(self.actionEditChannels, SIGNAL("triggered()"), lambda: self.edit_file(str(self.chanells_path))) self.connect(self.actionOpenChannelsFile, SIGNAL("triggered()"), lambda: self.load_channels_data()) self.connect(self.actionEditSource, SIGNAL("triggered()"), lambda: self.edit_file(path=sys.argv[0], editor=EDITOR)) self.connect(self.actionQuit, SIGNAL("triggered()"), self.close) self.connect(self.actionAbout, SIGNAL("triggered()"), lambda: QMessageBox.about(self, 'About %s' % APPNAME, ''' <h4>%s version %s</h4> <p> Created by <i>%s</i></p> <p><a href="mailto:%s">%s</a></p> <p><a href="%s">chanchantv.googlecode.com</a></p> ''' % (APPNAME, VERSION, AUTHOR, EMAIL.decode('base64'), EMAIL, WEB)) # warning(self, APPNAME, 'No playlist selected') ) # self.listbox.connect(self.listbox, SIGNAL("customContextMenuRequested(QPoint)"), # self.on_right_click) # self.txtChanInfo = QLineEdit() # self.txtChanInfo.setReadOnly(True) # self.logWindow = QTextEdit() # self.logWindow.setSizePolicyx(QSizePolicy.) self.status = QLabel() self.status.setText('channels') # ADD BEVELED BORDER::self.status.setFrameStyle(QFrame.Panel | QFrame.Sunken) self.groupBox = QGroupBox("Engine") sizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.groupBox.sizePolicy().hasHeightForWidth()) self.groupBox.setSizePolicy(sizePolicy) # self.groupBox.setAutoFillBackground(True) self.rbMplayer = QRadioButton('&Mplayer', self.groupBox) self.rbMplayer.setChecked(True) self.rbMplayer.setToolTip("Play with Mplayer") #self.rbGstreamer = QRadioButton('gst&123', self.groupBox) self.rbVlc = QRadioButton('&Vlc', self.groupBox) self.rbVlc.setToolTip("Play with VLC") self.rbTotem = QRadioButton('&Totem', self.groupBox) self.rbTotem.setToolTip("Play with Totem") self.rbBrowser = QRadioButton('&Browser', self.groupBox) self.rbBrowser.setToolTip("Open URL in web browser") self.hBoxTop = QHBoxLayout() self.hBoxTop.addWidget(self.rbMplayer) #self.hBoxTop.addWidget(self.rbGstreamer) self.hBoxTop.addWidget(self.rbVlc) self.hBoxTop.addWidget(self.rbTotem) self.hBoxTop.addWidget(self.rbBrowser) self.groupBox.setLayout(self.hBoxTop) self.cbPlaylistFlag = QCheckBox('Playlist') self.cbPlaylistFlag.setToolTip('Resource is a M3U, ASX or PLS playlist') self.cbFullScreen = QCheckBox('Full Screen') self.cbFullScreen.setToolTip('Start video in full screen') self.cbFullScreen.setChecked(self.is_full_screen) self.cbInhibitScreensaver = QCheckBox('Inhibit Screensaver') self.cbInhibitScreensaver.setToolTip('Disable screensaver while playing stream') self.cbInhibitScreensaver.setChecked(self.is_inhibit_screen) # addWidget(widget, row, column, rowSpan, columnSpan) grid.addWidget(self.groupBox, 0, 0, 1, 3) grid.addWidget(btn_play, 0, 4, 1, 1) grid.addWidget(btn_kill, 0, 5, 1, 1) grid.addWidget(self.search, 1, 0, 1, 4) grid.addWidget(self.clear_button, 1, 3, 1, 1) grid.addWidget(self.status, 1, 5, 1, 1) # listbox spans over 5 rows and 2 columns grid.addWidget(self.listbox, 2, 0, 5, 6) ## BAD grid.addWidget(self.hBoxFlags, 6, 0, 1, 1) grid.addWidget(self.cbPlaylistFlag, 7, 0, 1, 1) grid.addWidget(self.cbFullScreen, 7, 1, 1, 1) grid.addWidget(self.cbInhibitScreensaver, 7, 2, 1, 1) # grid.addWidget(self.txtChanInfo, 7, 0, 1, 6) # grid.addWidget(self.logWindow, 8, 0, 1, 6) self.setLayout(grid) self.search.setFocus() self.load_channels_data(self.chanells_path) def clear_search_text(self): print '------clear-search-text---------' self.search.clear() def on_search_text_change(self): if not self.chanells_all: # only need to do this once self.chanells_all = list(self.chanells) text = str(self.search.text()).strip() print 'DBG', len(text), len(self.chanells_all) if len(text) > 1: self.clear_button.setEnabled(True) filtered_list = self.get_matching_items(text.lower(), self.chanells_all) if len(filtered_list): self.chanells = filtered_list else: self.chanells = [] else: self.chanells = list(self.chanells_all) self.clear_button.setEnabled(False) self.load_channels_data(None, False) def get_matching_items(self, needle, haystack): 'search for a substring in channel list' matches = [] found_in_meta = False last_meta_item = None for ch in haystack: is_meta = ch.startswith('#') if is_meta and not needle in ch.lower(): last_meta_item = ch if needle in ch.lower(): if is_meta: found_in_meta = True elif not found_in_meta and last_meta_item not in matches: matches.append(last_meta_item) matches.append(ch) elif found_in_meta: if not is_meta: matches.append(ch) else: found_in_meta = False return matches def closeEvent(self, event): self.writeSettings() print 'closeEvent: Saving settings and exiting...' return quit_msg = "Are you sure you want to exit the program?" reply = QMessageBox.question(self, 'Message', quit_msg, QMessageBox.Yes, QMessageBox.No) if reply == QMessageBox.Yes: self.writeSettings() event.accept() QApplication.instance().quit() else: event.ignore() def keyPressEvent(self, event): if event.key() == Qt.Key_Escape: self.search.setFocus() self.search.selectAll() def copy_to_clipboard(self): clipboard = QApplication.clipboard() clipboard.setText(self.listbox.currentItem().text()) def load_channels_data(self, new_path=None, read_from_file=True): MediaItem.num_items = 0 if read_from_file: if not new_path: new_path = str(self.get_new_filename()) if not new_path: # QMessageBox.warning(self, APPNAME, 'No playlist selected') return try: fh = codecs.open(new_path, 'r', 'utf8') self.chanells = [ch.strip() for ch in fh.readlines()] except Exception as e: show_gui_error(e, 'File not found', 'Error opening playlist "%s" \n\n%s' % (new_path, str(e))) return self.chanells_path = new_path self.chanells = [ch.strip() for ch in self.chanells] self.chanells_all = None self.listbox.clear() current_params = None for chan in self.chanells: if not len(chan) or chan.strip() == '#EXTM3U': continue item = MediaItem(chan, self.icon) if item.is_meta: '''if a metadata line, then store and apply to all the following non-metadata items ''' current_params = item.params elif current_params: item.params = current_params item.setStatusTip(chan) self.listbox.addItem(item) self.setWindowTitle(APPNAME + ' ' + VERSION + ' - ' + self.chanells_path) self.status.setText(str(MediaItem.num_items) + ' channels') def edit_file(self, path, editor=EDITOR): if ' ' in editor: editor = editor.split(' ') subprocess.Popen([editor, path]) def get_new_filename(self): return QFileDialog.getOpenFileName(self, 'Load Playlist file', '', "Playlist files (*.m3u);;All Files (*.*);") def on_button_play(self): # self.on_select() self.play_media() def on_select(self): """an item in the listbox has been clicked/selected""" current_item = self.listbox.currentItem() if not current_item: return current_channel = current_item and str(current_item.text()) or '<no channel>' self.is_playlist = current_channel[-4:].lower() in ['.m3u', '.asx', '.pls'] # if current_channel.startswith('sop:'): #self.rbMplayer.setChecked(True) # self.cache_size = '1024' if current_item.params: 'set params for current channel according to metadata line' myparams = current_item.params.keys() if 'player' in myparams: player = current_item.params['player'].lower() if player == 'totem': self.rbTotem.setChecked(True) elif player == MPLAYER: self.rbMplayer.setChecked(True) #elif player == 'gst123': # self.rbGstreamer.setChecked(True) elif player == VLC: self.rbVlc.setChecked(True) elif player in ('browser', 'web'): self.rbBrowser.setChecked(True) if 'playlist' in myparams or 'pl' in myparams: self.is_playlist = current_item.params['playlist'].lower() in GOOD_VALUES if 'fullscreen' in myparams or 'fs' in myparams: self.is_full_screen = current_item.params['fullscreen'].lower() in GOOD_VALUES else: self.is_full_screen = IS_FULLSCREEN_DEFAULT if 'ontop' in myparams or 'top' in myparams: self.on_top = current_item.params['top'].lower() in GOOD_VALUES else: self.on_top = IS_ON_TOP_DEFAULT if 'cache' in myparams: self.cache_size = current_item.params['cache'] else: self.cache_size = CACHE_SIZE_DEFAULT if 'exec' in myparams or 'shell' in myparams: # set shell options: console or no console self.exec_shell_command = current_item.params['exec'] # # if 'exec' in myparams: # self.executable_name = current_item.params['exec'] self.cbPlaylistFlag.setChecked(self.is_playlist) # only setting True state if self.is_full_screen: self.cbFullScreen.setChecked(True) def on_double_click(self): self.play_media() """an item in the listbox has been double-clicked""" def restart_sopplayer(self): # if self.rbVlc.isChecked(): # if vlc_remote_command('testing if vlc remote is running...'): # vlc_remote_command('add %s' % SOPCAST_SERVER_URL) # vlc_remote_command('volume 200') # else: self.play_media(start_sopcast_server=False) def play_media(self, start_sopcast_server=True): current_item = self.listbox.currentItem() if not current_item: return current_channel = str(current_item.text()) if self.proc and self.proc.pid: self.kill_proc() args = [] if self.cbInhibitScreensaver.isChecked(): suspend_screensaver() ################ RUN SHELL COMMAND ############# if 'exec' in current_item.params: show_console = current_item.params['exec'].lower() == 'console' if show_console: args += ['xterm', '-geometry', '45x8-20+400', '-e'] args += [current_channel.strip()] self.proc = subprocess.Popen(args, stdout=subprocess.PIPE) print 'DBG:', self.proc else: args.insert(0, current_item.params['exec']) args += [current_channel.strip()] self.proc = subprocess.Popen(args, shell=True) return # don't use xterm for vlc, totem if (self.rbMplayer.isChecked()): if not is_win32 and not is_osx: args += ['xterm', '-geometry', '45x8-20+150', '-e'] self.is_sopcast = current_channel.lower().startswith('sop://') if self.is_sopcast: if start_sopcast_server: # args_sopcast = ['xterm', '-geometry', '45x8-20+400', '-e', sopcast_binary, current_channel, SOPCAST_LISTEN_PORT, SOPCAST_SERVER_PORT] try: print 'Waiting for sopcast server starup at %s ...' % current_channel self.proc_sopcast = run_command_in_new_terminal( sopcast_binary, current_channel, SOPCAST_LISTEN_PORT, SOPCAST_SERVER_PORT) # except Exception as e: show_gui_error(e, """ERROR! Sopcast executable not found or other error: To install sopcast support on Linux, run: %s""" % (SOPCAST_INSTALL_HOWTO)) return current_channel = SOPCAST_SERVER_URL time.sleep(SOPCAST_SERVER_WAIT_SECS) if self.rbMplayer.isChecked(): if is_win32: args = ['cmd', '/c', MPLAYER_PATH_WIN32, '-cache-min', CACHE_SIZE_MIN, '-cache', self.cache_size] else: args += [MPLAYER, '-cache-min', CACHE_SIZE_MIN, '-cache', self.cache_size] self.on_top and args.append('-ontop') self.cbFullScreen.isChecked() and args.append('-fs') self.cbPlaylistFlag.isChecked() and args.append('-playlist') #elif self.rbGstreamer.isChecked(): # args.append('gst123') # if '.m3u' in current_channel: # current_channel = getFirstUrl(current_channel) elif self.rbVlc.isChecked(): if is_win32: if os.path.exists(VLC_PATH_WIN32): args = [VLC_PATH_WIN32] elif os.path.exists(VLC_PATH_WIN32_CUSTOM): args = [VLC_PATH_WIN32_CUSTOM] elif is_osx: args = [VLC_PATH_OSX]#, '--one-instance'] else: args = ['vlc']#, '--one-instance'] # if vlc_remote_command('testing if vlc remote is running...'): # # print 'VLC Remote Control not running, starting new VLC instance...' # vlc_remote_command('add %s' % current_channel) # vlc_remote_command('volume 150') # return # else: # print 'VLC Remote Control not running, starting new VLC instance...' self.cbFullScreen.isChecked() and args.append('--fullscreen') args.append('--video-on-top') elif self.rbTotem.isChecked(): args += ['totem', '--replace'] # FIXME!!! totem segfaults when started with the --fullscreen switch # self.cbFullScreen.isChecked() and args.append('--fullscreen') elif self.rbBrowser.isChecked(): open_webbrowser(current_channel) return args.append(current_channel) print args try: if is_win32: #self.proc = subprocess.Popen(args, creationflags=subprocess.STARTF_USESHOWWINDOW, cwd=os.path.dirname(sys.argv[0])) ## TODO: get right options on win32 #http://stackoverflow.com/questions/7006238/how-do-i-hide-the-console-when-i-use-os-system-or-subprocess-call #startupinfo = subprocess.STARTUPINFO() #startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW #subprocess.call('taskkill /F /IM exename.exe', startupinfo=startupinfo) self.proc = subprocess.Popen(args, shell=True, cwd=os.path.dirname(sys.argv[0])) else: self.proc = subprocess.Popen(args, stdout=subprocess.PIPE, stdin=subprocess.PIPE) print 'DBG:', type(self.proc), self.proc # console_data = self.proc.stdout.read() # self.logWindow.setText(console_data) except Exception as e: show_gui_error(e, "ERROR! Selected player not available:\n") def kill_proc(self): if self.cbInhibitScreensaver.isChecked(): resume_screensaver() if self.proc and not self.rbVlc.isChecked(): try: self.proc.kill() except: pass if self.is_sopcast and self.proc_sopcast: try: self.proc_sopcast.kill() os.system('killall sopcast') except: pass def readSettings(self): # store settings object self.settings = QSettings(QSettings.IniFormat, QSettings.UserScope, "xh", "chanchan") pos = self.settings.value("pos", QVariant(QPoint(200, 200))).toPoint() size = self.settings.value("size", QVariant(QSize(400, 400))).toSize() self.resize(size) self.move(pos) self.chanells_path = self.settings.contains('channels_file') and str(self.settings.value("channels_file").toString()) or get_default_channels_path() self.is_inhibit_screen = self.settings.contains('inhibit_screen') and self.settings.value("inhibit_screen").toBool() self.is_full_screen = self.settings.contains('fullscreen') and self.settings.value("fullscreen").toBool() self.haveSeenFirstTime = self.settings.contains('seen_first_time') and self.settings.value("seen_first_time").toBool() def writeSettings(self): settings = QSettings(QSettings.IniFormat, QSettings.UserScope, "xh", "chanchan") settings.setValue("pos", QVariant(self.pos())) settings.setValue("size", QVariant(self.size())) settings.setValue("channels_file", QVariant(self.chanells_path)) settings.setValue("inhibit_screen", QVariant(self.cbInhibitScreensaver.isChecked())) settings.setValue("fullscreen", QVariant(self.cbFullScreen.isChecked())) settings.setValue("seen_first_time", QVariant(self.haveSeenFirstTime)) settings.sync()
class AddWordWidget(QDialog): def __init__(self, parent=None): super(AddWordWidget, self).__init__(parent=parent) self.setWindowTitle('Add word') self.create_layout() self.create_connections() def create_layout(self): hbox = QHBoxLayout() vbox = QVBoxLayout() vbox.addWidget(QLabel("Dictionary")) vbox.addWidget(QLabel("Original")) vbox.addWidget(QLabel("Translation")) vbox.addWidget(QLabel("Phoneme")) vbox.addWidget(QLabel("Parts of Speech")) vbox.addWidget(QLabel("Synonyms")) vbox.addWidget(QLabel("Antonyms")) hbox.addLayout(vbox) vbox = QVBoxLayout() self.dictionaries = Dictionary.objects.all() self.dictionary = QComboBox() self.dictionary.addItems([d.name for d in self.dictionaries]) vbox.addWidget(self.dictionary) self.original = QLineEdit() vbox.addWidget(self.original) self.translation = QLineEdit() vbox.addWidget(self.translation) self.phoneme = QLineEdit() vbox.addWidget(self.phoneme) self.pos = QComboBox() self.pos.addItems([p.strip() for p in self.dictionaries[0].pos.split(',') if len(p) > 0]) vbox.addWidget(self.pos) self.synonyms = QLineEdit() vbox.addWidget(self.synonyms) self.antonyms = QLineEdit() vbox.addWidget(self.antonyms) hbox.addLayout(vbox) vbox = QVBoxLayout() vbox.addLayout(hbox) vbox.addWidget(QLabel("Description")) self.description = QTextEdit() vbox.addWidget(self.description) self.add_button = QPushButton("&Add") self.close_button = QPushButton("&Close") hbox = QHBoxLayout() hbox.addStretch() hbox.addWidget(self.add_button) hbox.addWidget(self.close_button) vbox.addLayout(hbox) self.status = QLabel('Add a new word to a dictionary.') vbox.addWidget(self.status) self.setLayout(vbox) def create_connections(self): self.connect(self.dictionary, SIGNAL("currentIndexChanged(int)"), self.change_pos) self.connect(self.close_button, SIGNAL("clicked()"), self.close) self.connect(self.add_button, SIGNAL("clicked()"), self.add_word) def change_pos(self, index): current_dict = self.dictionaries[index] self.pos.clear() self.pos.addItems([p.strip() for p in current_dict.pos.split(',') if len(p) > 0]) def get_texts(self): current_dict = self.dictionaries[self.dictionary.currentIndex()].abbrev original = unicode(self.original.text()).strip() translation = unicode(self.translation.text()).strip() phoneme = unicode(self.phoneme.text()).strip() pos = unicode(self.pos.currentText()).strip() synonyms = unicode(self.synonyms.text()).strip() antonyms = unicode(self.antonyms.text()).strip() description = unicode(self.description.toPlainText()).strip() if not all([original, translation, pos]): self.status.setText('There was an error inserting the word. Please' ' try again.') QMessageBox.critical(self, "Error", "You must enter at least " "'Original', 'Translation' and 'Parts of " "Speech'.") return None return dict(dictionary=current_dict, original=original, translation=translation, phoneme=phoneme, pos=pos, synonyms=synonyms, antonyms=antonyms, description=description) def clear_texts(self): self.translation.clear() self.phoneme.clear() self.synonyms.clear() self.antonyms.clear() self.description.clear() self.original.setFocus() def add_word(self): self.status.clear() texts = self.get_texts() if not texts: return word = Word(**texts) word.save() self.clear_texts() self.status.setText('Word %s has been added successfully.' % word.original) self.words_widget.load_words() def save_word(self): self.status.clear() texts = self.get_texts() if not texts: return word = self.word word.dictionary = texts['dictionary'] word.original = texts['original'] word.translation = texts['translation'] word.phoneme = texts['phoneme'] word.pos = texts['pos'] word.synonyms = texts['synonyms'] word.antonyms = texts['antonyms'] word.description = texts['description'] word.save() self.status.setText('Word %s has been saved successfully' % word.original) self.words_widget.load_words() def get_word(self): return self._word def set_word(self, word): self._word = word self.setWindowTitle("Edit %s" % word.original) self.add_button.setText("&Save") self.disconnect(self.add_button, SIGNAL("clicked()"), self.add_word) if word.exported: self.add_button.setEnabled(False) self.status.setText('This word has been exported already. ' 'You cannot save the changes to it.') else: self.connect(self.add_button, SIGNAL("clicked()"), self.save_word) self.status.setText('Edit this word and save to your dictionary.') for i, d in enumerate(self.dictionaries): if d.abbrev == word.dictionary: self.dictionary.setCurrentIndex(i) break self.original.setText(word.original) self.translation.setText(word. translation) self.phoneme.setText(word.phoneme) self.synonyms.setText(word.synonyms) self.antonyms.setText(word.antonyms) self.description.setText(word.description) for i in range(self.pos.count()): if self.pos.itemText(i) == word.pos: self.pos.setCurrentIndex(i) break word = property(get_word, set_word)
class TagCompleterWidget(QObject): """ widget in lineEdit-style with integrated qcompleter """ def __init__(self, max_tags, expiry_prefix=None, tag_list=None, parent=None, separator=",", show_datestamp=False): QWidget.__init__(self, parent) self.__completer_active = False self.__max_tags = max_tags self.__tag_separator = separator self.__tag_list = tag_list self.__parent = parent self.__tag_line = QLineEdit(self.__parent) #self.__tag_line = TagLineEdit(self.__parent) self.__show_datestamp = show_datestamp self.__datestamp_format = TsConstants.DATESTAMP_FORMAT_DAY self.__expiry_prefix = expiry_prefix ## flag, if the line should be checked of emptiness self.__check_not_empty = False self.__check_tag_limit = False self.__restricted_vocabulary = False ## the latest activated suggestion self.__activated_text = None # value of the actual datestamp self.__datestamp = None self.__datestamp_hidden = False self.__completer = QCompleter(self.__tag_list, self); self.__completer.setCaseSensitivity(Qt.CaseInsensitive) self.__completer.setWidget(self.__tag_line) #self.__handle_datestamp() self.connect(self.__tag_line, SIGNAL("textChanged(QString)"), self.__text_changed_by_user) self.connect(self.__completer, SIGNAL("activated(QString)"), self.__text_activated) self.connect(self.__completer, SIGNAL("highlighted(QString)"), self.__text_highlighted) def __text_highlighted(self, item_name): """ a suggestion has been selected in the dropdownbox """ # set this variable to True just to know, that # this value comes from the completer and not from the user self.__completer_active = True self.__text_selected(item_name) self.__completer_active = False def __handle_datestamp(self, is_hidden): """ if the show_datestamp flag is set to True, provide an automatic datestamp on the tagline """ if self.__show_datestamp: self.__datestamp = time.strftime(self.__datestamp_format) if not is_hidden: self.__tag_line.clear() self.__tag_line.setText(self.__datestamp) def set_datestamp_format(self, format, is_hidden): self.__datestamp_format = format self.__datestamp_hidden = is_hidden self.__handle_datestamp(is_hidden) def show_datestamp(self, show): self.__show_datestamp = show self.__handle_datestamp(show) def clear_line(self): """ clear the tagline ... if auto datestamp is set to "on" a fresh stamp will be placed into the tagline """ self.__tag_line.clear() if self.__show_datestamp: self.__handle_datestamp(self.__datestamp_hidden) def set_check_not_empty(self, check_necessary): """ set this to True, if there should be sent a signal that indicates that the tagline is not empty anymore """ self.__check_not_empty = True def set_restricted_vocabulary(self, is_restricted): """ use True/False to turn the restricted function on/off """ self.__restricted_vocabulary = is_restricted def select_line(self): """ select the tagline ... """ self.__tag_line.selectAll() self.__tag_line.setFocus(QtCore.Qt.OtherFocusReason) def __text_changed_by_user(self, text): # create a QByteArray in utf8 all_text = text.toUtf8() # make a python string out of it all_text = str(all_text) # convert the python string tu unicode utf-8 all_text = unicode(all_text, "utf-8") if self.__check_not_empty: if all_text is not None and all_text != "": self.emit(QtCore.SIGNAL("line_empty"), False) else: self.emit(QtCore.SIGNAL("line_empty"), True) text = all_text[:self.__tag_line.cursorPosition()] ## remove whitespace and filter out duplicates by using a set tag_set = set([]) for tag in all_text.split(self.__tag_separator): strip_tag = tag.strip() if strip_tag != "": tag_set.add(strip_tag) max_tags = self.__max_tags if self.__datestamp_hidden: max_tags = max_tags - 1; ## do not proceed if the max tag count is reached if len(tag_set) > max_tags: self.emit(QtCore.SIGNAL("tag_limit_reached"), True) self.__check_tag_limit = True return else: if self.__check_tag_limit: self.emit(QtCore.SIGNAL("tag_limit_reached"), False) self.__check_tag_limit = False prefix = text.split(self.__tag_separator)[-1].strip() if not self.__completer_active: self.__update_completer(tag_set, prefix) def __update_completer(self, tag_set, completion_prefix): if self.__tag_list is None: return tags = list(set(self.__tag_list).difference(tag_set)) #tags = list(self.__tag_list) model = QStringListModel(tags, self) self.__completer.setModel(model) self.__completer.setCompletionPrefix(completion_prefix) if self.__restricted_vocabulary: self.__check_vocabulary(tag_set, completion_prefix) if completion_prefix.strip() != '': ## use the default completion algorithm self.__completer.complete() def __check_finished_tags(self, typed_tags_list): """ use this method to control all typed tags. this means all tags terminated with a comma """ pass def __check_in_completion_list(self, tag): """ if a written tag equals a tag of the completion list - the tag will be removed from the completion list so the completer will return a completion count of 0 for this tag. in this case there would be displayed an error message at the dialog (when controlled vocab is activated) so check manually, if the provided tag is contained in the suggestion_list """ #for sug_tag in self.__tag_list: # if sug_tag == tag: # return True #return False return tag in self.__tag_list def __check_vocabulary(self, tag_set, completion_prefix): """ have a look at the entered tag to be completed. if restricted vocabulary is turned on: datestamps do not have to be checked. """ not_allowed_tags_count = 0 no_completion_found = False stripped_text = unicode(self.__tag_line.text()).strip() ##when a tag separator is on the last position, there should have been entered a new tag ##check this tag for its correctness if len(stripped_text) > 0: ##check if all written tags are allowed (incl. datestamps an expiry tags) for tag in tag_set: ## tag can be a datestamp -> OK if not SpecialCharHelper.is_datestamp(tag) and tag != "": ## tag can be an expiry tag -> OK # if self.__expiry_prefix is not None and not SpecialCharHelper.is_expiry_tag(self.__expiry_prefix, tag): if self.__expiry_prefix is None or not SpecialCharHelper.is_partial_expiry_tag(self.__expiry_prefix, tag): if unicode(tag) not in self.__tag_list: not_allowed_tags_count += 1 if(completion_prefix.strip() == ""): ## if the prefix is an empty string - manually set the completion_count to 0 ## because the completer would return the whole number of tags in its suggestion list completion_count = 0 else: completion_count = self.__completer.completionCount() if self.__restricted_vocabulary and completion_count == 0: ## additionally check if the prefix equals a tag from the suggestion list ## this has to be done, because we do not get a completionCount > 0 if the prefix equals a given tag #if completion_prefix not in self.__tag_list: if completion_prefix is not None and len(completion_prefix) > 0 and completion_prefix.strip() != "": ## just send the signal if the tag is no datestamp AND if it is no full tag if not SpecialCharHelper.is_datestamp(completion_prefix) and not self.__check_in_completion_list(completion_prefix): if not SpecialCharHelper.is_partial_expiry_tag(self.__expiry_prefix, completion_prefix): no_completion_found = True ## there are tags (terminated with comma) which are not in the allowed tag_list if not_allowed_tags_count > 1: self.emit(QtCore.SIGNAL("no_completion_found"), True) return if not_allowed_tags_count > 0: ## in this case the user has entered a not allowed tag and terminated it with a comma to mark it as a tag ## the completion count is 0 because there is nothing after the last comma in the taglist if completion_count == 0: self.emit(QtCore.SIGNAL("no_completion_found"), True) return ## it could be the case, that the user is still typing an allowed tag ## so check, if the completer has a possible completion ## if not -> send the signal if no_completion_found: self.emit(QtCore.SIGNAL("no_completion_found"), True) return ## everytime there is no completion found, emit the signal elif no_completion_found: self.emit(QtCore.SIGNAL("no_completion_found"), True) return ## in this case everything is fine self.emit(QtCore.SIGNAL("no_completion_found"), False) def __text_selected(self, text): self.__activated_text = text cursor_pos = self.__tag_line.cursorPosition() before_text = unicode(self.__tag_line.text())[:cursor_pos] #after_text = unicode(self.__tag_line.text())[cursor_pos:] prefix_len = len(before_text.split(self.__tag_separator)[-1].strip()) self.__tag_line.setText("%s%s" % (before_text[:cursor_pos - prefix_len], text)) self.__tag_line.setCursorPosition(cursor_pos - prefix_len + len(text) + 2) def __text_activated(self, text): """ a suggestion has been choosen by the user """ self.__text_selected(text) self.emit(QtCore.SIGNAL("activated")) def get_tag_list(self): tag_string = unicode(self.__tag_line.text()) result = set([]) tag_list = tag_string.split(self.__tag_separator) for tag in tag_list: strip_tag = tag.strip() if strip_tag != "": result.add(strip_tag) # if the datestamp is hidden, add it manually to the taglist if self.__datestamp_hidden: result.add(self.__datestamp) return result def get_tag_line(self): return self.__tag_line def get_completer(self): return self.__completer def set_enabled(self, enable): self.__tag_line.setEnabled(enable) def set_text(self, text): self.__tag_line.setText(text) def set_tag_completion_list(self, tag_list): self.__tag_list = tag_list self.__completer.setModel(QtGui.QStringListModel(QtCore.QStringList(tag_list))) def get_tag_completion_list(self): return self.__tag_list def is_empty(self): if self.__tag_line.text() == "": return True else: return False def set_place_holder_text(self, text): self.__tag_line.setPlaceholderText(text)
class MainWindow(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.sync_delay = 5 self.sync_active = False self.verbose = False self.timePattern = re.compile('\.[0-9]+$') self.setWindowTitle('%s %s' % (QApplication.applicationName(), QApplication.applicationVersion())); self.widget = QWidget() self.setCentralWidget(self.widget) self.statusBar = QStatusBar(self) self.setStatusBar(self.statusBar) self.mAction = self.menuBar().addMenu(self.tr("&Action")) #self.mAction.addAction(self.tr("&update"), self.updateTplTable(), QKeySequence('F5')) self.mAction.addAction(self.tr('&import records'), self.onImport, QKeySequence('F6')) self.mAction.addAction(self.tr('edit &settings'), self.onSettings, QKeySequence('F8')) self.mAction.addAction(self.tr("e&xit"), self.onExit, 'Ctrl+Q') self.mAbout = self.menuBar().addMenu(self.tr("&about")) self.mAbout.addAction(QApplication.applicationName(), self.onAboutAppAction) self.mAbout.addAction("Qt", self.onAboutQtAction) self.pageForwardButton = QPushButton(self) self.pageForwardButton.setText('>') self.connect(self.pageForwardButton, SIGNAL('clicked()'), self.pageForward) self.pageBackwardButton = QPushButton(self) self.pageBackwardButton.setText('<') self.connect(self.pageBackwardButton, SIGNAL('clicked()'), self.pageBackward) self.timer = QTimer(self) self.timer.setInterval(1000) self.connect(self.timer, SIGNAL('timeout()'), self, SLOT('onTimer()')) self.time_begin = datetime.now() self.time_end = datetime.now() self.db_path = os.path.join(os.path.dirname(sys.argv[0]) if os.name != 'posix' else os.path.expanduser('~'), '.tt2.db') self.db = sqlite3.connect(self.db_path) self.cursor = self.db.cursor() try: self.cursor.execute('SELECT id FROM tt LIMIT 1') except: self.createDb() self.settings = self.fetchSettings() self.syncer = Syncer(self.db_path, self) self.connect( self.syncer, SIGNAL('active'), self.setSyncerActive ) self.connect( self.syncer, SIGNAL('message'), self.msg ) self.connect( self.syncer, SIGNAL('newSettings'), self.fetchSettings ) self.layout = QGridLayout(self.widget) self.descriptionLabel = QLabel(self.widget) self.descriptionLabel.setText('Beschreibung') self.descriptionLabel.setMaximumHeight( self.font().pointSize() * 2 ) self.descriptionInput = QLineEdit(self.widget) self.updateDescriptionEditCompleter() self.noteLabel = QLabel(self.widget) self.noteLabel.setText('Notiz') self.noteLabel.setMaximumHeight( self.font().pointSize() * 2 ) self.noteInput = QLineEdit(self.widget) self.startStopButton = QPushButton(self.widget) self.startStopButton.setText('Start') self.tableView = TplTable(self, int( self.getSetting('displayrows', DEFAULTROWS) ) ) self.pageForwardAction = QAction(self) self.pageForwardAction.setShortcut(QKeySequence('Right')) self.connect(self.pageForwardAction, SIGNAL('triggered()'), self.pageForward); self.pageForwardButton.addAction(self.pageForwardAction) self.pageBackwardAction = QAction(self) self.pageBackwardAction.setShortcut(QKeySequence('Left')) self.connect(self.pageBackwardAction, SIGNAL('triggered()'), self.pageBackward); self.pageBackwardButton.addAction(self.pageBackwardAction) self.updateTplTable() self.layout.addWidget(self.descriptionLabel, 0, 0, 1, 1) self.layout.addWidget(self.descriptionInput, 1, 0, 1, 1) self.layout.addWidget(self.noteLabel, 0, 1, 1, 1) self.layout.addWidget(self.noteInput, 1, 1, 1, 1) self.layout.addWidget(self.startStopButton, 2, 0, 1, 2) self.layout.addWidget(self.tableView, 3,0,1,2) self.layout.addWidget(self.pageBackwardButton, 4, 0, 1, 1) self.layout.addWidget(self.pageForwardButton, 4, 1, 1, 1) self.connect(self.descriptionInput, SIGNAL('returnPressed ()'), self.onStartStop ) self.connect(self.noteInput, SIGNAL('returnPressed ()'), self.onStartStop ) self.connect(self.startStopButton, SIGNAL('clicked()'), self.onStartStop ) self.connect(self.tableView, SIGNAL('valueChanged(int)'), self.onValueChanged ) self.connect(self.tableView, SIGNAL('del(int)'), self.onDelete ) self.last_sync = datetime.now() self.sync() def __del__(self): pass def setSyncerActive(self, active): if not active: self.last_sync = datetime.now() self.sync_active = active def msg(self, msg, timeout = 0): #print(msg) self.statusBar.showMessage(msg, timeout) def sync(self): if self.getSetting('syncEnabled','False') == 'False': return # reset delay if still active if self.sync_active: self.last_sync = datetime.now() if datetime.now() < ( self.last_sync + timedelta( seconds = self.sync_delay ) ): try: #print 'cancel' self.t.cancel() except: pass #print 'start +',( self.last_sync + timedelta( seconds = self.sync_delay ) - datetime.now() ).seconds + 1 self.t = Timer( ( self.last_sync + timedelta( seconds = self.sync_delay ) - datetime.now() ).seconds + 1 ,self.sync) self.t.start() else: # print 'start syncer instance' Thread(target=self.syncer.do_sync).start() def createDb(self): try: self.q('''CREATE TABLE tt ( id INTEGER PRIMARY KEY AUTOINCREMENT, remote_id INTEGER, time_begin INTEGER, time_end INTEGER, description STRING, note STRING DEFAULT "", is_new INTEGER DEFAULT 1, need_update INTEGER DEFAULT 0, is_delete INTEGER DEFAULT 0 )''') self.q('''CREATE TABLE settings ( key STRING UNIQUE, value STRING )''') self.q('CREATE INDEX idx_time_begin ON tt (time_begin)') except: self.statusBar.showMessage('error creating Database!') else: self.statusBar.showMessage('Table tt created successfully') def q(self, query): try: self.cursor.execute(query) except Exception as e: print( e ) self.statusBar.showMessage('query execution failed "%s"' % query) else: self.db.commit() def updateTplTable(self): self.q('SELECT id,time_begin,time_end,description,note FROM tt WHERE is_delete != 1 ORDER BY time_begin DESC LIMIT %d' % ( int( self.getSetting( 'displayrows', DEFAULTROWS ) ) ) ) self.tableView.set(self.cursor.fetchall()) def updateDescriptionEditCompleter(self): self.q('SELECT DISTINCT description FROM tt WHERE is_delete != 1') #words = QStringList() words = [] for word in self.cursor.fetchall(): words.append(str(word[0])) self.descriptionInput.setCompleter(QCompleter(words, self)) @pyqtSlot() def pageForward(self): self.q('SELECT MIN(time_begin) FROM tt') if not self.tableView.getLastTime() == self.cursor.fetchone()[0]: sql = 'SELECT id,time_begin,time_end,description,note FROM tt WHERE is_delete != 1 AND time_begin < %d ORDER BY time_begin DESC LIMIT %s' % ( self.tableView.getLastTime(), int( self.getSetting( 'displayrows', DEFAULTROWS ) ) ) if self.verbose: print( sql ) self.q( sql ) self.tableView.set(self.cursor.fetchall()) @pyqtSlot() def pageBackward(self): self.q('SELECT MAX(time_begin) FROM tt') if not self.tableView.getFirstTime() == self.cursor.fetchone()[0]: sql = 'SELECT * FROM ( SELECT id,time_begin,time_end,description,note FROM tt WHERE is_delete != 1 AND time_begin > %d ORDER BY time_begin LIMIT %s ) as tbl ORDER BY time_begin DESC' % ( self.tableView.getFirstTime(), int( self.getSetting( 'displayrows', DEFAULTROWS ) ) ) if self.verbose: print( sql ) self.q( sql ) self.tableView.set(self.cursor.fetchall()) @pyqtSlot() def onExit(self): QApplication.exit(); @pyqtSlot() def onValueChanged(self, _id): if self.verbose: print('changed:', _id) print(self.tableView.get(_id)) data = self.tableView.get(_id) self.q(''' UPDATE tt SET time_begin = %d, time_end = %d, description = '%s', note = '%s', need_update = 1 WHERE id = %d ''' % ( data[1], data[2], data[3], data[4], data[0] )) self.updateDescriptionEditCompleter() self.sync() @pyqtSlot() def onDelete(self, _id): if self.verbose: print('del:', _id,self.tableView.get(_id)[0]) self.q('UPDATE tt SET is_delete = 1 WHERE id = %d' % self.tableView.get(_id)[0]) self.updateTplTable() self.updateDescriptionEditCompleter() self.sync() @pyqtSlot() def onTimer(self): self.startStopButton.setText('Stop (%s)' % self.timePattern.sub( '', str( datetime.now() - self.time_begin ) ) ) @pyqtSlot() def onStartStop(self): if self.timer.isActive(): self.timer.stop() self.time_end = datetime.now() self.q(''' INSERT INTO tt (time_begin,time_end,description,note) VALUES ('%d','%d','%s','%s') ''' % ( int(mktime(self.time_begin.timetuple())), int(mktime(self.time_end.timetuple())), self.descriptionInput.text(), self.noteInput.text() )) self.noteInput.clear() self.updateTplTable() self.updateDescriptionEditCompleter() self.startStopButton.setText('Start') self.sync() else: self.time_begin = datetime.now() self.timer.start() self.onTimer() def onAboutAppAction(self): QMessageBox.about(self, self.tr("&about"), self.tr("%1 version %2").arg(QApplication.applicationName()).arg(QApplication.applicationVersion())) def onAboutQtAction(self): QMessageBox.aboutQt(self, self.tr("&about")) def checkSync(self): if self.sync_active: QMessageBox.information(self, 'Information', '''Sync is currently active. Please wait until it's finished''') return False else: return True def onSettings(self): if not self.checkSync(): return settings = self.fetchSettings() inp = SettingsWidget(settings, self) if inp.exec_(): for key in inp.data(): if type( inp.data()[key] ) == bytes: value = inp.data()[key].decode( 'UTF-8' ) else: value = inp.data()[key] self.q( '''REPLACE INTO settings VALUES ('%s','%s')''' % ( key, value ) ) try: dr = settings['displayrows'] except: dr = None if dr != inp.data()['displayrows']: QMessageBox.information(self, 'displayrows changed...', 'exiting now.') sys.exit(0) self.settings = self.fetchSettings() def onImport(self): if not self.checkSync(): return ImportWidget( self.db_path, self ).exec_() self.updateTplTable() self.updateDescriptionEditCompleter() def fetchSettings(self): s = {} self.q( 'SELECT key,value FROM settings' ) for key,value in self.cursor.fetchall(): s[key] = value return s def getSetting(self,key,default = None): try: v = self.settings[key] except: if default != None: v = default else: v = '' return v
class SVNPluginPropsDialog( QDialog ): " SVN plugin properties dialog " def __init__( self, plugin, client, path, parent = None ): QDialog.__init__( self, parent ) self.__plugin = plugin self.__client = client self.__path = path self.__createLayout() self.setWindowTitle( "SVN Properties of " + path ) self.__populate() self.__propsView.setFocus() return def __populate( self ): " Populate the properties list " # Get the currently selected name selectedName = None selected = list( self.__propsView.selectedItems() ) if selected: selectedName = str( selected[ 0 ].text( 0 ) ) self.__propsView.clear() properties = readProperties( self.__client, self.__path ) if properties: for itemPath, itemProps in properties: if self.__path == itemPath or \ self.__path == itemPath + os.path.sep: for name, value in itemProps.iteritems(): name = str( name ).strip() value = str( value ).strip() newItem = QTreeWidgetItem( [ name, value ] ) self.__propsView.addTopLevelItem( newItem ) self.__resizePropsView() self.__sortPropsView() if selectedName: index = 0 for index in xrange( 0, self.__propsView.topLevelItemCount() ): item = self.__propsView.topLevelItem( index ) if selectedName == item.text( 0 ): item.setSelected( True ) return def __resizePropsView( self ): " Resizes the properties table " self.__propsView.header().setStretchLastSection( True ) self.__propsView.header().resizeSections( QHeaderView.ResizeToContents ) return def __sortPropsView( self ): " Sorts the properties table " self.__propsView.sortItems( self.__propsView.sortColumn(), self.__propsView.header().sortIndicatorOrder() ) return def __createLayout( self ): " Creates the dialog layout " self.resize( 640, 480 ) self.setSizeGripEnabled( True ) vboxLayout = QVBoxLayout( self ) hLayout = QHBoxLayout() self.__propsView = QTreeWidget() self.__propsView.setAlternatingRowColors( True ) self.__propsView.setRootIsDecorated( False ) self.__propsView.setItemsExpandable( False ) self.__propsView.setSortingEnabled( True ) self.__propsView.setItemDelegate( NoOutlineHeightDelegate( 4 ) ) self.__propsView.itemSelectionChanged.connect( self.__propsSelectionChanged ) propsViewHeader = QTreeWidgetItem( [ "Property Name", "Property Value" ] ) self.__propsView.setHeaderItem( propsViewHeader ) self.__propsView.header().setSortIndicator( 0, Qt.DescendingOrder ) hLayout.addWidget( self.__propsView ) self.__delButton = QToolButton() self.__delButton.setText( "Delete" ) self.__delButton.setFocusPolicy( Qt.NoFocus ) self.__delButton.setEnabled( False ) self.__delButton.clicked.connect( self.__onDel ) hLayout.addWidget( self.__delButton, 0, Qt.AlignBottom ) vboxLayout.addLayout( hLayout ) # Set property part setGroupbox = QGroupBox( self ) setGroupbox.setTitle( "Set Property" ) setLayout = QGridLayout( setGroupbox ) setLayout.addWidget( QLabel( "Name" ), 0, 0, Qt.AlignTop | Qt.AlignRight ) setLayout.addWidget( QLabel( "Value" ), 1, 0, Qt.AlignTop | Qt.AlignRight ) self.__nameEdit = QLineEdit() self.__nameEdit.textChanged.connect( self.__nameChanged ) setLayout.addWidget( self.__nameEdit, 0, 1 ) self.__valueEdit = QTextEdit() self.__valueEdit.setAcceptRichText( False ) self.__valueEdit.textChanged.connect( self.__valueChanged ) metrics = QFontMetrics( self.__valueEdit.font() ) rect = metrics.boundingRect( "X" ) self.__valueEdit.setFixedHeight( rect.height() * 4 + 5 ) setLayout.addWidget( self.__valueEdit, 1, 1 ) self.__setButton = QToolButton() self.__setButton.setText( "Set" ) self.__setButton.setFocusPolicy( Qt.NoFocus ) self.__setButton.setEnabled( False ) self.__setButton.clicked.connect( self.__onSet ) setLayout.addWidget( self.__setButton, 1, 2, Qt.AlignBottom | Qt.AlignHCenter ) sizePolicy = QSizePolicy( QSizePolicy.Expanding, QSizePolicy.Maximum ) sizePolicy.setHorizontalStretch( 0 ) sizePolicy.setVerticalStretch( 0 ) sizePolicy.setHeightForWidth( setGroupbox.sizePolicy().hasHeightForWidth() ) setGroupbox.setSizePolicy( sizePolicy ) vboxLayout.addWidget( setGroupbox ) # Buttons at the bottom buttonBox = QDialogButtonBox( self ) buttonBox.setOrientation( Qt.Horizontal ) buttonBox.setStandardButtons( QDialogButtonBox.Ok ) buttonBox.button( QDialogButtonBox.Ok ).setDefault( True ) buttonBox.accepted.connect( self.close ) vboxLayout.addWidget( buttonBox ) return def __onSet( self ): " Triggered when propery set is clicked " name = self.__nameEdit.text().strip() value = self.__valueEdit.toPlainText().strip() try: commitInfo = self.__client.propset( name, value, self.__path ) if commitInfo: logging.info( str( commitInfo ) ) self.__populate() self.__plugin.notifyPathChanged( self.__path ) self.__nameEdit.clear() self.__valueEdit.clear() self.__propsView.setFocus() except pysvn.ClientError, exc: message = exc.args[ 0 ] logging.error( message ) return except Exception, exc: logging.error( str( exc ) ) return
class MainWindow(QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.fnames = [] # list of file names to be converted self.office_listener_started = False self.parse_cla() addQPB = QPushButton(self.tr('Add')) delQPB = QPushButton(self.tr('Delete')) clearQPB = QPushButton(self.tr('Clear')) vlayout1 = utils.add_to_layout('v', addQPB, delQPB, clearQPB, None) self.filesList = utils.FilesList() self.filesList.setSelectionMode(QAbstractItemView.ExtendedSelection) hlayout1 = utils.add_to_layout('h', self.filesList, vlayout1) outputQL = QLabel(self.tr('Output folder:')) self.toQLE = QLineEdit() self.toQLE.setReadOnly(True) self.toQTB = QToolButton() self.toQTB.setText('...') hlayout2 = utils.add_to_layout('h', outputQL, self.toQLE, self.toQTB) self.audiovideo_tab = AudioVideoTab(self) self.image_tab = ImageTab(self) self.document_tab = DocumentTab(self) self.tabs = [self.audiovideo_tab, self.image_tab, self.document_tab] tab_names = [self.tr('Audio/Video'), self.tr('Images'), self.tr('Documents')] self.tabWidget = QTabWidget() for num, tab in enumerate(tab_names): self.tabWidget.addTab(self.tabs[num], tab) self.tabWidget.setCurrentIndex(0) self.origQCB = QCheckBox( self.tr('Save each file in the same\nfolder as input file')) self.deleteQCB = QCheckBox(self.tr('Delete original')) convertQPB = QPushButton(self.tr('&Convert')) hlayout3 = utils.add_to_layout('h', self.origQCB, self.deleteQCB, None) hlayout4 = utils.add_to_layout('h', None, convertQPB) final_layout = utils.add_to_layout( 'v', hlayout1, self.tabWidget, hlayout2, hlayout3, hlayout4) self.dependenciesQL = QLabel() self.statusBar().addPermanentWidget(self.dependenciesQL, stretch=1) widget = QWidget() widget.setLayout(final_layout) self.setCentralWidget(widget) openAction = utils.create_action( self, self.tr('Open'), QKeySequence.Open, None, self.tr('Open a file'), self.add_files ) convertAction = utils.create_action( self, self.tr('Convert'), 'Ctrl+C', None, self.tr('Convert files'), self.start_conversion ) quitAction = utils.create_action( self, self.tr('Quit'), 'Ctrl+Q', None, self.tr('Quit'), self.close ) edit_presetsAction = utils.create_action( self, self.tr('Edit Presets'), 'Ctrl+P', None, self.tr('Edit Presets'), self.open_dialog_presets ) importAction = utils.create_action( self, self.tr('Import'), None, None, self.tr('Import presets'), self.import_presets ) exportAction = utils.create_action( self, self.tr('Export'), None, None, self.tr('Export presets'), self.export_presets ) resetAction = utils.create_action( self, self.tr('Reset'), None, None, self.tr('Reset presets'), self.reset_presets ) syncAction = utils.create_action( self, self.tr('Synchronize'), None, None, self.tr('Synchronize presets'), self.sync_presets ) removeoldAction = utils.create_action( self, self.tr('Remove old'), None, None, self.tr('Remove old presets'), self.removeold_presets ) clearallAction = utils.create_action( self, self.tr('Clear All'), None, None, self.tr('Clear form'), self.clear_all ) preferencesAction = utils.create_action( self, self.tr('Preferences'), 'Alt+Ctrl+P', None, self.tr('Preferences'), self.open_dialog_preferences ) trackerAction = utils.create_action( self, 'Issue tracker', None, None, None, lambda: webbrowser.open( "https://github.com/Ilias95/FF-Multi-Converter/issues") ) wikiAction = utils.create_action( self, 'Wiki', None, None, None, lambda: webbrowser.open( "https://github.com/Ilias95/FF-Multi-Converter/wiki") ) ffmpegdocAction = utils.create_action( self, 'FFmpeg ' + self.tr('documentation'), None, None, None, lambda: webbrowser.open( "https://www.ffmpeg.org/documentation.html") ) imagemagickdocAction = utils.create_action( self, 'ImageMagick ' + self.tr('documentation'), None, None, None, lambda: webbrowser.open( "http://www.imagemagick.org/script/convert.php") ) aboutAction = utils.create_action( self, self.tr('About'), 'Ctrl+?', None, self.tr('About'), self.open_dialog_about ) fileMenu = self.menuBar().addMenu(self.tr('File')) editMenu = self.menuBar().addMenu(self.tr('Edit')) presetsMenu = self.menuBar().addMenu(self.tr('Presets')) helpMenu = self.menuBar().addMenu(self.tr('Help')) utils.add_actions( fileMenu, [openAction, convertAction, None, quitAction]) utils.add_actions( presetsMenu, [edit_presetsAction, importAction, exportAction, resetAction, None, syncAction, removeoldAction] ) utils.add_actions(editMenu, [clearallAction, None, preferencesAction]) utils.add_actions( helpMenu, [trackerAction, wikiAction, None, ffmpegdocAction, imagemagickdocAction, None, aboutAction] ) self.filesList.dropped.connect(self.add_files_dropped) addQPB.clicked.connect(self.add_files) delQPB.clicked.connect(self.delete_files) clearQPB.clicked.connect(self.clear_fileslist) self.tabWidget.currentChanged.connect( lambda: self.tabs[0].moreQPB.setChecked(False)) self.origQCB.toggled.connect( lambda: self.toQLE.setEnabled(not self.origQCB.isChecked())) self.toQTB.clicked.connect(self.open_dir) convertQPB.clicked.connect(convertAction.triggered) del_shortcut = QShortcut(self) del_shortcut.setKey(Qt.Key_Delete) del_shortcut.activated.connect(self.delete_files) self.setWindowTitle('FF Multi Converter') QTimer.singleShot(0, self.check_for_dependencies) QTimer.singleShot(0, self.load_settings) QTimer.singleShot(0, self.audiovideo_tab.set_default_command) QTimer.singleShot(0, self.update_filesList) def parse_cla(self): """Parse command line arguments.""" for i in QCoreApplication.argv()[1:]: i = os.path.abspath(i) if os.path.isfile(i): self.fnames.append(i) else: print("ffmulticonverter: {0}: Not a file".format(i)) def check_for_dependencies(self): """ Check if each one of the program dependencies are installed and update self.dependenciesQL with the appropriate message. """ self.vidconverter = None if utils.is_installed('ffmpeg'): self.vidconverter = 'ffmpeg' elif utils.is_installed('avconv'): self.vidconverter = 'avconv' self.unoconv = utils.is_installed('unoconv') self.imagemagick = utils.is_installed('convert') missing = [] if self.vidconverter is None: missing.append('ffmpeg/avconv') if not self.unoconv: missing.append('unoconv') if not self.imagemagick: missing.append('imagemagick') if missing: missing = ', '.join(missing) status = self.tr('Missing dependencies:') + ' ' + missing self.dependenciesQL.setText(status) def load_settings(self, onstart=True): """ Load settings values. onstart -- True means that this is the first time the method called, usually when program beggins """ def get_str_value(settings, name): value = settings.value(name) if value is not None: return value return '' settings = QSettings() self.overwrite_existing = utils.str_to_bool( get_str_value(settings, 'overwrite_existing')) self.default_output = get_str_value(settings, 'default_output') self.prefix = get_str_value(settings, 'prefix') self.suffix = get_str_value(settings, 'suffix') defcmd = get_str_value(settings, 'default_command') extraformats = get_str_value(settings, 'extraformats') videocodecs = settings.value('videocodecs') audiocodecs = settings.value('audiocodecs') if videocodecs is None: videocodecs = "\n".join(config.video_codecs) settings.setValue('videocodecs', videocodecs) if audiocodecs is None: audiocodecs = "\n".join(config.audio_codecs) settings.setValue('audiocodecs', audiocodecs) if defcmd: self.default_command = defcmd else: self.default_command = config.default_ffmpeg_cmd self.audiovideo_tab.fill_video_comboboxes( videocodecs, audiocodecs, extraformats) if onstart: self.toQLE.setText(self.default_output) def current_tab(self): """Return the corresponding object of the selected tab.""" for i in self.tabs: if self.tabs.index(i) == self.tabWidget.currentIndex(): return i def update_filesList(self): """Clear self.filesList and add to it all items of self.fname.""" self.filesList.clear() for i in self.fnames: self.filesList.addItem(i) def add_files(self): """ Get file names using a standard Qt dialog. Append to self.fnames each file name that not already exists and update self.filesList. """ # Create lists holding file formats extension. # To be passed in QFileDialog.getOpenFileNames(). all_files = '*' audiovideo_files = ' '.join( ['*.'+i for i in self.audiovideo_tab.formats]) img_formats = self.image_tab.formats[:] img_formats.extend(self.image_tab.extra_img) image_files = ' '.join(['*.'+i for i in img_formats]) document_files = ' '.join(['*.'+i for i in self.document_tab.formats]) formats = [all_files, audiovideo_files, image_files, document_files] strings = [self.tr('All Files'), self.tr('Audio/Video Files'), self.tr('Image Files'), self.tr('Document Files')] filters = '' for string, extensions in zip(strings, formats): filters += string + ' ({0});;'.format(extensions) filters = filters[:-2] # remove last ';;' fnames = QFileDialog.getOpenFileNames(self, 'FF Multi Converter - ' + self.tr('Choose File'), config.home, filters) if fnames: for i in fnames: if not i in self.fnames: self.fnames.append(i) self.update_filesList() def add_files_dropped(self, links): """ Append to self.fnames each file name that not already exists and update self.filesList. """ for path in links: if os.path.isfile(path) and not path in self.fnames: self.fnames.append(path) self.update_filesList() def delete_files(self): """ Get selectedItems of self.filesList, remove them from self.fnames and update the filesList. """ items = self.filesList.selectedItems() if items: for i in items: self.fnames.remove(i.text()) self.update_filesList() def clear_fileslist(self): """Make self.fnames empty and update self.filesList.""" self.fnames = [] self.update_filesList() def clear_all(self): """Clear all values of graphical widgets.""" self.toQLE.clear() self.origQCB.setChecked(False) self.deleteQCB.setChecked(False) self.clear_fileslist() self.audiovideo_tab.clear() self.image_tab.clear() def open_dir(self): """ Get a directory name using a standard QtDialog and update self.toQLE with dir's name. """ if self.toQLE.isEnabled(): output = QFileDialog.getExistingDirectory( self, 'FF Multi Converter - ' + self.tr('Choose output destination'), config.home) if output: self.toQLE.setText(output) def import_presets(self): presets_dlgs.ShowPresets().import_presets() def export_presets(self): presets_dlgs.ShowPresets().export_presets() def reset_presets(self): presets_dlgs.ShowPresets().reset() def sync_presets(self): presets_dlgs.ShowPresets().synchronize() def removeold_presets(self): presets_dlgs.ShowPresets().remove_old() def ok_to_continue(self): """ Check if everything is ok to continue with conversion. Check if: - At least one file has given for conversion. - An output folder has given. - Output folder exists. Return False if an error arises, else True. """ try: if not self.fnames: raise ValidationError( self.tr('You must add at least one file to convert!')) elif not self.origQCB.isChecked() and not self.toQLE.text(): raise ValidationError( self.tr('You must choose an output folder!')) elif (not self.origQCB.isChecked() and not os.path.exists(self.toQLE.text())): raise ValidationError(self.tr('Output folder does not exists!')) if not self.current_tab().ok_to_continue(): return False return True except ValidationError as e: QMessageBox.warning( self, 'FF Multi Converter - ' + self.tr('Error!'), str(e)) return False def get_output_extension(self): """Extract the desired output file extension from GUI and return it.""" tab = self.current_tab() if tab.name == 'AudioVideo': ext_to = self.audiovideo_tab.extQCB.currentText() elif tab.name == 'Images': ext_to = tab.extQCB.currentText() else: ext_to = tab.convertQCB.currentText().split()[-1] return '.' + ext_to def start_conversion(self): """ Extract the appropriate information from GUI and call the Progress dialog with the suitable argumens. """ if not self.ok_to_continue(): return tab = self.current_tab() if tab.name == 'Documents' and not self.office_listener_started: utils.start_office_listener() self.office_listener_started = True ext_to = self.get_output_extension() _list = utils.create_paths_list( self.fnames, ext_to, self.prefix, self.suffix, self.toQLE.text(), self.origQCB.isChecked(), self.overwrite_existing ) dialog = progress.Progress( _list, tab, self.deleteQCB.isChecked(), self) dialog.show() def open_dialog_preferences(self): """Open the preferences dialog.""" dialog = preferences_dlg.Preferences(self) if dialog.exec_(): self.load_settings(onstart=False) def open_dialog_presets(self): """Open the presets dialog.""" dialog = presets_dlgs.ShowPresets(self) dialog.exec_() def open_dialog_about(self): """Call the about dialog with the appropriate values.""" msg = self.tr('Convert among several file types to other formats') msg = textwrap.fill(msg, 54).replace('\n', '<br>') text = '''<b> FF Multi Converter {0} </b> <p>{1} <p><a href="{2}">FF Multi Converter - Home Page</a> <p>Copyright © 2011-2015 {3} <br>License: {4} <p>Python {5} - Qt {6} - PyQt {7} on {8}'''\ .format(ffmc.__version__, msg, ffmc.__url__, ffmc.__author__, ffmc.__license__, platform.python_version()[:5], QT_VERSION_STR, PYQT_VERSION_STR, platform.system()) image = ':/ffmulticonverter.png' authors = '{0} <{1}>\n\n'.format(ffmc.__author__, ffmc.__author_email__) authors += 'Contributors:\nPanagiotis Mavrogiorgos' translators = [] for i in config.translators: translators.append('{0}\n {1}'.format(i[0], i[1])) translators = '\n\n'.join(translators) dialog = about_dlg.AboutDialog(text, image, authors, translators, self) dialog.exec_()
class AudioVideoTab(QWidget): def __init__(self, parent): super(AudioVideoTab, self).__init__(parent) self.parent = parent self.name = 'AudioVideo' self.formats = [ '3gp', 'aac', 'ac3', 'afc', 'aiff', 'amr', 'asf', 'au', 'avi', 'dvd', 'flac', 'flv', 'mka', 'mkv', 'mmf', 'mov', 'mp3', 'mp4', 'mpg', 'ogg', 'ogv', 'psp', 'rm', 'spx', 'vob', 'wav', 'webm', 'wma', 'wmv' ] self.extra_formats = [ 'aifc', 'm2t', 'm4a', 'm4v', 'mp2', 'mpeg', 'ra', 'ts' ] nochange = self.tr('No Change') frequency_values = [nochange, '22050', '44100', '48000'] bitrate_values = [ nochange, '32', '96', '112', '128', '160', '192', '256', '320' ] pattern = QRegExp(r'^[1-9]\d*') validator = QRegExpValidator(pattern, self) converttoLabel = QLabel(self.tr('Convert to:')) self.extComboBox = QComboBox() self.extComboBox.addItems(self.formats + [self.tr('Other')]) self.extComboBox.setMinimumWidth(130) self.extLineEdit = QLineEdit() self.extLineEdit.setMaximumWidth(85) self.extLineEdit.setEnabled(False) hlayout1 = pyqttools.add_to_layout(QHBoxLayout(), converttoLabel, None, self.extComboBox, self.extLineEdit) commandLabel = QLabel(self.tr('Command:')) self.commandLineEdit = QLineEdit() self.presetButton = QPushButton(self.tr('Preset')) self.defaultButton = QPushButton(self.tr('Default')) hlayout2 = pyqttools.add_to_layout(QHBoxLayout(), commandLabel, self.commandLineEdit, self.presetButton, self.defaultButton) sizeLabel = QLabel(self.tr('Video Size:')) aspectLabel = QLabel(self.tr('Aspect:')) frameLabel = QLabel(self.tr('Frame Rate (fps):')) bitrateLabel = QLabel(self.tr('Video Bitrate (kbps):')) self.widthLineEdit = pyqttools.create_LineEdit((50, 16777215), validator, 4) self.heightLineEdit = pyqttools.create_LineEdit((50, 16777215), validator, 4) label = QLabel('x') layout1 = pyqttools.add_to_layout(QHBoxLayout(), self.widthLineEdit, label, self.heightLineEdit) self.aspect1LineEdit = pyqttools.create_LineEdit((35, 16777215), validator, 2) self.aspect2LineEdit = pyqttools.create_LineEdit((35, 16777215), validator, 2) label = QLabel(':') layout2 = pyqttools.add_to_layout(QHBoxLayout(), self.aspect1LineEdit, label, self.aspect2LineEdit) self.frameLineEdit = pyqttools.create_LineEdit(None, validator, 4) self.bitrateLineEdit = pyqttools.create_LineEdit(None, validator, 6) labels = [sizeLabel, aspectLabel, frameLabel, bitrateLabel] widgets = [layout1, layout2, self.frameLineEdit, self.bitrateLineEdit] videosettings_layout = QHBoxLayout() for a, b in zip(labels, widgets): text = a.text() a.setText('<html><p align="center">{0}</p></html>'.format(text)) layout = pyqttools.add_to_layout(QVBoxLayout(), a, b) videosettings_layout.addLayout(layout) freqLabel = QLabel(self.tr('Frequency (Hz):')) chanLabel = QLabel(self.tr('Channels:')) bitrateLabel = QLabel(self.tr('Audio Bitrate (kbps):')) self.freqComboBox = QComboBox() self.freqComboBox.addItems(frequency_values) self.chan1RadioButton = QRadioButton('1') self.chan1RadioButton.setMaximumSize(QSize(51, 16777215)) self.chan2RadioButton = QRadioButton('2') self.chan2RadioButton.setMaximumSize(QSize(51, 16777215)) self.group = QButtonGroup() self.group.addButton(self.chan1RadioButton) self.group.addButton(self.chan2RadioButton) spcr1 = QSpacerItem(40, 20, QSizePolicy.Preferred, QSizePolicy.Minimum) spcr2 = QSpacerItem(40, 20, QSizePolicy.Preferred, QSizePolicy.Minimum) chanlayout = pyqttools.add_to_layout(QHBoxLayout(), spcr1, self.chan1RadioButton, self.chan2RadioButton, spcr2) self.audio_bitrateComboBox = QComboBox() self.audio_bitrateComboBox.addItems(bitrate_values) labels = [freqLabel, chanLabel, bitrateLabel] widgets = [self.freqComboBox, chanlayout, self.audio_bitrateComboBox] audiosettings_layout = QHBoxLayout() for a, b in zip(labels, widgets): text = a.text() a.setText('<html><p align="center">{0}</p></html>'.format(text)) layout = pyqttools.add_to_layout(QVBoxLayout(), a, b) audiosettings_layout.addLayout(layout) hidden_layout = pyqttools.add_to_layout(QVBoxLayout(), videosettings_layout, audiosettings_layout) line = QFrame() line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) self.moreButton = QPushButton(QApplication.translate('Tab', 'More')) self.moreButton.setSizePolicy(QSizePolicy(QSizePolicy.Fixed)) self.moreButton.setCheckable(True) hlayout3 = pyqttools.add_to_layout(QHBoxLayout(), line, self.moreButton) self.frame = QFrame() self.frame.setLayout(hidden_layout) self.frame.hide() final_layout = pyqttools.add_to_layout(QVBoxLayout(), hlayout1, hlayout2, hlayout3, self.frame) self.setLayout(final_layout) self.presetButton.clicked.connect(self.choose_preset) self.defaultButton.clicked.connect(self.set_default_command) self.moreButton.toggled.connect(self.frame.setVisible) self.moreButton.toggled.connect(self.resize_parent) self.extComboBox.currentIndexChanged.connect( lambda: self.extLineEdit.setEnabled(self.extComboBox.currentIndex( ) == len(self.formats))) self.widthLineEdit.textChanged.connect( lambda: self.command_elements_change('size')) self.heightLineEdit.textChanged.connect( lambda: self.command_elements_change('size')) self.aspect1LineEdit.textChanged.connect( lambda: self.command_elements_change('aspect')) self.aspect2LineEdit.textChanged.connect( lambda: self.command_elements_change('aspect')) self.frameLineEdit.textChanged.connect( lambda: self.command_elements_change('frames')) self.bitrateLineEdit.textChanged.connect( lambda: self.command_elements_change('video_bitrate')) self.freqComboBox.currentIndexChanged.connect( lambda: self.command_elements_change('frequency')) self.audio_bitrateComboBox.currentIndexChanged.connect( lambda: self.command_elements_change('audio_bitrate')) self.chan1RadioButton.clicked.connect( lambda: self.command_elements_change('channels1')) self.chan2RadioButton.clicked.connect( lambda: self.command_elements_change('channels2')) def resize_parent(self): """Resize MainWindow.""" height = MAIN_FIXED_HEIGHT if self.frame.isVisible() else MAIN_HEIGHT self.parent.setMinimumSize(MAIN_WIDTH, height) self.parent.resize(MAIN_WIDTH, height) def clear(self): """Clear all values of graphical widgets.""" lines = [ self.commandLineEdit, self.widthLineEdit, self.heightLineEdit, self.aspect1LineEdit, self.aspect2LineEdit, self.frameLineEdit, self.bitrateLineEdit, self.extLineEdit ] for i in lines: i.clear() self.freqComboBox.setCurrentIndex(0) self.audio_bitrateComboBox.setCurrentIndex(0) self.group.setExclusive(False) self.chan1RadioButton.setChecked(False) self.chan2RadioButton.setChecked(False) self.group.setExclusive(True) # setExclusive(False) in order to be able to uncheck checkboxes and # then setExclusive(True) so only one radio button can be set def ok_to_continue(self): """ Check if everything is ok with audiovideotab to continue conversion. Check if: - Either ffmpeg or avconv are installed. - Desired extension is valid. - self.commandLineEdit is empty. Return True if all tests pass, else False. """ if not self.parent.ffmpeg and not self.parent.avconv: QMessageBox.warning( self, 'FF Multi Converter - ' + self.tr('Error!'), self. tr('Neither ffmpeg nor avconv are installed.' '\nYou will not be able to convert audio/video files until you' ' install one of them.')) return False if self.extLineEdit.isEnabled(): text = str(self.extLineEdit.text()).strip() if len(text.split()) != 1 or text[0] == '.': QMessageBox.warning( self, 'FF Multi Converter - ' + self.tr('Error!'), self.tr('Extension must be one word and must ' 'not start with a dot.')) self.extLineEdit.selectAll() self.extLineEdit.setFocus() return False if not self.commandLineEdit.text(): QMessageBox.warning( self, 'FF Multi Converter - ' + self.tr('Error!'), self.tr('The command LineEdit may not be empty.')) self.commandLineEdit.setFocus() return False return True def set_default_command(self): """Set the default value to self.commandLineEdit.""" self.clear() self.commandLineEdit.setText(self.parent.default_command) def choose_preset(self): """ Open the presets dialog and update self.commandLineEdit, self.extComboBox and self.extLineEdit with the appropriate values. """ dialog = presets_dlgs.ShowPresets() if dialog.exec_() and dialog.the_command is not None: self.commandLineEdit.setText(dialog.the_command) self.commandLineEdit.home(False) find = self.extComboBox.findText(dialog.the_extension) if find >= 0: self.extComboBox.setCurrentIndex(find) else: self.extComboBox.setCurrentIndex(len(self.formats)) self.extLineEdit.setText(dialog.the_extension) def remove_consecutive_spaces(self, string): """Remove any consecutive spaces from a string and return it.""" temp = string string = '' for i in temp.split(): if i: string += i + ' ' return string[:-1] def command_elements_change(self, widget): """Fill self.commandLineEdit with the appropriate command parameters.""" command = str(self.commandLineEdit.text()) if widget == 'size': text1 = self.widthLineEdit.text() text2 = self.heightLineEdit.text() if (text1 or text2) and not (text1 and text2): return f = re.sub(r'^.*(-s\s+\d+x\d+).*$', r'\1', command) if re.match(r'^.*(-s\s+\d+x\d+).*$', f): command = command.replace(f, '').strip() if text1 and text2: command += ' -s {0}x{1}'.format(text1, text2) elif widget == 'aspect': text1 = self.aspect1LineEdit.text() text2 = self.aspect2LineEdit.text() if (text1 or text2) and not (text1 and text2): return f = re.sub(r'^.*(-aspect\s+\d+:\d+).*$', r'\1', command) if re.match(r'^.*(-aspect\s+\d+:\d+).*$', f): command = command.replace(f, '').strip() if text1 and text2: command += ' -aspect {0}:{1}'.format(text1, text2) elif widget == 'frames': text = self.frameLineEdit.text() f = re.sub(r'^.*(-r\s+\d+).*$', r'\1', command) if re.match(r'^.*(-r\s+\d+).*$', f): command = command.replace(f, '').strip() if text: command += ' -r {0}'.format(text) elif widget == 'video_bitrate': text = self.bitrateLineEdit.text() f = re.sub(r'^.*(-b\s+\d+k).*$', r'\1', command) if re.match(r'^.*(-b\s+\d+k).*$', f): command = command.replace(f, '') if text: command += ' -b {0}k'.format(text) command = command.replace('-sameq', '').strip() elif widget == 'frequency': text = self.freqComboBox.currentText() f = re.sub(r'^.*(-ar\s+\d+).*$', r'\1', command) if re.match(r'^.*(-ar\s+\d+).*$', f): command = command.replace(f, '').strip() if text != 'No Change': command += ' -ar {0}'.format(text) elif widget == 'audio_bitrate': text = self.audio_bitrateComboBox.currentText() f = re.sub(r'^.*(-ab\s+\d+k).*$', r'\1', command) if re.match(r'^.*(-ab\s+\d+k).*$', f): command = command.replace(f, '').strip() if text != 'No Change': command += ' -ab {0}k'.format(text) elif widget in ('channels1', 'channels2'): text = self.chan1RadioButton.text() if widget == 'channels1' \ else self.chan2RadioButton.text() f = re.sub(r'^.*(-ac\s+\d+).*$', r'\1', command) if re.match(r'^.*(-ac\s+\d+).*$', f): command = command.replace(f, '').strip() command += ' -ac {0}'.format(text) self.commandLineEdit.clear() self.commandLineEdit.setText(self.remove_consecutive_spaces(command))
class Search(QWidget, plugin.MainWindowPlugin): def __init__(self, mainwindow): super(Search, self).__init__(mainwindow) self._currentView = None self._positions = None self._replace = False # are we in replace mode? mainwindow.currentViewChanged.connect(self.viewChanged) mainwindow.actionCollection.edit_find_next.triggered.connect(self.findNext) mainwindow.actionCollection.edit_find_previous.triggered.connect(self.findPrevious) # dont inherit looks from view self.setFont(QApplication.font()) self.setPalette(QApplication.palette()) grid = QGridLayout() grid.setContentsMargins(4, 0, 4, 0) grid.setVerticalSpacing(0) self.setLayout(grid) self.searchEntry = QLineEdit(textChanged=self.slotSearchChanged) self.searchLabel = QLabel() self.caseCheck = QCheckBox(checked=True, focusPolicy=Qt.NoFocus) self.regexCheck = QCheckBox(focusPolicy=Qt.NoFocus) self.countLabel = QLabel(alignment=Qt.AlignRight | Qt.AlignVCenter) self.countLabel.setMinimumWidth(QApplication.fontMetrics().width("9999")) self.closeButton = QToolButton(autoRaise=True, focusPolicy=Qt.NoFocus) self.hideAction = QAction(self, triggered=self.slotHide) self.hideAction.setShortcut(QKeySequence(Qt.Key_Escape)) self.hideAction.setIcon(self.style().standardIcon(QStyle.SP_DialogCloseButton)) self.closeButton.setDefaultAction(self.hideAction) grid.addWidget(self.searchLabel, 0, 0) grid.addWidget(self.searchEntry, 0, 1) grid.addWidget(self.caseCheck, 0, 2) grid.addWidget(self.regexCheck, 0, 3) grid.addWidget(self.countLabel, 0, 4) grid.addWidget(self.closeButton, 0, 5) self.caseCheck.toggled.connect(self.slotSearchChanged) self.regexCheck.toggled.connect(self.slotSearchChanged) self.replaceEntry = QLineEdit() self.replaceLabel = QLabel() self.replaceButton = QPushButton(clicked=self.slotReplace) self.replaceAllButton = QPushButton(clicked=self.slotReplaceAll) grid.addWidget(self.replaceLabel, 1, 0) grid.addWidget(self.replaceEntry, 1, 1) grid.addWidget(self.replaceButton, 1, 2) grid.addWidget(self.replaceAllButton, 1, 3) app.settingsChanged.connect(self.readSettings) self.readSettings() app.translateUI(self) def translateUI(self): self.searchLabel.setText(_("Search:")) self.caseCheck.setText(_("&Case")) self.caseCheck.setToolTip(_("Case Sensitive")) self.regexCheck.setText(_("&Regex")) self.regexCheck.setToolTip(_("Regular Expression")) self.countLabel.setToolTip(_("The total number of matches")) self.hideAction.setToolTip(_("Close")) self.replaceLabel.setText(_("Replace:")) self.replaceButton.setText(_("Re&place")) self.replaceButton.setToolTip(_("Replaces the next occurrence of the search term.")) self.replaceAllButton.setText(_("&All")) self.replaceAllButton.setToolTip(_("Replaces all occurrences of the search term in the document or selection.")) def readSettings(self): data = textformats.formatData('editor') self.searchEntry.setFont(data.font) self.replaceEntry.setFont(data.font) p = data.palette() self.searchEntry.setPalette(p) self.replaceEntry.setPalette(p) def currentView(self): return self._currentView and self._currentView() def setCurrentView(self, view): self._currentView = weakref.ref(view) if view else None def showWidget(self): if self.isVisible(): self.hideWidget() view = self.window().currentView() self.setCurrentView(view) layout = widgets.borderlayout.BorderLayout.get(view) layout.addWidget(self, widgets.borderlayout.BOTTOM) self.show() def hideWidget(self): view = self.currentView() if view: viewhighlighter.highlighter(view).clear("search") self.hide() layout = widgets.borderlayout.BorderLayout.get(view) layout.removeWidget(self) def viewChanged(self, new): self.setParent(None) self.hideWidget() self.setCurrentView(new) self.updatePositions() def slotHide(self): view = self.currentView() if view: self.hideWidget() view.setFocus() def find(self): # hide replace stuff self.replaceLabel.hide() self.replaceEntry.hide() self.replaceButton.hide() self.replaceAllButton.hide() self._replace = False # we are not in replace mode visible = self.isVisible() if not visible: with qutil.signalsBlocked(self.searchEntry): self.searchEntry.clear() self.showWidget() if not visible and self.currentView(): # pick current word cursor = self.currentView().textCursor() cursor.movePosition(QTextCursor.StartOfWord) cursor.movePosition(QTextCursor.EndOfWord, QTextCursor.KeepAnchor) word = cursor.selection().toPlainText() if not re.search(r'\w', word): word = "" self.searchEntry.setText(word) self.searchEntry.selectAll() else: self.slotSearchChanged() self.searchEntry.setFocus() def replace(self): # show replace stuff self.replaceLabel.show() self.replaceEntry.show() self.replaceButton.show() self.replaceAllButton.show() focus = self.replaceEntry if self.isVisible() and self.searchEntry.text() else self.searchEntry self._replace = True # we are in replace mode self.showWidget() self.slotSearchChanged() focus.setFocus() def slotSearchChanged(self): self.updatePositions() viewhighlighter.highlighter(self.currentView()).highlight("search", self._positions, 1) def updatePositions(self): search = self.searchEntry.text() view = self.currentView() document = view.document() self._positions = [] if search: text = document.toPlainText() flags = re.MULTILINE | re.DOTALL if not self.caseCheck.isChecked(): flags |= re.IGNORECASE if not self.regexCheck.isChecked(): search = re.escape(search) try: matches = re.finditer(search, text, flags) except re.error: pass else: for m in matches: c = QTextCursor(document) c.setPosition(m.end()) c.setPosition(m.start(), QTextCursor.KeepAnchor) self._positions.append(c) self.countLabel.setText(unicode(len(self._positions))) def findNext(self): view = self.currentView() if view and self._positions: positions = [c.position() for c in self._positions] index = bisect.bisect_right(positions, view.textCursor().position()) if index < len(positions): view.setTextCursor(self._positions[index]) else: view.setTextCursor(self._positions[0]) view.ensureCursorVisible() def findPrevious(self): view = self.currentView() positions = [c.position() for c in self._positions] if view and positions: index = bisect.bisect_left(positions, view.textCursor().position()) - 1 view.setTextCursor(self._positions[index]) view.ensureCursorVisible() def keyPressEvent(self, ev): if ev.key() == Qt.Key_Tab: # prevent Tab from reaching the View widget self.window().focusNextChild() return # if in search mode, Up and Down jump between search results if not self._replace and self._positions and self.searchEntry.text() and not ev.modifiers(): if ev.key() == Qt.Key_Up: self.findPrevious() return elif ev.key() == Qt.Key_Down: self.findNext() return # use enter or return for search next if ev.key() in (Qt.Key_Enter, Qt.Key_Return): self.findNext() return super(Search, self).keyPressEvent(ev) def doReplace(self, cursor): text = cursor.selection().toPlainText() search = self.searchEntry.text() replace = self.replaceEntry.text() ok = text == self.searchEntry.text() if self.regexCheck.isChecked(): m = re.match(search, text) ok = False if m: try: replace = m.expand(replace) ok = True except re.error: pass if ok: pos = cursor.position() cursor.insertText(replace) cursor.setPosition(pos, QTextCursor.KeepAnchor) return ok def slotReplace(self): view = self.currentView() if view and self._positions: positions = [c.position() for c in self._positions] index = bisect.bisect_left(positions, view.textCursor().position()) if index >= len(positions): index = 0 if self.doReplace(self._positions[index]): viewhighlighter.highlighter(view).highlight("search", self._positions, 1) if index < len(positions) - 1: view.setTextCursor(self._positions[index+1]) else: view.setTextCursor(self._positions[0]) view.ensureCursorVisible() def slotReplaceAll(self): view = self.currentView() if view: replaced = False cursors = self._positions if view.textCursor().hasSelection(): cursors = [cursor for cursor in cursors if cursortools.contains(view.textCursor(), cursor)] view.textCursor().beginEditBlock() for cursor in cursors: if self.doReplace(cursor): replaced = True view.textCursor().endEditBlock() if replaced: viewhighlighter.highlighter(view).highlight("search", self._positions, 1)
class MainWindow(QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.home = os.getenv('HOME') self.fnames = list() # list of file names to be converted self.docconv = False # True when a documents conversion is running # parse command line arguments for i in QCoreApplication.argv()[1:]: i = codecs.utf_8_decode(os.path.abspath(i))[0] if os.path.isfile(i): self.fnames.append(i) else: print("ffmulticonverter: {0}: Not a file".format(i)) addButton = QPushButton(self.tr('Add')) delButton = QPushButton(self.tr('Delete')) clearButton = QPushButton(self.tr('Clear')) vlayout1 = pyqttools.add_to_layout(QVBoxLayout(), addButton, delButton, clearButton, None) self.filesList = FilesList() self.filesList.setSelectionMode(QAbstractItemView.ExtendedSelection) hlayout1 = pyqttools.add_to_layout(QHBoxLayout(), self.filesList, vlayout1) output_label = QLabel(self.tr('Output folder:')) self.toLineEdit = QLineEdit() self.toLineEdit.setReadOnly(True) self.toToolButton = QToolButton() self.toToolButton.setText('...') hlayout2 = pyqttools.add_to_layout(QHBoxLayout(), output_label, self.toLineEdit, self.toToolButton) self.audiovideo_tab = AudioVideoTab(self) self.image_tab = ImageTab(self) self.document_tab = DocumentTab(self) self.tabs = [self.audiovideo_tab, self.image_tab, self.document_tab] tab_names = [ self.tr('Audio/Video'), self.tr('Images'), self.tr('Documents') ] self.TabWidget = QTabWidget() for num, tab in enumerate(tab_names): self.TabWidget.addTab(self.tabs[num], tab) self.TabWidget.setCurrentIndex(0) self.origCheckBox = QCheckBox( self.tr('Save each file in the same\nfolder as input file')) self.deleteCheckBox = QCheckBox(self.tr('Delete original')) self.convertPushButton = QPushButton(self.tr('&Convert')) hlayout3 = pyqttools.add_to_layout(QHBoxLayout(), self.origCheckBox, self.deleteCheckBox, None) hlayout4 = pyqttools.add_to_layout(QHBoxLayout(), None, self.convertPushButton) final_layout = pyqttools.add_to_layout(QVBoxLayout(), hlayout1, self.TabWidget, hlayout2, hlayout3, hlayout4) self.statusBar = self.statusBar() self.dependenciesLabel = QLabel() self.statusBar.addPermanentWidget(self.dependenciesLabel, stretch=1) Widget = QWidget() Widget.setLayout(final_layout) self.setCentralWidget(Widget) c_act = pyqttools.create_action openAction = c_act(self, self.tr('Open'), QKeySequence.Open, None, self.tr('Open a file'), self.add_files) convertAction = c_act(self, self.tr('Convert'), 'Ctrl+C', None, self.tr('Convert files'), self.start_conversion) quitAction = c_act(self, self.tr('Quit'), 'Ctrl+Q', None, self.tr('Quit'), self.close) edit_presetsAction = c_act(self, self.tr('Edit Presets'), 'Ctrl+P', None, self.tr('Edit Presets'), self.presets) importAction = c_act(self, self.tr('Import'), None, None, self.tr('Import presets'), self.import_presets) exportAction = c_act(self, self.tr('Export'), None, None, self.tr('Export presets'), self.export_presets) resetAction = c_act(self, self.tr('Reset'), None, None, self.tr('Reset presets'), self.reset_presets) syncAction = c_act(self, self.tr('Synchronize'), None, None, self.tr('Synchronize presets'), self.sync_presets) removeoldAction = c_act(self, self.tr('Remove old'), None, None, self.tr('Remove old presets'), self.removeold_presets) clearallAction = c_act(self, self.tr('Clear All'), None, None, self.tr('Clear form'), self.clear_all) preferencesAction = c_act(self, self.tr('Preferences'), 'Alt+Ctrl+P', None, self.tr('Preferences'), self.preferences) aboutAction = c_act(self, self.tr('About'), 'Ctrl+?', None, self.tr('About'), self.about) fileMenu = self.menuBar().addMenu(self.tr('File')) editMenu = self.menuBar().addMenu(self.tr('Edit')) presetsMenu = self.menuBar().addMenu(self.tr('Presets')) helpMenu = self.menuBar().addMenu(self.tr('Help')) pyqttools.add_actions(fileMenu, [openAction, convertAction, None, quitAction]) pyqttools.add_actions(presetsMenu, [ edit_presetsAction, importAction, exportAction, resetAction, None, syncAction, removeoldAction ]) pyqttools.add_actions(editMenu, [clearallAction, None, preferencesAction]) pyqttools.add_actions(helpMenu, [aboutAction]) self.filesList.dropped.connect(self.url_dropped) addButton.clicked.connect(self.add_files) delButton.clicked.connect(self.delete_files) clearButton.clicked.connect(self.clear_fileslist) self.TabWidget.currentChanged.connect( lambda: self.tabs[0].moreButton.setChecked(False)) self.origCheckBox.clicked.connect(lambda: self.toLineEdit.setEnabled( not self.origCheckBox.isChecked())) self.toToolButton.clicked.connect(self.open_dir) self.convertPushButton.clicked.connect(convertAction.triggered) del_shortcut = QShortcut(self) del_shortcut.setKey(Qt.Key_Delete) del_shortcut.activated.connect(self.delete_files) self.resize(MAIN_WIDTH, MAIN_HEIGHT) self.setWindowTitle('FF Multi Converter') QTimer.singleShot(0, self.check_for_dependencies) QTimer.singleShot(0, self.load_settings) QTimer.singleShot(0, self.audiovideo_tab.set_default_command) QTimer.singleShot(0, self.update_filesList) def load_settings(self): """Load settings values.""" settings = QSettings() self.overwrite_existing = settings.value('overwrite_existing').toBool() self.default_output = unicode( settings.value('default_output').toString()) self.prefix = unicode(settings.value('prefix').toString()) self.suffix = unicode(settings.value('suffix').toString()) self.avconv_prefered = settings.value('avconv_prefered').toBool() self.default_command = unicode( settings.value('default_command').toString()) if not self.default_command: self.default_command = DEFAULT_COMMAND self.toLineEdit.setText(self.default_output) def current_tab(self): """Return the corresponding object of the selected tab.""" for i in self.tabs: if self.tabs.index(i) == self.TabWidget.currentIndex(): return i def update_filesList(self): """Clear self.filesList and add to it all items of self.fname.""" self.filesList.clear() for i in self.fnames: self.filesList.addItem(i) def url_dropped(self, links): """ Append to self.fnames each file name that not already exists and update self.filesList. """ for url in links: if os.path.isfile(url) and not url in self.fnames: self.fnames.append(url) self.update_filesList() def add_files(self): """ Get file names using a standard Qt dialog. Append to self.fnames each file name that not already exists and update self.filesList. """ # Create lists holding file formats extension. # To be passed in QFileDialog.getOpenFileNames(). all_files = '*' audiovideo_files = ' '.join( ['*.' + i for i in self.audiovideo_tab.formats]) img_formats = self.image_tab.formats[:] img_formats.extend(self.image_tab.extra_img) image_files = ' '.join(['*.' + i for i in img_formats]) document_files = ' '.join( ['*.' + i for i in self.document_tab.formats]) formats = [all_files, audiovideo_files, image_files, document_files] strings = [ self.tr('All Files'), self.tr('Audio/Video Files'), self.tr('Image Files'), self.tr('Document Files') ] filters = '' for string, extensions in zip(strings, formats): filters += string + ' ({0});;'.format(extensions) filters = filters[:-2] # remove last ';;' fnames = QFileDialog.getOpenFileNames( self, 'FF Multi Converter - ' + self.tr('Choose File'), self.home, filters) if fnames: for i in fnames: if not i in self.fnames: self.fnames.append(unicode(i)) self.update_filesList() def delete_files(self): """ Get selectedItems of self.filesList, remove them from self.fnames and update the filesList. """ items = self.filesList.selectedItems() if items: for i in items: self.fnames.remove(unicode(i.text())) self.update_filesList() def clear_fileslist(self): """Make self.fnames empty and update self.filesList.""" self.fnames = [] self.update_filesList() def clear_all(self): """Clear all values of graphical widgets.""" self.toLineEdit.clear() self.origCheckBox.setChecked(False) self.deleteCheckBox.setChecked(False) self.clear_fileslist() self.audiovideo_tab.clear() self.image_tab.clear() def open_dir(self): """ Get a directory name using a standard QtDialog and update self.toLineEdit with dir's name. """ if self.toLineEdit.isEnabled(): output = QFileDialog.getExistingDirectory( self, 'FF Multi Converter - ' + self.tr('Choose output destination'), self.home) #output = unicode(output) if output: self.toLineEdit.setText(output) def preferences(self): """Open the preferences dialog.""" dialog = preferences_dlg.Preferences(self) if dialog.exec_(): self.load_settings() def presets(self): """Open the presets dialog.""" dialog = presets_dlgs.ShowPresets(self) dialog.exec_() def import_presets(self): presets_dlgs.ShowPresets().import_presets() def export_presets(self): presets_dlgs.ShowPresets().export_presets() def reset_presets(self): presets_dlgs.ShowPresets().reset() def sync_presets(self): presets_dlgs.ShowPresets().synchronize() def removeold_presets(self): presets_dlgs.ShowPresets().remove_old() def ok_to_continue(self): """ Check if everything is ok to continue with conversion. Check if: - At least one file has given for conversion. - An output folder has given. - Output folder exists. Return False if an error arises, else True. """ try: if not self.fnames: raise ValidationError( self.tr('You must add at least one file to convert!')) elif not self.origCheckBox.isChecked( ) and not self.toLineEdit.text(): raise ValidationError( self.tr('You must choose an output folder!')) elif (not self.origCheckBox.isChecked() and not os.path.exists(unicode(self.toLineEdit.text()))): raise ValidationError( self.tr('Output folder does not exists!')) if not self.current_tab().ok_to_continue(): return False return True except ValidationError as e: QMessageBox.warning(self, 'FF Multi Converter - ' + \ self.tr('Error!'), unicode(e)) return False def output_ext(self): """Extract the desired output file extension from GUI and return it.""" tab = self.current_tab() if tab.name == 'AudioVideo': if self.audiovideo_tab.extLineEdit.isEnabled(): ext_to = self.audiovideo_tab.extLineEdit.text() else: ext_to = self.audiovideo_tab.extComboBox.currentText() elif tab.name == 'Images': ext_to = tab.extComboBox.currentText() else: ext_to = str(tab.convertComboBox.currentText()).split()[-1] return str('.' + ext_to) def create_paths_list(self, files_list, ext_to, prefix, suffix, output, orig_dir, overwrite_existing): """ Keyword arguments: files_list -- list with files to be converted ext_to -- the extension to which each file must be converted to prefix -- string that will be added as a prefix to all filenames suffix -- string that will be added as a suffix to all filenames output -- the output folder orig_dir -- if True, each file will be saved at its original directory else, files will be saved at output overwrite_existing -- if False, a '~' will be added as prefix to filenames Create and return a list with dicts. Each dict will have only one key and one corresponding value. Key will be a file to be converted and it's value will be the name of the new converted file. Example list: [{"/foo/bar.png" : "/foo/bar.bmp"}, {"/f/bar2.png" : "/f/bar2.bmp"}] """ assert ext_to.startswith('.'), 'ext_to must start with a dot (.)' conversion_list = [] dummy = [] for _file in files_list: _dir, name = os.path.split(_file) y = prefix + os.path.splitext(name)[0] + suffix + ext_to if orig_dir: y = _dir + '/' + y else: y = output + '/' + y if not overwrite_existing: while os.path.exists(y) or y in dummy: _dir2, _name2 = os.path.split(y) y = _dir2 + '/~' + _name2 dummy.append(y) # Add quotations to paths in order to avoid error in special # cases such as spaces or special characters. _file = '"' + _file + '"' y = '"' + y + '"' _dict = {} _dict[_file] = y conversion_list.append(_dict) return conversion_list def start_conversion(self): """ Extract the appropriate information from GUI and call the Progress dialog with the suitable argumens. """ if not self.ok_to_continue(): return ext_to = self.output_ext() _list = self.create_paths_list(self.fnames, ext_to, self.prefix, self.suffix, unicode(self.toLineEdit.text()), self.origCheckBox.isChecked(), self.overwrite_existing) tab = self.current_tab() cmd = '' size = str('') mntaspect = False if tab.name == 'AudioVideo': cmd = tab.commandLineEdit.text() elif tab.name == 'Images': width = tab.widthLineEdit.text() if width: height = tab.heightLineEdit.text() size = str('{0}x{1}'.format(width, height)) mntaspect = tab.aspectCheckBox.isChecked() else: self.docconv = True dialog = progress.Progress(_list, tab.name, cmd, not self.avconv_prefered, size, mntaspect, self.deleteCheckBox.isChecked(), self) dialog.show() def is_installed(self, program): """Return True if program appears in user's PATH var, else False.""" for path in os.getenv('PATH').split(os.pathsep): fpath = os.path.join(path, program) if os.path.exists(fpath) and os.access(fpath, os.X_OK): return True return False def check_for_dependencies(self): """ Check if each one of the program dependencies are installed and update self.dependenciesLabel with the appropriate message. """ self.ffmpeg = self.is_installed('ffmpeg') self.avconv = self.is_installed('avconv') self.unoconv = self.is_installed('unoconv') self.pmagick = True try: # We tried to import PythonMagick earlier. # If that raises an error it means that PythonMagick is not # available on the system. PythonMagick except NameError: self.pmagick = False missing = [] if not self.ffmpeg and not self.avconv: missing.append('FFmpeg/avconv') if not self.unoconv: missing.append('unoconv') if not self.pmagick: missing.append('PythonMagick') if missing: missing = ', '.join(missing) status = self.tr('Missing dependencies:') + ' ' + missing self.dependenciesLabel.setText(status) def about(self): """Call the about dialog with the appropriate values.""" link = 'http://sites.google.com/site/ffmulticonverter/' msg = self.tr('Convert among several file types to other extensions') if len(msg) > 54: # break line if msg is too long to fit the window nmsg = '' for n, w in enumerate(msg.split(' ')): if len(nmsg) > 54: break nmsg += w + ' ' nmsg += '<br>' + msg[len(nmsg):] msg = nmsg text = '''<b> FF Multi Converter {0} </b> <p>{1} <p><a href="{2}">FF Multi Converter - Home Page</a> <p>Copyright © 2011-2013 Ilias Stamatis <br>License: GNU GPL3 <p>Python {3} - Qt {4} - PyQt {5} on {6}'''\ .format(__version__, msg, link, platform.python_version()[:5], QT_VERSION_STR, PYQT_VERSION_STR, platform.system()) image = ':/ffmulticonverter.png' authors = 'Ilias Stamatis <*****@*****.**>\n\n' authors += 'Contributors:\nPanagiotis Mavrogiorgos' transl_list = [['[bg] Bulgarian', 'Vasil Blagoev'], ['[cs] Czech', 'Petr Simacek'], ['[de_DE] German (Germany)', 'Stefan Wilhelm'], ['[el] Greek', 'Ilias Stamatis'], ['[fr] French', 'Rémi Mercier' '\n Lebarhon'], ['[hu] Hungarian', 'Farkas Norbert'], ['[it] Italian', 'Fabio Boccaletti'], [ '[pl_PL] Polish (Poland)', 'Lukasz Koszy' '\n Piotr Surdacki' ], ['[pt] Portuguese', 'Sérgio Marques'], ['[pt_BR] Portuguese (Brasil)', 'José Humberto A Melo'], ['[ru] Russian', 'Andrew Lapshin'], ['[tu] Turkish', 'Tayfun Kayha'], ['[zh_CN] Chinese (China)', 'Dianjin Wang']] translators = '' for i in transl_list: translators += '{0}\n {1}\n\n'.format(i[0], i[1]) translators = translators[:-2] dialog = about_dlg.AboutDialog(text, image, authors, translators, self) dialog.exec_()
class SessionEditor(QDialog): def __init__(self, parent=None): super(SessionEditor, self).__init__(parent) self.setWindowModality(Qt.WindowModal) layout = QVBoxLayout() self.setLayout(layout) grid = QGridLayout() layout.addLayout(grid) self.name = QLineEdit() self.nameLabel = l = QLabel() l.setBuddy(self.name) grid.addWidget(l, 0, 0) grid.addWidget(self.name, 0, 1) self.autosave = QCheckBox() grid.addWidget(self.autosave, 1, 1) self.basedir = widgets.urlrequester.UrlRequester() self.basedirLabel = l = QLabel() l.setBuddy(self.basedir) grid.addWidget(l, 2, 0) grid.addWidget(self.basedir, 2, 1) layout.addWidget(widgets.Separator()) self.buttons = b = QDialogButtonBox(self) layout.addWidget(b) b.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) b.accepted.connect(self.accept) b.rejected.connect(self.reject) help.addButton(b, "sessions") app.translateUI(self) def translateUI(self): self.nameLabel.setText(_("Name:")) self.autosave.setText(_("Always save the list of documents in this session")) self.basedirLabel.setText(_("Base directory:")) def load(self, name): settings = sessions.sessionGroup(name) self.autosave.setChecked(settings.value("autosave", True, bool)) self.basedir.setPath(settings.value("basedir", "", type(""))) # more settings here def save(self, name): settings = sessions.sessionGroup(name) settings.setValue("autosave", self.autosave.isChecked()) settings.setValue("basedir", self.basedir.path()) # more settings here def defaults(self): self.autosave.setChecked(True) self.basedir.setPath('') # more defaults here def edit(self, name=None): self._originalName = name if name: caption = _("Edit session: {name}").format(name=name) self.name.setText(name) self.load(name) else: caption = _("Edit new session") self.name.clear() self.name.setFocus() self.defaults() self.setWindowTitle(app.caption(caption)) if self.exec_(): # name changed? name = self.name.text() if self._originalName and name != self._originalName: sessions.renameSession(self._originalName, name) self.save(name) return name def done(self, result): if not result or self.validate(): super(SessionEditor, self).done(result) def validate(self): """Checks if the input is acceptable. If this method returns True, the dialog is accepted when OK is clicked. Otherwise a messagebox could be displayed, and the dialog will remain visible. """ name = self.name.text().strip() self.name.setText(name) if not name: self.name.setFocus() QMessageBox.warning(self, app.caption(_("Warning")), _("Please enter a session name.")) if self._originalName: self.name.setText(self._originalName) return False elif name == 'none': self.name.setFocus() QMessageBox.warning(self, app.caption(_("Warning")), _("Please do not use the name '{name}'.".format(name="none"))) return False elif self._originalName != name and name in sessions.sessionNames(): self.name.setFocus() box = QMessageBox(QMessageBox.Warning, app.caption(_("Warning")), _("Another session with the name {name} already exists.\n\n" "Do you want to overwrite it?").format(name=name), QMessageBox.Discard | QMessageBox.Cancel, self) box.button(QMessageBox.Discard).setText(_("Overwrite")) result = box.exec_() if result != QMessageBox.Discard: return False return True
class NumberFormatDlg(QDialog): def __init__(self, format, callback, parent=None): super(NumberFormatDlg, self).__init__(parent) self.format = format self.callback = callback self.create_widgets() self.layout_widgets() self.create_connections() self.setWindowTitle("Set Number Format (`Live')") def create_widgets(self): punctuationRe = QRegExp(r"[ ,;:.]") self.thousandsLabel = QLabel("&Thousands separator") self.thousandsEdit = QLineEdit(self.format["thousandsseparator"]) self.thousandsLabel.setBuddy(self.thousandsEdit) self.thousandsEdit.setMaxLength(1) self.thousandsEdit.setValidator(QRegExpValidator(punctuationRe, self)) self.decimalMarkerLabel = QLabel("Decimal &marker") self.decimalMarkerEdit = QLineEdit(self.format["decimalmarker"]) self.decimalMarkerLabel.setBuddy(self.decimalMarkerEdit) self.decimalMarkerEdit.setMaxLength(1) self.decimalMarkerEdit.setValidator( QRegExpValidator(punctuationRe, self)) self.decimalMarkerEdit.setInputMask("X") self.decimalPlacesLabel = QLabel("&Decimal places") self.decimalPlacesSpinBox = QSpinBox() self.decimalPlacesLabel.setBuddy(self.decimalPlacesSpinBox) self.decimalPlacesSpinBox.setRange(0, 6) self.decimalPlacesSpinBox.setValue(self.format["decimalplaces"]) self.redNegativesCheckBox = QCheckBox("&Red negative numbers") self.redNegativesCheckBox.setChecked(self.format["rednegatives"]) def layout_widgets(self): grid = QGridLayout() grid.addWidget(self.thousandsLabel, 0, 0) grid.addWidget(self.thousandsEdit, 0, 1) grid.addWidget(self.decimalMarkerLabel, 1, 0) grid.addWidget(self.decimalMarkerEdit, 1, 1) grid.addWidget(self.decimalPlacesLabel, 2, 0) grid.addWidget(self.decimalPlacesSpinBox, 2, 1) grid.addWidget(self.redNegativesCheckBox, 3, 0, 1, 2) self.setLayout(grid) def create_connections(self): self.thousandsEdit.textEdited.connect(self.checkAndFix) self.decimalMarkerEdit.textEdited.connect(self.checkAndFix) self.decimalPlacesSpinBox.valueChanged.connect(self.apply) self.redNegativesCheckBox.toggled.connect(self.apply) def checkAndFix(self): thousands = unicode(self.thousandsEdit.text()) decimal = unicode(self.decimalMarkerEdit.text()) if thousands == decimal: self.thousandsEdit.clear() self.thousandsEdit.setFocus() if len(decimal) == 0: self.decimalMarkerEdit.setText(".") self.decimalMarkerEdit.selectAll() self.decimalMarkerEdit.setFocus() self.apply() def apply(self): self.format["thousandsseparator"] = (unicode( self.thousandsEdit.text())) self.format["decimalmarker"] = (unicode(self.decimalMarkerEdit.text())) self.format["decimalplaces"] = (self.decimalPlacesSpinBox.value()) self.format["rednegatives"] = (self.redNegativesCheckBox.isChecked()) self.callback()
class SessionEditor(QDialog): def __init__(self, parent=None): super(SessionEditor, self).__init__(parent) self.setWindowModality(Qt.WindowModal) layout = QVBoxLayout() self.setLayout(layout) grid = QGridLayout() layout.addLayout(grid) self.name = QLineEdit() self.nameLabel = l = QLabel() l.setBuddy(self.name) grid.addWidget(l, 0, 0) grid.addWidget(self.name, 0, 1) self.autosave = QCheckBox() grid.addWidget(self.autosave, 1, 1) self.basedir = widgets.urlrequester.UrlRequester() self.basedirLabel = l = QLabel() l.setBuddy(self.basedir) grid.addWidget(l, 2, 0) grid.addWidget(self.basedir, 2, 1) self.inclPaths = ip = QGroupBox(self, checkable=True, checked=False) ipLayout = QVBoxLayout() ip.setLayout(ipLayout) self.replPaths = QCheckBox() ipLayout.addWidget(self.replPaths) self.replPaths.toggled.connect(self.toggleReplace) self.include = widgets.listedit.FilePathEdit() self.include.listBox.setDragDropMode(QAbstractItemView.InternalMove) ipLayout.addWidget(self.include) grid.addWidget(ip, 3, 1) self.revt = QPushButton(self) self.clear = QPushButton(self) self.revt.clicked.connect(self.revertPaths) self.clear.clicked.connect(self.clearPaths) self.include.layout().addWidget(self.revt, 5, 1) self.include.layout().addWidget(self.clear, 6, 1) layout.addWidget(widgets.Separator()) self.buttons = b = QDialogButtonBox(self) layout.addWidget(b) b.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) b.accepted.connect(self.accept) b.rejected.connect(self.reject) userguide.addButton(b, "sessions") app.translateUI(self) def translateUI(self): self.nameLabel.setText(_("Name:")) self.autosave.setText(_("Always save the list of documents in this session")) self.basedirLabel.setText(_("Base directory:")) self.inclPaths.setTitle(_("Use session specific include path")) self.replPaths.setText(_("Replace global path")) self.replPaths.setToolTip(_("When checked, paths in LilyPond preferences are not included.")) self.revt.setText(_("Copy global path")) self.revt.setToolTip(_("Add and edit the path from LilyPond preferences.")) self.clear.setText(_("Clear")) self.clear.setToolTip(_("Remove all paths.")) def load(self, name): settings = sessions.sessionGroup(name) self.autosave.setChecked(settings.value("autosave", True, bool)) self.basedir.setPath(settings.value("basedir", "", type(""))) try: paths = settings.value("include-path", [], type("")) except TypeError: paths = [] self.include.setValue(paths) self.inclPaths.setChecked(settings.value("set-paths", False, bool)) self.replPaths.setChecked(settings.value("repl-paths", False, bool)) if not self.replPaths.isChecked(): self.addDisabledGenPaths() self.revt.setEnabled(False) # more settings here def fetchGenPaths(self): """Fetch paths from general preferences.""" s = QSettings() s.beginGroup("lilypond_settings") try: return s.value("include_path", [], type("")) except TypeError: return [] def addDisabledGenPaths(self): """Add global paths, but set as disabled.""" genPaths = self.fetchGenPaths() for p in genPaths: i = QListWidgetItem(p, self.include.listBox) i.setFlags(Qt.NoItemFlags) def toggleReplace(self): """Called when user changes setting for replace of global paths.""" if self.replPaths.isChecked(): items = self.include.items() for i in items: if not (i.flags() & Qt.ItemIsEnabled): #is not enabled self.include.listBox.takeItem(self.include.listBox.row(i)) self.revt.setEnabled(True) else: self.addDisabledGenPaths() self.revt.setEnabled(False) def revertPaths(self): """Add global paths (for edit).""" genPaths = self.fetchGenPaths() for p in genPaths: i = QListWidgetItem(p, self.include.listBox) def clearPaths(self): """Remove all active paths.""" items = self.include.items() for i in items: if i.flags() & Qt.ItemIsEnabled: self.include.listBox.takeItem(self.include.listBox.row(i)) def save(self, name): settings = sessions.sessionGroup(name) settings.setValue("autosave", self.autosave.isChecked()) settings.setValue("basedir", self.basedir.path()) settings.setValue("set-paths", self.inclPaths.isChecked()) settings.setValue("repl-paths", self.replPaths.isChecked()) path = [i.text() for i in self.include.items() if i.flags() & Qt.ItemIsEnabled] settings.setValue("include-path", path) # more settings here def defaults(self): self.autosave.setChecked(True) self.basedir.setPath('') self.inclPaths.setChecked(False) self.replPaths.setChecked(False) self.addDisabledGenPaths() self.revt.setEnabled(False) # more defaults here def edit(self, name=None): self._originalName = name if name: caption = _("Edit session: {name}").format(name=name) self.name.setText(name) self.load(name) else: caption = _("Edit new session") self.name.clear() self.name.setFocus() self.defaults() self.setWindowTitle(app.caption(caption)) if self.exec_(): # name changed? name = self.name.text() if self._originalName and name != self._originalName: sessions.renameSession(self._originalName, name) self.save(name) return name def done(self, result): if not result or self.validate(): super(SessionEditor, self).done(result) def validate(self): """Checks if the input is acceptable. If this method returns True, the dialog is accepted when OK is clicked. Otherwise a messagebox could be displayed, and the dialog will remain visible. """ name = self.name.text().strip() self.name.setText(name) if not name: self.name.setFocus() QMessageBox.warning(self, app.caption(_("Warning")), _("Please enter a session name.")) if self._originalName: self.name.setText(self._originalName) return False elif name == '-': self.name.setFocus() QMessageBox.warning(self, app.caption(_("Warning")), _("Please do not use the name '{name}'.".format(name="-"))) return False elif self._originalName != name and name in sessions.sessionNames(): self.name.setFocus() box = QMessageBox(QMessageBox.Warning, app.caption(_("Warning")), _("Another session with the name {name} already exists.\n\n" "Do you want to overwrite it?").format(name=name), QMessageBox.Discard | QMessageBox.Cancel, self) box.button(QMessageBox.Discard).setText(_("Overwrite")) result = box.exec_() if result != QMessageBox.Discard: return False return True
class MainWindow(QMainWindow): def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowMinimizeButtonHint) self.setWindowTitle(u"鱿鱼") self.setFixedSize(800, 600) self.setObjectName('principal') self.createGUI() def createGUI(self): self.frame_window = QWidget(self) self.frame_window.setGeometry(0, 0, 800, 40) self.frame_window.setObjectName('frame_window') self.title_frame = QLabel(self.frame_window) self.title_frame.setGeometry(0, 0, 800, 40) self.title_frame.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) self.title_frame.setFont(QFont("微软雅黑", 20, QFont.Bold)) self.title_frame.setText(u" 鱿鱼-阿里云白名单设置") self.title_frame.setObjectName('title_frame') # buttons clsfont = self.font() or QFont() clsfont.setFamily('Webdings') self.button_close = QPushButton('r', self.frame_window, font=clsfont) self.button_close.setGeometry(760, 0, 40, 40) self.button_close.setObjectName('button_close') self.button_close.setToolTip(u'关闭') self.button_close.enterEvent( self.button_close.setCursor(Qt.PointingHandCursor)) self.button_min = QPushButton('0', self.frame_window, font=clsfont) self.button_min.setGeometry(720, 0, 40, 40) self.button_min.setObjectName('button_min') self.button_min.setToolTip(u'最小化') self.button_min.enterEvent( self.button_min.setCursor(Qt.PointingHandCursor)) ###左边选择栏部分 self.GroupBox_checkbox = QGroupBox(self) self.GroupBox_checkbox.setTitle(u'选择白名单组') self.GroupBox_checkbox.setGeometry(10, 50, 200, 540) self.ecs_test = QCheckBox(u'测试环境服务器', self.GroupBox_checkbox) self.ecs_test.enterEvent(self.ecs_test.setCursor( Qt.PointingHandCursor)) self.ecs_test.setChecked(True) self.ecs_test.setGeometry(20, 30, 150, 30) self.rds_mysql = QCheckBox(u'MySQL数据库', self.GroupBox_checkbox) self.rds_mysql.enterEvent( self.rds_mysql.setCursor(Qt.PointingHandCursor)) self.rds_mysql.setChecked(True) self.rds_mysql.setGeometry(20, 60, 150, 30) self.rds_sqlserver = QCheckBox(u'SQLServer数据库', self.GroupBox_checkbox) self.rds_sqlserver.enterEvent( self.rds_sqlserver.setCursor(Qt.PointingHandCursor)) self.rds_sqlserver.setChecked(True) self.rds_sqlserver.setGeometry(20, 90, 150, 30) ###右边IP设置部分 self.GroupBox_ipset = QGroupBox(self) self.GroupBox_ipset.setTitle(u'公网IP配置') self.GroupBox_ipset.setGeometry(220, 50, 570, 200) self.label_outip = QLabel(self.GroupBox_ipset, objectName="label_outip") self.label_outip.setText(u'公网IP:') self.label_outip.setGeometry(15, 30, 75, 30) self.line_outip = QLineEdit(self.GroupBox_ipset) self.line_outip.setMinimumWidth(200) self.line_outip.setGeometry(85, 30, 150, 30) self.line_outip.setFont(QFont("Timers", 13, QFont.Bold)) self.line_outip.setStyleSheet("color:green") self.button_getip = QPushButton(u'自动获取公网IP', self.GroupBox_ipset, objectName="button_getip") self.button_getip.setToolTip(u'从ip138上抓取本机公网IP') self.button_getip.enterEvent( self.button_getip.setCursor(Qt.PointingHandCursor)) self.button_getip.setGeometry(300, 30, 110, 30) self.button_setup = QPushButton(u'添加', self.GroupBox_ipset, objectName="button_setup") self.button_setup.enterEvent( self.button_setup.setCursor(Qt.PointingHandCursor)) self.button_setup.setToolTip(u'将该IP添加至已选白名单组中') self.button_setup.setGeometry(430, 30, 110, 30) ###右边消息输出部分 self.GroupBox_text = QGroupBox(self) self.GroupBox_text.setGeometry(220, 260, 570, 330) self.browser_text = QTextBrowser(self.GroupBox_text) self.browser_text.setGeometry(0, 0, 570, 330) self.browser_text.setFont(QFont("Roman times", 12)) self.browser_text.setObjectName('browser_text') # conexiones self.button_close.clicked.connect(self.close) self.button_min.clicked.connect(self.showMinimized) self.button_getip.clicked.connect(self.auto_ip) self.button_setup.clicked.connect(self.setup) def auto_ip(self): self.line_outip.clear() self.button_getip.setEnabled(False) self.th_get_ip = GETIP() self.th_get_ip.ip_line_Signal.connect(self.show_ip_info) self.th_get_ip.start() def show_ip_info(self, ip=None, status=1): self.button_getip.setEnabled(True) if status: self.line_outip.setText(ip) else: self.browser_text.append(ip) def setup(self): myip = self.line_outip.text() if myip and validate_ip(myip): check_list = [] if self.ecs_test.isChecked(): check_list.append('ecs_test') if self.rds_mysql.isChecked(): check_list.append('rds_mysql') if self.rds_sqlserver.isChecked(): check_list.append('rds_sqlserver') if len(check_list) == 0: self.browser_text.append(u'没什么事可做的~') else: self.button_setup.setEnabled(False) self.th_setup = SETIP(myip, check_list) self.th_setup.text_browser_Signal.connect(self.show_text) self.th_setup.start() else: self.browser_text.append(u'请填入正确的IP地址!') def show_text(self, text=None, end=0): if end: self.button_setup.setEnabled(True) if text: self.browser_text.append(text) def mousePressEvent(self, event): self.offset = event.pos() def mouseMoveEvent(self, event): x = event.globalX() y = event.globalY() x_w = self.offset.x() y_w = self.offset.y() self.move(x - x_w, y - y_w)