class Panel(QToolBar): def __init__(self, state, parent=None, *, editableFontSize=False): super().__init__(parent) self.appState = state self.state = FormatState(self.appState, self) self.fontSizeSpinBox = None if editableFontSize: self.fontSizeSpinBox = QSpinBox() self.fontSizeSpinBox.setAlignment(Qt.AlignRight) self.fontSizeSpinBox.setFocusPolicy(Qt.NoFocus) self.fontSizeSpinBox.setRange(MIN_FONT_SIZE, MAX_FONT_SIZE) self.fontSizeSpinBox.setSuffix(" pt") self.fontSizeSpinBox.setValue(self.appState.stdFontSize) self.fontSizeSpinBox.setToolTip("""<p><b>Font Size</b></p> <p>Set the font size in points.</p>""") self.formatActions = Actions.Format.Actions( self, self.fontSizeSpinBox) for action in self.formatActions.forToolbar(): if action is not None: self.addAction(action) else: self.addSeparator() if editableFontSize: self.addWidget(self.fontSizeSpinBox)
def createFontBoxesFor(parent, name, family, size, *, mono=False, tooltips=None, which="Font"): font = QFont(family, size) fontComboBox = QFontComboBox(parent) if not mono: fontFilter = QFontComboBox.ScalableFonts else: fontFilter = (QFontComboBox.ScalableFonts | QFontComboBox.MonospacedFonts) fontComboBox.setFontFilters(fontFilter) fontComboBox.setCurrentFont(font) fontSizeSpinBox = QSpinBox(parent) fontSizeSpinBox.setAlignment(Qt.AlignRight) fontSizeSpinBox.setRange(6, 36) fontSizeSpinBox.setSuffix(" pt") fontSizeSpinBox.setAlignment(Qt.AlignVCenter | Qt.AlignRight) fontSizeSpinBox.setValue(font.pointSize()) if tooltips is not None: tooltips.append((fontComboBox, """\ <p><b>{0} Font</b></p><p>The font family to use for the {0} Font.</p>""". format(which))) tooltips.append((fontSizeSpinBox, """\ <p><b>{0} Font Size</b></p><p>The font point size to use for the {0} Font.</p>""".format(which))) setattr(parent, "{}FontComboBox".format(name.lower()), fontComboBox) setattr(parent, "{}FontSizeSpinBox".format(name.lower()), fontSizeSpinBox)
def createBinaryOptions(self): """ Binary Analysis Options """ groupBox = QtGui.QGroupBox('Binary Analysis') # Elements cbs_unique_str = QCheckBox('Show unique strings', self) cbs_unique_com = QCheckBox('Show unique comments', self) cbs_unique_calls = QCheckBox('Show unique calls', self) cbs_entropy = QCheckBox('Calculate entropy', self) cutoff_label = QLabel('Connect BB cutoff') sb_cutoff = QSpinBox() sb_cutoff.setRange(1, 40) cutoff_func_label = QLabel('Connect functions cutoff') sbf_cutoff = QSpinBox() sbf_cutoff.setRange(1, 40) # Default states are read from the Config # class and reflected in the GUI cbs_unique_str.setCheckState( self.get_state(self.config.display_unique_strings)) cbs_unique_com.setCheckState( self.get_state(self.config.display_unique_comments)) cbs_unique_calls.setCheckState( self.get_state(self.config.display_unique_calls)) cbs_entropy.setCheckState(self.get_state( self.config.calculate_entropy)) sb_cutoff.setValue(self.config.connect_bb_cutoff) sbf_cutoff.setValue(self.config.connect_func_cutoff) # Connect elements and signals cbs_unique_str.stateChanged.connect(self.string_unique) cbs_unique_com.stateChanged.connect(self.comment_unique) cbs_unique_calls.stateChanged.connect(self.calls_unique) cbs_entropy.stateChanged.connect(self.string_entropy) sb_cutoff.valueChanged[int].connect(self.set_cutoff) sb_cutoff.valueChanged[int].connect(self.set_func_cutoff) vbox = QtGui.QVBoxLayout() vbox.addWidget(cbs_unique_str) vbox.addWidget(cbs_unique_com) vbox.addWidget(cbs_unique_calls) vbox.addWidget(cbs_entropy) vbox.addWidget(cutoff_label) vbox.addWidget(sb_cutoff) vbox.addWidget(cutoff_func_label) vbox.addWidget(sbf_cutoff) vbox.addStretch(1) groupBox.setLayout(vbox) return groupBox
def createBinaryOptions(self): """ Binary Analysis Options """ groupBox = QtGui.QGroupBox('Binary Analysis') # Elements cbs_unique_str = QCheckBox('Show unique strings', self) cbs_unique_com = QCheckBox('Show unique comments', self) cbs_unique_calls = QCheckBox('Show unique calls', self) cbs_entropy = QCheckBox('Calculate entropy', self) cutoff_label = QLabel('Connect BB cutoff') sb_cutoff = QSpinBox() sb_cutoff.setRange(1, 40) cutoff_func_label = QLabel('Connect functions cutoff') sbf_cutoff = QSpinBox() sbf_cutoff.setRange(1, 40) # Default states are read from the Config # class and reflected in the GUI cbs_unique_str.setCheckState( self.get_state(self.config.display_unique_strings)) cbs_unique_com.setCheckState( self.get_state(self.config.display_unique_comments)) cbs_unique_calls.setCheckState( self.get_state(self.config.display_unique_calls)) cbs_entropy.setCheckState( self.get_state(self.config.calculate_entropy)) sb_cutoff.setValue(self.config.connect_bb_cutoff) sbf_cutoff.setValue(self.config.connect_func_cutoff) # Connect elements and signals cbs_unique_str.stateChanged.connect(self.string_unique) cbs_unique_com.stateChanged.connect(self.comment_unique) cbs_unique_calls.stateChanged.connect(self.calls_unique) cbs_entropy.stateChanged.connect(self.string_entropy) sb_cutoff.valueChanged[int].connect(self.set_cutoff) sb_cutoff.valueChanged[int].connect(self.set_func_cutoff) vbox = QtGui.QVBoxLayout() vbox.addWidget(cbs_unique_str) vbox.addWidget(cbs_unique_com) vbox.addWidget(cbs_unique_calls) vbox.addWidget(cbs_entropy) vbox.addWidget(cutoff_label) vbox.addWidget(sb_cutoff) vbox.addWidget(cutoff_func_label) vbox.addWidget(sbf_cutoff) vbox.addStretch(1) groupBox.setLayout(vbox) return groupBox
def __init__(self, parent, North="Up", East="Right", South="Down", West="Left", BoxLabel='Power', valueName='Position'): QWidget.__init__(self) self.North = North self.East = East self.South = South self.West = West self.boxLabel = BoxLabel buttonLayout = QGridLayout(self) northButton = QPushButton(self.North, self) # northbutton.click(actionscript) eastButton = QPushButton(self.East, self) southButton = QPushButton(self.South, self) westButton = QPushButton(self.West, self) speedSlider = QSlider() speedSlider.setTickPosition(QSlider.TicksRight) speedSlider.setTickInterval(10) speedSlider.TicksRight sliderPosition = QSpinBox() sliderPosition.setRange(0, 101) sliderLabel = QLabel(self.boxLabel) speedSlider.valueChanged.connect(sliderPosition.setValue) sliderPosition.valueChanged.connect(speedSlider.setValue) SliderValue = speedSlider.value() speedSlider.valueChanged.connect(self.printValue) #Needs work to fix the layout issues...... buttonLayout.addWidget(northButton, 1, 1) buttonLayout.addWidget(eastButton, 2, 2) buttonLayout.addWidget(westButton, 2, 0) buttonLayout.addWidget(southButton, 3, 1) buttonLayout.addWidget(sliderPosition, 1, 3) buttonLayout.addWidget(sliderLabel, 0, 3) buttonLayout.addWidget(speedSlider, 2, 3, 3, 3) self.setLayout(buttonLayout)
def __init__(self, parent, North="Up", East="Right", South="Down", West="Left",BoxLabel='Power', valueName='Position'): QWidget.__init__(self) self.North = North self.East= East self.South = South self.West = West self.boxLabel = BoxLabel buttonLayout = QGridLayout(self) northButton = QPushButton(self.North, self) # northbutton.click(actionscript) eastButton = QPushButton(self.East, self) southButton = QPushButton(self.South, self) westButton = QPushButton(self.West, self) speedSlider = QSlider() speedSlider.setTickPosition(QSlider.TicksRight) speedSlider.setTickInterval(10) speedSlider.TicksRight sliderPosition = QSpinBox() sliderPosition.setRange(0,101) sliderLabel = QLabel(self.boxLabel) speedSlider.valueChanged.connect(sliderPosition.setValue) sliderPosition.valueChanged.connect(speedSlider.setValue) SliderValue = speedSlider.value() speedSlider.valueChanged.connect(self.printValue) #Needs work to fix the layout issues...... buttonLayout.addWidget(northButton, 1, 1) buttonLayout.addWidget(eastButton, 2, 2) buttonLayout.addWidget(westButton, 2, 0) buttonLayout.addWidget(southButton, 3, 1) buttonLayout.addWidget(sliderPosition,1, 3) buttonLayout.addWidget(sliderLabel, 0, 3) buttonLayout.addWidget(speedSlider, 2, 3, 3,3) self.setLayout(buttonLayout)
class NewMarkerDialog(QDialog): def __init__(self): super(NewMarkerDialog, self).__init__() self.setWindowTitle('Add new marker...') newMarkerLabel = QLabel('Marker:') self.newMarker = QLineEdit() includeLabel = QLabel('Include all samples:') self.includeAll = QCheckBox() controlsLabel = QLabel('Control wells:') self.controls = QSpinBox() self.controls.setRange(0,8) self.controls.setValue(2) layout = QGridLayout() layout.addWidget(newMarkerLabel,0,0) layout.addWidget(self.newMarker,0,1) layout.addWidget(includeLabel,1,0) layout.addWidget(self.includeAll,1,1) layout.addWidget(controlsLabel,2,0) layout.addWidget(self.controls,2,1) self.buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.buttons.accepted.connect(self.accept) self.buttons.rejected.connect(self.reject) layout.addWidget(self.buttons,100,0,1,2) self.setLayout(layout) def getMarker(self): return self.newMarker.text() def getIncludeAll(self): return self.includeAll.isChecked() def getControls(self): return self.controls.value() @staticmethod def run(parent = None): dialog = NewMarkerDialog() result = dialog.exec_() newMarker = dialog.getMarker() includeAll = dialog.getIncludeAll() controls = dialog.getControls() return (newMarker,includeAll,controls,result == QDialog.Accepted)
class CalculateSalaryWidget(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) self.__parent = parent self.setWindowTitle("Calculate Salary") t = datetime.now() self.month = QComboBox() self.month.addItems([ "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE", "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER" ]) self.month.setCurrentIndex(t.month - 1) self.year = QSpinBox() self.year.setRange(1900, 3000) self.year.setValue(t.year) self.name = SearchBox(self) self.name.setPlaceholderText("Enter Name") self.name.returnPressed.connect(self.setIDList) self.nameList = [] self.nameList = DatabaseManager.db.getEmployeeNameList() self.name.setList(self.nameList) self.name.setCurrentIndex(-1) self.id = QComboBox() self.id.currentIndexChanged.connect( lambda: self.loadInfo(self.id.currentText())) self.designation = QLineEdit() self.designation.setReadOnly(True) self.originalPay = QLineEdit() self.originalPay.setReadOnly(True) self.originalPayGrade = QLineEdit() self.originalPayGrade.setReadOnly(True) self.DOJ = QLineEdit() self.DOJ.setReadOnly(True) self.pan = QLineEdit() self.pan.setReadOnly(True) self.presentPay = QLineEdit() self.presentPay.setReadOnly(True) self.da_percent = ValueBox() self.hra_percent = ValueBox() self.ta_percent = ValueBox() self.it_percent = ValueBox() self.pt_percent = ValueBox() self.name.editTextChanged.connect(self.clearInfo) self.bttnCalculate = QPushButton("Calculate") self.bttnCalculate.clicked.connect(self.calculate) self.bttnCancel = QPushButton("Back") self.bttnCancel.clicked.connect(self.goBack) self.bttnCalculate.setObjectName("OkButton") self.bttnCancel.setObjectName("CancelButton") self.setupUI() def calculate(self): if "" in (self.id.currentText(), self.name.text(), self.designation.text(), self.originalPay.text(), self.originalPayGrade.text(), self.DOJ.text(), self.pan.text(), self.da_percent.text(), self.hra_percent.text(), self.ta_percent.text(), self.it_percent.text(), self.pt_percent.text()): msg = QMessageBox(QMessageBox.Information, "Error", "Please enter all the information!", parent=self) msg.exec_() else: if self.__parent is not None: self.__parent.gotoPage( "Result", (self.id.currentText(), self.name.text(), self.designation.text(), self.originalPay.text(), self.originalPayGrade.text(), self.DOJ.text(), self.pan.text(), self.da_percent.text(), self.hra_percent.text(), self.ta_percent.text(), self.it_percent.text(), self.pt_percent.text(), self.month.currentText(), self.year.text())) def clearInfo(self): self.id.setCurrentIndex(-1) self.designation.clear() self.originalPay.clear() self.originalPayGrade.clear() self.DOJ.clear() self.pan.clear() self.da_percent.clear() self.hra_percent.clear() self.ta_percent.clear() self.it_percent.clear() self.pt_percent.clear() def loadInfo(self, id): print "id =", id, "...", len(id) if id != '': info = DatabaseManager.db.getEmployeeInfo(id) _, _, designation, originalPay, originalPayGrade, doj, pan = info self.designation.setText(str(designation)) self.originalPay.setText(str(originalPay)) self.originalPayGrade.setText(str(originalPayGrade)) self.DOJ.setText("%02d/%02d/%4d" % (doj.day, doj.month, doj.year)) self.pan.setText(str(pan)) _, da, hra, ta, it, pt = DatabaseManager.db.getDesignationInfo( designation) self.da_percent.setText(str(da)) self.hra_percent.setText(str(hra)) self.ta_percent.setText(str(ta)) self.it_percent.setText(str(it)) self.pt_percent.setText(str(pt)) def setIDList(self, name): self.id.clear() self.id.addItems(DatabaseManager.db.getIdListForName(name)) def goBack(self): if self.__parent is not None: self.__parent.goBack() def setupUI(self): layout = QVBoxLayout() layout.setContentsMargins(20, 20, 20, 10) datelayout = QHBoxLayout() datelayout.addWidget(QLabel("Salary for month of ")) datelayout.addWidget(self.month) datelayout.addWidget(self.year) datelayout.addStretch() layout.addLayout(datelayout) form = QFormLayout() form.setSpacing(10) form.addRow(QLabel("Name"), self.name) form.addRow(QLabel("ID No."), self.id) form.addRow(QLabel("Designation"), self.designation) form.addRow(QLabel("Original Pay"), self.originalPay) form.addRow(QLabel("Original Pay Grade"), self.originalPayGrade) form.addRow(QLabel("Date of joining"), self.DOJ) form.addRow(QLabel("Pan No."), self.pan) infoGroup = QGroupBox("Basic Info") infoGroup.setLayout(form) layout.addWidget(infoGroup) leftForm = QFormLayout() leftForm.addRow(QLabel("Dearness Allowance"), self.da_percent) leftForm.addRow(QLabel("Housing Rent Allowance"), self.hra_percent) leftForm.addRow(QLabel("Transport Allowance"), self.ta_percent) leftGroup = QGroupBox("Allowances") leftGroup.setLayout(leftForm) rightForm = QFormLayout() rightForm.addRow(QLabel("Income Tax"), self.it_percent) rightForm.addRow(QLabel("Profession Tax"), self.pt_percent) rightGroup = QGroupBox("Deductions") rightGroup.setLayout(rightForm) table = QHBoxLayout() table.addWidget(leftGroup) table.addWidget(rightGroup) layout.addLayout(table) layout.addStretch() bttnLayout = QHBoxLayout() bttnLayout.addStretch() bttnLayout.addWidget(self.bttnCancel) bttnLayout.addWidget(self.bttnCalculate) layout.addLayout(bttnLayout) self.setLayout(layout)
class EditorWindow(QMainWindow): """initialize editor""" def __init__(self, tixi, xmlFilename, cpacs_scheme=Config.path_cpacs_21_schema): super(EditorWindow, self).__init__() self.cur_file_path = "" self.cur_schema_path = "" self.setupEditor() self.setupButtonMenu() self.setupSearchBox() self.setupStatusbar() self.setupMenubar() self.setupNumbar() self.popUpWidget = None self.flag_layout = False self.hbox = QHBoxLayout() self.hbox.setSpacing(0) self.hbox.setContentsMargins(0,0,0,0) self.hbox.addWidget(self.number_bar) self.hbox.addWidget(self.editor) self.layout = QGridLayout() self.layout.addWidget(self.searchbox, 0, 0, 1, 4) self.layout.addWidget(self.button1, 0, 4, 1, 1) self.layout.addWidget(self.button2, 0, 5, 1, 1) self.layout.addLayout(self.hbox, 2, 0, 1, 8) self.layout.addWidget(self.fontsizeSpinBox, 0, 6, 1, 1) self.layout.addWidget(self.label1, 0, 7, 1, 1) self.window = QWidget() self.window.setLayout(self.layout) self.setWindowTitle('Simple XML editor') self.setCentralWidget(self.window) self.resize(800, 800) self.show() self.tixi = tixi self.loadFile(xmlFilename, cpacs_scheme) ''' loads cpacs file and validates it against the cpacs_schema @param xmlFilename: input file @param cpacs_scheme: validation scheme ''' def loadFile(self, xmlFilename=None, cpacs_scheme=Config.path_cpacs_21_schema): if xmlFilename and cpacs_scheme : try: self.tixi.open(xmlFilename) #self.tixi.openDocument(xmlFilename) #self.tixi.schemaValidateFromFile(cpacs_scheme) self.editor.setPlainText(self.tixi.exportDocumentAsString()) self.cur_file_path = xmlFilename self.cur_schema_path = cpacs_scheme except TixiException as e: self.statusBar().showMessage('CPACS ERROR: ' + e.error) ''' update the dictionary by the cpacs scheme @param path_dict: path to directory @param path_scheme: path to cpacs_scheme ''' def updatedictionary(self, path_dict=Config.path_code_completion_dict, path_scheme=Config.path_cpacs_21_schema): found = False olddict = open(path_dict) scheme_file = open(path_scheme, 'r') with open(path_dict, "a") as newdict : for line in scheme_file : word = re.search("(?<=\<xsd:complexType name=\").*(?=\"\>)", line) if word != None : for tmp in olddict : if tmp == word.group(0) +"\n" : found = True break if(not found) : newdict.write(word.group(0)+"\n") olddict.seek(0) found = False olddict.close() newdict.close() scheme_file.close() ''' validate xml file and write result to statusBar ''' def validate(self): try: etree.fromstring(str(self.editor.toPlainText())) self.statusBar().showMessage("Valid XML") except etree.XMLSyntaxError as e: if e.error_log.last_error is not None: msg = e.error_log.last_error.message line = e.error_log.last_error.line col = e.error_log.last_error.column self.statusBar().showMessage("Invalid XML: Line %s, Col %s: %s"%(line,col,msg)) except: self.statusBar().showMessage("Invalid XML: Unknown error") ''' close and cleanup tixi ''' def __del__(self): pass #self.tixi.close() #self.tixi.cleanup() ''' set and connect the search buttons ''' def setupButtonMenu(self): self.button1 = QPushButton("previous" ) self.button2 = QPushButton("next" ) self.label1 = QLabel("font") self.fontsizeSpinBox = QSpinBox() self.button1.hide() self.button2.hide() self.label1.hide() self.fontsizeSpinBox.hide() self.button1.clicked.connect(self.fire_search_backward) self.button2.clicked.connect(self.fire_search_foreward) self.fontsizeSpinBox.setRange(4, 30) self.fontsizeSpinBox.setSingleStep(1) self.fontsizeSpinBox.setSuffix('pt') self.fontsizeSpinBox.setValue(10) self.fontsizeSpinBox.valueChanged.connect(self.setfontsize) def setfontsize(self, value): self.font.setPointSize(value) self.editor.setFont(self.font) def setupEditor(self): self.font = QFont() self.font.setFamily('Courier') self.font.setFixedPitch(True) self.font.setPointSize(10) self.editor = EditorCodeCompletion(Config().path_code_completion_dict) self.editor.setFont(self.font) self.editor.setTabStopWidth(20) self.editor.setAcceptRichText(False) self.editor.setLineWrapMode(QTextEdit.NoWrap) self.editor.textChanged.connect(self.validate) self.highlighter = Highlighter(self.editor.document()) def setupNumbar(self): self.number_bar = NumberBar() self.number_bar.setTextEdit(self.getStates()) self.editor.cursorPositionChanged.connect(self.fireUpdateNumbar) self.connect(self.editor.verticalScrollBar(), SIGNAL("valueChanged(int)"), self.fireUpdateNumbar) #self.editor.verticalScrollBar.valueChanged.connect(self.fireUpdateNumbar) def setupStatusbar(self): self.lineNumber = -1 self.colNumber = -1 self.m_statusRight = QLabel("row: " + str(self.lineNumber) + ", col:" + str(self.colNumber), self) self.statusBar().addPermanentWidget(self.m_statusRight, 0) def setupSearchBox(self): self.searchbox = SearchField() self.searchbox.hide() def setupMenubar(self): commentAction = QAction('Comment', self) commentAction.setShortcut('Ctrl+K') commentAction.setStatusTip('Comment Block') commentAction.triggered.connect(self.fireComment) uncommentAction = QAction('Uncomment', self) uncommentAction.setShortcut('Ctrl+Shift+K') uncommentAction.setStatusTip('Comment Block') uncommentAction.triggered.connect(self.fireUnComment) searchAction = QAction('search', self) searchAction.setShortcut('Ctrl+F') searchAction.setStatusTip('search') searchAction.triggered.connect(self.fireSearchView) newAction = QAction('New', self) newAction.setShortcut('Ctrl+N') newAction.setStatusTip('creats empty cpacs-file') newAction.triggered.connect(self.fireNewAction) self.updateAction = QAction('Update', self) self.updateAction.setShortcut('Ctrl+U') self.updateAction.setStatusTip('Update CPACS') self.updateAction.triggered.connect(self.fireUpdate) revertAction = QAction('Revert', self) revertAction.setShortcut('Ctrl+R') revertAction.triggered.connect(self.fireRevert) clearAction = QAction('Clear', self) clearAction.setStatusTip('Clear Editor') clearAction.triggered.connect(self.editor.clear) numbarAction = QAction('Line Number', self) numbarAction.triggered.connect(self.fireSwitchLayout) self.xpathAction = QAction('Current XPath', self) self.xpathAction.triggered.connect(self.getCursorXPath) link_to_node_YesAction = QAction('yes', self) link_to_node_YesAction.triggered.connect(self.dummyFuction) link_to_node_NoAction = QAction('no', self) link_to_node_NoAction.triggered.connect(self.dummyFuction) toolXAction = QAction('Tool X',self) toolXAction.triggered.connect(self.fireToolX) menubar = self.menuBar() filemenu = menubar.addMenu("File") filemenu.addAction(newAction) filemenu.addAction(self.updateAction) filemenu.addAction(revertAction) sourcemenu = menubar.addMenu("Source") sourcemenu.addAction(commentAction) sourcemenu.addAction(uncommentAction) sourcemenu.addAction(searchAction) editormenu = menubar.addMenu("Editor") editormenu.addAction(clearAction) editormenu.addSeparator() editormenu.addAction(numbarAction) editormenu.addAction(self.xpathAction) editormenu_child1 = editormenu.addMenu('Link to node') editormenu_child1.addAction(link_to_node_YesAction) editormenu_child1.addAction(link_to_node_NoAction) toolmenu = menubar.addMenu("Tools") toolmenu.addAction(toolXAction) self.editor.setContextMenuPolicy(Qt.CustomContextMenu) self.editor.customContextMenuRequested.connect(self.showMenu) #self.editor.connect(self.editor, SIGNAL( "customContextMenuRequested(QPoint)" ), self.showMenu ) def showMenu( self, pos ): """ Show a context menu for the active layer in the legend """ menu = self.editor.createStandardContextMenu() menu.addAction(self.xpathAction) menu.exec_(QtCore.QPoint( self.mapToGlobal( pos ).x() + 5, self.mapToGlobal( pos ).y() )) def fireUpdateNumbar(self): self.updateLineNumber() self.number_bar.update() def dummyFuction(self): print ("not implemented yet") def getStates(self): self.stats = { "searchbox":self.searchbox, "editor":self.editor} return self.stats ''' find previous button ''' def fire_search_backward(self): self.editor.find(self.searchbox.text(), QTextDocument.FindBackward) self.searchbox.setFocus() ''' find next button ''' def fire_search_foreward(self): #print self.tixi.getNumberOfChilds('/cpacs/vehicles/aircraft/model[@uID="Aircraft1"]/wings/wing[@uID="Aircraft1_Wing1"]/transformation[@uID="Aircraft1_Wing1_Transf"]/scaling[@uID="Aircraft1_Wing1_Transf_Sca"]/z') searchList = list(filter(lambda a : a!='', self.searchbox.text().split('/'))) if len(searchList) == 1 : if self.editor.find(searchList[0]) : pass elif not self.editor.find(searchList[0], QTextDocument.FindBackward): QMessageBox.about(self, "error", "String %s not found" % (searchList[0])) else : self.editor.moveCursor(QTextCursor.Start) self.editor.find(searchList[0]) else : self.searchXPath(self.searchbox.text(), searchList) self.searchbox.setFocus() # test # /cpacs/vehicles/aircraft/model/wings/wing/sections/section def searchXPath(self, path, searchList): try: if self.tixi.xPathEvaluateNodeNumber(path) > 1 : QMessageBox.about(self, "error", "XPath %s not unique" % path) return self.editor.moveCursor(QTextCursor.Start) found = True # search index snd loop j = 0 # search backwards for uid for i in range(len(searchList)-1, -1, -1) : if '[' in searchList[i] : # get value in brackets : [x] --> x uid = re.search(r'\[(.*)\]', searchList[i]).group(1) uid = self.__transToSearchUid(searchList[:i+1], uid) found = self.editor.find(uid) j = i+1 break # search forward for all nodes after last uid while found and j < len(searchList) : found = self.editor.find('<'+searchList[j]) j += 1 if not found : QMessageBox.about(self, "error", "XPath %s not found" % path) except TixiException : QMessageBox.about(self, "error", "XPath %s not found" % path) def __transToSearchUid(self, path_list, uid): try: int(uid) path = "" for p in path_list : path = path + '/' + p return self.tixi.getTextAttribute(path , 'uID') except ValueError: return uid.replace('@', '') def getCursorXPath(self): start_pos = self.editor.textCursor().position() tag , tag_pos , isCursorInTag = self.getTagNameAtCursor() _,xpath_idx, xpath_uid = self.__findXPath_rec('/cpacs', '/cpacs' , tag, tag_pos) if not isCursorInTag: xpath_idx = self.__strRemoveReverseToChar(xpath_idx, '/') xpath_uid = self.__strRemoveReverseToChar(xpath_uid, '/') self.__setCursorToPostion(start_pos) self.__startXPathPopUp(xpath_idx, xpath_uid) def getTagNameAtCursor(self): ''' @return: name of tag , position of tag , cursor is btw open and closing tag ''' self.editor.find('<', QTextDocument.FindBackward) isClosingTag , fst_tag = self.__getTagName() pos = self.editor.textCursor().position() if isClosingTag : # find open tag of this closing tag self.editor.find('<'+fst_tag, QTextDocument.FindBackward) pos = self.editor.textCursor().position() return fst_tag , pos , False else: return fst_tag , pos , True def __getTagName(self): tc = self.editor.textCursor() tc.select(QTextCursor.WordUnderCursor) tx = tc.selectedText() isClosingTag = False if "</" in tx : # select next word tc.select(QTextCursor.WordUnderCursor) tx = tc.selectedText() isClosingTag = True return isClosingTag , "" if "<" in tx else tx def __findXPath_rec(self, xpath_idx, xpath_uid, search, pos): nodes = self.__getChildNodesIdxTuple(xpath_idx) for (node, idx) in nodes: if node != '#text' : new_xpath_idx, new_xpath_uid = self.__createNewXPath(xpath_idx, xpath_uid, node, idx) if search == node and self.isNodeAtSearchedTagPosition(new_xpath_uid, pos) : print ("gefunden" , new_xpath_idx) return True, new_xpath_idx , new_xpath_uid else: flag , res_idx, res_uid = self.__findXPath_rec(new_xpath_idx, new_xpath_uid, search, pos) if flag : return True, res_idx, res_uid return False , xpath_idx , xpath_uid def __getChildNodesIdxTuple(self, xpath): n = self.tixi.getNumberOfChilds(xpath) + 1 node_list = list(map(lambda i : self.tixi.getChildNodeName(xpath, i), range(1,n))) res = [] for j in range(len(node_list)) : cnt = 1 for k in range(j): if node_list[k] == node_list[j] : cnt = cnt + 1 res.append((node_list[j],cnt)) return res def __createNewXPath(self, xpath_idx, xpath_uid, node, idx): path_idx = xpath_idx + '/' + node path_uid = xpath_uid + '/' + node try : uID = self.tixi.getTextAttribute(path_idx + '[' + str(idx) + ']', 'uID') path_idx = path_idx + '[' + str(idx) + ']' path_uid = path_uid+'[@uID="' + uID + '"]' except TixiException: pass # e.error == 'ATTRIBUTE_NOT_FOUND return path_idx , path_uid def isNodeAtSearchedTagPosition(self, xpath, pos): ''' @param xpath: xpath with uids (doesn't work with indices) @param param: ''' self.editor.moveCursor(QTextCursor.Start) # split string at / and remove all empty strings l = list(filter(lambda x : x != '' , xpath.split('/'))) # search index snd loop j = 0 # search backwards for uid for i in range(len(l)-1, -1, -1) : if '[' in l[i] : # get value in brackets : [x] --> x uid = re.search(r'\[@(.*)\]', l[i]).group(1) self.editor.find(uid) j = i+1 break # search forward for all nodes after last uid while j < len(l) : self.editor.find('<'+l[j]) j += 1 return pos <= self.editor.textCursor().position() def __setCursorToPostion(self, pos): tc = self.editor.textCursor() tc.setPosition(pos) self.editor.setTextCursor(tc) def __startXPathPopUp(self, xpath_idx, xpath_uid): self.popUpWidget = XPathDialog(xpath_idx, xpath_uid) self.setEnabled(False) self.popUpWidget.closeAct.triggered.connect(self.__resetPopUpWidget) self.popUpWidget.show() def updateLineNumber(self): ''' sets the line and column number ''' self.lineNumber = self.editor.textCursor().blockNumber() + 1 self.colNumber = self.editor.textCursor().columnNumber() + 1 self.m_statusRight.setText("row: " + str(self.lineNumber) + ", col:" + str(self.colNumber)) def highlightCurrentLine(self) : ''' highlight line under cursor ''' extraSelections = [] selection = QTextEdit.ExtraSelection() lineColor = QColor(255, 250, 205) selection.format.setBackground(lineColor) selection.format.setProperty(QTextFormat.FullWidthSelection, True) selection.cursor = self.editor.textCursor() selection.cursor.clearSelection() extraSelections.append(selection) self.editor.setExtraSelections(extraSelections) self.editor.setFocus() #TODO: implemnt def fireUpdate(self): print ('dummy function - update the model') text_file = open(Config.path_cpacs_tmp_file, "w") text_file.write(self.editor.toPlainText()) text_file.close() #self.tixi.saveDocument(Config.path_cpacs_tmp_file) # '../cpacs_files/temp.xml' def fireRevert(self): ''' reloads cpacs file if not updated yet ''' if(self.cur_file_path and self.cur_schema_path) : self.loadFile(self.cur_file_path, self.cur_schema_path) else : QMessageBox.about(self, "error", "CPACS-File or Validation-Schema not available") def fireSwitchLayout(self): ''' function to show or hide line numbers ''' if(self.flag_layout) : self.number_bar.flag_show_numbers = True self.update() else : self.number_bar.flag_show_numbers = False self.update() self.flag_layout = not self.flag_layout def fireNewAction(self): ''' opens new file input form ''' self.setEnabled(False) self.popUpWidget = NewFileDialog() self.popUpWidget.buttonBox.accepted.connect(self.__createNewCpacsFile) self.popUpWidget.buttonBox.rejected.connect(self.__resetPopUpWidget) self.popUpWidget.closeAct.triggered.connect(self.__resetPopUpWidget) self.popUpWidget.show() def fireToolX(self): self.popUpWidget = ToolX("X-Tool", self.tixi) self.setEnabled(False) self.popUpWidget.buttonBox.accepted.connect(self.__resetPopUpWidget) self.popUpWidget.buttonBox.rejected.connect(self.__resetPopUpWidget) # closeAct for pressing X to close window self.popUpWidget.closeAct.triggered.connect(self.__resetPopUpWidget) self.popUpWidget.show() def __createNewCpacsFile(self): ''' closes all documents and creates new empty cpacs temporary file ''' idict = self.popUpWidget.fire_submitInput() self.tixi.closeAllDocuments() self.tixi.create('cpacs') self.tixi.addCpacsHeader(idict['name'], idict['creator'], idict['version'], idict['description'], idict['cpacsVersion']) self.tixi.saveDocument(Config.path_cpacs_tmp_file) self.loadFile(Config.path_cpacs_tmp_file) self.__resetPopUpWidget() def __resetPopUpWidget(self): self.popUpWidget.close() self.popUpWidget = None self.setEnabled(True) def fireComment(self): ''' inserts open respective closing tag before and after a selected text. ''' tc = self.editor.textCursor() tc.beginEditBlock() tc.setPosition(self.editor.textCursor().selectionStart()) tc.insertText("<!--") tc.setPosition(self.editor.textCursor().selectionEnd()) tc.insertText("-->") tc.endEditBlock() def fireUnComment(self): ''' removes open respective closing tag before and after a selected text. ''' tc = self.editor.textCursor() selectTxt = tc.selectedText() if selectTxt.find('<!--') != -1 : if selectTxt.rfind('-->') != -1 : selectTxt = selectTxt.replace('<!--', '', 1) selectTxt = self.__rreplace(selectTxt, '-->' , '', 1) tc.insertText(selectTxt) else: QMessageBox.about(self, "error", "no open tag (%s) in selection" % ('-->')) else: QMessageBox.about(self, "error", "no close tag (%s) in selection" % ('<!--')) def fireSearchView(self): ''' show and hide searchbox and buttons ''' if self.searchbox.isFocused() : self.searchbox.hide() self.button1.hide() self.button2.hide() self.label1.hide() self.fontsizeSpinBox.hide() else : self.searchbox.show() self.button1.show() self.button2.show() self.label1.show() self.fontsizeSpinBox.show() self.searchbox.setFocus() def keyPressEvent(self,event): ''' handle for searching strings by pressing enter key ''' if self.searchbox.isFocused() and event.key() == Qt.Key_Return : self.fire_search_foreward() # ====================================================================================================================== # utilities # ====================================================================================================================== def __strRemoveReverseToChar(self, s, c): return self.__rm_rec(s, c) def __rm_rec(self, s, c): if s == "" : return "" elif s[-1] == c : return s[:-1] else : return self.__rm_rec(s[:-1], c) def __rreplace(self, s, old, new, occurrence): ''' reverse string replace function @param s: source string @param old: char to be replaced @param new: new char @param occurrence: only the given count occurrences are replaced. ''' li = s.rsplit(old, occurrence) return new.join(li)
class CalculateSalaryWidget(QWidget): """A PySide widget which provides GUI for selecting employee and calculating salary for a month & year Tis contains boxes for month and year input. Enter the month and year of salary to be calculated here. This is initially automatically set to present month and year. Also contains a ``SearchBox`` for selecting name of employee who's salary needs to be calculated. Selecting the name automatically loads IDs of all employees with that name (in case multiple employees have exact same name) in a dropdown box (``QComboBox``). After selecting the required ID from there, the employee info is automatically loaded. The allowances and deductions are loaded in ``ValueBoxes`` and hence may be edited if required. After selecting everything, user needs to click 'calculate' button. This creates a ``Salary`` object from available info. The actual salary calculation takes place inside ``Salary`` class. This salary object is then passed to ``ShowPaySlipWidget`` which shows the final result and has option to confirm the calculation and print the payslip. Note: To automatically call functions on GUI interaction such as button click, PySide Signal and Slots are used. visit http://zetcode.com/gui/pysidetutorial/eventsandsignals/ for more on PySide Signal and Slots. See Also: - :py:mod:`SearchBox <CustomWidgets.searchBox.SearchBox>` widget from CustomWidgets - :py:mod:`ValueBox <CustomWidgets.valueBox.ValueBox>` widget from CustomWidgets - :py:mod:`Salary <CustomClasses.Salary.Salary>` class from CustomClasses - :py:mod:`ShowPaySlipWidget <ShowPaySlip.ShowPaySlipWidget>` """ def __init__(self, parent=None): QWidget.__init__(self, parent) self.__parent = parent self.title = "Calculate Salary" self.__desig = None self.__emp = None t = datetime.now() self.month = QComboBox() self.month.addItems([ "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE", "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER" ]) self.month.setCurrentIndex(t.month - 1) self.year = QSpinBox() self.year.setRange(1900, 3000) self.year.setValue(t.year) self.name = SearchBox(self) self.name.setPlaceholderText("Enter Name") self.nameList = [] self.nameList = Database.getdb().getEmployeeNameList() self.name.setList(self.nameList) self.id = QComboBox() self.designation = QLineEdit() self.designation.setReadOnly(True) self.originalPay = QLineEdit() self.originalPay.setReadOnly(True) self.originalPayGrade = QLineEdit() self.originalPayGrade.setReadOnly(True) self.DOJ = QLineEdit() self.DOJ.setReadOnly(True) self.pan = QLineEdit() self.pan.setReadOnly(True) self.presentPay = QLineEdit() self.presentPay.setReadOnly(True) self.da_percent = ValueBox() self.hra_percent = ValueBox() self.ta_percent = ValueBox() self.it_percent = ValueBox() self.pt_percent = ValueBox() self.name.editTextChanged.connect(self.clearInfo) self.bttnCalculate = QPushButton("Calculate") self.bttnCalculate.clicked.connect(self.calculate) self.bttnCancel = QPushButton("Back") self.bttnCancel.clicked.connect(self.goBack) self.bttnCalculate.setObjectName("OkButton") self.bttnCancel.setObjectName("CancelButton") self.name.returnPressed.connect(self.setIDList) self.id.currentIndexChanged.connect( lambda: self.loadInfo(self.id.currentText())) self.setupUI() def calculate(self): """Automatically called on clicking calculate button""" if self.__emp is None: QMessageBox(QMessageBox.Information, "Error", "Please select an employee!", parent=self).exec_() else: if self.__parent is not None: self.__desig = Designation(self.__desig.designation, self.da_percent.text(), self.hra_percent.text(), self.ta_percent.text(), self.it_percent.text(), self.pt_percent.text()) salary = Salary(self.__emp, self.__desig, self.month.currentText(), self.year.text()) self.__parent.gotoPage("Result", salary) def clearInfo(self): """Clears the contents of all input/display boxes""" self.id.setCurrentIndex(-1) self.designation.clear() self.originalPay.clear() self.originalPayGrade.clear() self.DOJ.clear() self.pan.clear() self.da_percent.clear() self.hra_percent.clear() self.ta_percent.clear() self.it_percent.clear() self.pt_percent.clear() self.__desig = None self.__emp = None def loadInfo(self, id): """Loads info for given ID in the GUI boxes. This automatically called on selecting an ID from GUI Args: id (str): ID of employee who's info needs to be loaded """ print "id =", id, "...", len(id) if id != '': self.__emp = Database.getdb().getEmployeeInfo(id) self.designation.setText(self.__emp.designation) self.originalPay.setText(str(self.__emp.originalPay)) self.originalPayGrade.setText(str(self.__emp.originalPayGrade)) self.DOJ.setText(self.__emp.getStrDate()) self.pan.setText(self.__emp.pan) self.__desig = Database.getdb().getDesignationInfo( self.__emp.designation) self.da_percent.setText(str(self.__desig.da)) self.hra_percent.setText(str(self.__desig.hra)) self.ta_percent.setText(str(self.__desig.ta)) self.it_percent.setText(str(self.__desig.it)) self.pt_percent.setText(str(self.__desig.pt)) def setIDList(self, name): """Loads IDs of all employees with given name into the ID dropdown box This function is automatically called after selecting a name from the GUI Args: name (str): Name of employee """ self.id.clear() self.id.addItems(Database.getdb().getIdListForName(name)) def goBack(self): if self.__parent is not None: self.__parent.goBack() def setupUI(self): """Arranges GUI elements inside the widget properly""" paneLayout = QHBoxLayout() paneLayout.setContentsMargins(0, 0, 0, 0) leftPane = QFrame() leftPane.setObjectName("leftPane") leftPaneLayout = QVBoxLayout() leftPaneLayout.setContentsMargins(20, 20, 20, 10) heading = QLabel("Select Employee: ") heading.setObjectName("heading") leftPaneLayout.addWidget(heading) leftPaneLayout.addSpacing(10) datelayout = QHBoxLayout() datelayout.addWidget(QLabel("Salary for month of ")) datelayout.addWidget(self.month) datelayout.addWidget(self.year) datelayout.addStretch() leftPaneLayout.addLayout(datelayout) leftForm = QFormLayout() leftForm.setSpacing(10) leftForm.addRow(QLabel("Name"), self.name) leftForm.addRow(QLabel("ID No."), self.id) leftPaneLayout.addLayout(leftForm) leftPaneLayout.addStretch() leftPane.setLayout(leftPaneLayout) paneLayout.addWidget(leftPane) layout = QVBoxLayout() layout.setContentsMargins(20, 20, 20, 10) form = QFormLayout() form.setSpacing(10) form.addRow(QLabel("Designation"), self.designation) form.addRow(QLabel("Original Pay"), self.originalPay) form.addRow(QLabel("Original Pay Grade"), self.originalPayGrade) form.addRow(QLabel("Date of joining"), self.DOJ) form.addRow(QLabel("Pan No."), self.pan) infoGroup = QGroupBox("Basic Info") infoGroup.setLayout(form) layout.addWidget(infoGroup) leftForm = QFormLayout() leftForm.addRow(QLabel("Dearness Allowance"), self.da_percent) leftForm.addRow(QLabel("Housing Rent Allowance"), self.hra_percent) leftForm.addRow(QLabel("Transport Allowance"), self.ta_percent) leftGroup = QGroupBox("Allowances") leftGroup.setLayout(leftForm) rightForm = QFormLayout() rightForm.addRow(QLabel("Income Tax"), self.it_percent) rightForm.addRow(QLabel("Profession Tax"), self.pt_percent) rightGroup = QGroupBox("Deductions") rightGroup.setLayout(rightForm) table = QHBoxLayout() table.addWidget(leftGroup) table.addWidget(rightGroup) layout.addLayout(table) layout.addStretch() bttnLayout = QHBoxLayout() bttnLayout.addStretch() bttnLayout.addWidget(self.bttnCancel) bttnLayout.addWidget(self.bttnCalculate) layout.addLayout(bttnLayout) paneLayout.addLayout(layout) self.setLayout(paneLayout)
class Form(QDialog): def __init__(self, state, parent=None): super().__init__(parent) Lib.prepareModalDialog(self) self.state = state self.setWindowTitle("Renumber Pages — {}".format( QApplication.applicationName())) self.createWidgets() self.layoutWidgets() self.createConnections() self.romanStartSpinBox.setFocus() self.updateUi() settings = QSettings() self.updateToolTips( bool( int( settings.value(Gopt.Key.ShowDialogToolTips, Gopt.Default.ShowDialogToolTips)))) def createWidgets(self): self.romanStartLabel = QLabel("&Roman from") self.romanStartSpinBox = Widgets.RomanSpinBox.SpinBox() self.tooltips.append((self.romanStartSpinBox, """\ <p><b>Roman from</b></p> <p>The first roman page number to change.</p>""")) self.romanStartLabel.setBuddy(self.romanStartSpinBox) self.romanEndLabel = QLabel("to") self.romanEndSpinBox = Widgets.RomanSpinBox.SpinBox() self.romanEndSpinBox.setValue(200) self.tooltips.append((self.romanEndSpinBox, """\ <p><b>Roman, to</b></p> <p>The last roman page number to change.</p>""")) self.romanChangeLabel = QLabel("change") self.romanChangeSpinBox = Widgets.ChangeSpinBox.SpinBox() self.romanChangeSpinBox.setRange(-100, 100) self.romanChangeSpinBox.setValue(0) self.romanChangeSpinBox.setMinimumWidth( self.romanChangeSpinBox.fontMetrics().width("W(no change)W")) self.tooltips.append((self.romanChangeSpinBox, """\ <p><b>Roman, change</b></p> <p>The amount to change the roman page numbers in the Roman from–to range.</p>""")) self.decimalStartLabel = QLabel("&Decimal from") self.decimalStartSpinBox = QSpinBox() self.decimalStartSpinBox.setAlignment(Qt.AlignRight) self.decimalStartLabel.setBuddy(self.decimalStartSpinBox) self.decimalStartSpinBox.setRange(1, 10000) self.tooltips.append((self.decimalStartSpinBox, """\ <p><b>Decimal from</b></p> <p>The first decimal page number to change.</p>""")) self.decimalEndLabel = QLabel("to") self.decimalEndSpinBox = QSpinBox() self.decimalEndSpinBox.setAlignment(Qt.AlignRight) self.decimalEndSpinBox.setRange(1, 10000) self.decimalEndSpinBox.setValue(2000) self.tooltips.append((self.decimalEndSpinBox, """\ <p><b>Decimal, to</b></p> <p>The last decimal page number to change.</p>""")) self.decimalChangeLabel = QLabel("change") self.decimalChangeSpinBox = Widgets.ChangeSpinBox.SpinBox() self.decimalChangeSpinBox.setRange(-100, 100) self.decimalChangeSpinBox.setValue(0) self.tooltips.append((self.decimalChangeSpinBox, """\ <p><b>Decimal, change</b></p> <p>The amount to change the decimal page numbers in the Decimal from–to range.</p>""")) self.buttonBox = QDialogButtonBox() self.renumberButton = QPushButton(QIcon(":/renumberpages.svg"), "Re&number") self.tooltips.append((self.renumberButton, """\ <p><b>Renumber</b></p> <p>Renumber roman and decimal page numbers within the given ranges by the specified amounts of change throughout the entire index.</p>""")) self.buttonBox.addButton(self.renumberButton, QDialogButtonBox.ActionRole) self.closeButton = QPushButton(QIcon(":/dialog-close.svg"), "&Cancel") self.tooltips.append((self.closeButton, """<p><b>Cancel</b></p> <p>Close the dialog without making any changes to the index.</p>""")) self.buttonBox.addButton(self.closeButton, QDialogButtonBox.RejectRole) self.helpButton = QPushButton(QIcon(":/help.svg"), "Help") self.tooltips.append( (self.helpButton, "Help on the Renumber Pages dialog")) self.buttonBox.addButton(self.helpButton, QDialogButtonBox.HelpRole) def layoutWidgets(self): grid = QGridLayout() grid.addWidget(self.romanStartLabel, 0, 0) grid.addWidget(self.romanStartSpinBox, 0, 1) grid.addWidget(self.romanEndLabel, 0, 2) grid.addWidget(self.romanEndSpinBox, 0, 3) grid.addWidget(self.romanChangeLabel, 0, 4) grid.addWidget(self.romanChangeSpinBox, 0, 5) grid.addWidget(self.decimalStartLabel, 1, 0) grid.addWidget(self.decimalStartSpinBox, 1, 1) grid.addWidget(self.decimalEndLabel, 1, 2) grid.addWidget(self.decimalEndSpinBox, 1, 3) grid.addWidget(self.decimalChangeLabel, 1, 4) grid.addWidget(self.decimalChangeSpinBox, 1, 5) hbox = QHBoxLayout() hbox.addLayout(grid) hbox.addStretch() layout = QVBoxLayout() layout.addLayout(hbox) layout.addStretch() layout.addWidget(self.buttonBox) self.setLayout(layout) def createConnections(self): self.buttonBox.rejected.connect(self.reject) self.renumberButton.clicked.connect(self.renumber) for spinbox in (self.romanStartSpinBox, self.romanEndSpinBox, self.romanChangeSpinBox, self.decimalStartSpinBox, self.decimalEndSpinBox, self.decimalChangeSpinBox): spinbox.valueChanged.connect(self.updateUi) self.helpButton.clicked.connect(self.help) def updateUi(self): self._synchronize(self.romanStartSpinBox, self.romanEndSpinBox) self._synchronize(self.decimalStartSpinBox, self.decimalEndSpinBox) changeRoman = ( (self.romanStartSpinBox.value() != self.romanEndSpinBox.value()) and self.romanChangeSpinBox.value() != 0) changeDecimal = ((self.decimalStartSpinBox.value() != self.decimalEndSpinBox.value()) and self.decimalChangeSpinBox.value() != 0) self.renumberButton.setEnabled(changeRoman or changeDecimal) self._setPrefix(self.romanChangeSpinBox) self._setPrefix(self.decimalChangeSpinBox) def _synchronize(self, startSpinBox, endSpinBox): value = startSpinBox.value() if endSpinBox.value() < value: endSpinBox.setValue(value) def _setPrefix(self, spinbox): spinbox.setPrefix("+" if spinbox.value() > 0 else "") def help(self): self.state.help("xix_ref_dlg_renumpages.html") def renumber(self): # No need to restore focus widget options = RenumberOptions(self.romanStartSpinBox.value(), self.romanEndSpinBox.value(), self.romanChangeSpinBox.value(), self.decimalStartSpinBox.value(), self.decimalEndSpinBox.value(), self.decimalChangeSpinBox.value()) with Lib.DisableUI(self): self.state.model.renumber(options, self.state.window.reportProgress) message = "Renumber pages" if self.state.model.canUndo: self.state.model.can_undo.emit(True, message) if self.state.model.canRedo: self.state.model.can_redo.emit(True, message) self.state.updateUi() say("Renumbered pages", SAY_TIMEOUT) self.accept()
class Panel(QWidget): def __init__(self, state, config, parent): super().__init__(parent) self.state = state self.config = config self.form = parent self.createWidgets() self.layoutWidgets() self.createConnections() def createWidgets(self): settings = QSettings() creator = settings.value(Gopt.Key.Creator, self.state.user) self.creatorLineEdit = QLineEdit() self.creatorLineEdit.setText(creator) self.form.tooltips.append((self.creatorLineEdit, """\ <p><b>Creator</b></p> <p>The indexer's name.</p>""")) initials = "" if creator: initials = Lib.initials(creator) initials = settings.value(Gopt.Key.Initials, initials) self.initialsLineEdit = QLineEdit() self.initialsLineEdit.setMaximumWidth( self.initialsLineEdit.fontMetrics().width("W") * 4) self.initialsLineEdit.setText(initials) self.form.tooltips.append((self.initialsLineEdit, """\ <p><b>Initials</b></p> <p>The indexer's initials.</p>""")) self.languageGroupBox = QGroupBox("&Language") defaultLanguage = LanguageKind( settings.value(Gopt.Key.Language, Gopt.Default.Language)) thisLanguage = self.config.get(Gconf.Key.Language, defaultLanguage) self.defaultLanguageComboBox = QComboBox() self.form.tooltips.append((self.defaultLanguageComboBox, """\ <p><b>Language, Default</b></p> <p>The default setting for the <b>Language, For This Index</b> combobox for new indexes.</p>""")) self.thisLanguageComboBox = QComboBox() self.form.tooltips.append((self.thisLanguageComboBox, """\ <p><b>Language, For This Index</b></p> <p>The language to use for spellchecking and suggestions for this index.</p>""")) self.populateLanguageComboBox(self.defaultLanguageComboBox, defaultLanguage) self.populateLanguageComboBox(self.thisLanguageComboBox, thisLanguage) self.limitsGroupBox = QGroupBox("Publisher's Limits for this Index") self.highestPageSpinBox = QSpinBox() self.highestPageSpinBox.setAlignment(Qt.AlignRight) self.highestPageSpinBox.setRange(10, 26000) self.highestPageSpinBox.setValue( self.config.get(Gconf.Key.HighestPageNumber, Gconf.Default.HighestPageNumber)) self.form.tooltips.append((self.highestPageSpinBox, """\ <p><b>Highest Page Number</b></p> <p>Any entries which contain a page number greater than this one will be shown in the Filtered view if you use the “Too High Page Number” filter.</p>""")) self.largestPageRangeSpinBox = QSpinBox() self.largestPageRangeSpinBox.setAlignment(Qt.AlignRight) self.largestPageRangeSpinBox.setRange(2, 1000) self.largestPageRangeSpinBox.setValue( self.config.get(Gconf.Key.LargestPageRange, Gconf.Default.LargestPageRange)) self.form.tooltips.append((self.largestPageRangeSpinBox, """\ <p><b>Largest Page Range Span</b></p> <p>Any entries which contain a page range that spans more pages than this will be shown in the Filtered view if you use the “Too Large Page Range” filter.</p>""")) self.mostPagesSpinBox = QSpinBox() self.mostPagesSpinBox.setAlignment(Qt.AlignRight) self.mostPagesSpinBox.setRange(2, 100) self.mostPagesSpinBox.setValue( self.config.get(Gconf.Key.MostPages, Gconf.Default.MostPages)) self.form.tooltips.append((self.mostPagesSpinBox, """\ <p><b>Most Pages per Entry</b></p> <p>Any entries which contain more pages and page ranges this will be shown in the Filtered view if you use the “Too Many Pages” filter.</p>""")) def layoutWidgets(self): layout = QVBoxLayout() form = QFormLayout() form.addRow("C&reator", self.creatorLineEdit) form.addRow("&Initials", self.initialsLineEdit) layout.addLayout(form) form = QFormLayout() form.addRow("For This Index", self.thisLanguageComboBox) form.addRow("Default", self.defaultLanguageComboBox) self.languageGroupBox.setLayout(form) layout.addWidget(self.languageGroupBox) form = QFormLayout() form.addRow("&Highest Page Number", self.highestPageSpinBox) form.addRow("Largest &Page Range Span", self.largestPageRangeSpinBox) form.addRow("&Most Pages per Entry", self.mostPagesSpinBox) self.limitsGroupBox.setLayout(form) hbox = QHBoxLayout() hbox.addWidget(self.limitsGroupBox) hbox.addStretch() layout.addLayout(hbox) layout.addStretch() self.setLayout(layout) def createConnections(self): self.creatorLineEdit.textChanged.connect(self.updateInitials) self.defaultLanguageComboBox.currentIndexChanged.connect( self.setDefaultLanguage) self.thisLanguageComboBox.currentIndexChanged.connect( self.setThisLanguage) def updateInitials(self): text = self.creatorLineEdit.text() if text: initials = Lib.initials(text) if initials: self.initialsLineEdit.setText(initials) def populateLanguageComboBox(self, combobox, theLanguage): index = -1 for i, language in enumerate(LanguageKind): if language is theLanguage: index = i name = language.value combobox.addItem(QIcon(":/{}.svg".format(name.replace(" ", "_"))), name, language) combobox.setCurrentIndex(index) def setDefaultLanguage(self, index): language = self.defaultLanguageComboBox.itemData(index) settings = QSettings() settings.setValue(Gopt.Key.Language, language.value) def setThisLanguage(self, index): language = self.defaultLanguageComboBox.itemData(index) self.state.model.setConfig(Gconf.Key.Language, language) self.state.entryPanel.spellHighlighter.rehighlight() self.state.window.updateLanguageIndicator()
class Panel(QWidget): def __init__(self, state, config, parent): super().__init__(parent) self.state = state self.config = config self.form = parent self.createWidgets() self.layoutWidgets() self.createConnections() def createWidgets(self): self.formatPanel = Widgets.FormatPanel.Panel(self.state, self, editableFontSize=True) formatActions = self.formatPanel.formatActions self.titleLabel = QLabel("&Index Title") self.titleTextEdit = Widgets.LineEdit.HtmlLineEdit( self.state, formatActions=formatActions) self.titleLabel.setBuddy(self.titleTextEdit) self.titleTextEdit.setHtml(self.config.get(Gconf.Key.Title)) self.form.tooltips.append((self.titleTextEdit, """\ <p><b>Index Title</b></p> <p>The index's title. Leave blank if the title is to be added directly in the output file.</p>""")) self.noteLabel = QLabel("Index &Note") self.noteTextEdit = Widgets.LineEdit.MultilineHtmlEdit( self.state, maxLines=8, formatActions=formatActions) self.noteLabel.setBuddy(self.noteTextEdit) self.noteTextEdit.setLineWrapMode(QTextEdit.FixedColumnWidth) self.noteTextEdit.setLineWrapColumnOrWidth(60) self.noteTextEdit.setWordWrapMode(QTextOption.WordWrap) self.noteTextEdit.setHtml(self.config.get(Gconf.Key.Note)) self.form.tooltips.append((self.noteTextEdit, """\ <p><b>Index Note</b></p> <p>The index's note. Leave blank if no note is required or if the note is to be added directly in the output file.</p>""")) self.sectionsGroupBox = QGroupBox("Sections") self.blankBeforeLabel = QLabel("&Blank Lines Before") self.blankBeforeSpinBox = QSpinBox() self.blankBeforeSpinBox.setAlignment(Qt.AlignRight) self.blankBeforeLabel.setBuddy(self.blankBeforeSpinBox) self.blankBeforeSpinBox.setRange(0, 3) self.blankBeforeSpinBox.setValue( self.config.get(Gconf.Key.SectionPreLines)) self.form.tooltips.append((self.blankBeforeSpinBox, """\ <p><b>Blank Lines Before</b></p> <p>How many blank lines to output before a section. (A section is a distinct part of the index, e.g., the ‘A’s.)</p>""")) self.blankAfterLabel = QLabel("Blank &Lines After") self.blankAfterSpinBox = QSpinBox() self.blankAfterSpinBox.setAlignment(Qt.AlignRight) self.blankAfterLabel.setBuddy(self.blankAfterSpinBox) self.blankAfterSpinBox.setRange(0, 3) self.blankAfterSpinBox.setValue( self.config.get(Gconf.Key.SectionPostLines)) self.form.tooltips.append((self.blankAfterSpinBox, """\ <p><b>Blank Lines After</b></p> <p>How many blank lines to output before after section's title. (A section is a distinct part of the index, e.g., the ‘A’s.)</p>""")) self.sectionTitlesCheckBox = QCheckBox("&Output Titles") self.sectionTitlesCheckBox.setChecked( self.config.get(Gconf.Key.SectionTitles)) self.form.tooltips.append((self.sectionTitlesCheckBox, """\ <p><b>Output Titles</b></p> <p>If checked, section titles are output before each section, e.g., ‘A’, before the As, ‘B’, before the Bs, and so on.</p>""")) self.sectionSpecialTitleLabel = QLabel("Special Section &Title") self.sectionSpecialTitleTextEdit = Widgets.LineEdit.HtmlLineEdit( self.state, formatActions=formatActions) self.sectionSpecialTitleLabel.setBuddy( self.sectionSpecialTitleTextEdit) self.sectionSpecialTitleTextEdit.setHtml( self.config.get(Gconf.Key.SectionSpecialTitle)) self.form.tooltips.append((self.sectionSpecialTitleTextEdit, """\ <p><b>Special Section Title</b></p> <p>If there are entries which precede the ‘A’ section, then this section title will be used for them.</p> <p>Note that even if this title isn't used, its font name and size will be used for all the other section titles.</p>""")) size = self.font().pointSize() + (1 if WIN else 2) family = self.config.get(Gconf.Key.StdFont) size = self.config.get(Gconf.Key.StdFontSize, size) Lib.createFontBoxesFor(self, "Std", family, size, tooltips=self.form.tooltips, which="Std.") self.onStdFontChange(False) family = self.config.get(Gconf.Key.AltFont) size = self.config.get(Gconf.Key.AltFontSize, size) Lib.createFontBoxesFor(self, "Alt", family, size, tooltips=self.form.tooltips, which="Alt.") self.onAltFontChange(False) family = self.config.get(Gconf.Key.MonoFont) size = self.config.get(Gconf.Key.MonoFontSize, size) Lib.createFontBoxesFor(self, "Mono", family, size, mono=True, tooltips=self.form.tooltips, which="Mono.") self.onMonoFontChange(False) self.monoFontAsStrikeoutCheckbox = QCheckBox( "Output Mono. &Font as Strikeout") self.form.tooltips.append((self.monoFontAsStrikeoutCheckbox, """\ <p><b>Output Mono. Font as Strikeout</b></p> <p>If checked, any text in the index that is styled as mono. font family will be output using the std. font family—but with <s>strikeout</s>.</p>""")) self.monoFontAsStrikeoutCheckbox.setChecked( self.config.get(Gconf.Key.MonoFontAsStrikeout)) self.styleLabel = QLabel("St&yle") self.styleComboBox = QComboBox() self.styleLabel.setBuddy(self.styleComboBox) oldStyle = self.config.get(Gconf.Key.Style) index = -1 for i, style in enumerate(StyleKind): self.styleComboBox.addItem(style.text, style.value) if style is oldStyle: index = i self.styleComboBox.setCurrentIndex(index) self.form.tooltips.append((self.styleComboBox, """\ <p><b>Style</b></p> <p>The style of index to output.</p>""")) self.termPagesSepLabel = QLabel("T&erm-Pages Separator") self.termPagesSepTextEdit = Widgets.LineEdit.SpacesHtmlLineEdit( self.state, 3, formatActions=formatActions) self.termPagesSepLabel.setBuddy(self.termPagesSepTextEdit) self.termPagesSepTextEdit.setHtml( self.config.get(Gconf.Key.TermPagesSeparator)) self.form.tooltips.append((self.termPagesSepTextEdit, """\ <p><b>Term-Pages Separator</b></p> <p>The separator text to use between the end of an entry's term and its pages.</p>{}""".format(BLANK_SPACE_HTML))) self.runInSepLabel = QLabel("&Run-in Separator") self.runInSepTextEdit = Widgets.LineEdit.SpacesHtmlLineEdit( self.state, 3, formatActions=formatActions) self.runInSepLabel.setBuddy(self.runInSepTextEdit) self.runInSepTextEdit.setHtml(self.config.get( Gconf.Key.RunInSeparator)) self.form.tooltips.append((self.runInSepTextEdit, """\ <p><b>Run-in Separator</b></p> <p>The separator text to use between run-in entries (for run-in style index output).</p>{}""".format(BLANK_SPACE_HTML))) self.formatPanel.state.editors = [ self.titleTextEdit, self.noteTextEdit, self.sectionSpecialTitleTextEdit, self.termPagesSepTextEdit, self.runInSepTextEdit ] def layoutWidgets(self): form = QFormLayout() hbox = QHBoxLayout() hbox.addStretch() hbox.addWidget(self.formatPanel) form.addRow(hbox) form.addRow(self.titleLabel, self.titleTextEdit) form.addRow(self.noteLabel, self.noteTextEdit) vbox = QVBoxLayout() hbox = QHBoxLayout() hbox.addWidget(self.blankBeforeLabel) hbox.addWidget(self.blankBeforeSpinBox) hbox.addWidget(self.blankAfterLabel) hbox.addWidget(self.blankAfterSpinBox) hbox.addStretch() vbox.addLayout(hbox) hbox = QHBoxLayout() hbox.addWidget(self.sectionTitlesCheckBox) hbox.addStretch() hbox.addWidget(self.sectionSpecialTitleLabel) hbox.addWidget(self.sectionSpecialTitleTextEdit) vbox.addLayout(hbox) self.sectionsGroupBox.setLayout(vbox) form.addRow(self.sectionsGroupBox) hbox = QHBoxLayout() hbox.addWidget(self.stdFontComboBox, 1) hbox.addWidget(self.stdFontSizeSpinBox) hbox.addStretch() label = QLabel("&Std. Font") label.setBuddy(self.stdFontComboBox) form.addRow(label, hbox) hbox = QHBoxLayout() hbox.addWidget(self.altFontComboBox, 1) hbox.addWidget(self.altFontSizeSpinBox) hbox.addStretch() label = QLabel("&Alt. Font") label.setBuddy(self.altFontComboBox) form.addRow(label, hbox) hbox = QHBoxLayout() hbox.addWidget(self.monoFontComboBox, 1) hbox.addWidget(self.monoFontSizeSpinBox) hbox.addStretch() label = QLabel("&Mono. Font") label.setBuddy(self.monoFontComboBox) form.addRow(label, hbox) grid = QGridLayout() grid.addWidget(self.monoFontAsStrikeoutCheckbox, 0, 0, 1, 2) grid.addWidget(self.termPagesSepLabel, 0, 2) grid.addWidget(self.termPagesSepTextEdit, 0, 3) grid.addWidget(self.styleLabel, 1, 0) grid.addWidget(self.styleComboBox, 1, 1) grid.addWidget(self.runInSepLabel, 1, 2) grid.addWidget(self.runInSepTextEdit, 1, 3) form.addRow(grid) self.setLayout(form) def createConnections(self): self.stdFontComboBox.currentFontChanged.connect(self.onStdFontChange) self.stdFontSizeSpinBox.valueChanged[int].connect(self.onStdFontChange) self.altFontComboBox.currentFontChanged.connect(self.onAltFontChange) self.altFontSizeSpinBox.valueChanged[int].connect(self.onAltFontChange) self.monoFontComboBox.currentFontChanged.connect(self.onMonoFontChange) self.monoFontSizeSpinBox.valueChanged[int].connect( self.onMonoFontChange) def onStdFontChange(self, propagate=True): font = QFont(self.stdFontComboBox.currentFont()) font.setPointSize(self.stdFontSizeSpinBox.value()) if propagate and bool(self.state.model): self.state.model.setConfig(Gconf.Key.StdFont, font.family()) self.state.model.setConfig(Gconf.Key.StdFontSize, font.pointSize()) def onAltFontChange(self, propagate=True): font = QFont(self.altFontComboBox.currentFont()) font.setPointSize(self.altFontSizeSpinBox.value()) if propagate and bool(self.state.model): self.state.model.setConfig(Gconf.Key.AltFont, font.family()) self.state.model.setConfig(Gconf.Key.AltFontSize, font.pointSize()) def onMonoFontChange(self, propagate=True): font = QFont(self.monoFontComboBox.currentFont()) font.setPointSize(self.monoFontSizeSpinBox.value()) if propagate and bool(self.state.model): self.state.model.setConfig(Gconf.Key.MonoFont, font.family()) self.state.model.setConfig(Gconf.Key.MonoFontSize, font.pointSize())
class Panel(QWidget): def __init__(self, state, config, parent): super().__init__(parent) self.state = state self.config = config self.form = parent self.createWidgets() self.layoutWidgets() self.createConnections() def createWidgets(self): settings = QSettings() self.sortRulesGroupBox = QGroupBox("Calculate &Sort As Rules") defaultSortAsRules = settings.value(Gconf.Key.SortAsRules, Gopt.Default.SortAsRules) self.thisSortAsRules = self.config.get(Gopt.Key.SortAsRules, defaultSortAsRules) self.defaultSortAsRulesBox = QComboBox() self.form.tooltips.append((self.defaultSortAsRulesBox, """\ <p><b>Calculate Sort As Rules, Default</b></p> <p>The default setting for the <b>Calculate Sort As Rules, For This Index</b> combobox for new indexes.</p>""")) self.thisSortAsRulesBox = QComboBox() self.form.tooltips.append((self.thisSortAsRulesBox, """\ <p><b>Calculate Sort As Rules, For This Index</b></p> <p>The rules to use for calculating each entry's sort as text for this index.</p> <p>If the rules are changed, when the dialog is closed, the new rules will be applied to every entry in the index.</p>""")) self.populateSortAsRulesBox(self.defaultSortAsRulesBox, defaultSortAsRules) self.populateSortAsRulesBox(self.thisSortAsRulesBox, self.thisSortAsRules) self.pageRangeRulesBox = QGroupBox("&Page Range Rules") defaultPageRangeRules = settings.value(Gconf.Key.PageRangeRules, Gopt.Default.PageRangeRules) self.thisPageRangeRules = self.config.get(Gopt.Key.PageRangeRules, defaultPageRangeRules) self.defaultPageRangeRulesBox = QComboBox() self.form.tooltips.append((self.defaultPageRangeRulesBox, """\ <p><b>Page Range Rules, Default</b></p> <p>The default setting for the <b>Page Range Rules, For This Index</b> combobox for new indexes.</p>""")) self.thisPageRangeRulesBox = QComboBox() self.form.tooltips.append((self.thisPageRangeRulesBox, """\ <p><b>Page Range Rules, For This Index</b></p> <p>The rules to use for handling page ranges, e.g., whether in full such as 120–124, or somehow compressed, e.g., 120–4, for this index.</p> <p>If the rules are changed, when the dialog is closed, the new rules will be applied to every entry in the index.</p>""")) self.populatePageRangeRulesBox(self.defaultPageRangeRulesBox, defaultPageRangeRules) self.populatePageRangeRulesBox(self.thisPageRangeRulesBox, self.thisPageRangeRules) self.padDigitsGroupBox = QGroupBox("Pad &Digits") defaultPadDigits = int( settings.value(Gconf.Key.PadDigits, Gopt.Default.PadDigits)) self.thisPadDigits = int( self.config.get(Gopt.Key.PadDigits, defaultPadDigits)) self.thisPadDigitsLabel = QLabel("For This Index") self.thisPadDigitsSpinBox = QSpinBox() self.thisPadDigitsSpinBox.setAlignment(Qt.AlignRight) self.thisPadDigitsSpinBox.setRange(0, 12) self.thisPadDigitsSpinBox.setValue(self.thisPadDigits) self.form.tooltips.append((self.thisPadDigitsSpinBox, """\ <p><b>Pad Digits, For This Index</b></p> <p>Sort as texts are compared textually, so if a term contains a number (or text which is converted to a number), the number must be padded by leading zeros to ensure correct ordering. This is the number of digits to pad for, for this index. For example, if set to 4, the numbers 1, 23, and 400 would be set to 0001, 0023, and 0400, in the sort as text.</p>""")) self.defaultPadDigitsLabel = QLabel("Default") self.defaultPadDigitsSpinBox = QSpinBox() self.defaultPadDigitsSpinBox.setAlignment(Qt.AlignRight) self.defaultPadDigitsSpinBox.setRange(0, 12) self.defaultPadDigitsSpinBox.setValue(defaultPadDigits) self.form.tooltips.append((self.defaultPadDigitsSpinBox, """\ <p><b>Pad Digits, Default</b></p> <p>The default setting for the <b>Pad Digits, For This Index</b> spinbox for new indexes.</p>""")) self.ignoreSubFirstsGroupBox = QGroupBox( "&Ignore Subentry Function Words") defaultIgnoreSubFirsts = bool( int( settings.value(Gconf.Key.IgnoreSubFirsts, Gopt.Default.IgnoreSubFirsts))) thisIgnoreSubFirsts = bool( int( self.config.get(Gopt.Key.IgnoreSubFirsts, defaultIgnoreSubFirsts))) self.thisIgnoreSubFirstsCheckBox = QCheckBox("For This Index") self.thisIgnoreSubFirstsCheckBox.setChecked(thisIgnoreSubFirsts) self.form.tooltips.append((self.thisIgnoreSubFirstsCheckBox, """\ <p><b>Ignore Subentry Function Words, For This Index</b></p> <p>This setting applies to this index.</p> <p>If checked, words listed in the <b>Index→Ignore Subentry Function Words</b> list are ignored for sorting purposes when the first word of a subentry, i.e., ignored when the first word of an entry's sort as text.</p> <p>This should normally be checked for Chicago Manual of Style Sort As Rules, and unchecked for NISO Rules.</p>""")) self.defaultIgnoreSubFirstsCheckBox = QCheckBox("Default") self.defaultIgnoreSubFirstsCheckBox.setChecked(defaultIgnoreSubFirsts) self.form.tooltips.append((self.defaultIgnoreSubFirstsCheckBox, """\ <p><b>Ignore Subentry Function Words, Default</b></p> <p>The default setting for the <b>Ignore Subentry Function Words, For This Index</b> checkbox for new indexes</p>""")) self.suggestSpelledGroupBox = QGroupBox( "&Suggest Spelled Out Numbers when Appropriate") defaultSuggestSpelled = bool( int( settings.value(Gconf.Key.SuggestSpelled, Gopt.Default.SuggestSpelled))) thisSuggestSpelled = bool( int(self.config.get(Gopt.Key.SuggestSpelled, defaultSuggestSpelled))) self.thisSuggestSpelledCheckBox = QCheckBox("For This Index") self.thisSuggestSpelledCheckBox.setChecked(thisSuggestSpelled) self.form.tooltips.append((self.thisSuggestSpelledCheckBox, """\ <p><b>Suggest Spelled Out Numbers when Appropriate, For This Index</b></p> <p>When checked (and providing the Sort As rules in force are not NISO rules), when adding or editing a term when the <b>Automatically Calculate Sort As</b> checkbox is checked, and when the term contains a number, the choice of sort as texts will include the number spelled out.</p>""")) self.defaultSuggestSpelledCheckBox = QCheckBox("Default") self.defaultSuggestSpelledCheckBox.setChecked(defaultSuggestSpelled) self.form.tooltips.append((self.defaultSuggestSpelledCheckBox, """\ <p><b>Suggest Spelled Out Numbers when Appropriate, Default</b></p> <p>The default setting for the <b>Suggest Spelled Out Numbers when Appropriate, For This Index</b> checkbox for new indexes.</p>""")) def layoutWidgets(self): layout = QVBoxLayout() form = QFormLayout() form.addRow("For This Index", self.thisSortAsRulesBox) form.addRow("Default", self.defaultSortAsRulesBox) self.sortRulesGroupBox.setLayout(form) layout.addWidget(self.sortRulesGroupBox) form = QFormLayout() form.addRow("For This Index", self.thisPageRangeRulesBox) form.addRow("Default", self.defaultPageRangeRulesBox) self.pageRangeRulesBox.setLayout(form) layout.addWidget(self.pageRangeRulesBox) hbox = QHBoxLayout() hbox.addWidget(self.thisPadDigitsLabel) hbox.addWidget(self.thisPadDigitsSpinBox) hbox.addStretch(1) hbox.addWidget(self.defaultPadDigitsLabel) hbox.addWidget(self.defaultPadDigitsSpinBox) hbox.addStretch(3) self.padDigitsGroupBox.setLayout(hbox) layout.addWidget(self.padDigitsGroupBox) hbox = QHBoxLayout() hbox.addWidget(self.thisIgnoreSubFirstsCheckBox) hbox.addWidget(self.defaultIgnoreSubFirstsCheckBox) hbox.addStretch() self.ignoreSubFirstsGroupBox.setLayout(hbox) layout.addWidget(self.ignoreSubFirstsGroupBox) hbox = QHBoxLayout() hbox.addWidget(self.thisSuggestSpelledCheckBox) hbox.addWidget(self.defaultSuggestSpelledCheckBox) hbox.addStretch() self.suggestSpelledGroupBox.setLayout(hbox) layout.addWidget(self.suggestSpelledGroupBox) layout.addStretch() self.setLayout(layout) def createConnections(self): self.defaultSortAsRulesBox.currentIndexChanged.connect( self.setDefaultSortAsRules) self.defaultPageRangeRulesBox.currentIndexChanged.connect( self.setDefaultPageRangeRules) self.defaultPadDigitsSpinBox.valueChanged.connect( self.setDefaultPadDigits) self.defaultIgnoreSubFirstsCheckBox.toggled.connect( self.setDefaultIgnoreSubFirsts) self.defaultSuggestSpelledCheckBox.toggled.connect( self.setDefaultSuggestSpelled) def populateSortAsRulesBox(self, combobox, rules): index = -1 for i, name in enumerate(SortAs.RulesForName): displayName = SortAs.RulesForName[name].name combobox.addItem(displayName, name) if name == rules: index = i combobox.setCurrentIndex(index) def setDefaultSortAsRules(self, index): index = self.defaultSortAsRulesBox.currentIndex() name = self.defaultSortAsRulesBox.itemData(index) settings = QSettings() settings.setValue(Gopt.Key.SortAsRules, name) def populatePageRangeRulesBox(self, combobox, rules): index = -1 for i, name in enumerate(Pages.RulesForName): displayName = Pages.RulesForName[name].name combobox.addItem(displayName, name) if name == rules: index = i combobox.setCurrentIndex(index) def setDefaultPageRangeRules(self, index): index = self.defaultPageRangeRulesBox.currentIndex() name = self.defaultPageRangeRulesBox.itemData(index) settings = QSettings() settings.setValue(Gopt.Key.PageRangeRules, name) def setDefaultPadDigits(self): value = self.defaultPadDigitsSpinBox.value() settings = QSettings() settings.setValue(Gopt.Key.PadDigits, value) def setDefaultIgnoreSubFirsts(self): value = int(self.defaultIgnoreSubFirstsCheckBox.isChecked()) settings = QSettings() settings.setValue(Gopt.Key.IgnoreSubFirsts, value) def setDefaultSuggestSpelled(self): value = int(self.defaultSuggestSpelledCheckBox.isChecked()) settings = QSettings() settings.setValue(Gopt.Key.SuggestSpelled, value)
# logo_style logo_style_label = QLabel("Logo style:") layout.addWidget(logo_style_label, 1, 2) logo_style_combo_box = QComboBox() logo_style_combo_box.addItem("Steady") logo_style_combo_box.addItem("Slow breath") logo_style_combo_box.addItem("Middle breath") logo_style_combo_box.addItem("Fast breath") layout.addWidget(logo_style_combo_box, 1, 3) # cpi1 cpi_one_label = QLabel("CPI1 (800):") layout.addWidget(cpi_one_label, 2, 0) cpi_one_spin_box = QSpinBox() cpi_one_spin_box.setRange(50, 6500) cpi_one_spin_box.setValue(800) cpi_one_spin_box.setSingleStep(50) layout.addWidget(cpi_one_spin_box, 2, 1) # cpi2 cpi_two_label = QLabel("CPI2 (1600):") layout.addWidget(cpi_two_label, 2, 2) cpi_two_spin_box = QSpinBox() cpi_two_spin_box.setRange(50, 6500) cpi_two_spin_box.setValue(1600) cpi_two_spin_box.setSingleStep(50) layout.addWidget(cpi_two_spin_box, 2, 3) # polling_rate polling_rate_label = QLabel("Polling rate (1000):")
class RunnerDialog(QDialog): options_added = Signal(Options) options_running = Signal(Options) options_simulated = Signal(Options) options_error = Signal(Options, Exception) results_saved = Signal(Results, str) results_error = Signal(Results, Exception) def __init__(self, parent=None): QDialog.__init__(self, parent) self.setWindowTitle('Runner') self.setMinimumWidth(750) # Runner self._runner = None self._running_timer = QTimer() self._running_timer.setInterval(500) # Widgets self._dlg_progress = QProgressDialog() self._dlg_progress.setRange(0, 100) self._dlg_progress.setModal(True) self._dlg_progress.hide() lbl_outputdir = QLabel("Output directory") self._txt_outputdir = DirBrowseWidget() max_workers = cpu_count() #@UndefinedVariable lbl_workers = QLabel('Number of workers') self._spn_workers = QSpinBox() self._spn_workers.setRange(1, max_workers) self._spn_workers.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) lbl_max_workers = QLabel('(max: %i)' % max_workers) self._chk_overwrite = QCheckBox("Overwrite existing results in output directory") self._chk_overwrite.setChecked(True) self._lbl_available = QLabel('Available') self._lst_available = QListView() self._lst_available.setModel(_AvailableOptionsListModel()) self._lst_available.setSelectionMode(QListView.SelectionMode.MultiSelection) tlb_available = QToolBar() spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) tlb_available.addWidget(spacer) act_open = tlb_available.addAction(getIcon("document-open"), "Open") act_open.setShortcut(QKeySequence.Open) tlb_available.addSeparator() act_remove = tlb_available.addAction(getIcon("list-remove"), "Remove") act_clear = tlb_available.addAction(getIcon("edit-clear"), "Clear") self._btn_addtoqueue = QPushButton(getIcon("go-next"), "") self._btn_addtoqueue.setToolTip("Add to queue") self._btn_addtoqueue.setEnabled(False) self._btn_addalltoqueue = QPushButton(getIcon("go-last"), "") self._btn_addalltoqueue.setToolTip("Add all to queue") self._btn_addalltoqueue.setEnabled(False) self._lbl_options = QLabel('Queued/Running/Completed') self._tbl_options = QTableView() self._tbl_options.setModel(_StateOptionsTableModel()) self._tbl_options.setItemDelegate(_StateOptionsItemDelegate()) self._tbl_options.setSelectionMode(QListView.SelectionMode.NoSelection) self._tbl_options.setColumnWidth(1, 60) self._tbl_options.setColumnWidth(2, 80) header = self._tbl_options.horizontalHeader() header.setResizeMode(0, QHeaderView.Interactive) header.setResizeMode(1, QHeaderView.Fixed) header.setResizeMode(2, QHeaderView.Fixed) header.setResizeMode(3, QHeaderView.Stretch) self._btn_start = QPushButton(getIcon("media-playback-start"), "Start") self._btn_cancel = QPushButton("Cancel") self._btn_cancel.setEnabled(False) self._btn_close = QPushButton("Close") self._btn_import = QPushButton("Import") self._btn_import.setEnabled(False) # Layouts layout = QVBoxLayout() sublayout = QGridLayout() sublayout.addWidget(lbl_outputdir, 0, 0) sublayout.addWidget(self._txt_outputdir, 0, 1) sublayout.addWidget(lbl_workers, 1, 0) subsublayout = QHBoxLayout() subsublayout.addWidget(self._spn_workers) subsublayout.addWidget(lbl_max_workers) sublayout.addLayout(subsublayout, 1, 1) layout.addLayout(sublayout) sublayout.addWidget(self._chk_overwrite, 2, 0, 1, 3) sublayout = QGridLayout() sublayout.setColumnStretch(0, 1) sublayout.setColumnStretch(2, 3) sublayout.addWidget(self._lbl_available, 0, 0) sublayout.addWidget(self._lst_available, 1, 0) sublayout.addWidget(tlb_available, 2, 0) subsublayout = QVBoxLayout() subsublayout.addStretch() subsublayout.addWidget(self._btn_addtoqueue) subsublayout.addWidget(self._btn_addalltoqueue) subsublayout.addStretch() sublayout.addLayout(subsublayout, 1, 1) sublayout.addWidget(self._lbl_options, 0, 2) sublayout.addWidget(self._tbl_options, 1, 2) layout.addLayout(sublayout) sublayout = QHBoxLayout() sublayout.addStretch() sublayout.addWidget(self._btn_import) sublayout.addWidget(self._btn_start) sublayout.addWidget(self._btn_cancel) sublayout.addWidget(self._btn_close) layout.addLayout(sublayout) self.setLayout(layout) # Signal self._running_timer.timeout.connect(self._onRunningTimer) act_open.triggered.connect(self._onOpen) act_remove.triggered.connect(self._onRemove) act_clear.triggered.connect(self._onClear) self._btn_addtoqueue.released.connect(self._onAddToQueue) self._btn_addalltoqueue.released.connect(self._onAddAllToQueue) self._btn_start.released.connect(self._onStart) self._btn_cancel.released.connect(self._onCancel) self._btn_close.released.connect(self._onClose) self._btn_import.released.connect(self._onImport) self.options_added.connect(self._onOptionsAdded) self.options_running.connect(self._onOptionsRunning) self.options_simulated.connect(self._onOptionsSimulated) self.options_error.connect(self._onOptionsError) self.results_error.connect(self._onResultsError) # Defaults settings = get_settings() section = settings.add_section('gui') if hasattr(section, 'outputdir'): self._txt_outputdir.setPath(section.outputdir) if hasattr(section, 'maxworkers'): self._spn_workers.setValue(int(section.maxworkers)) if hasattr(section, 'overwrite'): state = True if section.overwrite.lower() == 'true' else False self._chk_overwrite.setChecked(state) def _onDialogProgressProgress(self, progress, status): self._dlg_progress.setValue(progress * 100) self._dlg_progress.setLabelText(status) def _onDialogProgressCancel(self): self._dlg_progress.hide() if self._options_reader_thread is None: return self._options_reader_thread.cancel() self._options_reader_thread.quit() self._options_reader_thread.wait() def _onDialogProgressException(self, ex): self._dlg_progress.hide() self._options_reader_thread.quit() self._options_reader_thread.wait() messagebox.exception(self, ex) def _onRunningTimer(self): self._tbl_options.model().reset() def _onOpen(self): settings = get_settings() curdir = getattr(settings.gui, 'opendir', os.getcwd()) filepath, namefilter = \ QFileDialog.getOpenFileName(self, "Open", curdir, 'Options [*.xml] (*.xml)') if not filepath or not namefilter: return settings.gui.opendir = os.path.dirname(filepath) if not filepath.endswith('.xml'): filepath += '.xml' self._options_reader_thread = _OptionsReaderWrapperThread(filepath) self._dlg_progress.canceled.connect(self._onDialogProgressCancel) self._options_reader_thread.resultReady.connect(self._onOpened) self._options_reader_thread.progressUpdated.connect(self._onDialogProgressProgress) self._options_reader_thread.exceptionRaised.connect(self._onDialogProgressException) self._options_reader_thread.start() self._dlg_progress.reset() self._dlg_progress.show() def _onOpened(self, options): self._dlg_progress.hide() self._options_reader_thread.quit() self._options_reader_thread.wait() self._options_reader_thread = None try: self._lst_available.model().addOptions(options) except Exception as ex: messagebox.exception(self, ex) def _onRemove(self): selection = self._lst_available.selectionModel().selection().indexes() if len(selection) == 0: QMessageBox.warning(self, "Queue", "Select an options") return model = self._lst_available.model() for row in sorted(map(methodcaller('row'), selection), reverse=True): model.popOptions(row) def _onClear(self): self._lst_available.model().clearOptions() def _onAddToQueue(self): selection = self._lst_available.selectionModel().selection().indexes() if len(selection) == 0: QMessageBox.warning(self, "Queue", "Select an options") return model = self._lst_available.model() for row in sorted(map(methodcaller('row'), selection), reverse=True): options = model.options(row) try: self._runner.put(options) except Exception as ex: messagebox.exception(self, ex) return def _onAddAllToQueue(self): model = self._lst_available.model() for row in reversed(range(0, model.rowCount())): options = model.options(row) try: self._runner.put(options) except Exception as ex: messagebox.exception(self, ex) return def _onStart(self): outputdir = self._txt_outputdir.path() if not outputdir: QMessageBox.critical(self, 'Start', 'Missing output directory') return max_workers = self._spn_workers.value() overwrite = self._chk_overwrite.isChecked() self.start(outputdir, overwrite, max_workers) def _onCancel(self): self.cancel() def _onClose(self): if self._runner is not None: self._runner.close() self._running_timer.stop() self.close() def _onImport(self): list_options = self._lst_available.model().listOptions() if not list_options: return # Select options dialog = _OptionsSelector(list_options) if not dialog.exec_(): return options = dialog.options() # Start importer outputdir = self._runner.outputdir max_workers = self._runner.max_workers importer = LocalImporter(outputdir, max_workers) importer.start() importer.put(options) self._dlg_progress.show() try: while importer.is_alive(): if self._dlg_progress.wasCanceled(): importer.cancel() break self._dlg_progress.setValue(importer.progress * 100) finally: self._dlg_progress.hide() def _onOptionsAdded(self, options): logging.debug('runner: optionsAdded') self._tbl_options.model().addOptions(options) def _onOptionsRunning(self, options): logging.debug('runner: optionsRunning') self._tbl_options.model().resetOptions(options) def _onOptionsSimulated(self, options): logging.debug('runner: optionsSimulated') self._tbl_options.model().resetOptions(options) def _onOptionsError(self, options, ex): logging.debug('runner: optionsError') self._tbl_options.model().resetOptions(options) def _onResultsError(self, results, ex): logging.debug('runner: resultsError') self._tbl_options.model().reset() def closeEvent(self, event): if self.is_running(): message = 'Runner is running. Do you want to continue?' answer = QMessageBox.question(self, 'Runner', message, QMessageBox.Yes | QMessageBox.No) if answer == QMessageBox.No: event.ignore() return self.cancel() self._dlg_progress.close() settings = get_settings() section = settings.add_section('gui') path = self._txt_outputdir.path() if path: section.outputdir = path section.maxworkers = str(self._spn_workers.value()) section.overwrite = str(self._chk_overwrite.isChecked()) settings.write() event.accept() def addAvailableOptions(self, options): self._lst_available.model().addOptions(options) def removeAvailableOptions(self, options): self._lst_available.model().removeOptions(options) def clearAvailableOptions(self): self._lbl_available.model().clearOptions() def start(self, outputdir, overwrite, max_workers): self._runner = LocalRunner(outputdir=outputdir, overwrite=overwrite, max_workers=max_workers) self._tbl_options.setModel(_StateOptionsTableModel(self._runner)) self._spn_workers.setEnabled(False) self._txt_outputdir.setEnabled(False) self._chk_overwrite.setEnabled(False) self._btn_addtoqueue.setEnabled(True) self._btn_addalltoqueue.setEnabled(True) self._btn_start.setEnabled(False) self._btn_cancel.setEnabled(True) self._btn_close.setEnabled(False) self._btn_import.setEnabled(True) self._runner.options_added.connect(self.options_added.emit) self._runner.options_running.connect(self.options_running.emit) self._runner.options_simulated.connect(self.options_simulated.emit) self._runner.options_error.connect(self.options_error.emit) self._runner.results_saved.connect(self.results_saved.emit) self._runner.results_error.connect(self.results_error.emit) self._running_timer.start() self._runner.start() def cancel(self): if self._runner is None: return self._runner.cancel() self._running_timer.stop() self._runner.options_added.disconnect(self.options_added.emit) self._runner.options_running.disconnect(self.options_running.emit) self._runner.options_simulated.disconnect(self.options_simulated.emit) self._runner.options_error.disconnect(self.options_error.emit) self._runner.results_saved.disconnect(self.results_saved.emit) self._runner.results_error.disconnect(self.results_error.emit) self._runner = None self._spn_workers.setEnabled(True) self._txt_outputdir.setEnabled(True) self._chk_overwrite.setEnabled(True) self._btn_addtoqueue.setEnabled(False) self._btn_addalltoqueue.setEnabled(False) self._btn_start.setEnabled(True) self._btn_cancel.setEnabled(False) self._btn_close.setEnabled(True) self._btn_import.setEnabled(False) def is_running(self): return self._runner is not None and self._runner.is_alive()
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.debug = debug self.progset = QSettings("ADLMIDI-pyGUI", "ADLMIDI-pyGUI") self.about_window = None self.settings_window = None self.paused = False self.MaxRecentFiles = int(self.progset.value("file/MaxRecentFiles", 5)) self.recentList = self.progset.value("file/recent", []) if type(self.recentList) is unicode: self.recentList = [self.recentList] self.banks = [ " 0 = AIL (Star Control 3, Albion, Empire 2, Sensible Soccer, Settlers 2, many others)", "01 = Bisqwit (selection of 4op and 2op)", "02 = HMI (Descent, Asterix)", "03 = HMI (Descent:: Int)", "04 = HMI (Descent:: Ham)", "05 = HMI (Descent:: Rick)", "06 = HMI (Descent 2)", "07 = HMI (Normality)", "08 = HMI (Shattered Steel)", "09 = HMI (Theme Park)", "10 = HMI (3d Table Sports, Battle Arena Toshinden)", "11 = HMI (Aces of the Deep)", "12 = HMI (Earthsiege)", "13 = HMI (Anvil of Dawn)", "14 = DMX (Doom :: partially pseudo 4op)", "15 = DMX (Hexen, Heretic :: partially pseudo 4op)", "16 = DMX (MUS Play :: partially pseudo 4op)", "17 = AIL (Discworld, Grandest Fleet, Pocahontas, Slob Zone 3d, Ultima 4, Zorro)", "18 = AIL (Warcraft 2)", "19 = AIL (Syndicate)", "20 = AIL (Guilty, Orion Conspiracy, Terra Nova Strike Force Centauri :: 4op)", "21 = AIL (Magic Carpet 2)", "22 = AIL (Nemesis)", "23 = AIL (Jagged Alliance)", "24 = AIL (When Two Worlds War :: 4op, MISSING INSTRUMENTS)", "25 = AIL (Bards Tale Construction :: MISSING INSTRUMENTS)", "26 = AIL (Return to Zork)", "27 = AIL (Theme Hospital)", "28 = AIL (National Hockey League PA)", "29 = AIL (Inherit The Earth)", "30 = AIL (Inherit The Earth, file two)", "31 = AIL (Little Big Adventure :: 4op)", "32 = AIL (Wreckin Crew)", "33 = AIL (Death Gate)", "34 = AIL (FIFA International Soccer)", "35 = AIL (Starship Invasion)", "36 = AIL (Super Street Fighter 2 :: 4op)", "37 = AIL (Lords of the Realm :: MISSING INSTRUMENTS)", "38 = AIL (SimFarm, SimHealth :: 4op)", "39 = AIL (SimFarm, Settlers, Serf City)", "40 = AIL (Caesar 2 :: partially 4op, MISSING INSTRUMENTS)", "41 = AIL (Syndicate Wars)", "42 = AIL (Bubble Bobble Feat. Rainbow Islands, Z)", "43 = AIL (Warcraft)", "44 = AIL (Terra Nova Strike Force Centuri :: partially 4op)", "45 = AIL (System Shock :: partially 4op)", "46 = AIL (Advanced Civilization)", "47 = AIL (Battle Chess 4000 :: partially 4op, melodic only)", "48 = AIL (Ultimate Soccer Manager :: partially 4op)", "49 = AIL (Air Bucks, Blue And The Gray, America Invades, Terminator 2029)", "50 = AIL (Ultima Underworld 2)", "51 = AIL (Kasparov's Gambit)", "52 = AIL (High Seas Trader :: MISSING INSTRUMENTS)", "53 = AIL (Master of Magic, Master of Orion 2 :: 4op, std percussion)", "54 = AIL (Master of Magic, Master of Orion 2 :: 4op, orchestral percussion)", "55 = SB (Action Soccer)", "56 = SB (3d Cyberpuck :: melodic only)", "57 = SB (Simon the Sorcerer :: melodic only)", "58 = OP3 (The Fat Man 2op set)", "59 = OP3 (The Fat Man 4op set)", "60 = OP3 (JungleVision 2op set :: melodic only)", "61 = OP3 (Wallace 2op set, Nitemare 3D :: melodic only)", "62 = TMB (Duke Nukem 3D)", "63 = TMB (Shadow Warrior)", "64 = DMX (Raptor)" ] self.openicon = QIcon.fromTheme('document-open', QIcon('img/load.png')) self.saveicon = QIcon.fromTheme('document-save', QIcon('img/save.png')) self.playicon = QIcon.fromTheme('media-playback-start', QIcon('img/play.png')) self.pauseicon = QIcon.fromTheme('media-playback-pause', QIcon('img/pause.png')) self.stopicon = QIcon.fromTheme('media-playback-stop', QIcon('img/stop.png')) self.quiticon = QIcon.fromTheme('application-exit', QIcon('img/quit.png')) self.abouticon = QIcon.fromTheme('help-about', QIcon('img/about.png')) self.setticon = QIcon.fromTheme('preferences-desktop', QIcon('img/settings.png')) self.winsetup() def addWorker(self, worker): worker.message.connect(self.update) worker.finished.connect(self.workerFinished) self.threads.append(worker) def workerFinished(self): pass #barf('MSG', 'Thread completed the task!') def killWorkers(self): pass #for worker in self.threads: # worker.terminate() def winsetup(self): self.setWindowIcon(QIcon('img/note.png')) openFile = QAction(self.openicon, 'Open', self) openFile.setShortcut('Ctrl+O') openFile.triggered.connect(self.load) saveFile = QAction(self.saveicon, 'Save', self) saveFile.setShortcut('Ctrl+S') saveFile.triggered.connect(self.save) playFile = QAction(self.playicon, 'Play', self) playFile.setShortcut('Ctrl+P') playFile.triggered.connect(self.play) pausePlayb = QAction(self.pauseicon, 'Pause', self) pausePlayb.setShortcut('Ctrl+R') pausePlayb.triggered.connect(self.pause) stopPlay = QAction(self.stopicon, 'Stop', self) stopPlay.setShortcut('Ctrl+Z') stopPlay.triggered.connect(self.stop) exitAction = QAction(self.quiticon, 'Quit', self) exitAction.setShortcut('Ctrl+X') exitAction.triggered.connect(self.quit) aboutdlg = QAction(self.abouticon, 'About', self) aboutdlg.setShortcut('Ctrl+A') aboutdlg.triggered.connect(self.about) showSett = QAction(self.setticon, 'Settings', self) showSett.triggered.connect(self.settings) menubar = self.menuBar() fileMenu = menubar.addMenu('&File') configMenu = menubar.addMenu('&Options') configMenu.setStyleSheet("border: 1px solid black;") self.setLooped = QAction('Loop', configMenu, checkable=True) if self.progset.value("sound/Looped") == 'true': self.setLooped.setChecked(True) else: self.setLooped.setChecked(False) self.setLooped.setShortcut('Ctrl+L') self.setAutoplay = QAction('Autoplay', configMenu, checkable=True) if self.progset.value("sound/Autoplay") == 'true': self.setAutoplay.setChecked(True) else: self.setAutoplay.setChecked(False) self.setAutoplay.setShortcut('Ctrl+K') configMenu.addAction(self.setAutoplay) configMenu.addAction(self.setLooped) fileMenu.setStyleSheet("border: 1px solid black;") fileMenu.addAction(openFile) fileMenu.addAction(saveFile) fileMenu.addSeparator() self.recentMenu = fileMenu.addMenu('Recent') self.rfUpdate() fileMenu.addSeparator() fileMenu.addAction(showSett) fileMenu.addSeparator() fileMenu.addAction(exitAction) helpMenu = menubar.addMenu('&Help') helpMenu.setStyleSheet("border: 1px solid black;") helpMenu.addAction(aboutdlg) self.numCards = QSpinBox() numCards_text = QLabel(" OPL : ") self.numCards.setRange(1, 100) self.numCards.setValue(int(self.progset.value("sound/numCards", 3))) self.numCards.valueChanged.connect(self.updateMax4ops) self.fourOps = QSpinBox() fourOps_text = QLabel(" 4op Ch : ") self.fourOps.setRange(0, self.numCards.value()*6) self.fourOps.setValue(int(self.progset.value("sound/fourOps", self.numCards.value()*6))) self.twoOps = QSpinBox() twoOps_text = QLabel(" 2op Ch : ") self.twoOps.setValue((self.numCards.value()*12 - self.fourOps.value())) self.twoOps.setRange(self.twoOps.value(), self.twoOps.value()) toolbar = self.addToolBar('Media') toolbar.addAction(playFile) toolbar.addAction(pausePlayb) toolbar.addAction(stopPlay) toolbar.setMovable(False) toolbar.addSeparator() toolbar.addWidget(numCards_text) toolbar.addWidget(self.numCards) toolbar.addSeparator() toolbar.addWidget(fourOps_text) toolbar.addWidget(self.fourOps) #toolbar.addSeparator() #toolbar.addWidget(twoOps_text) #toolbar.addWidget(self.twoOps) self.statusBar() self.setFixedSize(380, 90) self.center() self.setWindowTitle('ADLMIDI pyGUI') self.show() if self.debug: barf("MSG", "Loaded Main Window", True, False) self.update("ready") self.threads = [] self.addWorker(AdlMidi(1)) self.addWorker(AdlMidiSave(2)) def rfUpdate(self): self.recentMenu.clear() def recentfile(f2l): return lambda: self.load2(f2l) self.recentFileActs = [] recentLength = len(self.recentList) for i in range(self.MaxRecentFiles): try: if i >= recentLength: break rev = (recentLength-1)-i filetoload = self.recentList[rev] filename = path.split(filetoload)[1] self.fileact = QAction(filename, self.recentMenu) self.fileact.triggered.connect(recentfile(filetoload)) self.recentFileActs.append(self.fileact) except Exception: pass for i in range(self.MaxRecentFiles): try: self.recentMenu.addAction(self.recentFileActs[i]) except Exception: pass def get_bank(self): try: selection = self.settings_window.combo.currentText() selection = str(selection[0])+str(selection[1]) return int(selection) except Exception: return 1 def center(self): qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) def about(self): if self.about_window is None: window = QMessageBox(self) self.about_window = window else: window = self.about_window window = self.about_window window.setWindowIcon(QIcon(self.abouticon)) window.setWindowTitle('About ADLMIDI pyGUI') credits = "<center><b>ADLMIDI pyGUI v%s (%s)</b><br>Developed by Tristy H. \"KittyTristy\"<br>[<a href=\"https://github.com/KittyTristy/ADLMIDI-pyGUI\">Website</a>] [<a href=\"mailto:[email protected]\">Email</a>] <br><br><br>" % (__version__, system()) title = "<b>ADLMIDI pyGUI</b> is a GUI wrapper<br>written in Python for use with..<br><br><b>ADLMIDI: MIDI Player<br>for Linux and Windows with OPL3 emulation</b><br>" cw = "(C) -- <a href=\"http://iki.fi/bisqwit/source/adlmidi.html\">http://iki.fi/bisqwit/source/adlmidi.html</a></center>" credits = credits + title + cw window.setText(credits) window.show() window.activateWindow() window.raise_() def settings(self): if self.settings_window is None: window = QDialog(self) self.settings_window = window else: window = self.settings_window window = self.settings_window window.setWindowTitle('Settings') window.notelabel = QLabel("Currently these settings are only guaranteed to work prior to loading the first MIDI!\nYou'll have to restart ADLMIDI pyGui to change them again if they stop working. \n\nSorry! This will be fixed soon!") window.notelabel.setWordWrap(True) window.notelabel.setStyleSheet("font-size: 8pt; border-style: dotted; border-width: 1px; padding: 12px;") window.banklabel = QLabel("<B>Choose Instrument Bank</B>") window.space = QLabel("") window.optlabel = QLabel("<B>Options</B>") window.combo = QComboBox() window.combo.addItems(self.banks) #window.combo.setMaximumWidth(350) window.combo.setMaxVisibleItems(12) window.combo.setStyleSheet("combobox-popup: 0;") window.combo.setCurrentIndex(int(self.progset.value("sound/bank", 1))) window.combo.currentIndexChanged.connect(self.saveSettings) window.perc = QCheckBox("Adlib Percussion Instrument Mode") #window.perc.stateChanged.connect(self.checkOpts) window.tremamp = QCheckBox("Tremolo Amplification Mode") #window.tremamp.stateChanged.connect(self.checkOpts) window.vibamp = QCheckBox("Vibrato Amplification Mode") #window.vibamp.stateChanged.connect(self.checkOpts) window.modscale = QCheckBox("Scaling of Modulator Volume") #window.modscale.stateChanged.connect(self.checkOpts) window.okButton = QPushButton('OK') window.okButton.clicked.connect(window.hide) vbox = QVBoxLayout() vbox.addWidget(window.space) vbox.addWidget(window.banklabel) vbox.addWidget(window.combo) vbox.addWidget(window.space) vbox.addWidget(window.optlabel) vbox.addWidget(window.perc) vbox.addWidget(window.tremamp) vbox.addWidget(window.vibamp) vbox.addWidget(window.modscale) vbox.addWidget(window.notelabel) hbox = QHBoxLayout() hbox.addStretch(1) hbox.addWidget(window.okButton) vbox.addLayout(hbox) window.setLayout(vbox) window.setFixedSize(530, 369) window.show() window.activateWindow() window.raise_() def updateMax4ops(self): self.fourOps.setMaximum(self.numCards.value()*6) self.fourOps.setValue(self.numCards.value()*6) barf("DBG", "Updating Maximum of 4ops Chs to %s" % (self.numCards.value()*6), True, False) #self.twoOps.setValue(self.numCards.value()*12 - self.fourOps.value()) #self.twoOps.setRange(self.twoOps.value(), self.twoOps.value()) def checkOpts(self): global arglist #barf("ACT", "Checking if Options have changed..", True, False) arglist = [] try: if QAbstractButton.isChecked(self.settings_window.perc) and not ('-p' in arglist): arglist.append('-p') elif not QAbstractButton.isChecked(self.settings_window.perc) and ('-p' in arglist): arglist.remove('-p') except Exception: pass try: if QAbstractButton.isChecked(self.settings_window.tremamp) and not ('-t' in arglist): arglist.append('-t') elif not QAbstractButton.isChecked(self.settings_window.tremamp) and ('-t' in arglist): arglist.remove('-t') except Exception: pass try: if QAbstractButton.isChecked(self.settings_window.vibamp) and not ('-v' in arglist): arglist.append('-v') elif not QAbstractButton.isChecked(self.settings_window.vibamp) and ('-v' in arglist): arglist.remove('-v') except Exception: pass try: if QAbstractButton.isChecked(self.settings_window.modscale) and not ('-s' in arglist): arglist.append('-s') elif not QAbstractButton.isChecked(self.settings_window.modscale) and ('-s' in arglist): arglist.remove('-s') except Exception: pass self.sel_bank = self.get_bank() def saveSettings(self): self.progset.setValue("sound/Autoplay", self.setAutoplay.isChecked()) self.progset.setValue("sound/Looped", self.setLooped.isChecked()) self.progset.setValue("sound/numCards", self.numCards.value()) self.progset.setValue("sound/fourOps", self.fourOps.value()) try: self.progset.setValue("sound/bank", self.settings_window.combo.currentIndex()) except Exception: pass if len(self.recentList) >= 1: self.progset.setValue("file/recent", self.recentList[-self.MaxRecentFiles:]) self.progset.setValue("file/MaxRecentFiles", self.MaxRecentFiles) #allkeys = self.progset.allKeys() #for key in allkeys: # barf('DBG', str(key) + " " + str(self.progset.value(key))) def closeEvent(self, event): self.stop() #self.pkill() self.saveSettings() barf("DBG", "Quitting", True, False) def quit(self): self.stop() #self.pkill() self.saveSettings() barf("DBG", "Quitting", True, False) exit(0) def pkill(self): try: p.kill() except Exception: pass ############################################################## ##### Statusbar Functions #################################### ############################################################## def clear(self): try: self.statusBar().removeWidget(self.playStatus) except Exception: pass @Slot(str) def update(self, status=''): self.clear() if status == "ready": text = " <B>Ready</b>" elif status == "play": text = " <B>Now Playing: </B>" + path.split(f.name)[1] elif status == "loop": text = " <B>Looping: </B>" + path.split(f.name)[1] elif status == "stop": text = " <B>Stopped: </B>" + path.split(f.name)[1] elif status == "pause": text = " <B>Paused: </B>" + path.split(f.name)[1] elif status == "loading": text = " <B>Loading.. </B>" elif status == "load": text = " <B>Loaded: </B>" + path.split(f.name)[1] elif status == "saving": text = " <B>Saving.. </B>" elif status == "saved": text = " <B>Saved as: </B>" + "saved/" + path.splitext(path.split(f.name)[1])[0] + ".wav" self.playStatus = QLabel(text) self.statusBar().addPermanentWidget(self.playStatus, 1) ############################################################## ####### Sound Functions ###################################### ############################################################## def play(self): global Paused, arglist if f != None and Paused == False: Paused = False self.stop() self.checkOpts() if not self.setLooped.isChecked(): arglist.append('-nl') arglist.append(str(self.progset.value("sound/bank", 1))) arglist.append(str(self.numCards.value())) arglist.append(str(self.fourOps.value())) for worker in self.threads: if worker.id == 1: worker.start() elif f != None and Paused == True: os.kill(p.pid, signal.SIGCONT) self.update("play") Paused = False def pause(self): global p, Paused if f != None: try: if Paused == False: os.kill(p.pid, signal.SIGSTOP) self.update("pause") Paused = True elif Paused == True: os.kill(p.pid, signal.SIGCONT) self.update("play") Paused = False except Exception: pass def stop(self): global Paused if f != None: Paused = False self.pkill() self.killWorkers() self.update("stop") ############################################################## ##### Load/Save Functions #################################### ############################################################## def load(self): global f lastdir = str(self.progset.value("file/lastdir", "")) fname, _ = QFileDialog.getOpenFileName(None, 'Open File', lastdir, "MIDI Audio File (*.mid *.MID)") if fname != "": f = file(fname, 'r') if not f.name in self.recentList: self.recentList.append(f.name) else: self.recentList.remove(f.name) self.recentList.append(f.name) self.progset.setValue("file/lastdir", path.split(f.name)[0]) self.rfUpdate() self.update("load") self.pkill() if self.debug: barf("SAV", "Loaded %s" % path.split(f.name)[1], True, False) if self.setAutoplay.isChecked(): self.play() else: self.update("load") def load2(self, r_file=None): global f f = file(r_file, 'r') self.recentList.remove(f.name) self.recentList.append(f.name) self.rfUpdate() self.update("load") self.pkill() if self.debug: barf("SAV", "Loaded %s" % path.split(f.name)[1], True, False) if self.setAutoplay.isChecked(): self.play() else: self.update("load") def save(self): if f != None: self.stop() for worker in self.threads: if worker.id == 2: worker.start()