class AsyncThreadController(AsyncAbstractController): def __init__(self, # |parent| parent=None): super(AsyncThreadController, self).__init__(parent) # Create a worker and a thread it runs in. This approach was # inspired by example given in the `QThread docs # <http://qt-project.org/doc/qt-4.8/qthread.html>`_. self._worker = _AsyncWorker() self._workerThread = QThread(parent) # Attach the worker to the thread's event queue. self._worker.moveToThread(self._workerThread) # Hook up signals. self._worker.startSignal.connect(self._worker.onStart) # Everything is ready. Start the worker thread, so it will # be ready for functions to run. self._workerThread.start() # |_start| def _start(self, future): self._worker.startSignal.emit(future) # |terminate| def _terminate(self): # Shut down the thread the Worker runs in. self._workerThread.quit() self._workerThread.wait() # Finally, detach (and probably garbage collect) the objects # used by this class. del self._worker del self._workerThread
class SortedListByThread(QObject): def __init__(self): super(SortedListByThread, self).__init__() self.thread = self.worker = None def run(self, lst, key, reverse): def finished(l_sorted): self.sortedList = l_sorted loop.exit() self.worker = WorkerSorted(lst, key, reverse) self.thread = QThread(self) loop = QEventLoop() self.sortedList = None self.worker.moveToThread(self.thread) self.thread.started.connect(self.worker.run) self.worker.finished.connect(finished) self.thread.start() loop.exec_() self._finishThread() return self.sortedList def kill(self): if not self.thread is None: self._finishThread() def _finishThread(self): self.thread.quit() self.thread.wait() self.thread.deleteLater() self.thread = self.worker = None
class SignalStream(QObject): '''SignalStream is a file-like object that emits a text signal on writing This class is used to provide threadsafe communication of data to the GUI. A SignalStream can be used in place of sys.stdout and the instance's write_signal can be connected to a slot that processes the text to where it ought to go. Since signals and slots are threadsafe, this lets you pass text from anywhere to anywhere reasonably safely SignalStream uses some intelligent buffering to prevent the signalstorm that happened the first time I used it. Signal emit only happens when flush() is called - so an application can force a flush - but in order to make sure that happens reasonable often SignalStream can be initialized with a QTimer on an interval (default: 100ms) and the QTimer will make sure to call flush() every 100ms. ''' write_signal = pyqtSignal(str) def __init__(self, interval_ms=100): '''Create a SignalStream that emits text at least every interval_ms''' super(SignalStream, self).__init__() self.mutex = QMutex() self.data = [] self.thread = QThread() self.pbar_timer = QTimer() self.pbar_timer.moveToThread(self.thread) self.pbar_timer.setInterval(interval_ms) self.pbar_timer.timeout.connect(self.flush) self.thread.started.connect(self.pbar_timer.start) self.thread.start() def __del__(self): self.thread.quit() self.thread.wait() def write(self, m): '''Add the message in m to this stream's cache''' locker = QMutexLocker(self.mutex) self.data.append(m) @pyqtSlot() def flush(self): '''Write all data in the stream and clear the stream's cache''' locker = QMutexLocker(self.mutex) if self.data: self.write_signal.emit(''.join(self.data)) self.data = [] def set_interval(self, interval_ms): '''Alter the pbar_timer period''' self.pbar_timer.setInteval(interval_ms)
class TargetThread(QObject): """ Simple QThread subclass made to support the ThreadPool interface, this thread uses the standard python approach to threading, of passing a callable to a Thread class. """ finished = pyqtSignal() def __init__(self, target, *args, **kwargs): """ TargetThread constructor. :param target: callable that gets called in the new thread of execution. :param args: var-args to pass to the target callable. :param kwargs: keyword-args to pass to the target callable. """ QObject.__init__(self) self.target = target self.args = args self.kwargs = kwargs self._thread = QThread() self.moveToThread(self._thread) self._connect_slots() def _connect_slots(self): self._thread.started.connect(self.run) def wait(self, timeout): """ Wait a given time, in seconds, for our thread to terminate. :param timeout: The time, in seconds, to wait. """ self._thread.wait(timeout) def start(self): """ Start our QThread instance, beginning execution of our target thread. """ self._thread.start() def run(self): """ Override of QThread run method that gets called from the new thread of execution, this is responsible for evoking the target callable with the args and kwargs given in the constructor. Lastly, it emits the finished signal to notify whom it may concern that our job is done. """ self.target(*self.args, **self.kwargs) self.finished.emit() self._thread.finished.emit() def terminate(self): """ Terminate this thread of execution abruptly. """ self._thread.terminate()
class SlicerEngineManager(QObject): ''' SlicerEngineManager is class designed for managing slicers engine and prepare parameters ''' cancel_signal = pyqtSignal() def __init__(self, controller): super(SlicerEngineManager, self).__init__() self.controller = controller self.slice_thread = None self.slice_engine = Slic3rEngineRunner(self.controller) def slice(self): self.slice_thread = QThread() #TODO:Make it universal(for other slice engines) self.slice_engine = Slic3rEngineRunner(self.controller) self.slice_engine.moveToThread(self.slice_thread) self.slice_thread.started.connect(self.slice_engine.slice) self.slice_engine.finished.connect(self.thread_ended) self.slice_engine.filament_info.connect( self.controller.set_print_info_text) self.slice_engine.step_increased.connect( self.controller.set_progress_bar) self.slice_engine.send_message.connect(self.controller.slicing_message) self.slice_engine.send_gcodedata.connect( self.controller.set_gcode_instance) self.cancel_signal.connect( self.slice_engine.gcode.gcode_parser.cancel_parsing) self.slice_thread.start() def cancel(self): logging.debug("Thread canceling") if self.slice_engine and self.slice_thread: self.slice_engine.is_running = False self.cancel_signal.emit() self.slice_engine.kill() self.slice_thread.quit() self.slice_thread.wait() self.controller.status = 'canceled' self.controller.set_generate_button() self.controller.set_progress_bar(0.0) def thread_ended(self): self.slice_thread.quit() #TODO: add function to read gcode self.controller.scene_was_sliced() def get_version(self): return self.slice_engine.get_version()
class Analyzer(object): def __init__(self, controller): self.controller = controller self.analyzer_runner = AnalyzerRunner(controller) self.analyzer_runner_thread = QThread() self.finish_function = None self.send_result_function = None def make_analyze(self, finish_function, result_function): self.finish_function = finish_function self.send_result_function = result_function if self.analyzer_runner.is_running: print("cancel old analyze") self.cancel_analyz() print("start new analyze") #self.analyzer_runner.whole_scene = whole_scene self.analyzer_runner.moveToThread(self.analyzer_runner_thread) self.analyzer_runner_thread.started.connect(self.analyzer_runner.start_analyze) self.analyzer_runner.finished.connect(self.set_finished_read) self.analyzer_runner.send_result.connect(self.set_result) self.analyzer_runner.is_running = True self.analyzer_runner_thread.start() def cancel_analyz(self): self.analyzer_runner.is_running = False self.analyzer_runner_thread.quit() self.analyzer_runner_thread.wait() self.analyzer_runner_thread = QThread() self.analyzer_runner = AnalyzerRunner(self.controller) def set_finished_read(self): print("analyze done") if self.finish_function: self.finish_function() def set_result(self, result): print(result) if self.send_result_function: self.send_result_function(result) '''
class Window(QWidget): def __init__(self, *args, **kwargs): QWidget.__init__(self, *args, **kwargs) self.button = QtGui.QPushButton("Run", self) self.button.clicked.connect(self.onButton) self.progress = QtGui.QProgressBar(self) self.progress.setTextVisible(False) self.layout = QtGui.QVBoxLayout() self.layout.setContentsMargins(5, 5, 5, 5) self.layout.addWidget(self.button) self.layout.addWidget(self.progress) self.layout.addStretch() self.worker_thread = QThread() self.worker_thread.run = run_gestures #self.worker self.worker_thread.should_close = False self.signals = Signals() self.signals.update.connect(self.progress.setValue) self.signals.enable_button.connect(self.button.setEnabled) self.setLayout(self.layout) self.show() self.resize(self.size().width(), 0) # Override def closeEvent(self, e): self.worker_thread.should_close = True self.worker_thread.wait() @pyqtSlot() def onButton(self): self.button.setDisabled(True) self.worker_thread.start() # Worker thread, no direct GUI updates! def worker(self): for i in range(1): if self.worker_thread.should_close: break self.signals.update.emit(i) sleep(0.1) self.signals.enable_button.emit(True)
class SlicerEngineManager(object): ''' SlicerEngineManager is class designed for managing slicers engine and prepare parameters ''' def __init__(self, controller): self.controller = controller self.slice_thread = None self.slice_engine = Slic3rEngineRunner(self.controller) def slice(self): self.slice_thread = QThread() #TODO:Make it universal(for other slice engines) self.slice_engine = Slic3rEngineRunner(self.controller) self.slice_engine.moveToThread(self.slice_thread) self.slice_thread.started.connect(self.slice_engine.slice) self.slice_engine.finished.connect(self.thread_ended) self.slice_engine.filament_info.connect(self.controller.set_print_info_text) self.slice_engine.step_increased.connect(self.controller.set_progress_bar) self.slice_engine.send_message.connect(self.controller.slicing_message) self.slice_engine.send_gcodedata.connect(self.controller.set_gcode_instance) self.slice_thread.start() def cancel(self): logging.debug("Thread canceling") if self.slice_engine and self.slice_thread: self.slice_engine.is_running = False self.slice_engine.kill() self.slice_thread.quit() self.slice_thread.wait() self.controller.status = 'canceled' self.controller.set_generate_button() self.controller.set_progress_bar(0.0) def thread_ended(self): self.slice_thread.quit() #TODO: add function to read gcode self.controller.scene_was_sliced() def get_version(self): return self.slice_engine.get_version()
class BisectRunner(QObject): bisector_created = Signal(object) running_state_changed = Signal(bool) def __init__(self, mainwindow): QObject.__init__(self) self.mainwindow = mainwindow self.bisector = None self.thread = None self.pending_threads = [] def bisect(self, fetch_config, options): self.stop() # global preferences global_prefs = get_prefs() # apply the global prefs now apply_prefs(global_prefs) self.bisector = GuiBisector(fetch_config, persist=global_prefs['persist']) # create a QThread, and move self.bisector in it. This will # allow to the self.bisector slots (connected after the move) # to be automatically called in the thread. self.thread = QThread() self.bisector.moveToThread(self.thread) self.bisector.download_manager.download_progress.connect( self.show_dl_progress) self.bisector.test_runner.evaluate_started.connect(self.evaluate) self.bisector.finished.connect(self.bisection_finished) self.bisector_created.emit(self.bisector) if options['bisect_type'] == 'nightlies': handler = NightlyHandler(find_fix=options['find_fix']) good = options['good_date'] bad = options['bad_date'] else: handler = InboundHandler(find_fix=options['find_fix']) good = options['good_changeset'] bad = options['bad_changeset'] # options for the app launcher launcher_kwargs = {} for name in ('profile', 'preferences'): if name in options: value = options[name] if value: launcher_kwargs[name] = value self.bisector.test_runner.launcher_kwargs = launcher_kwargs self.thread.start() self.bisector._bisect_args = (handler, good, bad) # this will be called in the worker thread. QTimer.singleShot(0, self.bisector.bisect) self.running_state_changed.emit(True) @Slot() def stop(self, wait=True): if self.bisector: self.bisector.finished.disconnect(self.bisection_finished) self.bisector.download_manager.cancel() self.bisector = None if self.thread: self.thread.quit() if wait: # wait for thread(s) completion - this is the case when # user close the application self.thread.wait() for thread in self.pending_threads: thread.wait() else: # do not block, just keep track of the thread - we got here # when user cancel the bisection with the button. self.pending_threads.append(self.thread) self.thread.finished.connect(self._remove_pending_thread) self.thread = None self.running_state_changed.emit(False) @Slot() def _remove_pending_thread(self): for thread in self.pending_threads[:]: if thread.isFinished(): self.pending_threads.remove(thread) @Slot(object, int, int) def show_dl_progress(self, dl, current, total): message = "downloading %s: %d/%d" % (dl.get_dest(), current, total) self.mainwindow.ui.statusbar.showMessage(message, 2000) @Slot() def evaluate(self): verdict = get_verdict(self.mainwindow) self.bisector.test_runner.finish(verdict) @Slot(object, int) def bisection_finished(self, bisection, resultcode): if resultcode == Bisection.USER_EXIT: msg = "Bisection stopped." dialog = QMessageBox.information elif resultcode == Bisection.NO_DATA: msg = "Unable to find enough data to bisect." dialog = QMessageBox.warning elif resultcode == Bisection.EXCEPTION: msg = "Error: %s" % self.bisector.error[1] dialog = QMessageBox.critical else: if bisection.fetch_config.can_go_inbound() and \ isinstance(bisection.handler, NightlyHandler): # we can go on inbound, let's ask the user if QMessageBox.question( self.mainwindow, "End of the bisection", "Nightly bisection is done, but you can continue the" " bisection on inbound builds. Contibue with inbounds ?", QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) == QMessageBox.Yes: # let's go on inbound QTimer.singleShot(0, self.bisector.nightlies_to_inbound) else: # no inbound, bisection is done. self.stop() return msg = "The bisection is done." dialog = QMessageBox.information dialog(self.mainwindow, "End of the bisection", msg) self.stop()
class Gui(QtGui.QMainWindow,QtGui.QWidget): def __init__(self): super(Gui, self).__init__() self.speaker = "" self.directory = "" self.type = "" self.line=0 self.text=[] self.decode="" self.fname="output" self.rec=0 self.initUI() self.file = "" def initUI(self): self.setWindowIcon(QtGui.QIcon('logo.png')) self.vr = VoiceRec() self.pl = Play() self.vrThread = QThread() self.plThread = QThread() self.vr.moveToThread(self.vrThread) self.pl.moveToThread(self.plThread) self.figure = plt.figure(1) self.canvas = FigureCanvas(self.figure) self.toolbar = NavigationToolbar(self.canvas, self) self.centralwidget = QtGui.QWidget(self) self.verticalLayout = QtGui.QVBoxLayout(self.centralwidget) self.verticalLayout.addWidget(self.toolbar) self.verticalLayout.addWidget(self.canvas) self.centralwidget.setGeometry(10,10,825,330) openFile = QtGui.QAction(QtGui.QIcon('open.png'), '&Open', self) openFile.setShortcut('Ctrl+O') openFile.setStatusTip('Open new File') openFile.triggered.connect(self.showDialogOpen) chUser = QtGui.QAction('&Change Speaker', self) chUser.setStatusTip('Change Speaker') chUser.triggered.connect(self.changeUser) exitAction = QtGui.QAction(QtGui.QIcon('exit.png'), '&Exit', self) exitAction.setShortcut('Ctrl+Q') exitAction.setStatusTip('Exit application') exitAction.triggered.connect(self.closeEvent) utf_8 = QtGui.QAction('&UTF-8', self) utf_8.setStatusTip('utf-8') utf_8.triggered.connect(self.encodeUTF8) utf_16 = QtGui.QAction('&UTF-16', self) utf_16.setStatusTip('utf-16') utf_16.triggered.connect(self.encodeUTF16) Ascii = QtGui.QAction('&ASCII', self) Ascii.setStatusTip('ascii') Ascii.triggered.connect(self.encodeASCII) about = QtGui.QAction('&About', self) about.setStatusTip('More About Voice Recorder') about.triggered.connect(self.showAbout) self.textEdit = QtGui.QTextEdit(self) self.textEdit.setGeometry(10,360,825,104) self.textEdit.setStyleSheet("QTextEdit {font-size: 14pt}") self.textEdit.setText("Please Open a File...") self.textEdit.setReadOnly(True) self.Open = QtGui.QPushButton('Open', self) self.Open.move(10,480) self.Open.clicked.connect(self.showDialogOpen) self.Record = QtGui.QPushButton('Record', self) self.Record.move(155,480) self.Record.setEnabled(False) self.Record.clicked.connect(self.record) self.Stop = QtGui.QPushButton('Stop', self) self.Stop.move(300,480) self.Stop.setEnabled(False) self.Stop.clicked.connect(self.stop) self.Play = QtGui.QPushButton('Play', self) self.Play.move(445,480) self.Play.setEnabled(False) self.Play.clicked.connect(self.play) self.Back = QtGui.QPushButton('Back', self) self.Back.move(590,480) self.Back.setEnabled(False) self.Back.clicked.connect(self.showBack) self.Next = QtGui.QPushButton('Next', self) self.Next.move(735,480) self.Next.setEnabled(False) self.Next.clicked.connect(self.showNext) menubar = self.menuBar() fileMenu = menubar.addMenu('&File') fileMenu.addAction(openFile) fileMenu.addAction(chUser) fileMenu.addAction(exitAction) encodeMenu = menubar.addMenu('&Encoding') encodeMenu.addAction(Ascii) encodeMenu.addAction(utf_8) encodeMenu.addAction(utf_16) helpMenu = menubar.addMenu('&Help') helpMenu.addAction(about) self.setGeometry(200,200, 845, 550) self.setFixedSize(845 , 550) self.setWindowTitle('Akshar Voice Recorder') self.user = User(self) def showDialogOpen(self): plt.clf() self.canvas.draw() self.statusBar().showMessage('Open a File') self.fname = QtGui.QFileDialog.getOpenFileName(self, 'Open file') if(self.fname!=""): self.Record.setEnabled(True) self.Play.setEnabled(True) self.Next.setEnabled(True) self.Back.setEnabled(True) self.directory=str(self.file)+"/"+str(self.speaker)+"_"+str(self.type)+"_"+str(self.fname).split("/")[-1] if not os.path.exists(self.directory): os.makedirs(self.directory) del self.text[:] f = open(self.fname, 'r') for lines in f: self.text.append(lines) f.close if(self.decode!=""): self.textEdit.setText(self.text[self.line].decode(self.decode)) else: self.textEdit.setText(self.text[self.line].decode('ascii')) self.line=0 else: self.Record.setEnabled(False) self.Play.setEnabled(False) self.Next.setEnabled(False) self.Back.setEnabled(False) self.statusBar().showMessage('') def showNext(self): plt.clf() self.canvas.draw() self.line+=1 if(len(self.text)>self.line): if(self.decode!=""): self.textEdit.setText(self.text[self.line].decode(self.decode)) else: self.textEdit.setText(self.text[self.line].decode('utf-8')) else: self.showDialogOpen() def showBack(self): plt.clf() self.canvas.draw() self.line-=1 if(len(self.text)>=self.line and self.line>=0): if(self.decode!=""): self.textEdit.setText(self.text[self.line].decode(self.decode)) else: self.textEdit.setText(self.text[self.line].decode('utf-8')) else: self.showDialogOpen() def showAbout(self): self.popup1=About() self.popup1.exec_() def encodeUTF8(self): self.decode="utf-8" def encodeUTF16(self): self.decode="utf-16" def encodeASCII(self): self.decode="ascii" def changeUser(self): self.user.__init__(self) def record(self): plt.clf() self.canvas.draw() self.statusBar().showMessage('Recording') self.rec=1 self.Record.setEnabled(False) self.Stop.setEnabled(True) self.Open.setEnabled(False) self.Play.setEnabled(False) self.Next.setEnabled(False) self.Back.setEnabled(False) self.vrThread.start() self.vr.record(self.directory, self.text[self.line].split(")")[0], self) def stop(self): self.statusBar().showMessage('') if self.rec == 1: self.vr.stop() self.vrThread.exit() self.vrThread.wait() self.vrThread.quit() elif self.rec == 2: self.pl.stop() self.plThread.exit() self.plThread.wait() self.plThread.quit() self.Record.setEnabled(True) self.Open.setEnabled(True) self.Play.setEnabled(True) self.Next.setEnabled(True) self.Back.setEnabled(True) self.rec=0 def play(self): self.statusBar().showMessage('Playing') self.rec=2 self.Record.setEnabled(False) self.Stop.setEnabled(True) self.Open.setEnabled(False) self.Play.setEnabled(False) self.Next.setEnabled(False) self.Back.setEnabled(False) self.plThread.start() self.pl.play(self.text[self.line].split(")")[0], self)
class BisectRunner(QObject): bisector_created = Signal(object) running_state_changed = Signal(bool) def __init__(self, mainwindow): QObject.__init__(self) self.mainwindow = mainwindow self.bisector = None self.thread = None self.pending_threads = [] def bisect(self, fetch_config, options): self.stop() # global preferences global_prefs = get_prefs() # apply the global prefs now apply_prefs(global_prefs) download_dir = global_prefs['persist'] persist_limit = int(abs(global_prefs['persist_size_limit']) * 1073741824) if not download_dir: download_dir = self.mainwindow.persist self.bisector = GuiBisector(fetch_config, download_dir, persist_limit) # create a QThread, and move self.bisector in it. This will # allow to the self.bisector slots (connected after the move) # to be automatically called in the thread. self.thread = QThread() self.bisector.moveToThread(self.thread) self.bisector.test_runner.evaluate_started.connect( self.evaluate) self.bisector.finished.connect(self.bisection_finished) self.bisector.choose_next_build.connect(self.choose_next_build) self.bisector_created.emit(self.bisector) if options['bisect_type'] == 'nightlies': handler = NightlyHandler(find_fix=options['find_fix']) good = options['good_date'] bad = options['bad_date'] else: handler = InboundHandler(find_fix=options['find_fix']) good = options['good_changeset'] bad = options['bad_changeset'] # options for the app launcher launcher_kwargs = {} for name in ('profile', 'preferences'): if name in options: value = options[name] if value: launcher_kwargs[name] = value # add add-ons paths to the app launcher launcher_kwargs['addons'] = options['addons'] self.bisector.test_runner.launcher_kwargs = launcher_kwargs self.thread.start() self.bisector._bisect_args = (handler, good, bad) # this will be called in the worker thread. QTimer.singleShot(0, self.bisector.bisect) self.running_state_changed.emit(True) @Slot() def stop(self, wait=True): if self.bisector: self.bisector.finished.disconnect(self.bisection_finished) self.bisector.download_manager.cancel() self.bisector = None if self.thread: self.thread.quit() if wait: # wait for thread(s) completion - this is the case when # user close the application self.thread.wait() for thread in self.pending_threads: thread.wait() else: # do not block, just keep track of the thread - we got here # when user cancel the bisection with the button. self.pending_threads.append(self.thread) self.thread.finished.connect(self._remove_pending_thread) self.thread = None self.running_state_changed.emit(False) @Slot() def _remove_pending_thread(self): for thread in self.pending_threads[:]: if thread.isFinished(): self.pending_threads.remove(thread) @Slot(str) def evaluate(self, err_message): if not err_message: verdict = get_verdict(self.mainwindow) else: QMessageBox.warning( self.mainwindow, "Launcher Error", ("An error occured while starting the process, so the build" " will be skipped. Error message:<br><strong>%s</strong>" % err_message) ) verdict = 's' self.bisector.test_runner.finish(verdict) @Slot() def choose_next_build(self): dlg = SkipDialog(self.bisector.bisection.build_range) self.bisector._next_build_index = dlg.choose_next_build() QTimer.singleShot(0, self.bisector._bisect_next) @Slot(object, int) def bisection_finished(self, bisection, resultcode): if resultcode == Bisection.USER_EXIT: msg = "Bisection stopped." dialog = QMessageBox.information elif resultcode == Bisection.NO_DATA: msg = "Unable to find enough data to bisect." dialog = QMessageBox.warning elif resultcode == Bisection.EXCEPTION: msg = "Error: %s" % self.bisector.error[1] dialog = QMessageBox.critical else: if self.bisector.fetch_config.can_go_inbound() and \ isinstance(bisection.handler, NightlyHandler): # we can go on inbound, let's ask the user if QMessageBox.question( self.mainwindow, "End of the bisection", "Nightly bisection is done, but you can continue the" " bisection on inbound builds. Continue with inbounds ?", QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes ) == QMessageBox.Yes: # let's go on inbound QTimer.singleShot(0, self.bisector.nightlies_to_inbound) else: # no inbound, bisection is done. self.stop() return msg = "The bisection is done." dialog = QMessageBox.information dialog(self.mainwindow, "End of the bisection", msg) self.stop()
class XdkWindow(QMainWindow): """ """ loadFileRequested = Signal(str) def __init__( self, parent = None ): super(XdkWindow, self).__init__( parent ) # load the user interface projexui.loadUi(__file__, self) # define custom properties self._currentContentsIndex = -1 self._worker = XdkWorker() self._workerThread = QThread() self._worker.moveToThread(self._workerThread) self._workerThread.start() # set default properties self.setAcceptDrops(True) self.setAttribute( Qt.WA_DeleteOnClose ) self.uiFindNextBTN.setDefaultAction(self.uiFindNextACT) self.uiFindPrevBTN.setDefaultAction(self.uiFindPrevACT) self.uiFindWIDGET.setVisible(False) self.uiSearchWEB.page().setLinkDelegationPolicy( QWebPage.DelegateAllLinks) self.refreshUi() # connect widgets self.uiContentsTAB.currentChanged.connect(self.refreshUi) self.uiContentsTAB.tabCloseRequested.connect(self.closeContentsWidget) self.uiContentsTREE.itemExpanded.connect(self.loadItem) self.uiContentsTREE.itemSelectionChanged.connect(self.refreshContents) self.uiSearchTXT.returnPressed.connect(self.search) self.uiSearchWEB.linkClicked.connect(self.gotoUrl) self.uiIndexTREE.itemSelectionChanged.connect(self.refreshFromIndex) # connect find actions self.uiBackACT.triggered.connect(self.goBack) self.uiForwardACT.triggered.connect(self.goForward) self.uiHomeACT.triggered.connect(self.goHome ) self.uiFindTXT.textChanged.connect( self.findNext ) self.uiFindTXT.returnPressed.connect( self.findNext ) self.uiFindNextACT.triggered.connect( self.findNext ) self.uiFindPrevACT.triggered.connect( self.findPrev ) self.uiFindACT.triggered.connect(self.showFind) self.uiFindCloseBTN.clicked.connect(self.uiFindWIDGET.hide) self.uiCopyTextACT.triggered.connect( self.copyText ) # connect zoom actions self.uiZoomResetACT.triggered.connect( self.zoomReset ) self.uiZoomInACT.triggered.connect( self.zoomIn ) self.uiZoomOutACT.triggered.connect( self.zoomOut ) # connect file actions self.uiLoadACT.triggered.connect( self.loadFilename ) self.uiNewTabACT.triggered.connect( self.addContentsWidget ) self.uiCloseTabACT.triggered.connect( self.closeContentsWidget ) self.uiQuitACT.triggered.connect( self.close ) # connect the signals self.loadFileRequested.connect(self._worker.loadFile) self._worker.loadingFinished.connect(self.__addXdkItem) QApplication.instance().aboutToQuit.connect(self.__cleanupWorker) def __del__(self): self.__cleanupWorker() def __addXdkItem(self, filename): item = XdkItem(filename) # add the xdk content item self.uiContentsTREE.addTopLevelItem(item) # add the index list items self.uiIndexTREE.blockSignals(True) self.uiIndexTREE.setUpdatesEnabled(False) for name, url in item.indexlist(): item = XTreeWidgetItem([name]) item.setToolTip(0, url) item.setFixedHeight(22) self.uiIndexTREE.addTopLevelItem(item) self.uiIndexTREE.blockSignals(False) self.uiIndexTREE.setUpdatesEnabled(True) self.uiIndexTREE.sortByColumn(0, Qt.AscendingOrder) self.unsetCursor() def __cleanupWorker(self): if self._workerThread is None: return self._workerThread.quit() self._workerThread.wait() self._worker.deleteLater() self._workerThread.deleteLater() self._worker = None self._workerThread = None def __gotoUrl(self, url): if url.toLocalFile(): self.gotoUrl(url.toString()) else: webbrowser.open(str(url.toString())) def addContentsWidget( self ): """ Adds a new contents widget tab into the contents tab. :return <QWebView> """ curr_widget = self.currentContentsWidget() widget = QWebView(self) page = widget.page() page.setLinkDelegationPolicy(page.DelegateAllLinks) self.uiContentsTAB.blockSignals(True) self.uiContentsTAB.addTab(widget, 'Documentation') self.uiContentsTAB.setCurrentIndex(self.uiContentsTAB.count() - 1) self.uiContentsTAB.blockSignals(False) self._currentContentsIndex = self.uiContentsTAB.count() - 1 if curr_widget: widget.setUrl(curr_widget.url()) widget.titleChanged.connect(self.refreshUi) widget.linkClicked.connect(self.__gotoUrl) return widget def closeContentsWidget( self ): """ Closes the current contents widget. """ widget = self.currentContentsWidget() if ( not widget ): return widget.close() widget.setParent(None) widget.deleteLater() def copyText( self ): """ Copies the selected text to the clipboard. """ view = self.currentWebView() QApplication.clipboard().setText(view.page().selectedText()) def currentContentsIndex( self ): """ Returns the last index used for the contents widgets. :return <int> """ return self._currentContentsIndex def currentContentsWidget( self, autoadd = False ): """ Returns the current contents widget based on the cached index. If \ no widget is specified and autoadd is True, then a new widget will \ be added to the tab. :param autoadd | <bool> :return <QWebView> """ widget = self.uiContentsTAB.widget(self.currentContentsIndex()) if ( not isinstance(widget, QWebView) ): widget = None if ( not widget and autoadd ): widget = self.addContentsWidget() return widget def currentWebView(self): return self.uiContentsTAB.currentWidget() def dragEnterEvent(self, event): if event.mimeData().hasUrls(): event.accept() def dragMoveEvent(self, event): if event.mimeData().hasUrls(): event.accept() def dropEvent(self, event): if event.mimeData().hasUrls(): for url in event.mimeData().urls(): self.loadFilename(str(url.toLocalFile())) def findNext( self ): """ Looks for the previous occurance of the current search text. """ text = self.uiFindTXT.text() view = self.currentWebView() options = QWebPage.FindWrapsAroundDocument if ( self.uiCaseSensitiveCHK.isChecked() ): options |= QWebPage.FindCaseSensitively view.page().findText(text, options) def findPrev( self ): """ Looks for the previous occurance of the current search text. """ text = self.uiFindTXT.text() view = self.currentWebView() options = QWebPage.FindWrapsAroundDocument options |= QWebPage.FindBackward if ( self.uiCaseSensitiveCHK.isChecked() ): options |= QWebPage.FindCaseSensitively view.page().findText(text, options) def findXdk( self, name ): """ Looks up the xdk item based on the current name. :param name | <str> :return <XdkItem> || None """ for i in range(self.uiContentsTREE.topLevelItemCount()): item = self.uiContentsTREE.topLevelItem(i) if ( item.text(0) == name ): return item return None def goBack( self ): widget = self.currentContentsWidget() if ( widget ): widget.page().history().back() def goForward( self ): widget = self.currentContentsWidget() if ( widget ): widget.page().history().forward() def goHome( self ): widget = self.currentContentsWidget() if ( widget ): widget.history().goHome() def gotoUrl(self, url): if not QApplication.keyboardModifiers() == Qt.ControlModifier: widget = self.currentContentsWidget(autoadd = True) else: widget = self.addContentsWidget() index = self.uiContentsTAB.indexOf(widget) self.uiContentsTAB.setCurrentIndex(index) widget.setUrl(QUrl(url)) def gotoItem(self, path): """ Goes to a particular path within the XDK. :param path | <str> """ if not path: return sections = str(path).split('/') check = projex.text.underscore(sections[0]) for i in range(self.uiContentsTREE.topLevelItemCount()): item = self.uiContentsTREE.topLevelItem(i) if projex.text.underscore(item.text(1)) == check: item.gotoItem('/'.join(sections[1:])) break def loadItem( self, item ): """ Loads the inputed item. :param item | <QTreeWidgetItem> """ if isinstance(item, XdkEntryItem): item.load() def loadedFilenames( self ): """ Returns a list of all the xdk files that are currently loaded. :return [<str>, ..] """ output = [] for i in range(self.uiContentsTREE.topLevelItemCount()): item = self.uiContentsTREE.topLevelItem(i) output.append(str(item.filepath())) return output def loadFilename( self, filename = '' ): """ Loads a new XDK file into the system. :param filename | <str> :return <bool> | success """ if ( not (filename and isinstance(filename, basestring)) ): filename = QFileDialog.getOpenFileName( self, 'Open XDK File', QDir.currentPath(), 'XDK Files (*.xdk)' ) if type(filename) == tuple: filename = str(filename[0]) if not filename: return False if not (filename and os.path.exists(filename)): return False elif filename in self.loadedFilenames(): return False self.loadFileRequested.emit(filename) self.setCursor(Qt.WaitCursor) return True def refreshFromIndex( self ): """ Refreshes the documentation from the selected index item. """ item = self.uiIndexTREE.currentItem() if ( not item ): return self.gotoUrl(item.toolTip(0)) def refreshContents( self ): """ Refreshes the contents tab with the latest selection from the browser. """ item = self.uiContentsTREE.currentItem() if not isinstance(item, XdkEntryItem): return item.load() url = item.url() if url: self.gotoUrl(url) def refreshUi( self ): """ Refreshes the interface based on the current settings. """ widget = self.uiContentsTAB.currentWidget() is_content = isinstance(widget, QWebView) if is_content: self._currentContentsIndex = self.uiContentsTAB.currentIndex() history = widget.page().history() else: history = None self.uiBackACT.setEnabled(is_content and history.canGoBack()) self.uiForwardACT.setEnabled(is_content and history.canGoForward()) self.uiHomeACT.setEnabled(is_content) self.uiNewTabACT.setEnabled(is_content) self.uiCopyTextACT.setEnabled(is_content) self.uiCloseTabACT.setEnabled(is_content and self.uiContentsTAB.count() > 2) for i in range(1, self.uiContentsTAB.count()): widget = self.uiContentsTAB.widget(i) self.uiContentsTAB.setTabText(i, widget.title()) def search( self ): """ Looks up the current search terms from the xdk files that are loaded. """ QApplication.instance().setOverrideCursor(Qt.WaitCursor) terms = str(self.uiSearchTXT.text()) html = [] entry_html = '<a href="%(url)s">%(title)s</a><br/>'\ '<small>%(url)s</small>' for i in range(self.uiContentsTREE.topLevelItemCount()): item = self.uiContentsTREE.topLevelItem(i) results = item.search(terms) results.sort(lambda x, y: cmp(y['strength'], x['strength'])) for item in results: html.append( entry_html % item ) if ( not html ): html.append('<b>No results were found for %s</b>' % terms) self.uiSearchWEB.setHtml(SEARCH_HTML % '<br/><br/>'.join(html)) QApplication.instance().restoreOverrideCursor() def showFind( self ): self.uiFindWIDGET.show() self.uiFindTXT.setFocus() self.uiFindTXT.selectAll() def zoomIn( self ): view = self.currentWebView() view.setZoomFactor(view.zoomFactor() + 0.1) def zoomOut( self ): view = self.currentWebView() view.setZoomFactor(view.zoomFactor() - 0.1) def zoomReset( self ): view = self.currentWebView() view.setZoomFactor(1) @staticmethod def browse( parent, filename = '' ): """ Creates a new XdkWidnow for browsing an XDK file. :param parent | <QWidget> filename | <str> """ dlg = XdkWindow(parent) dlg.show() if ( filename ): dlg.loadFilename(filename)
class AbbyyOcr(QObject): # Signals error = pyqtSignal(str) def __init__(self, abbyy_path, parent=None): super(AbbyyOcr, self).__init__(parent) self.abbyy_path = abbyy_path self.app_watcher = None self.proc = None self.current_profile = None def ocr(self, path): options = ['/OptionsFile', self.current_profile] if self.current_profile else [] args = [self.abbyy_path, path] + options + ['/send', 'Acrobat'] startup_info = subprocess.STARTUPINFO() startup_info.dwFlags |= subprocess.STARTF_USESHOWWINDOW self.proc = subprocess.Popen(args, startupinfo=startup_info) self.app_watcher_thread = QThread() self.app_watcher = AppWatcher(self.proc) self.app_watcher.moveToThread(self.app_watcher_thread) self.app_watcher.error.connect(self.emit_error) self.app_watcher_thread.started.connect(self.app_watcher.start) self.app_watcher_thread.finished.connect(self.app_watcher_thread.deleteLater) self.app_watcher_thread.start() def kill(self): print 'Killing...' try: abbyy_temp_path = self.app_watcher.current_temp_path if not abbyy_temp_path: abbyy_temp_path = get_abbyy_temp_folder(self.pid) self.proc.kill() self.proc.wait() self.proc = None except AttributeError: # The process has already been deleted. abbyy_temp_path = None try: self.app_watcher.deleteLater() self.app_watcher_thread.quit() self.app_watcher_thread.wait() except (RuntimeError, AttributeError): # self.app_watcher already deleted. pass # Try to remove temp files. if abbyy_temp_path: print 'Removing', abbyy_temp_path os.chmod(abbyy_temp_path, stat.S_IWRITE) try: rmtree(abbyy_temp_path) map(os.remove, glob.glob('{0:s}/*.tmp'.format(os.path.join(tempfile.gettempdir(), 'FineReader10')))) except (OSError, IOError, WindowsError): pass print 'Killed' def emit_error(self, error_message): self.kill() self.error.emit(error_message)
def stop(self): self.mutex.lock() self.stopMe = 1 self.mutex.unlock() QThread.wait(self)
class Runner: """A wrapper around thread and worker objects Correctly starts a new thread and moves worker to it. """ def __init__(self, cls): """Store worker class in instance""" self.cls = cls self.running = False def start(self, *args, **kwargs): """Starts worker in separate thread""" # stop any previously running workers self.stop() self.result = None self.error = None self.running = True self.thread = QThread() self.worker = self.cls(*args, **kwargs) self.worker.moveToThread(self.thread) self.thread.started.connect(self.worker.start) # graceful stop does not work without direct connection (?) self.worker.finished.connect(self.thread.quit, Qt.DirectConnection) self.worker.finished.connect(self.worker.deleteLater) self.thread.finished.connect(self.thread.deleteLater) # also save result/error on finish (useful for testing) self.worker.finished.connect(self.handlefinished, Qt.DirectConnection) self.worker.raised.connect(self.handleraised, Qt.DirectConnection) self.worker.completed.connect(self.handlecompleted, Qt.DirectConnection) self.worker.killed.connect(self.handlekilled, Qt.DirectConnection) self.thread.start() # returns worker so caller can connect signals, etc. return self.worker def stop(self): """Attempts to gracefully stop worker Forcefully terminates otherwise.""" logging.debug('Worker: trying to stop gracefully') if not self.running: logging.debug('Worker was not running') return try: self.worker.kill() if not self.thread.wait(settings.KILL_TIMEOUT): raise KillTimeoutError() except KillTimeoutError: logging.warn('Worker: kill timed out, force terminating...') self.thread.terminate() self.thread.wait() except Exception as e: logging.warn('Worker: terminate failed!?') logging.warn(e) # The following methods are for testing @pyqtSlot(str) def handleraised(self, error): """Slot that saves error, useful for testing""" logging.warn('[WORKER] raised: {}'.format(error)) self.error = error @pyqtSlot(object) def handlefinished(self): logging.debug('[WORKER] finished') self.running = False @pyqtSlot(object) def handlecompleted(self, result): """Slot that saves result, useful for testing""" logging.debug('[WORKER] completed') self.result = result @pyqtSlot(object) def handlekilled(self): logging.debug('[WORKER] killed') def wait(self, timeout): """Wait for thread to end, and return result Useful for testing. """ try: self.thread.wait(timeout) return self.result except: return None
class MainWindow(QMainWindow): """ MainWindow widget. Connects GUI and worker threads. Inherits from: QMainWindow Buttons: None Signals: None """ def __init__(self, content_gui, content_pipeline, settings_folder, mount_directory, version, parent=None): """ Setup the layout for the widget Arguments: content_gui - Content used to create the GUI outfit. content_pipeline - Content used to start processing threads. settings_folder - Name of the folder containing settings. mount_directory - Name of the folder containing mount points. version - Version of TranSPHIRE. parent - Parent widget (default None) Return: None """ super(MainWindow, self).__init__(parent) # Ask for sudo password if needed self.password = '' need_sudo_password = False for content in content_gui: if content['name'] == 'Status': for entry in content['content']: for widget in entry: for key in widget: if key == 'Mount/umount needs sudo password?': if widget[key][0] == 'True': need_sudo_password = True else: pass else: pass elif content['name'] == 'Mount': for entry in content['content_mount']: for widget in entry: for key in widget: if key == 'Need sudo for copy?': if widget[key][0] == 'True': need_sudo_password = True else: pass else: pass else: pass if need_sudo_password: dialog = SudoPasswordDialog(self) dialog.exec_() if not dialog.result(): QCoreApplication.instance().quit() sys.exit() else: self.password = dialog.password else: pass # Start TranSPHIRE from HOME directory. self.path = os.environ['HOME'] # Window title self.setWindowTitle('{0} v{1} - {2} - {3}'.format( 'TranSPHIRE', version, self.path, os.uname()[1])) # Initiate contents self.central_widget = None self.content = None self.layout = None # Settings folder self.settings_folder = settings_folder self.mount_directory = mount_directory self.temp_save = '{0}/temp_save'.format(settings_folder) # Threads self.mount_worker = None self.process_worker = None self.plot_worker = None self.mount_calculation_ssh = None self.mount_calculation_get = None self.mount_calculation_df = None self.thread_mount = None self.thread_process = None self.thread_plot = None self.mount_thread_list = None # Fill GUI self.reset_gui(content_gui=content_gui, content_pipeline=content_pipeline) def start_threads(self, content_pipeline): """ Start threads used in TranSPHIRE. Arguments: content_pipeline - Content used to start processing threads. Return: None """ # Stop threads if already started. if self.mount_worker is not None: self.mount_worker.setParent(None) if self.process_worker is not None: self.process_worker.setParent(None) if self.plot_worker is not None: self.plot_worker.setParent(None) if self.thread_mount is not None: self.thread_mount.quit() self.thread_mount.wait() self.thread_mount.setParent(None) if self.thread_process is not None: self.thread_process.quit() self.thread_process.wait() self.thread_process.setParent(None) if self.thread_plot is not None: self.thread_plot.quit() self.thread_plot.wait() self.thread_plot.setParent(None) if self.mount_thread_list is not None: for setting in self.content['Mount'].get_settings(): for key in setting: thread = self.mount_thread_list[key]['thread'] calculator = self.mount_thread_list[key]['object'] calculator.kill_thread = True thread.quit() thread.wait() # Create objects used in threads self.mount_worker = MountWorker(password=self.password, settings_folder=self.settings_folder, mount_directory=self.mount_directory) self.process_worker = ProcessWorker( password=self.password, content_process=content_pipeline, mount_directory=self.mount_directory) self.plot_worker = PlotWorker() # Create threads self.thread_mount = QThread(self) self.thread_process = QThread(self) self.thread_plot = QThread(self) # Start threads self.thread_mount.start() self.thread_process.start() self.thread_plot.start() # Start objects in threads self.mount_worker.moveToThread(self.thread_mount) self.process_worker.moveToThread(self.thread_process) self.plot_worker.moveToThread(self.thread_plot) def reset_gui(self, content_gui, content_pipeline, load_file=None): """ Reset the content of the mainwindow. Arguments: content_gui - Content used to fill the GUI. content_pipeline - Content used to start processing threads. load_file - Settings file (default None). Return: None """ # Fill MainWindow self.set_central_widget() self.set_layout_structure() self.start_threads(content_pipeline=content_pipeline) postprocess_content = self.fill_content(content_gui=content_gui) self.postprocess_content(postprocess_content) for content in content_gui: if content['name'] == 'Status': for entry in content['content']: for widget in entry: for key in widget: if key == 'Project name pattern': self.project_name_pattern = widget[key][0] elif key == 'Project name pattern example': self.project_name_pattern_example = widget[ key][0] else: pass else: pass # Load settings saved in load_file if load_file is not None: self.load(file_name=load_file) os.remove('{0}.txt'.format(load_file)) elif os.path.exists('{0}.txt'.format(self.temp_save)): # Result is True if answer is No result = tu.question(head='Restore previous session.', text='Restore previous session?', parent=self) if result: pass else: self.load(file_name=self.temp_save) else: pass self.mount_worker.sig_load_save.emit() def save_temp_settings(self): """ Save the status of the GUI in a temp file. Arguments: None Return: True, if saving was succesful. """ if os.path.exists('{0}.txt'.format(self.temp_save)): os.remove('{0}.txt'.format(self.temp_save)) else: pass value = self.save(file_name=self.temp_save, temp=True) return value def postprocess_content(self, error_list): """ Do postprocessing of creating GUI content, like connecting signals. Arguments: error_list - List of errors that occured. Return: True, if saving was succesful. """ for entry in error_list: tu.message(entry) self.process_worker.sig_finished.connect(self._finished) self.process_worker.sig_plot_ctf.connect( self.plot_worker.calculate_array_ctf) self.process_worker.sig_plot_motion.connect( self.plot_worker.calculate_array_motion) self.plot_worker.sig_message.connect(lambda msg: tu.message(msg)) self.mount_thread_list = {} for key in self.content['Mount'].content: thread = QThread(self) thread.start() mount_calculator = MountCalculator(name=key) mount_calculator.moveToThread(thread) self.mount_thread_list[key] = { 'thread': thread, 'object': mount_calculator } mount_calculator.sig_finished.connect( self.content['Status'].refresh_quota) mount_calculator.sig_finished.connect(self.abort_finished) self.mount_worker.sig_calculate_ssh_quota.connect( mount_calculator.calculate_ssh_quota) self.mount_worker.sig_calculate_df_quota.connect( mount_calculator.calculate_df_quota) self.mount_worker.sig_calculate_get_quota.connect( mount_calculator.calculate_get_quota) self.content['Mount'].set_threadlist( thread_list=self.mount_thread_list) def abort_finished(self, *args, **kwargs): """ Set the mount worker abort variable to True. Arguments: None Return: None """ self.mount_worker.abort_finished = True def set_central_widget(self): """ Reset the central widget of the MainWindow. Arguments: None Return: None """ if self.central_widget is not None: self.central_widget.setParent(None) else: pass self.central_widget = QWidget(self) self.central_widget.setObjectName('central') self.setCentralWidget(self.central_widget) def set_layout_structure(self): """ Setup the layout structure for the central widget. Arguments: None Return: None """ # Layout dictionary self.layout = {} self.layout['h1'] = QHBoxLayout(self.central_widget) self.layout['h2'] = QHBoxLayout() self.layout['h3'] = QHBoxLayout() self.layout['v'] = QVBoxLayout() # Layout architecture self.layout['h1'].addLayout(self.layout['v'], stretch=1) self.layout['v'].addLayout(self.layout['h2'], stretch=0) self.layout['v'].addWidget(Separator(typ='horizontal', color='grey'), stretch=0) self.layout['v'].addLayout(self.layout['h3'], stretch=1) def fill_content(self, content_gui): """ Fill the layouts of the central widget. Arguments: content_gui - Content used to create the GUI outfit. Return: List of errors that occured. """ self.content = {} exclude_set = tu.get_exclude_set(content=content_gui) error_list = [] tab_list = [] for entry in content_gui: key = entry['name'] if key in exclude_set: continue elif entry['layout'] in exclude_set: continue elif key == 'Stretch': layout = entry['layout'] self.layout[layout].addStretch(1) continue elif key == 'Separator': layout = entry['layout'] separator = entry['separator'] self.layout[layout].addWidget(separator) continue elif key == 'Path': tu.reduce_path_widget(exclude_set=exclude_set, content=entry['content']) elif key == 'Copy': tu.reduce_copy_entries(exclude_set=exclude_set, content=entry['content']) else: pass layout = entry['layout'] plot_labels = '' plot_name = '' try: plot_name = layout.replace('Plot ', '') plot_labels = ti.get_dtype_dict()[tu.get_function_dict() [plot_name]['typ']] except KeyError: pass # Create widget self.content[key] = entry['widget']( mount_worker=self.mount_worker, process_worker=self.process_worker, plot_worker=self.plot_worker, settings_folder=self.settings_folder, plot_labels=plot_labels, plot_name=plot_name, parent=self, **entry) if isinstance(self.content[key], TabDocker): tab_list.append(key) else: pass if layout in tab_list: self.content[layout].add_tab(self.content[key], key) else: self.layout[layout].addWidget(self.content[key]) if key == 'Button': self.content[key].sig_load.connect(self.load) self.content[key].sig_save.connect(self.save) self.content[key].sig_start.connect(self.start) self.content[key].sig_stop.connect(self.stop_dialog) self.content[key].sig_check_quota.connect(self.check_quota) else: pass if key == 'Notification': self.content[key].update_telegram() self.content[key].update_email() self.content[key].update() self.content[key].sig_stop.connect(self.stop) timer = QTimer(self) timer.setInterval(20000) timer.timeout.connect(self.content[key].get_telegram_messages) timer.start() else: pass if key == 'Plot per micrograph' or key == 'Plot histogram': self.plot_worker.sig_data.connect( self.content[key].update_figure) else: pass return error_list def check_quota(self): """ Check the quota for the project and scratch directory. Arguments: None Return: None """ global_settings = self.content['General'].get_settings() global_settings = {'General': global_settings[0]} self.mount_worker.sig_set_settings.emit(global_settings) def load(self, file_name=None): """ Load settings from settings file. Arguments: file_name - Name of the file (default None) Return: None """ if file_name is None: file_name = QFileDialog.getOpenFileName( caption='Load settings', directory=self.path, options=QFileDialog.DontUseNativeDialog) if QT_VERSION == 4: file_name = file_name elif QT_VERSION == 5: file_name = file_name[0] else: raise ImportError( 'QT version unknown! Please contact the transphire authors!' ) if not file_name: return else: pass if file_name.endswith('.txt'): pass elif os.path.exists(file_name): pass else: file_name = '{0}.txt'.format(file_name) settings = [] with open(file_name, 'r') as read: for line in read: line = line.replace('\n', '') key, *value = line.split('\t') if isinstance(value, list): settings.append([key, *value]) else: settings.append([key, value]) settings = self.settings_to_dict(settings=settings) self.set_settings(settings=settings) def set_settings(self, settings): """ Load settings from settings file. Arguments: settings - Settings as dictionary. Return: None """ for key in settings: if key == 'End': continue else: try: self.content[key].set_settings(settings[key]) except KeyError: print('Key', key, 'no longer exists') continue @staticmethod def settings_to_dict(settings): """ Make the settings readable for the widgets set settings method. Arguments: settings - Settings as dictionary. Return: None """ settings_dict = {} idx = -1 while idx < len(settings) - 1: idx += 1 if settings[idx][0] == '###': key = settings[idx][1] if key == 'Frames': settings_dict[key] = [] else: settings_dict[key] = {} continue if len(settings[idx]) == 1: settings[idx].append('') if key == 'Frames': setting = {} setting[settings[idx][0]] = settings[idx][1] for i in range(3): idx += 1 setting[settings[idx][0]] = settings[idx][1] settings_dict[key].append(setting) else: if key == 'Notification': settings_dict[key].update({ settings[idx][0]: [settings[idx][1], settings[idx][2]] }) else: settings_dict[key].update( {settings[idx][0]: settings[idx][1]}) return settings_dict def save(self, file_name=None, temp=False): """ Save GUI status to file. Arguments: file_name - File name to save settings to. temp - File is a temporary save file. Return: True, if saving was succesful. """ if file_name is None: file_name = QFileDialog.getSaveFileName( caption='Save settings', directory=self.path, options=QFileDialog.DontUseNativeDialog, filter="Text files (*.txt)") if QT_VERSION == 4: file_name = file_name elif QT_VERSION == 5: file_name = file_name[0] else: raise ImportError( 'QT version unknown! Please contact the transphire authors!' ) if not file_name: return None else: pass else: pass if file_name.endswith('.txt'): pass else: file_name = '{0}.txt'.format(file_name) # Do not override settings if os.path.exists(file_name): old_filename = file_name for number in range(9999): file_name = '{0}_{1}'.format(old_filename, number) if os.path.exists(file_name): continue else: break else: pass error = False with open(file_name, 'w') as write: for key in self.content: if key == 'Mount': continue else: pass try: settings = self.content[key].get_settings() except AttributeError: continue if settings is not None: write.write('###\t{0}\n'.format(key)) for entry in settings: for key_entry in entry: write.write('{0}\t{1}\n'.format( key_entry, entry[key_entry])) else: error = True message = 'Setting of {0} not valid!'.format(key) tu.message(message) continue write.write('###\tEnd\n') write.write('The\tEnd\n') message_pass = '******'.format(file_name) message_error = 'Invalid setting detected! Saveing failed!' if error: os.remove(file_name) tu.message(message_error) print(message_error) return False else: if temp: pass else: tu.message(message_pass) print(message_pass) return True @pyqtSlot() def start(self): """ Start TranSPHIRE processing. Arguments: None Return: None """ self.enable(False) settings = {} # Load settings to pass them to the working threads error_list = [] skip_list = ['Mount', 'Notification', 'Path', 'Frames'] for key in self.content: try: settings_widget = self.content[key].get_settings() except AttributeError: continue else: settings[key] = {} if settings_widget is None: self.enable(True) return None elif key == 'Frames': settings_motion = {} else: pass if key == 'Frames': skip_name_list = [] else: skip_name_list = tu.get_function_dict()[key]['allow_empty'] for entry in settings_widget: if key not in skip_list: for name in entry: if not entry[name] and name not in skip_name_list: error_list.append( '{0}:{1} is not allowed to be emtpy!'.format( key, name)) else: pass else: pass for idx, entry in enumerate(settings_widget): if key == 'Frames': settings_motion[idx] = entry else: settings[key].update(entry) if key == 'Frames': settings['motion_frames'] = settings_motion else: pass if error_list: tu.message('\n'.join(error_list)) self.enable(True) return None else: pass # Get mount information for key in settings['Mount']: device_name = key.replace(' ', '_') save_file = os.path.join(self.settings_folder, device_name) try: with open(save_file, 'r') as read: lines = read.readlines() except FileNotFoundError: continue for line in lines: name = line.split('\t')[0] settings['user_{0}'.format(device_name)] = name settings['user_Later'] = None if not re.match(self.project_name_pattern, settings['General']['Project name']): self.enable(True) tu.message( 'Project name needs to match pattern:\n{0}\n For example: {1}'. format(self.project_name_pattern, self.project_name_pattern_example)) return None else: pass # Project folder names settings['project_folder'] = os.path.join( settings['General']['Project directory'], settings['General']['Project name']) settings['compress_folder'] = os.path.join( settings['General']['Project directory'], settings['General']['Project name']) settings['motion_folder'] = os.path.join( settings['General']['Project directory'], settings['General']['Project name']) settings['ctf_folder'] = os.path.join( settings['General']['Project directory'], settings['General']['Project name']) settings['scratch_folder'] = os.path.join( settings['General']['Scratch directory'], settings['General']['Project name']) settings['Copy_hdd_folder'] = self.mount_directory settings['Copy_backup_folder'] = self.mount_directory settings['Copy_work_folder'] = self.mount_directory settings['settings_folder'] = os.path.join(settings['project_folder'], 'settings') settings['queue_folder'] = os.path.join(settings['project_folder'], 'queue') settings['error_folder'] = os.path.join(settings['project_folder'], 'error') # Check for continue mode if os.path.exists(settings['project_folder']): result = self.continue_dialog( text1='Output project folder already exists!', text2='Do you really want to continue the old run?\nType: YES!' ) if result: result_session = self.continue_dialog( text1='Software metafiles', text2='Software metafiles (Atlas, ...) might be already copied!\n' + \ 'Do you want to copy them again?\nType: YES!' ) settings['Copy_software_meta'] = bool(result_session) else: settings['Copy_software_meta'] = True else: settings['Copy_software_meta'] = True result = True # Create project and settings folder for name in [ 'project_folder', 'settings_folder', 'scratch_folder', 'queue_folder', 'error_folder' ]: try: tu.mkdir_p(settings[name]) except FileNotFoundError: tu.message('Project name cannot be empty') self.enable(True) return None # Start or stop procedure if result: self.content['Button'].start_button.setText('Stop') self.plot_worker.settings = settings self.process_worker.sig_start.emit(settings) self.mount_worker.set_settings(settings=settings) self.save( file_name=os.path.join(settings['settings_folder'], settings['General']['Project name'])) self.save_temp_settings() else: tu.message('Input needs to be "YES!" to work') self.enable(True) def continue_dialog(self, text1, text2): """ Check if the user wants to run the continue mode. Arguments: text1 - Dialog window name. text2 - Text of the dialog. Return: True, if the input is YES! """ dialog = QInputDialog(self) result = dialog.getText(self, text1, text2) return bool(result[0] == 'YES!') @pyqtSlot() def stop_dialog(self): """ Check if the user really wants to stop the process. Arguments: None Return: None """ result = self.continue_dialog( text1='Do you really want to stop?', text2='Do you really want to stop!\nType: YES!') if result: self.stop() else: tu.message('Input needs to be "YES!" to work') @pyqtSlot() def stop(self): """ Stop the process. Arguments: None Return: None """ self.process_worker.stop = True self.content['Button'].start_button.setEnabled(False) @pyqtSlot() def _finished(self): """ Rename the Stop Button to start and enable everything. Arguments: None Return: None """ self.enable(True) self.content['Button'].start_button.setText('Start') self.content['Button'].start_button.setEnabled(True) @pyqtSlot(bool) def enable(self, var, use_all=False): """Enable or disable widgets Arguments: var - Enable status of the widgets. use_all - Disable/Enable everything (Default False) Return: None """ for key in self.content: try: self.content[key].enable(var=var, use_all=use_all) except AttributeError: continue def closeEvent(self, event): """ Quit threads before close and check if the process is still running Arguments: event - QCloseEvent. Return: None """ if self.content['Button'].start_button.text() == 'Stop': event.ignore() tu.message('First stop the program before closing') return None elif not self.save_temp_settings(): result = tu.question( head='Error saving file!', text='Wrong setting detected! Quit without saving?', ) # Result is true if the answer is No if not result: pass else: event.ignore() return None else: pass self.thread_mount.quit() self.thread_mount.wait() self.thread_process.quit() self.thread_process.wait() self.thread_plot.quit() self.thread_plot.wait() for key in self.content['Mount'].content: thread = self.mount_thread_list[key]['thread'] calculator = self.mount_thread_list[key]['object'] calculator.kill_thread = True thread.quit() thread.wait() message = 'Bye Bye' print(message) super(MainWindow, self).closeEvent(event)
class RasterLegendSensitive(QObject): def __init__(self, iface, treeView, ckEnabled): super(RasterLegendSensitive, self).__init__() self.tree = TreeLegend(treeView) self.ckEnabled = ckEnabled # self.layer = self.worker = self.thread = self.transparencyLayer = None self.isExtentLayer = self.valuesFullExtent = None self.hasConnect = self.hasConnectTree = None self.iface = iface self.legend = iface.legendInterface() self.canvas = iface.mapCanvas() self.msgBar = iface.messageBar() self.nameModulus = "RasterLegendSensitive" # self.initThread() self._connect() self._connectTree() def __del__(self): del self.tree self.finishThread() if not self.hasConnect: self._connect(False) if not self.layer is None: self.setTransparenceLayer([]) def initThread(self): self.thread = QThread(self) self.thread.setObjectName(self.nameModulus) self.worker = WorkerRasterLegendSensitive() self.worker.moveToThread(self.thread) self._connectWorker() def finishThread(self): self._connectWorker(False) self.worker.deleteLater() self.thread.wait() self.thread.deleteLater() self.thread = self.worker = None def _connectWorker(self, isConnect=True): ss = [{ 'signal': self.thread.started, 'slot': self.worker.run }, { 'signal': self.worker.finished, 'slot': self.finishedWorker }, { 'signal': self.worker.messageStatus, 'slot': self.messageStatusWorker }] if isConnect: for item in ss: item['signal'].connect(item['slot']) else: for item in ss: item['signal'].disconnect(item['slot']) def _connect(self, isConnect=True): ss = [{ 'signal': self.legend.currentLayerChanged, 'slot': self.selectLayer }, { 'signal': QgsMapLayerRegistry.instance().layerWillBeRemoved, 'slot': self.removeLayer }, { 'signal': self.canvas.extentsChanged, 'slot': self.changeSensitiveLegend }] if isConnect: self.hasConnect = True for item in ss: item['signal'].connect(item['slot']) else: self.hasConnect = False for item in ss: item['signal'].disconnect(item['slot']) def _connectTree(self, isConnect=True): ss = [{ 'signal': self.tree.toggledLegend, 'slot': self.setTransparenceLayer }, { 'signal': self.tree.descriptionLegend, 'slot': self.sendClipboard }] if isConnect: self.hasConnectTree = True for item in ss: item['signal'].connect(item['slot']) else: self.hasConnectTree = False for item in ss: item['signal'].disconnect(item['slot']) def _resetLayer(self): if self.thread.isRunning(): self.worker.isKilled = True self.layer = None self.tree.setHeader() self.tree.layer = None def setEnabled(self, isEnabled=True): if not isEnabled and self.thread.isRunning(): self.worker.isKilled = True # self._connect(isEnabled) self._connectTree(isEnabled) self.tree.setEnabled(isEnabled) # if isEnabled: activeLayer = self.iface.activeLayer() if activeLayer == self.layer: if activeLayer is None: return self.changeSensitiveLegend() else: self.selectLayer(activeLayer) @pyqtSlot(list) def finishedWorker(self, values): self.thread.quit() self.msgBar.popWidget() if not self.worker.isKilled: if len(values) > 0: # Never Happing otherwise... self.tree.setLegend(values) if self.isExtentLayer: self.valuesFullExtent = values else: # When PAN/ZOOM/... self.thread.wait() if self.ckEnabled.checkState() == Qt.Checked: self.changeSensitiveLegend() @pyqtSlot(str) def messageStatusWorker(self, msg): self.msgBar.popWidget() self.msgBar.pushMessage(self.nameModulus, msg, QgsMessageBar.INFO) @pyqtSlot(list) def setTransparenceLayer(self, visibleItems): def refreshLayer(): if hasattr(self.layer, "setCacheImage"): self.layer.setCacheImage(None) # Refresh else: self.layer.triggerRepaint() def setTransparence(value, visible): t = QgsRasterTransparency.TransparentSingleValuePixel() t.min = t.max = value percent = 100.0 if not visible else 0.0 t.percentTransparent = percent return t valuesTransparent = [] item = 0 for visible in visibleItems: valuesTransparent.append(setTransparence(item, visible)) item += 1 self.transparencyLayer.setTransparentSingleValuePixelList( valuesTransparent) refreshLayer() del valuesTransparent[:] @pyqtSlot(str) def sendClipboard(self, description): mapSettings = self.canvas.mapSettings() crsCanvas = mapSettings.destinationCrs() extentCanvas = self.canvas.extent() extentLayer = self.layer.extent() if self.layer.crs() != crsCanvas: extentCanvas = mapSettings.mapToLayerCoordinates( self.layer, extentCanvas) if extentCanvas == extentLayer or extentCanvas.contains(extentLayer): msg = "Calculate for all extent of layer '%s'\n\n%s" % ( self.layer.name(), description) else: msg = "Calculate for subset of layer '%s' (extend: %s)\n\n%s" % ( self.layer.name(), extentCanvas.toString(), description) clip = QApplication.clipboard() clip.setText(msg) self.msgBar.pushMessage(self.nameModulus, "Copy to Clipboard", QgsMessageBar.INFO, 5) @pyqtSlot('QgsMapLayer') def selectLayer(self, layer): def processLegend(): self.tree.setLayer(layer) if not self.valuesFullExtent is None: # Save legend with all extent layer del self.valuesFullExtent[:] self.valuesFullExtent = None (self.layer, self.transparencyLayer) = (layer, layer.renderer().rasterTransparency()) self.worker.setLegendReadBlock(layer) self.changeSensitiveLegend() if not self.layer is None: if not self.layer in self.legend.layers(): self.removeLayer(self.layer.id()) else: self.setTransparenceLayer([]) self._resetLayer() if not layer is None and layer.type() == QgsMapLayer.RasterLayer: legendItems = layer.legendSymbologyItems() total = len(legendItems) if total > 0: # Had a classification processLegend() @pyqtSlot(str) def removeLayer(self, idLayer): if not self.layer is None and self.layer.id() == idLayer: msg = "Layer '%s' was removed" % self.tree.getLayerName() self.msgBar.pushMessage(self.nameModulus, msg, QgsMessageBar.WARNING, 5) self._resetLayer() @pyqtSlot() def changeSensitiveLegend(self): if self.layer is None: return if self.thread.isRunning(): self.worker.isKilled = True return mapSettings = self.canvas.mapSettings() crsCanvas = mapSettings.destinationCrs() extentCanvas = self.canvas.extent() extentLayer = self.layer.extent() resX = self.layer.rasterUnitsPerPixelX() resY = self.layer.rasterUnitsPerPixelY() if self.layer.crs() != crsCanvas: extentCanvas = mapSettings.mapToLayerCoordinates( self.layer, extentCanvas) if not extentCanvas.intersects(extentLayer): self.msgBar.popWidget() self.msgBar.pushMessage( self.nameModulus, "View not intersects Raster '%s'" % self.layer.name(), QgsMessageBar.WARNING, 5) self.tree.setLegend([]) return if extentCanvas == extentLayer or extentCanvas.contains(extentLayer): self.isExtentLayer = True if not self.valuesFullExtent is None: self.tree.setLegend(self.valuesFullExtent) return extent = extentLayer delta = 0 else: self.isExtentLayer = False extent = extentCanvas.intersect(extentLayer) delta = 1 widthRead = int(extent.width() / resX) + delta heightRead = int(extent.height() / resY) + delta self.worker.setProcessImage(extent, widthRead, heightRead) self.thread.start()
class CatalogOTF(QObject): # Signals settedLayer = pyqtSignal("QgsVectorLayer") removedLayer = pyqtSignal(str) killed = pyqtSignal(str) changedNameLayer = pyqtSignal(str, str) changedTotal = pyqtSignal(str, str) changedIconRun = pyqtSignal(str, bool) def __init__(self, iface, tableCOTF): def connecTableCOTF(): self.settedLayer.connect(tableCOTF.insertRow) self.removedLayer.connect(tableCOTF.removeRow) self.changedNameLayer.connect(tableCOTF.changedNameLayer) self.changedTotal.connect(tableCOTF.changedTotal) self.changedIconRun.connect(tableCOTF.changedIconRun) self.killed.connect(tableCOTF.killed) super(CatalogOTF, self).__init__() self.iface = iface self.canvas = iface.mapCanvas() self.ltv = iface.layerTreeView() self.model = self.ltv.layerTreeModel() self.ltgRoot = QgsProject.instance().layerTreeRoot() self.msgBar = iface.messageBar() self.legendTMS = LegendTMS('Catalog OTF') self.legendRaster = LegendRaster('Catalog OTF') self._initThread() connecTableCOTF() self.model.dataChanged.connect(self.dataChanged) QgsMapLayerRegistry.instance().layersWillBeRemoved.connect( self.layersWillBeRemoved) # Catalog layer removed self.layer = self.layerName = self.nameFieldSource = self.nameFieldDate = None self.ltgCatalog = self.ltgCatalogName = self.visibleSourceLayers = self.hasCanceled = None def __del__(self): self._finishThread() del self.legendTMS del self.legendRaster QgsMapLayerRegistry.instance().layersWillBeRemoved.disconnect( self.layersWillBeRemoved) # Catalog layer removed def _initThread(self): self.thread = QThread(self) self.thread.setObjectName("QGIS_Plugin_%s" % NAME_PLUGIN.replace(' ', '_')) self.worker = WorkerPopulateGroup(self.addLegendLayerWorker) self.worker.moveToThread(self.thread) self._connectWorker() def _finishThread(self): self._connectWorker(False) self.worker.deleteLater() self.thread.wait() self.thread.deleteLater() self.thread = self.worker = None def _connectWorker(self, isConnect=True): ss = [{ 'signal': self.thread.started, 'slot': self.worker.run }, { 'signal': self.worker.finished, 'slot': self.finishedPG }, { 'signal': self.worker.messageStatus, 'slot': self.messageStatusPG }, { 'signal': self.worker.messageError, 'slot': self.messageErrorPG }] if isConnect: for item in ss: item['signal'].connect(item['slot']) else: for item in ss: item['signal'].disconnect(item['slot']) def addLegendLayerWorker(self, layer): if layer.type() == QgsMapLayer.RasterLayer: metadata = layer.metadata() if metadata.find("GDAL provider") != -1: if metadata.find("OGC Web Map Service") != -1: if self.legendTMS.hasTargetWindows(layer): self.legendTMS.setLayer(layer) else: self.legendRaster.setLayer(layer) def run(self): self.hasCanceled = False # Check in finishedPG if self.thread.isRunning(): self.worker.kill() self.hasCanceled = True msgtrans = QCoreApplication.translate( "CatalogOTF", "Canceled search for image from layer %s") msg = msgtrans % self.layerName self.msgBar.pushMessage(NAME_PLUGIN, msg, QgsMessageBar.WARNING, 2) self.changedTotal.emit(self.layer.id(), "Canceling processing") self.killed.emit(self.layer.id()) return if self.layer is None: msgtrans = QCoreApplication.translate("CatalogOTF", "Need define layer catalog") self.msgBar.pushMessage(NAME_PLUGIN, msgtrans, QgsMessageBar.WARNING, 2) return self._setGroupCatalog() self.ltgCatalogName = self.ltgCatalog.name() renderFlag = self.canvas.renderFlag() if renderFlag: self.canvas.setRenderFlag(False) self.canvas.stopRendering() self._populateGroupCatalog() if renderFlag: self.canvas.setRenderFlag(True) self.canvas.refresh() def _populateGroupCatalog(self): def getSourceVisibleLayers(): def hasVisibleRaster(ltl): return ltl.isVisible() == Qt.Checked and ltl.layer().type( ) == QgsMapLayer.RasterLayer l_ltlVisible = filter(lambda item: hasVisibleRaster(item), self.ltgCatalog.findLayers()) return map(lambda item: item.layer().source(), l_ltlVisible) def runWorker(): data = {} data['nameFieldDate'] = self.nameFieldDate data['nameFieldSource'] = self.nameFieldSource data['layer'] = self.layer data['ltgCatalog'] = self.ltgCatalog self.worker.setData(data) self.thread.start() #self.worker.run() # DEBUG self.visibleSourceLayers = getSourceVisibleLayers() self.ltgCatalog.removeAllChildren() runWorker() # See finishPG def _setGroupCatalog(self): self.ltgCatalogName = "%s - Catalog" % self.layer.name() self.ltgCatalog = self.ltgRoot.findGroup(self.ltgCatalogName) if self.ltgCatalog is None: self.ltgCatalog = self.ltgRoot.addGroup(self.ltgCatalogName) @pyqtSlot(bool) def finishedPG(self, isKilled): def setSourceVisibleLayers(): l_ltlVisible = filter( lambda item: item.layer().source() in self.visibleSourceLayers, self.ltgCatalog.findLayers()) map(lambda item: item.setVisible(Qt.Checked), l_ltlVisible) self.thread.quit() if not self.layer is None: self.changedIconRun.emit(self.layer.id(), self.layer.selectedFeatureCount() > 0) if self.hasCanceled: self.changedTotal.emit(self.layer.id(), '0') else: setSourceVisibleLayers() del self.visibleSourceLayers[:] @pyqtSlot(str) def messageStatusPG(self, msg): self.changedTotal.emit(self.layer.id(), msg) @pyqtSlot(str) def messageErrorPG(self, msg): self.msgBar.pushMessage(NAME_PLUGIN, msg, QgsMessageBar.CRITICAL, 8) @pyqtSlot('QModelIndex', 'QModelIndex') def dataChanged(self, idTL, idBR): if idTL != idBR: return if not self.ltgCatalog is None and self.ltgCatalog == self.model.index2node( idBR): name = self.ltgCatalog.name() if self.ltgCatalogName != name: self.ltgCatalogName = name return if not self.layer is None and self.ltgRoot.findLayer( self.layer.id()) == self.model.index2node(idBR): name = self.layer.name() if self.layerName != name: self.changedNameLayer.emit(self.layer.id(), name) self.layerName = name @pyqtSlot(list) def layersWillBeRemoved(self, layerIds): if self.layer is None: return if self.layer.id() in layerIds: self.removedLayer.emit(self.layer.id()) self.removeLayerCatalog() @staticmethod def getNameFieldsCatalog(layer): def getFirstFeature(): f = QgsFeature() # fr = QgsFeatureRequest( ) # First FID can be 0 or 1 depend of provider type it = layer.getFeatures(fr) isOk = it.nextFeature(f) it.close() # if not isOk or not f.isValid(): del f return None else: return f def hasAddress(feature, nameField): def asValidUrl(url): isOk = True try: urllib2.urlopen(url) except urllib2.HTTPError, e: isOk = False except urllib2.URLError, e: isOk = False # return isOk value = feature.attribute(nameField) if value is None or type(value) == QPyNullVariant: return False isUrl = value.find('http://') == 0 or value.find('https://') == 0 lenSource = len(value) isUrl = isUrl and value.rfind( 'xml', lenSource - len('xml')) == lenSource - len('xml') if isUrl: return asValidUrl(value) # fileInfo = QFileInfo(value) return fileInfo.isFile()
class MavDialog(QDialog): # .. _updateMavState: # # This signal, sent by a MAV, informs the GUI of the MAV's current state. It simply invokes _on_updateMavState. updateMavState = pyqtSignal( # See mavIndex_. int, # See MAV_STATES_. object) def __init__(self, # .. _numMavs: # # The number of MAVs in the simulation. numMavs, # See _flyTimeSec. flyTimeSec, # See _chargeTimeSec. chargeTimeSec): # First, let the QDialog initialize itself. super(MavDialog, self).__init__() # Create a ChargingStation to manage the MAVs. self._chargingStation = ChargingStation(self, numMavs, flyTimeSec, chargeTimeSec) # `Load <http://pyqt.sourceforge.net/Docs/PyQt4/designer.html#PyQt4.uic.loadUi>`_ # in our UI. The secord parameter lods the resulting UI directly into # this class. uic.loadUi(join(dirname(__file__), 'mav_gui.ui'), self) # Only allow numbers between 0 and 99 for the line edits. flyTimeValidator = QDoubleValidator(0.0, 9.9, 1, self) flyTimeValidator.setNotation(QDoubleValidator.StandardNotation) self.leFlyTime.setValidator(flyTimeValidator) chargeTimeValidator = QDoubleValidator(0.0, 9.9, 1, self) chargeTimeValidator.setNotation(QDoubleValidator.StandardNotation) self.leChargeTime.setValidator(chargeTimeValidator) # Example: create a separate thread self._thread = QThread(self) #self._thread.start() # Create a worker. self._worker = DummyWorker(self) # Timer examples # ^^^^^^^^^^^^^^ # A single-shot timer. It can't be canceled. QTimer.singleShot(1500, self._onTimeout) # Another single-shot timer. Because it has a name, it can be canceled. self._timer = QTimer(self) self._timer.timeout.connect(self._onTimeout) self._timer.setSingleShot(True) self._timer.start(3000) # Add in status info GUI for numMavs MAVs. hl = QHBoxLayout() self.wMavStatus.setLayout(hl) assert numMavs > 0 self.numMavs = numMavs self.mavStatus = [] self.electrodeStatus = [] self._chargeTimeSec = [chargeTimeSec]*self.numMavs self._flyTimeSec = [flyTimeSec]*self.numMavs for index in range(self.numMavs): e = UncheckableRadioButton(self) self.electrodeStatus.append(e) hl.addWidget(e) # Add in a group box. smw = SingleMavWidget() mavName = 'MAV {}'.format(index + 1) smw.gb = QGroupBox(mavName, self.wMavStatus) vl = QVBoxLayout() smw.gb.setLayout(vl) smw.rbFlying = UncheckableRadioButton('Flying', smw.gb) smw.rbWaiting = UncheckableRadioButton('Waiting', smw.gb) smw.rbCharging = UncheckableRadioButton('Charging', smw.gb) vl.addWidget(smw.rbFlying) vl.addWidget(smw.rbWaiting) vl.addWidget(smw.rbCharging) self.mavStatus.append(smw) hl.addWidget(smw.gb) # Update the combo box. self.cbSelectedMav.insertItem(index, mavName) # Update GUI with parameters. self.on_cbSelectedMav_currentIndexChanged(0) self.updateMavState.connect(self._on_updateMavState) # .. _on_updateMavState: # # A standardized way for MAVs to update their status. Should be invoked @pyqtSlot(int, object) def _on_updateMavState(self, # See mavIndex_. mavIndex, # See MAV_STATES_. mavState): # Make only one of the radio buttons checkable, so that the user can't check a different one. ms = self.mavStatus[mavIndex] if mavState == _MAV_STATES.Waiting: ms.rbWaiting.setCheckable(True) ms.rbFlying.setCheckable(False) ms.rbCharging.setCheckable(False) ms.rbWaiting.setChecked(True) elif mavState == _MAV_STATES.Flying: ms.rbWaiting.setCheckable(False) ms.rbFlying.setCheckable(True) ms.rbCharging.setCheckable(False) self.mavStatus[mavIndex].rbFlying.setChecked(True) elif mavState == _MAV_STATES.Charging: ms.rbWaiting.setCheckable(False) ms.rbFlying.setCheckable(False) ms.rbCharging.setCheckable(True) self.mavStatus[mavIndex].rbCharging.setChecked(True) else: assert False @pyqtSlot() def _onTimeout(self): self.hsFlyTime.setValue(50) @pyqtSlot(int) def on_hsFlyTime_valueChanged(self, value): flyTimeSec = value/10.0 self._chargingStation._mav[self.cbSelectedMav.currentIndex()].updateFlyTimeSec.emit(flyTimeSec) self.leFlyTime.setText(str(flyTimeSec)) self._flyTimeSec[self.cbSelectedMav.currentIndex()] = flyTimeSec self._worker.run.emit(1.5) @pyqtSlot() def on_leFlyTime_editingFinished(self): self.hsFlyTime.setValue(float(self.leFlyTime.text())*10.0) @pyqtSlot(int) def on_hsChargeTime_valueChanged(self, value): chargeTimeSec = value/10.0 self._chargingStation._mav[self.cbSelectedMav.currentIndex()].updateChargeTimeSec.emit(chargeTimeSec) self.leChargeTime.setText(str(chargeTimeSec)) self._chargeTimeSec[self.cbSelectedMav.currentIndex()] = chargeTimeSec self._worker.run.emit(1.5) @pyqtSlot() def on_leChargeTime_editingFinished(self): self.hsChargeTime.setValue(float(self.leChargeTime.text())*10.0) @pyqtSlot(int) def on_cbSelectedMav_currentIndexChanged(self, index): self.hsChargeTime.setValue(self._chargeTimeSec[index]*10) self.hsFlyTime.setValue(self._flyTimeSec[index]*10) # Free all resources used by this class. def terminate(self): self._thread.quit() self._thread.wait() self._timer.stop()
class BAONQtApplication(QApplication): BACKUP_DIALOG_CAPTION = 'Rename Plan Backup Detected' BACKUP_DIALOG_ERROR_CAPTION = 'Error' BACKUP_INTRO_TEXT = 'BAON has detected a backed up rename plan from a previous run of the '\ 'application. This suggests that the application crashed partway through executing a rename operation. The '\ 'files may have been left in an inconsistent state.' BACKUP_PROMPT_TEXT = 'What do you want to do?' REVERT_BACKUP_PROGRESS_TEXT = 'Reverting the rename operation' SUCCESS_DIALOG_CAPTION = 'Success' WARNING_DIALOG_CAPTION = 'Warning' BACKUP_DELETED_DIALOG_TEXT =\ 'The backed up plan has been deleted. Further runs of the application will proceed normally.' BACKUP_REVERTED_SUCCESS_DIALOG_TEXT = 'The rename operation has been reverted successfully. The directory state '\ 'should now have been completely restored.' BACKUP_REVERTED_WARNING_DIALOG_TEXT = 'There were inconsistencies while trying to revert the previous rename '\ 'operation. The directory state may not have been fully restored.' REVERT_BACKUP_BUTTON_TEXT = 'Revert the rename (recommended)' DELETE_BACKUP_BUTTON_TEXT = 'Delete the backup file' EXAMINE_BACKUP_BUTTON_TEXT = 'Examine the plan in a text editor' QUIT_BUTTON_TEXT = 'Quit BAON' request_revert_backup = pyqtSignal() request_delete_backup = pyqtSignal() _main_window = None _core = None _progress_dialog = None _core_thread = None def __init__(self, args): super().__init__(sys.argv) # Actually we do quit when the last window is closed, but we need to do this in a more controlled way self.setQuitOnLastWindowClosed(False) self._init_threads() self._init_main_objects(args) self._connect_main_objects() self._start_core() def event(self, evt): if isinstance(evt, QFileOpenEvent): path = evt.file() if not os.path.isdir(path): path, _ = os.path.split(path) self._main_window.set_base_path(path) return True return super().event(evt) def _init_threads(self): self._core_thread = QThread() self._core_thread.start() def _init_main_objects(self, args): self._main_window = MainWindow(args) self._core = BAONQtCore(args) self._core.moveToThread(self._core_thread) def _connect_main_objects(self): self.aboutToQuit.connect(self._on_quit) # Core vs. application self._core.request_backup_decision.connect(self.backup_decision_requested) self._core.reverted_backup.connect(self.notify_backup_reverted) self._core.revert_backup_error.connect(self.handle_backup_op_error) self._core.deleted_backup.connect(self.notify_backup_deleted) self._core.delete_backup_error.connect(self.handle_backup_op_error) self.request_revert_backup.connect(self._core.revert_backup) self.request_delete_backup.connect(self._core.delete_backup) # Core vs. main window self._core.prologue_finished.connect(self._main_window.show_first_time) self._core.status_changed.connect(self._main_window.report_status) self._core.scanned_files_updated.connect(self._main_window.update_scanned_files) self._core.renamed_files_updated.connect(self._main_window.update_renamed_files) self._core.has_shutdown.connect(self.quit) self._main_window.base_path_edited.connect(self._core.update_base_path) self._main_window.scan_recursive_changed.connect(self._core.update_scan_recursive) self._main_window.rules_text_changed.connect(self._core.update_rules_text) self._main_window.use_path_changed.connect(self._core.update_use_path) self._main_window.use_extension_changed.connect(self._core.update_use_extension) self._main_window.request_add_override.connect(self._core.add_override) self._main_window.request_remove_override.connect(self._core.remove_override) self._main_window.request_do_rename.connect(self._core.do_rename) self._main_window.request_rescan.connect(self._core.rescan) self._main_window.rejected.connect(self._core.shutdown) def _start_core(self): QMetaObject.invokeMethod(self._core, 'start', Qt.QueuedConnection) def _on_quit(self): self._core_thread.quit() self._core_thread.wait() @pyqtSlot() def backup_decision_requested(self): self._show_backup_decision() @pyqtSlot(Exception) def handle_backup_op_error(self, error): self._close_progress_dialog() self._show_backup_decision(error=error) @pyqtSlot() def notify_backup_deleted(self): QMessageBox.information( None, self.SUCCESS_DIALOG_CAPTION, self.BACKUP_DELETED_DIALOG_TEXT, ) @pyqtSlot(bool) def notify_backup_reverted(self, complete_success): self._close_progress_dialog() if complete_success: QMessageBox.information( None, self.SUCCESS_DIALOG_CAPTION, self.BACKUP_REVERTED_SUCCESS_DIALOG_TEXT, ) else: QMessageBox.warning( None, self.WARNING_DIALOG_CAPTION, self.BACKUP_REVERTED_WARNING_DIALOG_TEXT, ) def _show_backup_decision(self, error=None): text = '<p>{0}</p><p>{1}</p>'.format( self.BACKUP_INTRO_TEXT if error is None else error, self.BACKUP_PROMPT_TEXT, ) dialog = QMessageBox( QMessageBox.Question if error is None else QMessageBox.Critical, self.BACKUP_DIALOG_CAPTION if error is None else self.BACKUP_DIALOG_ERROR_CAPTION, text, ) revert_button = dialog.addButton(self.REVERT_BACKUP_BUTTON_TEXT, QMessageBox.AcceptRole) delete_button = dialog.addButton(self.DELETE_BACKUP_BUTTON_TEXT, QMessageBox.DestructiveRole) examine_button = dialog.addButton(self.EXAMINE_BACKUP_BUTTON_TEXT, QMessageBox.ActionRole) dialog.addButton(self.QUIT_BUTTON_TEXT, QMessageBox.RejectRole) dialog.exec() clicked_button = dialog.clickedButton() if clicked_button == examine_button: QMetaObject.invokeMethod(self, '_examine_backup', Qt.QueuedConnection) elif clicked_button == revert_button: self._progress_dialog = QProgressDialog(None) self._progress_dialog.setLabelText(self.REVERT_BACKUP_PROGRESS_TEXT) self._progress_dialog.setCancelButton(None) self._progress_dialog.setRange(0, 0) self._progress_dialog.forceShow() self.request_revert_backup.emit() elif clicked_button == delete_button: self.request_delete_backup.emit() else: self.quit() @pyqtSlot() def _examine_backup(self): error = None try: filename = get_rename_plan_backup_filename() QDesktopServices.openUrl(QUrl.fromLocalFile(filename)) except Exception as err: error = err finally: self._show_backup_decision(error) def _close_progress_dialog(self): if self._progress_dialog is not None: self._progress_dialog.close() self._progress_dialog = None
class file_transfer(iface_gui_plugin): VERSION_INITIAL = 0 VERSION_CURRENT = VERSION_INITIAL def __init__(self): super(file_transfer, self).__init__() self.options = [((u"download_dir", u"Save received files in directory", self._downloadDirChanged), os.path.join(os.path.expanduser("~"), "Downloads")), ((u"overwrite", u"Overwrite existing files", self._overwriteChanged), False), ((u"compression", u"Use compression when sending", self._compressionChanged, (u"No", u"GZip", u"BZip2")), u"No")] def get_displayed_name(self): return u"File Transfer" def activate(self): iface_gui_plugin.activate(self) self._sendFileAction = _TransferFileAction() def deactivate(self): iface_gui_plugin.deactivate(self) def create_widget(self, parent): from file_transfer.file_transfer_widget import FileTransferWidget from file_transfer.file_transfer_handler import FileTransferHandler if canUseBackgroundQThreads(): from PyQt4.QtCore import QThread self._handlerThread = QThread() else: self._handlerThread = None self._handler = FileTransferHandler(self.logger, self.get_option(u"download_dir"), self.get_option(u"overwrite"), self.get_option(u"compression")) if self._handlerThread is not None: self._handlerThread.moveToThread(self._handlerThread) self._handlerThread.start() self._gui = FileTransferWidget(parent, self.logger, self) self._toolWindow = FileTransferWidget(parent, self.logger, self, asWindow=True) self._toolWindow.setWindowTitle("File Transfers") for gui in (self._gui, self._toolWindow): gui.retry.connect(self._handler.retrySendFileToPeer) gui.cancel.connect(self._handler.cancelOutgoingTransfer) self._handler.startOutgoingTransfer.connect(gui.startOutgoingTransfer) self._handler.outgoingTransferStarted.connect(gui.outgoingTransferStarted) self._handler.outgoingTransferCanceled.connect(gui.outgoingTransferCanceled) self._handler.incomingTransferStarted.connect(gui.incomingTransferStarted) return self._gui def destroy_widget(self): for gui in (self._gui, self._toolWindow): gui.retry.disconnect(self._handler.retrySendFileToPeer) gui.cancel.disconnect(self._handler.cancelOutgoingTransfer) self._handler.startOutgoingTransfer.disconnect(gui.startOutgoingTransfer) self._handler.outgoingTransferStarted.disconnect(gui.outgoingTransferStarted) self._handler.outgoingTransferCanceled.disconnect(gui.outgoingTransferCanceled) self._handler.incomingTransferStarted.disconnect(gui.incomingTransferStarted) self._handler.deactivate() if self._handlerThread is not None: self._handlerThread.quit() self._handlerThread.wait() self._handlerThread.deleteLater() self._handlerThread = None self._handler = None iface_gui_plugin.destroy_widget(self) def extendsInfoDict(self): # do not except file transfers without GUI return lunchinator_has_gui() def extendInfoDict(self, infoDict): infoDict[u"FT_v"] = self.VERSION_CURRENT def get_peer_actions(self): return [self._sendFileAction] def process_event(self, cmd, value, peerIP, peerInfo, preprocessedData=None): if not cmd.startswith(u"HELO_FT"): return peerID = peerInfo[u"ID"] subcmd = cmd[7:] if subcmd == u"": self._handler.processSendRequest(peerID, peerIP, value, preprocessedData) elif subcmd == u"_ACK": self._handler.processAck(peerID, peerIP, value) elif subcmd == u"_CANCEL": self._handler.processCancel(peerID, value) def getSendFileAction(self): return self._sendFileAction def chooseAndSendFilesToPeer(self, peerID, parent): from PyQt4.QtGui import QFileDialog selectedFiles = QFileDialog.getOpenFileNames(parent, u"Chooses files to upload") if len(selectedFiles) > 0: self._handler.sendFilesToPeer([convert_string(f) for f in selectedFiles], peerID) def sendFilesToPeer(self, toSend, peerID): self._handler.sendFilesToPeer([convert_string(f) for f in toSend], peerID) def _downloadDirChanged(self, _setting, newVal): self._handler.downloadDirChanged(newVal) return newVal def _overwriteChanged(self, _setting, newVal): self._handler.overwriteChanged(newVal) return newVal def _compressionChanged(self, _setting, newVal): self._handler.compressionChanged(newVal) return newVal
class GCode(object): def __init__(self, filename, controller, done_loading_callback, done_writing_callback): self.controller = controller self.done_loading_callback = done_loading_callback self.writing_done_callback = done_writing_callback self.data = defaultdict(list) self.all_data = [] self.data_keys = set() self.color_change_data = [] self.actual_z = '0.0' self.speed = 0.0 self.z_hop = False self.last_point = np.array([0.0, 0.0, 0.0]) self.actual_point = [0.0, 0.0, 0.0] self.printing_time = 0.0 self.filament_length = 0.0 #print("Filename type: " + str(type(filename))) #print("Filename: " + filename) #if type(filename)==: #self.filename = u'c:\\models\\super mega testovací Jindřich šložka čěýáéůú\\anubis_PLA_OPTIMAL.gcode' self.filename = filename self.is_loaded = False self.gcode_parser = GcodeParserRunner(controller, self.filename) self.gcode_parser_thread = QThread() self.gcode_copy = GcodeCopyRunner( self.filename, "", color_change_lst=self.color_change_data) self.gcode_copy_thread = QThread() def cancel_parsing_gcode(self): print("Cancel presset") if self.gcode_parser and self.gcode_parser_thread and self.gcode_parser_thread.isRunning( ): self.gcode_parser.is_running = False self.gcode_parser_thread.quit() self.gcode_parser_thread.wait() self.is_loaded = False self.data = {} self.all_data = [] self.data_keys = [] self.controller.set_progress_bar(0) def cancel_writing_gcode(self): print("Cancel writing gcode") if self.gcode_copy and self.gcode_copy_thread and self.gcode_copy_thread.isRunning( ): self.gcode_copy.quit() self.gcode_copy_thread.wait() def get_first_extruding_line_number_of_gcode_for_layers( self, layers_keys_lst): lines_number = [] for i in layers_keys_lst: line = self.data[i] for o in line: _a, _b, type, _speed, _extr, _extruder, line_n = o if 'E' in type: lines_number.append(line_n) break return lines_number def read_in_thread(self, update_progressbar_function, after_done_function): print("reading in thread") self.gcode_parser.moveToThread(self.gcode_parser_thread) self.done_loading_callback = after_done_function # connect all signals to thread class self.gcode_parser_thread.started.connect( self.gcode_parser.load_gcode_file) # connect all signals to parser class self.gcode_parser.finished.connect(self.set_finished_read) self.gcode_parser.update_progressbar = True self.gcode_parser.set_update_progress.connect( update_progressbar_function) self.gcode_parser.set_data_keys.connect(self.set_data_keys) self.gcode_parser.set_data.connect(self.set_data) self.gcode_parser.set_all_data.connect(self.set_all_data) self.gcode_parser.set_printing_time.connect(self.set_printig_time) self.gcode_parser_thread.start() def read_in_realtime(self): print("Read in realtime") self.gcode_parser.set_data_keys.connect(self.set_data_keys) self.gcode_parser.set_data.connect(self.set_data) self.gcode_parser.set_all_data.connect(self.set_all_data) self.gcode_parser.set_printing_time.connect(self.set_printig_time) self.gcode_parser.update_progressbar = False print("start read procedure") self.gcode_parser.load_gcode_file() self.is_loaded = True def set_printig_time(self, time): self.printing_time = time def set_data_keys(self, data_keys): self.data_keys = data_keys def set_all_data(self, all_data): self.all_data = all_data def set_data(self, data): self.data = data def set_finished_read(self): self.gcode_parser_thread.quit() self.is_loaded = True self.done_loading_callback() #self.controller.set_gcode() def set_finished_copy(self): self.gcode_copy_thread.quit() #print(str(self.writing_done_callback)) self.writing_done_callback() def set_color_change_data(self, data): self.color_change_data = data def write_with_changes_in_thread(self, filename_in, filename_out, update_function): self.gcode_copy.filename_in = filename_in self.gcode_copy.filename_out = filename_out self.gcode_copy.color_change_lst = self.color_change_data self.gcode_copy.moveToThread(self.gcode_copy_thread) self.gcode_copy_thread.started.connect(self.gcode_copy.write_file) self.gcode_copy.finished.connect(self.set_finished_copy) self.gcode_copy.set_update_progress.connect(update_function) self.gcode_copy_thread.start()
class ImageStream(QtGui.QLabel): def __init__(self, cal_wizard, device): super(ImageStream, self).__init__() self.cal_wizard = cal_wizard self.signal_snap = QtCore.SIGNAL("snapshot_taken") self.signal_reload = QtCore.SIGNAL("reload") self.device = device tree = ET.parse(device.local_config_path) self.group = tree.find('communicator').find('group').text self.receiver_thread = QThread() self.receiver_thread.start() self.image_receiver = ImageReceiver(self.device, self.group) self.image_receiver.moveToThread(self.receiver_thread) self.connect(self.image_receiver, self.image_receiver.signal, self.update_image) self.transmitter_thread = QThread() self.transmitter_thread.start() self.image_transmitter = ImageTransmitter(self.device) self.image_transmitter.moveToThread(self.transmitter_thread) self.connect(self.image_transmitter, self.image_transmitter.signal, self.reload) def finish(self): self.stop() self.receiver_thread.quit() self.receiver_thread.wait() self.transmitter_thread.quit() self.transmitter_thread.wait() def start(self): QtCore.QTimer.singleShot(0, self.image_transmitter.task) QtCore.QTimer.singleShot(0, self.image_receiver.task) def update_image(self): self.setPixmap(QtGui.QPixmap.fromImage(self.image_receiver.img)) return def stop(self): # note: The image receiver has to be stopped first # otherwise zyre will keep waiting for a message from the # transmitter indefinitely self.image_receiver.stop() self.image_transmitter.stop() def snap(self): # give command to take snapshot self.image_receiver.snap() # download snapshot ssh = self.device.ssh_manager.get_ssh() sftp = ssh.open_sftp() sftp.get(os.path.join(paths.get_remote_config_dir(self.device), 'snapshot.png'), self.cal_wizard.get_next_snap_path(self.device)) sftp.remove(os.path.join(paths.get_remote_config_dir(self.device), 'snapshot.png')) ssh.close() self.emit(self.signal_snap, 'snapshot taken') def reload(self): # Stop ImageTransmitter/Receiver self.stop() # Start ImageTransmitter again self.start() self.emit(self.signal_reload, 'reload')
class GCode(object): def __init__(self, filename, controller, done_loading_callback, done_writing_callback): self.controller = controller self.done_loading_callback = done_loading_callback self.writing_done_callback = done_writing_callback self.data = defaultdict(list) self.all_data = [] self.data_keys = set() self.color_change_data = [] self.actual_z = '0.0' self.speed = 0.0 self.z_hop = False self.last_point = np.array([0.0, 0.0, 0.0]) self.actual_point = [0.0, 0.0, 0.0] self.printing_time = 0.0 self.filament_length = 0.0 #print("Filename type: " + str(type(filename))) #print("Filename: " + filename) #if type(filename)==: #self.filename = u'c:\\models\\super mega testovací Jindřich šložka čěýáéůú\\anubis_PLA_OPTIMAL.gcode' self.filename = filename self.is_loaded = False self.gcode_parser = GcodeParserRunner(controller, self.filename) self.gcode_parser_thread = QThread() self.gcode_copy = GcodeCopyRunner(self.filename, "", color_change_lst=self.color_change_data) self.gcode_copy_thread = QThread() def cancel_parsing_gcode(self): print("Cancel presset") if self.gcode_parser and self.gcode_parser_thread and self.gcode_parser_thread.isRunning(): self.gcode_parser.is_running = False self.gcode_parser_thread.quit() self.gcode_parser_thread.wait() self.is_loaded = False self.data = {} self.all_data = [] self.data_keys = [] self.controller.set_progress_bar(0) def cancel_writing_gcode(self): print("Cancel writing gcode") if self.gcode_copy and self.gcode_copy_thread and self.gcode_copy_thread.isRunning(): self.gcode_copy.quit() self.gcode_copy_thread.wait() def get_first_extruding_line_number_of_gcode_for_layers(self, layers_keys_lst): lines_number = [] for i in layers_keys_lst: line = self.data[i] for o in line: _a, _b, type, _speed, _extr, line_n = o if 'E' in type: lines_number.append(line_n) break return lines_number def read_in_thread(self, update_progressbar_function, after_done_function): print("reading in thread") self.gcode_parser.moveToThread(self.gcode_parser_thread) self.done_loading_callback = after_done_function # connect all signals to thread class self.gcode_parser_thread.started.connect(self.gcode_parser.load_gcode_file) # connect all signals to parser class self.gcode_parser.finished.connect(self.set_finished_read) self.gcode_parser.update_progressbar=True self.gcode_parser.set_update_progress.connect(update_progressbar_function) self.gcode_parser.set_data_keys.connect(self.set_data_keys) self.gcode_parser.set_data.connect(self.set_data) self.gcode_parser.set_all_data.connect(self.set_all_data) self.gcode_parser.set_printing_time.connect(self.set_printig_time) self.gcode_parser_thread.start() def read_in_realtime(self): print("Read in realtime") self.gcode_parser.set_data_keys.connect(self.set_data_keys) self.gcode_parser.set_data.connect(self.set_data) self.gcode_parser.set_all_data.connect(self.set_all_data) self.gcode_parser.set_printing_time.connect(self.set_printig_time) self.gcode_parser.update_progressbar=False print("start read procedure") self.gcode_parser.load_gcode_file() self.is_loaded = True def set_printig_time(self, time): self.printing_time = time def set_data_keys(self, data_keys): self.data_keys = data_keys def set_all_data(self, all_data): self.all_data = all_data def set_data(self, data): self.data = data def set_finished_read(self): self.gcode_parser_thread.quit() self.is_loaded = True self.done_loading_callback() #self.controller.set_gcode() def set_finished_copy(self): self.gcode_copy_thread.quit() #print(str(self.writing_done_callback)) self.writing_done_callback() def set_color_change_data(self, data): self.color_change_data = data def write_with_changes_in_thread(self, filename_in, filename_out, update_function): self.gcode_copy.filename_in = filename_in self.gcode_copy.filename_out = filename_out self.gcode_copy.color_change_lst = self.color_change_data self.gcode_copy.moveToThread(self.gcode_copy_thread) self.gcode_copy_thread.started.connect(self.gcode_copy.write_file) self.gcode_copy.finished.connect(self.set_finished_copy) self.gcode_copy.set_update_progress.connect(update_function) self.gcode_copy_thread.start()
class BisectRunner(QObject): bisector_created = Signal(object) running_state_changed = Signal(bool) def __init__(self, mainwindow): QObject.__init__(self) self.mainwindow = mainwindow self.bisector = None self.thread = None self.pending_threads = [] def bisect(self, fetch_config, options): self.stop() # global preferences global_prefs = get_prefs() # apply the global prefs now apply_prefs(global_prefs) self.bisector = GuiBisector(fetch_config, persist=global_prefs['persist']) # create a QThread, and move self.bisector in it. This will # allow to the self.bisector slots (connected after the move) # to be automatically called in the thread. self.thread = QThread() self.bisector.moveToThread(self.thread) self.bisector.download_manager.download_progress.connect( self.show_dl_progress) self.bisector.test_runner.evaluate_started.connect( self.evaluate) self.bisector.finished.connect(self.bisection_finished) self.bisector_created.emit(self.bisector) if options['bisect_type'] == 'nightlies': handler = NightlyHandler(find_fix=options['find_fix']) start = options['start_date'] end = options['end_date'] else: handler = InboundHandler(find_fix=options['find_fix']) start = options['start_changeset'] end = options['end_changeset'] # options for the app launcher launcher_kwargs = {} for name in ('profile', 'preferences'): if name in options: value = options[name] if value: launcher_kwargs[name] = value self.bisector.test_runner.launcher_kwargs = launcher_kwargs self.thread.start() self.bisector._bisect_args = (handler, start, end) # this will be called in the worker thread. QTimer.singleShot(0, self.bisector.bisect) self.running_state_changed.emit(True) @Slot() def stop(self, wait=True): if self.bisector: self.bisector.finished.disconnect(self.bisection_finished) self.bisector.download_manager.cancel() self.bisector = None if self.thread: self.thread.quit() if wait: # wait for thread(s) completion - this is the case when # user close the application self.thread.wait() for thread in self.pending_threads: thread.wait() else: # do not block, just keep track of the thread - we got here # when user cancel the bisection with the button. self.pending_threads.append(self.thread) self.thread.finished.connect(self._remove_pending_thread) self.thread = None self.running_state_changed.emit(False) @Slot() def _remove_pending_thread(self): for thread in self.pending_threads[:]: if thread.isFinished(): self.pending_threads.remove(thread) @Slot(object, int, int) def show_dl_progress(self, dl, current, total): message = "downloading %s: %d/%d" % (dl.get_dest(), current, total) self.mainwindow.ui.statusbar.showMessage(message, 2000) @Slot() def evaluate(self): verdict = get_verdict(self.mainwindow) self.bisector.test_runner.finish(verdict) @Slot(object, int) def bisection_finished(self, bisection, resultcode): if resultcode == Bisection.USER_EXIT: msg = "Bisection stopped." dialog = QMessageBox.information elif resultcode == Bisection.NO_DATA: msg = "Unable to find enough data to bisect." dialog = QMessageBox.warning elif resultcode == Bisection.EXCEPTION: msg = "Error: %s" % self.bisector.error[1] dialog = QMessageBox.critical else: if bisection.fetch_config.can_go_inbound() and \ isinstance(bisection.handler, NightlyHandler): # we can go on inbound, let's ask the user if QMessageBox.question( self.mainwindow, "End of the bisection", "Nightly bisection is done, but you can continue the" " bisection on inbound builds. Contibue with inbounds ?", QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes ) == QMessageBox.Yes: # let's go on inbound QTimer.singleShot(0, self.bisector.nightlies_to_inbound) else: # no inbound, bisection is done. self.stop() return msg = "The bisection is done." dialog = QMessageBox.information dialog(self.mainwindow, "End of the bisection", msg) self.stop()
class SensitiveLegendRaster(QObject): def __init__(self): super(SensitiveLegendRaster, self).__init__() # QThread self.layer = self.worker = self.thread = None self.canvas = iface.mapCanvas() self.msgBar = iface.messageBar() self.legend = iface.legendInterface() self.nameModulus = "Script_Sensitive_Legend" # self.initThread() self._connect() # self.selectLayer(iface.activeLayer()) def __del__(self): self.finishThread() self._connect(False) def printMsgBar(self, msg, typeMsg=QgsMessageBar.INFO): self.msgBar.popWidget() if typeMsg == QgsMessageBar.INFO: self.msgBar.pushMessage("SensitiveLegendRaster Script", msg, typeMsg) else: self.msgBar.pushMessage("SensitiveLegendRaster Script", msg, typeMsg, 5) def initThread(self): self.thread = QThread(self) self.thread.setObjectName(self.nameModulus) self.worker = WorkerSensitiveLegendRaster() self.worker.moveToThread(self.thread) self._connectWorker() def finishThread(self): self._connectWorker(False) self.worker.deleteLater() self.thread.wait() self.thread.deleteLater() self.thread = self.worker = None def _connectWorker(self, isConnect=True): ss = [ {"signal": self.thread.started, "slot": self.worker.run}, {"signal": self.worker.finished, "slot": self.finishedWorker}, {"signal": self.worker.messageResult, "slot": self.messageResultWorker}, {"signal": self.worker.messageStatus, "slot": self.messageStatusWorker}, ] if isConnect: for item in ss: item["signal"].connect(item["slot"]) else: for item in ss: item["signal"].disconnect(item["slot"]) def _connect(self, isConnect=True): ss = [ {"signal": self.legend.currentLayerChanged, "slot": self.selectLayer}, {"signal": QgsMapLayerRegistry.instance().layerWillBeRemoved, "slot": self.unselectLayer}, {"signal": self.canvas.extentsChanged, "slot": self.changeSensitiveLegend}, ] if isConnect: for item in ss: item["signal"].connect(item["slot"]) else: for item in ss: item["signal"].disconnect(item["slot"]) @pyqtSlot() def finishedWorker(self): self.thread.quit() if self.worker.isKilled: # When PAN/ZOOM/... self.thread.wait() self.changeSensitiveLegend() @pyqtSlot(str) def messageResultWorker(self, msg): self.printMsgBar(msg) @pyqtSlot(str) def messageStatusWorker(self, msg): self.printMsgBar(msg) @pyqtSlot("QgsMapLayer") def selectLayer(self, layer): if self.thread.isRunning(): return isOk = True msg = "" typeMsg = QgsMessageBar.WARNING if not layer is None and layer.type() == QgsMapLayer.RasterLayer: legendColorAll = layer.legendSymbologyItems() if len(legendColorAll) > 0: # Had a classification self.layer = layer self.worker.setLegendReadBlock(layer) msg = "Raster Layer '%s' actived" % layer.name() typeMsg = QgsMessageBar.INFO else: msg = "Raster Layer '%s' need be a classification" % layer.name() isOk = False else: if layer is None: msg = "Active a Raster layer" else: msg = "Layer '%s' need be a Raster" % layer.name() isOk = False self.printMsgBar(msg, typeMsg) return isOk @pyqtSlot(str) def unselectLayer(self, idLayer): if idLayer == self.layer.id(): if self.thread.isRunning(): self.worker.isKilled = True msg = "Raster Layer '%s' was removed" % self.layer.name() self.printMsgBar(msg, QgsMessageBar.WARNING) self.layer = None @pyqtSlot() def changeSensitiveLegend(self): if self.layer is None: return if self.thread.isRunning(): self.worker.isKilled = True return mapSettings = self.canvas.mapSettings() crsCanvas = mapSettings.destinationCrs() extentCanvas = self.canvas.extent() extentLayer = self.layer.extent() resX = self.layer.rasterUnitsPerPixelX() resY = self.layer.rasterUnitsPerPixelY() if self.layer.crs() != crsCanvas: extentCanvas = mapSettings.mapToLayerCoordinates(self.layer, extentCanvas) if not extentCanvas.intersects(extentLayer): self.printMsgBar("View not intersects Raster '%s'" % self.layer.name, QgsMessageBar.WARNING) return keysLegend = range(len(self.worker.legendAll)) # [ idClass1, idClass2, ... ] [ 0..N-1] if extentCanvas == extentLayer or extentCanvas.contains(extentLayer): legendsView = map(lambda x: "(%s)%s" % (x, self.worker.legendAll[x]), keysLegend) msg = "[%d] = %s" % (len(legendsView), " ".join(legendsView)) self.printMsgBar(msg) return extent = extentCanvas.intersect(extentLayer) widthRead = int(extent.width() / resX) + 1 heightRead = int(extent.height() / resY) + 1 self.worker.setProcessImage(extent, widthRead, heightRead) self.thread.start()
class NGWResourcesModelJob(QObject): started = pyqtSignal() statusChanged = pyqtSignal(unicode) warningOccurred = pyqtSignal(object) errorOccurred = pyqtSignal(object) finished = pyqtSignal() def __init__(self, parent, worker, model_response=None): """Create job. Arguments: job_id -- Job identification worker -- The class object inherits from NGWResourceModelJob """ QObject.__init__(self, parent) self.__result = None self.__worker = worker self.__job_id = self.__worker.id self.__error = None self.__warnings = [] # self.__job_id = "%s_%s" % (self.__worker.id, str(uuid.uuid1())) self.__worker.started.connect(self.started.emit) self.__worker.dataReceived.connect(self.__rememberResult) self.__worker.statusChanged.connect(self.statusChanged.emit) self.__worker.errorOccurred.connect(self.processJobError) self.__worker.warningOccurred.connect(self.processJobWarnings) self.model_response = model_response def setResponseObject(self, resp): self.model_response = resp self.model_response.job_id = self.__job_id def __rememberResult(self, result): self.__result = result def getJobId(self): return self.__job_id def getResult(self): return self.__result def error(self): return self.__error def processJobError(self, job_error): self.__error = job_error self.errorOccurred.emit(job_error) def processJobWarnings(self, job_error): if self.model_response: self.model_response._warnings.append(job_error) # self.warningOccurred.emit(job_error) def start(self): self.__thread = QThread(self) self.__worker.moveToThread(self.__thread) self.__worker.finished.connect(self.finishProcess) self.__thread.started.connect(self.__worker.run) self.__thread.start() def finishProcess(self): self.__worker.started.disconnect() self.__worker.dataReceived.disconnect() self.__worker.statusChanged.disconnect() self.__worker.errorOccurred.disconnect() self.__worker.warningOccurred.disconnect() self.__worker.finished.disconnect() self.__thread.quit() self.__thread.wait() self.finished.emit()
class AbstractBuildRunner(QObject): """ Base class to run a build. Create the required test runner and build manager, along with a thread that should be used for blocking tasks. """ running_state_changed = Signal(bool) worker_created = Signal(object) worker_class = None def __init__(self, mainwindow): QObject.__init__(self) self.mainwindow = mainwindow self.thread = None self.worker = None self.pending_threads = [] self.test_runner = None self.download_manager = None self.options = None self.stopped = False def init_worker(self, fetch_config, options): """ Create and initialize the worker. Should be subclassed to configure the worker, and should return the worker method that should start the work. """ self.options = options # global preferences global_prefs = get_prefs() self.global_prefs = global_prefs # apply the global prefs now apply_prefs(global_prefs) if fetch_config.is_nightly(): fetch_config.set_base_url(global_prefs['archive_base_url']) download_dir = global_prefs['persist'] if not download_dir: download_dir = self.mainwindow.persist persist_limit = int( abs(global_prefs['persist_size_limit']) * 1073741824) self.download_manager = GuiBuildDownloadManager( download_dir, persist_limit) self.test_runner = GuiTestRunner() self.thread = QThread() # options for the app launcher launcher_kwargs = {} for name in ('profile', 'preferences'): if name in options: value = options[name] if value: launcher_kwargs[name] = value # add add-ons paths to the app launcher launcher_kwargs['addons'] = options['addons'] self.test_runner.launcher_kwargs = launcher_kwargs if options['profile_persistence'] in ('clone-first', 'reuse') or options['profile']: launcher_kwargs['cmdargs'] = launcher_kwargs.get( 'cmdargs', []) + ['--allow-downgrade'] self.worker = self.worker_class(fetch_config, self.test_runner, self.download_manager) # Move self.bisector in the thread. This will # allow to the self.bisector slots (connected after the move) # to be automatically called in the thread. self.worker.moveToThread(self.thread) self.worker_created.emit(self.worker) def start(self, fetch_config, options): action = self.init_worker(fetch_config, options) assert callable(action), "%s should be callable" % action self.thread.start() # this will be called in the worker thread. QTimer.singleShot(0, action) self.stopped = False self.running_state_changed.emit(True) @Slot() def stop(self, wait=True): self.stopped = True if self.options: if self.options['profile'] and \ self.options['profile_persistence'] == 'clone-first': self.options['profile'].cleanup() if self.download_manager: self.download_manager.cancel() if self.thread: self.thread.quit() if wait: if self.download_manager: self.download_manager.wait(raise_if_error=False) if self.thread: # wait for thread(s) completion - this is the case when # user close the application self.thread.wait() for thread in self.pending_threads: thread.wait() self.thread = None elif self.thread: # do not block, just keep track of the thread - we got here # when user uses the stop button. self.pending_threads.append(self.thread) self.thread.finished.connect(self._remove_pending_thread) if self.test_runner: self.test_runner.finish(None) self.running_state_changed.emit(False) log('Stopped') @Slot() def _remove_pending_thread(self): for thread in self.pending_threads[:]: if thread.isFinished(): self.pending_threads.remove(thread)
class private_messages(iface_gui_plugin): VERSION_INITIAL = 0 VERSION_CURRENT = VERSION_INITIAL def __init__(self): super(private_messages, self).__init__() self.options = [((u"prev_messages", u"Number of previous messages to display"), 5), ((u"enable_markdown", u"Enable Markdown annotations", self._enableMarkdownChanged), False)] self.hidden_options = {u"ack_timeout" : 3, # seconds until message delivery is marked as timed out u"next_msgid" : -1} # next free message ID. -1 = not initialized self._storage = None def get_displayed_name(self): return u"Chat" def activate(self): iface_gui_plugin.activate(self) if lunchinator_has_gui(): self._sendMessageAction = _SendMessageAction() self._openChatAction = _OpenChatAction(self._sendMessageAction) self._peerActions = [self._openChatAction, _BlockAction(self._sendMessageAction), self._sendMessageAction] else: self._peerActions = None def create_widget(self, parent): from private_messages.chat_history_view import ChatHistoryWidget self._lock = loggingMutex("Private Messages", logging=get_settings().get_verbose()) from PyQt4.QtCore import QThread from private_messages.chat_messages_handler import ChatMessagesHandler if canUseBackgroundQThreads(): self._messagesThread = QThread() else: self._messagesThread = None self._messagesHandler = ChatMessagesHandler(self.logger, self, self.hidden_options[u"ack_timeout"], self.hidden_options[u"next_msgid"]) if self._messagesThread is not None: self._messagesHandler.moveToThread(self._messagesThread) self._messagesThread.start() self._messagesHandler.delayedDelivery.connect(self._delayedDelivery) self._messagesHandler.messageIDChanged.connect(self._messageIDChanged) self._messagesHandler.displayOwnMessage.connect(self._displayOwnMessage) self._messagesHandler.newMessage.connect(self._displayMessage) self._openChats = {} # mapping peer ID -> ChatDockWidget self._history = ChatHistoryWidget(self, parent, self.logger) return self._history def destroy_widget(self): for chatWindow in self._openChats.values(): chatWindow.close() self.set_hidden_option(u"next_msgid", self._messagesHandler.getNextMessageIDForStorage(), convert=False) self._messagesHandler.deactivate() if self._messagesThread is not None: self._messagesThread.quit() self._messagesThread.wait() self._messagesThread.deleteLater() self._messagesThread = None self._messagesHandler = None self._storage = None self._lock = None iface_gui_plugin.destroy_widget(self) def _enableMarkdownChanged(self, _setting, newVal): for chatWindow in self._openChats.values(): chatWindow.getChatWidget().setMarkdownEnabled(newVal) def extendsInfoDict(self): return lunchinator_has_gui() def extendInfoDict(self, infoDict): infoDict[u"PM_v"] = self.VERSION_CURRENT def get_peer_actions(self): return self._peerActions def process_event(self, cmd, value, _ip, peerInfo, _prep): if not cmd.startswith(u"HELO_PM"): return peerID = peerInfo[u"ID"] subcmd = cmd[7:] if subcmd == u"_ACK": self._messagesHandler.processAck(peerID, value) elif subcmd == u"_TYPING": if peerID in self._openChats: self._openChats[peerID].getChatWidget().otherIsTyping() elif subcmd == u"_CLEARED": if peerID in self._openChats: self._openChats[peerID].getChatWidget().otherCleared() elif subcmd == u"_ERROR": self._messagesHandler.processAck(peerID, value, error=True) elif subcmd == u"": self._messagesHandler.processMessage(peerID, value) def getStorage(self): if self._storage == None: with self._lock: if self._storage == None: from private_messages.chat_messages_storage import ChatMessagesStorage self._storage = ChatMessagesStorage(self.logger) return self._storage @loggingFunc def _displayOwnMessage(self, otherID, msgID, recvTime, msgHTML, msgTime, status, errorMsg): otherID = convert_string(otherID) msgHTML = convert_string(msgHTML) errorMsg = convert_string(errorMsg) if recvTime == -1: recvTime = None if not errorMsg: errorMsg = None if otherID in self._openChats: chatWindow = self._openChats[otherID] chatWindow.getChatWidget().addOwnMessage(msgID, recvTime, msgHTML, msgTime, status, errorMsg) def _activateChat(self, chatWindow, forceForeground=True): chatWindow.showNormal() if forceForeground: chatWindow.raise_() chatWindow.activateWindow() return chatWindow def _openChat(self, myName, otherName, myAvatar, otherAvatar, otherID): from private_messages.chat_window import ChatWindow newWindow = ChatWindow(None, self.logger, myName, otherName, myAvatar, otherAvatar, otherID, self._sendMessageAction) newWindow.getChatWidget().setMarkdownEnabled(self.get_option(u"enable_markdown")) newWindow.windowClosing.connect(self._chatClosed) newWindow.getChatWidget().sendMessage.connect(self._messagesHandler.sendMessage) newWindow.getChatWidget().typing.connect(partial(self._messagesHandler.sendTyping, otherID)) newWindow.getChatWidget().cleared.connect(partial(self._messagesHandler.sendCleared, otherID)) self._openChats[otherID] = newWindow prevMessages = self.getStorage().getPreviousMessages(otherID, self.get_option(u"prev_messages")) from private_messages.chat_messages_storage import ChatMessagesStorage for row in reversed(prevMessages): # partner, ID, own, time, status, text isOwnMessage = row[ChatMessagesStorage.MSG_IS_OWN_MESSAGE_COL] != 0 if isOwnMessage: newWindow.getChatWidget().addOwnMessage(row[ChatMessagesStorage.MSG_ID_COL], row[ChatMessagesStorage.MSG_RECV_TIME_COL], row[ChatMessagesStorage.MSG_TEXT_COL], row[ChatMessagesStorage.MSG_TIME_COL], row[ChatMessagesStorage.MSG_STATUS_COL]) else: newWindow.getChatWidget().addOtherMessage(row[ChatMessagesStorage.MSG_TEXT_COL], row[ChatMessagesStorage.MSG_TIME_COL], row[ChatMessagesStorage.MSG_RECV_TIME_COL]) return self._activateChat(newWindow) @loggingFunc def _chatClosed(self, pID): pID = convert_string(pID) if pID in self._openChats: chatWindow = self._openChats[pID] chatWindow.deleteLater() del self._openChats[pID] else: self.logger.error("Closed chat window was not maintained: %s", pID) def getOpenChatAction(self): return self._openChatAction def openChat(self, pID, forceForeground=True): pID = convert_string(pID) if pID in self._openChats: return self._activateChat(self._openChats[pID], forceForeground) otherName = get_peers().getDisplayedPeerName(pID=pID) if otherName == None: self.logger.error("Could not get info of chat partner %s", pID) return otherAvatar = get_peers().getPeerAvatarFile(pID=pID) myName = get_settings().get_user_name() myAvatar = get_peers().getPeerAvatarFile(pID=get_settings().get_ID()) return self._openChat(myName, otherName, myAvatar, otherAvatar, pID) @loggingFunc def _delayedDelivery(self, otherID, msgID, recvTime, error, errorMessage): otherID = convert_string(otherID) errorMessage = convert_string(errorMessage) if otherID in self._openChats: chatWindow = self._openChats[otherID] chatWindow.getChatWidget().delayedDelivery(msgID, recvTime, error, errorMessage) @loggingFunc def _messageIDChanged(self, otherID, oldID, newID): otherID = convert_string(otherID) if otherID in self._openChats: chatWindow = self._openChats[otherID] chatWindow.getChatWidget().messageIDChanged(oldID, newID) @loggingFunc def _displayMessage(self, otherID, msgHTML, msgTime, msgDict): try: recvTime = time() chatWindow = self.openChat(otherID, False) chatWindow.getChatWidget().addOtherMessage(msgHTML, msgTime, recvTime) self._messagesHandler.receivedSuccessfully(otherID, msgHTML, msgTime, msgDict, recvTime) except: excType, excValue, _tb = sys.exc_info() errorMsg = u"Error processing message (%s: %s)" % (unicode(excType.__name__), unicode(excValue)) self._messagesHandler.errorReceivingMessage(otherID, msgDict, errorMsg) if not chatWindow.isActiveWindow(): from PyQt4.QtGui import QTextDocument doc = QTextDocument() doc.setHtml(msgHTML) displayNotification(chatWindow.getChatWidget().getOtherName(), convert_string(doc.toPlainText()), self.logger, chatWindow.getChatWidget().getOtherIconPath())
class remote_pictures(iface_gui_plugin): VERSION_DB = 0 VERSION_CURRENT = VERSION_DB def __init__(self): super(remote_pictures, self).__init__() self.options = [((u"min_opacity", u"Minimum opacity of controls:", self._minOpacityChanged), 20), ((u"max_opacity", u"Maximum opacity of controls:", self._maxOpacityChanged), 80), ((u"thumbnail_size", u"Thumbnail Size:", self._thumbnailSizeChanged), 150), ((u"smooth_scaling", u"Smooth scaling", self._smoothScalingChanged), False), ((u"store_locally", u"Store pictures locally", self._storeLocallyChanged), True)] self._gui = None self._handler = None self._rpAction = None def _handleOpacity(self, newValue, signal): if newValue < 0: newValue = 0 elif newValue > 100: newValue = 100 if signal is not None: signal.emit(float(newValue) / 100.) return newValue def _minOpacityChanged(self, _setting, newValue): return self._handleOpacity(newValue, None if self._gui is None else self._gui.minOpacityChanged) def _maxOpacityChanged(self, _setting, newValue): return self._handleOpacity(newValue, None if self._gui is None else self._gui.maxOpacityChanged) def _thumbnailSizeChanged(self, _setting, newValue): from remote_pictures.remote_pictures_category_model import CategoriesModel if newValue < CategoriesModel.MIN_THUMBNAIL_SIZE: newValue = CategoriesModel.MIN_THUMBNAIL_SIZE elif newValue > CategoriesModel.MAX_THUMBNAIL_SIZE: newValue = CategoriesModel.MAX_THUMBNAIL_SIZE if self._gui is not None: self._gui.thumbnailSizeChanged(newValue) if self._handler is not None: self._handler.thumbnailSizeChanged(newValue) return newValue def _storeLocallyChanged(self, _setting, newValue): self._handler.storeLocallyChanged(newValue) return newValue def _smoothScalingChanged(self, _setting, newValue): if self._gui is not None: self._gui.setSmoothScaling(newValue) def create_widget(self, parent): from PyQt4.QtCore import QThread from remote_pictures.remote_pictures_gui import RemotePicturesGui from remote_pictures.remote_pictures_handler import RemotePicturesHandler super(remote_pictures, self).create_widget(parent) self._gui = RemotePicturesGui(parent, self.logger, self.get_option(u"smooth_scaling"), self.get_option(u"min_opacity"), self.get_option(u"max_opacity")) if canUseBackgroundQThreads(): self._messagesThread = QThread() else: self._messagesThread = None self._handler = RemotePicturesHandler(self.logger, self.get_option(u"thumbnail_size"), self.get_option(u"store_locally"), self._gui) if self._messagesThread is not None: self._handler.moveToThread(self._messagesThread) self._messagesThread.start() self._gui.openCategory.connect(self._handler.openCategory) self._gui.displayPrev.connect(self._handler.displayPrev) self._gui.displayNext.connect(self._handler.displayNext) self._gui.pictureDownloaded.connect(self._handler.pictureDownloaded) self._gui.setCategoryThumbnail.connect(self._handler.setCategoryThumbnail) self._handler.addCategory.connect(self._gui.categoryModel.addCategory) self._handler.categoryThumbnailChanged.connect(self._gui.categoryModel.categoryThumbnailChanged) self._handler.displayImageInGui.connect(self._gui.displayImage) self._gui.categoryModel.categoriesChanged.connect(self._privacySettingsChanged) self._handler.categoriesChanged.connect(self._privacySettingsChanged) self._handler.loadPictures() return self._gui def destroy_widget(self): if self._gui is not None and self._handler is not None: self._gui.openCategory.disconnect(self._handler.openCategory) self._gui.displayPrev.disconnect(self._handler.displayPrev) self._gui.displayNext.disconnect(self._handler.displayNext) self._gui.pictureDownloaded.disconnect(self._handler.pictureDownloaded) self._gui.setCategoryThumbnail.disconnect(self._handler.setCategoryThumbnail) self._handler.addCategory.disconnect(self._gui.categoryModel.addCategory) self._handler.categoryThumbnailChanged.disconnect(self._gui.categoryModel.categoryThumbnailChanged) self._handler.displayImageInGui.disconnect(self._gui.displayImage) if self._gui is not None: self._gui.categoryModel.categoriesChanged.disconnect(self._privacySettingsChanged) self._gui.destroyWidget() if self._handler is not None: self._handler.categoriesChanged.disconnect(self._privacySettingsChanged) self._handler.finish() if self._messagesThread is not None: self._messagesThread.quit() self._messagesThread.wait() self._messagesThread.deleteLater() iface_gui_plugin.destroy_widget(self) def extendsInfoDict(self): return lunchinator_has_gui() def extendInfoDict(self, infoDict): infoDict[u"RP_v"] = self.VERSION_CURRENT def get_peer_actions(self): if lunchinator_has_gui(): self._rpAction = _RemotePictureAction() return [self._rpAction] else: return None def checkCategory(self, cat): if self._handler is not None: self._handler.checkCategory(cat) def process_event(self, cmd, value, ip, _info, _prep): if cmd=="HELO_REMOTE_PIC": if self._handler is not None: self._handler.processRemotePicture(value, ip) def getCategories(self): if self._handler is None: self.logger.error("Remote Pictures not initialized") return [] return self._handler.getCategoryNames(alsoEmpty=True) def getCategoryIcon(self, category): if self._gui is None: self.logger.error("Remote Pictures not initialized") return None return self._gui.getCategoryIcon(category) def willIgnorePeerAction(self, category, url): return self._handler.willIgnorePeerAction(category, url) def sendRemotePicture(self, peerID, peerInfo, parent): from remote_pictures.remote_pictures_dialog import RemotePicturesDialog dialog = RemotePicturesDialog(parent, peerID, peerInfo) result = dialog.exec_() if result == RemotePicturesDialog.Accepted: data = [dialog.getURL().encode('utf-8')] if dialog.getDescription(): data.append(dialog.getDescription().encode('utf-8')) if dialog.getCategory(): data.append(dialog.getCategory().encode('utf-8')) with contextlib.closing(StringIO()) as strOut: writer = csv.writer(strOut, delimiter = ' ', quotechar = '"') writer.writerow(data) get_server().call("HELO_REMOTE_PIC " + strOut.getvalue(), peerIDs=[peerID]) @loggingFunc def _privacySettingsChanged(self): get_notification_center().emitPrivacySettingsChanged(self._rpAction.getPluginName(), self._rpAction.getName())
class Measurement(QObject): throwMessage = pyqtSignal(str, int, name='throwMessage') sigSaveMeasurement = pyqtSignal(bool, name='save') updateWindows=pyqtSignal(str,name="updateView") sigUpdateCountrate=pyqtSignal(int,str) sigTest=pyqtSignal() def __init__(self,openFile=None,themisApp=None): QObject.__init__(self) self.themisApp=themisApp self.configWidget=configurationWidget.configurationWidget(self) self.config=self.configWidget.p self.DataThread=QThread(self) self.dataHandler=DataHandler(self.configWidget.toDict()) self.dataHandler.moveToThread(self.DataThread) self.dataHandler.updateTimer.timeout.connect(self.dataHandler.updateGui) self.dataHandler.sigUpdateGui.connect(self.updateView,QtCore.Qt.QueuedConnection) self.configWidget.sigConfigChanged.connect(self.dataHandler.configChanged,QtCore.Qt.QueuedConnection) self.DataThread.start() self.viewer=DataViewer(name="Measurement") self.timeFilter=[None,None] self.acquisitionTime=-1 #SetWindows self.viewer.addWidget("Control",self.configWidget,position="left",Size=(2,2),minSize=(250,250),sizePolicy=(QtGui.QSizePolicy.Fixed,QtGui.QSizePolicy.Fixed)) self.timeImage=self.viewer.addWidget("Time Image",PlotBase.TimeImageWidget(self),position="right",relativeTo="Control",Size=(10,10),minSize=(300,250)) self.energyImage=self.viewer.addWidget("Energy Image",PlotBase.EnergyImageWidget(self),position="below",relativeTo="Time Image",Size=(10,10),minSize=(300,250)) self.countrate=self.viewer.addWidget("Countrate",PlotBase.CountrateWidget(),position="bottom",relativeTo="Time Image",Size=(10,10),minSize=(300,250)) self.keithley=self.viewer.addWidget("Keithley",PlotBase.KeithleyWidget(),position="below",relativeTo="Countrate",Size=(10,10),minSize=(300,250)) self.timeHistogram=self.viewer.addWidget("Time Histogram",PlotBase.TimeHistogramWidget(),position="right",relativeTo="Time Image",Size=(10,10),minSize=(300,250)) self.energyHistogram=self.viewer.addWidget("Energy Histogram",PlotBase.EnergyHistogramWidget(self),position="below",relativeTo="Time Histogram",Size=(10,10),minSize=(300,250)) if themisApp!=None: self.liveView=self.viewer.addWidget("MCP",PlotBase.LiveView(self),position="above",relativeTo="Time Image",Size=(10,10),minSize=(400,250)) self.viewer.addWidget("Themis",self.themisApp,position="above",relativeTo="Control",Size=(10,10),minSize=(250,250)) # Buttons=QtGui.QHBoxLayout() # self.start=QtGui.QPushButton("Start") # self.start.setIcon(QtGui.QIcon('Bilder/accept.png')) # #self.start.clicked.connect(self.startMeasurement) # Buttons.addWidget(self.start) # self.pause=QtGui.QPushButton("Pause") # self.pause.setIcon(QtGui.QIcon('Bilder/pause.png')) # #self.pause.clicked.connect(self.pauseMeasurement) # Buttons.addWidget(self.pause) # self.stop=QtGui.QPushButton("Stop") # self.stop.setIcon(QtGui.QIcon('Bilder/stop.png')) # #self.stop.clicked.connect(self.on_stop_clicked) # Buttons.addWidget(self.stop) # #self.configWidget.layout().insertWidget(0,Buttons) else: self.liveView=None #None#self.viewer.addWidget("MCP",PlotBase.LiveView(),position="above",relativeTo="Time Image",Size=(10,10),minSize=(400,250)) if not openFile==None: self.loadMeasurement(openFile) self.initializeSignals() def finalize(self): self.dataHandler.finalize() self.dataHandler.deleteLater() del self.dataHandler self.DataThread.quit() self.DataThread.wait() #self.dataHandler.updateTimer.timeout.disconnect(self.dataHandler.updateGui) #self.dataHandler.sigUpdateGui.disconnect(self.updateView) #self.configWidget.sigConfigChanged.disconnect(self.dataHandler.configChanged,) #self.dataHandler.deleteLater() def initializeSignals(self): self.configWidget.connectSignal(self.config.param("Spectra","Time Histogram","Time min").sigValueChanged,self.timeConfigChanged) self.configWidget.connectSignal(self.config.param("Spectra","Time Histogram","Time max").sigValueChanged,self.timeConfigChanged) self.configWidget.connectSignal(self.config.param("Spectra","Time Histogram","Time resolution").sigValueChanged,self.timeConfigChanged) self.configWidget.connectSignal(self.config.param("Spectra","Time Image","Xbins").sigValueChanged,self.timeConfigChanged) self.configWidget.connectSignal(self.config.param("Spectra","Time Image","Ybins").sigValueChanged,self.timeConfigChanged) self.configWidget.connectSignal(self.config.param("Spectra","Rotate MCP").sigValueChanged,self.dataHandler.rotationChanged) self.configWidget.connectSignal(self.config.param("DLLParams","X Min").sigValueChanged,self.timeConfigChanged) self.configWidget.connectSignal(self.config.param("DLLParams","X Max").sigValueChanged,self.timeConfigChanged) self.configWidget.connectSignal(self.config.param("DLLParams","Y Min").sigValueChanged,self.timeConfigChanged) self.configWidget.connectSignal(self.config.param("DLLParams","Y Max").sigValueChanged,self.timeConfigChanged) self.configWidget.connectSignal(self.config.param('File Configuration', 'Save Measurement').sigActivated,self.saveMeasurement) self.configWidget.connectSignal(self.config.param('Spectra', 'Create new Conversion').sigActivated,self.createStandardConversion) self.sigSaveMeasurement.connect(self.saveMeasurement) self.timeHistogram.selectionChanged.connect(self.selectionChanged) def selectionChanged(self,min,max): with self.dataHandler: self.dataHandler.dataSet.timeImage.fill(0) electrons=self.dataHandler.dataSet.getElectronsFromRawData() if min==-999999999: timeFilter=(None,None) else: timeFilter=(self.dataHandler.dataSet.unitsToRawData(min,"T"),self.dataHandler.dataSet.unitsToRawData(max,"T")) if not timeFilter[0]==None and not timeFilter[1]==None: electrons = electrons[np.logical_and(electrons["time"] > timeFilter[0], electrons["time"] < timeFilter[1])] elif not timeFilter[0]==None: electrons = electrons[electrons["time"] > timeFilter[0]] elif not timeFilter[1]==None: electrons = electrons[electrons["time"] < timeFilter[1]] self.dataHandler.dataSet.setElectrons(electrons=electrons,spectrum="timeImage") self.updateView({"timeImage":np.copy(self.dataHandler.dataSet.timeImage)}) def timeConfigChanged(self): with self.dataHandler: if not self.dataHandler.dataSet.rawData==None: self.dataHandler.dataSet.setTimeRange() self.dataHandler.dataSet.setTimeImageRange() electrons=self.dataHandler.dataSet.getElectronsFromRawData() self.dataHandler.dataSet.setElectrons(electrons=electrons,spectrum=["timeHistogram","timeImage"]) self.dataHandler.dataTransfer(["timeHistogram","timeImage"]) else: self.dataHandler.dataSet.initialize() self.dataHandler.sigUpdateRequest.emit(["all"]) def updateView(self, data=None): if data==None: self.dataHandler.sigUpdateRequest.emit("all") return if "timeHistogram" in data: self.timeHistogram.updateData(data["timeHistogram"][0],data["timeHistogram"][1]) if "energyHistogram" in data: self.energyHistogram.updateData(data["energyHistogram"][0],data["energyHistogram"][1]) if "timeImage" in data: self.timeImage.updateData(data["timeImage"]) if "energyImage" in data: self.energyImage.updateData(data["energyImage"]) if "countrate" in data: self.countrate.updateData(data["countrate"][0],data["countrate"][1]) if "keithley" in data: self.keithley.updateData(data["keithley"][0],data["keithley"][1]) if "liveView" in data: if self.liveView!=None: self.liveView.updateData(data["liveView"][0]) self.liveView.countrate.setValue(data["liveView"][1]) self.liveView.selection.setValue(data["liveView"][2]) def setDLDParameter(self,factors,offsets,pxLimits): #set from dld self.configWidget.setDLLParams(factors=factors,offsets=offsets,pxLimits=pxLimits) def createConversion(self,dialog=False,recommended=False): conversion=EnergyConversion.ConversionItem(self.dataHandler.dataSet,self.configWidget) with self.dataHandler: if not self.dataHandler.dataSet.rawData==None: conversion.control.state.getEventData()._data=self.dataHandler.dataSet.getElectronsFromRawData() if dialog: newconversion=conversion.startConversionDialog() else: self.throwMessage.emit("Create ConversionSplines",2) newconversion=conversion.createStandardConversion(recommended=recommended) self.throwMessage.emit("--> Finished",4) if newconversion==None: return self.configWidget.setEnergyParams(newconversion.factors,newconversion.offsets) with self.dataHandler: self.dataHandler.dataSet.conversion=conversion self.dataHandler.dataSet.energyHistogram=np.sum(np.sum(newconversion.getDataContent(),0),0) self.dataHandler.dataSet.energyImage=np.sum(newconversion.getDataContent(),2) self.dataHandler.dataSet.setEnergyRange() self.energyImage.setExtent() self.dataHandler.sigUpdateRequest.emit(["energyHistogram","energyImage"]) def startConversionDialog(self): self.createConversion(dialog=True) def createStandardConversion(self): self.createConversion() def clearSpectra(self,rawData=True): QtCore.QMetaObject.invokeMethod(self.dataHandler,"clearSpectra",QtCore.Qt.QueuedConnection,QtCore.Q_ARG(bool,True)) # with self.dataHandler: # # self.dataHandler.dataSet.clearSpectra() # self.dataHandler.electrons=np.empty(0, [("x", 'i2'), ("y", 'i2'), ("time", 'i4')]) # if rawData: # self.dataHandler.closeRawData() # self.dataHandler.sigUpdateRequest.emit(["all"]) def saveMeasurement(self,confirm=True,autoOverride=False): path=self.config["File Configuration","Folder"] if path=="Default": path=fileaccess.createDefaultPath(self.config["File Configuration","Folder","Beamtime"],self.config["File Configuration","Folder","Groupname"]) else: path=self.config["File Configuration","Folder","Custom Folder"] if not fileaccess.checkIfPathExist(path): self.throwMessage.emit("--> Could not create the desired Path",0) self.throwMessage.emit("--> Measurement was not Saved",2) return False filename=self.config["File Configuration","Filename"] if self.themisApp!=None: filename=filename.replace("%n",("%03d"% self.themisApp.parent.joblist.measurementNumber.value())) self.themisApp.parent.joblist.measurementNumber.setValue(self.themisApp.parent.joblist.measurementNumber.value()+1) file=path+"/"+filename+".lv" if not autoOverride: if fileaccess.checkIfFileExists(file): file=fileaccess.fileOverwriteDialog(file,path) if file==None: self.throwMessage.emit("--> Measurement was not Saved",2) return False self.throwMessage.emit("Save Measurement as: "+file,2) file=file.replace("/","\\") with self.dataHandler: if not self.dataHandler.dataSet.rawData==None and self.dataHandler.dataSet.rawData.filename.replace("/","\\")==file.replace("/","\\"): file=file+"_temporay_while_edited" h5file = fileaccess.openFile(file, mode = "w", title = "Measurement") ##! Adjust and Save Config config=self.config.saveState() config["children"]["File Configuration"]["children"]["Folder"]["children"]["Custom Folder"]["value"]=path config["children"]["File Configuration"]["children"]["Folder"]["value"]="Custom" config["children"]["File Configuration"]["children"]["Filename"]["value"]=filename if config["children"]["Measurement Info"]["children"]["End of Acquisition"]["value"]=="not yet finished": config["children"]["Measurement Info"]["children"]["End of Acquisition"]["value"]=datetime.datetime.now().strftime("%Y-%m-%d, %H:%M:%S") h5file.root._v_attrs.config=str(config) self.dataHandler.dataSet.saveDataSet(h5file) h5file.flush() if "_temporay_while_edited" in file: self.dataHandler.dataSet.rawData.close() _cwd=os.getcwd() os.chdir(path) name=file.split("\\")[-1] os.remove(file[0:-22]) h5file.close() os.rename(name,name[0:-22]) self.dataHandler.dataSet.rawData=fileaccess.openFile(file[0:-22], mode = "a") self.dataHandler.dataSet.events=self.dataHandler.dataSet.rawData.getNode("/rawData/", "events") else: h5file.close() if self.config["File Configuration","Copy to Grouphome"]: grouphome=path.replace("C:/","Z:/") if grouphome==path: return try: fileaccess.checkIfPathExist(grouphome,create=True) shutil.copy(file,grouphome) except(WindowsError): self.throwMessage.emit("Error: Could not connect to Grouphome",2) if confirm: msgBox=QtGui.QMessageBox(self.viewer) msgBox.setWindowTitle("Measurement Saved") msgBox.setText("Measurement has been saved to:") msgBox.setInformativeText(file) msgBox.exec_() @staticmethod def loadMeasurement(file,mode="r"): measurement=Measurement() measurement.load(file,mode=mode) return(measurement) def load(self,file,mode="r"): self.viewer.setWindowTitle("Data Viewer - "+ file) if not fileaccess.checkIfFileExists(file): self.throwMessage.emit("Load Error: File "+file+" not found",0) return h5file = fileaccess.openFile(file, mode = mode) h5file =self.configWidget.restoreState(h5file,file=file) with self.dataHandler: self.dataHandler.dataSet.config=self.configWidget.toDict() self.dataHandler.dataSet.loadDataSet(h5file) self.timeImage.setExtent() self.energyImage.setExtent() self.dataHandler.sigUpdateRequest.emit(["all"]) def show(self): self.viewer.show()
class Measurement(QObject): throwMessage = pyqtSignal(str, int, name='throwMessage') sigSaveMeasurement = pyqtSignal(bool, name='save') updateWindows = pyqtSignal(str, name="updateView") sigUpdateCountrate = pyqtSignal(int, str) sigTest = pyqtSignal() def __init__(self, openFile=None, themisApp=None): QObject.__init__(self) self.themisApp = themisApp self.configWidget = configurationWidget.configurationWidget(self) self.config = self.configWidget.p self.DataThread = QThread(self) self.dataHandler = DataHandler(self.configWidget.toDict()) self.dataHandler.moveToThread(self.DataThread) self.dataHandler.updateTimer.timeout.connect( self.dataHandler.updateGui) self.dataHandler.sigUpdateGui.connect(self.updateView, QtCore.Qt.QueuedConnection) self.configWidget.sigConfigChanged.connect( self.dataHandler.configChanged, QtCore.Qt.QueuedConnection) self.DataThread.start() self.viewer = DataViewer(name="Measurement") self.timeFilter = [None, None] self.acquisitionTime = -1 #SetWindows self.viewer.addWidget("Control", self.configWidget, position="left", Size=(2, 2), minSize=(250, 250), sizePolicy=(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)) self.timeImage = self.viewer.addWidget("Time Image", PlotBase.TimeImageWidget(self), position="right", relativeTo="Control", Size=(10, 10), minSize=(300, 250)) self.energyImage = self.viewer.addWidget( "Energy Image", PlotBase.EnergyImageWidget(self), position="below", relativeTo="Time Image", Size=(10, 10), minSize=(300, 250)) self.countrate = self.viewer.addWidget("Countrate", PlotBase.CountrateWidget(), position="bottom", relativeTo="Time Image", Size=(10, 10), minSize=(300, 250)) self.keithley = self.viewer.addWidget("Keithley", PlotBase.KeithleyWidget(), position="below", relativeTo="Countrate", Size=(10, 10), minSize=(300, 250)) self.timeHistogram = self.viewer.addWidget( "Time Histogram", PlotBase.TimeHistogramWidget(), position="right", relativeTo="Time Image", Size=(10, 10), minSize=(300, 250)) self.energyHistogram = self.viewer.addWidget( "Energy Histogram", PlotBase.EnergyHistogramWidget(self), position="below", relativeTo="Time Histogram", Size=(10, 10), minSize=(300, 250)) if themisApp != None: self.liveView = self.viewer.addWidget("MCP", PlotBase.LiveView(self), position="above", relativeTo="Time Image", Size=(10, 10), minSize=(400, 250)) self.viewer.addWidget("Themis", self.themisApp, position="above", relativeTo="Control", Size=(10, 10), minSize=(250, 250)) # Buttons=QtGui.QHBoxLayout() # self.start=QtGui.QPushButton("Start") # self.start.setIcon(QtGui.QIcon('Bilder/accept.png')) # #self.start.clicked.connect(self.startMeasurement) # Buttons.addWidget(self.start) # self.pause=QtGui.QPushButton("Pause") # self.pause.setIcon(QtGui.QIcon('Bilder/pause.png')) # #self.pause.clicked.connect(self.pauseMeasurement) # Buttons.addWidget(self.pause) # self.stop=QtGui.QPushButton("Stop") # self.stop.setIcon(QtGui.QIcon('Bilder/stop.png')) # #self.stop.clicked.connect(self.on_stop_clicked) # Buttons.addWidget(self.stop) # #self.configWidget.layout().insertWidget(0,Buttons) else: self.liveView = None #None#self.viewer.addWidget("MCP",PlotBase.LiveView(),position="above",relativeTo="Time Image",Size=(10,10),minSize=(400,250)) if not openFile == None: self.loadMeasurement(openFile) self.initializeSignals() def finalize(self): self.dataHandler.finalize() self.dataHandler.deleteLater() del self.dataHandler self.DataThread.quit() self.DataThread.wait() #self.dataHandler.updateTimer.timeout.disconnect(self.dataHandler.updateGui) #self.dataHandler.sigUpdateGui.disconnect(self.updateView) #self.configWidget.sigConfigChanged.disconnect(self.dataHandler.configChanged,) #self.dataHandler.deleteLater() def initializeSignals(self): self.configWidget.connectSignal( self.config.param("Spectra", "Time Histogram", "Time min").sigValueChanged, self.timeConfigChanged) self.configWidget.connectSignal( self.config.param("Spectra", "Time Histogram", "Time max").sigValueChanged, self.timeConfigChanged) self.configWidget.connectSignal( self.config.param("Spectra", "Time Histogram", "Time resolution").sigValueChanged, self.timeConfigChanged) self.configWidget.connectSignal( self.config.param("Spectra", "Time Image", "Xbins").sigValueChanged, self.timeConfigChanged) self.configWidget.connectSignal( self.config.param("Spectra", "Time Image", "Ybins").sigValueChanged, self.timeConfigChanged) self.configWidget.connectSignal( self.config.param("Spectra", "Rotate MCP").sigValueChanged, self.dataHandler.rotationChanged) self.configWidget.connectSignal( self.config.param("DLLParams", "X Min").sigValueChanged, self.timeConfigChanged) self.configWidget.connectSignal( self.config.param("DLLParams", "X Max").sigValueChanged, self.timeConfigChanged) self.configWidget.connectSignal( self.config.param("DLLParams", "Y Min").sigValueChanged, self.timeConfigChanged) self.configWidget.connectSignal( self.config.param("DLLParams", "Y Max").sigValueChanged, self.timeConfigChanged) self.configWidget.connectSignal( self.config.param('File Configuration', 'Save Measurement').sigActivated, self.saveMeasurement) self.configWidget.connectSignal( self.config.param('Spectra', 'Create new Conversion').sigActivated, self.createStandardConversion) self.sigSaveMeasurement.connect(self.saveMeasurement) self.timeHistogram.selectionChanged.connect(self.selectionChanged) def selectionChanged(self, min, max): with self.dataHandler: self.dataHandler.dataSet.timeImage.fill(0) electrons = self.dataHandler.dataSet.getElectronsFromRawData() if min == -999999999: timeFilter = (None, None) else: timeFilter = (self.dataHandler.dataSet.unitsToRawData( min, "T"), self.dataHandler.dataSet.unitsToRawData(max, "T")) if not timeFilter[0] == None and not timeFilter[1] == None: electrons = electrons[np.logical_and( electrons["time"] > timeFilter[0], electrons["time"] < timeFilter[1])] elif not timeFilter[0] == None: electrons = electrons[electrons["time"] > timeFilter[0]] elif not timeFilter[1] == None: electrons = electrons[electrons["time"] < timeFilter[1]] self.dataHandler.dataSet.setElectrons(electrons=electrons, spectrum="timeImage") self.updateView( {"timeImage": np.copy(self.dataHandler.dataSet.timeImage)}) def timeConfigChanged(self): with self.dataHandler: if not self.dataHandler.dataSet.rawData == None: self.dataHandler.dataSet.setTimeRange() self.dataHandler.dataSet.setTimeImageRange() electrons = self.dataHandler.dataSet.getElectronsFromRawData() self.dataHandler.dataSet.setElectrons( electrons=electrons, spectrum=["timeHistogram", "timeImage"]) self.dataHandler.dataTransfer(["timeHistogram", "timeImage"]) else: self.dataHandler.dataSet.initialize() self.dataHandler.sigUpdateRequest.emit(["all"]) def updateView(self, data=None): if data == None: self.dataHandler.sigUpdateRequest.emit("all") return if "timeHistogram" in data: self.timeHistogram.updateData(data["timeHistogram"][0], data["timeHistogram"][1]) if "energyHistogram" in data: self.energyHistogram.updateData(data["energyHistogram"][0], data["energyHistogram"][1]) if "timeImage" in data: self.timeImage.updateData(data["timeImage"]) if "energyImage" in data: self.energyImage.updateData(data["energyImage"]) if "countrate" in data: self.countrate.updateData(data["countrate"][0], data["countrate"][1]) if "keithley" in data: self.keithley.updateData(data["keithley"][0], data["keithley"][1]) if "liveView" in data: if self.liveView != None: self.liveView.updateData(data["liveView"][0]) self.liveView.countrate.setValue(data["liveView"][1]) self.liveView.selection.setValue(data["liveView"][2]) def setDLDParameter(self, factors, offsets, pxLimits): #set from dld self.configWidget.setDLLParams(factors=factors, offsets=offsets, pxLimits=pxLimits) def createConversion(self, dialog=False, recommended=False): conversion = EnergyConversion.ConversionItem(self.dataHandler.dataSet, self.configWidget) with self.dataHandler: if not self.dataHandler.dataSet.rawData == None: conversion.control.state.getEventData( )._data = self.dataHandler.dataSet.getElectronsFromRawData() if dialog: newconversion = conversion.startConversionDialog() else: self.throwMessage.emit("Create ConversionSplines", 2) newconversion = conversion.createStandardConversion( recommended=recommended) self.throwMessage.emit("--> Finished", 4) if newconversion == None: return self.configWidget.setEnergyParams(newconversion.factors, newconversion.offsets) with self.dataHandler: self.dataHandler.dataSet.conversion = conversion self.dataHandler.dataSet.energyHistogram = np.sum( np.sum(newconversion.getDataContent(), 0), 0) self.dataHandler.dataSet.energyImage = np.sum( newconversion.getDataContent(), 2) self.dataHandler.dataSet.setEnergyRange() self.energyImage.setExtent() self.dataHandler.sigUpdateRequest.emit( ["energyHistogram", "energyImage"]) def startConversionDialog(self): self.createConversion(dialog=True) def createStandardConversion(self): self.createConversion() def clearSpectra(self, rawData=True): QtCore.QMetaObject.invokeMethod(self.dataHandler, "clearSpectra", QtCore.Qt.QueuedConnection, QtCore.Q_ARG(bool, True)) # with self.dataHandler: # # self.dataHandler.dataSet.clearSpectra() # self.dataHandler.electrons=np.empty(0, [("x", 'i2'), ("y", 'i2'), ("time", 'i4')]) # if rawData: # self.dataHandler.closeRawData() # self.dataHandler.sigUpdateRequest.emit(["all"]) def saveMeasurement(self, confirm=True, autoOverride=False): path = self.config["File Configuration", "Folder"] if path == "Default": path = fileaccess.createDefaultPath( self.config["File Configuration", "Folder", "Beamtime"], self.config["File Configuration", "Folder", "Groupname"]) else: path = self.config["File Configuration", "Folder", "Custom Folder"] if not fileaccess.checkIfPathExist(path): self.throwMessage.emit("--> Could not create the desired Path", 0) self.throwMessage.emit("--> Measurement was not Saved", 2) return False filename = self.config["File Configuration", "Filename"] if self.themisApp != None: filename = filename.replace( "%n", ("%03d" % self.themisApp.parent.joblist.measurementNumber.value())) self.themisApp.parent.joblist.measurementNumber.setValue( self.themisApp.parent.joblist.measurementNumber.value() + 1) file = path + "/" + filename + ".lv" if not autoOverride: if fileaccess.checkIfFileExists(file): file = fileaccess.fileOverwriteDialog(file, path) if file == None: self.throwMessage.emit("--> Measurement was not Saved", 2) return False self.throwMessage.emit("Save Measurement as: " + file, 2) file = file.replace("/", "\\") with self.dataHandler: if not self.dataHandler.dataSet.rawData == None and self.dataHandler.dataSet.rawData.filename.replace( "/", "\\") == file.replace("/", "\\"): file = file + "_temporay_while_edited" h5file = fileaccess.openFile(file, mode="w", title="Measurement") ##! Adjust and Save Config config = self.config.saveState() config["children"]["File Configuration"]["children"]["Folder"][ "children"]["Custom Folder"]["value"] = path config["children"]["File Configuration"]["children"]["Folder"][ "value"] = "Custom" config["children"]["File Configuration"]["children"]["Filename"][ "value"] = filename if config["children"]["Measurement Info"]["children"][ "End of Acquisition"]["value"] == "not yet finished": config["children"]["Measurement Info"]["children"][ "End of Acquisition"]["value"] = datetime.datetime.now( ).strftime("%Y-%m-%d, %H:%M:%S") h5file.root._v_attrs.config = str(config) self.dataHandler.dataSet.saveDataSet(h5file) h5file.flush() if "_temporay_while_edited" in file: self.dataHandler.dataSet.rawData.close() _cwd = os.getcwd() os.chdir(path) name = file.split("\\")[-1] os.remove(file[0:-22]) h5file.close() os.rename(name, name[0:-22]) self.dataHandler.dataSet.rawData = fileaccess.openFile( file[0:-22], mode="a") self.dataHandler.dataSet.events = self.dataHandler.dataSet.rawData.getNode( "/rawData/", "events") else: h5file.close() if self.config["File Configuration", "Copy to Grouphome"]: grouphome = path.replace("C:/", "Z:/") if grouphome == path: return try: fileaccess.checkIfPathExist(grouphome, create=True) shutil.copy(file, grouphome) except (WindowsError): self.throwMessage.emit( "Error: Could not connect to Grouphome", 2) if confirm: msgBox = QtGui.QMessageBox(self.viewer) msgBox.setWindowTitle("Measurement Saved") msgBox.setText("Measurement has been saved to:") msgBox.setInformativeText(file) msgBox.exec_() @staticmethod def loadMeasurement(file, mode="r"): measurement = Measurement() measurement.load(file, mode=mode) return (measurement) def load(self, file, mode="r"): self.viewer.setWindowTitle("Data Viewer - " + file) if not fileaccess.checkIfFileExists(file): self.throwMessage.emit("Load Error: File " + file + " not found", 0) return h5file = fileaccess.openFile(file, mode=mode) h5file = self.configWidget.restoreState(h5file, file=file) with self.dataHandler: self.dataHandler.dataSet.config = self.configWidget.toDict() self.dataHandler.dataSet.loadDataSet(h5file) self.timeImage.setExtent() self.energyImage.setExtent() self.dataHandler.sigUpdateRequest.emit(["all"]) def show(self): self.viewer.show()
class AbstractBuildRunner(QObject): """ Base class to run a build. Create the required test runner and build manager, along with a thread that should be used for blocking tasks. """ running_state_changed = Signal(bool) worker_created = Signal(object) worker_class = None def __init__(self, mainwindow): QObject.__init__(self) self.mainwindow = mainwindow self.thread = None self.worker = None self.pending_threads = [] self.test_runner = None self.download_manager = None self.options = None self.stopped = False def init_worker(self, fetch_config, options): """ Create and initialize the worker. Should be subclassed to configure the worker, and should return the worker method that should start the work. """ self.options = options # global preferences global_prefs = get_prefs() self.global_prefs = global_prefs # apply the global prefs now apply_prefs(global_prefs) download_dir = global_prefs['persist'] if not download_dir: download_dir = self.mainwindow.persist persist_limit = int(abs(global_prefs['persist_size_limit']) * 1073741824) self.download_manager = GuiBuildDownloadManager(download_dir, persist_limit) self.test_runner = GuiTestRunner() self.thread = QThread() # options for the app launcher launcher_kwargs = {} for name in ('profile', 'preferences'): if name in options: value = options[name] if value: launcher_kwargs[name] = value # add add-ons paths to the app launcher launcher_kwargs['addons'] = options['addons'] self.test_runner.launcher_kwargs = launcher_kwargs self.worker = self.worker_class(fetch_config, self.test_runner, self.download_manager) # Move self.bisector in the thread. This will # allow to the self.bisector slots (connected after the move) # to be automatically called in the thread. self.worker.moveToThread(self.thread) self.worker_created.emit(self.worker) def start(self, fetch_config, options): action = self.init_worker(fetch_config, options) assert callable(action), "%s should be callable" % action self.thread.start() # this will be called in the worker thread. QTimer.singleShot(0, action) self.stopped = False self.running_state_changed.emit(True) @Slot() def stop(self, wait=True): self.stopped = True if self.options: if self.options['profile'] and \ self.options['profile_persistence'] == 'clone-first': self.options['profile'].cleanup() if self.download_manager: self.download_manager.cancel() if self.thread: self.thread.quit() if wait: if self.download_manager: self.download_manager.wait(raise_if_error=False) if self.thread: # wait for thread(s) completion - this is the case when # user close the application self.thread.wait() for thread in self.pending_threads: thread.wait() self.thread = None elif self.thread: # do not block, just keep track of the thread - we got here # when user uses the stop button. self.pending_threads.append(self.thread) self.thread.finished.connect(self._remove_pending_thread) if self.test_runner: self.test_runner.finish(None) self.running_state_changed.emit(False) log('Stopped') @Slot() def _remove_pending_thread(self): for thread in self.pending_threads[:]: if thread.isFinished(): self.pending_threads.remove(thread)
class XdkWindow(QMainWindow): """ """ loadFileRequested = Signal(str) def __init__(self, parent=None): super(XdkWindow, self).__init__(parent) # load the user interface projexui.loadUi(__file__, self) # define custom properties self._currentContentsIndex = -1 self._worker = XdkWorker() self._workerThread = QThread() self._worker.moveToThread(self._workerThread) self._workerThread.start() # set default properties self.setAcceptDrops(True) self.setAttribute(Qt.WA_DeleteOnClose) self.uiFindNextBTN.setDefaultAction(self.uiFindNextACT) self.uiFindPrevBTN.setDefaultAction(self.uiFindPrevACT) self.uiFindWIDGET.setVisible(False) self.uiSearchWEB.page().setLinkDelegationPolicy( QWebPage.DelegateAllLinks) self.refreshUi() # connect widgets self.uiContentsTAB.currentChanged.connect(self.refreshUi) self.uiContentsTAB.tabCloseRequested.connect(self.closeContentsWidget) self.uiContentsTREE.itemExpanded.connect(self.loadItem) self.uiContentsTREE.itemSelectionChanged.connect(self.refreshContents) self.uiSearchTXT.returnPressed.connect(self.search) self.uiSearchWEB.linkClicked.connect(self.gotoUrl) self.uiIndexTREE.itemSelectionChanged.connect(self.refreshFromIndex) # connect find actions self.uiBackACT.triggered.connect(self.goBack) self.uiForwardACT.triggered.connect(self.goForward) self.uiHomeACT.triggered.connect(self.goHome) self.uiFindTXT.textChanged.connect(self.findNext) self.uiFindTXT.returnPressed.connect(self.findNext) self.uiFindNextACT.triggered.connect(self.findNext) self.uiFindPrevACT.triggered.connect(self.findPrev) self.uiFindACT.triggered.connect(self.showFind) self.uiFindCloseBTN.clicked.connect(self.uiFindWIDGET.hide) self.uiCopyTextACT.triggered.connect(self.copyText) # connect zoom actions self.uiZoomResetACT.triggered.connect(self.zoomReset) self.uiZoomInACT.triggered.connect(self.zoomIn) self.uiZoomOutACT.triggered.connect(self.zoomOut) # connect file actions self.uiLoadACT.triggered.connect(self.loadFilename) self.uiNewTabACT.triggered.connect(self.addContentsWidget) self.uiCloseTabACT.triggered.connect(self.closeContentsWidget) self.uiQuitACT.triggered.connect(self.close) # connect the signals self.loadFileRequested.connect(self._worker.loadFile) self._worker.loadingFinished.connect(self.__addXdkItem) QApplication.instance().aboutToQuit.connect(self.__cleanupWorker) def __del__(self): self.__cleanupWorker() def __addXdkItem(self, filename): item = XdkItem(filename) # add the xdk content item self.uiContentsTREE.addTopLevelItem(item) # add the index list items self.uiIndexTREE.blockSignals(True) self.uiIndexTREE.setUpdatesEnabled(False) for name, url in item.indexlist(): item = XTreeWidgetItem([name]) item.setToolTip(0, url) item.setFixedHeight(22) self.uiIndexTREE.addTopLevelItem(item) self.uiIndexTREE.blockSignals(False) self.uiIndexTREE.setUpdatesEnabled(True) self.uiIndexTREE.sortByColumn(0, Qt.AscendingOrder) self.unsetCursor() def __cleanupWorker(self): if self._workerThread is None: return self._workerThread.quit() self._workerThread.wait() self._worker.deleteLater() self._workerThread.deleteLater() self._worker = None self._workerThread = None def __gotoUrl(self, url): if url.toLocalFile(): self.gotoUrl(url.toString()) else: webbrowser.open(str(url.toString())) def addContentsWidget(self): """ Adds a new contents widget tab into the contents tab. :return <QWebView> """ curr_widget = self.currentContentsWidget() widget = QWebView(self) page = widget.page() page.setLinkDelegationPolicy(page.DelegateAllLinks) self.uiContentsTAB.blockSignals(True) self.uiContentsTAB.addTab(widget, 'Documentation') self.uiContentsTAB.setCurrentIndex(self.uiContentsTAB.count() - 1) self.uiContentsTAB.blockSignals(False) self._currentContentsIndex = self.uiContentsTAB.count() - 1 if curr_widget: widget.setUrl(curr_widget.url()) widget.titleChanged.connect(self.refreshUi) widget.linkClicked.connect(self.__gotoUrl) return widget def closeContentsWidget(self): """ Closes the current contents widget. """ widget = self.currentContentsWidget() if (not widget): return widget.close() widget.setParent(None) widget.deleteLater() def copyText(self): """ Copies the selected text to the clipboard. """ view = self.currentWebView() QApplication.clipboard().setText(view.page().selectedText()) def currentContentsIndex(self): """ Returns the last index used for the contents widgets. :return <int> """ return self._currentContentsIndex def currentContentsWidget(self, autoadd=False): """ Returns the current contents widget based on the cached index. If \ no widget is specified and autoadd is True, then a new widget will \ be added to the tab. :param autoadd | <bool> :return <QWebView> """ widget = self.uiContentsTAB.widget(self.currentContentsIndex()) if (not isinstance(widget, QWebView)): widget = None if (not widget and autoadd): widget = self.addContentsWidget() return widget def currentWebView(self): return self.uiContentsTAB.currentWidget() def dragEnterEvent(self, event): if event.mimeData().hasUrls(): event.accept() def dragMoveEvent(self, event): if event.mimeData().hasUrls(): event.accept() def dropEvent(self, event): if event.mimeData().hasUrls(): for url in event.mimeData().urls(): self.loadFilename(str(url.toLocalFile())) def findNext(self): """ Looks for the previous occurance of the current search text. """ text = self.uiFindTXT.text() view = self.currentWebView() options = QWebPage.FindWrapsAroundDocument if (self.uiCaseSensitiveCHK.isChecked()): options |= QWebPage.FindCaseSensitively view.page().findText(text, options) def findPrev(self): """ Looks for the previous occurance of the current search text. """ text = self.uiFindTXT.text() view = self.currentWebView() options = QWebPage.FindWrapsAroundDocument options |= QWebPage.FindBackward if (self.uiCaseSensitiveCHK.isChecked()): options |= QWebPage.FindCaseSensitively view.page().findText(text, options) def findXdk(self, name): """ Looks up the xdk item based on the current name. :param name | <str> :return <XdkItem> || None """ for i in range(self.uiContentsTREE.topLevelItemCount()): item = self.uiContentsTREE.topLevelItem(i) if (item.text(0) == name): return item return None def goBack(self): widget = self.currentContentsWidget() if (widget): widget.page().history().back() def goForward(self): widget = self.currentContentsWidget() if (widget): widget.page().history().forward() def goHome(self): widget = self.currentContentsWidget() if (widget): widget.history().goHome() def gotoUrl(self, url): if not QApplication.keyboardModifiers() == Qt.ControlModifier: widget = self.currentContentsWidget(autoadd=True) else: widget = self.addContentsWidget() index = self.uiContentsTAB.indexOf(widget) self.uiContentsTAB.setCurrentIndex(index) widget.setUrl(QUrl(url)) def gotoItem(self, path): """ Goes to a particular path within the XDK. :param path | <str> """ if not path: return sections = str(path).split('/') check = projex.text.underscore(sections[0]) for i in range(self.uiContentsTREE.topLevelItemCount()): item = self.uiContentsTREE.topLevelItem(i) if projex.text.underscore(item.text(1)) == check: item.gotoItem('/'.join(sections[1:])) break def loadItem(self, item): """ Loads the inputed item. :param item | <QTreeWidgetItem> """ if isinstance(item, XdkEntryItem): item.load() def loadedFilenames(self): """ Returns a list of all the xdk files that are currently loaded. :return [<str>, ..] """ output = [] for i in range(self.uiContentsTREE.topLevelItemCount()): item = self.uiContentsTREE.topLevelItem(i) output.append(str(item.filepath())) return output def loadFilename(self, filename=''): """ Loads a new XDK file into the system. :param filename | <str> :return <bool> | success """ if (not (filename and isinstance(filename, basestring))): filename = QFileDialog.getOpenFileName(self, 'Open XDK File', QDir.currentPath(), 'XDK Files (*.xdk)') if type(filename) == tuple: filename = str(filename[0]) if not filename: return False if not (filename and os.path.exists(filename)): return False elif filename in self.loadedFilenames(): return False self.loadFileRequested.emit(filename) self.setCursor(Qt.WaitCursor) return True def refreshFromIndex(self): """ Refreshes the documentation from the selected index item. """ item = self.uiIndexTREE.currentItem() if (not item): return self.gotoUrl(item.toolTip(0)) def refreshContents(self): """ Refreshes the contents tab with the latest selection from the browser. """ item = self.uiContentsTREE.currentItem() if not isinstance(item, XdkEntryItem): return item.load() url = item.url() if url: self.gotoUrl(url) def refreshUi(self): """ Refreshes the interface based on the current settings. """ widget = self.uiContentsTAB.currentWidget() is_content = isinstance(widget, QWebView) if is_content: self._currentContentsIndex = self.uiContentsTAB.currentIndex() history = widget.page().history() else: history = None self.uiBackACT.setEnabled(is_content and history.canGoBack()) self.uiForwardACT.setEnabled(is_content and history.canGoForward()) self.uiHomeACT.setEnabled(is_content) self.uiNewTabACT.setEnabled(is_content) self.uiCopyTextACT.setEnabled(is_content) self.uiCloseTabACT.setEnabled(is_content and self.uiContentsTAB.count() > 2) for i in range(1, self.uiContentsTAB.count()): widget = self.uiContentsTAB.widget(i) self.uiContentsTAB.setTabText(i, widget.title()) def search(self): """ Looks up the current search terms from the xdk files that are loaded. """ QApplication.instance().setOverrideCursor(Qt.WaitCursor) terms = str(self.uiSearchTXT.text()) html = [] entry_html = '<a href="%(url)s">%(title)s</a><br/>'\ '<small>%(url)s</small>' for i in range(self.uiContentsTREE.topLevelItemCount()): item = self.uiContentsTREE.topLevelItem(i) results = item.search(terms) results.sort(lambda x, y: cmp(y['strength'], x['strength'])) for item in results: html.append(entry_html % item) if (not html): html.append('<b>No results were found for %s</b>' % terms) self.uiSearchWEB.setHtml(SEARCH_HTML % '<br/><br/>'.join(html)) QApplication.instance().restoreOverrideCursor() def showFind(self): self.uiFindWIDGET.show() self.uiFindTXT.setFocus() self.uiFindTXT.selectAll() def zoomIn(self): view = self.currentWebView() view.setZoomFactor(view.zoomFactor() + 0.1) def zoomOut(self): view = self.currentWebView() view.setZoomFactor(view.zoomFactor() - 0.1) def zoomReset(self): view = self.currentWebView() view.setZoomFactor(1) @staticmethod def browse(parent, filename=''): """ Creates a new XdkWidnow for browsing an XDK file. :param parent | <QWidget> filename | <str> """ dlg = XdkWindow(parent) dlg.show() if (filename): dlg.loadFilename(filename)