Exemple #1
0
    def __changeDirectory(self, path):
        for c in self.filesview:
            c.setParent(None)
            c.deleteLater()
        self.filesview = []
        self.checkBox_2.setChecked(False)

        self.progressBars = {}
        for f in self.__getFiles(path):
            try:
                group = QGroupBox(f, self)
                group.setGeometry(QRect(20, 20, 100, 150))
                group.setCheckable(True)
                group.setChecked(False)
                group.setFixedSize(100, 150)
                group.setFlat(True)
                group.setToolTip(f)

                label = QLabel(group)
                label.setScaledContents(True)
                label.setGeometry(QRect(5, 25, 90, 90))
                label.setToolTip(f)

                progressBar = QProgressBar(group)
                progressBar.setGeometry(QRect(0, 70, 111, 10))
                progressBar.setProperty("value", 0)
                progressBar.setTextVisible(False)
                progressBar.setToolTip('0%')
                progressBar.setVisible(False)
                self.progressBars[f] = progressBar

                self.filesview.append(group)
                from os.path import isfile
                if isfile(path + '/' + f):
                    ext = f.split('.')[-1]
                    if isfile('icons/' + ext.lower() + '.png'):
                        label.setPixmap(
                            QPixmap('icons/' + ext.lower() + '.png'))
                    else:
                        label.setPixmap(QPixmap('icons/default.png'))
                else:
                    label.setPixmap(QPixmap('icons/folder.png'))
                self.connect(group, SIGNAL("clicked()"), self.__deselectFile)
            except ValueError:
                pass

        i = 0
        for x in list(range(len(self.filesview))):
            if (x % 4) == 0:
                i = i + 1
            self.rowsview[i].addWidget(self.filesview[x])
Exemple #2
0
    def initUI(self):
        self.setWindowTitle(APPNAME)

        file_menu = self.menuBar().addMenu('File')
        new_proj_action = create_action(self, 'New Project', self.new_project)
        open_proj_action = create_action(self, 'Open Project',
                                         self.open_project)
        import_orosMat_action = create_action(self, 'Import Oros Mat',
                                              self.import_orosMat)
        quit_action = create_action(self, 'Quit', self.quit)
        add_actions(file_menu, (new_proj_action, open_proj_action, None,
                                import_orosMat_action, None, quit_action))

        progress_bar = QProgressBar(self)
        progress_bar.setFixedWidth(200)
        progress_bar.setTextVisible(False)
        progress_bar.setVisible(False)
        self.progress_bar = progress_bar
        self.statusBar().addPermanentWidget(progress_bar)

        self.toolBar = self.addToolBar('Curves')

        main_widget = QWidget(self)
        main_layout = QGridLayout(main_widget)
        side_layout = QGridLayout()
        plot_widget = PlotWidget(main_widget)
        self.plot_widget = plot_widget

        list_widget = ListWidget()
        prop_widget = PropertyWidget()
        list_widget.registerPropertyWindow(prop_widget)
        side_layout.addWidget(list_widget, 0, 0)
        side_layout.addWidget(prop_widget, 1, 0)
        side_layout.setRowStretch(0, 2)
        side_layout.setRowStretch(1, 1)
        self.list_widget = list_widget

        main_layout.addLayout(side_layout, 0, 0)
        main_layout.addWidget(plot_widget, 0, 1)
        main_layout.setColumnStretch(0, 1)
        main_layout.setColumnStretch(1, 3)

        self.setCentralWidget(main_widget)
Exemple #3
0
class RenameGui(BaseWindow, QtGui.QMainWindow):
    renameCompleted = QtCore.pyqtSignal()

    def __init__(self, session, parent=None):
        super(RenameGui, self).__init__(parent)

        self.session = session

        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.ui.renameUser.clicked.connect(self.renameUser)

        self.progressIndicator = QProgressBar(self.ui.statusBar)
        self.progressIndicator.setMinimumHeight(5)
        self.progressIndicator.setVisible(False)
        self.progressIndicator.setMaximum(0)
        self.progressIndicator.setMinimum(0)
        self.ui.statusBar.addWidget(self.progressIndicator)

        self.renameCompleted.connect(self.renameCompletedSlot)

        self.uiTranslate()

    def uiTranslate(self):
        self.setWindowTitle(strings["renameWindowTitle"])
        self.ui.newUsername.setPlaceholderText(strings["newUsernameBoxHint"])
        self.ui.renameUser.setText(strings["renameUserButtonText"])

    def renameCompletedSlot(self):
        self.progressIndicator.setVisible(False)
        self.showMessageBox.emit(strings["renameSuccessText"])

    def renameUser(self):
        self.progressIndicator.setVisible(True)

        def renameThread():
            newUsername = self.ui.newUsername.text()
            if newUsername == "":
                self.showMessageBox.emit(strings["missingFieldsErrorText"])
                return
            try:
                oldUsername = self.session.username
                self.session.renameUser(newUsername)
                for message in sharedData.messages:
                    if message.sender == oldUsername:
                        message.sender = newUsername
                    elif message.receiver == oldUsername:
                        message.receiver = newUsername
                storeMessages(self.session.username, sharedData.messages)
                storeToken(self.session.username, self.session.token)
                storeKey(self.session.username, self.session.public, self.session.private)
                storeMessages(oldUsername, None)
                storeToken(oldUsername, None)
                storeKey(oldUsername, None, None)
                self.renameCompleted.emit()
            except SecureMessagingException as error:
                self.showMessageBox.emit(strings["errorText"] + responseTranslations[str(error)])
                return

        Thread(target=renameThread).start()
class ForgotPasswordUi(BaseWindow, QtGui.QMainWindow):
    requestSendingCompleted = QtCore.pyqtSignal()

    def __init__(self, parent=None):
        super(ForgotPasswordUi, self).__init__(parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.ui.forgot.clicked.connect(self.forgot)
        self.ui.forgot.setDefault(True)
        self.shortcut = QtGui.QShortcut(QtGui.QKeySequence("Return"), self)
        self.shortcut.activated.connect(self.forgot)
        self.shortcut2 = QtGui.QShortcut(QtGui.QKeySequence("Up"), self)
        self.shortcut2.activated.connect(self.focusUp)
        self.shortcut2 = QtGui.QShortcut(QtGui.QKeySequence("Down"), self)
        self.shortcut2.activated.connect(self.focusDown)

        self.progressIndicator = QProgressBar(self.ui.statusBar)
        self.progressIndicator.setMinimumHeight(5)
        self.progressIndicator.setVisible(False)
        self.progressIndicator.setMaximum(0)
        self.progressIndicator.setMinimum(0)
        self.ui.statusBar.addWidget(self.progressIndicator)

        self.requestSendingCompleted.connect(self.requestSendingCompleteSlot)

        self.uiTranslate()

    def uiTranslate(self):
        self.setWindowTitle(strings["forgotPasswordWindowTitle"])
        self.ui.username.setPlaceholderText(strings["usernameBoxHint"])
        self.ui.email.setPlaceholderText(strings["emailBoxHint"])
        self.ui.forgot.setText(strings["forgotPasswordButtonText"])

    def requestSendingCompleteSlot(self):
        self.progressIndicator.setVisible(False)
        self.showMessageBox.emit(strings["forgotSuccessText"])

    def focusUp(self):
        self.ui.username.setFocus()

    def focusDown(self):
        self.ui.email.setFocus()

    def forgot(self):
        self.progressIndicator.setVisible(True)

        def requestSenderThread():
            if self.ui.username.text() and self.ui.email.text():
                try:
                    requestRecovery(self.ui.username.text(), self.ui.email.text())
                    self.requestSendingCompleted.emit()
                except SecureMessagingException as error:
                    self.showMessageBox.emit(strings["errorText"] + responseTranslations[str(error)])
            else:
                self.showMessageBox.emit(strings["missingFieldsErrorText"])

        Thread(target=requestSenderThread).start()
Exemple #5
0
class AddUserGui(BaseWindow):
    addUserCompleted = QtCore.pyqtSignal()

    def __init__(self, parent=None):
        super(AddUserGui, self).__init__(parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.ui.adduser.clicked.connect(self.adduser)

        self.progressIndicator = QProgressBar(self.ui.statusBar)
        self.progressIndicator.setMinimumHeight(5)
        self.progressIndicator.setVisible(False)
        self.progressIndicator.setMaximum(0)
        self.progressIndicator.setMinimum(0)
        self.ui.statusBar.addWidget(self.progressIndicator)

        self.addUserCompleted.connect(self.addUserCompletedSlot)

        self.uiTranslate()

    def uiTranslate(self):
        self.setWindowTitle(strings["registerUserWindowTitle"])
        self.ui.username.setPlaceholderText(strings["usernameBoxHint"])
        self.ui.password.setPlaceholderText(strings["passwordBoxHint"])
        self.ui.email.setPlaceholderText(strings["emailBoxHint"])
        self.ui.confirm.setPlaceholderText(strings["confirmPasswordBoxHint"])
        self.ui.adduser.setText(strings["registerUserButtonText"])

    def addUserCompletedSlot(self):
        self.progressIndicator.setVisible(False)
        self.showMessageBox.emit(strings["registrationSuccessText"])

    def adduser(self):
        self.progressIndicator.setVisible(True)

        def addUserThread():
            name = self.ui.username.text()
            password = self.ui.password.text()
            confirm = self.ui.confirm.text()
            email = self.ui.email.text()
            if name == "" or password == "" or email == "":
                self.showMessageBox.emit(strings["missingFieldsErrorText"])
                return
            if password != confirm:
                self.showMessageBox.emit(strings["passwordsDontMatchErrorText"])
                return
            try:
                addUser(name, email, password)
                self.addUserCompleted.emit()
            except SecureMessagingException as error:
                self.showMessageBox.emit(strings["errorText"] + responseTranslations[str(error)])
                return

        Thread(target=addUserThread).start()
Exemple #6
0
class LDSControls(QFrame):
        
    STATIC_IMG = ('error_static.png','linz_static.png','busy_static.png','clean_static.png')
    ANIM_IMG   = ('error.gif','linz.gif','layer.gif','clean.gif')
    
    IMG_SPEED  = 100
    IMG_WIDTH  = 64
    IMG_HEIGHT = 64
    
    MAX_WD = 450
    
    GD_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../../bin/gdal/gdal-data'))
    STATUS = LU.enum('ERROR','IDLE','BUSY','CLEAN')
    
    def __init__(self,parent):
        super(LDSControls, self).__init__()
        self.parent = parent
        self.initConf()
        self.initEPSG()
        self.initUI()
        
    def initConf(self):
        '''Read files in conf dir ending in conf'''
        self.cflist = ConfigInitialiser.getConfFiles()
        #self.imgset = self.STATIC_IMG if ConfigWrapper().readDSProperty('Misc','indicator')=='static' else self.ANIM_IMG
        #self.imgset = self.STATIC_IMG if self.parent.confconn.tp.src.confwrap.readDSProperty('Misc','indicator')=='static' else self.ANIM_IMG
        sep = self.parent.confconn.reg.openEndPoint(self.parent.confconn.SRCNAME,self.parent.confconn.uconf)
        self.imgset = self.STATIC_IMG if sep.confwrap.readDSProperty('Misc','indicator')=='static' else self.ANIM_IMG
        self.parent.confconn.reg.closeEndPoint(self.parent.confconn.SRCNAME)
        
    def initEPSG(self):
        '''Read GDAL EPSG files, splitting by NZ(RSR) and RestOfTheWorld'''

        gcsf = gdal.FindFile('gdal','gcs.csv') 
        if not gcsf:
            gcsf = os.path.join(self.GD_PATH,'gcs.csv')
        pcsf = gdal.FindFile('gdal','pcs.csv') 
        if not pcsf: 
            pcsf = os.path.join(self.GD_PATH,'pcs.csv')
        gcs = ConfigInitialiser.readCSV(gcsf)
        pcs = ConfigInitialiser.readCSV(pcsf)

        self.nzlsr = [(e[0],e[0]+' - '+e[3]) for e in gcs if 'NZGD'     in e[1] or  'RSRGD'     in e[1]] \
                   + [(e[0],e[0]+' - '+e[1]) for e in pcs if 'NZGD'     in e[1] or  'RSRGD'     in e[1]]
        self.rowsr = [(e[0],e[0]+' - '+e[3]) for e in gcs if 'NZGD' not in e[1] and 'RSRGD' not in e[1]] \
                   + [(e[0],e[0]+' - '+e[1]) for e in pcs if 'NZGD' not in e[1] and 'RSRGD' not in e[1]]
                   
                   
    def initUI(self):
        
        # 0      1          2       3       4       5      6    7    8
        #'destname','lgselect','layer','uconf','group','epsg','fd','td','int'
        
        #self.rdest,rlgselect,self.rlayer,ruconf,self.rgroup,repsg,rfd,rtd,rint = readlist 
        
        QToolTip.setFont(QFont('SansSerif', 10))
        
        #labels
        destLabel = QLabel('Destination')
        lgLabel = QLabel('Group/Layer')
        epsgLabel = QLabel('EPSG')
        fromDateLabel = QLabel('From Date')
        toDateLabel = QLabel('To Date')
        confLabel = QLabel('User Config')
        
        self.view = QLabel() 
        self.view.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.view.setAlignment(Qt.AlignCenter)

        self.confcombo = QComboBox(self)
        self.confcombo.setToolTip('Enter your user config name (file) here')
        self.confcombo.addItems(self.cflist)
        self.confcombo.setEditable(False)
        #self.confcombo.currentIndexChanged.connect(self.doLGEditUpdate)
        
        #combos
        self.lgcombo = QComboBox(self)
        self.lgcombo.setMaximumWidth(self.MAX_WD)
        self.lgcombo.setDuplicatesEnabled(False)
        #self.lgcombo.setInsertPolicy(QComboBox.InsertAlphabetically)#?doesnt seem to work
        self.lgcombo.setToolTip('Select either Layer or Group entry')
        self.lgcombo.setEditable(False)
        self.sepindex = None
        #self.updateLGValues()
        
        self.epsgcombo = QComboBox(self)
        self.epsgcombo.setMaximumWidth(self.MAX_WD)
        self.epsgcombo.setToolTip('Setting an EPSG number here determines the output SR of the layer')  
        self.epsgcombo.addItems([i[1] for i in self.nzlsr])
        self.epsgcombo.insertSeparator(len(self.nzlsr))
        self.epsgcombo.addItems([i[1] for i in self.rowsr])
        self.epsgcombo.setEditable(True)
        self.epsgcombo.setEnabled(False)
        
        self.destlist = self.getConfiguredDestinations()
        self.destcombo = QComboBox(self)
        self.destcombo.setToolTip('Choose the desired output type')   
        self.destcombo.setEditable(False)
        self.destcombo.addItems(self.destlist)

        #date selection
        self.fromdateedit = QDateEdit()
        self.fromdateedit.setCalendarPopup(True)
        self.fromdateedit.setEnabled(False)
        
        self.todateedit = QDateEdit()
        self.todateedit.setCalendarPopup(True)
        self.todateedit.setEnabled(False)
        
        #check boxes
        self.epsgenable = QCheckBox()
        self.epsgenable.setCheckState(False)
        self.epsgenable.clicked.connect(self.doEPSGEnable)       
        
        self.fromdateenable = QCheckBox()
        self.fromdateenable.setCheckState(False)
        self.fromdateenable.clicked.connect(self.doFromDateEnable)
        
        self.todateenable = QCheckBox()
        self.todateenable.setCheckState(False) 
        self.todateenable.clicked.connect(self.doToDateEnable)
        
        self.progressbar = QProgressBar()
        self.progressbar.setRange(0,100)
        self.progressbar.setVisible(True)
        self.progressbar.setMinimumWidth(self.MAX_WD)
        
        
        #buttons        
        self.initbutton = QPushButton("waiting")
        self.initbutton.setToolTip('Initialise the Layer Configuration')
        self.initbutton.clicked.connect(self.doInitClickAction)
        
        self.cleanbutton = QPushButton("Clean")
        self.cleanbutton.setToolTip('Clean the selected layer/group from local storage')
        self.cleanbutton.clicked.connect(self.doCleanClickAction)
        
        self.replicatebutton = QPushButton("Replicate")
        self.replicatebutton.setToolTip('Execute selected replication')
        self.replicatebutton.clicked.connect(self.doReplicateClickAction)
        
        self.cancelbutton = QPushButton("Close")
        self.cancelbutton.setToolTip('Close the LDS Replicate application')       
        self.cancelbutton.clicked.connect(self.parent.close)


        #set dialog values using GPR
        self.updateGUIValues(self.parent.gvs)
        
        #set onchange here otherwise we get circular initialisation
        self.destcombo.currentIndexChanged.connect(self.doDestChanged)
        self.confcombo.currentIndexChanged.connect(self.doConfChanged)
        self.lgcombo.currentIndexChanged.connect(self.doLGComboChanged)

        self.setStatus(self.STATUS.IDLE)
        
        #grid
        grid = QGridLayout()
        grid.setSpacing(10)
        
        
        #placement section ------------------------------------
        #---------+---------+--------+---------+--------
        # dest LB |         | dest DD
        # grp LB  |         | grp DD
        # conf LB |         | conf DD
        # epsg L  | epsg CB | epsg DD
        # f dt L  | f dt CB | f dt DD
        # t td L  | t td CB | t td DD
        # icon    |       <- progress ->
        # layer B | <- . -> |repl B  | clean B | close B 
        #---------+---------+--------+---------+--------

        grid.addWidget(destLabel, 1, 0)
        grid.addWidget(self.destcombo, 1, 2)

        #grid.addWidget(layerLabel, 2, 0)
        grid.addWidget(lgLabel, 2, 0)
        grid.addWidget(self.lgcombo, 2, 2)
        
        grid.addWidget(confLabel, 3, 0)
        grid.addWidget(self.confcombo, 3, 2)
        
        #grid.addWidget(groupLabel, 4, 0)
        #grid.addWidget(self.groupEdit, 4, 2)
        
        grid.addWidget(epsgLabel, 5, 0)
        grid.addWidget(self.epsgenable, 5, 1)
        grid.addWidget(self.epsgcombo, 5, 2)

        grid.addWidget(fromDateLabel, 6, 0)
        grid.addWidget(self.fromdateenable, 6, 1)
        grid.addWidget(self.fromdateedit, 6, 2)
        
        grid.addWidget(toDateLabel, 7, 0)
        grid.addWidget(self.todateenable, 7, 1)
        grid.addWidget(self.todateedit, 7, 2)
        
        hbox3 = QHBoxLayout()
        hbox3.addWidget(self.view) 
        hbox3.addStretch(1)
        hbox3.addWidget(self.progressbar)

        #hbox3.addLayout(vbox2)
        #hbox3.addLayout(vbox3)
        
        hbox4 = QHBoxLayout()
        hbox4.addWidget(self.initbutton)
        hbox4.addStretch(1)
        hbox4.addWidget(self.replicatebutton)
        hbox4.addWidget(self.cleanbutton)
        hbox4.addWidget(self.cancelbutton)
        

        vbox = QVBoxLayout()
        #vbox.addStretch(1)
        vbox.addLayout(grid)
        vbox.addLayout(hbox3)
        vbox.addLayout(hbox4)
        
        self.setLayout(vbox)  
       
    #def setProgress(self,pct):
    #    self.progressbar.setValue(pct)
        
    def setStatus(self,status,message='',tooltip=None):
        '''Sets indicator icon and statusbar message'''
        self.parent.statusbar.showMessage(message)
        self.parent.statusbar.setToolTip(tooltip if tooltip else '')

        #progress
        loc = os.path.abspath(os.path.join(IMG_LOC,self.imgset[status]))
        #loc = os.path.abspath(os.path.join(os.path.dirname(__file__),self.parent.IMG_LOC,self.imgset[status]))
        self.progressbar.setVisible(status in (self.STATUS.BUSY, self.STATUS.CLEAN))
        
        #icon
        anim = QMovie(loc, QByteArray(), self)
        anim.setScaledSize(QSize(self.IMG_WIDTH,self.IMG_HEIGHT))
        anim.setCacheMode(QMovie.CacheAll)
        anim.setSpeed(self.IMG_SPEED)
        self.view.clear()
        self.view.setMovie(anim)
        anim.start()

        self.view.repaint()
        QApplication.processEvents(QEventLoop.AllEvents)

    def mainWindowEnable(self,enable=True):
        cons = (self.lgcombo, self.confcombo, self.destcombo, 
                self.initbutton, self.replicatebutton, self.cleanbutton, self.cancelbutton,
                self.epsgenable,self.fromdateenable,self.todateenable,
                self.parent.menubar)
        for c in cons:
            c.setEnabled(enable)
            
        if enable:
            self.epsgcombo.setEnabled(self.epsgenable.checkState())
            self.fromdateedit.setEnabled(self.fromdateenable.checkState())
            self.todateedit.setEnabled(self.todateenable.checkState())
        else:
            self.epsgcombo.setEnabled(False)
            self.fromdateedit.setEnabled(False)
            self.todateedit.setEnabled(False)
   
        QApplication.restoreOverrideCursor() if enable else QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) 

    def refreshLGCombo(self):
        '''Re index LG combobox since a refreshLG call (new dest?) will usually mean new groups'''
        self.lgcombo.clear()
        self.lgcombo.addItems([i[2] for i in self.parent.confconn.lglist])
        #NOTE the separator consumes an index, if not clearing the combobox selectively remove the old sepindex (assumes g preceeds l)
        #if self.sepindex:
        #    self.lgcombo.removeItem(self.sepindex)
        self.sepindex = [i[0] for i in self.parent.confconn.lglist].count(LORG.GROUP)
        self.lgcombo.insertSeparator(self.sepindex)
        
    def updateLGValues(self,uconf,lgval,dest):
        '''Sets the values displayed in the Layer/Group combo'''
        #because we cant seem to sort combobox entries and want groups at the top, clear and re-add
        #TRACE#        
        #pdb.set_trace()
        sf = None
        try:
            self.parent.confconn.initConnections(uconf,lgval,dest)
        except Exception as e:
            sf=1
            ldslog.error('Error Updating UC Values. '+str(e))
            
        if sf:
            self.setStatus(self.STATUS.ERROR,'Error Updating UC Values', str(e))
        else:
            self.setStatus(self.STATUS.IDLE)
            
        self.refreshLGCombo()
        
    def centre(self):
        
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())
        
    
    def gprParameters(self,rdest):
        '''Zip default and GPR values'''
        return [x if LU.assessNone(x) else y for x,y in zip(self.parent.gpr.readsec(rdest),self.parent.DEF_RVALS[1:])]
    
    def getLCE(self,ln):
        '''Read layer parameters'''
        dep = self.parent.confconn.reg.openEndPoint(self.parent.confconn.destname,self.parent.confconn.uconf)
        #sep = self.parent.confconn.reg.openEndPoint('WFS',self.parent.confconn.uconf)
        self.parent.confconn.reg.setupLayerConfig(self.parent.confconn.tp,None,dep,initlc=False)
        lce = dep.getLayerConf().readLayerParameters(ln)
        #self.parent.confconn.reg.closeEndPoint('WFS')
        self.parent.confconn.reg.closeEndPoint(self.parent.confconn.destname)
        sep,dep = None,None
        return lce
    
    
    def doDestChanged(self):
        '''Read the destname parameter and fill dialog with matching GPR values'''
        rdest = str(self.destlist[self.destcombo.currentIndex()])
        rvals = self.gprParameters(rdest)
        self.updateGUIValues([rdest]+rvals)    
        
        
    def doConfChanged(self):
        '''Read the user conf parameter and fill dialog with matching GPR values'''
        rdest = str(self.destlist[self.destcombo.currentIndex()])
        rlg,_,rep,rfd,rtd = self.gprParameters(rdest)
        ruc = str(self.cflist[self.confcombo.currentIndex()])
        self.updateGUIValues((rdest,rlg,ruc,rep,rfd,rtd))
        
        
    def doLGComboChanged(self):
        '''Read the layer/group value and change epsg to layer or gpr match'''
        #get a matching LG entry and test whether its a layer or group
        #lgi = self.parent.confconn.getLayerGroupIndex(self.lgcombo.currentText().toUtf8().data())
        lgi = self.parent.confconn.getLayerGroupIndex(LQ.readWidgetText(self.lgcombo.currentText()))
        #lgi can be none if we init a new group, in which case we use the GPR value
        if lgi:
            lge = self.parent.confconn.lglist[lgi]
            lce = self.getLCE(lge[1]) if lge[0]==LORG.LAYER else None
        else:
            lce = None
        
        #look for filled layer conf epsg OR use prefs stored in gpr
        if lce and LU.assessNone(lce.epsg):
            epsgval = lce.epsg
        else:
            rdest = str(self.destlist[self.destcombo.currentIndex()])
            _,_,epsgval,_,_ = self.gprParameters(rdest)
        epsgindex = [i[0] for i in self.nzlsr+[(0,0)]+self.rowsr].index(epsgval)
        if self.epsgcombo.currentIndex() != epsgindex:
            self.epsgcombo.setCurrentIndex(int(epsgindex))

        
    def updateGUIValues(self,readlist):
        '''Fill dialog values from provided list'''
        #TODO. Remove circular references when setCurrentIndex() triggers do###Changed()
        #Read user input
        rdest,self.rlgval,ruconf,repsg,rfd,rtd = readlist
        
        #--------------------------------------------------------------------
        
        #Destination Menu
        selecteddest = LU.standardiseDriverNames(rdest)
        if selecteddest not in self.destlist:
            self.destlist = self.getConfiguredDestinations()
            self.destcombo.addItem(selecteddest)
        destindex = self.destlist.index(selecteddest) if selecteddest else 0
        
        if self.destcombo.currentIndex() != destindex:
            self.destcombo.setCurrentIndex(destindex)
        
        #InitButton
        self.initbutton.setText('Layer Select')
        
        #Config File
        confindex = 0
        if LU.assessNone(ruconf):
            ruconf = ruconf.split('.')[0]
            if ruconf not in self.cflist:
                self.cflist += [ruconf,]
                self.confcombo.addItem(ruconf)
            confindex = self.cflist.index(ruconf)
            
        if self.confcombo.currentIndex() != confindex:
            self.confcombo.setCurrentIndex(confindex)
        #self.confEdit.setText(ruconf if LU.assessNone(ruconf) else '')
        
        #Layer/Group Selection
        self.updateLGValues(ruconf,self.rlgval,rdest)
        lgindex = None
        if LU.assessNone(self.rlgval):
            #index of list value
            lgindex = self.parent.confconn.getLayerGroupIndex(self.rlgval,col=1)
            
        if LU.assessNone(lgindex):
            #advance by 1 for sep
            lgindex += 1 if lgindex>self.sepindex else 0 
        else:
            #using the separator index sets the combo to blank
            lgindex = self.sepindex
        if self.lgcombo.currentIndex() != lgindex:
            self.lgcombo.setCurrentIndex(lgindex)
        #self.doLGEditUpdate()
        
        #EPSG
        #                                user > layerconf
        #useepsg = LU.precedence(repsg, lce.epsg if lce else None, None)
        epsgindex = [i[0] for i in self.nzlsr+[(None,None)]+self.rowsr].index(repsg)
        if self.epsgcombo.currentIndex() != epsgindex:
            self.epsgcombo.setCurrentIndex(epsgindex)
            
        #epsgedit = self.epsgcombo.lineEdit()
        #epsgedit.setText([e[1] for e in self.nzlsr+self.rowsr if e[0]==repsg][0])
        
        #epsgedit.setText([e for e in self.nzlsr+self.rowsr if re.match('^\s*(\d+).*',e).group(1)==repsg][0])
        
        #To/From Dates
        if LU.assessNone(rfd):
            self.fromdateedit.setDate(QDate(int(rfd[0:4]),int(rfd[5:7]),int(rfd[8:10])))
        else:
            early = DataStore.EARLIEST_INIT_DATE
            self.fromdateedit.setDate(QDate(int(early[0:4]),int(early[5:7]),int(early[8:10])))
            
        if LU.assessNone(rtd):
            self.todateedit.setDate(QDate(int(rtd[0:4]),int(rtd[5:7]),int(rtd[8:10]))) 
        else:
            today = DataStore.getCurrent()
            self.todateedit.setDate(QDate(int(today[0:4]),int(today[5:7]),int(today[8:10])))
            
        #Internal/External CheckBox
#        if LU.assessNone(rint):
#            self.internalTrigger.setChecked(rint.lower()==DataStore.CONF_INT)
#        else:
#            self.internalTrigger.setChecked(DataStore.DEFAULT_CONF==DataStore.CONF_INT)
        
        
    def getConfiguredDestinations(self):
        defml = ['',]+DataStore.DRIVER_NAMES.values()
        return [d for d in self.parent.gpr.getDestinations() if d in defml]
        
    def doEPSGEnable(self):
        self.epsgcombo.setEnabled(self.epsgenable.isChecked())
        
    def doFromDateEnable(self):
        self.fromdateedit.setEnabled(self.fromdateenable.isChecked())
          
    def doToDateEnable(self):
        self.todateedit.setEnabled(self.todateenable.isChecked())  
          
    def readParameters(self):
        '''Read values out of dialogs'''
        destination = LU.assessNone(str(self.destlist[self.destcombo.currentIndex()]))
        #lgindex = self.parent.confconn.getLayerGroupIndex(self.lgcombo.currentText().toUtf8().data())
        lgindex = self.parent.confconn.getLayerGroupIndex(LQ.readWidgetText(self.lgcombo.currentText()))
        #NB need to test for None explicitly since zero is a valid index
        lgval = self.parent.confconn.lglist[lgindex][1] if LU.assessNone(lgindex) else None       
        #uconf = LU.standardiseUserConfigName(str(self.confcombo.lineEdit().text()))
        #uconf = str(self.confcombo.lineEdit().text())
        uconf = str(self.cflist[self.confcombo.currentIndex()])
        ee = self.epsgenable.isChecked()
        epsg = None if ee is False else re.match('^\s*(\d+).*',str(self.epsgcombo.lineEdit().text())).group(1)
        fe = self.fromdateenable.isChecked()
        te = self.todateenable.isChecked()
        fd = None if fe is False else str(self.fromdateedit.date().toString('yyyy-MM-dd'))
        td = None if te is False else str(self.todateedit.date().toString('yyyy-MM-dd'))
        
        return destination,lgval,uconf,epsg,fe,te,fd,td
    
    def doInitClickAction(self):
        '''Initialise the LC on LC-button-click, action'''
        try:
            try:
                self.setStatus(self.STATUS.BUSY,'Opening Layer-Config Editor')  
                self.progressbar.setValue(0)
                self.parent.runLayerConfigAction()
            finally:
                self.setStatus(self.STATUS.IDLE,'Ready')
        except Exception as e:
            self.setStatus(self.STATUS.ERROR,'Error in Layer-Config',str(sys.exc_info()))#e))
        
    def doCleanClickAction(self):
        '''Set clean anim and run clean'''
        #lgo = self.lgcombo.currentText().toUtf8().data()
        lgo = LQ.readWidgetText(self.lgcombo.currentText())
        
        try:
            self.setStatus(self.STATUS.CLEAN,'Running Clean '+lgo)
            self.progressbar.setValue(0)
            self.runReplicationScript(True)
        except Exception as e:
            self.setStatus(self.STATUS.ERROR,'Failed Clean of '+lgo,str(sys.exc_info()))#e))
        
    def doReplicateClickAction(self):
        '''Set busy anim and run repl'''
        lgo = self.lgcombo.currentText()#.toUtf8().data()#only used for error messages
        try:
            self.setStatus(self.STATUS.BUSY,'Running Replicate '+lgo)
            self.progressbar.setValue(0)
            self.runReplicationScript(False)
            ldslog.debug('TRPfinish')
        except Exception as e:
            self.setStatus(self.STATUS.ERROR,'Failed Replication of '+lgo,str(sys.exc_info()))#e))

    def runReplicationScript(self,clean=False):
        '''Run the layer/group repliction script'''
        destination,lgval,uconf,epsg,fe,te,fd,td = self.readParameters()
        uconf_path = LU.standardiseUserConfigName(uconf)
        destination_path = LU.standardiseLayerConfigName(destination)
        destination_driver = LU.standardiseDriverNames(destination)

        if not os.path.exists(uconf_path):
            self.userConfMessage(uconf_path)
            return
        elif not MainFileReader(uconf_path).hasSection(destination_driver):
            self.userConfMessage(uconf_path,destination_driver)
            return
        #-----------------------------------------------------
        #'destname','layer','uconf','group','epsg','fd','td','int'
     
        self.parent.gpr.write((destination_driver,lgval,uconf,epsg,fd,td))        
        ldslog.info(u'dest={0}, lg={1}, conf={2}, epsg={3}'.format(destination_driver,lgval,uconf,epsg))
        ldslog.info('fd={0}, td={1}, fe={2}, te={3}'.format(fd,td,fe,te))
        lgindex = self.parent.confconn.getLayerGroupIndex(lgval,col=1)
        #lorg = self.parent.confconn.lglist[lgindex][0]
        #----------don't need lorg in TP anymore but it is useful for sorting/counting groups
        #self.parent.confconn.tp.setLayerOrGroup(lorg)
        self.parent.confconn.tp.setLayerGroupValue(lgval)
        if self.fromdateenable.isChecked(): self.parent.confconn.tp.setFromDate(fd)
        if self.todateenable.isChecked(): self.parent.confconn.tp.setToDate(td)
        self.parent.confconn.tp.setUserConf(uconf)
        if self.epsgenable: self.parent.confconn.tp.setEPSG(epsg)
        
        #because clean state persists in TP
        if clean:
            self.parent.confconn.tp.setCleanConfig()
        else:
            self.parent.confconn.tp.clearCleanConfig()
        #(re)initialise the data source since uconf may have changed
        #>>#self.parent.confconn.tp.src = self.parent.confconn.initSourceWrapper()
        #--------------------------
        ###ep = self.parent.confconn.reg.openEndPoint(self.parent.confconn.destname,self.parent.confconn.uconf)
        
        ###self.parent.confconn.reg.closeEndPoint(self.parent.confconn.destname)
        ###ep = None
        #Open ProcessRunner and run with TP(proc)/self(gui) instances
        #HACK temp add of dest_drv to PR call
        try:
            #TODO. Test for valid LC first
            self.tpr = ProcessRunner(self,destination_driver)
        except Exception as e:
            ldslog.error('Cannot create ProcessRunner {}. NB Possible missing Layer Config {}'.format(str(e),destination_path))
            self.layerConfMessage(destination_path)
            return
        #If PR has been successfully created we must vave a valid dst    
        ldslog.debug('TRPstart')
        self.tpr.start()
        
#     def quitProcessRunner(self):
#         self.tpr.join()
#         self.tpr.quit()
#         self.trp = None

        
    def userConfMessage(self,uconf,secname=None):
        ucans = QMessageBox.warning(self, 'User Config Missing/Incomplete', 
                                'Specified User-Config file, '+str(uconf)+' does not exist' if secname is None else 'User-Config file does not contain '+str(secname)+' section', 
                                'Back','Initialise User Config')
        if not ucans:
            #Retry
            ldslog.warn('Retry specifying UC')
            #self.confcombo.setCurrentIndex(0)
            return
        #Init
        ldslog.warn('Reset User Config Wizard')
        self.parent.runWizardAction()


    def layerConfMessage(self,dest):
        lcans = QMessageBox.warning(self, 'Layer Config Missing', 
                                'Required Layer-Config file, '+str(dest)+' does not exist', 
                                'Back','Run Layer Select')
        if not lcans:
            #Retry
            ldslog.warn('Retry specifying LC')
            #self.destcombo.setCurrentIndex(0)
            return
        #Init
        ldslog.warn('Reset Layer Config')
        self.doInitClickAction()
Exemple #7
0
class MainWinGui(QtGui.QMainWindow):
    progressIndeterminate = QtCore.pyqtSignal()
    progressSet = QtCore.pyqtSignal(int)
    progressStop = QtCore.pyqtSignal()

    def __init__(self, parent=None):
        super(MainWinGui, self).__init__(parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.ui.myName.setText(getStoredName() or "")

        self.ui.myName.textEdited.connect(self.nameChanged)

        self.communicator = Communicator(self)
        self.communicator.peersUpdated.connect(self.refreshPeers)
        self.communicator.fileReceived.connect(self.fileReceived)

        self.ui.refreshPeersButton.clicked.connect(self.discoverPeers)
        self.ui.peerList.itemClicked.connect(self.peerSelected)

        self.progressIndeterminate.connect(self.progressIndeterminateSlot)
        self.progressSet.connect(self.progressSetSlot)
        self.progressStop.connect(self.progressStopSlot)

        self.progressIndicator = QProgressBar(self.ui.statusbar)
        self.progressIndicator.setMinimumHeight(5)
        self.progressIndicator.setVisible(False)
        self.progressIndicator.setMaximum(0)
        self.progressIndicator.setMinimum(0)
        self.ui.statusbar.addWidget(self.progressIndicator)

    def nameChanged(self, newName):
        storeName(newName)
        self.communicator.updateName(newName)

    def progressStart(self):
        self.progressIndicator.setVisible(True)

    def progressSetSlot(self, value):
        self.progressStart()
        self.progressIndicator.setMaximum(100)
        self.progressIndicator.setValue(value)

    def progressIndeterminateSlot(self):
        self.progressStart()
        self.progressIndicator.setMaximum(0)

    def progressStopSlot(self):
        self.progressIndicator.setVisible(False)

    def show(self):
        super(MainWinGui, self).show()
        self.refreshPeers()
        self.discoverPeers()

    def discoverPeers(self):
        self.communicator.discoverPeers()

    def refreshPeers(self):
        self.ui.peerList.clear()
        for peer in self.communicator.peers:
            peer = self.communicator.peers[peer]
            peerName = QListWidgetItem(self.ui.peerList)
            peerName.peer = peer
            nameFont = QtGui.QFont()
            nameFont.setPointSize(14)
            peerDetails = QListWidgetItem(self.ui.peerList)
            peerDetails.peer = peer
            detailsFont = QtGui.QFont()
            detailsFont.setPointSize(10)
            name = peer.name
            details = ""
            if peer.publicKey is None:
                details += "Unpaired, "
            else:
                details += "Paired, "
            if peer.lastKnownIP is None:
                details += "unavailable"
            else:
                details += "available: " + peer.lastKnownIP
            peerName.setFont(nameFont)
            peerName.setText(name)
            peerDetails.setFont(detailsFont)
            peerDetails.setText(details)
            self.ui.peerList.addItem(peerName)
            self.ui.peerList.addItem(peerDetails)
            separatorItem = QListWidgetItem(self.ui.peerList)
            separatorItem.guid = peer.guid
            separatorItem.peer = None
            separatorItem.setFlags(QtCore.Qt.NoItemFlags)
            self.ui.peerList.addItem(separatorItem)

    def peerSelected(self, selectedItem):
        selectedItem.setSelected(False)
        if selectedItem.peer:
            PeerOptionsUi(self, selectedItem.peer, self.communicator).show()
        else:
            pass

    def sendFile(self, guid):
        fileName = QtGui.QFileDialog.getOpenFileName()
        if not fileName:
            return
        fileContents = open(fileName, "rb").read()
        basename = os.path.basename(fileName)
        self.communicator.sendFile(basename, fileContents, guid)

    def fileReceived(self, fileName, fileContents):
        fileName = QtGui.QFileDialog.getSaveFileName(directory=fileName)
        if not fileName:
            return
        with open(fileName, mode="wb") as file:
            file.write(fileContents)
Exemple #8
0
class ClientDialog(QDialog):
    """a simple popup dialog for asking the player what he wants to do"""
    def __init__(self, client, parent=None):
        QDialog.__init__(self, parent)
        self.setWindowTitle(m18n('Choose') + ' - Kajongg')
        self.setObjectName('ClientDialog')
        self.client = client
        self.layout = QGridLayout(self)
        self.progressBar = QProgressBar()
        self.timer = QTimer()
        if not client.game.autoPlay:
            self.timer.timeout.connect(self.timeout)
        self.deferred = None
        self.buttons = []
        self.setWindowFlags(Qt.SubWindow | Qt.WindowStaysOnTopHint)
        self.setModal(False)
        self.btnHeight = 0
        self.answered = False

    def keyPressEvent(self, event):
        """ESC selects default answer"""
        if not self.client.game or self.client.game.autoPlay:
            return
        if event.key() in [Qt.Key_Escape, Qt.Key_Space]:
            self.selectButton()
            event.accept()
        else:
            for btn in self.buttons:
                if str(event.text()).upper() == btn.message.shortcut:
                    self.selectButton(btn)
                    event.accept()
                    return
            QDialog.keyPressEvent(self, event)

    def __declareButton(self, message):
        """define a button"""
        maySay = self.client.sayable[message]
        if Preferences.showOnlyPossibleActions and not maySay:
            return
        btn = DlgButton(message, self)
        btn.setAutoDefault(True)
        btn.clicked.connect(self.selectedAnswer)
        self.buttons.append(btn)

    def focusTileChanged(self):
        """update icon and tooltip for the discard button"""
        if not self.client.game:
            return
        for button in self.buttons:
            button.decorate(self.client.game.myself.handBoard.focusTile)
        for tile in self.client.game.myself.handBoard.lowerHalfTiles():
            txt = []
            for button in self.buttons:
                _, _, tileTxt = button.message.toolTip(button, tile)
                if tileTxt:
                    txt.append(tileTxt)
            txt = '<br><br>'.join(txt)
            tile.graphics.setToolTip(txt)
        if self.client.game.activePlayer == self.client.game.myself:
            Internal.field.handSelectorChanged(self.client.game.myself.handBoard)

    def checkTiles(self):
        """does the logical state match the displayed tiles?"""
        for player in self.client.game.players:
            logExposed = list()
            physExposed = list()
            physConcealed = list()
            for tile in player.bonusTiles:
                logExposed.append(tile.element)
            for tile in player.handBoard.tiles:
                if tile.yoffset == 0 or tile.element[0] in 'fy':
                    physExposed.append(tile.element)
                else:
                    physConcealed.append(tile.element)
            for meld in player.exposedMelds:
                logExposed.extend(meld.pairs)
            logConcealed = sorted(player.concealedTileNames)
            logExposed.sort()
            physExposed.sort()
            physConcealed.sort()
            assert logExposed == physExposed, '%s != %s' % (logExposed, physExposed)
            assert logConcealed == physConcealed, '%s != %s' % (logConcealed, physConcealed)

    def messages(self):
        """a list of all messages returned by the declared buttons"""
        return list(x.message for x in self.buttons)

    def proposeAction(self):
        """either intelligently or first button by default. May also
        focus a proposed tile depending on the action."""
        result = self.buttons[0]
        game = self.client.game
        if game.autoPlay or Preferences.propose:
            answer, parameter = self.client.intelligence.selectAnswer(
                self.messages())
            result = [x for x in self.buttons if x.message == answer][0]
            result.setFocus()
            if answer in [Message.Discard, Message.OriginalCall]:
                for tile in game.myself.handBoard.tiles:
                    if tile.element == parameter:
                        game.myself.handBoard.focusTile = tile
        return result

    def askHuman(self, move, answers, deferred):
        """make buttons specified by answers visible. The first answer is default.
        The default button only appears with blue border when this dialog has
        focus but we always want it to be recognizable. Hence setBackgroundRole."""
        self.move = move
        self.deferred = deferred
        for answer in answers:
            self.__declareButton(answer)
        self.focusTileChanged()
        self.show()
        self.checkTiles()
        game = self.client.game
        myTurn = game.activePlayer == game.myself
        prefButton = self.proposeAction()
        if game.autoPlay:
            self.selectButton(prefButton)
            return
        prefButton.setFocus()

        self.progressBar.setVisible(not myTurn)
        if not myTurn:
            msecs = 50
            self.progressBar.setMinimum(0)
            self.progressBar.setMaximum(game.ruleset.claimTimeout * 1000 // msecs)
            self.progressBar.reset()
            self.timer.start(msecs)

    def placeInField(self):
        """place the dialog at bottom or to the right depending on space."""
        field = Internal.field
        cwi = field.centralWidget()
        view = field.centralView
        geometry = self.geometry()
        if not self.btnHeight:
            self.btnHeight = self.buttons[0].height()
        vertical = view.width() > view.height() * 1.2
        if vertical:
            height = (len(self.buttons) + 1) * self.btnHeight * 1.2
            width = (cwi.width() - cwi.height() ) // 2
            geometry.setX(cwi.width() - width)
            geometry.setY(min(cwi.height()//3, cwi.height() - height))
        else:
            handBoard = self.client.game.myself.handBoard
            if not handBoard:
                # we are in the progress of logging out
                return
            hbLeftTop = view.mapFromScene(handBoard.mapToScene(handBoard.rect().topLeft()))
            hbRightBottom = view.mapFromScene(handBoard.mapToScene(handBoard.rect().bottomRight()))
            width = hbRightBottom.x() - hbLeftTop.x()
            height = self.btnHeight
            geometry.setY(cwi.height() - height)
            geometry.setX(hbLeftTop.x())
        for idx, btn in enumerate(self.buttons + [self.progressBar]):
            self.layout.addWidget(btn, idx+1 if vertical else 0, idx+1 if not vertical else 0)
        idx = len(self.buttons) + 2
        spacer = QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.layout.addItem(spacer, idx if vertical else 0, idx if not vertical else 0)

        geometry.setWidth(width)
        geometry.setHeight(height)
        self.setGeometry(geometry)

    def showEvent(self, dummyEvent):
        """try to place the dialog such that it does not cover interesting information"""
        self.placeInField()

    def timeout(self):
        """the progressboard wants an update"""
        pBar = self.progressBar
        if isAlive(pBar):
            pBar.setValue(pBar.value()+1)
            pBar.setVisible(True)
            if pBar.value() == pBar.maximum():
                # timeout: we always return the original default answer, not the one with focus
                self.selectButton()
                pBar.setVisible(False)

    def selectButton(self, button=None):
        """select default answer. button may also be of type Message."""
        self.timer.stop()
        self.answered = True
        if button is None:
            button = self.focusWidget()
        if isinstance(button, Message):
            assert any(x.message == button for x in self.buttons)
            answer = button
        else:
            answer = button.message
        if not self.client.sayable[answer]:
            Sorry(m18n('You cannot say %1', answer.i18nName))
            return
        Internal.field.clientDialog = None
        self.deferred.callback(answer)

    def selectedAnswer(self, dummyChecked):
        """the user clicked one of the buttons"""
        game = self.client.game
        if game and not game.autoPlay:
            self.selectButton(self.sender())
Exemple #9
0
class LoginWinGui(BaseWindow, QtGui.QMainWindow):
    loginComplete = QtCore.pyqtSignal(Session)

    def __init__(self, parent=None):
        super(LoginWinGui, self).__init__(parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.ui.login.clicked.connect(self.login)
        self.ui.login.setDefault(True)
        self.ui.adduser.triggered.connect(self.adduser)
        self.ui.forgot.triggered.connect(self.forgot)
        QtGui.QShortcut(QtGui.QKeySequence("Return"), self).activated.connect(self.login)
        QtGui.QShortcut(QtGui.QKeySequence("Enter"), self).activated.connect(self.login)
        QtGui.QShortcut(QtGui.QKeySequence("Up"), self).activated.connect(self.focusUp)
        QtGui.QShortcut(QtGui.QKeySequence("Down"), self).activated.connect(self.focusDown)
        self.progressIndicator = QProgressBar(self.ui.statusBar)
        self.progressIndicator.setMinimumHeight(5)
        self.progressIndicator.setVisible(False)
        self.progressIndicator.setMaximum(0)
        self.progressIndicator.setMinimum(0)
        self.ui.statusBar.addWidget(self.progressIndicator)
        self.loginComplete.connect(self.loginCompleteSlot)

        self.uiTranslate()

    def uiTranslate(self):
        self.setWindowTitle(strings["loginWindowTitle"])
        self.ui.username.setPlaceholderText(strings["usernameBoxHint"])
        self.ui.password.setPlaceholderText(strings["passwordBoxHint"])
        self.ui.login.setText(strings["loginButtonText"])
        self.ui.adduser.setText(strings["registerUserWindowTitle"])
        self.ui.forgot.setText(strings["forgotPasswordWindowTitle"])
        self.ui.menuTools.setTitle(strings["toolsMenuText"])

    def loginCompleteSlot(self, session):
        self.progressIndicator.setVisible(False)
        self.mainWin = ConversationsWinGui(session)
        self.mainWin.windowClosed.connect(self.close)
        self.mainWin.loggedOut.connect(self.loggedOut)
        self.mainWin.show()
        self.hide()

    def loggedOut(self):
        self.show()
        self.mainWin.windowClosed.disconnect(self.close)
        self.mainWin.close()

    def onMainClose(self):
        pass

    def focusUp(self):
        self.ui.username.setFocus()

    def focusDown(self):
        self.ui.password.setFocus()

    def login(self):
        self.progressIndicator.setVisible(True)

        def loginThread():
            username = self.ui.username.text()
            password = self.ui.password.text()
            if username == "" or password == "":
                self.showMessageBox.emit(strings["missingFieldsErrorText"])
                return
            try:
                if storage.getToken(username) and storage.getKey(username):
                    token = storage.getToken(username)
                    public, private = storage.getKey(username)
                    newSession = Session(username, password, token, public, private)
                    storage.storeKey(newSession.username, newSession.public, newSession.private)
                else:
                    token, public, private = Session.requestNewToken(username, password)
                    newSession = Session(username, password, token, public, private)
                    storage.storeToken(newSession.username, token)
                    storage.storeKey(newSession.username, newSession.public, newSession.private)
                self.loginComplete.emit(newSession)
            except SecureMessagingException as error:
                if error.message == HTTPStrings.RESPONSE_UNAUTHORIZED:
                    storage.storeKey(username, None, None)
                    storage.storeToken(username, None)
                    loginThread()
                    return
                self.showMessageBox.emit(strings["errorText"] + responseTranslations[str(error)])

        Thread(target=loginThread).start()

    def adduser(self):
        addUserGui = AddUserGui(parent=self)
        addUserGui.show()

    def forgot(self):
        forgotUi = ForgotPasswordUi(parent=self)
        forgotUi.show()
Exemple #10
0
class UI_Psychrometry(QDialog):
    """Psychrometric charts tool"""

    def __init__(self, parent=None):
        super(UI_Psychrometry, self).__init__(parent)
        self.showMaximized()
        self.setWindowTitle("Psychrometric chart")

        layout = QGridLayout(self)
        self.diagrama2D = PsychroPlot(self, dpi=90)
        self.diagrama2D.fig.canvas.mpl_connect("motion_notify_event", self.scroll)
        layout.addWidget(self.diagrama2D, 1, 1, 1, 2)
        self.progressBar = QProgressBar()
        self.progressBar.setVisible(False)
        layout.addWidget(self.progressBar, 2, 1)
        self.status = QLabel()
        layout.addWidget(self.status, 2, 1)

        self.buttonBox = QDialogButtonBox(QDialogButtonBox.Close)
        butonPNG = QPushButton("Save as PNG")
        self.buttonBox.addButton(butonPNG, QDialogButtonBox.AcceptRole)
        self.buttonBox.rejected.connect(self.reject)
        self.buttonBox.accepted.connect(self.savePNG)
        layout.addWidget(self.buttonBox, 2, 2)

        self.plot()

    def savePNG(self):
        """Save chart image to png file"""
        fname = unicode(
            QFileDialog.getSaveFileName(self, "Save chart to file", "./", "Portable Network Graphics (*.png)")
        )
        self.diagrama2D.fig.savefig(fname, facecolor="#eeeeee")

    def drawlabel(self, name, Preferences, t, W, label, unit):
        """
        Draw annotation for isolines
            name: name of isoline
            Preferences: Configparse instance of pychemqt preferences
            t: x array of line
            W: y array of line
            label: text value to draw
            unit: text units to draw
        """
        if Preferences.getboolean("Psychr", name + "label"):
            tmin = Preferences.getfloat("Psychr", "isotdbStart") - 273.15
            tmax = Preferences.getfloat("Psychr", "isotdbEnd") - 273.15
            x = tmax - tmin
            wmin = Preferences.getfloat("Psychr", "isowStart")
            wmax = Preferences.getfloat("Psychr", "isowEnd")
            y = wmax - wmin

            i = 0
            for ti, wi in zip(t, W):
                if tmin <= ti <= tmax and wmin <= wi <= wmax:
                    i += 1
            label = str(label)
            if Preferences.getboolean("Psychr", name + "units"):
                label += unit
            pos = Preferences.getfloat("Psychr", name + "position")
            p = int(i * pos / 100 - 1)
            rot = np.arctan((W[p] - W[p - 1]) / y / (t[p] - t[p - 1]) * x) * 360.0 / 2.0 / np.pi
            self.diagrama2D.axes2D.annotate(label, (t[p], W[p]), rotation=rot, size="small", ha="center", va="center")

    def plot(self):
        """Plot chart"""
        Preferences = ConfigParser()
        Preferences.read("psyrc")

        self.diagrama2D.axes2D.clear()
        self.diagrama2D.config()
        filename = "%i.pkl" % P
        if os.path.isfile(filename):
            with open(filename, "r") as archivo:
                data = cPickle.load(archivo)
                self.status.setText("Loading cached data...")
                QApplication.processEvents()
        else:
            self.progressBar.setVisible(True)
            self.status.setText("Calculating data, be patient...")
            QApplication.processEvents()
            data = PsyCoolprop.calculatePlot(self)
            cPickle.dump(data, open(filename, "w"))
            self.progressBar.setVisible(False)
        self.status.setText("Plotting...")
        QApplication.processEvents()

        tmax = Preferences.getfloat("Psychr", "isotdbEnd") - 273.15

        t = [ti - 273.15 for ti in data["t"]]
        Hs = data["Hs"]
        format = {}
        format["ls"] = Preferences.get("Psychr", "saturationlineStyle")
        format["lw"] = Preferences.getfloat("Psychr", "saturationlineWidth")
        format["color"] = Preferences.get("Psychr", "saturationColor")
        format["marker"] = Preferences.get("Psychr", "saturationmarker")
        format["markersize"] = 3
        self.diagrama2D.plot(t, Hs, **format)

        format = {}
        format["ls"] = Preferences.get("Psychr", "isotdblineStyle")
        format["lw"] = Preferences.getfloat("Psychr", "isotdblineWidth")
        format["color"] = Preferences.get("Psychr", "isotdbColor")
        format["marker"] = Preferences.get("Psychr", "isotdbmarker")
        format["markersize"] = 3
        for i, T in enumerate(t):
            self.diagrama2D.plot([T, T], [0, Hs[i]], **format)

        H = data["H"]
        th = data["th"]
        format = {}
        format["ls"] = Preferences.get("Psychr", "isowlineStyle")
        format["lw"] = Preferences.getfloat("Psychr", "isowlineWidth")
        format["color"] = Preferences.get("Psychr", "isowColor")
        format["marker"] = Preferences.get("Psychr", "isowmarker")
        format["markersize"] = 3
        for i, H in enumerate(H):
            self.diagrama2D.plot([th[i], tmax], [H, H], **format)

        format = {}
        format["ls"] = Preferences.get("Psychr", "isohrlineStyle")
        format["lw"] = Preferences.getfloat("Psychr", "isohrlineWidth")
        format["color"] = Preferences.get("Psychr", "isohrColor")
        format["marker"] = Preferences.get("Psychr", "isohrmarker")
        format["markersize"] = 3
        for Hr, H0 in data["Hr"].iteritems():
            self.diagrama2D.plot(t, H0, **format)
            self.drawlabel("isohr", Preferences, t, H0, Hr, "%")

        format = {}
        format["ls"] = Preferences.get("Psychr", "isotwblineStyle")
        format["lw"] = Preferences.getfloat("Psychr", "isotwblineWidth")
        format["color"] = Preferences.get("Psychr", "isotwbColor")
        format["marker"] = Preferences.get("Psychr", "isotwbmarker")
        format["markersize"] = 3
        for T, (H, Tw) in data["Twb"].iteritems():
            self.diagrama2D.plot(Tw, H, **format)
            value = T - 273.15
            txt = u"ºC"
            self.drawlabel("isotwb", Preferences, Tw, H, value, txt)

        format = {}
        format["ls"] = Preferences.get("Psychr", "isochorlineStyle")
        format["lw"] = Preferences.getfloat("Psychr", "isochorlineWidth")
        format["color"] = Preferences.get("Psychr", "isochorColor")
        format["marker"] = Preferences.get("Psychr", "isochormarker")
        format["markersize"] = 3
        for v, (Td, H) in data["v"].iteritems():
            self.diagrama2D.plot(Td, H, **format)
            value = v
            txt = u"m³/kg"
            self.drawlabel("isochor", Preferences, Td, H, value, txt)

        self.diagrama2D.draw()
        self.status.setText("P = %i Pa" % P)

    def scroll(self, event):
        """Update graph annotate when mouse scroll over chart"""
        if event.xdata and event.ydata:
            punto = self.createState(event.xdata, event.ydata)
            if event.ydata < punto.ws:
                self.diagrama2D.showPointData(punto)
            else:
                self.diagrama2D.clearPointData()

    def createState(self, x, y):
        """Create psychrometric state from click or mouse position"""
        tdb = x + 273.15
        punto = PsyCoolprop(P=P, tdb=tdb, w=y)
        return punto
Exemple #11
0
class SegmentationClassificationWindow(SoundLabWindow, Ui_MainWindow):
    """

    Window that process the segmentation and classification of a signal
    Contains a QSignalDetectorWidget that wrapper several functionality
    Allows to select the segmentation and classification settings,
    and parameter measurement for detected segments.
    Provides a table for visualization of segment and measures,
    A two dimensional window to graph two measured params. One for each axis.
    Options for selection and visualization of segments
    Provides options for save the parameters to excel.
    """

    # region CONSTANTS

    # sort type of the parameter table
    PARAMETER_SORT_NONE, PARAMETER_SORT_BY_LOCATION, PARAMETER_SORT_BY_PARAMETER = range(
        3)

    # different colors for the even and odds rows in the parameter table and segment colors.
    TABLE_ROW_COLOR_ODD = QColor(0, 0, 255, 150)
    TABLE_ROW_COLOR_EVEN = QColor(0, 255, 0, 150)

    # stylesheet to use on excel file saved
    EXCEL_STYLE_HEADER = xlwt.easyxf(
        'font: name Times New Roman, color-index black, bold on, height 300')
    EXCEL_STYLE_BODY = xlwt.easyxf(
        'font: name Times New Roman, color-index black, height 220',
        num_format_str='#,# # 0.00')
    EXCEL_STYLE_COPYRIGHT = xlwt.easyxf(
        'font: name Arial, color-index pale_blue, height 250, italic on',
        num_format_str='# ,# # 0.00')

    # endregion

    # region Initialize

    def __init__(self, parent=None, signal=None, workspace=None):
        """
        Create a the window of segmentation and classification.
        :param parent:    the parent widget if any
        :param signal:    the signal to visualize for segmentation and classification
        :param workspace: the workspace with specgram and oscilogram generation options
        :return:
        """

        # set the visual variables and methods from ancestor's
        SoundLabWindow.__init__(self, parent)
        self.setupUi(self)

        # check the parameters
        if signal is None or not isinstance(signal, AudioSignal):
            raise Exception(
                "The signal to analyze must be of type AudioSignal")

        self.configureToolBarActionsGroups()

        # the segmentation window do not allow to record a signal (for now...)
        self.actionRecord.setEnabled(False)

        # the object that handles the measuring of parameters and manage the segments
        self.segmentManager = SegmentManager()
        self.segmentManager.measurementsFinished.connect(
            self.measurement_finished)
        self.segmentManager.detectionProgressChanged.connect(
            lambda x: self.windowProgressDetection.setValue(x * 0.9))
        self.segmentManager.segmentVisualItemAdded.connect(
            self.widget.add_parameter_visual_items)
        self.segmentManager.segmentationFinished.connect(
            self.segmentation_finished)

        # the factory of adapters for parameters to supply to the ui window or segmentation dialog
        self.parameter_manager = MeasurementTemplate(signal=signal)

        # set the signal to the widget
        self.widget.signal = signal
        self.segmentManager.signal = signal

        # set the configurations for the name of the signal and the visible label
        self.updateSignalPropertiesLabel(signal)
        self.signalNameLineEdit.setReadOnly(True)
        self.actionSignalName.setText(self.widget.signalName)

        # set visible the two graphs by default
        self.changeWidgetsVisibility(True, True)

        # shift of the table parameters rows. If the table visualization isn't expanded
        # the first row are the name of the parameters and the second one the locations
        self.parameter_table_row_shift = 2

        # connect the signals on the widget for new detected data by its tools
        # and to select the element in the table. Binding the element click to the table
        self.widget.toolDataDetected.connect(self.update_status_bar)
        self.widget.elementClicked.connect(self.select_element)

        self.tableParameterOscilogram.setSelectionBehavior(
            QAbstractItemView.SelectRows)
        self.tableParameterOscilogram.setEditTriggers(
            QAbstractItemView.NoEditTriggers)
        self.dockWidgetParameterTableOscilogram.setVisible(False)
        self.tableParameterOscilogram.setSortingEnabled(False)

        # connect the table parameter sort type actions
        self.actionGroupNone.triggered.connect(
            self.groupTableParametersChanged)
        self.actionGroupByParameter.triggered.connect(
            self.groupTableParametersChanged)
        self.actionGroupByLocation.triggered.connect(
            self.groupTableParametersChanged)

        # configuration variable for the parameter table visualization sort
        self.parameter_table_sort_type = self.PARAMETER_SORT_BY_PARAMETER

        # add the context menu actions to the widget
        self.__addContextMenuActions()

        # create the progress bar that is showed while the detection is made
        self.windowProgressDetection = QProgressBar(self)
        self.set_progress_bar_visibility(False)

        # array of windows with two dimensional graphs
        self.two_dim_windows = []
        self._cross_correlation_windows = []

        if workspace is not None:
            self.load_workspace(workspace)

        if parent is not None:
            # show window in the center of the parent
            parent_x, parent_y = parent.x(), parent.y()
            parent_width, parent_height = parent.width(), parent.height()
            a = str('a')
            window_x = parent_x + (parent_width - self.width()) / 2
            window_y = parent_y + (parent_height - self.height()) / 2
            self.move(window_x, window_y)

        self.show()

        self.try_restore_previous_session()

    def try_restore_previous_session(self):
        """
        Restore (if any) the previous session with this file.
        That means detected elements, measured parameters etc that are saved on the signal
        extra data.
        :return:
        """
        elements = self.widget.get_signal_segmentation_data()

        if len(elements) == 0:
            return

        buttons_box = QMessageBox.Yes | QMessageBox.No
        mbox = QMessageBox(
            QMessageBox.Question, self.tr(u"soundLab"),
            self.
            tr(u"The file has segmentation data stored. Do you want to load it?"
               ), buttons_box, self)
        result = mbox.exec_()

        if result == QMessageBox.Yes:
            for i, e in enumerate(elements):
                self.segmentManager.add_element(i, e[0], e[1])

            self.widget.elements = self.segmentManager.elements
            self.segmentManager.measure_parameters_and_classify()
            self.widget.graph()

    def __addContextMenuActions(self):
        """
        Add the context menu actions into the widget in the creation process of the window
        :return:
        """
        separator, separator1, separator2, separator3, separator4 = [
            QAction(self) for _ in xrange(5)
        ]

        for sep in [separator, separator1, separator2, separator3, separator4]:
            sep.setSeparator(True)

        # region Context Menu Actions

        self.widget.createContextCursor([
            # parameters manipulation actions
            self.actionMeditions,
            self.actionView_Parameters,
            self.actionAddElement,
            separator2,

            # Zoom Actions
            self.actionZoomIn,
            self.actionZoom_out,
            self.actionZoom_out_entire_file,
            separator1,

            # widgets visibility actions
            self.actionCombined,
            self.actionOscilogram,
            self.actionSpectogram,
            separator,

            # change tools actions
            self.actionZoom_Cursor,
            self.actionPointer_Cursor,
            self.actionRectangular_Cursor,
            separator3,

            # elements select/deselect
            self.actionDeselect_Elements,
            self.actionDelete_Selected_Elements,
            self.actionSelectedElement_Correlation,
            self.actionClassify,
            separator4
        ])
        # endregion
        # add the action to switch visualization mode on  the parameter table
        self.tableParameterOscilogram.setContextMenuPolicy(
            QtCore.Qt.ActionsContextMenu)

        parameter_tables_action_group = QActionGroup(
            self.tableParameterOscilogram)
        actions = [
            self.actionGroupNone, self.actionGroupByLocation,
            self.actionGroupByParameter
        ]

        for act in actions:
            parameter_tables_action_group.addAction(act)
            self.tableParameterOscilogram.addAction(act)

    def configureToolBarActionsGroups(self):
        """
        :return:
        """
        sep = QAction(self)
        sep.setSeparator(True)

        # region Segmentation and Transformations actions
        segm_transf_actions = QActionGroup(self)
        segm_transf_actions_list = [
            self.actionDetection, self.actionTwo_Dimensional_Graphs,
            self.actionDelete_Selected_Elements, self.actionDeselect_Elements,
            self.actionAddElement, self.actionParameter_Measurement, sep
        ]

        for act in segm_transf_actions_list:
            act.setActionGroup(segm_transf_actions)

        # endregion

        # add to the customizable sound lab toolbar first than the default actions
        # addActionGroup(actionGroup, name)
        self.toolBar.addActionGroup(segm_transf_actions,
                                    u"Segments and Parameters")

        # apply the common sound lab window toolbar actions
        SoundLabWindow.configureToolBarActionsGroups(self)

    # endregion

    # region Two Dimensional Graphs

    @pyqtSlot()
    def on_actionTwo_Dimensional_Graphs_triggered(self):
        """
        Creates a new two dimensional window for analysis.
        :return:
        """
        # a two dim window must be created after
        # segment detection and parameters measurement
        if self.segmentManager.rowCount == 0 or len(
                self.segmentManager.parameterColumnNames) == 0:
            QMessageBox.warning(
                QMessageBox(), self.tr(u"Error"),
                self.tr(
                    u"The two dimensional analyses window requires at least "
                    u"one detected element with one parameter measurement."))
            return

        wnd = TwoDimensionalAnalisysWindow(self, self.segmentManager)

        # connect the signals for update the new two dim window actions
        wnd.elementSelected.connect(self.select_element)
        wnd.elementsClassified.connect(
            lambda indexes_list, classification: self.segmentManager.
            set_manual_elements_classification(indexes_list, classification))

        # load the workspace in the new two dimensional window
        if self.workSpace:
            wnd.load_workspace(self.workSpace)

        # if any previous windows was opened then update in the new one the selected element
        if len(self.two_dim_windows) > 0:
            wnd.select_element(self.two_dim_windows[0].selectedElementIndex)

        # add the new window to the current opened windows
        self.two_dim_windows.append(wnd)

    def clear_two_dim_windows(self):
        """
        Close the two dimensional windows and clear the list of two dim windows
        :return:
        """
        # close the opened windows
        for window in self.two_dim_windows:
            window.close()
            del window

        # clear the list of two dimensional windows
        self.two_dim_windows = []

    # endregion

    # region Save Measurements

    @pyqtSlot()
    def on_actionMeditions_triggered(self):
        """
        Save to disc the measurement made by the window to the elements detected.
        :param name: The name of the file to save the data
        :param table: The table with the parameter to save into excel
        :return: True if successfully False otherwise
        """
        file_name = unicode(
            QFileDialog.getSaveFileName(
                self, self.tr(u"Save parameters as excel file"),
                os.path.join(self.workSpace.lastOpenedFolder,
                             str(self.widget.signalName) + ".xls"), "*.xls"))
        # save the data of table
        if not file_name:
            return False

        # if successfully selected the path save the excel book of data
        try:

            wb = xlwt.Workbook()
            ws = wb.add_sheet("Elements Measurements")
            self.write_data(ws, self.tableParameterOscilogram)
            wb.save(file_name)

            self.segmentManager.save_data_on_db()

        except Exception as ex:
            print("Error saving the excel file. " + ex.message)
            return False

        # open user manual file
        os.system("start " + file_name)
        return True

    @pyqtSlot()
    def on_actionSound_File_Segmentation_triggered(self):
        """
        Save the signal into file. Store the segmentation values
        (list of tuples start,end with the indexes of detected element)
        :return:
        """
        if self.segmentManager.rowCount == 0:
            return

        self.widget.save_segments_into_signal()

        # save the signal to file
        if self.widget.signalFilePath:
            self.widget.save()
        else:
            file_name = unicode(
                QFileDialog.getSaveFileName(
                    self, self.tr(u"Save signal"),
                    os.path.join(self.workSpace.lastOpenedFolder,
                                 str(self.widget.signalName)), u"*.wav"))
            if file_name:
                self.widget.save(file_name)
                self.widget.signalFilePath = file_name

    def set_signal_file(self, file_path=''):
        """
        Update the data of the current signal file path origin in the widget
        (if any)
        :param file_path:
        :return:
        """
        self.widget.signalFilePath = file_path

    def write_data(self, ws, table_parameter):
        """
        Write the data from the table into an excel file stylesheet.
        :param ws:WorkSheet object from xwlt module for interacts with excell files.
        :param table_parameter: QTableWidget with the information of the data to save.
        """
        # write headers into the document
        headers = []
        for pos in xrange(table_parameter.columnCount()):
            header_item = table_parameter.takeHorizontalHeaderItem(pos)
            if header_item is not None:
                headers.append(str(header_item.text()))

        for index, header in enumerate(headers):
            ws.write(0, index, header, self.EXCEL_STYLE_HEADER)

        # write data into the document
        for i in xrange(1, table_parameter.model().rowCount() + 1):
            for j in xrange(table_parameter.model().columnCount()):
                item = table_parameter.item(i - 1, j)
                if item is not None:
                    cell_data = str(item.data(Qt.DisplayRole).toString())

                    ws.write(i, j, cell_data, self.EXCEL_STYLE_BODY)

        # ws object must be part of a Work book that would be saved later
        ws.write(table_parameter.model().rowCount() + 3, 0,
                 unicode(self.tr(u"duetto-Sound Lab")),
                 self.EXCEL_STYLE_COPYRIGHT)

    # endregion

    # region Close and Exit

    @pyqtSlot()
    def on_actionExit_triggered(self):
        """
        Process the exit action requested by the user.
        :return:
        """
        self.close()

    def closeEvent(self, event):
        """
        Event that manages the close of the window.
        Intercepts the close event for save changes.
        :param event:
        :return:
        """

        mbox = QMessageBox(
            QMessageBox.Question, self.tr(u"Save measurements"),
            self.tr(u"Do you want to save the parameters of " +
                    unicode(self.widget.signalName)),
            QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel, self)

        # if the signal was playing must be stopped
        self.widget.stop()
        self.segmentManager.stop_processing()

        # if there is a measurement made and parameters measured that could be saved
        if self.tableParameterOscilogram.rowCount() > 0:

            result = mbox.exec_()

            # check if the user decision about save is discard and continue working
            if result == QMessageBox.Cancel or (
                    result == QMessageBox.Yes
                    and not self.on_actionMeditions_triggered()):
                event.ignore()
                return

            self.clear_two_dim_windows()

    # endregion

    # region Elements Selection

    @pyqtSlot()
    def on_actionDelete_Selected_Elements_triggered(self):
        """
        Delete the element under selection.
        the selection is the area under the zoom cursor if the zoom cursor is selected
        or the visible area otherwise.
        :return:
        """

        # delete the elements on the widget and get the indexes for update
        deleted_elements = self.widget.selected_elements_interval()

        self.widget.delete_selected_elements()

        if deleted_elements is None:
            return

        start_removed_index, end_removed_index = deleted_elements

        if start_removed_index is not None and start_removed_index >= 0 \
           and end_removed_index < self.segmentManager.rowCount:

            # updates the detected elements
            self.segmentManager.delete_elements(start_removed_index,
                                                end_removed_index)

            for wnd in self.two_dim_windows:
                wnd.update_data(self.segmentManager)

        # deselect the elements on the widget
        self.on_actionDeselect_Elements_triggered()

    @pyqtSlot()
    def on_actionDelete_All_triggered(self):
        """
        Removes all the detected elements on the widget
        :return:
        """
        # clear the segments
        self.segmentManager.elements = []

        # removes the widget elements
        self.widget.elements = []
        self.widget.graph()

    @pyqtSlot()
    def on_actionAddElement_triggered(self):
        """
        Try to add the selected region on the widget as a new element
        Performs the manual segmentation.
        :return:
        """
        element_added_index = self.widget.mark_region_as_element()

        if element_added_index is None:
            return

        element = self.widget.get_element(element_added_index)

        self.segmentManager.add_element(element_added_index, element.indexFrom,
                                        element.indexTo)

        self.update_two_dim_windows()

        self.widget.graph()

        self.__set_parameter_window_visible()

    @pyqtSlot()
    def on_actionDeselect_Elements_triggered(self):
        """
        Deselects the selected element in the widget and in the
        two dimensional windows opened.
        :return:
        """
        self.widget.deselect_element()

        for wnd in self.two_dim_windows:
            wnd.deselect_element()

        # the table remains equal as before for efficiency (do not update for deselect)

    def select_element(self, element_index, column=0):
        """
        Callback that is executed for update the element that is selected.
        An element is selected by the user ad must be updated in all visible representations
        like table parameter, two dimensional windows, and graphs.
        :param element_index: index of the element selected
        :param column: parameter provided to reuse this method as callback of
        the event selected cell in the QTableWidget. Useless in this application context.
        """
        # select the element in the table of parameters
        self.tableParameterOscilogram.selectRow(element_index +
                                                self.parameter_table_row_shift)

        # in the widget...
        self.widget.select_element(element_index)

        # in the opened two dimensional windows...
        for wnd in self.two_dim_windows:
            wnd.select_element(element_index)

        # and in the cross-correlation windows
        for i in xrange(len(self._cross_correlation_windows)):
            wnd = self._cross_correlation_windows[i]
            if wnd.isHidden():
                del self._cross_correlation_windows[i]
            else:
                wnd.select_element(element_index)

        # show the image if the element is classified
        try:
            classification = self.segmentManager.get_segment_classification(
                element_index)
            image = classification.get_image()
            if image:
                self.show_image_on_element(element_index, image)

            self.update_status_bar(classification.get_full_description())

        except Exception as ex:
            pass

    @pyqtSlot()
    def on_actionSelectedElement_Correlation_triggered(self):
        signal = self.widget.selected_element_signal()
        if not signal:
            QMessageBox.warning(QMessageBox(), self.tr(u"Error"),
                                self.tr(u"There is no selected element."))
            return

        dialog = CrossCorrelationDialog(self, self.widget, signal,
                                        self.TABLE_ROW_COLOR_ODD,
                                        self.TABLE_ROW_COLOR_EVEN)

        self._cross_correlation_windows.append(dialog)
        dialog.elementSelected.connect(self.select_element)
        dialog.show()

    @pyqtSlot()
    def on_actionClassify_triggered(self):
        """
        Open the classification dialog for update the categories and values
        in which could be classified a segment.
        """
        # create and open the dialog to edit the classification categories
        selection = self.widget.selected_elements_interval()

        if selection is None:
            QMessageBox.warning(QMessageBox(), self.tr(u"Warning"),
                                self.tr(u"There is no selection made."))
            return

        index_from, index_to = selection
        classification_dialog = ManualClassificationDialog()

        if classification_dialog.exec_():
            classification = classification_dialog.get_classification()
            self.segmentManager.set_manual_elements_classification(
                xrange(index_from, index_to + 1), classification)

    # endregion

    # region Classification

    def show_image_on_element(self, element_index, image):
        """
        show a toast with the specie image (if any and if is identified) of
        the element at element index position
        :param element_index:
        :return:
        """
        toast = ToastWidget(self, back_image=image, width=100, heigth=100)

        element = self.segmentManager.elements[element_index]
        min_x, max_x = self.widget.get_visible_region()

        x = element.indexFrom - min_x + (element.indexTo -
                                         element.indexFrom) / 2.0
        x = x * self.widget.width() * 1.0 / (max_x - min_x)

        toast.move(
            self.widget.mapToGlobal(
                QPoint(x - toast.width() / 2.0,
                       (self.widget.height() - toast.height()) / 2.0)))

        toast.disappear()

    @pyqtSlot()
    def on_actionCross_correlation_triggered(self):
        """
        Opens the cross-correlation dialog (after selecting a file containing a reference segment) to check each
        segment's match with a reference segment.
        """
        file_name = QFileDialog.getOpenFileName(
            self,
            self.tr(u"Select the file of a reference segment"),
            directory=self.workSpace.lastOpenedFile,
            filter=self.tr(u"Wave Files") + u"(*.wav);;All Files(*)")
        if file_name:
            dialog = CrossCorrelationDialog(self, self.widget, file_name,
                                            self.TABLE_ROW_COLOR_ODD,
                                            self.TABLE_ROW_COLOR_EVEN)

            self._cross_correlation_windows.append(dialog)
            dialog.elementSelected.connect(self.select_element)
            dialog.show()

    # endregion

    # region Detection

    def set_progress_bar_visibility(self, visibility=True):
        """
        Show the progress bar in the middle of the widget.
        Used when a high time demanding task is going to be made to
        show to the user it's progress.
        :return:
        """
        if not visibility:
            self.windowProgressDetection.setVisible(False)

        else:
            width, height = self.width(), self.height()
            x, y = self.widget.x(), self.widget.y()
            progress_bar_height = height / 20.0

            self.windowProgressDetection.resize(width / 3.0,
                                                progress_bar_height)
            self.windowProgressDetection.move(
                x + width / 3.0, y + height / 2.0 + progress_bar_height / 2.0)
            self.windowProgressDetection.setVisible(True)

        self.repaint()

    @pyqtSlot()
    def on_actionDetection_triggered(self):
        """
        Method that execute the detection
        """

        # there is an on going detection been made
        if self.windowProgressDetection.isVisible():
            QMessageBox.warning(
                QMessageBox(), self.tr(u"Error"),
                self.tr(u"There is an on going detection in progress."))
            return

        elementsDetectorDialog = ElemDetectSettingsDialog(
            self, self.widget.signal, self.segmentManager)
        elementsDetectorDialog.modifyParametersMeasurement.connect(
            lambda: self.on_actionParameter_Measurement_triggered())
        elementsDetectorDialog.load_workspace(self.workSpace)

        try:
            if elementsDetectorDialog.exec_():
                # the detection dialog is a factory of segmentation,
                # parameter parameters and classification concrete implementations

                # get the segmentation, classification and parameters methods
                self.segmentManager.detector_adapter = elementsDetectorDialog.detector
                self.segmentManager.classifier_adapter = elementsDetectorDialog.classifier
                self.segmentManager.parameters = self.parameter_manager.parameter_list(
                )

                self.windowProgressDetection.setValue(0)
                self.set_progress_bar_visibility(True)

                # execute the detection
                self.segmentManager.detect_elements()

        except Exception as e:
            print("detection errors: " + e.message)

            self.windowProgressDetection.setValue(100)
            self.set_progress_bar_visibility(False)

    def segmentation_finished(self):
        """
        Callback to execute when the segmentation segmentation_thread finished.
        :return:
        """
        self.windowProgressDetection.setValue(90)

        # put the elements detected into the widget to visualize them
        self.widget.elements = self.segmentManager.elements

        # shows the detection elements first and later the measurements as lazy load
        self.widget.draw_elements()

        self.windowProgressDetection.setValue(100)
        self.set_progress_bar_visibility(False)

        # measure the parameters over elements detected
        QTimer.singleShot(50,
                          self.segmentManager.measure_parameters_and_classify)

    def measurement_finished(self):
        """
        Callback to execute when the measurement has finished.
        :return:
        """
        # must be refreshed the widget because the parameter measurement
        # may include visual items into the graph
        self.widget.draw_elements()
        self.update_two_dim_windows()
        self.update_parameter_table()
        self.__set_parameter_window_visible()

    def __set_parameter_window_visible(self):
        # set the parameter window to visible state after measurements
        if not self.tableParameterOscilogram.isVisible():
            self.actionView_Parameters.setChecked(True)
            self.dockWidgetParameterTableOscilogram.setVisible(True)

    def update_two_dim_windows(self):
        # update the measured data on the two dimensional opened windows
        for wnd in self.two_dim_windows:
            wnd.load_data(self.segmentManager)

    def groupTableParametersChanged(self):

        grouped_params = self.actionGroupByParameter.isChecked()
        grouped_locations = self.actionGroupByLocation.isChecked()
        grouped_none = self.actionGroupNone.isChecked()

        self.parameter_table_row_shift = 0 if grouped_none else 2

        if grouped_none:
            self.parameter_table_sort_type = self.PARAMETER_SORT_NONE

        elif grouped_params:
            self.parameter_table_sort_type = self.PARAMETER_SORT_BY_PARAMETER

        elif grouped_locations:
            self.parameter_table_sort_type = self.PARAMETER_SORT_BY_LOCATION

        self.update_parameter_table()
        self.on_actionDeselect_Elements_triggered()

    # endregion

    # region Parameter Table

    def _group_measurements(self, parameters):
        """
        group the measurements for display in table
        :param parameters: the parameters measurements to group
        :return: list of groups (list) grouped by location or parameter
        accord to the instance variable  parameter_table_sort_type
        """
        groups = []

        def group_item_selector(param):
            if self.parameter_table_sort_type == self.PARAMETER_SORT_BY_LOCATION:
                return "-" if param.time_location is None else param.time_location.name
            return param.name

        param_positions = [(parameters[i], i) for i in xrange(len(parameters))]

        comparer = lambda x, y: cmp(group_item_selector(x[0]),
                                    group_item_selector(y[0]))

        param_positions.sort(cmp=comparer)

        index = 0
        while index < len(param_positions):
            current_group = []
            current_item = group_item_selector(param_positions[index][0])

            while index < len(parameters) and group_item_selector(
                    param_positions[index][0]) == current_item:
                current_group.append(param_positions[index][0])
                current_item = group_item_selector(param_positions[index][0])
                index += 1

            groups.append(current_group)

        return groups, [t[1] for t in param_positions]

    def _get_table_widget_item_centered(self, text):
        """
        return a TableWidgetItem with the text supplied and centered vertical and  horizontally
        :param text: text of the item
        :return:
        """
        item = QTableWidgetItem(unicode(text))
        item.setTextAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        return item

    def __fill_parameter_table_measurements(self, param_indexes):
        """
        Fill the values of the table parameters using the param indexes
        from the parameter sort defined by user. Is a helper method of the update parameter table
        :param param_indexes:
        :return:
        """

        # update every measurement [row, column] position
        for i in xrange(self.segmentManager.rowCount):
            for j in xrange(self.segmentManager.columnCount):
                # the last columns aren't for parameters but for classification
                param_index = param_indexes[j] if j < len(param_indexes) else j

                item = self._get_table_widget_item_centered(
                    self.segmentManager[i, param_index])

                # color options for the rows of the table
                item.setBackgroundColor(self.TABLE_ROW_COLOR_ODD if
                                        (i + self.parameter_table_row_shift) %
                                        2 == 0 else self.TABLE_ROW_COLOR_EVEN)

                self.tableParameterOscilogram.setItem(
                    i + self.parameter_table_row_shift, j, item)

    def __fill_parameter_table_grouped_columns_headers(self, params_groups,
                                                       indexes):
        # set the span value to group the param names columns and their names
        column_index = 0

        parameters = []
        for g in params_groups:
            parameters.extend(g)

        for j in xrange(len(parameters)):
            if self.parameter_table_sort_type == self.PARAMETER_SORT_BY_LOCATION:
                text = parameters[j].name
            else:
                text = "-" if parameters[j].time_location is None else unicode(
                    parameters[j].time_location.name)

            item = self._get_table_widget_item_centered(text)
            self.tableParameterOscilogram.setItem(1, j, item)

        # set the group names on the row 0
        for param_group in params_groups:
            span_size = len(param_group)
            if span_size > 1:
                self.tableParameterOscilogram.setSpan(0, column_index, 1,
                                                      span_size)

            if self.parameter_table_sort_type == self.PARAMETER_SORT_BY_PARAMETER:
                text = param_group[0].name
            else:
                text = "-" if param_group[0].time_location is None else unicode(
                    param_group[0].time_location.name)

            item = self._get_table_widget_item_centered(text)
            self.tableParameterOscilogram.setItem(0, column_index, item)
            column_index += span_size

        # put the classification category headers
        for index, category_classif in enumerate(
                self.segmentManager.classificationColumnNames):
            item = self._get_table_widget_item_centered(category_classif)
            self.tableParameterOscilogram.setItem(0, column_index + index,
                                                  item)

    def update_parameter_table(self):
        """
        Method that updates the parameter table to visualize
        the data of the detected segments, their measured parameters and classification
        :return:
        """
        parameters = self.segmentManager.parameters

        self.tableParameterOscilogram.clear()
        self.tableParameterOscilogram.setRowCount(
            self.segmentManager.rowCount + self.parameter_table_row_shift)
        self.tableParameterOscilogram.setColumnCount(
            self.segmentManager.columnCount)

        header_labels = self.segmentManager.columnNames

        if self.parameter_table_sort_type != self.PARAMETER_SORT_NONE:
            # get the list of parameters grouped by type
            params_groups, indexes = self._group_measurements(parameters)

            header_labels = ["" for _ in self.segmentManager.columnNames]

            # set the vertical names of rows. Parameters on first row and locations on second
            vertical_headers = [
                "Parameter" if s == 0 else
                "Location" if s == 1 else str(s -
                                              self.parameter_table_row_shift +
                                              1)
                for s in xrange(self.segmentManager.rowCount +
                                self.parameter_table_row_shift)
            ]

            if self.parameter_table_sort_type == self.PARAMETER_SORT_BY_LOCATION:
                swap = vertical_headers[0]
                vertical_headers[0] = vertical_headers[1]
                vertical_headers[1] = swap

            self.tableParameterOscilogram.setVerticalHeaderLabels(
                vertical_headers)
            self.__fill_parameter_table_grouped_columns_headers(
                params_groups, indexes)
            self.__fill_parameter_table_measurements(indexes)

        else:
            self.__fill_parameter_table_measurements(xrange(len(parameters)))

        self.tableParameterOscilogram.setHorizontalHeaderLabels(header_labels)

        # connect the table selection with the selection of an element
        cell_pressed_element = lambda index, col: self.select_element(
            index - self.parameter_table_row_shift, col)
        self.tableParameterOscilogram.cellPressed.connect(cell_pressed_element)

        self.tableParameterOscilogram.resizeColumnsToContents()
        self.tableParameterOscilogram.resizeRowsToContents()

    # endregion

    # region Visual Elements

    @pyqtSlot()
    def on_actionView_Parameters_triggered(self):
        """
        Changes the visibility on the window of the parameter table.
        The parameter table is where the detected segments and its measured parameters
        are displayed.
        """
        self.dockWidgetParameterTableOscilogram.setVisible(
            self.actionView_Parameters.isChecked())

    @pyqtSlot()
    def on_actionTemporal_Elements_triggered(self):
        """
        Temporal Elements are the elements that are visible on the oscilogram graph.
        This method allows to change its visibility
        """
        visibility = self.actionTemporal_Elements.isChecked()

        self.widget.visual_items_visibility.oscilogram_items_visible = visibility
        self.widget.draw_elements()

        for x in [
                self.actionTemporal_Figures, self.actionTemporal_Numbers,
                self.actionTemporal_Parameters
        ]:
            x.setEnabled(visibility)

    @pyqtSlot()
    def on_actionTemporal_Figures_triggered(self):
        self.widget.visual_items_visibility.oscilogram_figures_visible = self.actionTemporal_Figures.isChecked(
        )
        self.widget.draw_elements()

    @pyqtSlot()
    def on_actionTemporal_Parameters_triggered(self):
        self.widget.visual_items_visibility.oscilogram_parameters_visible = self.actionTemporal_Parameters.isChecked(
        )
        self.widget.draw_elements()

    @pyqtSlot()
    def on_actionTemporal_Numbers_triggered(self):
        """
        Change visibility of the numbers of the detected segments on the oscilogram graph

        """
        self.widget.visual_items_visibility.oscilogram_text_visible = self.actionTemporal_Numbers.isChecked(
        )
        self.widget.draw_elements()

    @pyqtSlot()
    def on_actionSpectral_Elements_triggered(self):
        """
        Spectral Elements are the elements that are visible on the spectrogram graph.
        This method allows to change its visibility
        """
        visibility = self.actionSpectral_Elements.isChecked()

        self.widget.visual_items_visibility.spectrogram_items_visible = visibility
        self.widget.draw_elements()

        for x in [
                self.actionSpectral_Numbers, self.actionSpectral_Figures,
                self.actionSpectral_Parameters
        ]:
            x.setEnabled(visibility)

    @pyqtSlot()
    def on_actionSpectral_Figures_triggered(self):
        self.widget.visual_items_visibility.spectrogram_figures_visible = self.actionSpectral_Figures.isChecked(
        )
        self.widget.draw_elements()

    @pyqtSlot()
    def on_actionSpectral_Parameters_triggered(self):
        self.widget.visual_items_visibility.spectrogram_parameters_visible = self.actionSpectral_Parameters.isChecked(
        )
        self.widget.draw_elements()

    @pyqtSlot()
    def on_actionSpectral_Numbers_triggered(self):
        """
        Change visibility of the numbers of the detected segments on the oscilogram graph

        """
        self.widget.visual_items_visibility.spectrogram_text_visible = self.actionSpectral_Numbers.isChecked(
        )
        self.widget.draw_elements()

    # endregion

    def update_parameters(self, parameter_manager):
        """
        Updates the parameters to measure from a change in their selection.
        :param parameter_manager:
        :return:
        """
        self.widget.release_items(parameter_items=True, elements_items=False)

        # update the segment manager that measure the new params
        self.segmentManager.parameters = parameter_manager.parameter_list()

        self.measurement_finished()

    @pyqtSlot()
    def on_actionParameter_Measurement_triggered(self):

        # check for previously parameters measurements to save
        # there is measured parameters when the list of their names has at least one element
        if len(self.segmentManager.parameterColumnNames) > 0:

            mbox = QMessageBox(
                QMessageBox.Question, self.tr(u"soundLab"),
                self.tr(
                    u"You are going to change the parameters to measure."
                    u"All your previously selected measurements will be lost."
                    u"Do you want to save measurements first?"),
                QMessageBox.Yes | QMessageBox.No, self)

            if mbox.exec_() == QMessageBox.Yes:
                self.on_actionMeditions_triggered()

        param_window = ParametersWindow(self,
                                        self.parameter_manager,
                                        self.widget.signal,
                                        workspace=self.workSpace)

        param_window.parameterChangeFinished.connect(
            lambda p: self.update_parameters(p))

        param_window.show()

    def load_workspace(self, workspace):
        """
        Method that loads the workspace to update visual options from main window.
        :param workspace:
        """
        self.workSpace = workspace
        self.widget.load_workspace(workspace)

        # update workspace on every window
        for wnd in self.two_dim_windows:
            wnd.load_workspace(self.workSpace)
class QuadStatusBar(QHBoxLayout):
    positionChanged = pyqtSignal(int, int, int)  # x,y,z

    def __init__(self, parent=None):
        QHBoxLayout.__init__(self, parent)
        self.setContentsMargins(0, 4, 0, 0)
        self.setSpacing(0)
        self.timeControlFontSize = 12

    def showXYCoordinates(self):
        self.zLabel.setHidden(True)
        self.zSpinBox.setHidden(True)

    def showXYZCoordinates(self):
        self.zLabel.setHidden(False)
        self.zSpinBox.setHidden(False)

    def hideTimeSlider(self, flag):
        visibleBefore = not self.timeSlider.isHidden()
        self.timeSlider.setHidden(flag)
        self.timeEndButton.setHidden(flag)
        self.timeStartButton.setHidden(flag)
        self.timePreviousButton.setHidden(flag)
        self.timeNextButton.setHidden(flag)
        self._registerTimeframeShortcuts(enabled=not flag,
                                         remove=visibleBefore)

    def setToolTipTimeButtonsCrop(self, croppingFlag=False):
        if croppingFlag == True:
            self.timeStartButton.setToolTip(
                "Jump to lirst frame of current crop")
            self.timeEndButton.setToolTip("Jump to last frame of current crop")
            self.timePreviousButton.setToolTip("Previous Frame")
            self.timeNextButton.setToolTip("Next Frame")
        else:
            self.timeStartButton.setToolTip("First Frame")
            self.timeEndButton.setToolTip("Last Frame")
            self.timePreviousButton.setToolTip("Previous Frame")
            self.timeNextButton.setToolTip("Next Frame")

    def setToolTipTimeSliderCrop(self, croppingFlag=False):
        if croppingFlag == True:
            self.timeSlider.setToolTip(
                "Choose the time coordinate of the current crop.")
        else:
            self.timeSlider.setToolTip(
                "Choose the time coordinate of the current dataset.")

    def createQuadViewStatusBar(self, xbackgroundColor, xforegroundColor,
                                ybackgroundColor, yforegroundColor,
                                zbackgroundColor, zforegroundColor):
        self.xLabel, self.xSpinBox = _get_pos_widget('X', xbackgroundColor,
                                                     xforegroundColor)
        self.yLabel, self.ySpinBox = _get_pos_widget('Y', ybackgroundColor,
                                                     yforegroundColor)
        self.zLabel, self.zSpinBox = _get_pos_widget('Z', zbackgroundColor,
                                                     zforegroundColor)

        self.xSpinBox.delayedValueChanged.connect(
            partial(self._handlePositionBoxValueChanged, 'x'))
        self.ySpinBox.delayedValueChanged.connect(
            partial(self._handlePositionBoxValueChanged, 'y'))
        self.zSpinBox.delayedValueChanged.connect(
            partial(self._handlePositionBoxValueChanged, 'z'))

        self.addWidget(self.xLabel)
        self.addWidget(self.xSpinBox)
        self.addWidget(self.yLabel)
        self.addWidget(self.ySpinBox)
        self.addWidget(self.zLabel)
        self.addWidget(self.zSpinBox)

        self.addSpacing(10)

        self.crosshairsCheckbox = QCheckBox()
        self.crosshairsCheckbox.setChecked(False)
        self.crosshairsCheckbox.setCheckable(True)
        self.crosshairsCheckbox.setText("Crosshairs")
        self.addWidget(self.crosshairsCheckbox)

        self.addSpacing(10)

        self.busyIndicator = QProgressBar()
        self.busyIndicator.setMaximumWidth(200)
        self.busyIndicator.setMaximum(0)
        self.busyIndicator.setMinimum(0)
        self.busyIndicator.setVisible(False)
        self.busyIndicator.setSizePolicy(QSizePolicy.Expanding,
                                         QSizePolicy.Fixed)
        self.addWidget(self.busyIndicator)
        self.setStretchFactor(self.busyIndicator, 1)

        self.addStretch()

        self.addSpacing(20)

        self.timeSpinBox = DelayedSpinBox(750)

        icons_dir = os.path.dirname(volumina.__file__) + "/icons"

        self.timeStartButton = QToolButton()
        self.timeStartButton.setIcon(QIcon(icons_dir + "/skip-start.png"))
        self.addWidget(self.timeStartButton)
        self.timeStartButton.clicked.connect(self._onTimeStartButtonClicked)
        #self.timeStartButton.setFixedWidth(4*self.timeControlFontSize)

        self.timePreviousButton = QToolButton()
        self.timePreviousButton.setIcon(QIcon(icons_dir + "/play-reverse.png"))
        self.addWidget(self.timePreviousButton)
        self.timePreviousButton.clicked.connect(
            self._onTimePreviousButtonClicked)
        #self.timePreviousButton.setFixedWidth(4*self.timeControlFontSize)

        self.timeSlider = QSlider(Qt.Horizontal)
        self.timeSlider.setMinimumWidth(10)
        self.timeSlider.setMaximumWidth(200)
        self.setToolTipTimeSliderCrop()
        self.addWidget(self.timeSlider)
        self.timeSlider.valueChanged.connect(self._onTimeSliderChanged)

        self.timeNextButton = QToolButton()
        self.timeNextButton.setIcon(QIcon(icons_dir + "/play.png"))
        self.addWidget(self.timeNextButton)
        self.timeNextButton.clicked.connect(self._onTimeNextButtonClicked)
        #self.timeNextButton.setFixedWidth(4*self.timeControlFontSize)

        self.timeEndButton = QToolButton()
        self.timeEndButton.setIcon(QIcon(icons_dir + "/skip-end.png"))
        #self.timeEndButton.setFixedWidth(4*self.timeControlFontSize)

        self.setToolTipTimeButtonsCrop()
        self.addWidget(self.timeEndButton)
        self.timeEndButton.clicked.connect(self._onTimeEndButtonClicked)

        self.timeLabel = QLabel("       Time:")
        self.addWidget(self.timeLabel)

        timeControlFont = self.timeSpinBox.font()
        if self.timeControlFontSize > timeControlFont.pointSize():
            timeControlFont.setPixelSize(2 * self.timeControlFontSize)
            self.timeStartButton.setFont(timeControlFont)
            self.timeEndButton.setFont(timeControlFont)
            self.timeLabel.setFont(timeControlFont)
            self.timeSpinBox.setFont(timeControlFont)

        self.addWidget(self.timeSpinBox)
        self.timeSpinBox.delayedValueChanged.connect(
            self._onTimeSpinBoxChanged)

        self._registerTimeframeShortcuts()

    def _registerTimeframeShortcuts(self, enabled=True, remove=True):
        """ Register or deregister "," and "." as keyboard shortcuts for scrolling in time """
        mgr = ShortcutManager()
        ActionInfo = ShortcutManager.ActionInfo

        def action(key, actionInfo):
            if enabled:
                mgr.register(key, actionInfo)
            else:
                if remove:
                    mgr.unregister(actionInfo)

        action(
            "<",
            ActionInfo("Navigation", "Go to next time frame",
                       "Go to next time frame", self._onTimeNextButtonClicked,
                       self.timeNextButton, self.timeNextButton))
        action(
            ">",
            ActionInfo("Navigation", "Go to previous time frame",
                       "Go to previous time frame",
                       self._onTimePreviousButtonClicked,
                       self.timePreviousButton, self.timePreviousButton))

    def _onTimeStartButtonClicked(self):
        self.timeSpinBox.setValue(
            self.parent().parent().parent().editor.cropModel.get_roi_t()[0])

    def _onTimeEndButtonClicked(self):
        self.timeSpinBox.setValue(
            self.parent().parent().parent().editor.cropModel.get_roi_t()[1])

    def _onTimePreviousButtonClicked(self):
        self.timeSpinBox.setValue(self.timeSpinBox.value() - 1)

    def _onTimeNextButtonClicked(self):
        self.timeSpinBox.setValue(self.timeSpinBox.value() + 1)

    def _onTimeSpinBoxChanged(self):
        editor = self.parent().parent().parent().editor
        cropModel = editor.cropModel
        minValueT = cropModel.get_roi_t()[0]
        maxValueT = cropModel.get_roi_t()[1]

        if cropModel.get_scroll_time_outside_crop():
            if minValueT > self.timeSpinBox.value(
            ) or maxValueT < self.timeSpinBox.value():
                for imgView in editor.imageViews:
                    imgView._croppingMarkers._shading_item.set_paint_full_frame(
                        True)
            else:
                for imgView in editor.imageViews:
                    imgView._croppingMarkers._shading_item.set_paint_full_frame(
                        False)
            self.timeSlider.setValue(self.timeSpinBox.value())
        else:
            for imgView in editor.imageViews:
                imgView._croppingMarkers._shading_item.set_paint_full_frame(
                    False)
            if minValueT > self.timeSpinBox.value():
                self.timeSlider.setValue(minValueT)
            elif maxValueT < self.timeSpinBox.value():
                self.timeSlider.setValue(maxValueT)
            elif minValueT <= self.timeSpinBox.value(
            ) and self.timeSpinBox.value() <= maxValueT:
                self.timeSlider.setValue(self.timeSpinBox.value())

    def _onTimeSliderChanged(self):
        cropModel = self.parent().parent().parent().editor.cropModel
        minValueT = cropModel.get_roi_t()[0]
        maxValueT = cropModel.get_roi_t()[1]

        if cropModel.get_scroll_time_outside_crop():
            self.timeSpinBox.setValue(self.timeSlider.value())
        else:
            if minValueT > self.timeSlider.value():
                self.timeSpinBox.setValue(minValueT)
                self.timeSlider.setValue(minValueT)
            elif self.timeSlider.value() > maxValueT:
                self.timeSpinBox.setValue(maxValueT)
                self.timeSlider.setValue(maxValueT)
            elif minValueT <= self.timeSlider.value(
            ) and self.timeSlider.value() <= maxValueT:
                self.timeSpinBox.setValue(self.timeSlider.value())

    def _handlePositionBoxValueChanged(self, axis, value):
        new_position = [
            self.xSpinBox.value(),
            self.ySpinBox.value(),
            self.zSpinBox.value()
        ]
        changed_axis = ord(axis) - ord('x')
        new_position[changed_axis] = value
        self.positionChanged.emit(*new_position)

    def updateShape5D(self, shape5D):
        self.timeSpinBox.setMaximum(shape5D[0] - 1)
        self.xSpinBox.setMaximum(shape5D[1] - 1)
        self.ySpinBox.setMaximum(shape5D[2] - 1)
        self.zSpinBox.setMaximum(shape5D[3] - 1)

    def updateShape5Dcropped(self, shape5DcropMin, shape5Dmax):
        self.timeSpinBox.setMaximum(shape5Dmax[0] - 1)
        self.xSpinBox.setMaximum(shape5Dmax[1] - 1)
        self.ySpinBox.setMaximum(shape5Dmax[2] - 1)
        self.zSpinBox.setMaximum(shape5Dmax[3] - 1)
        self.timeSlider.setMaximum(shape5Dmax[0] - 1)

        self.timeSpinBox.setValue(shape5DcropMin[0])
        self.xSpinBox.setValue(shape5DcropMin[1])
        self.ySpinBox.setValue(shape5DcropMin[2])
        self.zSpinBox.setValue(shape5DcropMin[3])
        self.timeSlider.setValue(shape5DcropMin[0])

    def setMouseCoords(self, x, y, z):
        self.xSpinBox.setValueWithoutSignal(x)
        self.ySpinBox.setValueWithoutSignal(y)
        self.zSpinBox.setValueWithoutSignal(z)
Exemple #13
0
class QuadStatusBar(QHBoxLayout):
    positionChanged = pyqtSignal(int, int, int)  # x,y,z

    def __init__(self, parent=None):
        QHBoxLayout.__init__(self, parent)
        self.setContentsMargins(0, 4, 0, 0)
        self.setSpacing(0)

    def showXYCoordinates(self):
        self.zLabel.setHidden(True)
        self.zSpinBox.setHidden(True)

    def showXYZCoordinates(self):
        self.zLabel.setHidden(False)
        self.zSpinBox.setHidden(False)

    def createQuadViewStatusBar(
        self, xbackgroundColor, xforegroundColor, ybackgroundColor, yforegroundColor, zbackgroundColor, zforegroundColor
    ):
        self.xLabel, self.xSpinBox = _get_pos_widget("X", xbackgroundColor, xforegroundColor)
        self.yLabel, self.ySpinBox = _get_pos_widget("Y", ybackgroundColor, yforegroundColor)
        self.zLabel, self.zSpinBox = _get_pos_widget("Z", zbackgroundColor, zforegroundColor)

        self.xSpinBox.delayedValueChanged.connect(partial(self._handlePositionBoxValueChanged, "x"))
        self.ySpinBox.delayedValueChanged.connect(partial(self._handlePositionBoxValueChanged, "y"))
        self.zSpinBox.delayedValueChanged.connect(partial(self._handlePositionBoxValueChanged, "z"))

        self.addWidget(self.xLabel)
        self.addWidget(self.xSpinBox)
        self.addWidget(self.yLabel)
        self.addWidget(self.ySpinBox)
        self.addWidget(self.zLabel)
        self.addWidget(self.zSpinBox)

        self.addSpacing(10)

        self.busyIndicator = QProgressBar()
        self.busyIndicator.setMaximum(0)
        self.busyIndicator.setMinimum(0)
        self.busyIndicator.setVisible(False)
        self.busyIndicator.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.addWidget(self.busyIndicator)
        self.setStretchFactor(self.busyIndicator, 1)

        self.addStretch()
        self.addSpacing(10)

        self.positionCheckBox = QCheckBox()
        self.positionCheckBox.setChecked(True)
        self.positionCheckBox.setCheckable(True)
        self.positionCheckBox.setText("Position")
        self.addWidget(self.positionCheckBox)

        self.addSpacing(20)

        self.timeLabel = QLabel("Time:")
        self.addWidget(self.timeLabel)

        self.timeSpinBox = DelayedSpinBox(750)
        self.addWidget(self.timeSpinBox)

    def _handlePositionBoxValueChanged(self, axis, value):
        new_position = [self.xSpinBox.value(), self.ySpinBox.value(), self.zSpinBox.value()]
        changed_axis = ord(axis) - ord("x")
        new_position[changed_axis] = value
        self.positionChanged.emit(*new_position)

    def updateShape5D(self, shape5D):
        self.timeSpinBox.setMaximum(shape5D[0] - 1)
        self.xSpinBox.setMaximum(shape5D[1] - 1)
        self.ySpinBox.setMaximum(shape5D[2] - 1)
        self.zSpinBox.setMaximum(shape5D[3] - 1)

    def setMouseCoords(self, x, y, z):
        self.xSpinBox.setValueWithoutSignal(x)
        self.ySpinBox.setValueWithoutSignal(y)
        self.zSpinBox.setValueWithoutSignal(z)
class ConversationsWinGui(BaseWindow, QtGui.QMainWindow):
    refreshList = QtCore.pyqtSignal()
    loggedOut = QtCore.pyqtSignal()
    windowClosed = QtCore.pyqtSignal()

    def __init__(self, session, parent=None):
        super(ConversationsWinGui, self).__init__(parent=parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        self.activeConversationWindows = {}
        self.newConversationWindow = None

        self.session = session
        sharedData.messages = getMessages(self.session.username) or []

        self.ui.refresh.clicked.connect(self.refresh)
        self.ui.logout.triggered.connect(self.logout)

        self.refreshShortcut = QtGui.QShortcut(QtGui.QKeySequence("F5"), self)
        self.refreshShortcut.activated.connect(self.refresh)

        self.setPeerShortcut = QtGui.QShortcut(QtGui.QKeySequence("Return"), self)
        self.setPeerShortcut.activated.connect(self.refresh)
        self.setPeerShortcut.setEnabled(False)

        self.refreshList.connect(self.refreshListSlot)

        self.ui.newConversation.clicked.connect(self.startNewConversation)

        self.ui.conversationsList.itemClicked.connect(self.conversationSelected)

        self.ui.unauthorizeClient.triggered.connect(self.unauthorize)

        self.ui.deleteMessages.triggered.connect(self.clearMessages)

        self.ui.setPassword.triggered.connect(self.setPassword)

        self.ui.markAllAsRead.triggered.connect(self.markAllAsRead)

        self.ui.renameUser.triggered.connect(self.renameUser)

        self.progressIndicator = QProgressBar(self.ui.statusBar)
        self.progressIndicator.setMinimumHeight(5)
        self.progressIndicator.setVisible(False)
        self.progressIndicator.setMaximum(0)
        self.progressIndicator.setMinimum(0)
        self.ui.statusBar.addWidget(self.progressIndicator)

        self.uiTranslate()

        self.refresh()

    def uiTranslate(self):
        self.ui.refresh.setText(strings["refreshButtonText"])
        self.ui.logout.setText(strings["logoutButtonText"])
        self.ui.unauthorizeClient.setText(strings["unauthorizeClientButtonText"])
        self.ui.deleteMessages.setText(strings["deleteAllMessagesButtonText"])
        self.ui.setPassword.setText(strings["setPasswordWindowTitle"])
        self.setWindowTitle(strings["appName"] + ": " + self.session.username)
        self.ui.newConversation.setText(strings["startNewConversationButtonText"])
        self.ui.menuTools.setTitle(strings["toolsMenuText"])
        self.ui.markAllAsRead.setText(strings["markAllAsReadButtonText"])
        self.ui.renameUser.setText(strings["renameUserButtonText"])

    def progressStart(self):
        self.progressIndicator.setVisible(True)

    def askForConfirmation(self, message):
        confirmationBox = QtGui.QMessageBox(parent=self, text=message)
        confirmationBox.setStandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
        confirmationBox.setWindowTitle(strings["appName"])
        return confirmationBox.exec() == QtGui.QMessageBox.Yes

    def progressStop(self):
        self.progressIndicator.setVisible(False)

    def show(self):
        super(ConversationsWinGui, self).show()
        self.refreshList.emit()

    def refresh(self):
        self.progressStart()

        def refreshThread():
            try:
                sharedData.messages += self.session.getMessages()
            except SecureMessagingException as error:
                self.showMessageBox.emit(strings["errorText"] + responseTranslations[str(error)])
                print(error)
                return
            sharedData.messages = sorted(sharedData.messages, key=messageSort)
            storeMessages(self.session.username, sharedData.messages)
            self.refreshList.emit()

        Thread(target=refreshThread).start()

    def refreshListSlot(self, refreshChildren=True):
        seenPeers = set()
        self.ui.conversationsList.clear()
        for message in reversed(sharedData.messages):
            if not message.messagePeer in seenPeers:
                seenPeers.add(message.messagePeer)
                peerName = QListWidgetItem(self.ui.conversationsList)
                nameFont = QtGui.QFont()
                contentsFont = QtGui.QFont()
                nameFont.setPointSize(14)
                if not message.read:
                    nameFont.setBold(True)
                    contentsFont.setBold(True)
                peerName.setFont(nameFont)
                peerName.setText(message.messagePeer)
                messageContents = QListWidgetItem(self.ui.conversationsList)
                if message.isFile:
                    contentLines = [message.fileName]
                elif not message.contents:
                    contentLines = [""]
                else:
                    contentLines = message.contents.splitlines(keepends=False)
                contentsFont.setPointSize(10)
                contents = contentLines[0]
                if len(contentLines) > 1:
                    contents += "\n" + contentLines[1]
                if len(contents) > 20:
                    contents = contents[:20]
                messageContents.setFont(contentsFont)
                messageContents.setText(contents)
                self.ui.conversationsList.addItem(peerName)
                self.ui.conversationsList.addItem(messageContents)
                separatorItem = QListWidgetItem(self.ui.conversationsList)
                separatorItem.setFlags(QtCore.Qt.NoItemFlags)
                self.ui.conversationsList.addItem(separatorItem)
        if refreshChildren:
            for peerName in self.activeConversationWindows:
                self.activeConversationWindows[peerName].refreshDisplay.emit()
        self.progressStop()

    def startNewConversation(self):
        if self.newConversationWindow:
            self.newConversationWindow.activateWindow()
            return
        self.newConversationWindow = MainWinGui(self.session, "")
        self.newConversationWindow.refreshDisplay.connect(self.refreshTriggeredInChild)
        self.newConversationWindow.onClose.connect(self.newConversationWindowClosed)
        self.newConversationWindow.sendCompleted.connect(self.conversationStarted)
        self.newConversationWindow.show()

    def conversationStarted(self, message):
        if message.messagePeer in self.activeConversationWindows:
            self.activeConversationWindows[message.messagePeer].close()
        self.newConversationWindow.onClose.disconnect(self.newConversationWindowClosed)
        self.newConversationWindow.sendCompleted.disconnect(self.conversationStarted)
        self.newConversationWindow.onClose.connect(lambda peerName: self.activeConversationWindows.pop(peerName))
        self.activeConversationWindows[message.messagePeer] = self.newConversationWindow
        self.newConversationWindow = None

    def newConversationWindowClosed(self, *args, **kwargs):
        self.newConversationWindow = None

    def conversationSelected(self, listItem):
        row = self.ui.conversationsList.indexFromItem(listItem).row()
        selectedPeer = ""
        if row % 3 == 0:
            selectedPeer += listItem.text()
        elif row % 3 == 1:
            selectedPeer += self.ui.conversationsList.item(row - 1).text()
        else:
            listItem.setSelected(False)
        if selectedPeer != "":
            if selectedPeer in self.activeConversationWindows:
                self.activeConversationWindows[selectedPeer].activateWindow()
            else:
                newWindow = MainWinGui(self.session, selectedPeer)
                self.activeConversationWindows[selectedPeer] = newWindow
                newWindow.onClose.connect(lambda peerName: self.activeConversationWindows.pop(peerName))
                newWindow.refreshDisplay.connect(self.refreshTriggeredInChild)
                newWindow.show()

    def refreshTriggeredInChild(self):
        self.refreshListSlot(False)

    def clearMessages(self):
        if self.askForConfirmation(strings["confirmDeleteAllMessagesText"]):
            sharedData.messages = []
            storeMessages(self.session.username, None)
            self.refreshList.emit()

    def setPassword(self):
        setPasswordUi = SetPasswordGui(self.session, parent=self)
        setPasswordUi.show()

    def renameUser(self):
        renameUi = RenameGui(self.session, parent=self)
        renameUi.show()

    def logout(self):
        self.session.logout()
        self.loggedOut.emit()

    def unauthorize(self):
        if self.askForConfirmation(strings["confirmUnauthorizeClientText"]):
            try:
                self.session.unauthorize()
            except SecureMessagingException as error:
                self.showMessageBox.emit(strings["errorText"] + responseTranslations[str(error)])
                return
            storeMessages(self.session.username, None)
            storeToken(self.session.username, None)
            storeKey(self.session.username, None, None)
            self.logout()

    def closeEvent(self, *args, **kwargs):
        windowsToClose = []
        for window in self.activeConversationWindows:
            windowsToClose += [self.activeConversationWindows[window]]
        for window in windowsToClose:
            window.close()
        if self.newConversationWindow:
            self.newConversationWindow.close()
        self.windowClosed.emit()

    def markAllAsRead(self):
        sharedData.markAsRead()
        storeMessages(self.session.username, sharedData.messages)
        self.refreshList.emit()
Exemple #15
0
class MainWinGui(BaseWindow, QtGui.QMainWindow):
    refreshDisplay = QtCore.pyqtSignal()
    sendCompleted = QtCore.pyqtSignal(Message)
    fileDownloadCompleted = QtCore.pyqtSignal(bytes, str)
    onClose = QtCore.pyqtSignal(str)

    def __init__(self, session, peerName, parent=None):
        super(MainWinGui, self).__init__(parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        self.session = session
        self.peerName = peerName
        if peerName == "":
            self.ui.peerName.setVisible(False)
            self.ui.peer.setVisible(True)
            self.ui.peer.setText("")
            self.ui.peer.setFocus()
        else:
            self.ui.peerName.setVisible(True)
            self.ui.peer.setVisible(False)
            self.ui.peer.setText(peerName)
            self.ui.peerName.setText(peerName)
            self.ui.message.setFocus()

        self.ui.refresh.clicked.connect(self.refresh)
        self.ui.send.clicked.connect(self.send)
        self.ui.scrollBar = self.ui.display.verticalScrollBar()
        self.ui.display.setOpenLinks(False)
        self.ui.display.anchorClicked.connect(self.linkClicked)
        self.ui.display.anchorClicked.emit(QtCore.QUrl("UP"))

        self.refreshShortcut = QtGui.QShortcut(QtGui.QKeySequence("F5"), self)
        self.refreshShortcut.activated.connect(self.refresh)

        self.enterShortcut = QtGui.QShortcut(QtGui.QKeySequence("Enter"), self)
        self.returnShortcut = QtGui.QShortcut(QtGui.QKeySequence("Return"), self)
        self.enterShortcut.activated.connect(self.enterPressed)
        self.returnShortcut.activated.connect(self.enterPressed)
        self.ui.message.keyPressEvent = types.MethodType(keyPressEventReplacement, self.ui.message)

        self.ui.uploadFile.triggered.connect(self.uploadFile)

        self.ui.deleteMessages.triggered.connect(self.clearMessages)

        self.ui.stopSigning.triggered.connect(self.clearSigningSecret)

        self.ui.signMessages.triggered.connect(self.askForSigningSecret)

        self.ui.message.parentWindow = self

        self.refreshDisplay.connect(self.refreshDisplaySlot)
        self.sendCompleted.connect(self.sendCompletedSlot)
        self.fileDownloadCompleted.connect(self.fileDownloadCompletedSlot)

        self.progressIndicator = QProgressBar(self.ui.statusBar)
        self.progressIndicator.setMinimumHeight(5)
        self.progressIndicator.setVisible(False)
        self.progressIndicator.setMaximum(0)
        self.progressIndicator.setMinimum(0)

        self.signatureIndicator = QLabel(self.ui.statusBar)

        self.ui.statusBar.addWidget(self.progressIndicator)
        self.ui.statusBar.addPermanentWidget(self.signatureIndicator)

        self.signingSecret = None

        self.uiTranslate()

        self.refresh()

    def uiTranslate(self):
        self.ui.peer.setPlaceholderText(strings["peerBoxHint"])
        self.ui.refresh.setText(strings["refreshButtonText"])
        self.ui.send.setText(strings["sendMessageButtonText"])
        self.ui.deleteMessages.setText(strings["deleteConversationButtonText"])
        self.setWindowTitle(strings["conversationWindowTitle"] + ": " + self.peerName)
        self.ui.menuTools.setTitle(strings["toolsMenuText"])
        self.ui.uploadFile.setText(strings["uploadFileButtonText"])
        self.ui.stopSigning.setText(strings["stopSigningButtonText"])
        self.ui.signMessages.setText(strings["signMessagesButtonText"])
        self.signatureIndicator.setText(strings["signatureIndicatorOffText"])

    def enterPressed(self):
        if self.ui.peer.hasFocus():
            self.ui.message.setFocus()

    def progressStart(self):
        self.progressIndicator.setVisible(True)

    def askForConfirmation(self, message):
        confirmationBox = QtGui.QMessageBox(parent=self, text=message)
        confirmationBox.setStandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
        confirmationBox.setWindowTitle(strings["appName"])
        return confirmationBox.exec() == QtGui.QMessageBox.Yes

    def askForSigningSecret(self):
        response = QInputDialog.getText(
            self, strings["signatureSecretInputTitle"], strings["signatureSecretInputLabel"]
        )
        if response[1]:
            self.signingSecret = response[0].encode("utf-8")
            self.signatureIndicator.setText(strings["signatureIndicatorOnText"])

    def clearSigningSecret(self):
        self.signingSecret = None
        self.signatureIndicator.setText(strings["signatureIndicatorOffText"])

    def progressStop(self):
        self.progressIndicator.setVisible(False)

    def fileDownloadCompletedSlot(self, contents, fileName):
        self.progressStop()
        try:
            with open(fileName, mode="wb") as file:
                file.write(contents)
        except (SecureMessagingException, IOError) as error:
            self.showMessageBox.emit(strings["errorText"] + responseTranslations[str(error)])
            return

    def sendCompletedSlot(self, message):
        sharedData.messages += [message]
        self.ui.message.clear()
        self.ui.peerName.setText(self.ui.peer.text())
        self.ui.peer.setVisible(False)
        self.ui.peerName.setVisible(True)
        self.peerName = self.ui.peer.text()
        self.setWindowTitle(strings["conversationWindowTitle"] + ": " + self.peerName)
        self.refresh()

    def show(self):
        super(MainWinGui, self).show()
        self.refreshDisplay.emit()

    def linkClicked(self, url):
        url = url.toString()
        if url == "UP":
            return
        if url.startswith("FILE"):
            messageId = url[len("FILE") :]
            messageId = int(messageId)
            message = sharedData.messages[messageId]
            fileName = QtGui.QFileDialog.getSaveFileName(directory=message.fileName)
            if fileName:
                self.progressStart()

                def fileDownloaderThread():
                    try:
                        fileContents = self.session.downloadFile(message)
                        self.fileDownloadCompleted.emit(fileContents, fileName)
                    except (SecureMessagingException, IOError) as error:
                        self.showMessageBox.emit(strings["errorText"] + responseTranslations[str(error)])
                        return

                Thread(target=fileDownloaderThread).start()
        elif url.startswith("DEL_"):
            messageId = int(url[len("DEL_") :])
            if self.askForConfirmation(strings["confirmDeleteMessageText"]):
                sharedData.messages.pop(messageId)
                storeMessages(self.session.username, sharedData.messages)
                self.refreshDisplay.emit()
        elif url.startswith("SGN_"):
            messageId = int(url[len("SGN_") :])
            message = sharedData.messages[messageId]
            response = QInputDialog.getText(
                self, strings["signatureSecretInputTitle"], strings["signatureSecretInputLabel"]
            )
            if response[1]:
                if message.verifySignature(response[0].encode("utf-8")):
                    self.showMessageBox.emit(strings["signatureOkMessageText"])
                else:
                    self.showMessageBox.emit(strings["signatureBadMessageText"])

    def refreshDisplaySlot(self):
        outputText = '<table width="100%" cellpadding="5" border="" style="padding:15px;width:100%;">'
        peer = self.ui.peer.text()
        msgCount = -1
        for message in sharedData.messages:
            msgCount += 1
            if message.messagePeer != peer:
                continue
            contents = message.contents
            contents = escape(contents)
            if message.isFile:
                contents = (
                    '<a href ="FILE' + str(sharedData.messages.index(message)) + '">File: ' + message.fileName + "</a>"
                )
            if message.sender == self.session.username:
                outputText += '<tr style="background-color:#cadced;color:#000000"><td>'
            else:
                outputText += '<tr style="background-color:#FFFFFF;color:#000000"><td>'
            outputText += "<b>" + message.sender + "</b>&#10153;<b>" + message.receiver + "</b>"
            outputText += "<pre style='word-break:break-all;white-space:pre-wrap;font-family:Arial'>"
            outputText += contents
            outputText += "</pre>"
            outputText += (
                "<a style='text-decoration:none;color:#000000' href='"
                + "DEL_"
                + str(msgCount)
                + "'><font size='1'>&#9003;</font></a>"
            )
            if message.isSigned():
                outputText += (
                    "&emsp;<a style='text-decoration:none;color:#000000' href='"
                    + "SGN_"
                    + str(msgCount)
                    + "'><font size='1'>&#10004;</font></a>"
                )
            outputText += "<div style='font-size:small;' align='right'>" + message.getTimeStamp() + "</div>"
            outputText += "</td></tr>"
        outputText += "</table>"
        self.ui.display.setHtml(outputText)
        self.ui.display.verticalScrollBar().setValue(self.ui.display.verticalScrollBar().maximum())
        self.progressStop()

    def refresh(self):
        self.progressStart()

        def refreshThread():
            try:
                sharedData.messages += self.session.getMessages()
            except SecureMessagingException as error:
                self.showMessageBox.emit(strings["errorText"] + responseTranslations[str(error)])
                return
            sharedData.messages = sorted(sharedData.messages, key=messageSort)
            sharedData.markAsRead(self.ui.peer.text())
            storeMessages(self.session.username, sharedData.messages)
            self.refreshDisplay.emit()

        Thread(target=refreshThread).start()

    def send(self):
        self.progressStart()

        def senderThread():
            peer = self.ui.peer.text()
            contents = self.ui.message.toPlainText()
            if peer == "" or contents == "":
                self.showMessageBox.emit(strings["missingPeerOrMessageErrorText"])
                return
            if peer == self.session.username:
                self.showMessageBox.emit(strings["cantSendMessageToSelfText"])
                return
            sharedData.messages = sorted(sharedData.messages, key=messageSort)
            try:
                self.session.sendMessage(contents, peer, signatureSecret=self.signingSecret)
            except SecureMessagingException as error:
                self.showMessageBox.emit(strings["errorText"] + responseTranslations[str(error)])
                return
            self.sendCompleted.emit(Message(contents, self.session.username, peer, peer, self.session.timeDiff))

        Thread(target=senderThread).start()

    def uploadFile(self):
        peer = self.ui.peer.text()
        if peer == "":
            self.showMessageBox.emit(strings["missingPeerErrorText"])
            return
        if peer == self.session.username:
            self.showMessageBox.emit(strings["cantSendMessageToSelfText"])
            return
        fileName = QtGui.QFileDialog.getOpenFileName()
        if fileName:
            self.progressStart()

            def uploaderThread():
                try:
                    fileContents = open(fileName, "rb").read()
                    basename = os.path.basename(fileName)
                    fileType = mimetypes.guess_type("file://" + fileName)[0] or "application/octet-stream"
                    fileType = fileType.encode("ascii")
                    self.session.sendFile(basename, fileContents, peer, fileType)
                    self.sendCompleted.emit(Message(basename, self.session.username, peer, peer, self.session.timeDiff))
                except (SecureMessagingException, IOError) as error:
                    self.showMessageBox.emit(strings["errorText"] + responseTranslations[str(error)])
                    return

            Thread(target=uploaderThread).start()

    def clearMessages(self):
        if self.peerName and self.askForConfirmation(strings["confirmDeleteConversationText"]):
            numberOfMessages = len(sharedData.messages)
            deletedMessages = 0
            for i in range(numberOfMessages):
                if sharedData.messages[i - deletedMessages].messagePeer == self.peerName:
                    sharedData.messages.pop(i - deletedMessages)
                    deletedMessages += 1
            storeMessages(self.session.username, sharedData.messages)
            self.refreshDisplay.emit()

    def closeEvent(self, event):
        self.onClose.emit(self.ui.peer.text())
        super(MainWinGui, self).closeEvent(event)
Exemple #16
0
class UI_Psychrometry(QDialog):
    """Psychrometric charts tool"""
    def __init__(self, parent=None):
        super(UI_Psychrometry, self).__init__(parent)
        self.showMaximized()
        self.setWindowTitle("Psychrometric chart")

        layout = QGridLayout(self)
        self.diagrama2D = PsychroPlot(self, dpi=90)
        self.diagrama2D.fig.canvas.mpl_connect('motion_notify_event', self.scroll)
        layout.addWidget(self.diagrama2D, 1, 1, 1, 2)
        self.progressBar = QProgressBar()
        self.progressBar.setVisible(False)
        layout.addWidget(self.progressBar, 2, 1)
        self.status = QLabel()
        layout.addWidget(self.status, 2, 1)

        self.buttonBox = QDialogButtonBox(QDialogButtonBox.Close)
        butonPNG = QPushButton("Save as PNG")
        self.buttonBox.addButton(butonPNG, QDialogButtonBox.AcceptRole)
        self.buttonBox.rejected.connect(self.reject)
        self.buttonBox.accepted.connect(self.savePNG)
        layout.addWidget(self.buttonBox, 2, 2)

        self.plot()

    def savePNG(self):
        """Save chart image to png file"""
        fname = unicode(QFileDialog.getSaveFileName(
            self, "Save chart to file",
            "./", "Portable Network Graphics (*.png)"))
        self.diagrama2D.fig.savefig(fname, facecolor='#eeeeee')


    def drawlabel(self, name, Preferences, t, W, label, unit):
        """
        Draw annotation for isolines
            name: name of isoline
            Preferences: Configparse instance of pychemqt preferences
            t: x array of line
            W: y array of line
            label: text value to draw
            unit: text units to draw
        """
        if Preferences.getboolean("Psychr", name+"label"):
            tmin = Preferences.getfloat("Psychr", "isotdbStart")-273.15
            tmax = Preferences.getfloat("Psychr", "isotdbEnd")-273.15
            x = tmax-tmin
            wmin = Preferences.getfloat("Psychr", "isowStart")
            wmax = Preferences.getfloat("Psychr", "isowEnd")
            y = wmax-wmin

            i = 0
            for ti, wi in zip(t, W):
                if tmin <= ti <= tmax and wmin <= wi <= wmax:
                    i += 1
            label = str(label)
            if Preferences.getboolean("Psychr", name+"units"):
                label += unit
            pos = Preferences.getfloat("Psychr", name+"position")
            p = int(i*pos/100-1)
            rot = np.arctan((W[p]-W[p-1])/y/(t[p]-t[p-1])*x)*360.0/2.0/np.pi
            self.diagrama2D.axes2D.annotate(label, (t[p], W[p]),
                rotation=rot, size="small", ha="center", va="center")

    def plot(self):
        """Plot chart"""
        Preferences = ConfigParser()
        Preferences.read("psyrc")

        self.diagrama2D.axes2D.clear()
        self.diagrama2D.config()
        filename = "%i.pkl" % P
        if os.path.isfile(filename):
            with open(filename, "r") as archivo:
                data = cPickle.load(archivo)
                self.status.setText("Loading cached data...")
                QApplication.processEvents()
        else:
            self.progressBar.setVisible(True)
            self.status.setText("Calculating data, be patient...")
            QApplication.processEvents()
            data = PsyCoolprop.calculatePlot(self)
            cPickle.dump(data, open(filename, "w"))
            self.progressBar.setVisible(False)
        self.status.setText("Plotting...")
        QApplication.processEvents()

        tmax = Preferences.getfloat("Psychr", "isotdbEnd")-273.15

        t = [ti-273.15 for ti in data["t"]]
        Hs = data["Hs"]
        format = {}
        format["ls"] = Preferences.get("Psychr", "saturationlineStyle")
        format["lw"] = Preferences.getfloat("Psychr", "saturationlineWidth")
        format["color"] = Preferences.get("Psychr", "saturationColor")
        format["marker"] = Preferences.get("Psychr", "saturationmarker")
        format["markersize"] = 3
        self.diagrama2D.plot(t, Hs, **format)

        format = {}
        format["ls"] = Preferences.get("Psychr", "isotdblineStyle")
        format["lw"] = Preferences.getfloat("Psychr", "isotdblineWidth")
        format["color"] = Preferences.get("Psychr", "isotdbColor")
        format["marker"] = Preferences.get("Psychr", "isotdbmarker")
        format["markersize"] = 3
        for i, T in enumerate(t):
            self.diagrama2D.plot([T, T], [0, Hs[i]], **format)

        H = data["H"]
        th = data["th"]
        format = {}
        format["ls"] = Preferences.get("Psychr", "isowlineStyle")
        format["lw"] = Preferences.getfloat("Psychr", "isowlineWidth")
        format["color"] = Preferences.get("Psychr", "isowColor")
        format["marker"] = Preferences.get("Psychr", "isowmarker")
        format["markersize"] = 3
        for i, H in enumerate(H):
            self.diagrama2D.plot([th[i], tmax], [H, H], **format)

        format = {}
        format["ls"] = Preferences.get("Psychr", "isohrlineStyle")
        format["lw"] = Preferences.getfloat("Psychr", "isohrlineWidth")
        format["color"] = Preferences.get("Psychr", "isohrColor")
        format["marker"] = Preferences.get("Psychr", "isohrmarker")
        format["markersize"] = 3
        for Hr, H0 in data["Hr"].iteritems():
            self.diagrama2D.plot(t, H0, **format)
            self.drawlabel("isohr", Preferences, t, H0, Hr, "%")

        format = {}
        format["ls"] = Preferences.get("Psychr", "isotwblineStyle")
        format["lw"] = Preferences.getfloat("Psychr", "isotwblineWidth")
        format["color"] = Preferences.get("Psychr", "isotwbColor")
        format["marker"] = Preferences.get("Psychr", "isotwbmarker")
        format["markersize"] = 3
        for T, (H, Tw) in data["Twb"].iteritems():
            self.diagrama2D.plot(Tw, H, **format)
            value = T-273.15
            txt = u"ºC"
            self.drawlabel("isotwb", Preferences, Tw, H, value, txt)

        format = {}
        format["ls"] = Preferences.get("Psychr", "isochorlineStyle")
        format["lw"] = Preferences.getfloat("Psychr", "isochorlineWidth")
        format["color"] = Preferences.get("Psychr", "isochorColor")
        format["marker"] = Preferences.get("Psychr", "isochormarker")
        format["markersize"] = 3
        for v, (Td, H) in data["v"].iteritems():
            self.diagrama2D.plot(Td, H, **format)
            value = v
            txt = u"m³/kg"
            self.drawlabel("isochor", Preferences, Td, H, value, txt)

        self.diagrama2D.draw()
        self.status.setText("P = %i Pa" % P)

    def scroll(self, event):
        """Update graph annotate when mouse scroll over chart"""
        if event.xdata and event.ydata:
            punto = self.createState(event.xdata, event.ydata)
            if event.ydata < punto.ws:
                self.diagrama2D.showPointData(punto)
            else:
                self.diagrama2D.clearPointData()

    def createState(self, x, y):
        """Create psychrometric state from click or mouse position"""
        tdb = x+273.15
        punto = PsyCoolprop(P=P, tdb=tdb, w=y)
        return punto
class QuadStatusBar(QHBoxLayout):
    positionChanged = pyqtSignal(int, int, int)  # x,y,z

    def __init__(self, parent=None):
        QHBoxLayout.__init__(self, parent)
        self.setContentsMargins(0, 4, 0, 0)
        self.setSpacing(0)

    def showXYCoordinates(self):
        self.zLabel.setHidden(True)
        self.zSpinBox.setHidden(True)

    def showXYZCoordinates(self):
        self.zLabel.setHidden(False)
        self.zSpinBox.setHidden(False)

    def createQuadViewStatusBar(self, xbackgroundColor, xforegroundColor,
                                ybackgroundColor, yforegroundColor,
                                zbackgroundColor, zforegroundColor):
        self.xLabel, self.xSpinBox = _get_pos_widget('X', xbackgroundColor,
                                                     xforegroundColor)
        self.yLabel, self.ySpinBox = _get_pos_widget('Y', ybackgroundColor,
                                                     yforegroundColor)
        self.zLabel, self.zSpinBox = _get_pos_widget('Z', zbackgroundColor,
                                                     zforegroundColor)

        self.xSpinBox.delayedValueChanged.connect(
            partial(self._handlePositionBoxValueChanged, 'x'))
        self.ySpinBox.delayedValueChanged.connect(
            partial(self._handlePositionBoxValueChanged, 'y'))
        self.zSpinBox.delayedValueChanged.connect(
            partial(self._handlePositionBoxValueChanged, 'z'))

        self.addWidget(self.xLabel)
        self.addWidget(self.xSpinBox)
        self.addWidget(self.yLabel)
        self.addWidget(self.ySpinBox)
        self.addWidget(self.zLabel)
        self.addWidget(self.zSpinBox)

        self.addSpacing(10)

        self.busyIndicator = QProgressBar()
        self.busyIndicator.setMaximum(0)
        self.busyIndicator.setMinimum(0)
        self.busyIndicator.setVisible(False)
        self.busyIndicator.setSizePolicy(QSizePolicy.Expanding,
                                         QSizePolicy.Fixed)
        self.addWidget(self.busyIndicator)
        self.setStretchFactor(self.busyIndicator, 1)

        self.addStretch()
        self.addSpacing(10)

        self.positionCheckBox = QCheckBox()
        self.positionCheckBox.setChecked(True)
        self.positionCheckBox.setCheckable(True)
        self.positionCheckBox.setText("Position")
        self.addWidget(self.positionCheckBox)

        self.addSpacing(20)

        self.timeLabel = QLabel("Time:")
        self.addWidget(self.timeLabel)

        self.timeSpinBox = DelayedSpinBox(750)
        self.addWidget(self.timeSpinBox)

    def _handlePositionBoxValueChanged(self, axis, value):
        new_position = [
            self.xSpinBox.value(),
            self.ySpinBox.value(),
            self.zSpinBox.value()
        ]
        changed_axis = ord(axis) - ord('x')
        new_position[changed_axis] = value
        self.positionChanged.emit(*new_position)

    def updateShape5D(self, shape5D):
        self.timeSpinBox.setMaximum(shape5D[0] - 1)
        self.xSpinBox.setMaximum(shape5D[1] - 1)
        self.ySpinBox.setMaximum(shape5D[2] - 1)
        self.zSpinBox.setMaximum(shape5D[3] - 1)

    def setMouseCoords(self, x, y, z):
        self.xSpinBox.setValueWithoutSignal(x)
        self.ySpinBox.setValueWithoutSignal(y)
        self.zSpinBox.setValueWithoutSignal(z)
Exemple #18
0
class StatusBox(QGroupBox):
    STATUS_BOX_TEXT = 'Status'

    BASE_PATH_REQUIRED_MESSAGE_TEXT = 'Fill in the base path to start scanning for files to be renamed.'
    SCAN_FILES_PROGRESS_TEXT = 'Scanning files'
    SCAN_FILES_ERROR_CAPTION_TEXT = 'Error scanning files'

    RULES_ERROR_CAPTION_TEXT = 'Error in rules'

    NO_FILES_TO_RENAME_MESSAGE_TEXT = 'No files to rename.'
    RENAME_FILES_PROGRESS_TEXT = 'Renaming files'
    RENAME_FILES_ERROR_CAPTION_TEXT = 'Error renaming files'

    NO_FILES_RENAMED_MESSAGE_TEXT = 'No files changed.'
    READY_TO_RENAME_MESSAGE_TEXT = 'Ready to rename.'
    RENAME_PROGRESS_TEXT = 'Executing rename'
    PLANNING_RENAME_ERROR_CAPTION_TEXT = 'Error while planning rename'
    RENAME_ERROR_CAPTION_TEXT = 'Error while executing rename'

    RENAME_COMPLETE_MESSAGE_TEXT = 'Rename completed.'

    READY_MESSAGE_TEXT = 'Ready.'

    ERROR_COLOR = '#ff0000'

    _status_label = None
    _status_progressbar = None

    def __init__(self, parent):
        super().__init__(self.STATUS_BOX_TEXT, parent)

        self._status_label = QLabel(self)
        self._status_progressbar = QProgressBar(self)
        self._status_progressbar.setVisible(False)
        self._status_progressbar.setMinimum(0)

        layout = QHBoxLayout(self)
        layout.addWidget(self._status_label)
        layout.addWidget(self._status_progressbar)

    @pyqtSlot(BAONStatus)
    def show_status(self, status):
        if status.scan_status == BAONStatus.IN_PROGRESS:
            self._show_progress(status.scan_status_extra, self.SCAN_FILES_PROGRESS_TEXT)
        elif status.rename_status == BAONStatus.IN_PROGRESS:
            self._show_progress(status.rename_status_extra, self.RENAME_FILES_PROGRESS_TEXT)
        elif status.execute_status == BAONStatus.IN_PROGRESS:
            self._show_progress(status.execute_status_extra, self.RENAME_PROGRESS_TEXT)
        elif status.scan_status == BAONStatus.ERROR:
            self._show_error(status.scan_status_extra, self.SCAN_FILES_ERROR_CAPTION_TEXT)
        elif status.rules_status == BAONStatus.ERROR:
            self._show_error(status.rules_status_extra, self.RULES_ERROR_CAPTION_TEXT)
        elif status.rename_status == BAONStatus.ERROR:
            self._show_error(status.rename_status_extra, self.RENAME_FILES_ERROR_CAPTION_TEXT)
        elif status.execute_status == BAONStatus.ERROR:
            if isinstance(status.execute_status_extra, MakeRenamePlanError):
                self._show_error(status.execute_status_extra, self.PLANNING_RENAME_ERROR_CAPTION_TEXT)
            else:
                self._show_error(status.execute_status_extra, self.RENAME_ERROR_CAPTION_TEXT)
        elif status.scan_status == BAONStatus.NOT_AVAILABLE:
            self._show_message(self.BASE_PATH_REQUIRED_MESSAGE_TEXT)
        elif status.rename_status == BAONStatus.NOT_AVAILABLE:
            self._show_message(self.NO_FILES_TO_RENAME_MESSAGE_TEXT)
        elif status.execute_status == BAONStatus.NOT_AVAILABLE:
            self._show_message(self.NO_FILES_RENAMED_MESSAGE_TEXT)
        elif status.execute_status == BAONStatus.WAITING_FOR_USER:
            self._show_message(self.READY_TO_RENAME_MESSAGE_TEXT)
        elif status.execute_status == BAONStatus.AVAILABLE:
            self._show_message(self.RENAME_COMPLETE_MESSAGE_TEXT)
        else:
            self._show_message(self.READY_MESSAGE_TEXT)

    def _show_message(self, format_string, *args, **kwargs):
        self._show_raw_message(format_string.format(*args, **kwargs))

    def _show_progress(self, progress, text):
        self._show_raw_message(text, progress=progress)

    def _show_error(self, error, caption=None):
        text = str(error)
        if caption is not None:
            text = caption + ': ' + text

        self._show_raw_message(text, is_error=True)

    def _show_raw_message(self, text, is_error=False, progress=None):
        self._status_label.setText(text)
        self._status_label.setStyleSheet("QLabel {{ color: {0} }}".format(self.ERROR_COLOR) if is_error else "")

        self._status_progressbar.setVisible(progress is not None)

        if progress is not None:
            if progress.is_indeterminate():
                self._status_progressbar.setMaximum(0)
            else:
                self._status_progressbar.setMaximum(progress.total)
                self._status_progressbar.setValue(progress.done)
Exemple #19
0
class QuadStatusBar(QHBoxLayout):
    positionChanged = pyqtSignal(int, int, int) # x,y,z
    
    def __init__(self, parent=None ):
        QHBoxLayout.__init__(self, parent)
        self.setContentsMargins(0,4,0,0)
        self.setSpacing(0)
        self.timeControlFontSize = 12

    def showXYCoordinates(self):
        self.zLabel.setHidden(True)
        self.zSpinBox.setHidden(True)
        
    def showXYZCoordinates(self):
        self.zLabel.setHidden(False)
        self.zSpinBox.setHidden(False)
    
    def hideTimeSlider(self,flag):
        self.timeSlider.setHidden(flag)
        self.timeEndButton.setHidden(flag)
        self.timeStartButton.setHidden(flag)

    def setToolTipTimeButtonsCrop(self,croppingFlag=False):
        if croppingFlag==True:
            self.timeStartButton.setToolTip("Set the time coordinate to the beginning of the current crop.")
            self.timeEndButton.setToolTip("Set the time coordinate to the end of the current crop.")
            self.timePreviousButton.setToolTip("Set the time coordinate to the previous time frame.")
            self.timeNextButton.setToolTip("Set the time coordinate to the next time frame.")
        else:
            self.timeStartButton.setToolTip("Set the time coordinate to the beginning of the current dataset.")
            self.timeEndButton.setToolTip("Set the time coordinate to the end of the current dataset.")
            self.timePreviousButton.setToolTip("Set the time coordinate to the previous time frame.")
            self.timeNextButton.setToolTip("Set the time coordinate to the next time frame.")

    def setToolTipTimeSliderCrop(self,croppingFlag=False):
        if croppingFlag==True:
            self.timeSlider.setToolTip("Choose the time coordinate of the current crop.")
        else:
            self.timeSlider.setToolTip("Choose the time coordinate of the current dataset.")

    def createQuadViewStatusBar(self,
                                xbackgroundColor, xforegroundColor,
                                ybackgroundColor, yforegroundColor,
                                zbackgroundColor, zforegroundColor):
        self.xLabel, self.xSpinBox = _get_pos_widget('X',
                                                     xbackgroundColor,
                                                     xforegroundColor)
        self.yLabel, self.ySpinBox = _get_pos_widget('Y',
                                                     ybackgroundColor,
                                                     yforegroundColor)
        self.zLabel, self.zSpinBox = _get_pos_widget('Z',
                                                     zbackgroundColor,
                                                     zforegroundColor)
        
        self.xSpinBox.delayedValueChanged.connect( partial(self._handlePositionBoxValueChanged, 'x') )
        self.ySpinBox.delayedValueChanged.connect( partial(self._handlePositionBoxValueChanged, 'y') )
        self.zSpinBox.delayedValueChanged.connect( partial(self._handlePositionBoxValueChanged, 'z') )

        self.addWidget(self.xLabel)
        self.addWidget(self.xSpinBox)
        self.addWidget(self.yLabel)
        self.addWidget(self.ySpinBox)
        self.addWidget(self.zLabel)
        self.addWidget(self.zSpinBox)

        self.addSpacing(10)

        self.busyIndicator = QProgressBar()
        self.busyIndicator.setMaximumWidth(200)
        self.busyIndicator.setMaximum(0)
        self.busyIndicator.setMinimum(0)
        self.busyIndicator.setVisible(False)
        self.busyIndicator.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.addWidget( self.busyIndicator )
        self.setStretchFactor(self.busyIndicator, 1)

        self.addStretch()
        self.addSpacing(10)

        self.positionCheckBox = QCheckBox()
        self.positionCheckBox.setChecked(False)
        self.positionCheckBox.setCheckable(True)
        self.positionCheckBox.setText("Position")
        self.addWidget(self.positionCheckBox)

        self.addSpacing(20)

        self.timeSpinBox = DelayedSpinBox(750)

        self.timeStartButton = QPushButton("|<")
        self.addWidget(self.timeStartButton)
        self.timeStartButton.clicked.connect(self._onTimeStartButtonClicked)

        self.timePreviousButton = QPushButton("<")
        self.addWidget(self.timePreviousButton)
        self.timePreviousButton.clicked.connect(self._onTimePreviousButtonClicked)
        self.timePreviousButton.setFixedWidth(4*self.timeControlFontSize)

        self.timeSlider = QSlider(Qt.Horizontal)
        self.timeSlider.setMinimumWidth(10)
        self.timeSlider.setMaximumWidth(200)
        self.setToolTipTimeSliderCrop()
        self.addWidget(self.timeSlider)
        self.timeSlider.valueChanged.connect(self._onTimeSliderChanged)

        self.timeNextButton = QPushButton(">")
        self.addWidget(self.timeNextButton)
        self.timeNextButton.clicked.connect(self._onTimeNextButtonClicked)
        self.timeNextButton.setFixedWidth(4*self.timeControlFontSize)

        self.timeEndButton = QPushButton(">|")
        self.timeEndButton.setFixedWidth(4*self.timeControlFontSize)

        self.timeStartButton.setFixedWidth(4*self.timeControlFontSize)
        
        self.setToolTipTimeButtonsCrop()
        self.addWidget(self.timeEndButton)
        self.timeEndButton.clicked.connect(self._onTimeEndButtonClicked)

        self.timeLabel = QLabel("       Time:")
        self.addWidget(self.timeLabel)

        timeControlFont = self.timeSpinBox.font()
        if self.timeControlFontSize > timeControlFont.pointSize():
            timeControlFont.setPixelSize(2*self.timeControlFontSize)
            self.timeStartButton.setFont(timeControlFont)
            self.timeEndButton.setFont(timeControlFont)
            self.timeLabel.setFont(timeControlFont)
            self.timeSpinBox.setFont(timeControlFont)

        self.addWidget(self.timeSpinBox)
        self.timeSpinBox.delayedValueChanged.connect(self._onTimeSpinBoxChanged)

    def _onTimeStartButtonClicked(self):
        self.timeSpinBox.setValue(self.parent().parent().parent().editor.cropModel.get_roi_t()[0])

    def _onTimeEndButtonClicked(self):
        self.timeSpinBox.setValue(self.parent().parent().parent().editor.cropModel.get_roi_t()[1])

    def _onTimePreviousButtonClicked(self):
        self.timeSpinBox.setValue(self.timeSpinBox.value()-1)

    def _onTimeNextButtonClicked(self):
        self.timeSpinBox.setValue(self.timeSpinBox.value()+1)

    def _onTimeSpinBoxChanged(self):
        editor = self.parent().parent().parent().editor
        cropModel = editor.cropModel
        minValueT = cropModel.get_roi_t()[0]
        maxValueT = cropModel.get_roi_t()[1]

        if cropModel.get_scroll_time_outside_crop():
            if minValueT > self.timeSpinBox.value() or maxValueT < self.timeSpinBox.value():
                for imgView in editor.imageViews:
                    imgView._croppingMarkers._shading_item.set_paint_full_frame(True)
            else:
                for imgView in editor.imageViews:
                    imgView._croppingMarkers._shading_item.set_paint_full_frame(False)
            self.timeSlider.setValue(self.timeSpinBox.value())
        else:
            for imgView in editor.imageViews:
                imgView._croppingMarkers._shading_item.set_paint_full_frame(False)
            if minValueT > self.timeSpinBox.value():
                self.timeSlider.setValue(minValueT)
            elif maxValueT < self.timeSpinBox.value():
                self.timeSlider.setValue(maxValueT)
            elif minValueT <= self.timeSpinBox.value() and self.timeSpinBox.value() <= maxValueT:
                self.timeSlider.setValue(self.timeSpinBox.value())

    def _onTimeSliderChanged(self):
        cropModel = self.parent().parent().parent().editor.cropModel
        minValueT = cropModel.get_roi_t()[0]
        maxValueT = cropModel.get_roi_t()[1]

        if cropModel.get_scroll_time_outside_crop():
            self.timeSpinBox.setValue(self.timeSlider.value())
        else:
            if minValueT > self.timeSlider.value():
                self.timeSpinBox.setValue(minValueT)
                self.timeSlider.setValue(minValueT)
            elif self.timeSlider.value() > maxValueT:
                self.timeSpinBox.setValue(maxValueT)
                self.timeSlider.setValue(maxValueT)
            elif minValueT <= self.timeSlider.value() and self.timeSlider.value() <= maxValueT:
                self.timeSpinBox.setValue(self.timeSlider.value())

    def _handlePositionBoxValueChanged(self, axis, value):
        new_position = [self.xSpinBox.value(), self.ySpinBox.value(), self.zSpinBox.value()]
        changed_axis = ord(axis) - ord('x')
        new_position[changed_axis] = value
        self.positionChanged.emit(*new_position)

    def updateShape5D(self, shape5D):
        self.timeSpinBox.setMaximum(shape5D[0]-1)
        self.xSpinBox.setMaximum(shape5D[1]-1)
        self.ySpinBox.setMaximum(shape5D[2]-1)
        self.zSpinBox.setMaximum(shape5D[3]-1)

    def updateShape5Dcropped(self, shape5DcropMin, shape5Dmax):
        self.timeSpinBox.setMaximum(shape5Dmax[0]-1)
        self.xSpinBox.setMaximum(shape5Dmax[1]-1)
        self.ySpinBox.setMaximum(shape5Dmax[2]-1)
        self.zSpinBox.setMaximum(shape5Dmax[3]-1)
        self.timeSlider.setMaximum(shape5Dmax[0]-1)

        self.timeSpinBox.setValue(shape5DcropMin[0])
        self.xSpinBox.setValue(shape5DcropMin[1])
        self.ySpinBox.setValue(shape5DcropMin[2])
        self.zSpinBox.setValue(shape5DcropMin[3])
        self.timeSlider.setValue(shape5DcropMin[0])

    def setMouseCoords(self, x, y, z):
        self.xSpinBox.setValueWithoutSignal(x)
        self.ySpinBox.setValueWithoutSignal(y)
        self.zSpinBox.setValueWithoutSignal(z)
Exemple #20
0
class SearchWidget(QFrame):
    """Widget, appeared, when Ctrl+F pressed.
    Has different forms for different search modes
    """

    Normal = 'normal'
    Good = 'good'
    Bad = 'bad'
    Incorrect = 'incorrect'

    visibilityChanged = pyqtSignal(bool)
    """
    visibilityChanged(visible)
    
    **Signal** emitted, when widget has been shown or hidden
    """  # pylint: disable=W0105

    searchInDirectoryStartPressed = pyqtSignal(type(re.compile('')), list,
                                               unicode)
    """
    searchInDirectoryStartPressed(regEx, mask, path)
    
    **Signal** emitted, when 'search in directory' button had been pressed
    """  # pylint: disable=W0105

    searchInDirectoryStopPressed = pyqtSignal()
    """
    searchInDirectoryStopPressed()
    
    **Signal** emitted, when 'stop search in directory' button had been pressed
    """  # pylint: disable=W0105

    replaceCheckedStartPressed = pyqtSignal(unicode)
    """
    replaceCheckedStartPressed(replText)
    
    **Signal** emitted, when 'replace checked' button had been pressed
    """  # pylint: disable=W0105

    replaceCheckedStopPressed = pyqtSignal()
    """
    replaceCheckedStartPressed()
    
    **Signal** emitted, when 'stop replacing checked' button had been pressed
    """  # pylint: disable=W0105

    searchRegExpChanged = pyqtSignal(type(re.compile('')))
    """
    searchRegExpValidStateChanged(regEx)
    
    **Signal** emitted, when search regexp has been changed.
    If reg exp is invalid - regEx object contains empty pattern
    """  # pylint: disable=W0105

    searchNext = pyqtSignal()
    """
    searchNext()
    
    **Signal** emitted, when 'Search Next' had been pressed
    """  # pylint: disable=W0105

    searchPrevious = pyqtSignal()
    """
    searchPrevious()
    
    **Signal** emitted, when 'Search Previous' had been pressed
    """  # pylint: disable=W0105

    replaceFileOne = pyqtSignal(unicode)
    """
    replaceFileOne(replText)
    
    **Signal** emitted, when 'Replace' had been pressed
    """  # pylint: disable=W0105

    replaceFileAll = pyqtSignal(unicode)
    """
    replaceFileAll(replText)
    
    **Signal** emitted, when 'Replace All' had been pressed
    """  # pylint: disable=W0105

    def __init__(self, plugin):
        QFrame.__init__(self, core.workspace())
        self._mode = None
        self.plugin = plugin
        from PyQt4 import uic  # lazy import for better startup performance
        uic.loadUi(os.path.join(os.path.dirname(__file__), 'SearchWidget.ui'),
                   self)

        self.cbSearch.setCompleter(None)
        self.cbReplace.setCompleter(None)
        self.cbMask.setCompleter(None)

        self.fsModel = QDirModel(self.cbPath.lineEdit())
        self.fsModel.setFilter(QDir.AllDirs | QDir.NoDotAndDotDot)
        self.cbPath.lineEdit().setCompleter(
            QCompleter(self.fsModel, self.cbPath.lineEdit()))
        # TODO QDirModel is deprecated but QCompleter does not yet handle
        # QFileSystemodel - please update when possible."""
        self.cbSearch.setCompleter(None)
        self.pbSearchStop.setVisible(False)
        self.pbReplaceCheckedStop.setVisible(False)

        self._progress = QProgressBar(self)
        self._progress.setAlignment(Qt.AlignCenter)
        self._progress.setToolTip(self.tr("Search in progress..."))
        self._progress.setMaximumSize(QSize(80, 16))
        core.mainWindow().statusBar().insertPermanentWidget(1, self._progress)
        self._progress.setVisible(False)

        # cd up action
        self.tbCdUp = QToolButton(self.cbPath.lineEdit())
        self.tbCdUp.setIcon(QIcon(":/enkiicons/go-up.png"))
        self.tbCdUp.setCursor(Qt.ArrowCursor)
        self.tbCdUp.installEventFilter(self)  # for drawing button

        self.cbSearch.installEventFilter(
            self)  # for catching Tab and Shift+Tab
        self.cbReplace.installEventFilter(
            self)  # for catching Tab and Shift+Tab
        self.cbPath.installEventFilter(self)  # for catching Tab and Shift+Tab
        self.cbMask.installEventFilter(self)  # for catching Tab and Shift+Tab

        self._closeShortcut = QShortcut(QKeySequence("Esc"), self)
        self._closeShortcut.setContext(Qt.WidgetWithChildrenShortcut)
        self._closeShortcut.activated.connect(self.hide)

        # connections
        self.cbSearch.lineEdit().textChanged.connect(
            self._onSearchRegExpChanged)

        self.cbSearch.lineEdit().returnPressed.connect(self._onReturnPressed)
        self.cbReplace.lineEdit().returnPressed.connect(self._onReturnPressed)
        self.cbPath.lineEdit().returnPressed.connect(self._onReturnPressed)
        self.cbMask.lineEdit().returnPressed.connect(self._onReturnPressed)

        self.cbRegularExpression.stateChanged.connect(
            self._onSearchRegExpChanged)
        self.cbCaseSensitive.stateChanged.connect(self._onSearchRegExpChanged)
        self.cbWholeWord.stateChanged.connect(self._onSearchRegExpChanged)

        self.tbCdUp.clicked.connect(self._onCdUpPressed)

        self.pbNext.pressed.connect(self.searchNext)
        self.pbPrevious.pressed.connect(self.searchPrevious)
        self.pbSearchStop.pressed.connect(self.searchInDirectoryStopPressed)
        self.pbReplaceCheckedStop.pressed.connect(
            self.replaceCheckedStopPressed)

        core.mainWindow().hideAllWindows.connect(self.hide)
        core.workspace().escPressed.connect(self.hide)

        core.workspace().currentDocumentChanged.connect( \
                    lambda old, new: self.setVisible(self.isVisible() and new is not None))

    def show(self):
        """Reimplemented function. Sends signal
        """
        super(SearchWidget, self).show()
        self.visibilityChanged.emit(self.isVisible())

    def hide(self):
        """Reimplemented function.
        Sends signal, returns focus to workspace
        """
        super(SearchWidget, self).hide()
        core.workspace().focusCurrentDocument()
        self.visibilityChanged.emit(self.isVisible())

    def setVisible(self, visible):
        """Reimplemented function. Sends signal
        """
        super(SearchWidget, self).setVisible(visible)
        self.visibilityChanged.emit(self.isVisible())

    def _regExEscape(self, text):
        """Improved version of re.escape()
        Doesn't escape space, comma, underscore.
        Escapes \n and \t
        """
        text = re.escape(text)
        # re.escape escapes space, comma, underscore, but, it is not necessary and makes text not readable
        for symbol in (' ,_=\'"/:@#%&'):
            text = text.replace('\\' + symbol, symbol)

        text = text.replace('\\\n', '\\n')
        text = text.replace('\\\t', '\\t')

        return text

    def _makeEscapeSeqsVisible(self, text):
        """Replace invisible \n and \t with escape sequences
        """
        text = text.replace('\\', '\\\\')
        text = text.replace('\t', '\\t')
        text = text.replace('\n', '\\n')
        return text

    def setMode(self, mode):
        """Change search mode.
        i.e. from "Search file" to "Replace directory"
        """
        if self._mode == mode and self.isVisible():
            if core.workspace().currentDocument() is not None and \
               not core.workspace().currentDocument().hasFocus():
                self.cbSearch.lineEdit().selectAll()
                self.cbSearch.setFocus()

        self._mode = mode

        # Set Search and Replace text
        document = core.workspace().currentDocument()
        if document is not None and \
           document.hasFocus() and \
           document.qutepart.selectedText:
            searchText = document.qutepart.selectedText

            self.cbReplace.setEditText(self._makeEscapeSeqsVisible(searchText))

            if self.cbRegularExpression.checkState() == Qt.Checked:
                searchText = self._regExEscape(searchText)
            self.cbSearch.setEditText(searchText)

        if not self.cbReplace.lineEdit().text() and \
            self.cbSearch.lineEdit().text() and \
            not self.cbRegularExpression.checkState() == Qt.Checked:
            replaceText = self.cbSearch.lineEdit().text().replace('\\', '\\\\')
            self.cbReplace.setEditText(replaceText)

        # Move focus to Search edit
        self.cbSearch.setFocus()
        self.cbSearch.lineEdit().selectAll()

        # Set search path
        if mode & MODE_FLAG_DIRECTORY and \
           not (self.isVisible() and self.cbPath.isVisible()):
            try:
                searchPath = os.path.abspath(unicode(os.path.curdir))
                self.cbPath.setEditText(searchPath)
            except OSError:  # current directory might have been deleted
                pass

        # Set widgets visibility flag according to state
        widgets = (self.wSearch, self.pbPrevious, self.pbNext, self.pbSearch, self.wReplace, self.wPath, \
                   self.pbReplace, self.pbReplaceAll, self.pbReplaceChecked, self.wOptions, self.wMask)
        #                         wSear  pbPrev pbNext pbSear wRepl  wPath  pbRep  pbRAll pbRCHK wOpti wMask
        visible = \
        {MODE_SEARCH :               (1,     1,     1,     0,     0,     0,     0,     1,     1,    1,    0,),
         MODE_REPLACE:               (1,     1,     1,     0,     1,     0,     1,     1,     0,    1,    0,),
         MODE_SEARCH_DIRECTORY:      (1,     0,     0,     1,     0,     1,     0,     0,     0,    1,    1,),
         MODE_REPLACE_DIRECTORY:     (1,     0,     0,     1,     1,     1,     0,     0,     1,    1,    1,),
         MODE_SEARCH_OPENED_FILES:   (1,     0,     0,     1,     0,     0,     0,     0,     0,    1,    1,),
         MODE_REPLACE_OPENED_FILES:  (1,     0,     0,     1,     1,     0,     0,     0,     1,    1,    1,)}

        for i, widget in enumerate(widgets):
            widget.setVisible(visible[mode][i])

        # Search next button text
        if mode == MODE_REPLACE:
            self.pbNext.setText('Next')
        else:
            self.pbNext.setText(u'Next↵')

        # Finaly show all with valid size
        self.show()  # show before updating widgets and labels
        self._updateLabels()
        self._updateWidgets()

    def eventFilter(self, object_, event):
        """ Event filter for mode switch tool button
        Draws icons in the search and path lineEdits
        """
        if event.type(
        ) == QEvent.Paint and object_ is self.tbCdUp:  # draw CdUp button in search path QLineEdit
            toolButton = object_
            lineEdit = self.cbPath.lineEdit()
            lineEdit.setContentsMargins(lineEdit.height(), 0, 0, 0)

            height = lineEdit.height()
            availableRect = QRect(0, 0, height, height)

            if toolButton.rect() != availableRect:
                toolButton.setGeometry(availableRect)

            painter = QPainter(toolButton)
            toolButton.icon().paint(painter, availableRect)

            return True

        elif event.type(
        ) == QEvent.KeyPress:  # Tab and Shift+Tab in QLineEdits

            if event.key() == Qt.Key_Tab:
                self._moveFocus(1)
                return True
            elif event.key() == Qt.Key_Backtab:
                self._moveFocus(-1)
                return True

        return QFrame.eventFilter(self, object_, event)

    def _onReturnPressed(self):
        """Return or Enter pressed on widget.
        Search next or Replace next
        """
        if self.pbReplace.isVisible():
            self.pbReplace.click()
        elif self.pbNext.isVisible():
            self.pbNext.click()
        elif self.pbSearch.isVisible():
            self.pbSearch.click()
        elif self.pbSearchStop.isVisible():
            self.pbSearchStop.click()

    def _moveFocus(self, step):
        """Move focus forward or backward according to step.
        Standard Qt Keyboard focus algorithm doesn't allow circular navigation
        """
        allFocusableWidgets = (self.cbSearch, self.cbReplace, self.cbPath,
                               self.cbMask)
        visibleWidgets = [widget for widget in allFocusableWidgets \
                                    if widget.isVisible()]

        try:
            focusedIndex = visibleWidgets.index(QApplication.focusWidget())
        except ValueError:
            print >> sys.stderr, 'Invalid focused widget in Search Widget'
            return

        nextFocusedIndex = (focusedIndex + step) % len(visibleWidgets)

        visibleWidgets[nextFocusedIndex].setFocus()
        visibleWidgets[nextFocusedIndex].lineEdit().selectAll()

    def _updateLabels(self):
        """Update 'Search' 'Replace' 'Path' labels geometry
        """
        width = 0

        if self.lSearch.isVisible():
            width = max(width, self.lSearch.minimumSizeHint().width())

        if self.lReplace.isVisible():
            width = max(width, self.lReplace.minimumSizeHint().width())

        if self.lPath.isVisible():
            width = max(width, self.lPath.minimumSizeHint().width())

        self.lSearch.setMinimumWidth(width)
        self.lReplace.setMinimumWidth(width)
        self.lPath.setMinimumWidth(width)

    def _updateWidgets(self):
        """Update geometry of widgets with buttons
        """
        width = 0

        if self.wSearchRight.isVisible():
            width = max(width, self.wSearchRight.minimumSizeHint().width())

        if self.wReplaceRight.isVisible():
            width = max(width, self.wReplaceRight.minimumSizeHint().width())

        if self.wPathRight.isVisible():
            width = max(width, self.wPathRight.minimumSizeHint().width())

        self.wSearchRight.setMinimumWidth(width)
        self.wReplaceRight.setMinimumWidth(width)
        self.wPathRight.setMinimumWidth(width)

    def updateComboBoxes(self):
        """Update comboboxes with last used texts
        """
        searchText = self.cbSearch.currentText()
        replaceText = self.cbReplace.currentText()
        maskText = self.cbMask.currentText()

        # search
        if searchText:
            index = self.cbSearch.findText(searchText)

            if index == -1:
                self.cbSearch.addItem(searchText)

        # replace
        if replaceText:
            index = self.cbReplace.findText(replaceText)

            if index == -1:
                self.cbReplace.addItem(replaceText)

        # mask
        if maskText:
            index = self.cbMask.findText(maskText)

            if index == -1:
                self.cbMask.addItem(maskText)

    def _searchPatternTextAndFlags(self):
        """Get search pattern and flags
        """
        pattern = self.cbSearch.currentText()

        pattern = pattern.replace(
            u'\u2029',
            '\n')  # replace unicode paragraph separator with habitual \n

        if not self.cbRegularExpression.checkState() == Qt.Checked:
            pattern = re.escape(pattern)

        if self.cbWholeWord.checkState() == Qt.Checked:
            pattern = r'\b' + pattern + r'\b'

        flags = 0
        if not self.cbCaseSensitive.checkState() == Qt.Checked:
            flags = re.IGNORECASE
        return pattern, flags

    def getRegExp(self):
        """Read search parameters from controls and present it as a regular expression
        """
        pattern, flags = self._searchPatternTextAndFlags()
        return re.compile(pattern, flags)

    def isSearchRegExpValid(self):
        """Try to compile search pattern to check if it is valid
        Returns bool result and text error
        """
        pattern, flags = self._searchPatternTextAndFlags()
        try:
            re.compile(pattern, flags)
        except re.error, ex:
            return False, unicode(ex)

        return True, None
Exemple #21
0
class Base(QMainWindow):
    """
    Esta clase sirve de base para todos aquellos 
    formularios que siguen el estandar de dos pestañas, una para navegación
    y otra para edición
    """

    orientation = QPrinter.Portrait
    pageSize = QPrinter.Letter
    web = ""

    def __init__(self, parent, own_toolbar=False):
        """
        @param parent: El widget padre de esta ventana
        @param own_toolbar: Si este widget dibujara su toolbar en el padre o en el mismo
        @type parent: QWidget
        @type own_toolbar: bool
        """
        super(Base, self).__init__(parent)
        self.user = user.LoggedUser
        self._status = True
        self.parentWindow = parent
        self.own_toolbar = own_toolbar

        self.database = QSqlDatabase.database()
        """
        @type: QSqlDatabase
        @ivar: La base de datos a la cual se conecta el sistema
        """

        self.mapper = QDataWidgetMapper(self)
        u"""
        @type: QDataWidgetMapper
        @ivar: El mapper que se encarga de asignar los 
        datos del modelo de navegación a los distintos widgets
        """

        self.printProgressBar = QProgressBar(self)
        self.webview = QWebView()
        """
        @ivar: EL objeto webview usado para cargar los reportes
        @type: QWebView
        """
        self.loaded = False
        """
        @ivar: Si se pudo o no cargar un reporte
        @type: bool
        """

        self.startUi()

        self.editmodel = None
        self.printer = QPrinter()

        self._status = False

    def startUi(self):
        """
        Iniciar todos los elementos graficos
        """
        self.setupUi(self)
        if not self.own_toolbar:
            self.parent().addToolBar(self.toolBar)
            self.removeToolBar(self.toolBar)

        settings = QSettings()
        self.restoreState(settings.value(self.windowTitle() + "/State").toByteArray())

        """
        @ivar: El MainWindow al que pertenece este widget
        """
        self.createActions()

        self.printProgressBar.setVisible(False)

        _tab1shortcut = QShortcut(QKeySequence("Ctrl+1"), self, functools.partial(self.tabWidget.setCurrentIndex, 0))
        _tab2shortcut = QShortcut(QKeySequence("Ctrl+2"), self, functools.partial(self.tabWidget.setCurrentIndex, 1))

        self.mapper.currentIndexChanged[int].connect(self.updateDetailFilter)

        self.actionCut.setVisible(False)
        self.actionPaste.setVisible(False)
        self.actionCopy.setVisible(False)

    def closeEvent(self, event):
        u"""
        Guardar el tamaño, la posición en la pantalla y la posición de
         la barra de tareas
        Preguntar si realmente se desea cerrar la pestaña cuando
         se esta en modo edición
        """
        if not self.status:
            if (
                not QMessageBox.question(
                    self, qApp.organizationName(), u"¿Está seguro que desea salir?", QMessageBox.Yes | QMessageBox.No
                )
                == QMessageBox.Yes
            ):
                event.ignore()

        # Guardar el tamaño y la posición
        settings = QSettings()
        settings.setValue(self.windowTitle() + "/Geometry", self.saveGeometry())

        if not self.own_toolbar:
            self.parent().mdiArea().parent().parent().removeToolBar(self.toolBar)

    def editCell(self):
        """
        Editar la celda actualmente seleccionada de self.tableedit
        """
        self.tabledetails.edit(self.tabledetails.selectionModel().currentIndex())

    @pyqtSlot(QDateTime)
    @if_edit_model
    def on_dtPicker_dateTimeChanged(self, datetime):
        """
        Cambiar el tipo de cambio del modelo de edición si cambia la fecha
        @param datetime: La fecha contenida en self.dtPicker
        @type datetime: QDateTime
        """
        query = QSqlQuery()
        try:
            if not self.database.isOpen():
                if not self.database.open():
                    raise Exception(
                        "No se pudo conectar a la base de " + "datos para recuperar los tipos " + "de cambio"
                    )

            q = """
                SELECT idtc, tasa
                FROM tiposcambio
                WHERE fecha = %s
                LIMIT 1
            """ % datetime.toString(
                "yyyyMMdd"
            )

            if not query.exec_(q):

                raise UserWarning("No se pudieron recuperar los tipos de " + "cambio")
            if not query.size() == 1:
                logging.critical(u"La consulta para obtener tipos de " + "cambio no devolvio exactamente un valor")
                raise UserWarning(u"Hubo un error al obtener los tipos " + "de cambio")

            query.first()
            self.editmodel.exchangeRateId = query.value(0).toInt()[0]
            self.editmodel.exchangeRate = Decimal(query.value(1).toString())

            # self.editmodel.setData( self.editmodel.index( 0, 0 ), self.editmodel.index( 0, 0 ).data() )

            self.editmodel.datetime = datetime
        except UserWarning as inst:
            QMessageBox.critical(self, qApp.organizationName(), unicode(inst))
            self.dtPicker.setDateTime(self.editmodel.datetime)
            logging.error(inst)
            logging.error(query.lastError().text())
        except Exception as inst:
            QMessageBox.critical(self, qApp.organizationName(), u"Hubo un error al obtener los tipos de" + " cambio")
            logging.critical(query.lastError().text())
            logging.critical(inst)
            self.dtPicker.setDateTime(self.editmodel.datetime)

    def navigate(self, to):
        """
        Esta funcion se encarga de navegar entro los distintos documentos
        @param to: es una string que puede tomar los valores 'next' 'previous'
         'first' 'last'
        """
        if self.mapper.currentIndex != -1:
            row = self.mapper.currentIndex()
            if to == "next":
                row += 1
                if row >= self.navproxymodel.rowCount():
                    row = self.navproxymodel.rowCount() - 1
                self.mapper.setCurrentIndex(row)
            elif to == "previous":
                if row <= 1:
                    row = 0
                else:
                    row = row - 1
                self.mapper.setCurrentIndex(row)
            elif to == "first":
                self.mapper.toFirst()
            elif to == "last":
                self.mapper.toLast()
        else:
            self.mapper.toLast()()

        if self.tabledetails != None:
            self.tabledetails.resizeColumnsToContents()
            self.tabledetails.horizontalHeader().setStretchLastSection(True)
        self.tablenavigation.selectRow(self.mapper.currentIndex())

    def updateDetailFilter(self, _index):
        """
        Esta función se debe implementar en los formularios para que al 
        navegar se actualize el filtro de la tabla detalles
        @param index: Este es el indice del mapper en el que actualmente 
        se encuentra navegando
        @type index: int 
        """
        QMessageBox.information(self, qApp.organizationName(), u"Esta parte del sistema no ha " + "sido implementada")
        raise NotImplementedError()

    def loadModels(self):
        """
        Esta función se ejecuta en el constructor del formulario mediante
        un QTimer, carga los formularios por primera vez
        """
        self.updateModels()

        self.navigate("last")
        self.status = True

    def _setStatus(self, stat):
        """
        @param stat:  False = editando, True = navegando
        @type stat: bool
        """
        self._status = stat
        self.setControls(self._status)

    def _getStatus(self):
        """
        esta propiedad cambia entre navegar y editar
        """
        return self._status

    status = property(_getStatus, _setStatus)

    @pyqtSlot(unicode)
    def on_txtSearch_textChanged(self, searchstring):
        """
        Cambiar el filtro para el navigation model
        @param searchstring: Es el contenido por el cual se va a 
        filtrar el modelo de navegación
        @type searchstring: string
        """
        self.navproxymodel.setFilterFixedString(searchstring)

    @pyqtSlot(QModelIndex)
    def on_tablenavigation_doubleClicked(self, index):
        """
        Al hacer doble click en la tabla de navegación el se cambia a la
        pestaña detalles mostrando el documento seleccionado
        @param index: El indice de la tabla en la que se dio doble click
        @type index: QModelIndex 
        """
        self.mapper.setCurrentIndex(index.row())
        self.tabWidget.setCurrentIndex(0)

    @pyqtSlot(QModelIndex)
    def on_tablenavigation_clicked(self, index):
        self.mapper.setCurrentIndex(index.row())

    def save(self, ask=True):
        """
        Guardar el documento actual
        @param ask: Si se deberia o no preguntar al usuario si 
            esta seguro antes de proceder
        @type ask: bool
        """
        if (
            ask == False
            or QMessageBox.question(
                self, qApp.organizationName(), u"¿Esta seguro que desea guardar?", QMessageBox.Yes | QMessageBox.No
            )
            == QMessageBox.Yes
        ):
            if self.editmodel.valid:
                if self.editmodel.save():
                    QMessageBox.information(self, qApp.organizationName(), u"El documento se ha guardado con éxito")
                    self.editmodel = None
                    self.updateModels()
                    self.navigate("last")
                    self.status = True
                else:
                    QMessageBox.critical(self, qApp.organizationName(), "Ha ocurrido un error al guardar el documento")

            else:
                try:
                    QMessageBox.warning(self, qApp.organizationName(), self.editmodel.validError)
                except AttributeError:
                    QMessageBox.warning(
                        self,
                        qApp.organizationName(),
                        u"El documento no puede guardarse" + " ya que la información no esta" + " completa",
                    )

    def setControls(self, unused_status):
        """
        Habilitar o deshabilitar los controles según status
        @param status: 
        @type status: bool
        """
        QMessageBox.information(self, qApp.organizationName(), u"Esta parte del sistema no ha sido implementada")
        raise NotImplementedError()

    def addLine(self):
        """
        añadir una linea a table edit, solo se llama directamente 
        en una ocasion, al comenzar la edicion de un documento
        """
        row = self.editmodel.rowCount()
        self.editmodel.insertRows(row)

    def createAction(self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False, signal="triggered"):
        """
        Crear un objeto acción
        @param text: El texto de la acción
        @type text: string

        @param slot: El slot que se ejecutara cuando se dispare esta acción
        @type slot: callable

        @param shortcut: El acceso directo que tiene asignada esta acción
        @type shortcut: QKeySequence

        @param icon: El icono de esta acción
        @type icon: string

        @param tip: El tooltip que tendra esta acción
        @type tip: string

        @param checkable: Si esta acción es checkable o no
        @type checkable: bool

        @param signal: La señal en la que esta acción ejecutara el slot
        @type signal: string

        @rtype: QAction
        """
        action = QAction(text, self)
        if icon is not None:
            if type(icon) == QIcon:
                action.setIcon(icon)
            else:
                action.setIcon(QIcon(icon))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tip is not None:
            action.setToolTip(tip)
            action.setStatusTip(tip)
        if slot is not None:
            getattr(action, signal).connect(slot)
        if checkable:
            action.setCheckable(True)
        return action

    def newDocument(self):
        """
        Empezar la edición de un nuevo documento
        """
        QMessageBox.information(self, qApp.organizationName(), u"Esta parte del sistema no ha sido implementada")
        raise NotImplementedError()

    def cancel(self):
        """
        Cancelar la edición del nuevo documento
        """
        QMessageBox.information(self, qApp.organizationName(), u"Esta parte del sistema no ha sido implementada")
        raise NotImplementedError()

    @property
    def printIdentifier(self):
        """
        La identificación de este documento para reporte,
         normalmente sera el iddocumento o el ndocimpreso
        @rtype:string
        """
        raise NotImplementedError(u"printIdentifier debe implementarse para " + "poder imprimir")

    def preview(self):
        """
        Muestra el dialogo de vista previa de impresión
        """
        try:
            printer = QPrinter()
            printer.setOrientation(self.orientation)
            printer.setPageSize(self.pageSize)
            web = self.web + self.printIdentifier
            report = reports.frmReportes(web, printer, self)
            report.exec_()
        except NotImplementedError as inst:
            QMessageBox.information(
                self, qApp.organizationName(), u"No se ha implementado la función de impresión para este modulo"
            )
            logging.error(unicode(inst))
        except UserWarning as inst:
            QMessageBox.critical(self, qApp.organizationName(), unicode(inst))
            logging.error(unicode(inst))
        except Exception as inst:
            QMessageBox.critical(self, qApp.organizationName(), "Hubo un error al intentar mostrar su reporte")
            logging.critical(unicode(inst))

    def printDocument(self):
        """
        Imprime el documento actual
        """
        try:

            base = reports.Reports.url

            if base == "":
                raise UserWarning(u"No existe una configuración para el " + "servidor de reportes")

            self.printer.setOrientation(self.orientation)
            self.printer.setPageSize(self.pageSize)

            web = base + self.web + self.printIdentifier + "&uname=" + self.user.user + "&hash=" + self.user.hash
            self.loaded = False

            self.webview.load(QUrl(web))

            self.webview.loadFinished[bool].connect(self.on_webview_loadFinished)
            self.webview.loadProgress[int].connect(self.on_webview_loadProgress)
        except NotImplementedError as inst:
            logging.error(unicode(inst))
            QMessageBox.information(
                self, qApp.organizationName(), u"La función de impresión no se ha " + "implementado para este modulo"
            )
        except UserWarning as inst:
            logging.error(unicode(inst))
            QMessageBox.critical(self, qApp.organizationName(), unicode(inst))
        except Exception as inst:
            logging.critical(unicode(inst))
            QMessageBox.critical(self, qApp.organizationName(), "Hubo un problema al intentar imprimir" + " su reporte")

    def on_webview_loadProgress(self, progress):
        """
        Muestra el progreso de la carga del reporte en un progressBar
        """
        self.printProgressBar.setValue(progress)

    def on_webview_loadFinished(self, status):
        if self.printProgressBar.isVisible():
            self.printProgressBar.hide()
        if not status:
            QMessageBox.critical(self, qApp.organizationName(), "El reporte no se pudo cargar")
            logging.error("No se pudo cargar el reporte")

        self.loaded = True

        printdialog = QPrintDialog(self.printer, self)
        if printdialog.exec_() == QDialog.Accepted:
            self.webview.print_(self.printer)

        del self.webview

    def deleteRow(self):
        """
        Funcion usada para borrar lineas de la tabla
        """
        index = self.tabledetails.currentIndex()

        if not index.isValid():
            return
        row = index.row()

        self.editmodel.removeRows(row, 1)
        self.updateLabels()

    def updateLabels(self):
        """
        Este metodo se llama para actualizar las etiquetas de totales en el
        formulario
        """
        raise NotImplementedError()

    def createActions(self):
        """
        Crea las acciones predefinidas del sistema
        """
        self.actionNew = self.createAction(
            text="Nuevo",
            tip="Crear un nuevo documento",
            icon=QIcon.fromTheme("document-new", QIcon(":/icons/res/document-new.png")),
            shortcut="Ctrl+n",
            slot=self.newDocument,
        )
        self.actionPreview = self.createAction(
            text="Previsualizar",
            tip=u"Vista de impresión del documento",
            icon=QIcon.fromTheme("document-preview", QIcon(":/icons/res/document-preview.png")),
            shortcut="Ctrl+p",
            slot=self.preview,
        )
        self.actionPrint = self.createAction(
            text="Imprimir",
            tip="Imprimir el documento",
            icon=QIcon.fromTheme("document-print", QIcon(":/icons/res/document-print.png")),
            slot=self.printDocument,
        )
        self.actionSave = self.createAction(
            text="Guardar",
            tip="Guardar el documento",
            icon=QIcon.fromTheme("document-save", QIcon(":/icons/res/document-save.png")),
            shortcut="Ctrl+g",
            slot=self.save,
        )
        self.actionCancel = self.createAction(
            text="Cancelar",
            tip=u"Cancelar la creación del nuevo documento",
            icon=QIcon.fromTheme("dialog-cancel", QIcon(":/icons/res/dialog-cancel.png")),
            shortcut="Esc",
            slot=self.cancel,
        )

        # edicion, TODO: QUE FUNCIONEN ESTAS ACCIONES
        self.actionCopy = self.createAction(
            text="Copiar", icon=QIcon.fromTheme("edit-copy", QIcon(":/icons/res/edit-copy.png")), shortcut="Ctrl+c"
        )
        self.actionCut = self.createAction(
            text="Cortar", icon=QIcon.fromTheme("edit-cut", QIcon(":/icons/res/edit-cut.png")), shortcut="Ctrl+x"
        )
        self.actionPaste = self.createAction(text="Pegar", icon=":/icons/res/edit-paste.png", shortcut="Ctrl+v")

        # navegación
        self.actionGoFirst = self.createAction(
            text="Primer documento",
            tip="Ir al primer documento",
            icon=QIcon.fromTheme("go-first", QIcon(":/icons/res/go-first.png")),
            slot=functools.partial(self.navigate, "first"),
        )
        self.actionGoPrevious = self.createAction(
            text="Documento anterior",
            tip="Ir al documento anterior",
            icon=QIcon.fromTheme("go-previous", QIcon(":/icons/res/go-previous.png")),
            slot=functools.partial(self.navigate, "previous"),
        )
        self.actionGoLast = self.createAction(
            text="Ultimo documento",
            tip="Ir al ultimo documento",
            icon=QIcon.fromTheme("go-last", QIcon(":/icons/res/go-last.png")),
            slot=functools.partial(self.navigate, "last"),
        )
        self.actionGoNext = self.createAction(
            text="Documento siguiente",
            tip="Ir al siguiente documento",
            icon=QIcon.fromTheme("go-next", QIcon(":/icons/res/go-next.png")),
            slot=functools.partial(self.navigate, "next"),
        )

        self.actionDeleteRow = self.createAction(
            text="Borrar la fila",
            icon=QIcon.fromTheme("edit-delete", QIcon(":/icons/res/edit-delete.png")),
            slot=self.deleteRow,
        )

        self.addActionsToToolBar()

    def addActionsToToolBar(self):
        """
        Añade las acciones predefinidas a la barra de tareas
        """
        self.toolBar.addActions(
            [self.actionNew, self.actionPreview, self.actionPrint, self.actionSave, self.actionCancel]
        )
        self.toolBar.addSeparator()

        self.toolBar.addActions(
            [self.actionGoFirst, self.actionGoPrevious, self.actionGoLast, self.actionGoNext, self.actionGoLast]
        )

    @pyqtSlot()
    @if_edit_model
    def on_txtObservations_textChanged(self):
        """
        Asignar las observaciones al editmodel
        """
        self.editmodel.observations = self.txtObservations.toPlainText().strip()
Exemple #22
0
class LDSControls(QFrame):
        
    STATIC_IMG = ('error_static.png','linz_static.png','busy_static.png','clean_static.png')
    ANIM_IMG   = ('error.gif','linz.gif','layer.gif','clean.gif')
    
    IMG_SPEED  = 100
    IMG_WIDTH  = 64
    IMG_HEIGHT = 64
    
    MAX_WD = 450
    
    GD_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../../bin/gdal/gdal-data'))
    STATUS = LU.enum('ERROR','IDLE','BUSY','CLEAN')
    
    def __init__(self,parent):
        super(LDSControls, self).__init__()
        self.parent = parent
        self.initConf()
        self.initEPSG()
        self.initUI()
        
    def initConf(self):
        '''Read files in conf dir ending in conf'''
        self.cflist = ConfigInitialiser.getConfFiles()
        #self.imgset = self.STATIC_IMG if ConfigWrapper().readDSProperty('Misc','indicator')=='static' else self.ANIM_IMG
        #self.imgset = self.STATIC_IMG if self.parent.confconn.tp.src.confwrap.readDSProperty('Misc','indicator')=='static' else self.ANIM_IMG
        sep = self.parent.confconn.reg.openEndPoint(self.parent.confconn.SRCNAME,self.parent.confconn.uconf)
        self.imgset = self.STATIC_IMG if sep.confwrap.readDSProperty('Misc','indicator')=='static' else self.ANIM_IMG
        self.parent.confconn.reg.closeEndPoint(self.parent.confconn.SRCNAME)
        
    def initEPSG(self):
        '''Read GDAL EPSG files, splitting by NZ(RSR) and RestOfTheWorld'''

        gcsf = gdal.FindFile('gdal','gcs.csv') 
        if not gcsf:
            gcsf = os.path.join(self.GD_PATH,'gcs.csv')
        pcsf = gdal.FindFile('gdal','pcs.csv') 
        if not pcsf: 
            pcsf = os.path.join(self.GD_PATH,'pcs.csv')
        gcs = ConfigInitialiser.readCSV(gcsf)
        pcs = ConfigInitialiser.readCSV(pcsf)

        self.nzlsr = [(e[0],e[0]+' - '+e[3]) for e in gcs if 'NZGD'     in e[1] or  'RSRGD'     in e[1]] \
                   + [(e[0],e[0]+' - '+e[1]) for e in pcs if 'NZGD'     in e[1] or  'RSRGD'     in e[1]]
        self.rowsr = [(e[0],e[0]+' - '+e[3]) for e in gcs if 'NZGD' not in e[1] and 'RSRGD' not in e[1]] \
                   + [(e[0],e[0]+' - '+e[1]) for e in pcs if 'NZGD' not in e[1] and 'RSRGD' not in e[1]]
                   
                   
    def initUI(self):
        
        # 0      1          2       3       4       5      6    7    8
        #'destname','lgselect','layer','uconf','group','epsg','fd','td','int'
        
        #self.rdest,rlgselect,self.rlayer,ruconf,self.rgroup,repsg,rfd,rtd,rint = readlist 
        
        QToolTip.setFont(QFont('SansSerif', 10))
        
        #labels
        destLabel = QLabel('Destination')
        lgLabel = QLabel('Group/Layer')
        epsgLabel = QLabel('EPSG')
        fromDateLabel = QLabel('From Date')
        toDateLabel = QLabel('To Date')
        confLabel = QLabel('User Config')
        
        self.view = QLabel() 
        self.view.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.view.setAlignment(Qt.AlignCenter)

        self.confcombo = QComboBox(self)
        self.confcombo.setToolTip('Enter your user config name (file) here')
        self.confcombo.addItems(self.cflist)
        self.confcombo.setEditable(False)
        #self.confcombo.currentIndexChanged.connect(self.doLGEditUpdate)
        
        #combos
        self.lgcombo = QComboBox(self)
        self.lgcombo.setMaximumWidth(self.MAX_WD)
        self.lgcombo.setDuplicatesEnabled(False)
        #self.lgcombo.setInsertPolicy(QComboBox.InsertAlphabetically)#?doesnt seem to work
        self.lgcombo.setToolTip('Select either Layer or Group entry')
        self.lgcombo.setEditable(False)
        self.sepindex = None
        #self.updateLGValues()
        
        self.epsgcombo = QComboBox(self)
        self.epsgcombo.setMaximumWidth(self.MAX_WD)
        self.epsgcombo.setToolTip('Setting an EPSG number here determines the output SR of the layer')  
        self.epsgcombo.addItems([i[1] for i in self.nzlsr])
        self.epsgcombo.insertSeparator(len(self.nzlsr))
        self.epsgcombo.addItems([i[1] for i in self.rowsr])
        self.epsgcombo.setEditable(True)
        self.epsgcombo.setEnabled(False)
        
        self.destlist = self.getConfiguredDestinations()
        self.destcombo = QComboBox(self)
        self.destcombo.setToolTip('Choose the desired output type')   
        self.destcombo.setEditable(False)
        self.destcombo.addItems(self.destlist)

        #date selection
        self.fromdateedit = QDateEdit()
        self.fromdateedit.setCalendarPopup(True)
        self.fromdateedit.setEnabled(False)
        
        self.todateedit = QDateEdit()
        self.todateedit.setCalendarPopup(True)
        self.todateedit.setEnabled(False)
        
        #check boxes
        self.epsgenable = QCheckBox()
        self.epsgenable.setCheckState(False)
        self.epsgenable.clicked.connect(self.doEPSGEnable)       
        
        self.fromdateenable = QCheckBox()
        self.fromdateenable.setCheckState(False)
        self.fromdateenable.clicked.connect(self.doFromDateEnable)
        
        self.todateenable = QCheckBox()
        self.todateenable.setCheckState(False) 
        self.todateenable.clicked.connect(self.doToDateEnable)
        
        self.progressbar = QProgressBar()
        self.progressbar.setRange(0,100)
        self.progressbar.setVisible(True)
        self.progressbar.setMinimumWidth(self.MAX_WD)
        
        
        #buttons        
        self.initbutton = QPushButton("waiting")
        self.initbutton.setToolTip('Initialise the Layer Configuration')
        self.initbutton.clicked.connect(self.doInitClickAction)
        
        self.cleanbutton = QPushButton("Clean")
        self.cleanbutton.setToolTip('Clean the selected layer/group from local storage')
        self.cleanbutton.clicked.connect(self.doCleanClickAction)
        
        self.replicatebutton = QPushButton("Replicate")
        self.replicatebutton.setToolTip('Execute selected replication')
        self.replicatebutton.clicked.connect(self.doReplicateClickAction)
        
        self.cancelbutton = QPushButton("Close")
        self.cancelbutton.setToolTip('Close the LDS Replicate application')       
        self.cancelbutton.clicked.connect(self.parent.close)


        #set dialog values using GPR
        self.updateGUIValues(self.parent.gvs)
        
        #set onchange here otherwise we get circular initialisation
        self.destcombo.currentIndexChanged.connect(self.doDestChanged)
        self.confcombo.currentIndexChanged.connect(self.doConfChanged)
        self.lgcombo.currentIndexChanged.connect(self.doLGComboChanged)

        self.setStatus(self.STATUS.IDLE)
        
        #grid
        grid = QGridLayout()
        grid.setSpacing(10)
        
        
        #placement section ------------------------------------
        #---------+---------+--------+---------+--------
        # dest LB |         | dest DD
        # grp LB  |         | grp DD
        # conf LB |         | conf DD
        # epsg L  | epsg CB | epsg DD
        # f dt L  | f dt CB | f dt DD
        # t td L  | t td CB | t td DD
        # icon    |       <- progress ->
        # layer B | <- . -> |repl B  | clean B | close B 
        #---------+---------+--------+---------+--------

        grid.addWidget(destLabel, 1, 0)
        grid.addWidget(self.destcombo, 1, 2)

        #grid.addWidget(layerLabel, 2, 0)
        grid.addWidget(lgLabel, 2, 0)
        grid.addWidget(self.lgcombo, 2, 2)
        
        grid.addWidget(confLabel, 3, 0)
        grid.addWidget(self.confcombo, 3, 2)
        
        #grid.addWidget(groupLabel, 4, 0)
        #grid.addWidget(self.groupEdit, 4, 2)
        
        grid.addWidget(epsgLabel, 5, 0)
        grid.addWidget(self.epsgenable, 5, 1)
        grid.addWidget(self.epsgcombo, 5, 2)

        grid.addWidget(fromDateLabel, 6, 0)
        grid.addWidget(self.fromdateenable, 6, 1)
        grid.addWidget(self.fromdateedit, 6, 2)
        
        grid.addWidget(toDateLabel, 7, 0)
        grid.addWidget(self.todateenable, 7, 1)
        grid.addWidget(self.todateedit, 7, 2)
        
        hbox3 = QHBoxLayout()
        hbox3.addWidget(self.view) 
        hbox3.addStretch(1)
        hbox3.addWidget(self.progressbar)

        #hbox3.addLayout(vbox2)
        #hbox3.addLayout(vbox3)
        
        hbox4 = QHBoxLayout()
        hbox4.addWidget(self.initbutton)
        hbox4.addStretch(1)
        hbox4.addWidget(self.replicatebutton)
        hbox4.addWidget(self.cleanbutton)
        hbox4.addWidget(self.cancelbutton)
        

        vbox = QVBoxLayout()
        #vbox.addStretch(1)
        vbox.addLayout(grid)
        vbox.addLayout(hbox3)
        vbox.addLayout(hbox4)
        
        self.setLayout(vbox)  
       
    #def setProgress(self,pct):
    #    self.progressbar.setValue(pct)
        
    def setStatus(self,status,message='',tooltip=None):
        '''Sets indicator icon and statusbar message'''
        self.parent.statusbar.showMessage(message)
        self.parent.statusbar.setToolTip(tooltip if tooltip else '')

        #progress
        loc = os.path.abspath(os.path.join(IMG_LOC,self.imgset[status]))
        #loc = os.path.abspath(os.path.join(os.path.dirname(__file__),self.parent.IMG_LOC,self.imgset[status]))
        self.progressbar.setVisible(status in (self.STATUS.BUSY, self.STATUS.CLEAN))
        
        #icon
        anim = QMovie(loc, QByteArray(), self)
        anim.setScaledSize(QSize(self.IMG_WIDTH,self.IMG_HEIGHT))
        anim.setCacheMode(QMovie.CacheAll)
        anim.setSpeed(self.IMG_SPEED)
        self.view.clear()
        self.view.setMovie(anim)
        anim.start()

        self.view.repaint()
        QApplication.processEvents(QEventLoop.AllEvents)

    def mainWindowEnable(self,enable=True):
        cons = (self.lgcombo, self.confcombo, self.destcombo, 
                self.initbutton, self.replicatebutton, self.cleanbutton, self.cancelbutton,
                self.epsgenable,self.fromdateenable,self.todateenable,
                self.parent.menubar)
        for c in cons:
            c.setEnabled(enable)
            
        if enable:
            self.epsgcombo.setEnabled(self.epsgenable.checkState())
            self.fromdateedit.setEnabled(self.fromdateenable.checkState())
            self.todateedit.setEnabled(self.todateenable.checkState())
        else:
            self.epsgcombo.setEnabled(False)
            self.fromdateedit.setEnabled(False)
            self.todateedit.setEnabled(False)
   
        QApplication.restoreOverrideCursor() if enable else QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) 

    def refreshLGCombo(self):
        '''Re index LG combobox since a refreshLG call (new dest?) will usually mean new groups'''
        self.lgcombo.clear()
        self.lgcombo.addItems([i[2] for i in self.parent.confconn.lglist])
        #NOTE the separator consumes an index, if not clearing the combobox selectively remove the old sepindex (assumes g preceeds l)
        #if self.sepindex:
        #    self.lgcombo.removeItem(self.sepindex)
        self.sepindex = [i[0] for i in self.parent.confconn.lglist].count(LORG.GROUP)
        self.lgcombo.insertSeparator(self.sepindex)
        
    def updateLGValues(self,uconf,lgval,dest):
        '''Sets the values displayed in the Layer/Group combo'''
        #because we cant seem to sort combobox entries and want groups at the top, clear and re-add
        #TRACE#        
        #pdb.set_trace()
        sf = None
        try:
            self.parent.confconn.initConnections(uconf,lgval,dest)
        except Exception as e:
            sf=1
            ldslog.error('Error Updating UC Values. '+str(e))
            
        if sf:
            self.setStatus(self.STATUS.ERROR,'Error Updating UC Values', str(e))
        else:
            self.setStatus(self.STATUS.IDLE)
            
        self.refreshLGCombo()
        
    def centre(self):
        
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())
        
    
    def gprParameters(self,rdest):
        '''Zip default and GPR values'''
        return [x if LU.assessNone(x) else y for x,y in zip(self.parent.gpr.readsec(rdest),self.parent.DEF_RVALS[1:])]
    
    def getLCE(self,ln):
        '''Read layer parameters'''
        dep = self.parent.confconn.reg.openEndPoint(self.parent.confconn.destname,self.parent.confconn.uconf)
        #sep = self.parent.confconn.reg.openEndPoint('WFS',self.parent.confconn.uconf)
        self.parent.confconn.reg.setupLayerConfig(self.parent.confconn.tp,None,dep,initlc=False)
        lce = dep.getLayerConf().readLayerParameters(ln)
        #self.parent.confconn.reg.closeEndPoint('WFS')
        self.parent.confconn.reg.closeEndPoint(self.parent.confconn.destname)
        sep,dep = None,None
        return lce
    
    
    def doDestChanged(self):
        '''Read the destname parameter and fill dialog with matching GPR values'''
        rdest = str(self.destlist[self.destcombo.currentIndex()])
        rvals = self.gprParameters(rdest)
        self.updateGUIValues([rdest]+rvals)    
        
        
    def doConfChanged(self):
        '''Read the user conf parameter and fill dialog with matching GPR values'''
        rdest = str(self.destlist[self.destcombo.currentIndex()])
        rlg,_,rep,rfd,rtd = self.gprParameters(rdest)
        ruc = str(self.cflist[self.confcombo.currentIndex()])
        self.updateGUIValues((rdest,rlg,ruc,rep,rfd,rtd))
        
        
    def doLGComboChanged(self):
        '''Read the layer/group value and change epsg to layer or gpr match'''
        #get a matching LG entry and test whether its a layer or group
        #lgi = self.parent.confconn.getLayerGroupIndex(self.lgcombo.currentText().toUtf8().data())
        lgi = self.parent.confconn.getLayerGroupIndex(LQ.readWidgetText(self.lgcombo.currentText()))
        #lgi can be none if we init a new group, in which case we use the GPR value
        if lgi:
            lge = self.parent.confconn.lglist[lgi]
            lce = self.getLCE(lge[1]) if lge[0]==LORG.LAYER else None
        else:
            lce = None
        
        #look for filled layer conf epsg OR use prefs stored in gpr
        if lce and LU.assessNone(lce.epsg):
            epsgval = lce.epsg
        else:
            rdest = str(self.destlist[self.destcombo.currentIndex()])
            _,_,epsgval,_,_ = self.gprParameters(rdest)
        epsgindex = [i[0] for i in self.nzlsr+[(0,0)]+self.rowsr].index(epsgval)
        if self.epsgcombo.currentIndex() != epsgindex:
            self.epsgcombo.setCurrentIndex(int(epsgindex))

        
    def updateGUIValues(self,readlist):
        '''Fill dialog values from provided list'''
        #TODO. Remove circular references when setCurrentIndex() triggers do###Changed()
        #Read user input
        rdest,self.rlgval,ruconf,repsg,rfd,rtd = readlist
        
        #--------------------------------------------------------------------
        
        #Destination Menu
        selecteddest = LU.standardiseDriverNames(rdest)
        if selecteddest not in self.destlist:
            self.destlist = self.getConfiguredDestinations()
            self.destcombo.addItem(selecteddest)
        destindex = self.destlist.index(selecteddest) if selecteddest else 0
        
        if self.destcombo.currentIndex() != destindex:
            self.destcombo.setCurrentIndex(destindex)
        
        #InitButton
        self.initbutton.setText('Layer Select')
        
        #Config File
        confindex = 0
        if LU.assessNone(ruconf):
            ruconf = ruconf.split('.')[0]
            if ruconf not in self.cflist:
                self.cflist += [ruconf,]
                self.confcombo.addItem(ruconf)
            confindex = self.cflist.index(ruconf)
            
        if self.confcombo.currentIndex() != confindex:
            self.confcombo.setCurrentIndex(confindex)
        #self.confEdit.setText(ruconf if LU.assessNone(ruconf) else '')
        
        #Layer/Group Selection
        self.updateLGValues(ruconf,self.rlgval,rdest)
        lgindex = None
        if LU.assessNone(self.rlgval):
            #index of list value
            lgindex = self.parent.confconn.getLayerGroupIndex(self.rlgval,col=1)
            
        if LU.assessNone(lgindex):
            #advance by 1 for sep
            lgindex += 1 if lgindex>self.sepindex else 0 
        else:
            #using the separator index sets the combo to blank
            lgindex = self.sepindex
        if self.lgcombo.currentIndex() != lgindex:
            self.lgcombo.setCurrentIndex(lgindex)
        #self.doLGEditUpdate()
        
        #EPSG
        #                                user > layerconf
        #useepsg = LU.precedence(repsg, lce.epsg if lce else None, None)
        epsgindex = [i[0] for i in self.nzlsr+[(None,None)]+self.rowsr].index(repsg)
        if self.epsgcombo.currentIndex() != epsgindex:
            self.epsgcombo.setCurrentIndex(epsgindex)
            
        #epsgedit = self.epsgcombo.lineEdit()
        #epsgedit.setText([e[1] for e in self.nzlsr+self.rowsr if e[0]==repsg][0])
        
        #epsgedit.setText([e for e in self.nzlsr+self.rowsr if re.match('^\s*(\d+).*',e).group(1)==repsg][0])
        
        #To/From Dates
        if LU.assessNone(rfd):
            self.fromdateedit.setDate(QDate(int(rfd[0:4]),int(rfd[5:7]),int(rfd[8:10])))
        else:
            early = DataStore.EARLIEST_INIT_DATE
            self.fromdateedit.setDate(QDate(int(early[0:4]),int(early[5:7]),int(early[8:10])))
            
        if LU.assessNone(rtd):
            self.todateedit.setDate(QDate(int(rtd[0:4]),int(rtd[5:7]),int(rtd[8:10]))) 
        else:
            today = DataStore.getCurrent()
            self.todateedit.setDate(QDate(int(today[0:4]),int(today[5:7]),int(today[8:10])))
            
        #Internal/External CheckBox
#        if LU.assessNone(rint):
#            self.internalTrigger.setChecked(rint.lower()==DataStore.CONF_INT)
#        else:
#            self.internalTrigger.setChecked(DataStore.DEFAULT_CONF==DataStore.CONF_INT)
        
        
    def getConfiguredDestinations(self):
        defml = ['',]+DataStore.DRIVER_NAMES.values()
        return [d for d in self.parent.gpr.getDestinations() if d in defml]
        
    def doEPSGEnable(self):
        self.epsgcombo.setEnabled(self.epsgenable.isChecked())
        
    def doFromDateEnable(self):
        self.fromdateedit.setEnabled(self.fromdateenable.isChecked())
          
    def doToDateEnable(self):
        self.todateedit.setEnabled(self.todateenable.isChecked())  
          
    def readParameters(self):
        '''Read values out of dialogs'''
        destination = LU.assessNone(str(self.destlist[self.destcombo.currentIndex()]))
        #lgindex = self.parent.confconn.getLayerGroupIndex(self.lgcombo.currentText().toUtf8().data())
        lgindex = self.parent.confconn.getLayerGroupIndex(LQ.readWidgetText(self.lgcombo.currentText()))
        #NB need to test for None explicitly since zero is a valid index
        lgval = self.parent.confconn.lglist[lgindex][1] if LU.assessNone(lgindex) else None       
        #uconf = LU.standardiseUserConfigName(str(self.confcombo.lineEdit().text()))
        #uconf = str(self.confcombo.lineEdit().text())
        uconf = str(self.cflist[self.confcombo.currentIndex()])
        ee = self.epsgenable.isChecked()
        epsg = None if ee is False else re.match('^\s*(\d+).*',str(self.epsgcombo.lineEdit().text())).group(1)
        fe = self.fromdateenable.isChecked()
        te = self.todateenable.isChecked()
        fd = None if fe is False else str(self.fromdateedit.date().toString('yyyy-MM-dd'))
        td = None if te is False else str(self.todateedit.date().toString('yyyy-MM-dd'))
        
        return destination,lgval,uconf,epsg,fe,te,fd,td
    
    def doInitClickAction(self):
        '''Initialise the LC on LC-button-click, action'''
        try:
            try:
                self.setStatus(self.STATUS.BUSY,'Opening Layer-Config Editor')  
                self.progressbar.setValue(0)
                self.parent.runLayerConfigAction()
            finally:
                self.setStatus(self.STATUS.IDLE,'Ready')
        except Exception as e:
            self.setStatus(self.STATUS.ERROR,'Error in Layer-Config',str(sys.exc_info()))#e))
        
    def doCleanClickAction(self):
        '''Set clean anim and run clean'''
        #lgo = self.lgcombo.currentText().toUtf8().data()
        lgo = LQ.readWidgetText(self.lgcombo.currentText())
        
        try:
            self.setStatus(self.STATUS.CLEAN,'Running Clean '+lgo)
            self.progressbar.setValue(0)
            self.runReplicationScript(True)
        except Exception as e:
            self.setStatus(self.STATUS.ERROR,'Failed Clean of '+lgo,str(sys.exc_info()))#e))
        
    def doReplicateClickAction(self):
        '''Set busy anim and run repl'''
        lgo = self.lgcombo.currentText()#.toUtf8().data()#only used for error messages
        try:
            self.setStatus(self.STATUS.BUSY,'Running Replicate '+lgo)
            self.progressbar.setValue(0)
            self.runReplicationScript(False)
        except Exception as e:
            self.setStatus(self.STATUS.ERROR,'Failed Replication of '+lgo,str(sys.exc_info()))#e))

    def runReplicationScript(self,clean=False):
        '''Run the layer/group repliction script'''
        destination,lgval,uconf,epsg,fe,te,fd,td = self.readParameters()
        uconf_path = LU.standardiseUserConfigName(uconf)
        destination_path = LU.standardiseLayerConfigName(destination)
        destination_driver = LU.standardiseDriverNames(destination)

        if not os.path.exists(uconf_path):
            self.userConfMessage(uconf_path)
            return
        elif not MainFileReader(uconf_path).hasSection(destination_driver):
            self.userConfMessage(uconf_path,destination_driver)
            return
        #-----------------------------------------------------
        #'destname','layer','uconf','group','epsg','fd','td','int'
     
        self.parent.gpr.write((destination_driver,lgval,uconf,epsg,fd,td))        
        ldslog.info(u'dest={0}, lg={1}, conf={2}, epsg={3}'.format(destination_driver,lgval,uconf,epsg))
        ldslog.info('fd={0}, td={1}, fe={2}, te={3}'.format(fd,td,fe,te))
        lgindex = self.parent.confconn.getLayerGroupIndex(lgval,col=1)
        #lorg = self.parent.confconn.lglist[lgindex][0]
        #----------don't need lorg in TP anymore but it is useful for sorting/counting groups
        #self.parent.confconn.tp.setLayerOrGroup(lorg)
        self.parent.confconn.tp.setLayerGroupValue(lgval)
        if self.fromdateenable.isChecked(): self.parent.confconn.tp.setFromDate(fd)
        if self.todateenable.isChecked(): self.parent.confconn.tp.setToDate(td)
        self.parent.confconn.tp.setUserConf(uconf)
        if self.epsgenable: self.parent.confconn.tp.setEPSG(epsg)
        
        #because clean state persists in TP
        if clean:
            self.parent.confconn.tp.setCleanConfig()
        else:
            self.parent.confconn.tp.clearCleanConfig()
        #(re)initialise the data source since uconf may have changed
        #>>#self.parent.confconn.tp.src = self.parent.confconn.initSourceWrapper()
        #--------------------------
        ###ep = self.parent.confconn.reg.openEndPoint(self.parent.confconn.destname,self.parent.confconn.uconf)
        
        ###self.parent.confconn.reg.closeEndPoint(self.parent.confconn.destname)
        ###ep = None
        #Open ProcessRunner and run with TP(proc)/self(gui) instances
        #HACK temp add of dest_drv to PR call
        try:
            #TODO. Test for valid LC first
            self.tpr = ProcessRunner(self,destination_driver)
        except Exception as e:
            ldslog.error('Cannot create ProcessRunner {}. NB Possible missing Layer Config {}'.format(str(e),destination_path))
            self.layerConfMessage(destination_path)
            return
        #If PR has been successfully created we must vave a valid dst    
        self.tpr.start()
        
    def quitProcessRunner(self):
        self.tpr.join()
        self.tpr.quit()
        self.trp = None

        
    def userConfMessage(self,uconf,secname=None):
        ucans = QMessageBox.warning(self, 'User Config Missing/Incomplete', 
                                'Specified User-Config file, '+str(uconf)+' does not exist' if secname is None else 'User-Config file does not contain '+str(secname)+' section', 
                                'Back','Initialise User Config')
        if not ucans:
            #Retry
            ldslog.warn('Retry specifying UC')
            #self.confcombo.setCurrentIndex(0)
            return
        #Init
        ldslog.warn('Reset User Config Wizard')
        self.parent.runWizardAction()


    def layerConfMessage(self,dest):
        lcans = QMessageBox.warning(self, 'Layer Config Missing', 
                                'Required Layer-Config file, '+str(dest)+' does not exist', 
                                'Back','Run Layer Select')
        if not lcans:
            #Retry
            ldslog.warn('Retry specifying LC')
            #self.destcombo.setCurrentIndex(0)
            return
        #Init
        ldslog.warn('Reset Layer Config')
        self.doInitClickAction()
Exemple #23
0
class QuadStatusBar(QHBoxLayout):
    positionChanged = pyqtSignal(int, int, int) # x,y,z
    
    def __init__(self, parent=None ):
        QHBoxLayout.__init__(self, parent)
        self.setContentsMargins(0,4,0,0)
        self.setSpacing(0)
        self.timeControlFontSize = 12

    def showXYCoordinates(self):
        self.zLabel.setHidden(True)
        self.zSpinBox.setHidden(True)
        
    def showXYZCoordinates(self):
        self.zLabel.setHidden(False)
        self.zSpinBox.setHidden(False)
    
    def hideTimeSlider(self,flag):
        self.timeSlider.setHidden(flag)
        self.timeEndButton.setHidden(flag)
        self.timeStartButton.setHidden(flag)

    def setToolTipTimeButtonsCrop(self,croppingFlag=False):
        if croppingFlag==True:
            self.timeStartButton.setToolTip("Set the time coordinate to the beginning of the current crop.")
            self.timeEndButton.setToolTip("Set the time coordinate to the end of the current crop.")
        else:
            self.timeStartButton.setToolTip("Set the time coordinate to the beginning of the current dataset.")
            self.timeEndButton.setToolTip("Set the time coordinate to the end of the current dataset.")

    def setToolTipTimeSliderCrop(self,croppingFlag=False):
        if croppingFlag==True:
            self.timeSlider.setToolTip("Choose the time coordinate of the current crop.")
        else:
            self.timeSlider.setToolTip("Choose the time coordinate of the current dataset.")

    def createQuadViewStatusBar(self,
                                xbackgroundColor, xforegroundColor,
                                ybackgroundColor, yforegroundColor,
                                zbackgroundColor, zforegroundColor):
        self.xLabel, self.xSpinBox = _get_pos_widget('X',
                                                     xbackgroundColor,
                                                     xforegroundColor)
        self.yLabel, self.ySpinBox = _get_pos_widget('Y',
                                                     ybackgroundColor,
                                                     yforegroundColor)
        self.zLabel, self.zSpinBox = _get_pos_widget('Z',
                                                     zbackgroundColor,
                                                     zforegroundColor)
        
        self.xSpinBox.delayedValueChanged.connect( partial(self._handlePositionBoxValueChanged, 'x') )
        self.ySpinBox.delayedValueChanged.connect( partial(self._handlePositionBoxValueChanged, 'y') )
        self.zSpinBox.delayedValueChanged.connect( partial(self._handlePositionBoxValueChanged, 'z') )

        self.addWidget(self.xLabel)
        self.addWidget(self.xSpinBox)
        self.addWidget(self.yLabel)
        self.addWidget(self.ySpinBox)
        self.addWidget(self.zLabel)
        self.addWidget(self.zSpinBox)

        self.addSpacing(10)

        self.busyIndicator = QProgressBar()
        self.busyIndicator.setMaximumWidth(200)
        self.busyIndicator.setMaximum(0)
        self.busyIndicator.setMinimum(0)
        self.busyIndicator.setVisible(False)
        self.busyIndicator.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.addWidget( self.busyIndicator )
        self.setStretchFactor(self.busyIndicator, 1)

        self.addStretch()
        self.addSpacing(10)

        self.positionCheckBox = QCheckBox()
        self.positionCheckBox.setChecked(True)
        self.positionCheckBox.setCheckable(True)
        self.positionCheckBox.setText("Position")
        self.addWidget(self.positionCheckBox)

        self.addSpacing(20)

        self.timeSpinBox = DelayedSpinBox(750)

        self.timeStartButton = QPushButton("Start")
        self.addWidget(self.timeStartButton)
        self.timeStartButton.clicked.connect(self._onTimeStartButtonClicked)

        self.timeSlider = QSlider(Qt.Horizontal)
        self.timeSlider.setMinimumWidth(10)
        self.timeSlider.setMaximumWidth(200)
        self.setToolTipTimeSliderCrop()
        self.addWidget(self.timeSlider)
        self.timeSlider.valueChanged.connect(self._onTimeSliderChanged)

        self.timeEndButton = QPushButton("End")
        self.timeEndButton.setFixedWidth(4*self.timeControlFontSize)

        self.timeStartButton.setFixedWidth(4*self.timeControlFontSize)
        
        self.setToolTipTimeButtonsCrop()
        self.addWidget(self.timeEndButton)
        self.timeEndButton.clicked.connect(self._onTimeEndButtonClicked)

        self.timeLabel = QLabel("       Time:")
        self.addWidget(self.timeLabel)

        timeControlFont = self.timeSpinBox.font()
        if self.timeControlFontSize > timeControlFont.pointSize():
            timeControlFont.setPixelSize(self.timeControlFontSize)
            self.timeStartButton.setFont(timeControlFont)
            self.timeEndButton.setFont(timeControlFont)
            self.timeLabel.setFont(timeControlFont)
            self.timeSpinBox.setFont(timeControlFont)

        self.addWidget(self.timeSpinBox)
        self.timeSpinBox.delayedValueChanged.connect(self._onTimeSpinBoxChanged)

    def _onTimeStartButtonClicked(self):
        self.timeSpinBox.setValue(self.parent().parent().parent().editor.cropModel.get_roi_t()[0])

    def _onTimeEndButtonClicked(self):
        self.timeSpinBox.setValue(self.parent().parent().parent().editor.cropModel.get_roi_t()[1])

    def _onTimeSpinBoxChanged(self):
        editor = self.parent().parent().parent().editor
        cropModel = editor.cropModel
        minValueT = cropModel.get_roi_t()[0]
        maxValueT = cropModel.get_roi_t()[1]

        if cropModel.get_scroll_time_outside_crop():
            if minValueT > self.timeSpinBox.value() or maxValueT < self.timeSpinBox.value():
                for imgView in editor.imageViews:
                    imgView._croppingMarkers._shading_item.set_paint_full_frame(True)
            else:
                for imgView in editor.imageViews:
                    imgView._croppingMarkers._shading_item.set_paint_full_frame(False)
            self.timeSlider.setValue(self.timeSpinBox.value())
        else:
            for imgView in editor.imageViews:
                imgView._croppingMarkers._shading_item.set_paint_full_frame(False)
            if minValueT > self.timeSpinBox.value():
                self.timeSlider.setValue(minValueT)
            elif maxValueT < self.timeSpinBox.value():
                self.timeSlider.setValue(maxValueT)
            elif minValueT <= self.timeSpinBox.value() and self.timeSpinBox.value() <= maxValueT:
                self.timeSlider.setValue(self.timeSpinBox.value())

    def _onTimeSliderChanged(self):
        cropModel = self.parent().parent().parent().editor.cropModel
        minValueT = cropModel.get_roi_t()[0]
        maxValueT = cropModel.get_roi_t()[1]

        if cropModel.get_scroll_time_outside_crop():
            self.timeSpinBox.setValue(self.timeSlider.value())
        else:
            if minValueT > self.timeSlider.value():
                self.timeSpinBox.setValue(minValueT)
                self.timeSlider.setValue(minValueT)
            elif self.timeSlider.value() > maxValueT:
                self.timeSpinBox.setValue(maxValueT)
                self.timeSlider.setValue(maxValueT)
            elif minValueT <= self.timeSlider.value() and self.timeSlider.value() <= maxValueT:
                self.timeSpinBox.setValue(self.timeSlider.value())

    def _handlePositionBoxValueChanged(self, axis, value):
        new_position = [self.xSpinBox.value(), self.ySpinBox.value(), self.zSpinBox.value()]
        changed_axis = ord(axis) - ord('x')
        new_position[changed_axis] = value
        self.positionChanged.emit(*new_position)

    def updateShape5D(self, shape5D):
        self.timeSpinBox.setMaximum(shape5D[0]-1)
        self.xSpinBox.setMaximum(shape5D[1]-1)
        self.ySpinBox.setMaximum(shape5D[2]-1)
        self.zSpinBox.setMaximum(shape5D[3]-1)

    def updateShape5Dcropped(self, shape5DcropMin, shape5Dmax):
        self.timeSpinBox.setMaximum(shape5Dmax[0]-1)
        self.xSpinBox.setMaximum(shape5Dmax[1]-1)
        self.ySpinBox.setMaximum(shape5Dmax[2]-1)
        self.zSpinBox.setMaximum(shape5Dmax[3]-1)
        self.timeSlider.setMaximum(shape5Dmax[0]-1)

        self.timeSpinBox.setValue(shape5DcropMin[0])
        self.xSpinBox.setValue(shape5DcropMin[1])
        self.ySpinBox.setValue(shape5DcropMin[2])
        self.zSpinBox.setValue(shape5DcropMin[3])
        self.timeSlider.setValue(shape5DcropMin[0])

    def setMouseCoords(self, x, y, z):
        self.xSpinBox.setValueWithoutSignal(x)
        self.ySpinBox.setValueWithoutSignal(y)
        self.zSpinBox.setValueWithoutSignal(z)
Exemple #24
0
class ExcelWorkbookView(QWidget):
    """A read-only table view for browsing MS Excel data."""
    def __init__(self, *args, **kwargs):
        super(QWidget, self).__init__(*args, **kwargs)
        self._init_ui()

        # Optional args
        self._dt_format = kwargs.pop('date_format', '%Y-%m-%d')

        # Map for sheet widgets
        self._ws_info = {}

        # Reset the view
        self.reset_view()

        # Check availability of XLRD library
        if not XLRD_AVAIL:
            QMessageBox.critical(
                self, self.tr('Missing Dependency'),
                self.
                tr('\'xlrd\' library is missing.\nExcel data cannot be loaded '
                   'without this library. Please install it and try again.'))
            self.setEnabled(False)

            return

    @property
    def date_format(self):
        """
        :return: Returns the format used to render the date/time in the
        view. The default formatting will return the date in ISO 8601 format
        i.e. 'YYYY-MM-DD' where the format is '%Y-%m-%d'.
        :rtype: str
        """
        return self._dt_format

    @date_format.setter
    def date_format(self, format):
        """
        Sets the format used to render the date/time in the view. The format
        needs to be in a format that is understood by Python's 'strftime()'
        function.
        :param format: Format for rendering date/time
        :type format: str
        """
        self._dt_format = format

    def worksheet_info(self, idx):
        """
        :param idx:
        :return: Returns a WorksheetInfo object containing references to the
        ExcelWorksheetView, xlrd.sheet.Sheet and name of the sheet, will
        return None if the index does not exist.
        :rtype: WorksheetInfo
        """
        return self._ws_info.get(idx, None)

    def current_worksheet_info(self):
        """
        :return: Returns the WorksheetInfo object for the current displayed
        tab. None if the view is empty.
        :rtype:WorksheetInfo
        """
        curr_idx = self._tbw.currentIndex()
        return self.worksheet_info(curr_idx)

    @property
    def progress_bar(self):
        """
        :return: Returns the progress bar for showing progress when Excel
        data is being added to the table.
        :rtype: QProgressBar
        """
        return self._pg_par

    def sizeHint(self):
        return QSize(480, 360)

    def clear_view(self):
        # Removes and deletes all sheet widgets and resets the widget registry index.
        self._tbw.clear()
        self._ws_info.clear()

    def reset_view(self):
        # Clears the view and add an empty default sheet.
        self.clear_view()
        self._add_default_sheet()

    def _add_default_sheet(self):
        # Add a default/empty sheet to the view.
        def_sheet = ExcelSheetView()
        self._tbw.addTab(def_sheet, self.tr('Sheet 1'))

    def _init_ui(self):
        # Set up layout and widgets
        self._vl = QVBoxLayout()
        self._tbw = QTabWidget()
        self._tbw.setTabShape(QTabWidget.Triangular)
        self._tbw.setTabPosition(QTabWidget.South)
        self._tbw.setStyleSheet('QTabBar::tab:selected { color: green; }')
        self._vl.addWidget(self._tbw)
        self._pg_par = QProgressBar()
        self._pg_par.setVisible(False)
        self._vl.addWidget(self._pg_par)
        self.setLayout(self._vl)

    def add_xlrd_sheet(self, xsheet):
        """
        Adds data contained in a sheet object to the view.
        :param xsheet: Object containing worksheet data.
        :type xsheet: xlrd.sheet.Sheet
        """
        worksheet = ExcelSheetView()
        worksheet.date_format = self._dt_format
        name = xsheet.name
        idx = self._tbw.addTab(worksheet, name)
        self._tbw.setTabToolTip(idx, name)

        worksheet.load_worksheet(xsheet)

        # Add worksheet info to collection
        wsi = WorksheetInfo()
        wsi.name = name
        wsi.idx = idx
        wsi.ws_widget = worksheet
        wsi.ws = xsheet

        self._ws_info[wsi.idx] = wsi

    def load_workbook(self, path):
        """
        Loads the workbook contained in the specified file to the view.
        :param path: Path to fil containing workbook data.
        :type path: str
        """
        xfile = QFile(path)
        if not xfile.exists():
            QMessageBox.critical(
                self, self.tr('Invalid path'),
                u'\'{0}\' {1}'.format(path, self.tr('does not exist.')))

            return

        # Check permissions
        xfileinfo = QFileInfo(xfile)
        if not xfileinfo.isReadable():
            QMessageBox.critical(
                self, self.tr('Unreadable file'),
                u'{0} {1}'.format(path, self.tr('is not readable.')))

            return

        # Clear view
        self.clear_view()

        # Show progress bar
        self._pg_par.setVisible(True)
        pg_val = 0

        # Add sheets
        wb = open_workbook(path)
        self._pg_par.setRange(0, wb.nsheets)
        for s in wb.sheets():
            self.add_xlrd_sheet(s)

            # Update progress bar
            pg_val += 1
            self._pg_par.setValue(pg_val)

        self._pg_par.setVisible(False)
class OnlineUpdateGUI(QWidget):
    CHECK_INTERVAL = 12 * 60 * 60 * 1000  # check twice a day

    checkForAppUpdate = pyqtSignal()
    checkForRepoUpdates = pyqtSignal()
    installUpdates = pyqtSignal()

    def __init__(self, installedVersion, parent):
        super(OnlineUpdateGUI, self).__init__(parent)

        self._canCheckForAppUpdate = False
        self._canCheckForRepoUpdate = False
        self._appUpdatesAvailable = False
        self._repoUpdatesAvailable = False

        layout = QVBoxLayout(self)
        layout.addWidget(self._createAppUpdateWidget(installedVersion))
        layout.addWidget(self._createRepoUpdateWidget())

        self._installUpdatesButton = QPushButton("Install Update(s) and Restart", self)
        self._installUpdatesButton.clicked.connect(self.installUpdates)
        self._installUpdatesButton.setEnabled(False)
        layout.addWidget(self._installUpdatesButton)
        self._spacing = QWidget(self)
        layout.addWidget(self._spacing, 1)

        self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)

    def _createAppUpdateWidget(self, installedVersion):
        widget = QGroupBox("Application", self)

        layout = QVBoxLayout(widget)
        versionLabel = QLabel("Installed Version: " + installedVersion)
        layout.addWidget(versionLabel, 0)

        self._appStatusLabel = QLabel(widget)
        self._appStatusLabel.setWordWrap(True)
        layout.addWidget(self._appStatusLabel, 0)

        self._progressBar = QProgressBar(widget)
        self._progressBar.setVisible(False)
        layout.addWidget(self._progressBar, 0)

        self._appCheckButton = QPushButton("Check for Update", widget)
        self._appCheckButton.clicked.connect(self.checkForAppUpdate)

        layout.addWidget(self._appCheckButton, 0)

        self._appChangeLog = QTextEdit(self)
        self._appChangeLog.setReadOnly(True)
        self._appChangeLog.setVisible(False)
        layout.addWidget(self._appChangeLog, 1)

        return widget

    def _createRepoUpdateWidget(self):
        widget = QGroupBox("Plugin Repositories", self)
        layout = QVBoxLayout(widget)

        self._repoStatusLabel = QLabel(widget)
        layout.addWidget(self._repoStatusLabel)

        self._repoCheckButton = QPushButton("Check for Updates", widget)
        self._repoCheckButton.clicked.connect(self.checkForRepoUpdates)
        layout.addWidget(self._repoCheckButton)

        return widget

    def setChangelogVisible(self, v):
        self._appChangeLog.setVisible(v)
        self._spacing.setVisible(not v)

    def setProgress(self, prog):
        self._progressBar.setValue(prog)

    def setProgressIndeterminate(self, indeterminate):
        self._progressBar.setMaximum(0 if indeterminate else 100)

    def setCheckAppUpdateButtonText(self, text=None):
        if not text:
            text = "Check for Update"
        self._appCheckButton.setText(text)

    def setInteractive(self, interactive):
        if interactive:
            self._appCheckButton.setEnabled(self._canCheckForAppUpdate)
            self._repoCheckButton.setEnabled(self._canCheckForRepoUpdate)
            self._installUpdatesButton.setEnabled(self._appUpdatesAvailable or self._repoUpdatesAvailable)
        else:
            self._appCheckButton.setEnabled(False)
            self._repoCheckButton.setEnabled(False)
            self._installUpdatesButton.setEnabled(False)

    def setCanCheckForAppUpdate(self, can):
        self._canCheckForAppUpdate = can
        self._appCheckButton.setEnabled(can)

    def setCanCheckForRepoUpdate(self, can):
        self._canCheckForRepoUpdate = can
        self._repoCheckButton.setEnabled(can)

    def appInstallReady(self):
        self._appUpdatesAvailable = True
        self._installUpdatesButton.setEnabled(True)

    def setRepoUpdatesAvailable(self, avail):
        self._repoUpdatesAvailable = True
        self._installUpdatesButton.setEnabled(avail or self._appUpdatesAvailable)

    def setRepoStatus(self, status):
        self._repoStatusLabel.setText(status)

    def setAppStatus(self, status, progress=False):
        self._progressBar.setVisible(progress)
        self._appStatusLabel.setText(status)

    def setAppStatusToolTip(self, text):
        self._appStatusLabel.setToolTip(text)

    def setAppChangeLog(self, log):
        self._appChangeLog.clear()
        document = self._appChangeLog.document()
        document.setIndentWidth(20)
        cursor = QTextCursor(document)

        cursor.insertText("Changes:\n")

        listFormat = QTextListFormat()
        listFormat.setStyle(QTextListFormat.ListDisc)
        listFormat2 = QTextListFormat()
        listFormat2.setStyle(QTextListFormat.ListDisc)
        listFormat2.setIndent(2)

        for line in log:
            if line.startswith("*"):
                cursor.insertList(listFormat2)
                line = line[1:]
            else:
                cursor.insertList(listFormat)
            cursor.insertText(line)

        self.setChangelogVisible(True)
Exemple #26
0
class HoldersTableView(QWidget):
    """A read-only table view for browsing MS Excel or CSV data."""
    def __init__(self, *args, **kwargs):
        super(QWidget, self).__init__(*args, **kwargs)
        self._init_ui()

        # Optional args
        self._dt_format = kwargs.pop('date_format', '%d-%m-%Y')

        # Map for sheet widgets
        self._ws_info = {}

        # Reset the view
        self.reset_view()

    @property
    def date_format(self):
        """
        :return: Returns the format used to render the date/time in the
        view. The default formatting will return the date in ISO 8601 format
        i.e. 'YYYY-MM-DD' where the format is '%Y-%m-%d'.
        :rtype: str
        """
        return self._dt_format

    @date_format.setter
    def date_format(self, format):
        """
        Sets the format used to render the date/time in the view. The format
        needs to be in a format that is understood by Python's 'strftime()'
        function.
        :param format: Format for rendering date/time
        :type format: str
        """
        self._dt_format = format

    def worksheet_info(self, idx):
        """
        :param idx:
        :return: Returns a WorksheetInfo object containing references to the
        ExcelWorksheetView, xlrd.sheet.Sheet and name of the sheet, will
        return None if the index does not exist.
        :rtype: WorksheetInfo
        """
        return self._ws_info.get(idx, None)

    @property
    def progress_bar(self):
        """
        :return: Returns the progress bar for showing progress when Excel
        data is being added to the table.
        :rtype: QProgressBar
        """
        return self._pg_par

    def sizeHint(self):
        return QSize(480, 360)

    def clear_view(self):
        # Removes and deletes all sheet widgets and resets the widget registry index.
        self._tbw.clear()
        self._ws_info.clear()

    def reset_view(self):
        # Clears the view and add an empty default sheet.
        self.clear_view()
        self._add_default_sheet()

    def _add_default_sheet(self):
        # Add a default/empty sheet to the view.
        def_sheet = HoldersSheetView()
        self._tbw.addTab(def_sheet, self.tr('Sheet 1'))

    def _init_ui(self):
        # Set up layout and widgets
        self._vl = QVBoxLayout()
        self._tbw = QTabWidget()
        self._tbw.setTabShape(QTabWidget.Triangular)
        self._tbw.setTabPosition(QTabWidget.South)
        self._tbw.setStyleSheet('QTabBar::tab:selected { color: green; }')
        self._vl.addWidget(self._tbw)
        self._pg_par = QProgressBar()
        self._pg_par.setVisible(False)
        self._vl.addWidget(self._pg_par)
        self.setLayout(self._vl)

    def add_vector_layer(self, vl):
        """
        Adds data contained in Qgis vector layer object to the view.
        :param vl: Object containing holders data.
        :type vl: QgsVectorLayer
        """
        holders_sheet = HoldersSheetView()
        holders_sheet.date_format = self._dt_format
        name = vl.name()
        idx = self._tbw.addTab(holders_sheet, name)
        self._tbw.setTabToolTip(idx, name)

        holders_sheet.load_qgs_vector_layer(vl)

        # Add worksheet info to collection
        wsi = WorksheetInfo()
        wsi.name = name
        wsi.idx = idx
        wsi.ws_widget = holders_sheet
        wsi.ws = vl

        self._ws_info[wsi.idx] = wsi

    def current_sheet_view(self):
        """
        Gets the sheet view in the current tab view.
        :return: Sheet view widget.
        :rtype: HoldersSheetView
        """
        return self._tbw.currentWidget()

    def sheet_view(self, idx):
        """
        Gets the sheet view widget with the given index.
        :param idx: Index number.
        :type idx: int
        :return: Sheet view widget.
        :rtype: HoldersSheetView
        """
        return self.worksheet_info(idx).ws_widget

    def load_holders_file(self, path):
        """
        Loads the holders data contained in the specified file to the view.
        :param path: Path to file containing holders data.
        :type path: str
        """
        holders_file = QFile(path)
        if not holders_file.exists():
            QMessageBox.critical(
                self, self.tr('Invalid path'),
                u'\'{0}\' {1}'.format(path, self.tr('does not exist.')))

            return

        # Check permissions
        holders_fileinfo = QFileInfo(holders_file)
        if not holders_fileinfo.isReadable():
            QMessageBox.critical(
                self, self.tr('Unreadable file'),
                u'{0} {1}'.format(path, self.tr('is not readable.')))

            return

        # Get file extension
        ext = holders_fileinfo.suffix()

        # Get reader based on suffix
        if ext not in holder_readers:
            msg = 'No reader defined for \'{0}\' file extension'.format(ext)
            QMessageBox.critical(self, self.tr('Invalid Extension'), msg)

            return

        reader = holder_readers[ext]

        vl = None

        try:
            # Get vector layer
            vl = reader(path)
        except Exception as ex:
            QMessageBox.critical(self, self.tr('Error Loading Data Source.'),
                                 str(ex))

            return

        if not vl:
            QMessageBox.critical(
                self.parentWidget(), self.tr('Null Data Source'),
                self.tr('Data source object is None, cannot be loaded.'))

            return

        if not vl.isValid():
            err = vl.error()
            if not err.isEmpty():
                err_msg = err.summary()
            else:
                err_msg = 'The holders data source is invalid.'

            QMessageBox.critical(self.parentWidget(),
                                 self.tr('Invalid Data Source'), err_msg)

            return

        # Clear view
        self.clear_view()

        # Show progress bar
        self._pg_par.setVisible(True)
        pg_val = 0

        # Add vector layer to the view
        self._pg_par.setRange(0, 1)
        self.add_vector_layer(vl)

        self._pg_par.setValue(1)

        self._pg_par.setVisible(False)
class GUI(QWidget):
    def __init__(self, parent=None):
        global f
        f = open(filename, "a")
        f.write("Widget init.\n")
        f.close()
        QWidget.__init__(self, parent, Qt.WindowStaysOnTopHint)
        self.__setup_gui__(self)
        self._flag = False
        self._change = False
        f = open(filename, "a")
        f.write("End of widget init.\n")
        f.close()

    def closeEvent(self, event):
        reply = QMessageBox.question(self, "Confirm",
                                     "Are you sure You want to quit?",
                                     QMessageBox.Yes | QMessageBox.No,
                                     QMessageBox.No)
        if reply == QMessageBox.Yes: event.accept()
        else: event.ignore()

    def __setup_gui__(self, Dialog):
        global f
        f = open(filename, "a")
        f.write("Setup of gui.\n")
        f.close()
        Dialog.setObjectName("Dialog")
        Dialog.resize(270, 145)
        self.setWindowTitle("Map Layer")
        screen = QDesktopWidget().screenGeometry()
        size = self.geometry()
        self.move((screen.width() - size.width()) / 2,
                  (screen.height() - size.height()) / 2)
        self.Render = QPushButton("Render", Dialog)
        self.Render.setGeometry(QRect(85, 90, 100, 25))
        self.Render.setObjectName("Render")
        self.comboBox = QComboBox(Dialog)
        self.comboBox.setGeometry(QRect(100, 34, 115, 18))
        self.comboBox.setEditable(False)
        self.comboBox.setMaxVisibleItems(11)
        self.comboBox.setInsertPolicy(QComboBox.InsertAtBottom)
        self.comboBox.setObjectName("comboBox")
        self.comboBox.addItems([
            "Google Roadmap", "Google Terrain", "Google Satellite",
            "Google Hybrid", "Yahoo Roadmap", "Yahoo Satellite",
            "Yahoo Hybrid", "Bing Roadmap", "Bing Satellite", "Bing Hybrid",
            "Open Street Maps"
        ])
        self.comboBox.setCurrentIndex(10)
        self.label1 = QLabel("Source:", Dialog)
        self.label1.setGeometry(QRect(55, 35, 35, 16))
        self.label1.setObjectName("label1")
        self.slider = QSlider(Dialog)
        self.slider.setOrientation(Qt.Horizontal)
        self.slider.setMinimum(1)
        self.slider.setMaximum(12)
        self.slider.setValue(4)
        self.slider.setGeometry(QRect(110, 61, 114, 16))
        self.label2 = QLabel("Quality: " + str(self.slider.value()), Dialog)
        self.label2.setGeometry(QRect(47, 61, 54, 16))
        self.label2.setObjectName("label2")
        self.doubleSpinBox = QDoubleSpinBox(Dialog)
        self.doubleSpinBox.setGeometry(QRect(160, 5, 40, 20))
        self.doubleSpinBox.setDecimals(0)
        self.doubleSpinBox.setObjectName("doubleSpinBox")
        self.doubleSpinBox.setMinimum(10.0)
        self.doubleSpinBox.setValue(20.0)
        self.doubleSpinBox.setEnabled(False)
        self.checkBox = QCheckBox("Auto refresh", Dialog)
        self.checkBox.setGeometry(QRect(50, 6, 100, 20))
        self.checkBox.setLayoutDirection(Qt.RightToLeft)
        self.checkBox.setObjectName("checkBox")
        self.progressBar = QProgressBar(Dialog)
        self.progressBar.setGeometry(QRect(5, 130, 260, 10))
        self.progressBar.setProperty("value", 0)
        self.progressBar.setTextVisible(False)
        self.progressBar.setObjectName("progressBar")
        self.progressBar.setVisible(False)
        QObject.connect(self.Render, SIGNAL("clicked()"), Dialog.__repaint__)
        QMetaObject.connectSlotsByName(Dialog)
        QObject.connect(self.slider, SIGNAL("valueChanged(int)"),
                        self.__update_slider_label__)
        QObject.connect(self.comboBox, SIGNAL("activated(int)"),
                        self.__combobox_changed__)
        self.timerRepaint = QTimer()
        QObject.connect(self.checkBox, SIGNAL("clicked()"),
                        self.__activate_timer__)
        QObject.connect(self.timerRepaint, SIGNAL("timeout()"),
                        self.__on_timer__)
        f = open(filename, "a")
        f.write("End of setup of gui.\n")
        f.close()

    def __combobox_changed__(self):
        self._change = True

    def __activate_timer__(self):
        self.doubleSpinBox.setEnabled(self.checkBox.isChecked())
        if self.checkBox.isChecked():
            self.timerRepaint.start(self.doubleSpinBox.value() * 1000)
            self.Render.setEnabled(False)
            if _progress == 0: self.__repaint__()
        else:
            self.timerRepaint.stop()
            self.Render.setEnabled(True)

    def __get_net_size__(self):
        global f
        f = open(filename, "a")
        f.write("Geting net size...\n")
        f.close()
        if not os.path.exists(Paths["Screenshot"]):
            Visum.Graphic.Screenshot(Paths["Screenshot"])
        size = Image.open(Paths["Screenshot"]).size
        f = open(filename, "a")
        f.write("Read net size:" + str(size) + ".\n")
        f.close()
        return size

    def __on_timer__(self):
        global _paramGlobal
        self._flag = False
        Visum.Graphic.MaximizeNetWindow()
        param = _paramGlobal
        _paramGlobal = Visum.Graphic.GetWindow()
        shift = abs((param[0] - _paramGlobal[0]) / (param[2] - param[0]))
        zoom = abs((param[2] - param[0]) /
                   (_paramGlobal[2] - _paramGlobal[0]) - 1)
        print _windowSizeGlobal
        if _windowSizeGlobal[2:4] != Visum.Graphic.GetMainWindowPos()[2:4]:
            self.__get_net_size__()
            self._flag = True
        elif shift > 0.4 or zoom > 0.2:
            self._flag = True
        if self._flag or self._change and _progress == 0:
            self.__repaint__()
            self._change = False

    def __update_slider_label__(self, value):
        self.label2.setText("Quality: " + str(value))
        self._change = True

    def __update_progress_bar__(self):
        if _progress != 0:
            self.progressBar.setVisible(True)
            self.progressBar.setValue(_progress)
        else:
            self.progressBar.setVisible(False)

    def __rebuild_paths__(self):
        global Paths
        Paths["Images"] = []
        list = os.listdir(Paths["ScriptFolder"])
        imageList = []
        for i in range(len(list)):
            if list[i][-3:] == "png": imageList.append(list[i])
        for i in range(len(imageList)):
            try:
                Visum.Graphic.Backgrounds.ItemByKey(imageList[i])
                Paths["Images"].append(Paths["ScriptFolder"] + "\\" +
                                       imageList[i])
            except:
                pass

    def __repaint__(self):
        global _progress, f
        if len(Visum.Graphic.Backgrounds.GetAll) != len(Paths["Images"]):
            self.__rebuild_paths__()
        if _progress == 0:
            f = open(filename, "a")
            f.write("Doing repaint...\n")
            f.close()
            QWebSettings.clearMemoryCaches()
            timer = QTimer()
            timer.start(100)
            QObject.connect(timer, SIGNAL("timeout()"),
                            self.__update_progress_bar__)
            Main(self.comboBox.currentIndex(), Visum.Graphic.GetWindow(),
                 self.slider.value() / 4.0, self.__get_net_size__())
        Visum.Graphic.Draw()
        self.__update_progress_bar__()
        _progress = 0
        QTimer().singleShot(1500, self.__update_progress_bar__)
        f = open(filename, "a")
        f.write("End of doing repaint.\n")
        f.close()
Exemple #28
0
class SearchWidget(QFrame):
    """Widget, appeared, when Ctrl+F pressed.
    Has different forms for different search modes
    """

    Normal = "normal"
    Good = "good"
    Bad = "bad"
    Incorrect = "incorrect"

    visibilityChanged = pyqtSignal(bool)
    """
    visibilityChanged(visible)
    
    **Signal** emitted, when widget has been shown or hidden
    """  # pylint: disable=W0105

    searchInDirectoryStartPressed = pyqtSignal(type(re.compile("")), list, unicode)
    """
    searchInDirectoryStartPressed(regEx, mask, path)
    
    **Signal** emitted, when 'search in directory' button had been pressed
    """  # pylint: disable=W0105

    searchInDirectoryStopPressed = pyqtSignal()
    """
    searchInDirectoryStopPressed()
    
    **Signal** emitted, when 'stop search in directory' button had been pressed
    """  # pylint: disable=W0105

    replaceCheckedStartPressed = pyqtSignal(unicode)
    """
    replaceCheckedStartPressed(replText)
    
    **Signal** emitted, when 'replace checked' button had been pressed
    """  # pylint: disable=W0105

    replaceCheckedStopPressed = pyqtSignal()
    """
    replaceCheckedStartPressed()
    
    **Signal** emitted, when 'stop replacing checked' button had been pressed
    """  # pylint: disable=W0105

    searchRegExpChanged = pyqtSignal(type(re.compile("")))
    """
    searchRegExpValidStateChanged(regEx)
    
    **Signal** emitted, when search regexp has been changed.
    If reg exp is invalid - regEx object contains empty pattern
    """  # pylint: disable=W0105

    searchNext = pyqtSignal()
    """
    searchNext()
    
    **Signal** emitted, when 'Search Next' had been pressed
    """  # pylint: disable=W0105

    searchPrevious = pyqtSignal()
    """
    searchPrevious()
    
    **Signal** emitted, when 'Search Previous' had been pressed
    """  # pylint: disable=W0105

    replaceFileOne = pyqtSignal(unicode)
    """
    replaceFileOne(replText)
    
    **Signal** emitted, when 'Replace' had been pressed
    """  # pylint: disable=W0105

    replaceFileAll = pyqtSignal(unicode)
    """
    replaceFileAll(replText)
    
    **Signal** emitted, when 'Replace All' had been pressed
    """  # pylint: disable=W0105

    def __init__(self, plugin):
        QFrame.__init__(self, core.workspace())
        self._mode = None
        self.plugin = plugin
        from PyQt4 import uic  # lazy import for better startup performance

        uic.loadUi(os.path.join(os.path.dirname(__file__), "SearchWidget.ui"), self)

        self.cbSearch.setCompleter(None)
        self.cbReplace.setCompleter(None)
        self.cbMask.setCompleter(None)

        self.fsModel = QDirModel(self.cbPath.lineEdit())
        self.fsModel.setFilter(QDir.AllDirs | QDir.NoDotAndDotDot)
        self.cbPath.lineEdit().setCompleter(QCompleter(self.fsModel, self.cbPath.lineEdit()))
        # TODO QDirModel is deprecated but QCompleter does not yet handle
        # QFileSystemodel - please update when possible."""
        self.cbSearch.setCompleter(None)
        self.pbSearchStop.setVisible(False)
        self.pbReplaceCheckedStop.setVisible(False)

        self._progress = QProgressBar(self)
        self._progress.setAlignment(Qt.AlignCenter)
        self._progress.setToolTip(self.tr("Search in progress..."))
        self._progress.setMaximumSize(QSize(80, 16))
        core.mainWindow().statusBar().insertPermanentWidget(1, self._progress)
        self._progress.setVisible(False)

        # cd up action
        self.tbCdUp = QToolButton(self.cbPath.lineEdit())
        self.tbCdUp.setIcon(QIcon(":/enkiicons/go-up.png"))
        self.tbCdUp.setCursor(Qt.ArrowCursor)
        self.tbCdUp.installEventFilter(self)  # for drawing button

        self.cbSearch.installEventFilter(self)  # for catching Tab and Shift+Tab
        self.cbReplace.installEventFilter(self)  # for catching Tab and Shift+Tab
        self.cbPath.installEventFilter(self)  # for catching Tab and Shift+Tab
        self.cbMask.installEventFilter(self)  # for catching Tab and Shift+Tab

        self._closeShortcut = QShortcut(QKeySequence("Esc"), self)
        self._closeShortcut.setContext(Qt.WidgetWithChildrenShortcut)
        self._closeShortcut.activated.connect(self.hide)

        # connections
        self.cbSearch.lineEdit().textChanged.connect(self._onSearchRegExpChanged)

        self.cbSearch.lineEdit().returnPressed.connect(self._onReturnPressed)
        self.cbReplace.lineEdit().returnPressed.connect(self._onReturnPressed)
        self.cbPath.lineEdit().returnPressed.connect(self._onReturnPressed)
        self.cbMask.lineEdit().returnPressed.connect(self._onReturnPressed)

        self.cbRegularExpression.stateChanged.connect(self._onSearchRegExpChanged)
        self.cbCaseSensitive.stateChanged.connect(self._onSearchRegExpChanged)

        self.tbCdUp.clicked.connect(self._onCdUpPressed)

        core.mainWindow().hideAllWindows.connect(self.hide)
        core.workspace().currentDocumentChanged.connect(
            lambda old, new: self.setVisible(self.isVisible() and new is not None)
        )

    def show(self):
        """Reimplemented function. Sends signal
        """
        super(SearchWidget, self).show()
        self.visibilityChanged.emit(self.isVisible())

    def hide(self):
        """Reimplemented function.
        Sends signal, returns focus to workspace
        """
        super(SearchWidget, self).hide()
        core.workspace().focusCurrentDocument()
        self.visibilityChanged.emit(self.isVisible())

    def setVisible(self, visible):
        """Reimplemented function. Sends signal
        """
        super(SearchWidget, self).setVisible(visible)
        self.visibilityChanged.emit(self.isVisible())

    def _regExEscape(self, text):
        """Improved version of re.escape()
        Doesn't escape space, comma, underscore.
        Escapes \n and \t
        """
        text = re.escape(text)
        # re.escape escapes space, comma, underscore, but, it is not necessary and makes text not readable
        for symbol in " ,_='\"/:@#%&":
            text = text.replace("\\" + symbol, symbol)

        text = text.replace("\\\n", "\\n")
        text = text.replace("\\\t", "\\t")

        return text

    def _makeEscapeSeqsVisible(self, text):
        """Replace invisible \n and \t with escape sequences
        """
        text = text.replace("\t", "\\t")
        text = text.replace("\n", "\\n")
        return text

    def setMode(self, mode):
        """Change search mode.
        i.e. from "Search file" to "Replace directory"
        """
        if self._mode == mode and self.isVisible():
            if core.workspace().currentDocument() is not None and not core.workspace().currentDocument().hasFocus():
                self.cbSearch.lineEdit().selectAll()
                self.cbSearch.setFocus()

        self._mode = mode

        # Set Search and Replace text
        if (
            core.workspace().currentDocument() is not None
            and core.workspace().currentDocument().hasFocus()
            and core.workspace().currentDocument().selectedText()
        ):
            searchText = core.workspace().currentDocument().selectedText()

            self.cbReplace.setEditText(self._makeEscapeSeqsVisible(searchText))

            if self.cbRegularExpression.checkState() == Qt.Checked:
                searchText = self._regExEscape(searchText)
            self.cbSearch.setEditText(searchText)

        if (
            not self.cbReplace.lineEdit().text()
            and self.cbSearch.lineEdit().text()
            and not self.cbRegularExpression.checkState() == Qt.Checked
        ):
            self.cbReplace.setEditText(self.cbSearch.lineEdit().text())

        # Move focus to Search edit
        self.cbSearch.setFocus()
        self.cbSearch.lineEdit().selectAll()

        # Set search path
        if mode & ModeFlagDirectory and not (self.isVisible() and self.cbPath.isVisible()):
            try:
                searchPath = os.path.abspath(unicode(os.path.curdir))
                self.cbPath.setEditText(searchPath)
            except OSError:  # current directory might have been deleted
                pass

        # Set widgets visibility flag according to state
        widgets = (
            self.wSearch,
            self.pbPrevious,
            self.pbNext,
            self.pbSearch,
            self.wReplace,
            self.wPath,
            self.pbReplace,
            self.pbReplaceAll,
            self.pbReplaceChecked,
            self.wOptions,
            self.wMask,
        )
        #                         wSear  pbPrev pbNext pbSear wRepl  wPath  pbRep  pbRAll pbRCHK wOpti wMask
        visible = {
            ModeSearch: (1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0),
            ModeReplace: (1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0),
            ModeSearchDirectory: (1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1),
            ModeReplaceDirectory: (1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1),
            ModeSearchOpenedFiles: (1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1),
            ModeReplaceOpenedFiles: (1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1),
        }

        for i, widget in enumerate(widgets):
            widget.setVisible(visible[mode][i])

        # Search next button text
        if mode == ModeReplace:
            self.pbNext.setText("Next")
        else:
            self.pbNext.setText(u"Next↵")

        # Finaly show all with valid size
        self.show()  # show before updating widgets and labels
        self._updateLabels()
        self._updateWidgets()

    def eventFilter(self, object_, event):
        """ Event filter for mode switch tool button
        Draws icons in the search and path lineEdits
        """
        if event.type() == QEvent.Paint and object_ is self.tbCdUp:  # draw CdUp button in search path QLineEdit
            toolButton = object_
            lineEdit = self.cbPath.lineEdit()
            lineEdit.setContentsMargins(lineEdit.height(), 0, 0, 0)

            height = lineEdit.height()
            availableRect = QRect(0, 0, height, height)

            if toolButton.rect() != availableRect:
                toolButton.setGeometry(availableRect)

            painter = QPainter(toolButton)
            toolButton.icon().paint(painter, availableRect)

            return True

        elif event.type() == QEvent.KeyPress:  # Tab and Shift+Tab in QLineEdits

            if event.key() == Qt.Key_Tab:
                self._moveFocus(1)
                return True
            elif event.key() == Qt.Key_Backtab:
                self._moveFocus(-1)
                return True

        return QFrame.eventFilter(self, object_, event)

    def _onReturnPressed(self):
        """Return or Enter pressed on widget.
        Search next or Replace next
        """
        if self.pbReplace.isVisible():
            self.pbReplace.click()
        elif self.pbNext.isVisible():
            self.pbNext.click()
        elif self.pbSearch.isVisible():
            self.pbSearch.click()
        elif self.pbSearchStop.isVisible():
            self.pbSearchStop.click()

    def _moveFocus(self, step):
        """Move focus forward or backward according to step.
        Standard Qt Keyboard focus algorithm doesn't allow circular navigation
        """
        allFocusableWidgets = (self.cbSearch, self.cbReplace, self.cbPath, self.cbMask)
        visibleWidgets = [widget for widget in allFocusableWidgets if widget.isVisible()]

        try:
            focusedIndex = visibleWidgets.index(QApplication.focusWidget())
        except ValueError:
            print >>sys.stderr, "Invalid focused widget in Search Widget"
            return

        nextFocusedIndex = (focusedIndex + step) % len(visibleWidgets)

        visibleWidgets[nextFocusedIndex].setFocus()
        visibleWidgets[nextFocusedIndex].lineEdit().selectAll()

    def _updateLabels(self):
        """Update 'Search' 'Replace' 'Path' labels geometry
        """
        width = 0

        if self.lSearch.isVisible():
            width = max(width, self.lSearch.minimumSizeHint().width())

        if self.lReplace.isVisible():
            width = max(width, self.lReplace.minimumSizeHint().width())

        if self.lPath.isVisible():
            width = max(width, self.lPath.minimumSizeHint().width())

        self.lSearch.setMinimumWidth(width)
        self.lReplace.setMinimumWidth(width)
        self.lPath.setMinimumWidth(width)

    def _updateWidgets(self):
        """Update geometry of widgets with buttons
        """
        width = 0

        if self.wSearchRight.isVisible():
            width = max(width, self.wSearchRight.minimumSizeHint().width())

        if self.wReplaceRight.isVisible():
            width = max(width, self.wReplaceRight.minimumSizeHint().width())

        if self.wPathRight.isVisible():
            width = max(width, self.wPathRight.minimumSizeHint().width())

        self.wSearchRight.setMinimumWidth(width)
        self.wReplaceRight.setMinimumWidth(width)
        self.wPathRight.setMinimumWidth(width)

    def _updateComboBoxes(self):
        """Update comboboxes with last used texts
        """
        searchText = self.cbSearch.currentText()
        replaceText = self.cbReplace.currentText()
        maskText = self.cbMask.currentText()

        # search
        if searchText:
            index = self.cbSearch.findText(searchText)

            if index == -1:
                self.cbSearch.addItem(searchText)

        # replace
        if replaceText:
            index = self.cbReplace.findText(replaceText)

            if index == -1:
                self.cbReplace.addItem(replaceText)

        # mask
        if maskText:
            index = self.cbMask.findText(maskText)

            if index == -1:
                self.cbMask.addItem(maskText)

    def _searchPatternTextAndFlags(self):
        """Get search pattern and flags
        """
        pattern = self.cbSearch.currentText()
        if not self.cbRegularExpression.checkState() == Qt.Checked:
            pattern = re.escape(pattern)
        flags = 0
        if not self.cbCaseSensitive.checkState() == Qt.Checked:
            flags = re.IGNORECASE
        return pattern, flags

    def getRegExp(self):
        """Read search parameters from controls and present it as a regular expression
        """
        pattern, flags = self._searchPatternTextAndFlags()
        return re.compile(pattern, flags)

    def isSearchRegExpValid(self):
        """Try to compile search pattern to check if it is valid
        Returns bool result and text error
        """
        pattern, flags = self._searchPatternTextAndFlags()
        try:
            re.compile(pattern, flags)
        except re.error, ex:
            return False, unicode(ex)

        return True, None
Exemple #29
0
class MibMainwindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        self.__setup_ui()
        self.__connect_slot()
        self.__entity_parser = EntityParser()
        self.__entity_parser.parse()

    def __setup_ui(self):
        self.resize(1024, 768)
        self.__setup_menu()

        split = QSplitter()
        self.__mib_tree_widget = MibTreeWidget()
        split.addWidget(self.__mib_tree_widget)
        #
        self.__data_widget = DataWidget()
        split.addWidget(self.__data_widget)
        split.setHandleWidth(2)
        split.setStretchFactor(0, 1)
        split.setStretchFactor(1, 200)

        la = QVBoxLayout()
        self.__progress_bar = QProgressBar()
        self.__progress_bar.setValue(0)
        self.__progress_bar.setVisible(False)
        la.addWidget(self.__progress_bar, 1)
        la.addWidget(split, 1)

        cw = QWidget()
        cw.setLayout(la)

        self.setCentralWidget(cw)

    def __setup_menu(self):
        fileMenu = QMenu("Db", self)
        profileMenu = QMenu('Profiles', self)

        self.menuBar().addMenu(fileMenu)
        self.menuBar().addMenu(profileMenu)

        self.__new_action = QAction(QIcon(ICON_IDR + 'add_database.png'),
                                    "&New", fileMenu)
        fileMenu.addAction(self.__new_action)

        self.__profile_action = QAction(QIcon(ICON_IDR + 'profiles.png'),
                                        "&Open profiles", profileMenu)
        profileMenu.addAction(self.__profile_action)

        tool_bar = QToolBar()
        tool_bar.setMovable(False)
        tool_bar.setToolButtonStyle(Qt.ToolButtonIconOnly)
        tool_bar.addAction(self.__new_action)
        tool_bar.addAction(self.__profile_action)
        tool_bar.setIconSize(QSize(30, 30))
        #tool_bar.setStyleSheet("QToolButton { padding-left: 5px; padding-right: 5px; }  QToolBar{padding-left: 5px; padding-right: 5px}")

        self.addToolBar(tool_bar)

    def __connect_slot(self):
        self.connect(self.__new_action, SIGNAL('triggered()'), self,
                     SLOT('__on_new_action()'))
        self.connect(
            self.__mib_tree_widget,
            SIGNAL(
                'table_double_clicked(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)'
            ), self,
            SLOT(
                '__on_table_double_clicked(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)'
            ))

    @pyqtSlot()
    def __on_new_action(self):
        new_dlg = NewConnectionDlg()
        if new_dlg.exec_():

            # for i in range(0,100):
            #     self.__progress_bar.setValue(i)
            #     time.sleep(0.01)
            #     QApplication.processEvents()
            # self.__progress_bar.setValue(100)

            olt_key = ConnectionManager().add_dolt_connection(
                '192.168.200.131', 9192, '111')
            onu_key = ConnectionManager().add_onu_communicator(olt_key,
                                                               slot_id=1,
                                                               intf_id=0,
                                                               onu_id=1)
            task = MibLoadTask()

            self.__progress_bar.setVisible(True)
            for i, n in task.do(onu_key):
                self.__progress_bar.setValue(i * 100 / n)
                QApplication.processEvents()

            self.__progress_bar.setValue(100)
            self.__progress_bar.setVisible(False)
            mib = task.get_mib()

            # mib = Mib()
            # mib.load_from_file()
            keys = []
            for k in mib.get_keys():
                keys.append(self.__entity_parser.get_cls_name_by_id(k))
            self.__mib_tree_widget.add_mib_tree('192.168.200.131', 9192, 1, 0,
                                                1, keys)

    @pyqtSlot('PyQt_PyObject', 'PyQt_PyObject', 'PyQt_PyObject')
    def __on_table_double_clicked(self, identify, me_name, label_color):
        # table_name type is PyQt4.QtCore.QString,con_key type is str
        mib = Mib()
        mib.load_from_file()
        #self.__data_widget.add_tab(identify, to_python_str(con_key), to_python_str(table_name), label_color)
        me_id = self.__entity_parser.get_me_id_by_me_name(me_name)
        self.__data_widget.add_tab(identify,
                                   self.__entity_parser.get_cls_by_id(me_id),
                                   mib.get_entity_class_value(me_id),
                                   label_color)