Exemple #1
0
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)
Exemple #4
0
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()
Exemple #5
0
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()
Exemple #6
0
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)
Exemple #8
0
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()
Exemple #12
0
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)
Exemple #14
0
    def stop(self):
        self.mutex.lock()
        self.stopMe = 1
        self.mutex.unlock()

        QThread.wait(self)
Exemple #15
0
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
Exemple #16
0
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)
Exemple #17
0
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()
Exemple #19
0
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()
Exemple #20
0
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
Exemple #21
0
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
Exemple #22
0
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()
Exemple #23
0
    def stop(self):
        self.mutex.lock()
        self.stopMe = 1
        self.mutex.unlock()

        QThread.wait(self)
Exemple #24
0
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')
Exemple #25
0
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()
Exemple #26
0
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()
Exemple #28
0
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()
Exemple #29
0
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)
Exemple #30
0
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())
Exemple #31
0
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)
Exemple #35
0
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)