class TrackProgressDialog(QDialog): finished = pyqtSignal() def __init__(self, parent=None, numStages=1): QDialog.__init__(self, parent) self.currentStep = 0 self.progress = None l = QVBoxLayout() self.setLayout(l) self.overallProgress = QProgressBar() self.overallProgress.setRange(0, numStages) self.overallProgress.setFormat("step %v of " + str(numStages)) self.currentStepProgress = QProgressBar() self.currentStepProgress.setRange(0, 100) self.currentStepProgress.setFormat("%p %") self.overallLabel = QLabel("Overall progress") self.currentStepLabel = QLabel("Current step") l.addWidget(self.overallLabel) l.addWidget(self.overallProgress) l.addWidget(self.currentStepLabel) l.addWidget(self.currentStepProgress) l.maximumSize() self.update() def __onNewStep(self, description): self.currentStep += 1 self.currentStepProgress.setValue(0) self.overallProgress.setValue(self.currentStep) self.currentStepLabel.setText(description) self.update() def __onCurrentStepProgressChanged(self, progress): timesHundred = round(1000.0 * progress) timesTen = round(100.0 * progress) if (not self.currentStepProgress.value() == timesTen) and (timesHundred - 10 * timesTen) == 0: self.currentStepProgress.setValue(timesTen) self.update() def run(self): self.trackProgress = TrackProgress(self) self.trackProgress.progress.connect( self.__onCurrentStepProgressChanged, Qt.BlockingQueuedConnection) self.trackProgress.newStep.connect(self.__onNewStep, Qt.BlockingQueuedConnection) self.trackProgress.done.connect(self.onTrackDone) self.trackProgress.start() def onTrackDone(self): self.trackProgress.wait( ) # Join the extractor thread so its safe to immediately destroy the window self.finished.emit() self.close()
def _before_upload(self, doc_type): """ Activated just before an upload. It disables user actions and shows a progress bar. """ doc_info = self.row_document_info_from_type(doc_type) if not doc_info: return row_num = doc_info.row_num # Disable user actions in the given row self._enable_user_action_widgets( row_num, False ) # Show progress bar pg_bar = QProgressBar() pg_bar.setRange(0, 0) pg_bar.setTextVisible(False) # Remove text before showing progress bar ti = self.item(row_num, 2) ti.setText('') self.setCellWidget(row_num, 2, pg_bar)
def _createTrackProgress(self, parent, track): w = QWidget(parent) l = QVBoxLayout(w) p = QProgressBar(w) p.setRange(0, 100) p.setValue(track['progress']) w.progress = p label = QLabel(w) label.setContentsMargins(5, 2, 5, 2) label.setOpenExternalLinks(True) label.setWordWrap(True) if track['name'] is not None: label.setText(track['name']) elif track['error']: label.setText('<font color="red">%s</font>' % track['error']) p.setValue(100) w.label = label l.addWidget(label) l.addWidget(p) w.setLayout(l) return w
def __init__(self, parent=None): from radiance import __version__ self.__version = __version__ self.parent = parent pixmap = QPixmap(QString(':/Radiance/splashscreen.png')) flags = Qt.WindowStaysOnTopHint QSplashScreen.__init__(self, pixmap, flags) self.setMask(pixmap.mask()) # Custom progress bar stylesheet progressbar_stylesheet = """ QProgressBar:horizontal { border: 1px solid black; background: white; padding: 1px; } QProgressBar::chunk:horizontal { background-color: qlineargradient(spread: pad, x1: 1, y1: 0.5, x2: 0, y2: 0.5, stop: 0 black, stop: 1 white); } """ # Place progress bar to bottom of splash screen. progressbar = QProgressBar(self) progressbar.setRange(0, 0) progressbar.setGeometry(10, self.height() - 20, self.width() - 20, 10) progressbar.setTextVisible(False) progressbar.setStyleSheet(progressbar_stylesheet) self.progressbar = progressbar self.show()
class progressBar: def __init__(self, parent, msg='', steps=0): ''' progressBar class instatiation method. It creates a QgsMessageBar with provided msg and a working QProgressBar :param parent: :param msg: string ''' self.iface = parent.iface widget = self.iface.messageBar().createMessage("fdtm plugin:", msg) self.progressBar = QProgressBar() self.progressBar.setRange(0, steps) #(1,steps) self.progressBar.setValue(0) self.progressBar.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) widget.layout().addWidget(self.progressBar) qApp.processEvents() self.iface.messageBar().pushWidget(widget, QgsMessageBar.INFO, 50) qApp.processEvents() def setStep(self, step): self.progressBar.setValue(step) qApp.processEvents() def stop(self, msg=''): ''' the progressbar is stopped with a succes message :param msg: string :return: ''' self.iface.messageBar().clearWidgets() message = self.iface.messageBar().createMessage("fdtm plugin:", msg) self.iface.messageBar().pushWidget(message, QgsMessageBar.SUCCESS, 3)
def downloadBtnClicked(self): # TODO: disable search button till the downloads finish or stopped manually self.ui.downloadBtn.setText("Please wait...") self.ui.downloadBtn.setEnabled(False) QtGui.QApplication.processEvents() selected_range = self.ui.chapterTable.selectedRanges() selected_range = [i for r in selected_range for i in range(r.topRow(), r.bottomRow() + 1)] # "selected_range" is a list of positions in table print "{} items selected".format(len(selected_range)) for i in selected_range: try: index = i file = DownloadFile(self.course.getMp4UrlMirror(index), self.get_file_path(index), index, lambda index, size, tot, i=index: self.updateProgress.emit( index, size, tot, i)) pg = QProgressBar() pg.setRange(0, 100) pg.setValue(0) self.ui.chapterTable.setCellWidget(i, 1, pg) self.downloadQueue.addToQueue(file) print file.fileName + " Added to download queue" except Exception as e: pass self.ui.downloadBtn.setText("Start Download") self.ui.downloadBtn.setEnabled(True) QtGui.QApplication.processEvents()
class BusyBar(QThread): """ Adapted from: http://stackoverflow.com/questions/8007602/ looping-qprogressbar-gives-error-qobjectinstalleventfilter-cannot-filter-e Looping progress bar create the signal that the thread will emit .. note:: This function creates a busy bar but I have not figured out how to \ attach it to a process. Therefore, it is currently functionally \ useless. """ changeValue = pyqtSignal(int) def __init__(self, text=""): QThread.__init__(self, parent=None) self.text = text self.stop = False self.proBar = QProgressBar() self.proBar.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.SplashScreen) self.proBar.setRange(0, 100) self.proBar.setTextVisible(True) self.proBar.setFormat(self.text) self.proBar.setValue(0) self.proBar.setFixedSize(300, 40) self.proBar.setAlignment(Qt.AlignCenter) self.proBar.show() #self.changeValue.connect(self.proBar.setValue, Qt.QueuedConnection) # Make the Busybar delete itself and the QProgressBar when done self.finished.connect(self.onFinished) def run(self): """ """ while not self.stop: # keep looping while self is visible # Loop sending mail for i in range(100): # emit the signal instead of calling setValue # also we can't read the progress bar value from the thread self.changeValue.emit(i) time.sleep(0.01) self.changeValue.emit(0) def onFinished(self): """ """ self.proBar.deleteLater() self.deleteLater() def Kill(self): """ """ self.stop = True
class BusyBar(QThread): """ Adapted from: http://stackoverflow.com/questions/8007602/ looping-qprogressbar-gives-error-qobjectinstalleventfilter-cannot-filter-e Looping progress bar create the signal that the thread will emit .. note:: This function creates a busy bar but I have not figured out how to \ attach it to a process. Therefore, it is currently functionally \ useless. """ changeValue = pyqtSignal(int) def __init__(self, text = "" ): QThread.__init__(self, parent = None) self.text = text self.stop = False self.proBar = QProgressBar() self.proBar.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.SplashScreen ) self.proBar.setRange( 0, 100 ) self.proBar.setTextVisible( True ) self.proBar.setFormat( self.text ) self.proBar.setValue( 0 ) self.proBar.setFixedSize( 300 , 40 ) self.proBar.setAlignment(Qt.AlignCenter) self.proBar.show() #self.changeValue.connect(self.proBar.setValue, Qt.QueuedConnection) # Make the Busybar delete itself and the QProgressBar when done self.finished.connect(self.onFinished) def run(self): """ """ while not self.stop: # keep looping while self is visible # Loop sending mail for i in range(100): # emit the signal instead of calling setValue # also we can't read the progress bar value from the thread self.changeValue.emit( i ) time.sleep(0.01) self.changeValue.emit( 0 ) def onFinished(self): """ """ self.proBar.deleteLater() self.deleteLater() def Kill(self): """ """ self.stop = True
class ThreadManagerDialog(QDialog): def __init__( self, iface, title="Worker Thread"): QDialog.__init__( self, iface)#.mainWindow() ) self.iface = iface self.setWindowTitle(title) self.setLayout(QVBoxLayout()) self.primaryLabel = QLabel(self) self.layout().addWidget(self.primaryLabel) self.primaryBar = QProgressBar(self) self.layout().addWidget(self.primaryBar) self.secondaryLabel = QLabel(self) self.layout().addWidget(self.secondaryLabel) self.secondaryBar = QProgressBar(self) self.layout().addWidget(self.secondaryBar) self.closeButton = QPushButton("Close") self.closeButton.setEnabled(False) self.layout().addWidget(self.closeButton) self.closeButton.clicked.connect(self.reject) def run(self): self.runThread() self.exec_() def runThread( self): QObject.connect( self.workerThread, SIGNAL( "jobFinished( PyQt_PyObject )" ), self.jobFinishedFromThread ) QObject.connect( self.workerThread, SIGNAL( "primaryValue( PyQt_PyObject )" ), self.primaryValueFromThread ) QObject.connect( self.workerThread, SIGNAL( "primaryRange( PyQt_PyObject )" ), self.primaryRangeFromThread ) QObject.connect( self.workerThread, SIGNAL( "primaryText( PyQt_PyObject )" ), self.primaryTextFromThread ) QObject.connect( self.workerThread, SIGNAL( "secondaryValue( PyQt_PyObject )" ), self.secondaryValueFromThread ) QObject.connect( self.workerThread, SIGNAL( "secondaryRange( PyQt_PyObject )" ), self.secondaryRangeFromThread ) QObject.connect( self.workerThread, SIGNAL( "secondaryText( PyQt_PyObject )" ), self.secondaryTextFromThread ) self.workerThread.start() def cancelThread( self ): self.workerThread.stop() def jobFinishedFromThread( self, success ): self.workerThread.stop() self.primaryBar.setValue(self.primaryBar.maximum()) self.secondaryBar.setValue(self.secondaryBar.maximum()) self.emit( SIGNAL( "jobFinished( PyQt_PyObject )" ), success ) self.closeButton.setEnabled( True ) def primaryValueFromThread( self, value ): self.primaryBar.setValue(value) def primaryRangeFromThread( self, range_vals ): self.primaryBar.setRange( range_vals[ 0 ], range_vals[ 1 ] ) def primaryTextFromThread( self, value ): self.primaryLabel.setText(value) def secondaryValueFromThread( self, value ): self.secondaryBar.setValue(value) def secondaryRangeFromThread( self, range_vals ): self.secondaryBar.setRange( range_vals[ 0 ], range_vals[ 1 ] ) def secondaryTextFromThread( self, value ): self.secondaryLabel.setText(value)
class BlockingTask(QObject): """ Blocking task provides a UI wrapper for long running tasks. While the task is executed a modal progress dialog will be shown. The task can be canceled through the UI. """ load_finished = pyqtSignal(scene.Scene) def __init__(self, scene_load_func, message, *args, **kwargs): super(BlockingTask, self).__init__(*args, **kwargs) self.scene_load_func = scene_load_func self.message = message self.progress_bar = QProgressBar() self.progress_bar.setRange(0, 0) self.worker = None def start_task(self): self._async_execute() def _on_load_finished(self): logger.debug('On task finished') self.scene = self.worker.result if self.scene is not None: self.load_finished.emit(self.scene) self.progress_dialog.hide() def _on_load_start(self): logger.debug('On task start') self.progress_dialog = QProgressDialog(self.message, "Abort", 0, 0, self.parent(), flags=Qt.CustomizeWindowHint, ) self.progress_dialog.setWindowModality(Qt.WindowModal) self.progress_dialog.canceled.connect(self._abort) self.progress_dialog.show() def _abort(self): self.worker.terminate() def _async_execute(self): self._on_load_start() self.worker = TaskWorker(self.scene_load_func) self.worker.task_done.connect(self._on_load_finished) self.worker.start()
def show_progress(i_face, msg): """ Creates and shows a progress bar for some event. Does not have any progress information. Used to show user that something should be happening in the background :param i_face: iface where the progressbar will be shown :param msg: Message to be displayed in front of the progress bar """ # Progress bar (without progress) bar = QProgressBar() bar.setRange(0, 0) progress_msg = i_face.messageBar().createMessage(msg) progress_msg.layout().addWidget(bar) i_face.messageBar().pushWidget(progress_msg, level=0)
def __init__(self, parent, msg = ''): ''' progressBar class instatiation method. It creates a QgsMessageBar with provided msg and a working QProgressBar :param parent: :param msg: string ''' self.iface = parent.iface widget = self.iface.messageBar().createMessage("GooGIS plugin:",msg) progressBar = QProgressBar() progressBar.setRange(0,0) #(1,steps) progressBar.setValue(0) progressBar.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) widget.layout().addWidget(progressBar) QtGui.qApp.processEvents() self.iface.messageBar().pushWidget(widget, QgsMessageBar.INFO, 50) QtGui.qApp.processEvents()
def create_progress_message_bar(iface, msg, no_percentage=False): """ Use the messageBar of QGIS to display a message describing what's going on (typically during a time-consuming task), and a bar showing the progress of the process. :param msg: Message to be displayed, describing the current task :type: str :returns: progress object on which we can set the percentage of completion of the task through progress.setValue(percentage) :rtype: QProgressBar """ progress_message_bar = iface.messageBar().createMessage(msg) progress = QProgressBar() if no_percentage: progress.setRange(0, 0) progress_message_bar.layout().addWidget(progress) iface.messageBar().pushWidget(progress_message_bar, iface.messageBar().INFO) return progress_message_bar, progress
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()
def createUnbefFlaechen(dbQK, liste_selAbflparamTeilgeb, autokorrektur, dbtyp='spatialite'): '''Import der Kanaldaten aus einer HE-Firebird-Datenbank und Schreiben in eine QKan-SpatiaLite-Datenbank. :dbQK: Datenbankobjekt, das die Verknüpfung zur QKan-SpatiaLite-Datenbank verwaltet. :type database: DBConnection (geerbt von dbapi...) :liste_selAbflparamTeilgeb: Liste der bei der Bearbeitung zu berücksichtigenden Kombinationen aus Abflussparameter und Teilgebiet (Tabelle tezg) :type: list :autokorrektur: Option, ob eine automatische Korrektur der Bezeichnungen durchgeführt werden soll. Falls nicht, wird die Bearbeitung mit einer Fehlermeldung abgebrochen. :type autokorrektur: String :dbtyp: Typ der Datenbank (spatialite, postgis) :type dbtyp: String :returns: void Für alle TEZG-Flächen wird, falls nicht schon vorhanden, ein unbefestigtes Flächenobjekt erzeugt. Dazu können in der Auswahlmaske zunächst die Kombinationen aus Abflussparameter und Teilgebiet gewählt werden, die in der Tabelle "tezg" vorkommen und die nachfolgenden Voraussetzungen erfüllen: - Im Feld "abflussparameter" muss auf einen Abflussparameter verwiesen werden, der für unbefestigte Flächen erzeugt wurde (infiltrationsparameter > 0) ''' global progress_bar progress_bar = QProgressBar(iface.messageBar()) progress_bar.setRange(0, 100) status_message = iface.messageBar().createMessage( u"Info", u"Erzeugung von unbefestigten Flächen in Arbeit. Bitte warten.") status_message.layout().addWidget(progress_bar) iface.messageBar().pushWidget(status_message, QgsMessageBar.INFO, 10) # status_message.setText(u"Erzeugung von unbefestigten Flächen ist in Arbeit.") progress_bar.setValue(1) # ------------------------------------------------------------------------------ # Datenbankverbindungen # Kontrolle, ob tezg-Flächen eindeutig Namen haben: if not checknames(dbQK, u'tezg', u'flnam', u'ft_', autokorrektur): return False if not checknames(dbQK, u'flaechen', u'flnam', u'f_', autokorrektur): return False # Prüfung, ob unzulässige Kombinationen ausgewählt wurden if len(liste_selAbflparamTeilgeb) > 0: logger.debug(u'\nliste_selAbflparamTeilgeb (2): {}'.format( liste_selAbflparamTeilgeb)) if False in [(attr[-1] == u'') for attr in liste_selAbflparamTeilgeb]: fehlermeldung( u"Falsche Auswahl", u"Bitte nur zulässige Abflussparameter und Teilgebiete auswählen (siehe Spalte 'Anmerkungen')" ) return False else: sql = u"""SELECT count(*) AS anz FROM tezg AS te LEFT JOIN abflussparameter AS ap ON te.abflussparameter = ap.apnam LEFT JOIN bodenklassen AS bk ON bk.bknam = ap.bodenklasse WHERE te.abflussparameter ISNULL OR bk.infiltrationsrateanfang ISNULL OR bk.infiltrationsrateanfang < 0.00001""" if not dbQK.sql(sql, u'QKan.CreateUnbefFlaechen (1)'): return False data = dbQK.fetchall() if len(data) > 0: if data[0][0] > 0: fehlermeldung( u"Unvollständige Daten", u"In der Tabelle TEZG-Flächen sind noch fehlerhafte Daten zu den Abflussparametern oder den Bodenklassen enthalten. " ) return False # Für die Erzeugung der Restflächen reicht eine SQL-Abfrage aus. # status_message.setText(u"Erzeugung von unbefestigten Flächen") progress_bar.setValue(10) # Vorbereitung des Auswahlkriteriums für die SQL-Abfrage: Kombination aus abflussparameter und teilgebiet # Dieser Block ist identisch in k_unbef und in application enthalten if len(liste_selAbflparamTeilgeb) == 0: auswahl = u'' elif len(liste_selAbflparamTeilgeb) == 1: auswahl = u' AND' elif len(liste_selAbflparamTeilgeb) >= 2: auswahl = u' AND (' else: fehlermeldung(u"Interner Fehler", u"Fehler in Fallunterscheidung!") return False # Anfang SQL-Krierien zur Auswahl der tezg-Flächen first = True for attr in liste_selAbflparamTeilgeb: if attr[4] == u'None' or attr[1] == u'None': fehlermeldung( u'Datenfehler: ', u'In den ausgewählten Daten sind noch Datenfelder nicht definiert ("NULL").' ) return False if first: first = False auswahl += u""" (tezg.abflussparameter = '{abflussparameter}' AND tezg.teilgebiet = '{teilgebiet}')""".format( abflussparameter=attr[0], teilgebiet=attr[1]) else: auswahl += u""" OR\n (tezg.abflussparameter = '{abflussparameter}' AND tezg.teilgebiet = '{teilgebiet}')""".format( abflussparameter=attr[0], teilgebiet=attr[1]) if len(liste_selAbflparamTeilgeb) >= 2: auswahl += u")" # Ende SQL-Krierien zur Auswahl der tezg-Flächen # Erläuterung zur nachfolgenden SQL-Abfrage: # 1. aus der Abfrage werden alle Datensätze ohne geom-Objekte ausgeschlossen # 2. Wenn in einer tezg-Fläche keine Fläche liegt, wird einfach die tezg-Fläche übernommen sql = u"""WITH flbef AS ( SELECT 'fd_' || ltrim(tezg.flnam, 'ft_') AS flnam, tezg.haltnam AS haltnam, tezg.neigkl AS neigkl, tezg.regenschreiber AS regenschreiber, tezg.teilgebiet AS teilgebiet, tezg.abflussparameter AS abflussparameter, 'Erzeugt mit Plugin Erzeuge unbefestigte Flaechen' AS kommentar, MakeValid(tezg.geom) AS geot, ST_Union(MakeValid(flaechen.geom)) AS geob FROM (SELECT * FROM tezg WHERE geom IS NOT NULL) AS tezg LEFT JOIN (SELECT * FROM flaechen WHERE geom IS NOT NULL) AS flaechen ON Intersects(tezg.geom, flaechen.geom) WHERE 'fd_' || ltrim(tezg.flnam, 'ft_') not in ( SELECT flnam FROM flaechen WHERE flnam IS NOT NULL){auswahl} GROUP BY tezg.pk) INSERT INTO flaechen (flnam, haltnam, neigkl, regenschreiber, teilgebiet, abflussparameter, kommentar, geom) SELECT flnam AS flnam, haltnam, neigkl, regenschreiber, teilgebiet, abflussparameter, kommentar, CASE WHEN geob IS NULL THEN geot ELSE CastToMultiPolygon(Difference(geot,geob)) END AS geof FROM flbef WHERE area(geof) > 0.5 AND geof IS NOT NULL""".format( auswahl=auswahl) logger.debug(u'QKan.k_unbef (3) - liste_selAbflparamTeilgeb = \n{}'.format( str(liste_selAbflparamTeilgeb))) if not dbQK.sql(sql, u"QKan.CreateUnbefFlaechen (4)"): return False # # status_message.setText(u"Erstellen der Anbindungen für die unbefestigten Flächen") # progress_bar.setValue(50) # # Hinzufügen von Verknüpfungen in die Tabelle linkfl für die neu erstellten unbefestigten Flächen # sql = u"""INSERT INTO linkfl (flnam, aufteilen, teilgebiet, geom, glink) # SELECT # fl.flnam AS flnam, # NULL AS aufteilen, # fl.teilgebiet AS teilgebiet, # NULL AS geom, # MakeLine(PointOnSurface(fl.geom),Centroid(ha.geom)) AS glink # FROM flaechen AS fl # LEFT JOIN haltungen AS ha # ON fl.haltnam = ha.haltnam # INNER JOIN tezg AS tg # ON 'fd_' || ltrim(tg.flnam, 'ft_') = fl.flnam # WHERE fl.flnam NOT IN # ( SELECT flnam FROM linkfl WHERE flnam IS NOT NULL)""" # if not dbQK.sql(sql, u"QKan.CreateUnbefFlaechen (5)"): # return False # status_message.setText(u"Nachbearbeitung") progress_bar.setValue(90) dbQK.commit() del dbQK # Karte aktualisieren iface.mapCanvas().refreshAllLayers() iface.mainWindow().statusBar().clearMessage() iface.messageBar().pushMessage(u"Information", u"Restflächen sind erstellt!", level=QgsMessageBar.INFO) QgsMessageLog.logMessage(u"\nRestflächen sind erstellt!", level=QgsMessageLog.INFO) progress_bar.setValue(100) status_message.setText( u"Erzeugung von unbefestigten Flächen abgeschlossen.") status_message.setLevel(QgsMessageBar.SUCCESS)
class CarvingProcess(QWidget, EventHandler): def __init__(self, selector, vnode): QWidget.__init__(self) EventHandler.__init__(self) self.vnode = vnode self.filesize = vnode.value().size() self.tm = TaskManager() self.selector = selector self.setLayout(QVBoxLayout()) self.factor = 1 self.parsetime = 0 self.time = time.time() self.starttime = time.time() self.createStartOffset() self.createButtons() self.createStateInfo() def createStartOffset(self): self.offsetLayout = QHBoxLayout() self.offsetSpinBox = QFFSpinBox(self) self.offsetSpinBox.setMinimum(0) self.offsetSpinBox.setMaximum(self.filesize) self.offsetLabel = QLabel("start offset:") self.offsetLayout.addWidget(self.offsetLabel) self.offsetLayout.addWidget(self.offsetSpinBox) self.layout().addLayout(self.offsetLayout) def createButtons(self): self.startButton = QPushButton("Start") self.stopButton = QPushButton("Stop") self.stopButton.setEnabled(False) self.connect(self.stopButton, SIGNAL("clicked()"), self.stopCarving) self.connect(self.startButton, SIGNAL("clicked()"), self.startCarving) self.connect(self, SIGNAL("ended"), self.carvingEnded) self.buttonLayout = QHBoxLayout() self.buttonLayout.addWidget(self.startButton) self.buttonLayout.addWidget(self.stopButton) self.layout().addLayout(self.buttonLayout) def createStateInfo(self): self.stateLayout = QVBoxLayout() self.overallLayout = QHBoxLayout() self.currentLabel = QLabel("Overall progress :") self.currentProgress = QProgressBar() self.overallLayout.addWidget(self.currentLabel) self.overallLayout.addWidget(self.currentProgress) self.stateLayout.addLayout(self.overallLayout) self.elapsedLabel = QLabel("elapsed time: 00d00h00m00s") self.stateLayout.addWidget(self.elapsedLabel) self.estimatedLabel = QLabel("estimated time: 00d00h00m00s") self.stateLayout.addWidget(self.estimatedLabel) self.totalLabel = QLabel("total headers found: 0") self.stateLayout.addWidget(self.totalLabel) self.stateLayout.setEnabled(False) self.layout().addLayout(self.stateLayout) def createContext(self, selected): lpatterns = VList() lpatterns.thisown = False for filetype in selected.iterkeys(): patterns = selected[filetype][0] aligned = selected[filetype][1] for pattern in patterns: vpattern = VMap() vpattern.thisown = False vfiletype = Variant(filetype, typeId.String) vfiletype.thisown = False vpattern["filetype"] = vfiletype header = VMap() header.thisown = False val = Variant(pattern[0], typeId.String) val.thisown = False header["needle"] = val val = Variant(len(pattern[0]), typeId.UInt32) val.thisown = False header["size"] = val footer = VMap() footer.thisown = False val = Variant(pattern[1], typeId.String) val.thisown = False footer["needle"] = val val = Variant(len(pattern[1]), typeId.UInt32) val.thisown = False footer["size"] = val vheader = Variant(header) vheader.thisown = False vpattern["header"] = vheader vfooter = Variant(footer) vfooter.thisown = False vpattern["footer"] = vfooter vwindow = Variant(int(pattern[2]), typeId.UInt32) vwindow.thisown = False vpattern["window"] = vwindow val = Variant(aligned, typeId.Bool) val.thisown = False vpattern["aligned"] = val lpatterns.append(vpattern) vpatterns = Variant(lpatterns) vpatterns.thisown = False return vpatterns def startCarving(self): selected = self.selector.selectedItems() patterns = self.createContext(selected) args = VMap() args.thisown = False args["patterns"] = patterns args["file"] = self.vnode startoff = Variant(self.offsetSpinBox.value(), typeId.UInt64) startoff.thisown = False args["start-offset"] = startoff factor = round(float(self.filesize) / 2147483647) self.startButton.setEnabled(False) self.stopButton.setEnabled(True) self.stopButton.setDown(False) if factor == 0: factor = 1 proc = self.tm.add("carver", args, ["gui", "thread"]) if proc: self.doJob(self.filesize, factor, self.offsetSpinBox.value()) self.stateLayout.setEnabled(True) self.connection(proc.inst) proc.inst.connection(self) #self.connect(self, SIGNAL("stateInfo(QString)"), self.setStateInfo) def carvingEnded(self, res): #results = str(res).split("\n") #print results #for item in results: # begidx = item.find(":") # self.res.add_const(str(item[:begidx]), str(item[begidx+1:] + "\n")) self.startButton.setEnabled(True) self.stopButton.setEnabled(False) self.stateLayout.setEnabled(False) def stopCarving(self): self.killJob() self.stopButton.setDown(True) def strtime(self, day, hour, min, sec): day = str(day) hour = str(hour) min = str(min) sec = str(sec) res = "0" * (2-len(day)) + day + "d" + "0" * (2-len(hour)) + hour + "h" + "0" * (2-len(min)) + min + "m" + "0" * (2-len(sec)) + sec + "s" return res def timesec2str(self, timesec): day = hour = min = sec = 0 if timesec > 3600 * 24: day = timesec / (3600 * 24) timesec = timesec % (3600 * 24) if timesec > 3600: hour = timesec / 3600 timesec = timesec % 3600 if timesec > 60: min = timesec / 60 timesec = timesec % 60 sec = timesec res = self.strtime(int(day), int(hour), int(min), int(sec)) return res def Event(self, e): if e.type == Carver.Position: self.emit(SIGNAL("updatePosition"), e) elif e.type == Carver.Matches: self.emit(SIGNAL("updateMatches"), e) elif e.type == Carver.EndOfProcessing: self.emit(SIGNAL("ended"), "") def updatePosition(self, e): ref = time.time() - self.time self.time = time.time() if not str(ref).startswith("0.0"): ref *= self.parsetime res = self.timesec2str(ref) self.estimatedLabel.setText("estimated time: " + res) res = self.timesec2str(time.time() - self.starttime) self.elapsedLabel.setText("elapsed time: " + res) i = int(e.value.value() / self.factor) if i > 2147483647: i = 2147483647 self.emit(SIGNAL("valueChanged(int)"), i) info = self.currentProgress.text() + " - " + self.totalLabel.text() self.emit(SIGNAL("stateInfo(QString)"), info) def updateMatches(self, e): self.totalLabel.setText("total headers found: " + str(e.value)) def doJob(self, filesize, factor, start): self.factor = factor self.parsetime = filesize / (10*1204*1024) self.elapsedLabel.setText("elapsed time: 00d00h00m00s") self.estimatedLabel.setText("estimated time: 00d00h00m00s") self.totalLabel.setText("total headers found: 0") maxrange = int(filesize / self.factor) if maxrange > 2147483647: maxrange = 2147483647 self.currentProgress.setRange(0, maxrange) self.currentProgress.setValue(0) self.connect(self, SIGNAL("valueChanged(int)"), self.currentProgress.setValue) self.time = time.time() self.starttime = time.time() self.connect(self, SIGNAL("updateMatches"), self.updateMatches) self.connect(self, SIGNAL("updatePosition"), self.updatePosition) def killJob(self): e = event() e.thisown = False e.value = None e.type = Carver.Stop self.notify(e)
class UploadDialog(QDialog): def __init__(self, tracks, device_info=None, username=None, password=None, auth_token=None, parent=None): super(UploadDialog, self).__init__(parent) self.tracks = tracks self.username = username self.password = password self._first_auth = True self.total_progress = QProgressBar(self) self.total_progress.setRange(0, len(tracks)) self.total_progress.setValue(0) self.total_progress.setFormat('%v of %m tracks uploaded') self.item_progress = QProgressBar(self) self.item_progress.setRange(0, 100) self.item_progress.setValue(0) self.item_progress.setFormat('%p%') self.buttons = QDialogButtonBox(QDialogButtonBox.Cancel) self.buttons.rejected.connect(self.reject) self.status_msg = QLabel('Starting upload', self) self.setWindowTitle('Uploading') self._createLayout() self.upload = StravaUpload(tracks, device_info=device_info, parent=self, auth_token=auth_token) self.upload.authNeeded.connect(self._onAuthNeeded) self.upload.itemProgress.connect(self.item_progress.setValue) self.upload.totalProgress.connect(self.total_progress.setValue) self.upload.statusMessage.connect(self.status_msg.setText) self.upload.finished.connect(self._onFinished) self.rejected.connect(self._onCanceled) QTimer.singleShot(100, self.upload.start) def _createLayout(self): l = QVBoxLayout() l.addWidget(self.status_msg) l.addWidget(self.item_progress) l.addWidget(self.total_progress) l.addWidget(self.buttons) self.setLayout(l) def _onAuthNeeded(self): if self._first_auth and self.username is not None and self.password is not None: self._first_auth = False self.upload.authenticate(self.username, self.password) return d = AuthDialog(self) if d.exec_() == QDialog.Accepted: u, p = d.getValues() self.upload.authenticate(u, p) else: log.debug('Auth dialog rejected') self._onCanceled() def _onFinished(self): res = self.upload.results if len(res) != len(self.tracks): res.extend([{'status' : 'ERROR', 'msg' : 'Canceled'}] * (len(self.tracks) - len(res))) log.debug('Upload finished') d = ResultDialog(zip(self.tracks, res), self) d.exec_() self.accept() def _onCanceled(self): log.debug('Upload canceled') self.upload.cancel() self._onFinished()
class _CancellableProgressEditor(Editor): title = Unicode # synced from factory.title_name message = Unicode # synced from factory.message_name min = Int#Float # synced from factory.min_name max = Int#Float # synced from factory.max_name show_time = Bool # synced from factory.show_time_name def _title_changed(self): if self._title is not None: self._title.setText('<B>%s</B>' % self.title) self._title.setVisible(len(self.title) > 0) def _message_changed(self): if self._message is not None: self._message.setText(self.message) self._message.setVisible(len(self.message) > 0) if self.factory.prefix_message: self.set_text() def _show_time_changed(self): if self._time_widget is not None: self._time_widget.setVisible(self.show_time) @on_trait_change('min, max') def change_range(self): if self._progress_bar is not None: self._progress_bar.setRange(self.min, self.max) self.update_editor() def init(self, parent): self.title = self.factory.title if len(self.factory.title_name) > 0: self.sync_value(self.factory.title_name, 'title')#, 'from') self.message = self.factory.message if len(self.factory.message_name) > 0: self.sync_value(self.factory.message_name, 'message')#, 'from') self.min = self.factory.min if len(self.factory.min_name) > 0: self.sync_value(self.factory.min_name, 'min')#, 'from') self.max = self.factory.max if len(self.factory.max_name) > 0: self.sync_value(self.factory.max_name, 'max')#, 'from') self.show_time = self.factory.show_time if len(self.factory.show_time_name) > 0: self.sync_value(self.factory.show_time_name, 'show_time')#, 'from') self.control = self._create_control(parent) self.can_cancel = self.factory.can_cancel if len(self.factory.can_cancel_name) > 0: self.sync_value(self.factory.can_cancel_name, 'can_cancel')#, 'from') self.set_tooltip() self.reset() can_cancel = Bool(False) from traits.api import Any buttons = Any @on_trait_change('can_cancel') def set_buttons_visible(self, value): self.buttons.setVisible(value) def _create_control(self, parent): layout = QVBoxLayout() if len(self.title) > 0: self._title = QLabel('<B>%s</B>' % self.title) layout.addWidget(self._title) if not self.factory.prefix_message and len(self.message) > 0: self._message = QLabel(self.message) # self._message = QTextEdit(self.message) # self._message.setReadOnly(True) layout.addWidget(self._message) self._progress_bar = QProgressBar() self._progress_bar.setRange(self.min, self.max) if not self.factory.can_cancel: layout.addWidget(self._progress_bar) else: self.buttons = QDialogButtonBox() self.buttons.addButton(u'Cancel', QDialogButtonBox.RejectRole) self.buttons.connect(self.buttons, SIGNAL('rejected()'), self.factory.cancelled) grid_layout = QGridLayout() grid_layout.addWidget(self._progress_bar, 0, 0) grid_layout.setColumnStretch(0, 1) grid_layout.addWidget(self.buttons, 0, 1) layout.addLayout(grid_layout) if self.factory.show_time: elapsed_label = QLabel('Elapsed time:') estimated_label = QLabel('Estimated time:') remaining_label = QLabel('Remaining time:') self._elapsed_control = QLabel('unknown') self._estimated_control = QLabel('unknown') self._remaining_control = QLabel('unknown') grid_layout = QGridLayout() grid_layout.addWidget(elapsed_label, 0, 0) grid_layout.addWidget(self._elapsed_control, 0, 1) grid_layout.addWidget(estimated_label, 1, 0) grid_layout.addWidget(self._estimated_control, 1, 1) grid_layout.addWidget(remaining_label, 2, 0) grid_layout.addWidget(self._remaining_control, 2, 1) grid_layout.setColumnStretch(1, 1) self._time_widget = QWidget() self._time_widget.setLayout(grid_layout) layout.addWidget(self._time_widget) if self.factory.show_text: self.set_text() else: self._progress_bar.setTextVisible(False) widget = QWidget() widget.setLayout(layout) return widget def set_text(self): if self._progress_bar is None: return if self.factory.prefix_message: format = self.message + ' ' else: format = '' if self.factory.show_value: format += '%v' if self.factory.show_max: if self.factory.show_value: format += '/' format += '%m' if self.factory.show_value or self.factory.show_max: format += ' ' if self.factory.show_percent: if self.factory.show_value or self.factory.show_max: format += '(%p%)' else: format += '%p%' self._progress_bar.setFormat(format) def _set_time_label(self, value, control): hours = value / 3600 minutes = (value % 3600) / 60 seconds = value % 60 label = "%1u:%02u:%02u" % (hours, minutes, seconds) control.setText(control.text()[:-7] + label) def update_editor(self): if self.factory.min <= self.value <= self.factory.max: if self.value == self.factory.min: self.reset() self._progress_bar.setValue(self.value) if self.factory.show_time: if (self.factory.max != self.factory.min): percent = (float(self.value) - self.factory.min) / (self.factory.max - self.factory.min) # if float(<undefined>) raises an error here then probably the # name of the trait this is editing is mispelled or owned by # the handler, e.g. 'handler.progress' instead of 'progress'. else: percent = 1.0 if self.factory.show_time and (percent != 0): current_time = time.time() elapsed = current_time - self._start_time estimated = elapsed / percent remaining = estimated - elapsed self._set_time_label(elapsed, self._elapsed_control) self._set_time_label(estimated, self._estimated_control) self._set_time_label(remaining, self._remaining_control) def reset(self): self._progress_bar.reset() self._start_time = time.time()
class FeedLol(QMainWindow): def __init__(self, parent = None): QMainWindow.__init__(self, parent) self.setWindowTitle("FeedLol") self.aboutAction = QAction(QIcon("data/icons/help-about.svg"), "&About FeedLol...", self) self.connect(self.aboutAction, SIGNAL("triggered()"), self.slotAbout) self.reloadAction = QAction(QIcon("data/icons/view-refresh.svg"), "&Reload", self) self.reloadAction.setShortcut(QKeySequence.Refresh) self.homeAction = QAction(QIcon("data/icons/go-home.svg"), "Go &Home", self) self.homeAction.setShortcut("Alt+Home") self.userAction = QAction(QIcon("data/icons/user-identity.svg"), "&Me", self) self.userAction.setShortcut("Ctrl+M") self.logoutAction = QAction(QIcon("data/icons/dialog-close.svg"), "Log&out", self) self.logoutAction.setShortcut(QKeySequence.Close) self.settingsAction = QAction(QIcon("data/icons/configure.svg"), "&Preferences...", self) self.connect(self.settingsAction, SIGNAL("triggered()"), self.slotSettings) self.toolbar = QToolBar("Toolbar", self) self.toolbar.setObjectName("toolbar") self.toolbar.addAction(self.homeAction) self.toolbar.addAction(self.userAction) self.toolbar.addAction(self.reloadAction) self.toolbar.addSeparator() self.toolbar.addAction(self.logoutAction) self.toolbar.addSeparator() self.toolbar.addAction(self.settingsAction) self.toolbar.addAction(self.aboutAction) self.addToolBar(self.toolbar) self.loadStatus = QProgressBar(self) self.loadStatus.setRange(0, 100) self.loadStatus.setMaximumWidth(200) self.loadStatus.setTextVisible(False) self.loadStatus.hide() self.statusBar().addPermanentWidget(self.loadStatus) self.feedView = FeedView(self) self.setCentralWidget(self.feedView) self.connect(self.feedView, SIGNAL("titleChanged(const QString&)"), self.slotSetTitle) self.connect(self.feedView, SIGNAL("statusBarMessage(const QString&)"), self.statusBar(), SLOT("showMessage(const QString&)")) self.connect(self.feedView, SIGNAL("loadStarted()"), self.loadStart) self.connect(self.feedView, SIGNAL("loadFinished(bool)"), self.loadStop) self.connect(self.feedView, SIGNAL("loadProgress(int)"), self.loadProgress) self.connect(self.reloadAction, SIGNAL("triggered()"), self.feedView.reload) self.connect(self.homeAction, SIGNAL("triggered()"), self.feedView.goHome) self.connect(self.userAction, SIGNAL("triggered()"), self.feedView.goToUserPage) self.connect(self.logoutAction, SIGNAL("triggered()"), self.feedView.logout) self.connect(self.feedView.page(), SIGNAL("linkHovered(const QString&, const QString&, const QString&)"), self.linkHovered) self.settingsDialog = SettingsDialog(self.feedView, self) settings = QSettings() if settings.contains("proxy/type"): proxy = QNetworkProxy() proxyType = settings.value("proxy/type").toInt()[0] proxy.setType( (proxyType == 2) and QNetworkProxy.Socks5Proxy or ( (proxyType == 1) and QNetworkProxy.HttpProxy or QNetworkProxy.NoProxy ) ) if proxy.type() != QNetworkProxy.NoProxy: proxy.setHostName(settings.value("proxy/host").toString()) proxy.setPort(settings.value("proxy/port").toInt()[0]) if settings.value("proxy/user").toString(): proxy.setUser(settings.value("proxy/user").toString()) proxy.setPassword(settings.value("proxy/password").toString()) QNetworkProxy.setApplicationProxy(proxy) if settings.contains("mainWindow/geometry"): self.restoreGeometry(settings.value("mainWindow/geometry").toByteArray()) else: self.resize(320,480) if settings.contains("mainWindow/state"): self.restoreState(settings.value("mainWindow/state").toByteArray()) self.feedView.goHome() def saveConfig(self): settings = QSettings() settings.setValue("mainWindow/geometry", QVariant(self.saveGeometry())) settings.setValue("mainWindow/state", QVariant(self.saveState())) session = self.feedView.siteServer.session from cPickle import dumps session = dumps(session) settings.setValue("session", QVariant(session)) proxy = QNetworkProxy.applicationProxy() proxyType = (proxy.type() == QNetworkProxy.Socks5Proxy) and 2 or ( (proxy.type() == QNetworkProxy.HttpProxy) and 1 or 0 ) settings.setValue("proxy/type", QVariant(proxyType)) settings.setValue("proxy/host", QVariant(proxy.hostName())) settings.setValue("proxy/port", QVariant(proxy.port())) settings.setValue("proxy/user", QVariant(proxy.user())) settings.setValue("proxy/password", QVariant(proxy.password())) def slotAbout(self): from PyQt4.QtGui import QMessageBox QMessageBox.about(self, "FeedLol", "<h2>FeedLol 0.1</h2><p>Copyright © 2008 <a href=\"mailto:[email protected]\">Bodil Stokke</a></p>") def slotSettings(self): self.settingsDialog.updateSettings() if self.settingsDialog.exec_() == QDialog.Accepted: self.settingsDialog.applySettings() def slotSetTitle(self, title): self.setWindowTitle("FeedLol: " + title) def loadStart(self): self.loadStatus.show() def loadStop(self): self.loadStatus.hide() def loadProgress(self, progress): self.loadStatus.setValue(progress) def linkHovered(self, url, title, text): if url and QUrl(url).scheme() != "chrome": self.statusBar().showMessage(url) else: self.statusBar().clearMessage()
class LineCounterDialog( QDialog, object ): """ line counter dialog implementation """ def __init__( self, fName = None, editor = None, parent = None ): QDialog.__init__( self, parent ) self.__cancelRequest = False self.__inProgress = False if fName is not None: self.__fName = fName.strip() else: self.__fName = None self.__editor = editor self.__createLayout() self.setWindowTitle( "Line counter" ) QTimer.singleShot( 0, self.__process ) return def __createLayout( self ): """ Creates the dialog layout """ self.resize( 450, 220 ) self.setSizeGripEnabled( True ) self.verticalLayout = QVBoxLayout( self ) # Info label self.infoLabel = FitPathLabel( self ) #sizePolicy = QSizePolicy( QSizePolicy.Expanding, # QSizePolicy.Preferred ) sizePolicy = QSizePolicy( QSizePolicy.Minimum, QSizePolicy.Preferred ) sizePolicy.setHorizontalStretch( 0 ) sizePolicy.setVerticalStretch( 0 ) sizePolicy.setHeightForWidth( self.infoLabel.sizePolicy().hasHeightForWidth() ) self.infoLabel.setSizePolicy( sizePolicy ) self.verticalLayout.addWidget( self.infoLabel ) # Progress bar self.progressBar = QProgressBar( self ) self.progressBar.setValue( 0 ) self.progressBar.setOrientation( Qt.Horizontal ) self.verticalLayout.addWidget( self.progressBar ) # Result window self.resultEdit = QTextEdit( self ) self.resultEdit.setTabChangesFocus( False ) self.resultEdit.setAcceptRichText( False ) self.resultEdit.setReadOnly( True ) self.resultEdit.setFontFamily( GlobalData().skin.baseMonoFontFace ) font = self.resultEdit.font() # Calculate the vertical size fontMetrics = QFontMetrics( font ) rect = fontMetrics.boundingRect( "W" ) # 6 lines, 5 line spacings, 2 frames self.resultEdit.setMinimumHeight( rect.height() * 7 + 4 * 5 + self.resultEdit.frameWidth() * 2 ) self.verticalLayout.addWidget( self.resultEdit ) # Buttons self.buttonBox = QDialogButtonBox( self ) self.buttonBox.setOrientation( Qt.Horizontal ) self.buttonBox.setStandardButtons( QDialogButtonBox.Close ) self.verticalLayout.addWidget( self.buttonBox ) self.buttonBox.rejected.connect( self.__onClose ) return def __scanDir( self, path, files ): " Recursively builds a list of python files " if path in self.__scannedDirs: return self.__scannedDirs.append( path ) for item in os.listdir( path ): if os.path.isdir( path + item ): nestedDir = os.path.realpath( path + item ) if not nestedDir.endswith( os.path.sep ): nestedDir += os.path.sep self.__scanDir( nestedDir, files ) else: candidate = os.path.realpath( path + item ) if candidate.endswith( ".py" ) or \ candidate.endswith( ".py3" ) or \ candidate.endswith( ".pyw" ): if not candidate in files: files.append( candidate ) return def __onClose( self ): " triggered when the close button is clicked " self.__cancelRequest = True if not self.__inProgress: self.close() return def __process( self ): " Accumulation process " self.__inProgress = True if self.__fName is not None: if os.path.exists( self.__fName ): if os.path.isdir( self.__fName ): self.__fName = os.path.realpath( self.__fName ) if not self.__fName.endswith( os.path.sep ): self.__fName += os.path.sep files = [] self.__scannedDirs = [] QApplication.setOverrideCursor( QCursor( Qt.WaitCursor ) ) self.__scanDir( self.__fName, files ) QApplication.restoreOverrideCursor() else: files = [ self.__fName ] else: files = [] elif self.__editor is not None: files = [ "buffer" ] else: files = GlobalData().project.filesList self.progressBar.setRange( 0, len( files ) ) accumulator = LinesCounter() current = LinesCounter() index = 1 for fileName in files: if self.__cancelRequest: self.__inProgress = False self.close() return self.infoLabel.setPath( 'Processing: ' + fileName ) processed = False if self.__editor is not None: current.getLinesInBuffer( self.__editor ) processed = True else: if (fileName.endswith( '.py' ) or \ fileName.endswith( '.py3' ) or \ fileName.endswith( '.pyw' )) and \ os.path.exists( fileName ): current.getLines( fileName ) processed = True if processed: accumulator.files += current.files accumulator.filesSize += current.filesSize accumulator.codeLines += current.codeLines accumulator.emptyLines += current.emptyLines accumulator.commentLines += current.commentLines accumulator.classes += current.classes self.progressBar.setValue( index ) index += 1 QApplication.processEvents() self.infoLabel.setPath( 'Done' ) self.__inProgress = False # Update text in the text window nFiles = splitThousands( str( accumulator.files ) ) filesSize = splitThousands( str( accumulator.filesSize ) ) classes = splitThousands( str( accumulator.classes ) ) codeLines = splitThousands( str( accumulator.codeLines ) ) emptyLines = splitThousands( str( accumulator.emptyLines ) ) commentLines = splitThousands( str( accumulator.commentLines ) ) totalLines = splitThousands( str( accumulator.codeLines + accumulator.emptyLines + accumulator.commentLines ) ) output = "Classes: " + classes + "\n" \ "Code lines: " + codeLines + "\n" \ "Empty lines: " + emptyLines + "\n" \ "Comment lines: " + commentLines + "\n" \ "Total lines: " + totalLines if self.__editor is None: output = "Number of python files: " + nFiles + "\n" \ "Total files size: " + filesSize + " bytes\n" + \ output else: output = "Number of characters: " + filesSize + "\n" + \ output self.resultEdit.setText( output ) return
class MainWindow(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.setCentralWidget(self.ui.mangaTableView) self.newMangaDialog = NewMangaDialog() self.mangaDownloadDialog = MangaDownloadDialog() self.mangaTableModel = QStandardItemModel(0, 3, self) self.mangaTableModel.setHorizontalHeaderItem(0, QStandardItem(QString("Manga"))) self.mangaTableModel.setHorizontalHeaderItem(1, QStandardItem(QString("Latest Chapter"))) self.mangaTableModel.setHorizontalHeaderItem(2, QStandardItem(QString("Status"))) self.ui.mangaTableView.setModel(self.mangaTableModel) newMangaAction = QAction(QIcon("./icon/add.ico"),'New Manga', self) newMangaAction.setShortcut('Ctrl+N') newMangaAction.triggered.connect(self.newMangaDialog.show) removeMangaAction = QAction(QIcon("./icon/delete.ico"),'Remove Manga', self) removeMangaAction.setShortcut('Delete') preferencesAction = QAction(QIcon("./icon/preferences.ico"),'Preferences', self) aboutAction = QAction(QIcon("./icon/about.ico"),'About', self) self.ui.toolBar.addAction(newMangaAction) self.ui.toolBar.addAction(removeMangaAction) self.ui.toolBar.addSeparator() self.ui.toolBar.addAction(preferencesAction) self.ui.toolBar.addSeparator() self.ui.toolBar.addAction(aboutAction) self.progressBar = QProgressBar(self.ui.statusbar) self.ui.statusbar.addPermanentWidget(self.progressBar) self.progressBar.hide() def closeEvent(self, QCloseEvent): mangaList = [] for i in range(self.mangaTableModel.rowCount()): mangaList.append({ "name" : str(self.mangaTableModel.item(i, 0).text()), "latestChapter" : str(self.mangaTableModel.item(i, 1).text()), "status" : "Updated", "link" : "/trial.html" }) self.emit(SIGNAL("applicationClosed"),mangaList) def initializeProgressBar(self, size): self.progressBar.setRange(0, size) self.progressBar.setValue(0) self.progressBar.show() def updateProgressBar(self, value): self.progressBar.setValue(value) def updateStatusBar(self, msg): self.ui.statusbar.showMessage(msg) def updateMangaTable(self, chapter): isFound = False for i in range(self.mangaTableModel.rowCount()): mangaItem = self.mangaTableModel.item(i) if mangaItem.text() == chapter["name"]: self.mangaTableModel.item(i, 1).setText(chapter["latestChapter"]) self.mangaTableModel.item(i, 2).setText(chapter["status"]) isFound = True break if not isFound: self.addRowToMangaTable(chapter) def addMangaListToMangaTable(self, mangaList): for i in range(len(mangaList)): self.addRowToMangaTable(mangaList[i]) def addRowToMangaTable(self, manga): i = self.mangaTableModel.rowCount() mangaItem = QStandardItem(QString(manga["name"])) latestChapterItem = QStandardItem(QString(manga["latestChapter"])) statusItem = QStandardItem(QString(manga["status"])) brush = QBrush(QColor(255, 255, 255)) if i%2==0 else QBrush(QColor(200, 200, 200)) mangaItem.setBackground(brush) latestChapterItem.setBackground(brush) statusItem.setBackground(brush) self.mangaTableModel.setItem(i, 0, mangaItem) self.mangaTableModel.setItem(i, 1, latestChapterItem) self.mangaTableModel.setItem(i, 2, statusItem)
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)
def updateVersion(self): """Prüft die Version der Datenbank. :returns: Anpassung erfolgreich: True = alles o.k. :rtype: logical Voraussetzungen: - Die aktuelle Datenbank ist bereits geöffnet. Die aktuelle Versionsnummer steht in der Datenbank: info.version Diese wird mit dem Attribut self.actversion verglichen. Bei Differenz werden die nötigen Anpassungen vorgenommen und die Versionsnummer jeweils aktualisiert. Falls Tabellenspalten umbenannt oder gelöscht wurden, wird eine Warnmeldung erzeugt mit der Empfehlung, das aktuelle Projekt neu zu laden. """ logger.debug('0 - actversion = {}'.format(self.actversion)) # --------------------------------------------------------------------------------------------- # Aktuelle Version abfragen sql = u"""SELECT value FROM info WHERE subject = 'version'""" if not self.sql(sql, u'dbfunc.version (1)'): return False data = self.cursl.fetchone() if data is not None: versiondbQK = data[0] logger.debug( 'dbfunc.version: Aktuelle Version der qkan-Datenbank ist {}'. format(versiondbQK)) else: logger.debug( 'dbfunc.version: Keine Versionsnummer vorhanden. data = {}'. format(repr(data))) sql = u"""INSERT INTO info (subject, value) Values ('version', '1.9.9')""" if not self.sql(sql, u'dbfunc.version (2)'): return False versiondbQK = u'1.9.9' logger.debug('0 - versiondbQK = {}'.format(versiondbQK)) self.versionlis = [ int(el.replace('a', '').replace('b', '').replace('c', '')) for el in versiondbQK.split('.') ] # --------------------------------------------------------------------------------------------- # Aktualisierung von Version 1.9.9 und früher if versionolder(self.versionlis, [2, 0, 2]): # Tabelle einleit sqllis = [ u"""CREATE TABLE IF NOT EXISTS einleit( pk INTEGER PRIMARY KEY AUTOINCREMENT, elnam TEXT, haltnam TEXT, teilgebiet TEXT, zufluss REAL, kommentar TEXT, createdat TEXT DEFAULT CURRENT_DATE)""", u"""SELECT AddGeometryColumn('einleit','geom',{},'POINT',2)""". format(self.epsg), u"""SELECT CreateSpatialIndex('einleit','geom')""" ] for sql in sqllis: if not self.sql(sql, u'dbfunc.version (3c)'): return False sqllis = [ u"""CREATE TABLE IF NOT EXISTS linksw ( pk INTEGER PRIMARY KEY AUTOINCREMENT, elnam TEXT, haltnam TEXT, teilgebiet TEXT)""", u"""SELECT AddGeometryColumn('linksw','geom',{},'POLYGON',2)""" .format(self.epsg), u"""SELECT AddGeometryColumn('linksw','gbuf',{},'MULTIPOLYGON',2)""" .format(self.epsg), u"""SELECT AddGeometryColumn('linksw','glink',{},'LINESTRING',2)""" .format(self.epsg), u"""SELECT CreateSpatialIndex('linksw','geom')""" ] for sql in sqllis: if not self.sql(sql, u'dbfunc.version (3d)'): return False self.versionlis = [2, 0, 2] # --------------------------------------------------------------------------------------------------------- if versionolder(self.versionlis, [2, 1, 2]): attrlis = self.attrlist(u'linksw') if not attrlis: fehlermeldung(u'dbfunc.version (2.0.2):', u'attrlis für linksw ist leer') return False elif u'elnam' not in attrlis: logger.debug(u'linksw.elnam ist nicht in: {}'.format( str(attrlis))) sql = u"""ALTER TABLE linksw ADD COLUMN elnam TEXT""" if not self.sql(sql, u'dbfunc.version (2.0.2-1)'): return False self.commit() attrlis = self.attrlist(u'linkfl') if not attrlis: fehlermeldung(u'dbfunc.version (2.0.2):', u'attrlis für linkfl ist leer') return False elif u'tezgnam' not in attrlis: logger.debug(u'linkfl.tezgnam ist nicht in: {}'.format( str(attrlis))) sql = u"""ALTER TABLE linkfl ADD COLUMN tezgnam TEXT""" if not self.sql(sql, u'dbfunc.version (2.0.2-3)'): return False self.commit() self.versionlis = [2, 1, 2] # --------------------------------------------------------------------------------------------------------- if versionolder(self.versionlis, [2, 2, 0]): attrlis = self.attrlist(u'einleit') if not attrlis: return False elif u'ew' not in attrlis: logger.debug(u'einleit.ew ist nicht in: {}'.format( str(attrlis))) sql = u"""ALTER TABLE einleit ADD COLUMN ew REAL""" if not self.sql(sql, u'dbfunc.version (2.1.2-1)'): return False sql = u"""ALTER TABLE einleit ADD COLUMN einzugsgebiet TEXT""" if not self.sql(sql, u'dbfunc.version (2.1.2-2)'): return False self.commit() sql = u"""CREATE TABLE IF NOT EXISTS einzugsgebiete ( pk INTEGER PRIMARY KEY AUTOINCREMENT, tgnam TEXT, ewdichte REAL, wverbrauch REAL, stdmittel REAL, fremdwas REAL, kommentar TEXT, createdat TEXT DEFAULT CURRENT_DATE)""" if not self.sql(sql, u'dbfunc.version (2.1.2-3)'): return False sql = u"""SELECT AddGeometryColumn('einzugsgebiete','geom',{},'MULTIPOLYGON',2)""".format( self.epsg) if not self.sql(sql, u'dbfunc.version (2.1.2-4)'): return False sql = u"""SELECT CreateSpatialIndex('einzugsgebiete','geom')""" if not self.sql(sql, u'dbfunc.version (2.1.2-5)'): return False self.versionlis = [2, 2, 0] # --------------------------------------------------------------------------------------------------------- if versionolder(self.versionlis, [2, 2, 1]): attrlis = self.attrlist(u'flaechen') if not attrlis: return False elif u'abflusstyp' not in attrlis: logger.debug(u'flaechen.abflusstyp ist nicht in: {}'.format( str(attrlis))) sql = u"""ALTER TABLE flaechen ADD COLUMN abflusstyp TEXT""" if not self.sql(sql, u'dbfunc.version (2.2.0-1)'): return False self.commit() self.versionlis = [2, 2, 1] # --------------------------------------------------------------------------------------------------------- if versionolder(self.versionlis, [2, 2, 2]): attrlis = self.attrlist(u'flaechen') if not attrlis: return False elif u'abflusstyp' not in attrlis: logger.debug(u'flaechen.abflusstyp ist nicht in: {}'.format( str(attrlis))) sql = u"""ALTER TABLE flaechen ADD COLUMN abflusstyp TEXT""" if not self.sql(sql, u'dbfunc.version (2.2.1-1)'): return False self.commit() self.versionlis = [2, 2, 2] # --------------------------------------------------------------------------------------------------------- if versionolder(self.versionlis, [2, 2, 3]): global progress_bar progress_bar = QProgressBar(iface.messageBar()) progress_bar.setRange(0, 100) status_message = iface.messageBar().createMessage( u"", u"Die Datenbank wird an Version 2.2.3 angepasst. Bitte warten..." ) status_message.layout().addWidget(progress_bar) iface.messageBar().pushWidget(status_message, QgsMessageBar.INFO, 10) progress_bar.setValue(80) # Tabelle flaechen ------------------------------------------------------------- # 1. Schritt: Trigger für zu ändernde Tabelle abfragen und in triggers speichern # sql = u"""SELECT type, sql FROM sqlite_master WHERE tbl_name='flaechen'""" # if not self.sql(sql, u'dbfunc.version.pragma (1)'): # return False # triggers = self.fetchall() # 2. Schritt: Tabelle umbenennen, neu anlegen und Daten rüberkopieren sqllis = [ u"""BEGIN TRANSACTION;""", u"""CREATE TABLE flaechen_t ( pk INTEGER PRIMARY KEY AUTOINCREMENT, flnam TEXT, haltnam TEXT, neigkl INTEGER DEFAULT 0, abflusstyp TEXT, he_typ INTEGER DEFAULT 0, speicherzahl INTEGER DEFAULT 2, speicherkonst REAL, fliesszeit REAL, fliesszeitkanal REAL, teilgebiet TEXT, regenschreiber TEXT, abflussparameter TEXT, aufteilen TEXT DEFAULT 'nein', kommentar TEXT, createdat TEXT DEFAULT CURRENT_DATE);""", u"""SELECT AddGeometryColumn('flaechen_t','geom',{},'MULTIPOLYGON',2);""" .format(self.epsg), u"""INSERT INTO flaechen_t ( "flnam", "haltnam", "neigkl", "he_typ", "speicherzahl", "speicherkonst", "fliesszeit", "fliesszeitkanal", "teilgebiet", "regenschreiber", "abflussparameter", "aufteilen", "kommentar", "createdat", "geom") SELECT "flnam", "haltnam", "neigkl", "he_typ", "speicherzahl", "speicherkonst", "fliesszeit", "fliesszeitkanal", "teilgebiet", "regenschreiber", "abflussparameter", "aufteilen", "kommentar", "createdat", "geom" FROM "flaechen";""", u"""SELECT DiscardGeometryColumn('flaechen','geom')""", u"""DROP TABLE flaechen;""", u"""CREATE TABLE flaechen ( pk INTEGER PRIMARY KEY AUTOINCREMENT, flnam TEXT, haltnam TEXT, neigkl INTEGER DEFAULT 0, abflusstyp TEXT, he_typ INTEGER DEFAULT 0, speicherzahl INTEGER DEFAULT 2, speicherkonst REAL, fliesszeit REAL, fliesszeitkanal REAL, teilgebiet TEXT, regenschreiber TEXT, abflussparameter TEXT, aufteilen TEXT DEFAULT 'nein', kommentar TEXT, createdat TEXT DEFAULT CURRENT_DATE);""", u"""SELECT AddGeometryColumn('flaechen','geom',{},'MULTIPOLYGON',2);""" .format(self.epsg), u"""SELECT CreateSpatialIndex('flaechen','geom')""", u"""INSERT INTO flaechen ( "flnam", "haltnam", "neigkl", "he_typ", "speicherzahl", "speicherkonst", "fliesszeit", "fliesszeitkanal", "teilgebiet", "regenschreiber", "abflussparameter", "aufteilen", "kommentar", "createdat", "geom") SELECT "flnam", "haltnam", "neigkl", "he_typ", "speicherzahl", "speicherkonst", "fliesszeit", "fliesszeitkanal", "teilgebiet", "regenschreiber", "abflussparameter", "aufteilen", "kommentar", "createdat", "geom" FROM "flaechen_t";""", u"""SELECT DiscardGeometryColumn('flaechen_t','geom')""", u"""DROP TABLE flaechen_t;""" ] for sql in sqllis: if not self.sql( sql, u'dbfunc.version (2.2.2-1)', transaction=True): return False # 3. Schritt: Trigger wieder herstellen # for el in triggers: # if el[0] != 'table': # sql = el[1] # logger.debug(u"Trigger 'flaechen' verarbeitet:\n{}".format(el[1])) # if not self.sql(sql, u'dbfunc.version (2.2.2-2)', transaction=True): # return False # else: # logger.debug(u"1. Trigger 'table' erkannt:\n{}".format(el[1])) # 4. Schritt: Transaction abschließen self.commit() # 5. Schritt: Spalte abflusstyp aus Spalte he_typ übertragen sql = u"""UPDATE flaechen SET abflusstyp = CASE he_typ WHEN 0 THEN 'Direktabfluss' WHEN 1 THEN 'Fließzeiten' WHEN 2 THEN 'Schwerpunktfließzeit' ELSE NULL END WHERE abflusstyp IS NULL""" if not self.sql(sql, u'dbfunc.version (2.2.2-3)'): return False progress_bar.setValue(20) # Tabelle linksw ------------------------------------------------------------- # 1. Schritt: Trigger für zu ändernde Tabelle abfragen und in triggers speichern # sql = u"""SELECT type, sql FROM sqlite_master WHERE tbl_name='linksw'""" # if not self.sql(sql, u'dbfunc.version.pragma (3)'): # return False # triggers = self.fetchall() # 2. Schritt: Tabelle umbenennen, neu anlegen und Daten rüberkopieren sqllis = [ u"""BEGIN TRANSACTION;""", u"""CREATE TABLE linksw_t ( pk INTEGER PRIMARY KEY AUTOINCREMENT, elnam TEXT, haltnam TEXT, teilgebiet TEXT)""", u"""SELECT AddGeometryColumn('linksw_t','geom',{},'POLYGON',2)""" .format(self.epsg), u"""SELECT AddGeometryColumn('linksw_t','gbuf',{},'MULTIPOLYGON',2)""" .format(self.epsg), u"""SELECT AddGeometryColumn('linksw_t','glink',{},'LINESTRING',2)""" .format(self.epsg), u"""INSERT INTO linksw_t ( "elnam", "haltnam", "teilgebiet", "geom", "gbuf", "glink") SELECT "elnam", "haltnam", "teilgebiet", "geom", "gbuf", "glink" FROM "linksw";""", u"""SELECT DiscardGeometryColumn('linksw','geom')""", u"""SELECT DiscardGeometryColumn('linksw','gbuf')""", u"""SELECT DiscardGeometryColumn('linksw','glink')""", u"""DROP TABLE linksw;""", u"""CREATE TABLE linksw ( pk INTEGER PRIMARY KEY AUTOINCREMENT, elnam TEXT, haltnam TEXT, teilgebiet TEXT)""", u"""SELECT AddGeometryColumn('linksw','geom',{},'POLYGON',2)""" .format(self.epsg), u"""SELECT AddGeometryColumn('linksw','gbuf',{},'MULTIPOLYGON',2)""" .format(self.epsg), u"""SELECT AddGeometryColumn('linksw','glink',{},'LINESTRING',2)""" .format(self.epsg), u"""SELECT CreateSpatialIndex('linksw','geom')""", u"""INSERT INTO linksw ( "elnam", "haltnam", "teilgebiet", "geom", "gbuf", "glink") SELECT "elnam", "haltnam", "teilgebiet", "geom", "gbuf", "glink" FROM "linksw_t";""", u"""SELECT DiscardGeometryColumn('linksw_t','geom')""", u"""SELECT DiscardGeometryColumn('linksw_t','gbuf')""", u"""SELECT DiscardGeometryColumn('linksw_t','glink')""", u"""DROP TABLE linksw_t;""" ] for sql in sqllis: if not self.sql( sql, u'dbfunc.version (2.2.2-4)', transaction=True): return False # 3. Schritt: Trigger wieder herstellen # for el in triggers: # if el[0] != 'table': # sql = el[1] # logger.debug(u"Trigger 'linksw' verarbeitet:\n{}".format(el[1])) # if not self.sql(sql, u'dbfunc.version (2.2.2-5)', transaction=True): # return False # else: # logger.debug(u"1. Trigger 'table' erkannt:\n{}".format(el[1])) # 4. Schritt: Transaction abschließen self.commit() progress_bar.setValue(40) # Tabelle linkfl ------------------------------------------------------------- # 1. Schritt: Trigger für zu ändernde Tabelle abfragen und in triggers speichern # sql = u"""SELECT type, sql FROM sqlite_master WHERE tbl_name='linkfl'""" # if not self.sql(sql, u'dbfunc.version.pragma (5)'): # return False # triggers = self.fetchall() # 2. Schritt: Temporäre Tabelle anlegen, Daten rüber kopieren, # Tabelle löschen und wieder neu anlegen und Daten zurück kopieren sqllis = [ u"""BEGIN TRANSACTION;""", u"""CREATE TABLE linkfl_t ( pk INTEGER PRIMARY KEY AUTOINCREMENT, flnam TEXT, haltnam TEXT, tezgnam TEXT, aufteilen TEXT, teilgebiet TEXT);""", u"""SELECT AddGeometryColumn('linkfl_t','geom',{},'MULTIPOLYGON',2)""" .format(self.epsg), u"""SELECT AddGeometryColumn('linkfl_t','gbuf',{},'MULTIPOLYGON',2)""" .format(self.epsg), u"""SELECT AddGeometryColumn('linkfl_t','glink',{},'LINESTRING',2)""" .format(self.epsg), u"""INSERT INTO linkfl_t ( "flnam", "haltnam", "tezgnam", "aufteilen", "teilgebiet", "geom", "gbuf", "glink") SELECT "flnam", "haltnam", "tezgnam", "aufteilen", "teilgebiet", "geom", "gbuf", "glink" FROM "linkfl";""", u"""SELECT DiscardGeometryColumn('linkfl','geom')""", u"""SELECT DiscardGeometryColumn('linkfl','gbuf')""", u"""SELECT DiscardGeometryColumn('linkfl','glink')""", u"""DROP TABLE linkfl;""", u"""CREATE TABLE linkfl ( pk INTEGER PRIMARY KEY AUTOINCREMENT, flnam TEXT, haltnam TEXT, tezgnam TEXT, aufteilen TEXT, teilgebiet TEXT);""", u"""SELECT AddGeometryColumn('linkfl','geom',{},'MULTIPOLYGON',2)""" .format(self.epsg), u"""SELECT AddGeometryColumn('linkfl','gbuf',{},'MULTIPOLYGON',2)""" .format(self.epsg), u"""SELECT AddGeometryColumn('linkfl','glink',{},'LINESTRING',2)""" .format(self.epsg), u"""SELECT CreateSpatialIndex('linkfl','glink')""", u"""INSERT INTO linkfl ( "flnam", "haltnam", "tezgnam", "aufteilen", "teilgebiet", "geom", "gbuf", "glink") SELECT "flnam", "haltnam", "tezgnam", "aufteilen", "teilgebiet", "geom", "gbuf", "glink" FROM "linkfl_t";""", u"""SELECT DiscardGeometryColumn('linkfl_t','geom')""", u"""SELECT DiscardGeometryColumn('linkfl_t','gbuf')""", u"""SELECT DiscardGeometryColumn('linkfl_t','glink')""", u"""DROP TABLE linkfl_t;""" ] for sql in sqllis: if not self.sql( sql, u'dbfunc.version (2.2.2-6)', transaction=True): return False # 3. Schritt: Trigger wieder herstellen # for el in triggers: # if el[0] != 'table': # sql = el[1] # logger.debug(u"Trigger 'linkfl' verarbeitet:\n{}".format(el[1])) # if not self.sql(sql, u'dbfunc.version (2.2.2-7)', transaction=True): # return False # else: # logger.debug(u"1. Trigger 'table' erkannt:\n{}".format(el[1])) # 4. Schritt: Transaction abschließen self.commit() progress_bar.setValue(60) # Tabelle einleit ------------------------------------------------------------- # 1. Schritt: Trigger für zu ändernde Tabelle abfragen und in triggers speichern # sql = u"""SELECT type, sql FROM sqlite_master WHERE tbl_name='einleit'""" # if not self.sql(sql, u'dbfunc.version.pragma (7)'): # return False # triggers = self.fetchall() # 2. Schritt: Tabelle umbenennen, neu anlegen und Daten rüberkopieren sqllis = [ u"""BEGIN TRANSACTION;""", u"""CREATE TABLE einleit_t ( pk INTEGER PRIMARY KEY AUTOINCREMENT, elnam TEXT, haltnam TEXT, teilgebiet TEXT, zufluss REAL, ew REAL, einzugsgebiet TEXT, kommentar TEXT, createdat TEXT DEFAULT CURRENT_DATE);""", u"""SELECT AddGeometryColumn('einleit_t','geom',{},'POINT',2)""" .format(self.epsg), u"""INSERT INTO einleit_t ( "elnam", "haltnam", "teilgebiet", "zufluss", "ew", "einzugsgebiet", "kommentar", "createdat", "geom") SELECT "elnam", "haltnam", "teilgebiet", "zufluss", "ew", "einzugsgebiet", "kommentar", "createdat", "geom" FROM "einleit";""", u"""SELECT DiscardGeometryColumn('einleit','geom')""", u"""DROP TABLE einleit;""", u"""CREATE TABLE einleit ( pk INTEGER PRIMARY KEY AUTOINCREMENT, elnam TEXT, haltnam TEXT, teilgebiet TEXT, zufluss REAL, ew REAL, einzugsgebiet TEXT, kommentar TEXT, createdat TEXT DEFAULT CURRENT_DATE);""", u"""SELECT AddGeometryColumn('einleit','geom',{},'POINT',2)""". format(self.epsg), u"""SELECT CreateSpatialIndex('einleit','geom')""", u"""INSERT INTO einleit ( "elnam", "haltnam", "teilgebiet", "zufluss", "ew", "einzugsgebiet", "kommentar", "createdat", "geom") SELECT "elnam", "haltnam", "teilgebiet", "zufluss", "ew", "einzugsgebiet", "kommentar", "createdat", "geom" FROM "einleit_t";""", u"""SELECT DiscardGeometryColumn('einleit_t','geom')""", u"""DROP TABLE einleit_t;""" ] for sql in sqllis: if not self.sql( sql, u'dbfunc.version (2.2.2-8)', transaction=True): return False # 3. Schritt: Trigger wieder herstellen # for el in triggers: # if el[0] != 'table': # sql = el[1] # logger.debug(u"Trigger 'einleit' verarbeitet:\n{}".format(el[1])) # if not self.sql(sql, u'dbfunc.version (2.2.2-9)', transaction=True): # return False # else: # logger.debug(u"1. Trigger 'table' erkannt:\n{}".format(el[1])) # 4. Schritt: Transaction abschließen self.commit() progress_bar.setValue(100) status_message.setText( u"Achtung! Benutzerhinweis: Die Datenbank wurde geändert. Bitte QGIS-Projekt neu laden..." ) status_message.setLevel(QgsMessageBar.WARNING) iface.messageBar().pushMessage( u"Achtung! Benutzerhinweis!", u"Die Datenbank wurde geändert. Bitte QGIS-Projekt neu laden...", level=QgsMessageBar.WARNING, duration=0) # Versionsnummer hochsetzen self.versionlis = [2, 2, 3] # --------------------------------------------------------------------------------------------------------- if versionolder(self.versionlis, [2, 2, 16]): sql = u""" CREATE TABLE IF NOT EXISTS dynahal ( pk INTEGER PRIMARY KEY AUTOINCREMENT, haltnam TEXT, schoben TEXT, schunten TEXT, teilgebiet TEXT, kanalnummer TEXT, haltungsnummer TEXT, anzobob INTEGER, anzobun INTEGER, anzunun INTEGER, anzunob INTEGER)""" if not self.sql(sql, u'dbfunc.version (2.4.1-1)'): return False sql = u""" ALTER TABLE profile ADD COLUMN kp_key TEXT """ if not self.sql(sql, u'dbfunc.version (2.4.1-3)'): return False sql = u""" ALTER TABLE entwaesserungsarten ADD COLUMN kp_nr INTEGER """ if not self.sql(sql, u'dbfunc.version (2.4.1-2)'): return False sqllis = [ u"""UPDATE entwaesserungsarten SET kp_nr = 0 WHERE bezeichnung = 'Mischwasser'""", u"""UPDATE entwaesserungsarten SET kp_nr = 1 WHERE bezeichnung = 'Schmutzwasser'""", u"""UPDATE entwaesserungsarten SET kp_nr = 2 WHERE bezeichnung = 'Regenwasser'""" ] for sql in sqllis: if not self.sql(sql, u'dbfunc.version (2.4.1-4)'): return False self.commit() # Versionsnummer hochsetzen self.versionlis = [2, 2, 16] # --------------------------------------------------------------------------------------------------------- if versionolder(self.versionlis, [2, 4, 9]): sql = u'''DROP VIEW IF EXISTS "v_linkfl_check"''' if not self.sql(sql, u'dbfunc.version (2.4.9-1)'): return False sql = u'''CREATE VIEW IF NOT EXISTS "v_linkfl_check" AS WITH lfok AS ( SELECT lf.pk AS "pk", lf.flnam AS "linkfl_nam", lf.haltnam AS "linkfl_haltnam", fl.flnam AS "flaech_nam", tg.flnam AS "tezg_nam", min(lf.pk) AS pkmin, max(lf.pk) AS pkmax, count(*) AS anzahl FROM linkfl AS lf LEFT JOIN flaechen AS fl ON lf.flnam = fl.flnam LEFT JOIN tezg AS tg ON lf.tezgnam = tg.flnam WHERE fl.aufteilen = "ja" and fl.aufteilen IS NOT NULL GROUP BY fl.flnam, tg.flnam UNION SELECT lf.pk AS "pk", lf.flnam AS "linkfl_nam", lf.haltnam AS "linkfl_haltnam", fl.flnam AS "flaech_nam", NULL AS "tezg_nam", min(lf.pk) AS pkmin, max(lf.pk) AS pkmax, count(*) AS anzahl FROM linkfl AS lf LEFT JOIN flaechen AS fl ON lf.flnam = fl.flnam WHERE fl.aufteilen <> "ja" OR fl.aufteilen IS NULL GROUP BY fl.flnam) SELECT pk, anzahl, CASE WHEN anzahl > 1 THEN 'mehrfach vorhanden' WHEN flaech_nam IS NULL THEN 'Keine Fläche' WHEN linkfl_haltnam IS NULL THEN 'Keine Haltung' ELSE 'o.k.' END AS fehler FROM lfok''' if not self.sql(sql, u'dbfunc.version (2.4.9-2)'): return False sql = u'''DROP VIEW IF EXISTS "v_flaechen_ohne_linkfl"''' if not self.sql(sql, u'dbfunc.version (2.4.9-3)'): return False sql = u'''CREATE VIEW IF NOT EXISTS "v_flaechen_ohne_linkfl" AS SELECT fl.pk, fl.flnam AS "flaech_nam", fl.aufteilen AS "flaech_aufteilen", 'Verbindung fehlt' AS "Fehler" FROM flaechen AS fl LEFT JOIN linkfl AS lf ON lf.flnam = fl.flnam LEFT JOIN tezg AS tg ON tg.flnam = lf.tezgnam WHERE ( (fl.aufteilen <> "ja" or fl.aufteilen IS NULL) AND lf.pk IS NULL) OR ( fl.aufteilen = "ja" AND fl.aufteilen IS NOT NULL AND lf.pk IS NULL) UNION VALUES (0, '', '', 'o.k.')''' if not self.sql(sql, u'dbfunc.version (2.4.9-4)'): return False self.commit() # Versionsnummer hochsetzen self.versionlis = [2, 4, 9] # --------------------------------------------------------------------------------------------------------- if versionolder(self.versionlis, [2, 5, 2]): # Einleitungen aus Aussengebieten ---------------------------------------------------------------- sql = u'''CREATE TABLE aussengebiete ( pk INTEGER PRIMARY KEY AUTOINCREMENT, gebnam TEXT, schnam TEXT, hoeheob REAL, hoeheun REAL, fliessweg REAL, basisabfluss REAL, cn REAL, regenschreiber TEXT, teilgebiet TEXT, kommentar TEXT, createdat TEXT DEFAULT CURRENT_DATE)''' if not self.sql(sql, u'dbfunc.version (2.5.2-1)'): return False sql = u"""SELECT AddGeometryColumn('aussengebiete','geom',{},'MULTIPOLYGON',2)""".format( self.epsg) if not self.sql(sql, u'dbfunc.version (2.5.2-2)'): return False sql = u"""SELECT CreateSpatialIndex('aussengebiete','geom')""" if not self.sql(sql, u'dbfunc.version (2.5.2-3)'): return False # Anbindung Aussengebiete ------------------------------------------------------------------------- sql = u"""CREATE TABLE linkageb ( pk INTEGER PRIMARY KEY AUTOINCREMENT, gebnam TEXT, schnam TEXT, teilgebiet TEXT)""" if not self.sql(sql, u'dbfunc.version (2.5.2-4)'): return False sql = u"""SELECT AddGeometryColumn('linkageb','glink',{epsg},'LINESTRING',2)""".format( epsg=self.epsg) if not self.sql(sql, u'dbfunc.version (2.5.2-5)'): return False sql = u"""SELECT CreateSpatialIndex('linkageb','glink')""" if not self.sql(sql, u'dbfunc.version (2.5.2-6)'): return False self.commit() # Versionsnummer hochsetzen self.versionlis = [2, 5, 2] # Formulare aktualisieren ---------------------------------------------------------- # # Dieser Block muss im letzten Update vorkommen, in dem auch Formulare geändert wurden... # # Spielregel: QKan-Formulare werden ohne Rückfrage aktualisiert. # Falls eigene Formulare gewünscht sind, können diese im selben Verzeichnis liegen, # die Eingabeformulare müssen jedoch andere Namen verwenden, auf die entsprechend # in der Projektdatei verwiesen werden muss. try: projectpath = os.path.dirname(self.dbname) if u'eingabemasken' not in os.listdir(projectpath): os.mkdir(os.path.join(projectpath, u'eingabemasken')) formpath = os.path.join(projectpath, u'eingabemasken') formlist = os.listdir(formpath) logger.debug( u"\nEingabeformulare aktualisieren: \n" + "projectpath = {projectpath}\n".format( projectpath=projectpath) + "formpath = {formpath}\n".format(formpath=formpath) + "formlist = {formlist}\n".format(formlist=formlist) + "templatepath = {templatepath}".format( templatepath=self.templatepath)) for formfile in glob.iglob( os.path.join(self.templatepath, u'*.ui')): logger.debug( u"Eingabeformular aktualisieren: {} -> {}".format( formfile, formpath)) shutil.copy2(formfile, formpath) except BaseException as err: fehlermeldung( u'Fehler beim Aktualisieren der Eingabeformulare\n', u"{e}".format(e=repr(err))) # ------------------------------------------------------------------------------------------ # Aktuelle Version in Tabelle "info" schreiben sql = u"""UPDATE info SET value = '{}' WHERE subject = 'version'""".format( self.actversion) if not self.sql(sql, u'dbfunc.version (aktuell)'): return False self.commit() return True
class OWDatabasesPack(OWWidget.OWWidget): settingsList = ["fileslist", "downloadurl", "downloadmessage"] def __init__(self, parent=None, signalManager=None, title="Databases Pack"): super(OWDatabasesPack, self).__init__(parent, signalManager, title, wantMainArea=False) self.fileslist = [("Taxonomy", "ncbi_taxonomy.tar.gz")] self.downloadurl = "https://dl.dropboxusercontent.com/u/100248799/sf_pack.tar.gz" self.downloadmessage = ( "Downloading a subset of available databases for a smoother " + "ride through the workshop" ) self.loadSettings() self._tmpfile = None self.reply = None # Locks held on server files self.locks = [] self.net_manager = QNetworkAccessManager() # Lock all files in files list so any other (in process) atempt to # download the files waits) box = OWGUI.widgetBox(self.controlArea, "Info") self.info = OWGUI.widgetLabel(box, self.downloadmessage) self.info.setWordWrap(True) box = OWGUI.widgetBox(self.controlArea, "Status") self.statusinfo = OWGUI.widgetLabel(box, "Please wait") self.statusinfo.setWordWrap(True) self.progressbar = QProgressBar() box.layout().addWidget(self.progressbar) self.setMinimumWidth(250) already_available = [ (domain, filename) for domain in serverfiles.listdomains() for filename in serverfiles.listfiles(domain) ] if set(self.fileslist) <= set(already_available): # All files are already downloaded self.statusinfo.setText("All files already available") self.setStatusMessage("Done") else: for domain, filename in self.fileslist + [("_tmp_cache_", "pack")]: manager = serverfiles._lock_file(domain, filename) try: manager.__enter__() except Exception: warnings.warn("Could not acquire lock for {0} {0}".format(domain, filename)) self.warning(0, "...") else: self.locks.append(manager) QTimer.singleShot(0, self.show) QTimer.singleShot(0, self.run) def run(self): self.setStatusMessage("Downloading") self.info.setText(self.downloadmessage) target_dir = os.path.join(environ.buffer_dir, "serverfiles_pack_cache") try: os.makedirs(target_dir) except OSError: pass self.progressBarInit() req = QNetworkRequest(QUrl(self.downloadurl)) self.reply = self.net_manager.get(req) self.reply.downloadProgress.connect(self._progress) self.reply.error.connect(self._error) self.reply.finished.connect(self._finished) self.reply.readyRead.connect(self._read) url = urlparse.urlsplit(self.downloadurl) self._tmpfilename = posixpath.basename(url.path) self._tmpfile = open(os.path.join(target_dir, self._tmpfilename), "wb+") def _progress(self, rec, total): if rec == 0 and total == 0: self.progressbar.setRange(0, 0) self.progressBarValue = 1.0 else: self.progressbar.setRange(0, total) self.progressbar.setValue(rec) self.progressBarValue = 100.0 * rec / (total or 1) def _error(self, error): self.statusinfo.setText(u"Error: {0}".format(error.errorString())) self.error(0, "Error: {0}".format(error.errorString())) self.setStatusMessage("Error") self._releaselocks() self._removetmp() self.progressBarFinshed() def _read(self): contents = str(self.reply.readAll()) self._tmpfile.write(contents) def _finished(self): self.progressbar.reset() if self.reply.error() != QNetworkReply.NoError: self._releaselocks() self._removetmp() return self.statusinfo.setText("Extracting") self.setStatusMessage("Extracting") try: self._extract() except Exception: # Permission errors, ... ?? pass self.statusinfo.setText("Done") self.setStatusMessage("Done") self.progressbar.reset() self.progressBarFinished() self._releaselocks() self._removetmp() def _extract(self): self._tmpfile.seek(0, 0) archive = tarfile.open(fileobj=self._tmpfile) target_dir = serverfiles.localpath() archive.extractall(target_dir) def onDeleteWidget(self): super(OWDatabasesPack, self).onDeleteWidget() self._releaselocks() if self.reply is not None and self.reply.isOpen(): self.reply.finished.disconnect(self._finished) self.reply.error.disconnect(self._error) self.reply.close() if self._tmpfile is not None: self._tmpfile.close() self._tmpfile = None def _releaselocks(self): for lock in self.locks: lock.__exit__(None, None, None) self.locks = [] def _removetmp(self): if self._tmpfile is not None: self._tmpfile.close() self._tmpfile = None tmp_file = os.path.join(environ.buffer_dir, "serverfiles_pack_cache", self._tmpfilename) os.remove(tmp_file)
class FileItem(QTreeWidgetItem): cols = ['Filepath', 'Renamed Filepath'] invalid_char_map = {':': ''} re_filename_episodes = [ re.compile( r'.*[Ss](?P<season>\d{1,2})[\s\-_]*[Ee](?P<episode>\d{1,2}).*', re.I), re.compile( r'.*season\s*(?P<season>\d{1,2})[\s\-_]*episode\s*[Ee](?P<episode>\d{1,2}).*', re.I), ] re_filepath_episodes = [ re.compile( r'.*season\s*(?P<season>\d{1,2})\\(?:season\s*\d{1,2}[\s\-_]*)?(?:episode|ep\.?|e)\s*(?P<episode>\d{1,2}).*', re.I), ] def __init__(self, parent, filepath, mediaman): super(FileItem, self).__init__(parent) self._renamed = False self.mediaman = mediaman self.filepath = filepath self.renamed_filepath = None self.media_info = None self.episode_info = None self.thread = None self.pbar = None self.setText(0, self.filepath) self.send_thread() def send_thread(self): if self.thread is None: self.thread = FilepathSearchThread(self.treeWidget()) self.thread.finished.connect(self.receive_thread) thread_ready = self.thread.wait(10000) if thread_ready: tree = self.treeWidget() self.pbar = QProgressBar(tree) self.pbar.setRange(0, 0) tree.setItemWidget(self, 1, self.pbar) self.thread.filepath = self.filepath self.thread.start() def receive_thread(self): self.media_info = self.thread.result self.pbar.reset() tree = self.treeWidget() tree.removeItemWidget(self, 1) self.pbar.deleteLater() self.refresh() def _replace_invalid_chars(self, text): for k, v in FileItem.invalid_char_map.items(): if k in text: text = text.replace(k, v) return text def refresh(self): moviedir = self.mediaman.moviedir() tvdir = self.mediaman.tvdir() if self.media_info: title = self.media_info.get('title') title = self._replace_invalid_chars(title) year = self.media_info.get('year') filename, ext = os.path.splitext(os.path.basename(self.filepath)) if self.episode_info or self.media_info.get('episodes'): if not self.episode_info: episodes = self.media_info['episodes'] ep_match = None for reg in FileItem.re_filename_episodes: m = reg.search(filename) if m: ep_match = m.groupdict() break if not ep_match: for reg in FileItem.re_filepath_episodes: m = reg.search(self.filepath) if m: ep_match = m.groupdict() if ep_match: season, episode = int(ep_match['season']), int( ep_match['episode']) for episode_info in episodes: if (episode_info['season'], episode_info['episode']) == (season, episode): self.episode_info = episode_info break if self.episode_info: self.renamed_filepath = ur'{tvdir}\{title}\Season{season:02d}\{title}.S{season:02d}E{episode:02d}.{episode_title}{ext}'.format( tvdir=tvdir, title=title, year=year, season=self.episode_info['season'], episode=self.episode_info['episode'], episode_title=self._replace_invalid_chars( self.episode_info['title']), ext=ext, ) else: self.renamed_filepath = ur'{tvdir}\{title}\Season00\{title}.S00E00.XXX{ext}'.format( tvdir=tvdir, title=title, year=year, ext=ext, ) else: self.renamed_filepath = ur'{moviedir}\{title} ({year})\{title}{ext}'.format( moviedir=moviedir, title=title, year=year, ext=ext) self.setText(1, self.renamed_filepath) if os.path.exists(self.renamed_filepath): self.setBackgroundColor( FileItem.cols.index('Renamed Filepath'), QColor(0, 255, 0, 100))
class RipperWidget(SmoothWidget, ripper.Ripper): """ One-button multi-track ripper. """ def __init__(self, parent=None): SmoothWidget.__init__(self, parent) ripper.Ripper.__init__(self) Layout = QVBoxLayout(self) self.discLabel = QLabel(self) Layout.addWidget(self.discLabel) # ONLY ONE BUTTON! self.button = QPushButton('Cancel', self) self.button.setEnabled(True) self.button.hide() QObject.connect(self.button, SIGNAL('clicked()'), self.cancel) Layout.addWidget(self.button) self.catFrame = QFrame(self) self.catFrame.setFrameStyle(QFrame.StyledPanel) self.catFrame.hide() QHBoxLayout(self.catFrame) self.categories = CategoryButtons(self.catFrame) QObject.connect(self.categories, SIGNAL('selected(QString &)'), self.start) self.catFrame.layout().addWidget(self.categories) Layout.addWidget(self.catFrame) self.progress = QProgressBar(self) self.progress.setRange(0, 100) self.progress.hide() Layout.addWidget(self.progress) def start(self, category): """ Should already have the track info. """ self.genre = str(category) self._progress_data = {} self.disc_length = 0.0 for i in range(self.count): sec = cd_logic.get_track_time_total(i) self._progress_data[i] = {'rip' : 0, 'enc' : 0, 'length' : sec} self.disc_length += sec self.rip_n_encode() text = '%s - %s' % (self.artist, self.album) self.discLabel.setText('Copying "'+text+'"...') self.button.show() self.progress.show() self.catFrame.hide() def cancel(self): self.stop_request = True path = os.path.join(ripper.LIBRARY, self.genre, self.artist+' - '+self.album) os.system('rm -rf \"%s\"' % path) self.discLabel.setText('Canceled') self.button.hide() self.progress.hide() self.progress.setValue(0) self.emit(SIGNAL('canceled()')) def read_disc_info(self): self.discLabel.setText('Getting disc info...') ripper.Ripper.read_disc_info(self) def ripper_event(self, e): """ """ event = QEvent(event_type(e.type)) event.data = e.__dict__ QApplication.instance().postEvent(self, event) def customEvent(self, e): if e.type() == event_type(ripper.CDDB_DONE): self.button.setEnabled(True) text = '%s - %s' % (self.artist, self.album) text += ' ( Select a category... )' self.discLabel.setText(text) self.catFrame.show() self.emit(SIGNAL('foundDiscInfo()')) elif e.type() == event_type(ripper.STATUS_UPDATE): self.updateProgress(e.data) self.emit(SIGNAL('status(QEvent *)'), e) def updateProgress(self, data): """ assume rip and enc are equal in time. """ state = data['state'] tracknum = data['tracknum'] percent = data['percent'] goal_percents = self.count * 200 item = self._progress_data[tracknum] if state == 'rip': item['rip'] = percent elif state == 'enc': item['enc'] = percent else: # err, etc... item['rip'] = 0 item['enc'] = 0 total = 0 for i, v in self._progress_data.items(): seconds = v['length'] rip_perc = v['rip'] enc_perc = v['enc'] worth = seconds / self.disc_length rip_perc *= worth enc_perc *= worth total += rip_perc + enc_perc #print i, worth, rip_perc, enc_perc, total percent = total / 2 self.progress.setValue(percent) if percent == 100: if self.is_ripping: print 'percent == 100 but still ripping?' if self.is_encoding: print 'percent == 100 but still encoding?' else: print 'percent == 100 and ripper finished' self.button.hide() self.progress.hide() text = 'Finished copying \"%s - %s\"' % (self.artist, self.album) self.discLabel.setText(text) self.emit(SIGNAL('doneRipping()'))
class MainWindow(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.setWindowTitle('%s %s' % (QApplication.applicationName(), QApplication.applicationVersion())); self.config = ConfigHandler(os.path.join(os.path.expanduser('~'), '.pywv/pywv.cfg'), self) self.setStyle(QStyleFactory.create(self.config.loadStyle())) if self.config.loadStyleSheet(): self.setStyleSheet(self.config.loadStyleSheet()) else: self.setStyleSheet("* {}") # without any stylesheet, windowstyles won't apply self.setDockOptions(QMainWindow.AnimatedDocks | QMainWindow.AllowNestedDocks | QMainWindow.AllowTabbedDocks | QMainWindow.VerticalTabs); # self.dummy = QWidget(self) self.setCentralWidget(QWidget(self)) self.pBar = QProgressBar(self) self.pBar.setRange(0, self.config.loadReloadInterval()) self.pBar.setFormat("%v Sekunden") if not self.config.loadAutoload(): self.pBar.hide() self.statusBar = QStatusBar(self) self.setStatusBar(self.statusBar) self.statusBar.addWidget(self.pBar) self.reloadTimer = QTimer(self); self.reloadTimer.setInterval(self.config.loadReloadInterval() * 1000) self.connect(self.reloadTimer, SIGNAL('timeout()'), self.reload_) if self.config.loadAutoload(): self.reloadTimer.start() self.autoloadStatusTimer = QTimer(self) self.autoloadStatusTimer.setInterval(1000) # 1 sec self.connect(self.autoloadStatusTimer, SIGNAL('timeout()'), self.onAutoloadStatus) self.autoloadStatusTimer.start() self.mAction = self.menuBar().addMenu(self.tr("&Action")) self.mAction.addAction(self.tr("&update"), self.reload_, QKeySequence('F5')) self.mAction.addAction(self.tr("e&xit"), self.onExit, 'Ctrl+Q') self.mStyle = QMenu(self.tr("&Style"), self) for s in list(QStyleFactory.keys()):# // fill in all available Styles self.mStyle.addAction(s) self.connect(self.mStyle, SIGNAL('triggered(QAction*)'), self.onStyleMenu) self.mOption = self.menuBar().addMenu(self.tr("&Options")) self.mOption.addAction(self.tr("reloadinterval") , self.onReloadTime , 'F8') self.mOption.addAction(self.tr("manage links") , self.onNewLink , 'F6') self.mOption.addSeparator() self.ontopAction = QAction(self.tr("always on &top") , self) self.showTrayAction = QAction(self.tr("show tray &icon") , self) self.closeToTrayAction = QAction(self.tr("close to &tray") , self) self.autoloadAction = QAction(self.tr("auto&load") , self) self.ontopAction.setCheckable(True) self.showTrayAction.setCheckable(True) self.closeToTrayAction.setCheckable(True) self.autoloadAction.setCheckable(True) self.showTrayAction.setChecked (self.config.loadShowTray() ) self.ontopAction.setChecked (self.config.loadOntop() ) self.closeToTrayAction.setChecked(self.config.loadCloseToTray()) self.autoloadAction.setChecked (self.config.loadAutoload() ) self.connect(self.ontopAction , SIGNAL('toggled(bool)') , self.onOntopAction) self.connect(self.showTrayAction , SIGNAL('toggled(bool)') , self.onShowTrayAction) self.connect(self.closeToTrayAction , SIGNAL('toggled(bool)') , self.onCloseToTrayAction) self.connect(self.autoloadAction , SIGNAL('toggled(bool)') , self.onAutoloadAction) self.mOption.addAction(self.ontopAction) self.mOption.addAction(self.showTrayAction) self.mOption.addAction(self.closeToTrayAction) self.mOption.addAction(self.autoloadAction) self.mOption.addSeparator() self.mOption.addMenu(self.mStyle) self.trayIcon = QSystemTrayIcon(QIcon(':/appicon'), self); self.trayMgr = TrayManager(self.config, self.trayIcon) self.connect(self.trayIcon, SIGNAL('activated(QSystemTrayIcon::ActivationReason)'), self.onTrayIcon) if self.config.loadShowTray(): self.trayIcon.show() self.trayIconMenu = QMenu() self.trayIconMenu.addAction(self.tr("e&xit"), self.onExit) self.trayIcon.setContextMenu(self.trayIconMenu) self.mAbout = self.menuBar().addMenu(self.tr("&about")) self.mAbout.addAction(QApplication.applicationName(), self.onAboutAppAction) self.mAbout.addAction("Qt", self.onAboutQtAction) self.createWidgets() self.resize(self.config.loadWindowSize()) self.restoreState(self.config.loadWindowState()) if self.config.loadIsVisible(): self.show() self.reload_() def __del__(self): self.config.saveWindowState(self.saveState()) def createSingleWidget(self, name): # print 'crt', name, type(name), '\n', self.widgets # print 'crt', name, type(name) links = self.config.loadLinks() if links[name]['type'] == 'generic': self.widgets[name] = GenericWidget(name, self.config, self) else: pluginsAvail = classdirPlugins().all_() for plugin in pluginsAvail: if links[name]['type'] == plugin['class']: pluginClass = plugin['class'] break else: continue exec('self.widgets[name] = %s(name, self.config, self)' % pluginClass) # print(('loaded plugin', self.widgets[name])) self.addDockWidget(0x4, self.widgets[name]) self.widgets[name].reload_() def delWidget(self, name): #print 'del', name, type(name), '\n', self.widgets self.removeDockWidget(self.widgets[name]) self.widgets[name].deleteLater() self.widgets[name] = None del self.widgets[name] def createWidgets(self): self.widgets = {} for name in self.config.loadLinks(): self.createSingleWidget(name) @pyqtSlot() def onExit(self): self.config.saveWindowSize(self.size()) QApplication.exit(); def closeEvent(self, event): self.config.saveWindowSize(self.size()) # QApplication.exit() # tray is visible -> close to tray # else close app if self.trayIcon.isVisible(): event.accept() else: QApplication.exit() return # if close-to-tray is set, do so if self.config.loadCloseToTray(): event.accept() else: QApplication.exit() return; # save this state if self.trayIcon.isVisible(): self.config.saveIsVisible(False) else: self.config.saveIsVisible(True); @pyqtSlot() def reload_(self): for name in self.widgets: self.widgets[name].reload_() self.pBar.setValue(self.config.loadReloadInterval()) self.reloadTimer.start(self.config.loadReloadInterval()*1000) @pyqtSlot() def onAutoloadStatus(self): self.pBar.setValue(self.pBar.value()-1) # print([idx for idx in self.widgets]) def onStyleMenu(self, a): QApplication.setStyle(QStyleFactory.create(a.text())) self.setStyle(QStyleFactory.create(a.text())) self.config.saveStyle(a.text()) def onReloadTime(self): ok = False value, ok = QInputDialog.getInteger(self, self.tr("reloadinterval"), # title self.tr("insert time in s"), # text self.config.loadReloadInterval(), # default 10, # minimum 86400, # maximum (at least once a day) 1, # step ) if ok: self.config.saveReloadInterval(value) self.pBar.setRange(0,self.config.loadReloadInterval()) self.reload_() def onAutoloadAction(self, b): if b: self.reloadTimer.start() self.pBar.show() self.reload_() else: self.reloadTimer.stop() self.pBar.hide() self.config.saveAutoload(b) def onNewLink(self): inp = LinkInput(self.config, self) if inp.exec_(): # sync active widgets for name in inp.modifiedWidgets(): if name in self.widgets: self.delWidget(name) self.createSingleWidget(name) else: self.createSingleWidget(name) # remove deleted # for name in self.widgets: print 'shown', name # for name in self.config.loadLinks(): print 'conf', name todel = [] for name in self.widgets: if name not in self.config.loadLinks(): todel.append(name) for widget in todel: self.delWidget(widget) def onOntopAction(self, b): if b: self.setWindowFlags(Qt.Dialog | Qt.WindowStaysOnTopHint) else: self.setWindowFlags(Qt.Dialog) self.setWindowIcon(QIcon(':/appicon')) self.show(); self.config.saveOntop(b) def onShowTrayAction(self, b): if b: self.trayIcon.show() else: self.trayIcon.hide() self.config.saveShowTray(b) def onCloseToTrayAction(self, b): self.config.saveCloseToTray(b) def onTrayIcon(self, reason): if reason == QSystemTrayIcon.Trigger: if(self.isVisible()): self.config.saveWindowSize(self.size()) self.hide() self.config.saveIsVisible(False) else: self.show() self.resize(self.config.loadWindowSize()) self.config.saveIsVisible(True) def onAboutAppAction(self): QMessageBox.about(self, self.tr("&about"), self.tr("name %1 version %2").arg(QApplication.applicationName()).arg(QApplication.applicationVersion())) def onAboutQtAction(self): QMessageBox.aboutQt(self, self.tr("&about"))
class mainWin(QMainWindow): def __init__(self, parent=None): QMainWindow.__init__(self, parent) screen = QDesktopWidget().screenGeometry() self.setGeometry(80, 100, int((1/2)*screen.width()), int((4/10)*screen.height())) self.main_frame = QFrame() self.cw = QFrame() self.cw.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken) self.main_sizer = QVBoxLayout() self.hbox1_sizer = QHBoxLayout() self.setWindowTitle(self.tr("Consonance Rating")) ## self.sessionRunning = False self.listenerID = "" self.currentTrial = 1 self.intervals_db = pd.read_csv(os.path.abspath(os.path.dirname(__file__)) + "/resources/intervals_database.csv", sep=";") # self.rootNotes = np.array([110, 130.81, 185]) # self.intervalsCents = np.array([100, # 500, # 600, # 700, # 800, # 1100]) #self.rootNotes = np.array([110, 185]) self.rootNotes = np.array([146.83, 155.56, 164.81, 174.61, 185, 196, 207.65, 220]) self.intervalsCents = np.array([600, 700 ]) self.diadDur = 1980 self.diadRamps = 10 self.diadTotLev = np.array([40, 80]) self.diadFilterType = "lowpass" self.diadFilterCutoffs = (2500,) self.diadLowHarm = 1 self.diadHighHarm = 50 self.diadNote1Chan = "Both" self.diadNote2Chan = "Both" self.fs = 48000 self.maxLevel = self.getPhonesCal() self.noise1SL = -200 self.noise1LowFreq = 0 self.noise1HighFreq = 2000 self.noise1Type = "Pink" self.noise2Type = "Pink" self.noise2SL = np.array([0, 40]) self.noise2LowFreq = 4000 self.noise2HighFreq = 8000 self.noise1RefHz = 100 self.noise2RefHz = 4000 self.preTrialNoiseRefHz = 1000 self.preTrialNoiseLowFreq = 20 self.preTrialNoiseHighFreq = 8000 self.preTrialNoiseDur = 1980 self.preTrialNoiseRamps = 10 self.preTrialNoiseSL = np.array([0, 40]) self.preTrialNoiseType = "Pink" self.preTrialNoiseChannel = "Both" self.preTrialNoiseDiadISI = 500 self.noiseChannel = "Both" self.nPracticeTrialsXStim = 4 self.nTrialsXStim = 2 self.nTrials = len(self.rootNotes)*len(self.intervalsCents)*len(self.diadTotLev)*(self.nTrialsXStim) + self.nPracticeTrialsXStim*len(self.intervalsCents)*len(self.diadTotLev) print(self.nTrials) practiceTrials = [] mainTrials = [] for rootNote in self.rootNotes: for intervalCents in self.intervalsCents: for n in range(self.nTrialsXStim): mainTrials.append((rootNote, intervalCents, "main", self.diadTotLev[0], self.noise2SL[0], self.preTrialNoiseSL[0])) for intervalCents in self.intervalsCents: for n in range(self.nPracticeTrialsXStim): practiceTrials.append((random.choice(self.rootNotes), intervalCents, "practice", self.diadTotLev[0], self.noise2SL[0], self.preTrialNoiseSL[0])) random.shuffle(practiceTrials) random.shuffle(mainTrials) practiceTrials2 = [] mainTrials2 = [] for rootNote in self.rootNotes: for intervalCents in self.intervalsCents: for n in range(self.nTrialsXStim): mainTrials2.append((rootNote, intervalCents, "main", self.diadTotLev[1], self.noise2SL[1], self.preTrialNoiseSL[1])) for intervalCents in self.intervalsCents: for n in range(self.nPracticeTrialsXStim): practiceTrials2.append((random.choice(self.rootNotes), intervalCents, "practice", self.diadTotLev[1], self.noise2SL[1], self.preTrialNoiseSL[1])) random.shuffle(practiceTrials2) random.shuffle(mainTrials2) #root note #interval cents #practice or main #dialTotLev #noise2SL #preTrialNoiseSL #remove some practice trials #practiceTrials = practiceTrials[0:4] #practiceTrials2 = practiceTrials2[0:4] self.trialList = [] if random.choice([0,1]) == 0: self.trialList.extend(practiceTrials) self.trialList.extend(practiceTrials2) else: self.trialList.extend(practiceTrials2) self.trialList.extend(practiceTrials) if random.choice([0,1]) == 0: self.trialList.extend(mainTrials) self.trialList.extend(mainTrials2) else: self.trialList.extend(mainTrials2) self.trialList.extend(mainTrials) print(len(self.trialList)) self.menubar = self.menuBar() self.fileMenu = self.menubar.addMenu(self.tr('-')) self.editPhonesAction = QAction(self.tr('Phones Calibration'), self) self.fileMenu.addAction(self.editPhonesAction) self.editPhonesAction.triggered.connect(self.onEditPhones) self.setupListenerButton = QPushButton(self.tr("Setup Listener"), self) self.setupListenerButton.clicked.connect(self.onClickSetupListenerButton) self.setupListenerButton.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)) # self.setupListenerButton.setToolTip(self.tr("Choose file to save results")) # self.setupListenerButton.setWhatsThis(self.tr("Choose where to save the result files")) self.setupListenerButton.setStyleSheet('font-size: 32pt; font-weight: bold') self.hbox1_sizer.addWidget(self.setupListenerButton) self.main_sizer.addLayout(self.hbox1_sizer) #statusButtonFont = QFont("Arial", 26); self.statusButton = QPushButton(self.tr("Start"), self) self.statusButton.clicked.connect(self.onClickStatusButton) self.statusButton.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)) self.main_sizer.addWidget(self.statusButton) #self.statusButton.setFont(statusButtonFont) self.statusButton.setStyleSheet('font-size: 32pt; font-weight: bold') self.statusButton.hide() self.cw.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) borderWidth = 4 self.main_sizer.addItem(QSpacerItem(20, 60, QSizePolicy.Fixed)) self.overallRatingSliderValue = QLabel(self.tr("0"), self) self.main_sizer.addWidget(self.overallRatingSliderValue) self.overallRatingSliderValue.setStyleSheet('font-size: 22pt; font-weight: normal') self.overallRatingSliderValue.setAlignment(Qt.AlignCenter) self.main_sizer.addItem(QSpacerItem(20,60, QSizePolicy.Fixed)) sliderFont = QFont("Ubuntu", 18) self.overallRatingSlider = Qwt.QwtSlider(self, Qt.Horizontal, Qwt.QwtSlider.BottomScale) self.overallRatingSlider.setFont(sliderFont) self.overallRatingSlider.setScale(-3.0,3.0, 1) self.overallRatingSlider.setRange(-3.0,3.0) self.overallRatingSlider.valueChanged[float].connect(self.sliderChanged) self.overallRatingSlider.setMinimumSize(800, 20) self.overallRatingSlider.setBorderWidth(borderWidth) self.main_sizer.addWidget(self.overallRatingSlider) self.main_sizer.addItem(QSpacerItem(20,30, QSizePolicy.Fixed)) self.gauge = QProgressBar(self) self.gauge.setRange(0, 100) self.main_sizer.addWidget(self.gauge) self.cw.setLayout(self.main_sizer) self.setCentralWidget(self.cw) self.show() def onClickStatusButton(self): if self.statusButton.text() == self.tr("Finished"): return self.sessionRunning = True self.statusButton.setText(self.tr("Running")) QApplication.processEvents() if self.listenerID == "": text, ok = QInputDialog.getText(self, "" , "Listener ID: ") if ok: self.listenerID = text self.statusButton.setText(self.tr("Start")) return if self.currentTrial == 1: self.setupListenerButton.hide() self.overallRatingSlider.setValue(0) self.overallRatingSliderValue.setText("") self.doTrial() return if self.overallRatingSliderValue.text() == "": ret = QMessageBox.warning(self, self.tr("Warning"), self.tr("You need to move the slider before going to the next trial.\nIf you want to assign a score of zero move the slider forth and then back to the zero position."), QMessageBox.Ok) return if self.currentTrial > 1: self.storeRating() self.gauge.setValue((self.currentTrial-1)/self.nTrials*100) #self.sliderChanged(0) self.sliderLabelReset() self.statusButton.setText(self.tr("Running")) QApplication.processEvents() if self.currentTrial <= self.nTrials : self.doTrial() else: self.statusButton.setText(self.tr("Finished")) def doTrial(self): self.statusButton.setText(self.tr("Running")) QApplication.processEvents() #root note rootNote = self.trialList[self.currentTrial-1][0] #interval cents intervalCents = self.trialList[self.currentTrial-1][1] #practice or main trialMode = self.trialList[self.currentTrial-1][2] #dialTotLev diadTotLev = self.trialList[self.currentTrial-1][3] #noise2SL noise2SL = self.trialList[self.currentTrial-1][4] #preTrialNoiseSL preTrialNoiseSL = self.trialList[self.currentTrial-1][5] try: intervalName = self.intervals_db["name"][self.intervals_db["cents"] == self.trialList[self.currentTrial-1][1]].values[0] except: intervalName = str(self.trialList[self.currentTrial-1][1]) print(intervalName) preTrialNoise = broadbandNoise(spectrumLevel=preTrialNoiseSL, duration=self.preTrialNoiseDur, ramp=self.preTrialNoiseRamps, channel=self.preTrialNoiseChannel, fs=self.fs, maxLevel=self.maxLevel) if self.preTrialNoiseType == "Pink": preTrialNoise = makePinkRef(preTrialNoise, self.fs, self.preTrialNoiseRefHz) preTrialNoise = fir2Filter2(preTrialNoise, filterType="bandpass", nTaps=256, cutoffs=(self.preTrialNoiseLowFreq, self.preTrialNoiseHighFreq), transitionWidth=0.2, fs=self.fs) diad = makeDiad(rootNote, intervalCents, filterType=self.diadFilterType, filterCutoffs=self.diadFilterCutoffs, lowHarm=self.diadLowHarm, highHarm=self.diadHighHarm, diadTotLev=diadTotLev, duration=self.diadDur, ramp=self.diadRamps, note1Channel=self.diadNote1Chan, note2Channel=self.diadNote2Chan, fs=self.fs, maxLevel=self.maxLevel) noise1 = broadbandNoise(spectrumLevel=self.noise1SL, duration=self.diadDur, ramp=self.diadRamps*6, channel=self.noiseChannel, fs=self.fs, maxLevel=self.maxLevel) if self.noise1Type == "Pink": noise1 = makePinkRef(noise1, self.fs, self.noise1RefHz) noise1 = fir2Filter2(noise1, filterType="bandpass", nTaps=256, cutoffs=(self.noise1LowFreq, self.noise1HighFreq), transitionWidth=0.2, fs=self.fs) noise1 = noise1[0:diad.shape[0],:] noise1 = gate(self.diadRamps, noise1, self.fs) noise2 = broadbandNoise(spectrumLevel=noise2SL, duration=self.diadDur, ramp=self.diadRamps*6, channel=self.noiseChannel, fs=self.fs, maxLevel=self.maxLevel) if self.noise2Type == "Pink": noise2 = makePinkRef(noise2, self.fs, self.noise2RefHz) noise2 = fir2Filter2(noise2, filterType="bandpass", nTaps=256, cutoffs=(self.noise2LowFreq, self.noise2HighFreq), transitionWidth=0.2, fs=self.fs) noise2 = noise2[0:diad.shape[0],:] noise2 = gate(self.diadRamps, noise2, self.fs) stim = diad+noise1+noise2 noiseDiadSilence = makeSilence(self.preTrialNoiseDiadISI) snd = np.concatenate((preTrialNoise, noiseDiadSilence, stim), axis=0) wavwrite(snd, self.fs, 32, "snd.wav") wavwrite(diad, self.fs, 32, "diad.wav") wavwrite(diad+noise1+noise2, self.fs, 32, "diad_in_noise.wav") sound(snd) self.currentTrial = self.currentTrial+1 def storeRating(self): try: intervalName = self.intervals_db["name"][self.intervals_db["cents"] == self.trialList[self.currentTrial-2][1]].values[0] except: intervalName = str(self.trialList[self.currentTrial-2][1]) #rootNote = str(self.trialList[self.currentTrial-2][0]) #root note rootNote = self.trialList[self.currentTrial-2][0] #interval cents intervalCents = self.trialList[self.currentTrial-2][1] #practice or main trialMode = self.trialList[self.currentTrial-2][2] #dialTotLev diadTotLev = self.trialList[self.currentTrial-2][3] #noise2SL noise2SL = self.trialList[self.currentTrial-2][4] #preTrialNoiseSL preTrialNoiseSL = self.trialList[self.currentTrial-2][5] # if self.currentTrial-1 <= len(self.rootNotes)*len(self.intervalsCents)*self.nPracticeTrialsXStim: # trialMode = "practice" # else: # trialMode = "main" self.thisPageFile.write(self.listenerID + ';') self.thisPageFile.write(str(rootNote) + ';') self.thisPageFile.write(intervalName + ';') self.thisPageFile.write(str(intervalCents) + ';') self.thisPageFile.write(trialMode + ';') self.thisPageFile.write(str(diadTotLev) + ';') #self.thisPageFile.write(str(noise2SL) + ';') self.thisPageFile.write(self.overallRatingSliderValue.text() + '\n') self.thisPageFile.flush() self.overallRatingSlider.setValue(0) self.overallRatingSliderValue.setText("") def sliderChanged(self, value): self.overallRatingSliderValue.setText(str(round(value,1))) if self.currentTrial > 1 and self.statusButton.text() != self.tr("Finished"): self.statusButton.setText(self.tr("Next")) def sliderLabelReset(self): self.overallRatingSliderValue.setText("0") def onClickSetupListenerButton(self): text, ok = QInputDialog.getText(self, "" , "Listener ID: ") if ok: self.listenerID = text else: return ftow = QFileDialog.getSaveFileName(self, self.tr('Choose file to write results'), "", self.tr('All Files (*)'), "", QFileDialog.DontConfirmOverwrite)[0] if len(ftow) > 0: self.thisPagePath = ftow self.thisPageFile = open(self.thisPagePath, "a") self.thisPageFile.write("listener;root_note;interval;intervalCents;trial_type;totLev;rating\n") self.setupListenerButton.hide() self.statusButton.show() else: return def getPhonesCal(self): fHandle = open(phonesCalFile, 'r') currCal = float(fHandle.readline().strip()) fHandle.close() return currCal def writePhonesCal(self, val): fHandle = open(phonesCalFile, 'w') fHandle.write(str(val)) fHandle.close() def onEditPhones(self): currCal = self.getPhonesCal() val, ok = QInputDialog.getDouble(self, self.tr('Phones Calibration'), self.tr('Phones Max. Level'), currCal) self.writePhonesCal(val) self.maxLevel = val
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 CompileWidget(QWidget): progress = pyqtSignal(int) def __init__(self, parent=None): QWidget.__init__(self, parent) self._options = None self._conf = None self._go = QPushButton('Go') self._go.setMaximumWidth(100) font = self._go.font() font.setPointSizeF(font.pointSizeF() * 2.0) font.setWeight(QFont.Bold) self._go.setFont(font) self._go.clicked.connect(self.go) self._saveLog = QPushButton('Save') saveLogLabel = QLabel('Log File:') saveLogBrowse = QPushButton('&Browse') saveLogBrowse.clicked.connect(self.browseSaveLog) self._saveLogEdit = QLineEdit('') gLayout = QGridLayout() gLayout.addWidget(saveLogLabel, 0, 0, 1, 1, Qt.AlignRight) gLayout.addWidget(self._saveLogEdit, 0, 1, 1, 6) gLayout.addWidget(saveLogBrowse, 0, 7, 1, 1) self._console = QTextEdit() self._console.setLineWrapMode(QTextEdit.NoWrap) self._console.setMinimumSize(800, 400) palette = self._console.palette() palette.setColor(QPalette.Base, QColor.fromRgb(255, 255, 221)) # ffffdd. self._console.setPalette(palette) font = QFont('Bitstream Vera Sans Mono', self._console.font().pointSize()) self._console.setFont(font) self._highlighter = Highlighter(self._console.document()) self._progressBar = QProgressBar() self._progressBar.setRange(0, 100) self._progressBar.setTextVisible(True) hLayout = QHBoxLayout() hLayout.addStretch() hLayout.addWidget(self._go) hLayout.addStretch() hLayout.addWidget(self._saveLog) hLayout.addStretch() vLayout = QVBoxLayout() vLayout.addLayout(hLayout) vLayout.addLayout(gLayout) vLayout.addWidget(self._progressBar) vLayout.addWidget(self._console) self.setLayout(vLayout) self.progress.connect(self._progressBar.setValue) self._saveLog.clicked.connect(self.saveLog) self.readSettings() return def _setOptions(self, options): self._options = options def _setConf(self, conf): self._conf = conf def _getOptions(self): return self._options def _getConf(self): return self._conf options = property(_getOptions, _setOptions) conf = property(_getConf, _setConf) def browseSaveLog(self): self._saveLogEdit.setText( QFileDialog.getSaveFileName(self, 'Select Log File Report', self._saveLogEdit.text(), 'Report Files (*.log *.txt)')) return def saveLog(self): if self._saveLogEdit.text(): fd = open(self._saveLogEdit.text(), 'w+') fd.write(self._console.toPlainText()) fd.close() return def shellCommand(self): command = [self.conf.bootstrapDir + '/ccb.py'] for project in self.options.projects: for tool in project.actives: command += ['--tool=' + tool] toolsCount = len(command) - 1 if self.conf.rootDir: command += ['--root=%s' % self.conf.rootDir] #if self.options.svnUpdate: command += [ '--svn-update' ] #if self.options.svnStatus: command += [ '--svn-update' ] if self.options.enableDoc: command += ['--doc'] if self.options.devtoolset2: command += ['--devtoolset-2'] if self.options.qt5: command += ['--qt5'] if self.options.noCache: command += ['--no-cache'] if self.options.rmBuild: command += ['--rm-build'] if self.options.verbose: command += ['--verbose'] if self.options.make: makeArguments = 'install ' + self.options.threads command += ['--make=%s' % makeArguments] if self.options.buildMode == 'Debug': command += ['--debug'] return toolsCount, command def go(self): rePercentage = re.compile(r'^\[\s*(?P<percent>\d+)%\].*') reProcessTool = re.compile(r'^Processing tool:\s*"(?P<tool>.+)"') if not self.options or not self.conf: return toolsCount, command = self.shellCommand() if not toolsCount: return self._progressBar.reset() self._progressBar.setRange(0, toolsCount * 100) strCommand = command[0] for arg in command[1:]: strCommand += ' ' + arg strCommand += '\n\n' self._console.setFontItalic(True) self._console.insertPlainText(strCommand) self._console.setFontItalic(False) toolsDone = -1 builderProcess = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) while True: line = builderProcess.stdout.readline() if line == '': break m = rePercentage.match(line) if m: self.progress.emit(toolsDone * 100 + int(m.group('percent'))) else: m = reProcessTool.match(line) if m: toolsDone += 1 self._console.insertPlainText(line) scrollBar = self._console.verticalScrollBar() scrollBar.setValue(scrollBar.maximum()) QApplication.processEvents() builderProcess.wait() if builderProcess.returncode == None: pass return def readSettings(self): settings = QSettings() self._saveLogEdit.setText(settings.value('compile/saveLog').toString()) return def saveSettings(self): settings = QSettings() settings.setValue('compile/saveLog', self._saveLogEdit.text()) return
class NotUsedAnalysisProgress( QDialog ): " Progress of the not used analysis " Functions = 0 Classes = 1 Globals = 2 def __init__( self, what, sourceModel, parent = None ): QDialog.__init__( self, parent ) if what not in [ self.Functions, self.Classes, self.Globals ]: raise Exception( "Unsupported unused analysis type: " + \ str( what ) ) self.__cancelRequest = False self.__inProgress = False self.__what = what # what is in source model self.__srcModel = sourceModel # source model of globals or # functions or classes # Avoid pylint complains self.__progressBar = None self.__infoLabel = None self.__foundLabel = None self.__found = 0 # Number of found self.__createLayout() self.setWindowTitle( self.__formTitle() ) QTimer.singleShot( 0, self.__process ) return def keyPressEvent( self, event ): " Processes the ESC key specifically " if event.key() == Qt.Key_Escape: self.__onClose() else: QDialog.keyPressEvent( self, event ) return def __formTitle( self ): " Forms the progress dialog title " title = "Unused " if self.__what == self.Functions: title += 'function' elif self.__what == self.Classes: title += 'class' else: title += 'globlal variable' return title + " analysis" def __formInfoLabel( self, name ): " Forms the info label " if self.__what == self.Functions: return 'Function: ' + name if self.__what == self.Classes: return 'Class: ' + name return 'Globlal variable: ' + name def __whatAsString( self ): " Provides 'what' as string " if self.__what == self.Functions: return 'function' if self.__what == self.Classes: return 'class' return 'global variable' def __updateFoundLabel( self ): " Updates the found label " text = "Found: " + str( self.__found ) + " candidate" if self.__found != 1: text += "s" self.__foundLabel.setText( text ) return def __createLayout( self ): """ Creates the dialog layout """ self.resize( 450, 20 ) self.setSizeGripEnabled( True ) verticalLayout = QVBoxLayout( self ) # Note label noteLabel = QLabel( "<b>Note</b>: the analysis is " \ "suggestive and not precise. " \ "Use the results with caution.\n", self ) verticalLayout.addWidget( noteLabel ) # Info label self.__infoLabel = QLabel( self ) verticalLayout.addWidget( self.__infoLabel ) # Progress bar self.__progressBar = QProgressBar( self ) self.__progressBar.setValue( 0 ) self.__progressBar.setOrientation( Qt.Horizontal ) verticalLayout.addWidget( self.__progressBar ) # Found label self.__foundLabel = QLabel( self ) verticalLayout.addWidget( self.__foundLabel ) # Buttons buttonBox = QDialogButtonBox( self ) buttonBox.setOrientation( Qt.Horizontal ) buttonBox.setStandardButtons( QDialogButtonBox.Close ) verticalLayout.addWidget( buttonBox ) buttonBox.rejected.connect( self.__onClose ) return def __onClose( self ): " triggered when the close button is clicked " self.__cancelRequest = True if not self.__inProgress: self.close() return def __process( self ): " Analysis process " self.__inProgress = True mainWindow = GlobalData().mainWindow editorsManager = mainWindow.editorsManagerWidget.editorsManager modified = editorsManager.getModifiedList( True ) # True - only project files if modified: modNames = [ modItem[ 0 ] for modItem in modified ] label = "File" if len( modified ) >= 2: label += "s" label += ": " logging.warning( "The analisys is performed for the content of saved files. " \ "The unsaved modifications will not be taken into account. " \ + label + ", ".join( modNames ) ) self.__updateFoundLabel() self.__progressBar.setRange( 0, len( self.__srcModel.rootItem.childItems ) ) QApplication.processEvents() QApplication.setOverrideCursor( QCursor( Qt.WaitCursor ) ) count = 0 candidates = [] for treeItem in self.__srcModel.rootItem.childItems: if self.__cancelRequest: break name = str( treeItem.data( 0 ) ).split( '(' )[ 0 ] path = os.path.realpath( treeItem.getPath() ) lineNumber = int( treeItem.data( 2 ) ) absPosition = treeItem.sourceObj.absPosition count += 1 self.__progressBar.setValue( count ) self.__infoLabel.setText( self.__formInfoLabel( name ) ) QApplication.processEvents() # Analyze the name found = False try: # True is for throwing exceptions locations = getOccurrences( path, absPosition, True ) if len( locations ) == 1 and \ locations[ 0 ][ 1 ] == lineNumber: found = True index = getSearchItemIndex( candidates, path ) if index < 0: widget = mainWindow.getWidgetForFileName( path ) if widget is None: uuid = "" else: uuid = widget.getUUID() newItem = ItemToSearchIn( path, uuid ) candidates.append( newItem ) index = len( candidates ) - 1 candidates[ index ].addMatch( name, lineNumber ) except Exception, exc: # There is nothing interesting with exceptions here. # It seems to me that rope throws them in case if the same item # is declared multiple times in a file. I also suspect that # exceptions may come up in case of syntactic errors. # So I just suppress them. pass #logging.warning( "Error detected while analysing " + \ # self.__whatAsString() + " '" + name + \ # "'. Message: " + str( exc ) ) if found: self.__found += 1 self.__updateFoundLabel() QApplication.processEvents() if self.__found == 0: # The analysis could be interrupted if not self.__cancelRequest: logging.info( "No unused candidates found" ) else: mainWindow.displayFindInFiles( "", candidates ) QApplication.restoreOverrideCursor() self.__infoLabel.setText( 'Done' ) self.__inProgress = False self.accept() return
class ImportsDiagramProgress( QDialog ): " Progress of the diagram generator " def __init__( self, what, options, path = "", buf = "", parent = None ): QDialog.__init__( self, parent ) self.__cancelRequest = False self.__inProgress = False self.__what = what self.__options = options self.__path = path # could be a dir or a file self.__buf = buf # content in case of a modified file # Working process data self.__participantFiles = [] # Collected list of files self.__projectImportDirs = [] self.__projectImportsCache = {} # utils.settings -> /full/path/to.py self.__dirsToImportsCache = {} # /dir/path -> { my.mod: path.py, ... } self.dataModel = ImportDiagramModel() self.scene = QGraphicsScene() # Avoid pylint complains self.progressBar = None self.infoLabel = None self.__createLayout() self.setWindowTitle( 'Imports/dependencies diagram generator' ) QTimer.singleShot( 0, self.__process ) return def keyPressEvent( self, event ): " Processes the ESC key specifically " if event.key() == Qt.Key_Escape: self.__onClose() else: QDialog.keyPressEvent( self, event ) return def __createLayout( self ): """ Creates the dialog layout """ self.resize( 450, 20 ) self.setSizeGripEnabled( True ) verticalLayout = QVBoxLayout( self ) # Info label self.infoLabel = QLabel( self ) verticalLayout.addWidget( self.infoLabel ) # Progress bar self.progressBar = QProgressBar( self ) self.progressBar.setValue( 0 ) self.progressBar.setOrientation( Qt.Horizontal ) verticalLayout.addWidget( self.progressBar ) # Buttons buttonBox = QDialogButtonBox( self ) buttonBox.setOrientation( Qt.Horizontal ) buttonBox.setStandardButtons( QDialogButtonBox.Close ) verticalLayout.addWidget( buttonBox ) buttonBox.rejected.connect( self.__onClose ) return def __onClose( self ): " triggered when the close button is clicked " self.__cancelRequest = True if not self.__inProgress: self.close() return def __buildParticipants( self ): " Builds a list of participating files and dirs " if self.__what in [ ImportsDiagramDialog.SingleBuffer, ImportsDiagramDialog.SingleFile ]: # File exists but could be modified self.__path = os.path.realpath( self.__path ) self.__participantFiles.append( self.__path ) return if self.__what == ImportsDiagramDialog.ProjectFiles: self.__scanProjectDirs() return # This is a recursive directory self.__path = os.path.realpath( self.__path ) self.__scanDirForPythonFiles( self.__path + os.path.sep ) return def __scanDirForPythonFiles( self, path ): " Scans the directory for the python files recursively " for item in os.listdir( path ): if item in [ ".svn", ".cvs" ]: continue if os.path.isdir( path + item ): self.__scanDirForPythonFiles( path + item + os.path.sep ) continue if item.endswith( ".py" ) or item.endswith( ".py3" ): fName = os.path.realpath( path + item ) # If it was a link, the target could be non-python if fName.endswith( ".py" ) or fName.endswith( ".py3" ): self.__participantFiles.append( fName ) return def __scanProjectDirs( self ): " Populates participant lists from the project files " for fName in GlobalData().project.filesList: if fName.endswith( ".py" ) or fName.endswith( ".py3" ): self.__participantFiles.append( fName ) return def isProjectImport( self, importString ): " Checks if it is a project import string and provides a path if so " if importString in self.__projectImportsCache: return self.__projectImportsCache[ importString ] subpath = importString.replace( '.', os.path.sep ) candidates = [ subpath + ".py", subpath + ".py3", subpath + os.path.sep + "__init__.py", subpath + os.path.sep + "__init__.py3" ] for path in self.__projectImportDirs: for item in candidates: fName = path + os.path.sep + item if os.path.isfile( fName ): self.__projectImportsCache[ importString ] = fName return fName return None def isLocalImport( self, dirName, importString ): " Checks if it is local dir import string and provides a path if so " dirFound = False if dirName in self.__dirsToImportsCache: dirFound = True importsDict = self.__dirsToImportsCache[ dirName ] if importString in importsDict: return importsDict[ importString ] subpath = importString.replace( '.', os.path.sep ) candidates = [ subpath + ".py", subpath + ".py3", subpath + os.path.sep + "__init__.py", subpath + os.path.sep + "__init__.py3" ] for item in candidates: fName = dirName + os.path.sep + item if os.path.isfile( fName ): # Found on the FS. Add to the dictionary if dirFound: importsDict[ importString ] = fName else: self.__dirsToImportsCache[ dirName ] = { importString: fName } return fName return None def isSystemWideImport( self, importString ): " Provides a path to the system wide import or None " # Systemwide modules may not have a path if it is a # built-in module, or to have a path to an .so library try: path = getSystemWideModules()[ importString ] if path is None: return True, None if path.endswith( ".py" ): return True, path if path.endswith( ".py3" ): return True, path return True, None except: return False, None def __addBoxInfo( self, box, info ): " Adds information to the given box if so configured " if info.docstring is not None: box.docstring = info.docstring.text if self.__options.includeClasses: for klass in info.classes: box.classes.append( klass ) if self.__options.includeFuncs: for func in info.functions: box.funcs.append( func ) if self.__options.includeGlobs: for glob in info.globals: box.globs.append( glob ) if self.__options.includeConnText: for imp in info.imports: box.imports.append( imp ) return def __addDocstringBox( self, info, fName, modBoxName ): " Adds a docstring box if needed " if self.__options.includeDocs: if info.docstring is not None: docBox = DgmDocstring() docBox.docstring = info.docstring docBox.refFile = fName # Add the box and its connection docBoxName = self.dataModel.addDocstringBox( docBox ) conn = DgmConnection() conn.kind = DgmConnection.ModuleDoc conn.source = modBoxName conn.target = docBoxName self.dataModel.addConnection( conn ) # Add rank for better layout rank = DgmRank() rank.firstObj = modBoxName rank.secondObj = docBoxName self.dataModel.addRank( rank ) return def __getSytemWideImportDocstring( self, path ): " Provides the system wide module docstring " if not path.endswith( '.py' ) and not path.endswith( '.py3' ): return "" try: info = GlobalData().briefModinfoCache.get( path ) if info.docstring is not None: return info.docstring.text return "" except: return "" @staticmethod def __getModuleTitle( fName ): " Extracts a module name out of the file name " baseTitle = os.path.basename( fName ).split( '.' )[ 0 ] if baseTitle != "__init__": return baseTitle # __init__ is not very descriptive. Add a top level dir. dirName = os.path.dirname( fName ) topDir = os.path.basename( dirName ) return topDir + "(" + baseTitle + ")" def __addSingleFileToDataModel( self, info, fName ): " Adds a single file to the data model " if fName.endswith( "__init__.py" ) or \ fName.endswith( "__init__.py3" ): if not info.classes and not info.functions and \ not info.globals and not info.imports: # Skip dummy init files return modBox = DgmModule() modBox.refFile = fName modBox.kind = DgmModule.ModuleOfInterest modBox.title = self.__getModuleTitle( fName ) self.__addBoxInfo( modBox, info ) modBoxName = self.dataModel.addModule( modBox ) self.__addDocstringBox( info, fName, modBoxName ) # Add what is imported isProjectFile = GlobalData().project.isProjectFile( fName ) for item in info.imports: impBox = DgmModule() importPath = None systemWideImportPath = None if isProjectFile: importPath = self.isProjectImport( item.name ) if importPath is None: importPath = self.isLocalImport( os.path.dirname( fName ), item.name ) if importPath is not None: impBox.kind = DgmModule.OtherProjectModule impBox.title = os.path.basename( importPath ).split( '.' )[ 0 ] impBox.refFile = importPath otherInfo = GlobalData().briefModinfoCache.get( importPath ) # It's a local or project import self.__addBoxInfo( impBox, otherInfo ) else: impBox.kind = DgmModule.UnknownModule impBox.title = item.name found, systemWideImportPath = self.isSystemWideImport( item.name ) if found: if systemWideImportPath is not None: impBox.kind = DgmModule.SystemWideModule impBox.refFile = systemWideImportPath impBox.docstring = \ self.__getSytemWideImportDocstring( \ systemWideImportPath ) else: impBox.kind = DgmModule.BuiltInModule impBoxName = self.dataModel.addModule( impBox ) impConn = DgmConnection() impConn.kind = DgmConnection.ModuleDependency impConn.source = modBoxName impConn.target = impBoxName if self.__options.includeConnText: for impWhat in item.what: if impWhat.name != "": impConn.labels.append( impWhat ) self.dataModel.addConnection( impConn ) return def __process( self ): " Accumulation process " # Intermediate working data self.__participantFiles = [] self.__projectImportDirs = [] self.__projectImportsCache = {} self.dataModel.clear() self.__inProgress = True try: self.infoLabel.setText( 'Building the list of files to analyze...' ) QApplication.processEvents() # Build the list of participating python files self.__buildParticipants() self.__projectImportDirs = \ GlobalData().project.getImportDirsAsAbsolutePaths() QApplication.processEvents() if self.__cancelRequest == True: QApplication.restoreOverrideCursor() self.close() return self.progressBar.setRange( 0, len( self.__participantFiles ) ) index = 1 # Now, parse the files and build the diagram data model if self.__what == ImportsDiagramDialog.SingleBuffer: info = getBriefModuleInfoFromMemory( str( self.__buf ) ) self.__addSingleFileToDataModel( info, self.__path ) else: infoSrc = GlobalData().briefModinfoCache for fName in self.__participantFiles: self.progressBar.setValue( index ) self.infoLabel.setText( 'Analyzing ' + fName + "..." ) QApplication.processEvents() if self.__cancelRequest == True: QApplication.restoreOverrideCursor() self.dataModel.clear() self.close() return info = infoSrc.get( fName ) self.__addSingleFileToDataModel( info, fName ) index += 1 # The import caches and other working data are not needed anymore self.__participantFiles = None self.__projectImportDirs = None self.__projectImportsCache = None # Generating the graphviz layout self.infoLabel.setText( 'Generating layout using graphviz...' ) QApplication.processEvents() graph = getGraphFromDescriptionData( self.dataModel.toGraphviz() ) graph.normalize( self.physicalDpiX(), self.physicalDpiY() ) QApplication.processEvents() if self.__cancelRequest == True: QApplication.restoreOverrideCursor() self.dataModel.clear() self.close() return # Generate graphics scene self.infoLabel.setText( 'Generating graphics scene...' ) QApplication.processEvents() self.__buildGraphicsScene( graph ) # Clear the data model self.dataModel = None except Exception, exc: QApplication.restoreOverrideCursor() logging.error( str( exc ) ) self.__inProgress = False self.__onClose() return QApplication.restoreOverrideCursor() self.infoLabel.setText( 'Done' ) QApplication.processEvents() self.__inProgress = False self.accept() return
class CarvingProcess(QWidget, EventHandler): def __init__(self, selector, vnode): QWidget.__init__(self) EventHandler.__init__(self) self.vnode = vnode.value() self.filesize = self.vnode.size() self.tm = TaskManager() self.selector = selector self.setLayout(QVBoxLayout()) self.factor = 1 self.parsetime = 0 self.time = time.time() self.starttime = time.time() self.createStartOffset() self.createButtons() self.createStateInfo() def createStartOffset(self): self.offsetLayout = QHBoxLayout() self.offsetSpinBox = QFFSpinBox(self) self.offsetSpinBox.setMinimum(0) self.offsetSpinBox.setMaximum(self.filesize) self.offsetLabel = QLabel("start offset:") self.offsetLayout.addWidget(self.offsetLabel) self.offsetLayout.addWidget(self.offsetSpinBox) self.layout().addLayout(self.offsetLayout) def createButtons(self): self.startButton = QPushButton("Start") self.stopButton = QPushButton("Stop") self.stopButton.setEnabled(False) self.connect(self.stopButton, SIGNAL("clicked()"), self.stopCarving) self.connect(self.startButton, SIGNAL("clicked()"), self.startCarving) self.connect(self, SIGNAL("ended"), self.carvingEnded) self.buttonLayout = QHBoxLayout() self.buttonLayout.addWidget(self.startButton) self.buttonLayout.addWidget(self.stopButton) self.layout().addLayout(self.buttonLayout) def createStateInfo(self): self.stateLayout = QVBoxLayout() self.overallLayout = QHBoxLayout() self.currentLabel = QLabel("Overall progress :") self.currentProgress = QProgressBar() self.overallLayout.addWidget(self.currentLabel) self.overallLayout.addWidget(self.currentProgress) self.stateLayout.addLayout(self.overallLayout) self.elapsedLabel = QLabel("elapsed time: 00d00h00m00s") self.stateLayout.addWidget(self.elapsedLabel) self.estimatedLabel = QLabel("estimated time: 00d00h00m00s") self.stateLayout.addWidget(self.estimatedLabel) self.totalLabel = QLabel("total headers found: 0") self.stateLayout.addWidget(self.totalLabel) self.stateLayout.setEnabled(False) self.layout().addLayout(self.stateLayout) def createContext(self, selected): lpatterns = VList() for filetype in selected.iterkeys(): patterns = selected[filetype][0] aligned = selected[filetype][1] for pattern in patterns: vpattern = VMap() vpattern["filetype"] = Variant(filetype, typeId.String) header = VMap() header["needle"] = Variant(pattern[0], typeId.String) header["size"] = Variant(len(pattern[0]), typeId.UInt32) footer = VMap() footer["needle"] = Variant(pattern[1], typeId.String) footer["size"] = Variant(len(pattern[1]), typeId.UInt32) vpattern["header"] = Variant(header) vpattern["footer"] = Variant(footer) vpattern["window"] = Variant(int(pattern[2]), typeId.UInt32) vpattern["aligned"] = Variant(aligned, typeId.Bool) lpatterns.append(vpattern) return lpatterns def startCarving(self): selected = self.selector.selectedItems() if len(selected): try: f = self.vnode.open() f.close() except: mbox = QMessageBox( QMessageBox.Warning, self.tr("Carver bad input"), self. tr("The provided input file seems to be a directory. Please, apply the module on a file" ), QMessageBox.Ok, self) mbox.exec_() return patterns = self.createContext(selected) args = VMap() args["patterns"] = Variant(patterns) args["file"] = Variant(self.vnode) args["start-offset"] = Variant(self.offsetSpinBox.value(), typeId.UInt64) factor = round(float(self.filesize) / 2147483647) self.startButton.setEnabled(False) self.stopButton.setEnabled(True) self.stopButton.setDown(False) if factor == 0: factor = 1 proc = self.tm.add("carver", args, ["gui", "thread"]) if proc: self.doJob(self.filesize, factor, self.offsetSpinBox.value()) self.stateLayout.setEnabled(True) self.connection(proc.inst) proc.inst.connection(self) #self.connect(self, SIGNAL("stateInfo(QString)"), self.setStateInfo) else: mbox = QMessageBox( QMessageBox.Warning, self.tr("Carver no items selected"), self. tr("No items have been provided to know what to look for. Please chose types you want to search." ), QMessageBox.Ok, self) mbox.exec_() return def carvingEnded(self, res): #results = str(res).split("\n") #print results #for item in results: # begidx = item.find(":") # self.res.add_const(str(item[:begidx]), str(item[begidx+1:] + "\n")) self.startButton.setEnabled(True) self.stopButton.setEnabled(False) self.stateLayout.setEnabled(False) def stopCarving(self): self.killJob() self.stopButton.setDown(True) def strtime(self, day, hour, min, sec): day = str(day) hour = str(hour) min = str(min) sec = str(sec) res = "0" * (2 - len(day)) + day + "d" + "0" * ( 2 - len(hour)) + hour + "h" + "0" * ( 2 - len(min)) + min + "m" + "0" * (2 - len(sec)) + sec + "s" return res def timesec2str(self, timesec): day = hour = min = sec = 0 if timesec > 3600 * 24: day = timesec / (3600 * 24) timesec = timesec % (3600 * 24) if timesec > 3600: hour = timesec / 3600 timesec = timesec % 3600 if timesec > 60: min = timesec / 60 timesec = timesec % 60 sec = timesec res = self.strtime(int(day), int(hour), int(min), int(sec)) return res def Event(self, e): if e.type == Carver.Position: self.emit(SIGNAL("updatePosition"), e) elif e.type == Carver.Matches: self.emit(SIGNAL("updateMatches"), e) elif e.type == Carver.EndOfProcessing: self.emit(SIGNAL("ended"), "") def updatePosition(self, e): ref = time.time() - self.time self.time = time.time() if not str(ref).startswith("0.0"): ref *= self.parsetime res = self.timesec2str(ref) self.estimatedLabel.setText("estimated time: " + res) res = self.timesec2str(time.time() - self.starttime) self.elapsedLabel.setText("elapsed time: " + res) i = int(e.value.value() / self.factor) if i > 2147483647: i = 2147483647 self.emit(SIGNAL("valueChanged(int)"), i) info = self.currentProgress.text() + " - " + self.totalLabel.text() self.emit(SIGNAL("stateInfo(QString)"), info) def updateMatches(self, e): self.totalLabel.setText("total headers found: " + str(e.value)) def doJob(self, filesize, factor, start): self.factor = factor self.parsetime = filesize / (10 * 1204 * 1024) self.elapsedLabel.setText("elapsed time: 00d00h00m00s") self.estimatedLabel.setText("estimated time: 00d00h00m00s") self.totalLabel.setText("total headers found: 0") maxrange = int(filesize / self.factor) if maxrange > 2147483647: maxrange = 2147483647 self.currentProgress.setRange(0, maxrange) self.currentProgress.setValue(0) self.connect(self, SIGNAL("valueChanged(int)"), self.currentProgress.setValue) self.time = time.time() self.starttime = time.time() self.connect(self, SIGNAL("updateMatches"), self.updateMatches) self.connect(self, SIGNAL("updatePosition"), self.updatePosition) def killJob(self): e = event() e.thisown = False e.type = Carver.Stop self.notify(e)
class ImportWidget(QDialog): def __init__(self, db_path, parent = None): QWidget.__init__(self) self.setParent(parent) self.setWindowFlags(Qt.Dialog) self.setWindowTitle(self.tr('Import')) self.setModal(1) self.startButton = QPushButton(self) self.startButton.setText('&start') self.connect( self.startButton, SIGNAL('clicked()'), self.onStart ) self.stopButton = QPushButton(self) self.stopButton.setText('&cancel') self.stopButton.setEnabled( False ) self.connect( self.stopButton, SIGNAL('clicked()'), self.onStop ) self.okButton = QPushButton(self) self.okButton.setText('&done') self.okButton.setEnabled( False ) self.connect( self.okButton, SIGNAL('clicked()'), self.onOk ) self.statusBar = QProgressBar(self) self.statusBar.setRange(0, 100) self.statusLabel = QLabel(self) self.worker = ImportWorker(db_path, self) self.connect( self.worker, SIGNAL('statusChanged'), self.statusBar.setValue ) self.connect( self.worker, SIGNAL('done'), self.onDone ) self.connect( self.worker, SIGNAL('message'), self.statusLabel.setText ) self.connect( self.worker, SIGNAL('range'), self.statusBar.setRange ) self.layout = QGridLayout(self) self.layout.addWidget( self.startButton, 0, 0 ) self.layout.addWidget( self.stopButton, 0, 1 ) self.layout.addWidget( self.okButton, 0, 2 ) self.layout.addWidget( self.statusBar, 1, 0, 1, 3 ) self.layout.addWidget( self.statusLabel, 2, 0, 1, 3 ) def onStart(self): self.startButton.setEnabled( False ) self.stopButton.setEnabled( True ) self.statusBar.setEnabled( True ) self.statusLabel.setEnabled( True ) Thread(target=self.worker.run).start() def onDone(self): self.okButton.setEnabled( True ) self.stopButton.setEnabled( False ) def onStop(self): self.worker.term() self.statusBar.setEnabled( False ) self.statusLabel.setEnabled( False ) self.startButton.setEnabled( True ) self.stopButton.setEnabled( False ) def onOk(self): self.accept() def closeEvent(self,event): if self.worker.running: event.ignore() else: event.accept()
class OWDatabasesPack(OWWidget.OWWidget): settingsList = ["fileslist", "downloadurl", "downloadmessage"] def __init__(self, parent=None, signalManager=None, title="Databases Pack"): super(OWDatabasesPack, self).__init__( parent, signalManager, title, wantMainArea=False) self.fileslist = [("Taxonomy", "ncbi_taxonomy.tar.gz")] self.downloadurl = "https://dl.dropboxusercontent.com/u/100248799/sf_pack.tar.gz" self.downloadmessage = ( "Downloading a subset of available databases for a smoother " + "ride through the workshop" ) self.loadSettings() self._tmpfile = None self.reply = None # Locks held on server files self.locks = [] self.net_manager = QNetworkAccessManager() # Lock all files in files list so any other (in process) atempt to # download the files waits) box = OWGUI.widgetBox(self.controlArea, "Info") self.info = OWGUI.widgetLabel(box, self.downloadmessage) self.info.setWordWrap(True) box = OWGUI.widgetBox(self.controlArea, "Status") self.statusinfo = OWGUI.widgetLabel(box, "Please wait") self.statusinfo.setWordWrap(True) self.progressbar = QProgressBar() box.layout().addWidget(self.progressbar) self.setMinimumWidth(250) already_available = [(domain, filename) for domain in serverfiles.listdomains() for filename in serverfiles.listfiles(domain)] if set(self.fileslist) <= set(already_available): # All files are already downloaded self.statusinfo.setText("All files already available") self.setStatusMessage("Done") else: for domain, filename in self.fileslist + [("_tmp_cache_", "pack")]: manager = serverfiles._lock_file(domain, filename) try: manager.__enter__() except Exception: warnings.warn("Could not acquire lock for {0} {0}" .format(domain, filename)) self.warning(0, "...") else: self.locks.append(manager) QTimer.singleShot(0, self.show) QTimer.singleShot(0, self.run) def run(self): self.setStatusMessage("Downloading") self.info.setText(self.downloadmessage) target_dir = os.path.join(environ.buffer_dir, "serverfiles_pack_cache") try: os.makedirs(target_dir) except OSError: pass self.progressBarInit() req = QNetworkRequest(QUrl(self.downloadurl)) self.reply = self.net_manager.get(req) self.reply.downloadProgress.connect(self._progress) self.reply.error.connect(self._error) self.reply.finished.connect(self._finished) self.reply.readyRead.connect(self._read) url = urlparse.urlsplit(self.downloadurl) self._tmpfilename = posixpath.basename(url.path) self._tmpfile = open( os.path.join(target_dir, self._tmpfilename), "wb+" ) def _progress(self, rec, total): if rec == 0 and total == 0: self.progressbar.setRange(0, 0) self.progressBarValue = 1.0 else: self.progressbar.setRange(0, total) self.progressbar.setValue(rec) self.progressBarValue = 100.0 * rec / (total or 1) def _error(self, error): self.statusinfo.setText( u"Error: {0}".format(error.errorString()) ) self.error(0, "Error: {0}".format(error.errorString())) self.setStatusMessage("Error") self._releaselocks() self._removetmp() self.progressBarFinshed() def _read(self): contents = str(self.reply.readAll()) self._tmpfile.write(contents) def _finished(self): self.progressbar.reset() if self.reply.error() != QNetworkReply.NoError: self._releaselocks() self._removetmp() return self.statusinfo.setText("Extracting") self.setStatusMessage("Extracting") try: self._extract() except Exception: # Permission errors, ... ?? pass self.statusinfo.setText("Done") self.setStatusMessage("Done") self.progressbar.reset() self.progressBarFinished() self._releaselocks() self._removetmp() def _extract(self): self._tmpfile.seek(0, 0) archive = tarfile.open(fileobj=self._tmpfile) target_dir = serverfiles.localpath() archive.extractall(target_dir) def onDeleteWidget(self): super(OWDatabasesPack, self).onDeleteWidget() self._releaselocks() if self.reply is not None and self.reply.isOpen(): self.reply.finished.disconnect(self._finished) self.reply.error.disconnect(self._error) self.reply.close() if self._tmpfile is not None: self._tmpfile.close() self._tmpfile = None def _releaselocks(self): for lock in self.locks: lock.__exit__(None, None, None) self.locks = [] def _removetmp(self): if self._tmpfile is not None: self._tmpfile.close() self._tmpfile = None tmp_file = os.path.join( environ.buffer_dir, "serverfiles_pack_cache", self._tmpfilename ) os.remove(tmp_file)
class MyCustomDialog(QDialog): def __init__(self): super(MyCustomDialog, self).__init__() layout = QVBoxLayout(self) # Create a progress bar and a button and add them to the main layout self.progressBarUpdate = QProgressBar(self) self.progressBarUpdate.setAlignment(Qt.AlignCenter) layout.addWidget(self.progressBarUpdate) pushButtonUpdate = QPushButton("Start", self) layout.addWidget(pushButtonUpdate) pushButtonCancel = QPushButton("Cancel", self) layout.addWidget(pushButtonCancel) pushButtonUpdate.clicked.connect(self.check_folder_exists) # Set data for download and saving in path self.location = os.path.abspath(os.path.join('temp', 'example-app-0.3.win32.zip')) self.url = 'http://sophus.bplaced.net/download/example-app-0.3.win32.zip' self.download_task = Download_Thread(self.location, self.url) self.download_task.notify_progress.connect(self.on_progress) self.download_task.finished_thread.connect(self.on_finished) self.download_task.error_http.connect(self.on_HTTPError) self.download_task.finished_download.connect(self.on_finish_download) pushButtonCancel.clicked.connect(self.on_finished) def on_start(self): self.progressBarUpdate.setRange(0, 0) self.download_task.start() def on_finish_download(self): msg_box = QMessageBox() QMessageBox.question(msg_box, ' Message ', "The file has been fully downloaded.", msg_box.Ok) def on_HTTPError(self): reply = QMessageBox.question(self, ' Error ', "The file could not be downloaded. Will they do it again?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: self.on_start() else: event.ignore() def on_progress(self, i): self.progressBarUpdate.setRange(0, 100) self.progressBarUpdate.setValue(i) def check_folder_exists(self): location = os.path.abspath(os.path.join('temp')) if not os.path.exists(location): os.makedirs(location) print "Folder was created" self.on_start() else: print "Folder already exists" self.on_start() def on_finished(self): self.progressBarUpdate.setValue(0) self.close() def closeEvent(self, event): self.download_task.stop()
class BR_JobDock(QDockWidget): transcode_data = pyqtSignal([dict], [str]) job_complete = pyqtSignal() def __init__(self, job, passes, job_id, closesig, source, parent=None): name = source.title super().__init__(name, parent) self.job = job self.passes = passes self.job_id = job_id self.closesig = closesig self.source = source self.setWindowTitle(name) self.setFeatures(QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetFloatable) self.setAllowedAreas(Qt.BottomDockWidgetArea) self.setFloating(True) self.widget = QWidget() layout = QVBoxLayout() # layout.setSizeConstraint(QVBoxLayout.SetFixedSize) message_layout = QFormLayout() self.lblPass = QLabel('Pass ? of {}'.format(passes)) message_layout.addRow(self.lblPass) self.lblFrame = QLabel('?') message_layout.addRow('Frame:', self.lblFrame) self.lblFps = QLabel('?') message_layout.addRow('Frames per Second:', self.lblFps) self.lblSize = QLabel('?') message_layout.addRow('File Size:', self.lblSize) self.lblTime = QLabel('?') message_layout.addRow('Video Time:', self.lblTime) self.lblBitrate = QLabel('?') message_layout.addRow('Bitrate:', self.lblBitrate) layout.addLayout(message_layout) self.progressbar = QProgressBar() self.progressbar.setRange(0, self.source.length.total_seconds()) layout.addWidget(self.progressbar) self.qualitybar = QualityBar() layout.addWidget(self.qualitybar) btn_layout = QHBoxLayout() btn_More = QPushButton('More') btn_More.setCheckable(True) btn_layout.addWidget(btn_More) btn_layout.addStretch() self.btnCancel = QPushButton('Close') self.btnCancel.setIcon(QIcon(QPixmap(':/icons/application-exit.png'))) self.btnCancel.clicked.connect(self.on_cancel_clicked) btn_layout.addWidget(self.btnCancel) layout.addLayout(btn_layout) self.terminal = QPlainTextEdit() self.terminal.setReadOnly(True) self.terminal.setShown(False) # self.terminal.setMinimumWidth(400) btn_More.toggled.connect(self.terminal.setVisible) layout.addWidget(self.terminal) griplayout = QHBoxLayout() griplayout.addWidget(QSizeGrip(self.widget)) griplayout.addStretch() griplayout.addWidget(QSizeGrip(self.widget)) layout.addLayout(griplayout) self.widget.setLayout(layout) self.setWidget(self.widget) self.transcode_data[dict].connect(self.on_avconv_data) self.transcode_data[str].connect(self.on_terminal_data) self.closesig.connect(parent.on_jobclose) def start(self, dir): self.runjob = TranscodeJob(self.job, self.passes, self.source, dir, self.transcode_data, self.job_complete) self.runjob.completesig.connect(self.on_job_complete) self.btnCancel.setText('Stop') self.runjob.start() @pyqtSlot(dict) def on_avconv_data(self, match): self.lblPass.setText('Pass {pass} of {passes}'.format(**match)) self.lblFrame.setText('{frame}'.format(**match)) self.lblFps.setText('{fps}'.format(**match)) size = round(int(match['size']) / 1024, 2) self.lblSize.setText('{} MB'.format(size)) time = DvdTimeDelta(seconds=float(match['time'])) self.lblTime.setText('{}'.format(time)) self.lblBitrate.setText('{bitrate} kbps'.format(**match)) self.qualitybar.setValue(int(round(float(match['q']) * 10))) self.progressbar.setValue(int(round(float(match['time'])))) @pyqtSlot(str) def on_terminal_data(self, text): self.terminal.appendPlainText(text) @pyqtSlot() def on_cancel_clicked(self): if self.runjob.is_alive(): msg = QMessageBox(QMessageBox.Question, 'Cancelling Job', 'Do you want to cancel the running job?') msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No) msg.setDefaultButton(QMessageBox.No) ans = msg.exec_() if ans == QMessageBox.Yes: self.runjob.cancel() else: self.close_demand() @pyqtSlot() def on_job_complete(self): self.lblPass.setText('Completed') self.btnCancel.setText('Close') def close_demand(self): self.closesig.emit(self.job_id) self.close() def cancel(self): self.runjob.cancel() self.runjob.join()
class DeviceInfoWidget(QWidget): DEVICE_IMAGES = { 'rider20' : resource_path('img/rider20_icon.jpg'), 'rider30' : resource_path('img/rider30_icon.jpg'), 'rider35' : resource_path('img/rider35_icon.jpg'), 'rider40' : resource_path('img/rider40_icon.jpg'), 'rider50' : resource_path('img/rider50_icon.jpg'), 'rider' : resource_path('img/rider_icon.jpg'), 'cardio30' : resource_path('img/cardio30_icon.jpg'), 'cardio35' : resource_path('img/cardio35_icon.jpg'), 'cardio' : resource_path('img/cardio_icon.jpg'), } def __init__(self, parent=None): super(DeviceInfoWidget, self).__init__(parent) self.image = QLabel(self) self.image.setPixmap(QPixmap(self.DEVICE_IMAGES['rider'])) self.image_frame = QFrame(self) self.image_frame.setMaximumHeight(55) self.image_frame.setMinimumHeight(55) self.image_frame.setMaximumWidth(55) self.image_frame.setMinimumWidth(55) self.image_frame.setFrameShape(QFrame.StyledPanel) self.image_frame.setFrameShadow(QFrame.Raised) self.storage_usage = QProgressBar(self) self.storage_usage.setFormat('Disk usage %p%') self.storage_usage.setRange(0, 100) self.storage_usage.setValue(0) self.device_name = QLabel(self) self.device_name.setText('<b>Unknown</b>') self.device_name.setContentsMargins(3, 0, 0, 0) self._createLayout() def setDeviceInfo(self, dev_info): name = dev_info['name'].lower() if name in self.DEVICE_IMAGES: img = self.DEVICE_IMAGES[name] elif 'rider' in name: img = self.DEVICE_IMAGES['rider'] elif 'cardio' in name: img = self.DEVICE_IMAGES['cardio'] else: img = self.DEVICE_IMAGES['rider'] self.device_name.setText('<b>%s</b>' % dev_info['name']) self.image.setPixmap(QPixmap(img)) self.storage_usage.setValue( float(dev_info['storage_used']) / dev_info['total_storage'] * 100 ) def _createLayout(self): l = QHBoxLayout() l.addWidget(self.image) l.setContentsMargins(1, 1, 1, 1) self.image_frame.setLayout(l) l = QHBoxLayout() l.addWidget(self.image_frame) v = QVBoxLayout() v.addWidget(self.device_name) v.addWidget(self.storage_usage, 1) l.addLayout(v) self.setLayout(l)
class UploadDialog(QDialog): def __init__(self, bbclient, parent=None, session_id=None, username=None, password=None): super(UploadDialog, self).__init__(parent, Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowMinMaxButtonsHint) self.session_id = session_id self.username = username self.password = password self._first_auth = True self.total_progress = QProgressBar(self) self.total_progress.setRange(0, 100) self.total_progress.setValue(0) self.total_progress.setFormat('%p%') self.status_msg = QLabel('Starting upload', self) self.setWindowTitle('Uploading') self._createLayout() self.upload = BrytonSportUpload(bbclient, parent=self) self.upload.authNeeded.connect(self._onAuthNeeded) self.upload.totalProgress.connect(self.total_progress.setValue) self.upload.statusMessage.connect(self.status_msg.setText) self.upload.finished.connect(self._onFinished) self.upload.failed.connect(self._onError) # self.upload.start() QTimer.singleShot(100, self.upload.start) def _createLayout(self): l = QVBoxLayout() l.addWidget(self.status_msg) l.addWidget(self.total_progress) self.setLayout(l) def _onAuthNeeded(self): if self._first_auth and self.username is not None and self.password is not None: self._first_auth = False self.upload.authenticate(self.username, self.password) return d = AuthDialog(self) if d.exec_() == QDialog.Accepted: u, p = d.getValues() self.upload.authenticate(u, p) else: self.accept() def _onFinished(self): QMessageBox.information(self, 'Upload Finished', 'The tracks was successfully uploaded.') self.accept() def _onError(self): QMessageBox.warning(self, 'Upload Failed', 'The upload failed with an unknown error.') self.accept()
class ProgressDialog ( MProgressDialog, Window ): """ A simple progress dialog window which allows itself to be updated FIXME: buttons are not set up correctly yet """ #-- Facet Definitions ------------------------------------------------------ progress_bar = Instance( QProgressBar ) title = Unicode message = Unicode min = Int max = Int margin = Int( 5 ) can_cancel = Bool( False ) show_time = Bool( False ) show_percent = Bool( False ) _user_cancelled = Bool( False ) dialog_size = Instance( QRect ) # Label for the 'cancel' button cancel_button_label = Unicode( 'Cancel' ) #-- Public Methods --------------------------------------------------------- def open ( self ): super( ProgressDialog, self ).open() self._start_time = time.time() def close ( self ): self.progress_bar.destroy() self.progress_bar = None super( ProgressDialog, self ).close() def update ( self, value ): """ Updates the progress bar to the desired value. If the value is >= the maximum and the progress bar is not contained in another panel the parent window will be closed """ if self.progress_bar is None: return ( None, None ) self.progress_bar.setValue( value ) percent = (float( value ) - self.min) / (self.max - self.min) if self.show_time and (percent != 0): current_time = time.time() elapsed = current_time - self._start_time estimated = elapsed / percent remaining = estimated - elapsed self._set_time_label( elapsed, self._elapsed_control ) self._set_time_label( estimated, self._estimated_control ) self._set_time_label( remaining, self._remaining_control ) self._message_control.setText( self.message ) if self.show_percent: self._percent_control = "%3f" % ((percent * 100) % 1) if (value >= self.max) or self._user_cancelled: self.close() return ( not self._user_cancelled, False ) def reject ( self, event ): self._user_cancelled = True self.close() def _set_time_label ( self, value, control ): hours = value / 3600 minutes = (value % 3600) / 60 seconds = value % 60 label = "%1u:%02u:%02u" % ( hours, minutes, seconds ) control.setText( control.text()[:-7] + label ) def _create_buttons ( self, dialog, layout ): """ Creates the buttons. """ # Create the button: buttons = QDialogButtonBox() if self.can_cancel: buttons.addButton( self.cancel_button_label, QDialogButtonBox.RejectRole ) buttons.addButton( QDialogButtonBox.Ok ) # TODO: hookup the buttons to our methods, this may involve subclassing # from QDialog if self.can_cancel: buttons.connect( buttons, SIGNAL( 'rejected()' ), dialog, SLOT( 'reject() ' ) ) buttons.connect( buttons, SIGNAL( 'accepted()' ), dialog, SLOT( 'accept()' ) ) layout.addWidget( buttons ) def _create_label ( self, dialog, layout, text ): dummy = QLabel( text, dialog ) dummy.setAlignment( Qt.AlignTop | Qt.AlignLeft ) label = QLabel( "unknown", dialog ) label.setAlignment( Qt.AlignTop | Qt.AlignLeft | Qt.AlignRight ) sub_layout = QHBoxLayout() sub_layout.addWidget( dummy ) sub_layout.addWidget( label ) layout.addLayout( sub_layout ) return label def _create_gauge ( self, dialog, layout ): self.progress_bar = QProgressBar( dialog ) self.progress_bar.setRange( self.min, self.max ) layout.addWidget( self.progress_bar ) def _create_message ( self, dialog, layout ): label = QLabel( self.message, dialog ) label.setAlignment( Qt.AlignTop | Qt.AlignLeft ) layout.addWidget( label ) self._message_control = label def _create_percent ( self, dialog, layout ): #not an option with the QT progress bar return def _create_timer ( self, dialog, layout ): if not self.show_time: return self._elapsed_control = self._create_label( dialog, layout, "Elapsed time : " ) self._estimated_control = self._create_label( dialog, layout, "Estimated time : " ) self._remaining_control = self._create_label( dialog, layout, "Remaining time : " ) def _create_control ( self, parent ): control = QDialog( parent ) control.setWindowTitle( self.title ) return control def _create ( self ): super( ProgressDialog, self )._create() contents = self._create_contents( self.control ) def _create_contents ( self, parent ): dialog = parent layout = QVBoxLayout( dialog ) # The 'guts' of the dialog: self._create_message( dialog, layout ) self._create_gauge( dialog, layout ) self._create_percent( dialog, layout ) self._create_timer( dialog, layout ) self._create_buttons( dialog, layout ) parent.setLayout( layout ) #-- EOF ------------------------------------------------------------------------
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()
class NotUsedAnalysisProgress(QDialog): " Progress of the not used analysis " Functions = 0 Classes = 1 Globals = 2 def __init__(self, what, sourceModel, parent=None): QDialog.__init__(self, parent) if what not in [self.Functions, self.Classes, self.Globals]: raise Exception( "Unsupported unused analysis type: " + \ str( what ) ) self.__cancelRequest = False self.__inProgress = False self.__what = what # what is in source model self.__srcModel = sourceModel # source model of globals or # functions or classes # Avoid pylint complains self.__progressBar = None self.__infoLabel = None self.__foundLabel = None self.__found = 0 # Number of found self.__createLayout() self.setWindowTitle(self.__formTitle()) QTimer.singleShot(0, self.__process) return def keyPressEvent(self, event): " Processes the ESC key specifically " if event.key() == Qt.Key_Escape: self.__onClose() else: QDialog.keyPressEvent(self, event) return def __formTitle(self): " Forms the progress dialog title " title = "Unused " if self.__what == self.Functions: title += 'function' elif self.__what == self.Classes: title += 'class' else: title += 'globlal variable' return title + " analysis" def __formInfoLabel(self, name): " Forms the info label " if self.__what == self.Functions: return 'Function: ' + name if self.__what == self.Classes: return 'Class: ' + name return 'Globlal variable: ' + name def __whatAsString(self): " Provides 'what' as string " if self.__what == self.Functions: return 'function' if self.__what == self.Classes: return 'class' return 'global variable' def __updateFoundLabel(self): " Updates the found label " text = "Found: " + str(self.__found) + " candidate" if self.__found != 1: text += "s" self.__foundLabel.setText(text) return def __createLayout(self): """ Creates the dialog layout """ self.resize(450, 20) self.setSizeGripEnabled(True) verticalLayout = QVBoxLayout(self) # Note label noteLabel = QLabel( "<b>Note</b>: the analysis is " \ "suggestive and not precise. " \ "Use the results with caution.\n", self ) verticalLayout.addWidget(noteLabel) # Info label self.__infoLabel = QLabel(self) verticalLayout.addWidget(self.__infoLabel) # Progress bar self.__progressBar = QProgressBar(self) self.__progressBar.setValue(0) self.__progressBar.setOrientation(Qt.Horizontal) verticalLayout.addWidget(self.__progressBar) # Found label self.__foundLabel = QLabel(self) verticalLayout.addWidget(self.__foundLabel) # Buttons buttonBox = QDialogButtonBox(self) buttonBox.setOrientation(Qt.Horizontal) buttonBox.setStandardButtons(QDialogButtonBox.Close) verticalLayout.addWidget(buttonBox) buttonBox.rejected.connect(self.__onClose) return def __onClose(self): " triggered when the close button is clicked " self.__cancelRequest = True if not self.__inProgress: self.close() return def __process(self): " Analysis process " self.__inProgress = True mainWindow = GlobalData().mainWindow editorsManager = mainWindow.editorsManagerWidget.editorsManager modified = editorsManager.getModifiedList( True) # True - only project files if modified: modNames = [modItem[0] for modItem in modified] label = "File" if len(modified) >= 2: label += "s" label += ": " logging.warning( "The analisys is performed for the content of saved files. " \ "The unsaved modifications will not be taken into account. " \ + label + ", ".join( modNames ) ) self.__updateFoundLabel() self.__progressBar.setRange(0, len(self.__srcModel.rootItem.childItems)) QApplication.processEvents() QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) count = 0 candidates = [] for treeItem in self.__srcModel.rootItem.childItems: if self.__cancelRequest: break name = str(treeItem.data(0)).split('(')[0] path = os.path.realpath(treeItem.getPath()) lineNumber = int(treeItem.data(2)) absPosition = treeItem.sourceObj.absPosition count += 1 self.__progressBar.setValue(count) self.__infoLabel.setText(self.__formInfoLabel(name)) QApplication.processEvents() # Analyze the name found = False try: # True is for throwing exceptions locations = getOccurrences(path, absPosition, True) if len( locations ) == 1 and \ locations[ 0 ][ 1 ] == lineNumber: found = True index = getSearchItemIndex(candidates, path) if index < 0: widget = mainWindow.getWidgetForFileName(path) if widget is None: uuid = "" else: uuid = widget.getUUID() newItem = ItemToSearchIn(path, uuid) candidates.append(newItem) index = len(candidates) - 1 candidates[index].addMatch(name, lineNumber) except Exception, exc: # There is nothing interesting with exceptions here. # It seems to me that rope throws them in case if the same item # is declared multiple times in a file. I also suspect that # exceptions may come up in case of syntactic errors. # So I just suppress them. pass #logging.warning( "Error detected while analysing " + \ # self.__whatAsString() + " '" + name + \ # "'. Message: " + str( exc ) ) if found: self.__found += 1 self.__updateFoundLabel() QApplication.processEvents() if self.__found == 0: # The analysis could be interrupted if not self.__cancelRequest: logging.info("No unused candidates found") else: mainWindow.displayFindInFiles("", candidates) QApplication.restoreOverrideCursor() self.__infoLabel.setText('Done') self.__inProgress = False self.accept() return
class FileItem(QTreeWidgetItem): cols = ['Filepath', 'Renamed Filepath'] invalid_char_map = {':': ''} re_filename_episodes = [ re.compile(r'.*[Ss](?P<season>\d{1,2})[\s\-_]*[Ee](?P<episode>\d{1,2}).*', re.I), re.compile(r'.*season\s*(?P<season>\d{1,2})[\s\-_]*episode\s*[Ee](?P<episode>\d{1,2}).*', re.I), ] re_filepath_episodes = [ re.compile(r'.*season\s*(?P<season>\d{1,2})\\(?:season\s*\d{1,2}[\s\-_]*)?(?:episode|ep\.?|e)\s*(?P<episode>\d{1,2}).*', re.I), ] def __init__(self, parent, filepath, mediaman): super(FileItem, self).__init__(parent) self._renamed = False self.mediaman = mediaman self.filepath = filepath self.renamed_filepath = None self.media_info = None self.episode_info = None self.thread = None self.pbar = None self.setText(0, self.filepath) self.send_thread() def send_thread(self): if self.thread is None: self.thread = FilepathSearchThread(self.treeWidget()) self.thread.finished.connect(self.receive_thread) thread_ready = self.thread.wait(10000) if thread_ready: tree = self.treeWidget() self.pbar = QProgressBar(tree) self.pbar.setRange(0, 0) tree.setItemWidget(self, 1, self.pbar) self.thread.filepath = self.filepath self.thread.start() def receive_thread(self): self.media_info = self.thread.result self.pbar.reset() tree = self.treeWidget() tree.removeItemWidget(self, 1) self.pbar.deleteLater() self.refresh() def _replace_invalid_chars(self, text): for k, v in FileItem.invalid_char_map.items(): if k in text: text = text.replace(k, v) return text def refresh(self): moviedir = self.mediaman.moviedir() tvdir = self.mediaman.tvdir() if self.media_info: title = self.media_info.get('title') title = self._replace_invalid_chars(title) year = self.media_info.get('year') filename, ext = os.path.splitext(os.path.basename(self.filepath)) if self.episode_info or self.media_info.get('episodes'): if not self.episode_info: episodes = self.media_info['episodes'] ep_match = None for reg in FileItem.re_filename_episodes: m = reg.search(filename) if m: ep_match = m.groupdict() break if not ep_match: for reg in FileItem.re_filepath_episodes: m = reg.search(self.filepath) if m: ep_match = m.groupdict() if ep_match: season, episode = int(ep_match['season']), int(ep_match['episode']) for episode_info in episodes: if (episode_info['season'], episode_info['episode']) == (season, episode): self.episode_info = episode_info break if self.episode_info: self.renamed_filepath = ur'{tvdir}\{title}\Season{season:02d}\{title}.S{season:02d}E{episode:02d}.{episode_title}{ext}'.format( tvdir=tvdir, title=title, year=year, season=self.episode_info['season'] , episode=self.episode_info['episode'], episode_title=self._replace_invalid_chars(self.episode_info['title']), ext=ext, ) else: self.renamed_filepath = ur'{tvdir}\{title}\Season00\{title}.S00E00.XXX{ext}'.format( tvdir=tvdir, title=title, year=year, ext=ext, ) else: self.renamed_filepath = ur'{moviedir}\{title} ({year})\{title}{ext}'.format( moviedir=moviedir, title=title, year=year, ext=ext ) self.setText(1, self.renamed_filepath) if os.path.exists(self.renamed_filepath): self.setBackgroundColor(FileItem.cols.index('Renamed Filepath'), QColor(0, 255, 0, 100))