Example #1
0
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)
Example #2
0
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)
Example #3
0
    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
Example #4
0
    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
Example #5
0
    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)
Example #7
0
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)
Example #9
0
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)   
Example #10
0
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)
Example #11
0
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&ndash;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&ndash;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()
Example #12
0
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()
Example #13
0
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&mdash;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())
Example #14
0
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&ndash;124, or somehow compressed, e.g., 120&ndash;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)
Example #15
0
# 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):")
Example #16
0
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()
Example #17
0
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 = "&nbsp;<B>Ready</b>"
		elif status == "play": text = "&nbsp;<B>Now Playing: </B>" + path.split(f.name)[1]
		elif status == "loop": text = "&nbsp;<B>Looping: </B>" + path.split(f.name)[1]
		elif status == "stop": text = "&nbsp;<B>Stopped: </B>" + path.split(f.name)[1]
		elif status == "pause": text = "&nbsp;<B>Paused: </B>" + path.split(f.name)[1]
		elif status == "loading": text = "&nbsp;<B>Loading.. </B>"
		elif status == "load": text = "&nbsp;<B>Loaded: </B>" + path.split(f.name)[1]
		elif status == "saving": text = "&nbsp;<B>Saving.. </B>"
		elif status == "saved": text = "&nbsp;<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()