Example #1
0
File: qt.py Project: kwikteam/phy
class AsyncCaller(object):
    """Call a Python function after a delay."""
    def __init__(self, delay=10):
        self._delay = delay
        self._timer = None

    def _create_timer(self, f):
        self._timer = QTimer()
        self._timer.timeout.connect(f)
        self._timer.setSingleShot(True)

    def set(self, f):
        """Call a function after a delay, unless another function is set
        in the meantime."""
        self.stop()
        self._create_timer(f)
        self.start()

    def start(self):
        """Start the timer and call the function after a delay."""
        if self._timer:
            self._timer.start(self._delay)

    def stop(self):
        """Stop the current timer if there is one and cancel the async call."""
        if self._timer:
            self._timer.stop()
            self._timer.deleteLater()
Example #2
0
class DelayWidget(WebWidget):
	def __init__(self, name, cfg, parent = None):
		WebWidget.__init__(self, name, parent)

		self.config = cfg

		self.url.setUrl(self.config.loadLinks()[str(self.objectName())]['data'])

		self.timer = QTimer(self)
		self.timer.setInterval(1000)
		self.timer.setSingleShot(1)

		self.timeoutTimer = QTimer(self)
		self.timeoutTimer.setInterval(10000)
		self.timeoutTimer.setSingleShot(1)

		self.connect(self.timeoutTimer , SIGNAL('timeout()') , self.clear)
		self.connect(self.timer        , SIGNAL('timeout()') , self.reload_)
		self.connect(self              , SIGNAL('done()')    , self.clear)

	def clear(self):
		self.config.saveDelayWidgetBusy(False)

	def reload_(self):
		if not self.isVisible(): return
		if not self.timeoutTimer.isActive():
			self.timeoutTimer.start()
		if self.config.loadDelayWidgetBusy():
			self.timer.start()
		else:
			self.timeoutTimer.stop()
			self.config.saveDelayWidgetBusy(True)
			WebWidget.reload_(self)
Example #3
0
class _StatusBar(QStatusBar):
    """Extended status bar. Supports HTML messages
    """
    def __init__(self, *args):
        QStatusBar.__init__(self, *args)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.setSizeGripEnabled(False)
        self.setStyleSheet("QStatusBar {border: 0} QStatusBar::item {border: 0}")
        self._label = QLabel(self)
        self._label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self._label.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        self._label.setStyleSheet("color: red")
        self.addWidget(self._label)
        self._timer = QTimer()
        self._timer.setSingleShot(True)
        self._timer.timeout.connect(self.clearMessage)
    
    def showMessage(self, text, timeout=0):
        """QStatusBar.showMessage()
        """
        self._label.setText(text)
        self._timer.stop()
        if timeout > 0:
            self._timer.start(timeout)
    
    def clearMessage(self):
        """QStatusBar.clearMessage()
        """
        self._label.clear()
Example #4
0
class Holter(QMainWindow, Ui_Holter):
    """
    Class documentation goes here.
    """
    count=0 #用于计数realFHR的绘画次数,即timer的计数次数
    #baseCount=0
    def __init__(self,parent = None):
        """
        Constructor
        """
        QMainWindow.__init__(self, parent)
        self.setupUi(self)
        self.timer = QTimer()
        self.timerSound=QTimer()
        global soundfile 
        soundfile = "F:/work in 2015 winter/5-HOLTER/FHR/_eric4project/rawHR.wav" 
        self.timer.start(1)
        QtCore.QObject.connect(self.timer, SIGNAL("timeout()"),self.update)

    def paintEvent(self, event): 
        qp = QtGui.QPainter()       
        qp.begin(self)
        drawBackground(self, qp)
        drawScales(self, qp)        
        realFHR(self, qp, FHR, Holter.count)
        realBaseline(self, qp, Baseline, Holter.count)       
        Holter.count+=1
        if Holter.count%1000==0:
            print time.strftime('%H:%M:%S',time.localtime(time.time()))        
            print Holter.count
        
    def sound(self):
        winsound.PlaySound(soundfile, winsound.SND_ASYNC) #立即返回,支持异步播放
class MyWindowClass(QtGui.QMainWindow, form_class):
	connected = bool(False)
	windfreak = None 
	time = 0


	
	def __init__(self, parent=None):
		QtGui.QMainWindow.__init__(self, parent)
		self.setupUi(self)
		self.ButtonUpdate_freq.clicked.connect(self.ButtonUpdate_freq_clicked)# Bind the event handlers
		self.ButtonUpdate_power.clicked.connect(self.ButtonUpdate_power_clicked)
		self.ButtonUpdate_channel.clicked.connect(self.ButtonUpdate_channel_clicked)
		self.ButtonConnect.clicked.connect(self.ButtonConnect_clicked)
		self.comboSerialBox.addItems(serial_ports()) #Gets a list of avaliable serial ports to connect to and adds to combo box
		
		
	def ButtonConnect_clicked(self,connection):
		if not self.connected:
			self.windfreak = wc.windfreakusb2(str(self.comboSerialBox.currentText()))
			self.timer = QTimer()
			self.connected = True
			self.timer.timeout.connect(self.update)
			self.timer.start(1000)
			self.control_label.setText('connected to ' + str(self.comboSerialBox.currentText()))
			self.freq = float(self.windfreak.get_freq())/1000
			self.power = self.windfreak.get_power()
			self.label_freq.setText(str(self.freq)+"MHz")
			self.label_power.setText(str(self.power))
			self.windfreak.set_clock(str(1)) #sets internal clock so that is locks
			self.windfreak.set_freq(str(self.freq))
			
	def ButtonUpdate_freq_clicked(self,value):
		self.windfreak.set_freq(self.freq_box.text())
		self.freq = float(self.windfreak.get_freq())/1000
		self.label_freq.setText(str(self.freq)+"MHz")
		print 'freq updated'
		
	def ButtonUpdate_power_clicked(self,value):
		self.windfreak.set_power(self.power_box.text())
		self.power = self.windfreak.get_power()
		self.label_power.setText(self.power)
		print 'power updated'
	
	def ButtonUpdate_channel_clicked(self,value):
		
		url = "http://charsiew.qoptics.quantum.nus.edu.sg:8080" 
		try:
			urllib2.urlopen(url+"/switch_"+str(self.channel_box.text()))
		except:
		    pass
		print 'channel updated'
		
		
	def update(self):
		url = "http://charsiew.qoptics.quantum.nus.edu.sg:8080" 
		self.data = json.load(urllib2.urlopen(url+"/data"))
		self.label_wavelength.setText(self.data['wavelength'])
		self.label_optical_freq.setText(self.data['freq'])
		self.label_channel.setText(self.data['channel'])
Example #6
0
class VUMeter(QObject):
    KITCHEN_SINK = 'alsa_output.pci-0000_00_1b.0.analog-stereo'

    def __init__(self, parent, sink_name=None):
        super(VUMeter, self).__init__(parent)

        if sink_name == None:
            self.sink_name = self.KITCHEN_SINK
        else:
            self.sink_name = sink_name

        self.meter_rate = 344
        self.display_scale = 8
        self.monitor = PAPeakMonitor(self.sink_name, self.meter_rate)

        self.timer = QTimer()
        self.timer.timeout.connect(self.update)
        self.timer.start(100)

        self.view = VUWidgetView(parent)
        self.view.setGeometry(0, 0, 20, parent.height() )

    def update(self):
        for sample in self.monitor:
            sample = sample * self.display_scale
            self.view.update(sample)
Example #7
0
    def wait(self, time_ms, callback, onredirect=None, onerror=None):
        """
        Wait for time_ms, then run callback.

        If onredirect is True then the timer is cancelled if redirect happens.
        If onredirect is callable then in case of redirect the timer is
        cancelled and this callable is called.

        If onerror is True then the timer is cancelled if a render error
        happens. If onerror is callable then in case of a render error the
        timer is cancelled and this callable is called.
        """

        timer = QTimer()
        timer.setSingleShot(True)
        timer_callback = functools.partial(self._on_wait_timeout,
            timer=timer,
            callback=callback,
        )
        timer.timeout.connect(timer_callback)

        self.logger.log("waiting %sms; timer %s" % (time_ms, id(timer)), min_level=2)

        timer.start(time_ms)
        self._active_timers.add(timer)
        if onredirect:
            self._timers_to_cancel_on_redirect[timer] = onredirect
        if onerror:
            self._timers_to_cancel_on_error[timer] = onerror
Example #8
0
    def private_call_later(self, callback, delay=None):
        if delay is None:
            delay = 0
        if not isinstance(delay, (float, int)):
            raise ScriptError({
                "argument": "delay",
                "message": "splash:call_later delay must be a number",
                "splash_method": "call_later",
            })
        delay = int(float(delay)*1000)
        if delay < 0:
            raise ScriptError({
                "argument": "delay",
                "message": "splash:call_later delay must be >= 0",
                "splash_method": "call_later",
            })
        if lupa.lua_type(callback) != 'function':
            raise ScriptError({
                "argument": "callback",
                "message": "splash:call_later callback is not a function",
                "splash_method": "call_later",
            })

        qtimer = QTimer(self.tab)
        qtimer.setSingleShot(True)
        timer = _ExposedTimer(self, qtimer)
        run_coro = self.get_coroutine_run_func(
            "splash:call_later", callback, return_error=timer.store_error
        )
        qtimer.timeout.connect(run_coro)
        qtimer.start(delay)
        return timer
Example #9
0
class CalendarWidget(QFrame):
    def __init__(self, parent = None):
        QFrame.__init__(self, parent)
        self.timer = QTimer()
        self.timer.setInterval(1000)
        self.timer.timeout.connect(self.updateCurrentDateTime)
        self.timer.start()

    def paintEvent(self, event):
        QFrame.paintEvent(self, event)
        text = QDateTime.currentDateTime().toString(Qt.SystemLocaleLongDate)
        logicalRect = QRectF(QPointF(0, 0), QSizeF(QFontMetrics(self.font()).size(Qt.TextSingleLine, text)))
        physicalRect, frameWidth = QRectF(self.rect()), self.frameWidth()
        physicalRect.adjust(frameWidth, frameWidth, -frameWidth, -frameWidth)
        scaleForWidth = physicalRect.width() / logicalRect.width()
        scaleForHeight = physicalRect.height() / logicalRect.height()
        logicalRect.moveTo(frameWidth / scaleForWidth , frameWidth / scaleForHeight)

        painter = QStylePainter(self)
        painter.scale(scaleForWidth, scaleForHeight)
        painter.drawText(logicalRect, Qt.AlignCenter, text)

    def updateCurrentDateTime(self):
        if self.isVisible():
            self.update()
    class IntegrationTest(QWidget):
        """ Test the controller and view """
        def __init__(self, model):
            super(IntegrationTest, self).__init__()

            self.model = model
            model.current_time = parse(u'2014-05-29T17:54:55+01:00').\
                    replace(tzinfo=pytz.utc)
            model.start_time = parse(u'2014-05-29T17:00:00+01:00').\
                    replace(tzinfo=pytz.utc)
            model.end_time = parse(u'2014-05-29T18:00:00+01:00').\
                    replace(tzinfo=pytz.utc)

            view = AutoStopDialog(self)
            self.auto_stop = AutoStopController(model, view, parent=self)

            self.setWindowModality(Qt.WindowModal)

            self.setWindowTitle('Example')
            self.timer = QTimer()
            self.timer.timeout.connect(self.inc_time)
            self.timer.start(1000)
            self.show()

        def inc_time(self):
            """ Increment the mock timer """
            self.model.current_time = self.model.current_time + timedelta(0, 1)
Example #11
0
class _GlobalUpdateWordSetTimer:
    """Timer updates word set, when editor is idle. (5 sec. after last change)
    Timer is global, for avoid situation, when all instances
    update set simultaneously
    """
    _IDLE_TIMEOUT_MS = 1000

    def __init__(self):
        self._timer = QTimer()
        self._timer.setSingleShot(True)
        self._timer.timeout.connect(self._onTimer)
        self._scheduledMethods = []

    def schedule(self, method):
        if not method in self._scheduledMethods:
            self._scheduledMethods.append(method)
        self._timer.start(self._IDLE_TIMEOUT_MS)

    def cancel(self, method):
        """Cancel scheduled method
        Safe method, may be called with not-scheduled method"""
        if method in self._scheduledMethods:
            self._scheduledMethods.remove(method)

        if not self._scheduledMethods:
            self._timer.stop()

    def _onTimer(self):
        method = self._scheduledMethods.pop()
        method()
        if self._scheduledMethods:
            self._timer.start(self._IDLE_TIMEOUT_MS)
Example #12
0
class UptimeDisplayApplet(plasmascript.Applet):
    def __init__(self,parent,args=None):
        plasmascript.Applet.__init__(self,parent)

    def init(self):
        self.setHasConfigurationInterface(True)
        self.setAspectRatioMode(Plasma.Square)
        self.uptime = ''
        self.update_timer = QTimer()
        self.update_timer.start(60000) #60s
        QObject.connect(self.update_timer, SIGNAL("timeout()"), self.constantUpdate)
        self.readUptime()

    def sizeHint(self):
        return QSize(400, 400)

    def readUptime(self):
        with open('/proc/uptime', 'r') as f:
            uptime_seconds = float(f.readline().split()[0])
            uptime_hours = int(uptime_seconds / 3600)
            uptime_minutes = int((uptime_seconds - (uptime_hours * 3600)) / 60)

            self.uptime = "%dh\n%dm" % (uptime_hours, uptime_minutes)

    def constantUpdate(self):
        self.readUptime()
        self.update()

    def paintInterface(self, painter, option, rect):
        painter.save()
        painter.setPen(Qt.black)
        painter.setFont(QFont('Decorative', 8))
        painter.drawText(rect, Qt.AlignVCenter | Qt.AlignHCenter, str(self.uptime))
        painter.restore()
class ErrorMessageFilter(QObject):
    """
    In a parallel program, the same error may occur in several threads in close succession.
    For example, all slice views will notice a "filter too large" error simultaneously.
    This class collects error messages for a certain time (currently: 1000ms) and then
    displays each unique message only once.
    """
    def __init__(self, parent):
        super(QObject, self).__init__(parent)
        self.messages = {}
        self.timer = QTimer(self)
        self.timer.setSingleShot(True)
        self.timer.setInterval(1000)
        self.connect(self.timer, QtCore.SIGNAL("timeout()"), self.timeout)
        
    def showErrorMessage(self, caption, text):
        if not self.timer.isActive():
            self.timer.start()
        self.messages[caption] = text
        
    def timeout(self):
        # Must copy now because the eventloop is allowed to run during QMessageBox.critical, below.
        # That is, self.messages might change while the loop is executing (not allowed).
        messages = copy.copy(self.messages)
        for caption, text in messages.iteritems():
            QMessageBox.critical(self.parent(), caption, text)
        self.messages = {}
        
Example #14
0
  def run(self):
    app = QApplication(sys.argv)
    imageProvider = ImageProvider()

    # Create the QML user interface.
    view = QDeclarativeView()
    
    view.setResizeMode(QDeclarativeView.SizeRootObjectToView)

    engine = view.engine()
    
    engine.addImageProvider("mazakodron", imageProvider)
    
    view.setSource(QUrl('symulator/mazakodron.qml'))
    rootObject = view.rootObject()
    if not rootObject:
      view.setSource(QUrl('mazakodron.qml'))
      rootObject = view.rootObject()
    
    rootObject.requestDraw.connect(imageProvider.draw)
    
    self.rootObject = rootObject

    view.setGeometry(0, 0, 800, 600)
    view.show()

    timer = QTimer()
    timer.start(1000/60) # 60FPS
    timer.timeout.connect(self.process)

    sys.exit(app.exec_());
class MyForm(QtGui.QMainWindow):

    def __init__(self, parent=None):
        self.ticketNumber = ''
        ticketStatus()
        QtGui.QWidget.__init__(self, parent)
        self.ui = Ui_ticketReaderView()
        self.ui.setupUi(self)
        self.timer = QTimer()
        self.timer.timeout.connect(self.setDefault)

        self.statusBar = QtGui.QStatusBar()
        self.setStatusBar(self.statusBar)
        self.statusBar.hide()

        self.menuBar = QtGui.QMenuBar()
        self.setMenuBar(self.menuBar)
        self.menuBar.hide()

        self.ui.mainToolBar.hide()

        #self.showFullScreen()
		
    def keyPressEvent(self, event):
         key = event.key()
         if key != QtCore.Qt.Key_Return:
             self.ticketNumber+=chr(key)
             print('pressed: ', chr(key))
         if key == QtCore.Qt.Key_Return:
            print('Ticket:', self.ticketNumber)
            if(len(self.ticketNumber)>0):
                self.checkIsTicketValid()
            self.timer.start(3000)
            self.ticketNumber = ''

    def setDefault(self):
        self.ui.textEdit.setHtml(_translate("ticketReaderView", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
                                            "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
                                            "p, li { white-space: pre-wrap; }\n"
                                            "</style></head><body style=\" font-family:\'MS Shell Dlg 2\'; font-size:8.25pt; font-weight:400; font-style:normal;\">\n"
                                            "<p align=\"center\" style=\" margin-top:0px; margin-bottom:15px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#00A3E8;\"><span style=\" font-family:\'Calibri\'; font-size:28pt; font-weight:600; color:#ffffff; background-color:#00A3E8;\">Molimo nanesite <br /> Vaš tiket<br /> </span></p></body></html>", None))


    def checkIsTicketValid(self):
        self.status = ticketStatus.checkTicketNumber(self.ticketNumber)

        if self.status['validationSuccess'] == 'ok':
            self.ui.textEdit.setHtml(_translate("ticketReaderView", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
                                                "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
                                                "p, li { white-space: pre-wrap; }\n"
                                                "</style></head><body style=\" font-family:\'MS Shell Dlg 2\'; font-size:8.25pt; font-weight:400; font-style:normal;\">\n"
                                                "<p align=\"center\" style=\" margin-top:0px; margin-bottom:15px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#00A3E8;\"><span style=\" font-family:\'Calibri\'; font-size:28pt; font-weight:600; color:#ffffff; background-color:#00A3E8;\">"+self.status['validationMessage']+"<br /> </span></p></body></html>", None))
            print (self.status)
        else:
            self.ui.textEdit.setHtml(_translate("ticketReaderView", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
                                                "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
                                                "p, li { white-space: pre-wrap; }\n"
                                                "</style></head><body style=\" font-family:\'MS Shell Dlg 2\'; font-size:8.25pt; font-weight:400; font-style:normal;\">\n"
                                                "<p align=\"center\" style=\" margin-top:0px; margin-bottom:15px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#00A3E8;\"><span style=\" font-family:\'Calibri\'; font-size:28pt; font-weight:600; color:#ffffff; background-color:#00A3E8;\">"+self.status['validationMessage']+"<br /> </span></p></body></html>", None))
            print (self.status)
class DeviceReader(QThread):
    """Used for polling data from the Input layer during configuration"""
    raw_axis_data_signal = pyqtSignal(object)
    raw_button_data_signal = pyqtSignal(object)
    mapped_values_signal = pyqtSignal(object)

    def __init__(self, input):
        QThread.__init__(self)

        self._input = input
        self._read_timer = QTimer()
        self._read_timer.setInterval(25)

        self.connect(self._read_timer, SIGNAL("timeout()"), self._read_input)

    def stop_reading(self):
        """Stop polling data"""
        self._read_timer.stop()

    def start_reading(self):
        """Start polling data"""
        self._read_timer.start()

    def _read_input(self):
        [rawaxis, rawbuttons, mapped_values] = self._input.read_raw_values()
        self.raw_axis_data_signal.emit(rawaxis)
        self.raw_button_data_signal.emit(rawbuttons)
        self.mapped_values_signal.emit(mapped_values)
Example #17
0
class StartPage(QWidget):
    """ Interfáz QML """

    def __init__(self):
        QWidget.__init__(self)
        box = QVBoxLayout(self)
        box.setContentsMargins(0, 0, 0, 0)
        view = QDeclarativeView()
        view.setMinimumSize(400, 400)
        qml = os.path.join(paths.PATH, "ui", "StartPage.qml")
        path = QDir.fromNativeSeparators(qml)
        view.setSource(QUrl.fromLocalFile(path))
        view.setResizeMode(QDeclarativeView.SizeRootObjectToView)
        self._root = view.rootObject()
        box.addWidget(view)

        self._current_text = ""
        # Timer
        self.timer = QTimer(self)
        self.timer.setInterval(3000)
        self._show_welcome_text()
        self.timer.timeout.connect(self._show_text)
        self.timer.start()

    def _show_welcome_text(self):
        self._root.show_text(WELCOME)

    def _show_text(self):
        if not self._current_text:
            self.timer.setInterval(7000)
        result = random.choice(TEXTS)
        # Para evitar que se repita
        if result != self._current_text:
            self._root.show_text(result)
        self._current_text = result
Example #18
0
def ask_password_dialog(parent, title, prompt, timeout = None):
    if parent is None:
        app = qt4tools.create_qapplication()
        translator = qt4tools.get_translator()
        app.installTranslator(translator)

    import icon
    dialog = QInputDialog()

    timer = QTimer()
    if not timeout is None:
        dialog.connect(timer, SIGNAL("timeout()"), dialog.reject)
        timer.setInterval(timeout * 1000)
        timer.start()

    dialog.setWindowIcon(icon.BIT_LOGO)
    dialog.setWindowTitle(title)
    dialog.setLabelText(prompt)
    dialog.setTextEchoMode(QLineEdit.Password)
    QApplication.processEvents()

    ret = dialog.exec_()

    timer.stop()
    if ret:
        password = dialog.textValue()
    else:
        password = ''
    del(dialog)

    return(password)
Example #19
0
class PregSim(QDialog, Ui_PregSim):
    """
    Class documentation goes here.
    """
    def __init__(self, parent = None):
        """
        Constructor
        """
        QDialog.__init__(self, parent)
        self.setupUi(self)
    
    def switch2_simple(self, an24Dict_chosen):
        self.an24 = an24Dict_chosen
        self.timerUpdate = QTimer()
        QtCore.QObject.connect(self.timerUpdate, SIGNAL("timeout()"),self.update)
        self.timerUpdate.start(1000)
        self.exec_()
    
    @pyqtSignature("bool")
    def on_pushButton_clicked(self, checked):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        self.is_hiden = True
        self.accept()
    
    def is_simple_hidden(self):
        try:
            is_hiden = self.is_hiden
        except Exception, reason:
            is_hiden = False
        return is_hiden
Example #20
0
    def __init__(self):
        super(QtGlWindow, self).__init__()
        # self.data = np.array(.2*np.random.randn(100000, 2), dtype=np.float32)
        self.data = np.array([
            -0.5, 0.0, 0.5,
            0.5, 0.0, 0.5,
            0.5, 0.0, -0.5,
            -0.5, 0.0, -0.5,
            0.0, 0.5, 0.0
        ], dtype=np.float32)
        self.index = np.array([
            1, 2, 5,
            2, 3, 5,
            3, 4, 5,
            4, 1, 5,
            1, 2, 3,
            2, 3, 4
        ], dtype=np.uint32)
        self.widget = GlPlotWidget()
        self.widget.set_data(self.data, self.index)
        self.setGeometry(100, 100, self.widget.width, self.widget.height)
        self.setCentralWidget(self.widget)

        # automatically update window
        timer = QTimer(self)
        timer.timeout.connect(self.widget.updateGL)
        timer.start(1)
Example #21
0
 def highlight(self, format, cursors, priority=0, msec=0):
     """Highlights the selection of an arbitrary list of QTextCursors.
     
     format can be a name for a predefined text format or a QTextCharFormat;
     in the first case the textFormat() method should return a qtextformat to use.
     priority determines the order of drawing, highlighting with higher priority
     is drawn over highlighting with lower priority.
     msec, if > 0, removes the highlighting after that many milliseconds.
     
     """
     if isinstance(format, QTextFormat):
         fmt = format
         key = id(format)
         self._formats[key] = format
     else:
         fmt = self.textFormat(format)
         key = format
     selections = []
     for cursor in cursors:
         es = QTextEdit.ExtraSelection()
         es.cursor = cursor
         es.format = fmt
         selections.append(es)
     if msec:
         def clear(selfref=weakref.ref(self)):
             self = selfref()
             if self:
                 self.clear(format)
         timer = QTimer(timeout=clear, singleShot=True)
         timer.start(msec)
         self._selections[key] = (priority, selections, timer)
     else:
         self._selections[key] = (priority, selections)
     self.update()
Example #22
0
class LabelableSegmentationEdgesLayer( SegmentationEdgesLayer ):
    """
    Shows a set of user-labeled edges.
    """
    
    labelsChanged = pyqtSignal( dict ) # { id_pair, label_class }
    
    def __init__(self, datasource, label_class_pens, initial_labels={}, delay_ms=1000):
        # Class 0 (no label) is the default pen
        super(LabelableSegmentationEdgesLayer, self).__init__( datasource, default_pen=label_class_pens[0] )
        self._delay_ms = delay_ms
        self._label_class_pens = label_class_pens

        # Initialize the labels and pens
        self.overwrite_edge_labels(initial_labels)
        
        self._buffered_updates = {}

        # To avoid sending lots of single updates if the user is clicking quickly,
        # we buffer the updates into a dict that is only sent after a brief delay.
        self._timer = QTimer(self)
        self._timer.setInterval(self._delay_ms)
        self._timer.setSingleShot(True)
        self._timer.timeout.connect( self._signal_buffered_updates )

    def overwrite_edge_labels(self, new_edge_labels):
        self._edge_labels = defaultdict(lambda: 0, new_edge_labels)

        # Change the pens accordingly
        pen_table = {}
        for id_pair, label_class in self._edge_labels.items():
            pen_table[id_pair] = self._label_class_pens[label_class]
        self.pen_table.overwrite(pen_table)
    
    def handle_edge_clicked(self, id_pair):
        """
        Overridden from SegmentationEdgesLayer
        """
        num_classes = len(self._label_class_pens)
        old_class = self._edge_labels[id_pair]
        new_class = (old_class+1) % num_classes

        # Update the display
        self.pen_table[id_pair] = self._label_class_pens[new_class]

        # For now, edge_labels dictionary will still contain 0-labeled edges.
        # We could delete them, but why bother?
        self._edge_labels[id_pair] = new_class

        # Buffer the update for listeners
        self._buffered_updates[id_pair] = new_class
        
        # Reset the timer
        self._timer.start()

    def _signal_buffered_updates(self):
        updates = self._buffered_updates
        self._buffered_updates = {}
        self.labelsChanged.emit( updates )
        
Example #23
0
class VideoWidget(QWidget):
    """ A class for rendering video coming from OpenCV """

    def __init__(self, parent=None):
        QWidget.__init__(self)
        self._capture = cv.CreateCameraCapture(0)
        # Take one frame to query height
        frame = cv.QueryFrame(self._capture)
        self.setMinimumSize(frame.width, frame.height)
        self.setMaximumSize(self.minimumSize())
        self._frame = None
        self._image = self._build_image(frame)
        # Paint every 50 ms
        self._timer = QTimer(self)
        self._timer.timeout.connect(self.queryFrame)
        self._timer.start(50)

    def _build_image(self, frame):
        if not self._frame:
            self._frame = cv.CreateImage((frame.width, frame.height), cv.IPL_DEPTH_8U, frame.nChannels)
        if frame.origin == cv.IPL_ORIGIN_TL:
            cv.Copy(frame, self._frame)
        else:
            cv.Flip(frame, self._frame, 0)
        return IplQImage(self._frame)

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.drawImage(QPoint(0, 0), self._image)

    def queryFrame(self):
        frame = cv.QueryFrame(self._capture)
        self._image = self._build_image(frame)
        self.update()
Example #24
0
def main():
    signal.signal(signal.SIGINT, lambda *args: QtGui.QApplication.quit())
    app = QtGui.QApplication(sys.argv)

    w = QtGui.QWidget()
    trayIcon = SystemTrayIcon(myicon("stop.svg"), w)

    def show_icon(icon):
        trayIcon.setToolTip("<i>unko!</i>")
        trayIcon.setIcon(icon)
        trayIcon.show()

    def callback(state):
        show_icon(myicon("%s.svg"%state))

    def check_status():
        status = subprocess.Popen("ti status --no-gui-notification".split(), stdout=subprocess.PIPE).communicate()[0]
        if status.find("Not working on any task.") != -1:
            state = "stop"
        elif status.find("Working on ") != -1:
            state = "start"
        else:
            raise Exception()
        callback(state)

    check_status()
    timer = QTimer()
    timer.start(1000)  # You may change this if you wish.
    timer.timeout.connect(check_status)  # Let the interpreter run each 500 ms.

    # ti_server.CALLBACK = callback
    # ti_server.main()
    app.exec_()
    sys.exit()
class ErrorMessageFilter(QObject):
    """
    In a parallel program, the same error may occur in several threads in close succession.
    For example, all slice views will notice a "filter too large" error simultaneously.
    This class collects error messages for a certain time (currently: 200ms) and then
    displays each unique message only once.
    """
    def __init__(self, parent):
        super(QObject, self).__init__(parent)
        self.messages = {}
        self.timer = QTimer(self)
        self.timer.setSingleShot(True)
        self.timer.setInterval(200)
        self.connect(self.timer, QtCore.SIGNAL("timeout()"), self.timeout)
        
    def showErrorMessage(self, caption, text):
        if not self.timer.isActive():
            self.timer.start()
        self.messages[text] = caption
        
    def timeout(self):
        for text, caption in self.messages.iteritems():
            QMessageBox.critical(self.parent(), caption, text)
        self.messages = {}
        
Example #26
0
 def register_timer(self, time_delta, callback):
     """Registers a callback function to be run after time_delta ms."""
     timer = QTimer(self.window)
     timer.setSingleShot(True)
     timer.timeout.connect(callback)
     timer.setInterval(time_delta)
     timer.start()
Example #27
0
class Player(QThread, midifile.player.Player):
    """An implementation of midifile.player.Player using a QThread and QTimer.
    
    emit signals:
    
    stateChanged(playing):
        True or False if playing state changes
        
    time(msec):
        The playing time, emit by default every 1000ms
        
    beat(measnum, beat, num, den):
        the measure number, beat number, time signature numerator and denom.,
        where 0 = whole note, 1 = half note, 2 = quarter note, etc.
    
    """
    stateChanged = pyqtSignal(bool)
    time = pyqtSignal(int)
    beat = pyqtSignal(int, int, int, int)
    
    def __init__(self, parent=None):
        QThread.__init__(self, parent)
        midifile.player.Player.__init__(self)
        self._timer = None
    
    def run(self):
        self._timer = QTimer(singleShot=True)
        self._timer.timeout.connect(self.timer_timeout, Qt.DirectConnection)
        self.timer_start_playing()
        self.stateChanged.emit(True)
        if self.exec_():
            self.timer_stop_playing()
        self._timer = None
        self.stateChanged.emit(False)
    
    def start(self):
        if self.has_events():
            QThread.start(self)
    
    def stop(self):
        if self.isRunning():
            self.exit(1)
            self.wait()
    
    def timer_start(self, msec):
        """Starts the timer to fire once, the specified msec from now."""
        self._timer.start(int(msec))
    
    def timer_stop(self):
        self._timer.stop()

    def finish_event(self):
        midifile.player.Player.finish_event(self)
        self.exit(0)

    def time_event(self, time):
        self.time.emit(time)
    
    def beat_event(self, measnum, beat, num, den):
        self.beat.emit(measnum, beat, num, den)
Example #28
0
class Plugin:
  def __init__(self):
    self.timer = QTimer(None)
    self.timer.setInterval(10000)
    self.timer.timeout.connect(self.Timeout)
    self.timer.setSingleShot(True)
    self.action = QAction("Preview mode", None)
    self.action.setCheckable(True)
    self.action.triggered.connect(self.Enabled)
    clementine.ui.AddAction("playlist_menu", self.action)
    clementine.player.Playing.connect(self.Playing)
    clementine.player.Paused.connect(self.Stopped)
    clementine.player.Stopped.connect(self.Stopped)
    self.enabled = False

  def Enabled(self, enabled):
    self.enabled = enabled
    if enabled:
      if clementine.player.GetState() == 2:  # Playing
        self.timer.start()
    else:
      self.timer.stop()

  def Playing(self):
    if self.enabled:
      self.timer.start()

  def Stopped(self):
    self.timer.stop()

  def Timeout(self):
    if clementine.player.GetState() == 2:
      clementine.player.Next()
Example #29
0
    def get(self, url=None, script=None, key=None):
        """Load given url in webkit and return html when loaded
        """
        self.base_url = self.base_url or url # set base URL if not set
        html = self.cache.get(key)
        if html:
            if self.debug: print 'load cache', key 
            self.setHtml(html, QUrl(self.base_url))
        elif url:
            self.load(QUrl(url))
        elif script:
            self.js(script)

        loop = QEventLoop()
        timer = QTimer()
        timer.setSingleShot(True)
        timer.timeout.connect(loop.quit)
        self.loadFinished.connect(loop.quit)
        timer.start(self.timeout * 1000)
        loop.exec_() # delay here until download finished or timeout
    
        if timer.isActive():
            # downloaded successfully
            timer.stop()
            html = self.current_html()
            if key:
                self.cache[key] = html
            self.inject_jquery()
        else:
            # didn't download in time
            print 'Download timeout'
            html = ''
        return html
    def __init__(self):
        super().__init__()
        self.cap = None
        self.snapshot_flash = 0
        self.IMAGE_DIR = tempfile.mkdtemp(prefix='Orange-WebcamCapture-')

        self.setSizePolicy(QSizePolicy.MinimumExpanding,
                           QSizePolicy.MinimumExpanding)
        box = self.controlArea
        image = self.imageLabel = QLabel(
            margin=0,
            alignment=Qt.AlignCenter,
            sizePolicy=QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored))
        box.layout().addWidget(image, 100)

        self.name_edit = line_edit = gui.lineEdit(
            box, self, 'image_title', 'Title:', orientation=Qt.Horizontal)
        line_edit.setPlaceholderText(self.DEFAULT_TITLE)

        hbox = gui.hBox(box)
        gui.checkBox(hbox, self, 'avatar_filter', 'Avatar filter')
        button = self.capture_button = QPushButton('Capture', self,
                                                   clicked=self.capture_image)
        hbox.layout().addWidget(button, 1000)
        box.layout().addWidget(hbox)

        timer = QTimer(self, interval=40)
        timer.timeout.connect(self.update_webcam_image)
        timer.start()
Example #31
0
class QuickHelp(QTextBrowser):

    #: Emitted when the shown text changes.
    textChanged = Signal()

    def __init__(self, *args, **kwargs):
        QTextBrowser.__init__(self, *args, **kwargs)

        self.setOpenExternalLinks(False)
        self.setOpenLinks(False)

        self.__text = ""
        self.__permanentText = ""

        self.__timer = QTimer(self, timeout=self.__on_timeout, singleShot=True)
        self.anchorClicked.connect(self.__on_anchorClicked)

    def showHelp(self, text, timeout=0):
        """
        Show help for `timeout` milliseconds. if timeout is 0 then
        show the text until it is cleared with clearHelp or showHelp is
        called with an empty string.

        """
        if self.__text != text:
            self.__text = str(text)
            self.__update()
            self.textChanged.emit()

        if timeout > 0:
            self.__timer.start(timeout)

    def clearHelp(self):
        """
        Clear help text previously set with `showHelp`.
        """
        self.__timer.stop()
        self.showHelp("")

    def showPermanentHelp(self, text):
        """
        Set permanent help text. The text may be temporarily overridden
        by showHelp but will be shown again when that is cleared.

        """
        if self.__permanentText != text:
            self.__permanentText = text
            self.__update()
            self.textChanged.emit()

    def currentText(self):
        """
        Return the current shown text.
        """
        return self.__text or self.__permanentText

    def __update(self):
        if self.__text:
            self.setHtml(self.__text)
        else:
            self.setHtml(self.__permanentText)

    def __on_timeout(self):
        if self.__text:
            self.__text = ""
            self.__update()
            self.textChanged.emit()

    def __on_anchorClicked(self, anchor):
        ev = QuickHelpDetailRequestEvent(anchor.toString(), anchor)
        QCoreApplication.postEvent(self, ev)
Example #32
0
class DynamicPlotter(pg.PlotWidget):

    def __init__(self, sample_interval=0.01, time_window=20., parent=None):
        super(DynamicPlotter, self).__init__(parent)
        self.sample_interval = sample_interval
        self.time_window = time_window
        self.showGrid(x=True, y=True)
        self.setLabel('top', 'Input Real Time')
        self.setLabel('left', 'Amplitude', 'V')
        self.setLabel('bottom', 'Time', 's')
        self.curve = None
        global global_buffer


    def initData(self):
        self._interval = int(self.sample_interval * 1000)
        self._bufsize = int(self.time_window / self.sample_interval)
        self.databuffer = collections.deque([0.0] * self._bufsize, self._bufsize)
        self.x = np.linspace(-self.time_window, 0.0, self._bufsize)
        self.y = np.zeros(self._bufsize, dtype=np.float)
        self.audio = AudioRecord("output.wav", 1000, 1)
        self.audio.begin_audio()

        self.timer = QTimer()
        self.timer.timeout.connect(self.updateplot)
        self.timer.start(self._interval)
        self.curve = self.plot(self.x, self.y, pen=(0, 255, 255), antialias=True)
        self.curve.clear()

    def setSampleInterval(self, sample_interval):
        self.sample_interval = sample_interval
        self.curve.clear()
        self.initData()

    def setTimeWindow(self, time_window):
        self.time_window = time_window
        self.curve.clear()
        self.initData()

    def getdata(self):
        # frequency = 0.5
        # noise = random.normalvariate(0., 1.)
        # new = 10. * math.sin(time.time() * frequency * 2 * math.pi) + noise
        a, b = self.audio.get_data_from_audio()
        new = b[0]

        if global_buffer.recording is True:
            global_buffer.counter += 1

            if global_buffer.counter >= global_buffer.buffer_size:

            global_buffer.data[global_buffer.counter] = new

        return new

    def updateplot(self):
        stp = self.getdata()
        self.databuffer.append(stp)
        self.y[:] = self.databuffer
        self.curve.setData(self.x, self.y)

    def setCurveColor(self, r, g, b):
        self.curve.setPen(pg.mkPen(color=(r, g, b)))


class MainWindow(QMainWindow):

    """Main window class."""

    def __init__(self, parent=None):
        """Constructor of the class

        :param parent: parent
        :type param: QWidget()
        """
        super(MainWindow, self).__init__(parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.setWindowTitle(__app_name__ + '  ' + __version__)
        self.ui.labelAbout.setText(self.tr(about))
        # Connecting actions
        # File actions
        self.ui.actionNew.triggered.connect(self.newFile)
        # For now it cannot open a file
        # self.ui.actionOpen.triggered.connect(self.openFile)
        self.ui.actionSave.triggered.connect(self.saveFile)
        self.ui.actionSave_As.triggered.connect(self.saveFileAs)
        # Acquire actions
        self.ui.actionRecord.triggered.connect(self.record)
        self.ui.actionRecord.setCheckable(True)
        self.ui.actionPause.triggered.connect(self.pause)
        self.ui.actionPause.setCheckable(True)
        self.ui.actionPause.setEnabled(False)
        self.ui.actionStop.triggered.connect(self.stop)
        self.ui.actionStop.setEnabled(False)
        # Tools actions
        self.ui.actionConvert_Wav_to_Dat.triggered.connect(self.callTools)
        # Program actions
        self.ui.actionQuit.triggered.connect(self.close)
        self.ui.actionAbout_Wavy.triggered.connect(self.about)
        # Plot widget

        self.plot_widget = DynamicPlotter(sample_interval=0.01, time_window=20.)
        self.plot_widget.initData()
        self.ui.gridLayout_2.addWidget(self.plot_widget, 0, 1)
        self.plot_widget_rec = Plotter(sample_interval=0.01, time_window=5.)
        self.ui.gridLayout_2.addWidget(self.plot_widget_rec, 1, 1)
        # Inputs
        self.ui.doubleSpinBoxSampleInterval.valueChanged.connect(self.plot_widget.setSampleInterval)
        self.ui.doubleSpinBoxSampleInterval.valueChanged.connect(self.setSampleRate)
        self.ui.doubleSpinBoxSampleRate.valueChanged.connect(self.setSampleInterval)
        self.ui.spinBoxWindowTime.valueChanged.connect(self.plot_widget.setTimeWindow)
        self.setSampleRate(self.ui.doubleSpinBoxSampleInterval.value())

        global global_buffer

    def setSampleRate(self, sample_interval):
        """Sets sample rate.
        """
        self.ui.doubleSpinBoxSampleRate.setValue(1. / sample_interval)

    def setSampleInterval(self, sample_rate):
        """Sets sample interval.
        """
        self.ui.doubleSpinBoxSampleInterval.setValue(1. / sample_rate)

    def callTools(self):
        dlg = ConvertWave2Data()
        dlg.exec_()

    def record(self):
        """Starts acquiring.
        """

        if self.plot_widget_rec.curve is not None:
            self.plot_widget_rec.curve.clear()
        self.plot_widget_rec.initData()
        self.plot_widget_rec.setCurveColor(255, 0, 0)
        self.plot_widget_rec.setLabel('top', 'Recording ...')
        # Set enabled buttons
        self.ui.actionPause.setEnabled(True)
        self.ui.actionStop.setEnabled(True)
        self.ui.actionRecord.setEnabled(False)
        # Set enabled inputs
        self.ui.spinBoxWindowTime.setEnabled(False)
        self.ui.doubleSpinBoxSampleInterval.setEnabled(False)
        self.ui.doubleSpinBoxSampleRate.setEnabled(False)
        self.ui.spinBoxStopRecordingAfter.setEnabled(False)
        # Set enabled tool bar and menu
        self.ui.toolBarFile.setEnabled(False)
        self.ui.menuFile.setEnabled(False)
        self.ui.menuTools.setEnabled(False)

        global_buffer.recording = True


    def pause(self):
        """Pauses acquiring.
        """

        if self.ui.actionPause.isChecked():
            # Stopping changing color and label
            self.plot_widget_rec.timer.stop()
            self.plot_widget_rec.setCurveColor(255, 153, 0)
            self.plot_widget_rec.setLabel('top', 'Paused ...')
            global_buffer.recording = False
        else:
            # Starting changing color and label
            self.plot_widget_rec.timer.start()
            self.plot_widget_rec.setCurveColor(255, 0, 0)
            self.plot_widget_rec.setLabel('top', 'Recording ...')
            global_buffer.recording = True
        # Set enabled tool bar
        self.ui.toolBarFile.setEnabled(False)
        self.ui.menuFile.setEnabled(False)
        self.ui.menuTools.setEnabled(False)

    def stop(self):
        """Stops acquiring.
        """

        # Stopping changing color and label
        self.plot_widget_rec.timer.stop()
        self.plot_widget_rec.setCurveColor(0, 255, 0)
        self.plot_widget_rec.setLabel('top', 'Stoped ...')
        # Set checked
        self.ui.actionRecord.setChecked(False)
        self.ui.actionPause.setChecked(False)
        # Set enabled buttons
        self.ui.actionPause.setEnabled(False)
        self.ui.actionStop.setEnabled(False)
        self.ui.actionRecord.setEnabled(True)
        # Set enabled inputs
        self.ui.doubleSpinBoxSampleInterval.setEnabled(True)
        self.ui.doubleSpinBoxSampleRate.setEnabled(True)
        self.ui.spinBoxWindowTime.setEnabled(True)
        self.ui.spinBoxStopRecordingAfter.setEnabled(True)
        # Set enabled tool bar
        self.ui.toolBarFile.setEnabled(True)
        self.ui.menuFile.setEnabled(True)
        self.ui.menuTools.setEnabled(True)

        global_buffer.recording = False

    def newFile(self):
        """Creates a new file."""

    def saveFile(self):
        """Saves a file."""

    def saveFileAs(self, filename=''):
        """Saves file as new name."""

    def about(self):
        """Show the dialog about."""

        QMessageBox.about(self, self.tr('About'),
                          self.tr(about))

    def closeQuestion(self):
        """Asks about to close."""
        answer = QMessageBox.question(self,
                                      self.tr('Close'),
                                      self.tr('Do you want to exit ?'),
                                      QMessageBox.Yes | QMessageBox.No,
                                      QMessageBox.No)

        return answer == QMessageBox.Yes

    def closeEvent(self, event):
        """Re implements close event."""
        if self.closeQuestion():
            self.stop()
            self.plot_widget.audio.end_audio()
            event.accept()
        else:
            event.ignore()
class Window(QtGui.QMainWindow, Ui_MainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        Ui_MainWindow.__init__(self)
        self.setupUi(self)
        self.initUI()

    def initUI(self):
        self.w = QWidget()

        # a figure instance to plot on
        self.figure = Figure()

        # this is the Canvas Widget that displays the `figure`
        # it takes the `figure` instance as a parameter to __init__
        self.canvas = FigureCanvas(self.figure)

        # this is the Navigation widget
        # it takes the Canvas widget and a parent
        self.toolbar = NavigationToolbar(self.canvas, self)

        # set the layout for the main window
        self.dispLayout.addWidget(self.toolbar)
        self.dispLayout.addWidget(self.canvas)

        #buttons
        self.nextFrame.clicked.connect(self.dispNextImg)
        self.prevFrame.clicked.connect(self.dispPrevImg)
        self.selectFileBut.clicked.connect(self.getFile)
        self.playVidBut.clicked.connect(self.play)
        self.makeTiffBut.clicked.connect(self.makeTiff2)
        self.displayC.clicked.connect(self.dispCDef)
        self.displayC.clicked.connect(self.displayTempValues)
        self.displayF.clicked.connect(self.dispFDef)
        self.displayF.clicked.connect(self.displayTempValues)
        self.sl.valueChanged.connect(self.slValueChange)
        self.saveCvImageBut.clicked.connect(self.saveCvImage)
        #cid = self.canvas.mpl_connect('button_press_event', self.on_press)
        self.saveAsVideoSS.clicked.connect(self.saveVideoSS)
        self.pauseVidBut.clicked.connect(self.pauseVideo)
        #self.startEdit.returnPressed(frame = str(self.startEdit.text()))
        #self.startEdit.returnPressed(frame = str(self.startEdit.text()))

        #self.history.verticalScrollBar().setValue(self.history.verticalScrollBar().maximum())

        self.timer = QTimer(self)
        self.timer.setInterval(timerHz)
        self.timer.timeout.connect(self.playVid5)
        self.timer.start()

    def dispCDef(self):
        global toggleUnitState
        toggleUnitState = 'C'
        self.history.insertPlainText('Display ' + str(toggleUnitState) + '\n')
        self.history.moveCursor(QTextCursor.End)

    def dispFDef(self):
        global toggleUnitState
        toggleUnitState = 'F'
        self.history.insertPlainText('Display ' + str(toggleUnitState) + '\n')
        self.history.moveCursor(QTextCursor.End)

    def startTimer(self):
        global hz
        self.timer.stop()
        print(hz)
        self.timer.setInterval(timerHz)
        self.timer.timeout.connect(self.playVid5)
        self.timer.start()
        print('Re-Started Timer')

    def stopTimer(self):
        self.timer.stop()

    def speed(self):
        global framerate
        hzIndex = self.comboBoxHz.currentIndex()
        if hzIndex == 0:
            framerate = 0.5
            print('Half Framerate')
        elif hzIndex == 1:
            framerate = 1
            print('Normal Framerate')
        elif hzIndex == 2:
            framerate = 2
            print('Double Framerate')
        else:
            hz = 111
        self.startTimer()

    def slValueChange(self):
        global frame
        #global fileSelected
        #if fileSelected != "":
        #print('SlValueChange Def Called')
        frame = self.sl.value()
        self.dispImg()
        self.canvas.draw()

    def setSlider(self):
        global lastFrame
        #print('Set Slider Function Called')
        #print('Enable Slider')
        self.sl.setEnabled(True)
        #print('Set Minimum')
        self.sl.setMinimum(1)
        #print(lastFrame)
        #print('Set Maximum')
        self.sl.setMaximum(lastFrame)
        self.sl.setValue(1)
        self.sl.setTickPosition(QSlider.TicksBelow)
        self.sl.setTickInterval(9)
        self.slStartF.setText('First Frame: 1')
        self.slMidF.setText('Mid Frame: ' + str(lastFrame / 2))
        self.slEndF.setText('Last Frame: ' + str(lastFrame))
        self.slStartT.setText('0 Seconds')
        self.slMidT.setText(str(lastFrame / (2 * 9)) + ' Seconds')
        self.slEndT.setText(str(lastFrame / 9) + ' Seconds')

    def saveVideoSS(self):
        global frame
        global editLastFrame
        global videoState
        videoState = 'pause'
        if fileSelected != "":
            fileNameVid = ""
            dlgVid = QFileDialog()
            #dlg.setNameFilter('PNG files (*.png)')
            dlgVid.setDefaultSuffix('.avi')
            fileNameVid = dlgVid.getSaveFileName(
                self.w,
                'Navigate to Directory and Choose a File Name to Save To',
                'untitled.avi', 'AVI Video (*.avi)')
            #if self.startEdit.isModified():
            fileNameVid = str(fileNameVid)
            #if fileNameVid.endswith('.avi') == False:
            #	fileNameVid = fileNameVid + '.avi'
            frame = int(self.startEdit.text())
            #if self.stopEdit.isModified():
            editLastFrame = int(self.stopEdit.text())
            fourcc = cv2.VideoWriter_fourcc(*'MJPG')
            if fileNameVid != "":
                try:
                    out = cv2.VideoWriter(fileNameVid, fourcc, 9.0, (640, 480),
                                          True)
                    print('past out')
                    for i in range(frame, editLastFrame):
                        print('frame' + str(i))
                        frameForVid = self.grabDataFrame()
                        out.write(frameForVid)
                        if frame <= editLastFrame:
                            frame += framerate
                        else:
                            print('You are at Last Frame')
                    out.release()
                    print('out release')
                    print('Saved Video As ' + str(fileNameVid))
                    self.history.insertPlainText('SUCCESS: Saved Video\n')
                    self.history.moveCursor(QTextCursor.End)
                except:
                    self.history.insertPlainText(
                        'No AVI Video Generated\n Did Not Specify Proper FileName\n'
                    )
                    self.history.moveCursor(QTextCursor.End)
                    print('Did Not Specify Proper FileName')
                    print('No AVI Video Generated')
            else:
                self.history.insertPlainText(
                    'No AVI Video Generated\n Did Not Specify Proper FileName\n'
                )
                self.history.moveCursor(QTextCursor.End)
                print('Did Not Specify Proper FileName')
                print('No AVI Video Generated')

    def saveCvImage(self):
        global fileSelected
        global videoState
        videoState = 'pause'
        if fileSelected != "":
            dlg = QFileDialog()
            #dlg.setNameFilter('PNG files (*.png)')
            dlg.setDefaultSuffix('.png')
            fileNameImage = dlg.getSaveFileName(
                self.w,
                'Navigate to Directory and Choose a File Name to Save To',
                'untitled.png', 'PNG Image (*.png)')
            if fileNameImage != "":
                try:
                    print(fileNameImage)
                    cv2.imwrite(str(fileNameImage), self.grabDataFrame())
                    print('Saved frame ' + str(frame) + ' as .png')
                    self.history.insertPlainText('SUCCESS: Saved Frame: ' +
                                                 str(frame) + ' as PNG\n')
                    self.history.moveCursor(QTextCursor.End)
                except:
                    self.history.insertPlainText(
                        'No PNG Image Generated\n Did Not Specify Proper FileName\n'
                    )
                    self.history.moveCursor(QTextCursor.End)
                    print('Did Not Specify Proper FileName')
                    print('No PNG Image Generated')
            else:
                self.history.insertPlainText(
                    'No PNG Image Generated\n Did Not Specify Proper FileName\n'
                )
                self.history.moveCursor(QTextCursor.End)
                print('Did Not Specify Proper FileName')
                print('No PNG Image Generated')

    def makeTiff2(self):
        global lastFrame
        global fileSelected
        global videoState
        videoState = 'pause'
        if fileSelected != "":
            dlgTiff = QFileDialog()
            #dlg.setNameFilter('PNG files (*.png)')
            dlgTiff.setDefaultSuffix('.tiff')
            fileNameTiff = dlgTiff.getSaveFileName(
                self.w,
                'Navigate to Directory and Choose a File Name to Save To',
                'untitled.tiff', 'TIFF File (*.tiff)')
            print(fileNameTiff)
            if fileNameTiff != "":
                self.history.insertPlainText('File Name Selected\n')
                self.history.moveCursor(QTextCursor.End)
                print('Collecting Data Frames...')
                for i in range(1, lastFrame):
                    #print('Frame to Tiff: ' + str(i))
                    data = self.f_read[('image' + str(i))][:]
                    if i == 1:
                        dataCollection = data
                    else:
                        dataCollection = np.dstack((dataCollection, data))
                    i += 1
                    if i == lastFrame / 2:
                        print('Half Way Through File...')
                print('Completed Collecting All Data Frames')
                try:
                    imsave((str(fileNameTiff)), dataCollection)
                    print('Saved Tiff As ' + str(fileNameTiff))
                    self.history.insertPlainText(' Saved Tiff\n')
                    self.history.moveCursor(QTextCursor.End)
                except:
                    self.history.insertPlainText(
                        'No Tiff File Generated\n Did Not Specify Proper FileName\n'
                    )
                    self.history.moveCursor(QTextCursor.End)
                    print('Did Not Specify Proper FileName')
                    print('No Tiff File Generated')
            else:
                self.history.insertPlainText(
                    'No Tiff File Generated\n Did Not Specify Proper FileName\n'
                )
                self.history.moveCursor(QTextCursor.End)
                print('Did Not Specify Proper FileName')
                print('No Tiff File Generated')

    def grabTempValue(self):
        global frame
        global lastFrame
        global fileSelected
        global xMouse
        global yMouse
        data = self.f_read[('image' + str(frame))][:]
        data = cv2.resize(data[:, :], (640, 480))
        return data[yMouse, xMouse]

    def on_press(self, event):
        global xMouse
        global yMouse
        global cursorVal
        #print('you pressed', event.button, event.xdata, event.ydata)
        xMouse = event.xdata
        yMouse = event.ydata
        cursorVal = self.grabTempValue()
        self.cursorTempLabel.setText('Cursor Temp: ' +
                                     readTemp(toggleUnitState, 'none'))

    def hover(self, event):
        global xMouse
        global yMouse
        global cursorVal
        #print('you pressed', event.button, event.xdata, event.ydata)
        if event.xdata != None:
            xMouse = int(round(event.xdata))
            yMouse = int(round(event.ydata))
            cursorVal = int(round(self.grabTempValue()))
            #if xMouse > 1 and xMouse < 640 and yMouse > 0 and yMouse < 480:
            self.cursorTempLabel.setText('Cursor Temp: ' +
                                         readTemp(toggleUnitState, 'none'))
            #else:
            #self.cursorTempLabel.setText('Cursor Temp: MOVE CURSOR OVER IMAGE')
        else:
            #print('MOVE CURSOR OVER IMAGE')
            self.cursorTempLabel.setText('Cursor Temp: MOVE CURSOR OVER IMAGE')

    def displayTempValues(self):
        global fileSelected
        global toggleUnitState
        if fileSelected != "":
            self.maxTempLabel.setText('Current Max Temp: ' +
                                      readTemp(toggleUnitState, 'max'))
            self.maxTempLocLabel.setText('Max Temp Loc: ' + str(maxLoc))
            self.minTempLabel.setText('Current Min Temp: ' +
                                      readTemp(toggleUnitState, 'min'))
            self.minTempLocLabel.setText('Min Temp Loc: ' + str(minLoc))

    def grabDataFrame(self):
        global frame
        global lastFrame
        global fileSelected
        #print('Display Image at Frame: ' + str(frame))
        data = self.f_read[('image' + str(frame))][:]
        data = cv2.resize(data[:, :], (640, 480))
        img = cv2.LUT(raw_to_8bit(data), generate_colour_map())
        img2 = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        rgbImage = cv2.cvtColor(img2, cv2.COLOR_BGR2RGB)
        return (rgbImage)

    def play(self):
        global frame
        global editLastFrame
        global fileSelected
        global videoState
        self.history.insertPlainText('Play Video\n')
        self.history.moveCursor(QTextCursor.End)
        #print(self.startEdit.text())
        if self.startEdit.isModified():
            frame = int(self.startEdit.text())
            print('Starting at Frame: ' + self.startEdit.text())
        if self.stopEdit.isModified():
            editLastFrame = int(self.stopEdit.text())
        if fileSelected != "":
            self.timer.start()
            videoState = 'play'

    def pauseVideo(self):
        global videoState
        self.history.insertPlainText('Paused Video\n')
        self.history.moveCursor(QTextCursor.End)
        videoState = 'pause'

    def playVid5(self):
        global videoState
        global frame
        global lastFrame
        global editLastFrame
        if videoState == 'play':
            if editLastFrame <= lastFrame:
                if frame <= editLastFrame:
                    self.sl.setValue(frame)
                    if frame != lastFrame:
                        frame += 1
                    #print('playing video')
                else:
                    print('You are at Stop Frame')
                    videoState = 'pause'
            else:
                print('You are at Last Frame')
                videoState = 'pause'

    def dispNextImg(self):
        global frame
        global lastFrame
        global framerate
        global fileSelected
        global videoState
        videoState = 'pause'
        self.history.insertPlainText('Next Frame: ' + str(frame) + '\n')
        self.history.moveCursor(QTextCursor.End)
        if fileSelected != "":
            if lastFrame > frame:
                frame += framerate
            else:
                print('You are at Last Frame')
            #self.dispImg()
            #self.canvas.draw()
            self.sl.setValue(frame)

    def dispPrevImg(self):
        global frame
        global fileSelected
        global videoState
        self.history.insertPlainText('Previous Frame: ' + str(frame) + '\n')
        self.history.moveCursor(QTextCursor.End)
        videoState = 'pause'
        if fileSelected != "":
            if frame > 1:
                frame -= 1
            else:
                print('You are at First Frame')
            #self.dispImg()
            #self.canvas.draw()
            self.sl.setValue(frame)

    def dispImg(self):
        global frame
        global lastFrame
        global fileSelected
        global maxVal
        global minVal
        global maxLoc
        global minLoc
        #if frame > 1:
        #self.cb.remove()
        #print('Display Image at Frame: ' + str(frame))
        self.currentFrameDisp.setText('Current Frame: ' + str(frame))
        data = self.f_read[('image' + str(frame))][:]
        data = cv2.resize(data[:, :], (640, 480))
        minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(data)
        img = cv2.LUT(raw_to_8bit(data), generate_colour_map())
        rgbImage = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        self.ax = self.figure.add_subplot(111)
        self.ax.clear()
        #cmap = mpl.cm.cool
        #norm = mpl.colors.Normalize(vmin=5, vmax=10)
        #print('Ran dispImg')
        #print(frame)
        if frame == 1:
            self.figure.tight_layout()
        #colorVals = cm.get_clim(rgbImage)
        #print(colorVals)
        #cax = self.figure.add_axes([0.2, 0.08, 0.6, 0.04])
        #self.figure.colorbar(rgbImage, cax, orientation='horizontal')
        self.cax = self.ax.imshow(rgbImage)
        #self.cb = self.figure.colorbar(self.cax)
        lastFrame = len(self.f_read)
        self.sl.setValue(frame)
        self.displayTempValues()
        self.currentTimeLabel.setText('Current Time: ' +
                                      str(round(((frame - 1) / 9.00), 2)))
        cid = self.canvas.mpl_connect('motion_notify_event', self.hover)

    def enableThings(self):
        self.playVidBut.setEnabled(True)
        self.pauseVidBut.setEnabled(True)
        self.nextFrame.setEnabled(True)
        self.prevFrame.setEnabled(True)
        self.startEdit.setEnabled(True)
        self.stopEdit.setEnabled(True)
        self.saveAsVideoSS.setEnabled(True)
        self.saveCvImageBut.setEnabled(True)
        self.makeTiffBut.setEnabled(True)
        self.displayC.setEnabled(True)
        self.displayF.setEnabled(True)

    def getFile(self):
        global frame
        global fileSelected
        global editLastFrame
        global lastFrame
        #self.pauseVideo()
        fileSelected = ""
        fileSelected = QFileDialog.getOpenFileName(self.w, 'Open File', '/')
        print(fileSelected)
        #fileTypes = ['hdf5','HDF5','HD5F','hd5f']
        if fileSelected != "":
            #if any(x in fileSelected for x in fileTypes):
            try:
                self.dispSelectedFile.setText(fileSelected)
                self.f_read = h5py.File(str(fileSelected), 'r')
                self.dispImg()
                self.enableThings()
                self.setSlider()
                editLastFrame = lastFrame
                self.startEdit.setText(str(frame))
                self.stopEdit.setText(str(lastFrame))
                self.history.insertPlainText(
                    'Selected File and Displayed First Frame\n')
                self.history.moveCursor(QTextCursor.End)
                print('Selected File and Displayed First Frame')
                self.canvas.draw()
            #else:
            except:
                self.history.insertPlainText(
                    'ERROR: Incorrect File Type Selected\n Please select .HDF5 File\n'
                )
                self.history.moveCursor(QTextCursor.End)
                print(
                    'Incorrect File Type Selected. Please select .HDF5 File.')
        else:
            self.history.insertPlainText(
                'ERROR: Incorrect File Type Selected\n Please select .HDF5 File\n'
            )
            self.history.moveCursor(QTextCursor.End)
            print('Incorrect File Type Selected. Please select .HDF5 File.')
Example #34
0
def multi_mode(cli_parsed):
    dbm = db_manager.DB_Manager(cli_parsed.d + '/ew.db')
    dbm.open_connection()
    if not cli_parsed.resume:
        dbm.initialize_db()
    dbm.save_options(cli_parsed)
    m = Manager()
    targets = m.Queue()
    lock = m.Lock()
    multi_counter = m.Value('i', 0)
    display = None

    def exitsig(*args):
        dbm.close()
        if current_process().name == 'MainProcess':
            print ''
            print 'Resume using ./EyeWitness.py --resume {0}'.format(
                cli_parsed.d + '/ew.db')
        os._exit(1)

    signal.signal(signal.SIGINT, exitsig)
    if cli_parsed.resume:
        pass
    else:
        url_list, rdp_list, vnc_list = target_creator(cli_parsed)
        if any((cli_parsed.web, cli_parsed.headless)):
            for url in url_list:
                dbm.create_http_object(url, cli_parsed)
        for rdp in rdp_list:
            dbm.create_vnc_rdp_object('rdp', rdp, cli_parsed)
        for vnc in vnc_list:
            dbm.create_vnc_rdp_object('vnc', vnc, cli_parsed)

    if any((cli_parsed.web, cli_parsed.headless)):
        if cli_parsed.web and not cli_parsed.show_selenium:
            display = Display(visible=0, size=(1920, 1080))
            display.start()

        multi_total = dbm.get_incomplete_http(targets)
        if multi_total > 0:
            if cli_parsed.resume:
                print 'Resuming Web Scan ({0} Hosts Remaining)'.format(
                    str(multi_total))
            else:
                print 'Starting Web Requests ({0} Hosts)'.format(
                    str(multi_total))

        if multi_total < cli_parsed.threads:
            num_threads = multi_total
        else:
            num_threads = cli_parsed.threads
        for i in xrange(num_threads):
            targets.put(None)
        try:
            workers = [
                Process(target=worker_thread,
                        args=(cli_parsed, targets, lock, (multi_counter,
                                                          multi_total)))
                for i in xrange(num_threads)
            ]
            for w in workers:
                w.start()
            for w in workers:
                w.join()
        except Exception as e:
            print str(e)

        # Set up UA table here
        if cli_parsed.cycle is not None:
            ua_dict = get_ua_values(cli_parsed.cycle)
            if not cli_parsed.ua_init:
                dbm.clear_table("ua")
                completed = dbm.get_complete_http()
                completed[:] = [x for x in completed if x.error_state is None]
                for item in completed:
                    for browser, ua in ua_dict.iteritems():
                        dbm.create_ua_object(item, browser, ua)

                cli_parsed.ua_init = True
                dbm.clear_table("opts")
                dbm.save_options(cli_parsed)

            for browser, ua in ua_dict.iteritems():
                targets = m.Queue()
                multi_counter.value = 0
                multi_total = dbm.get_incomplete_ua(targets, browser)
                if multi_total > 0:
                    print(
                        "[*] Starting requests for User Agent {0}"
                        " ({1} Hosts)").format(browser, str(multi_total))
                if multi_total < cli_parsed.threads:
                    num_threads = multi_total
                else:
                    num_threads = cli_parsed.threads
                for i in xrange(num_threads):
                    targets.put(None)
                workers = [
                    Process(target=worker_thread,
                            args=(cli_parsed, targets, lock,
                                  (multi_counter, multi_total), (browser, ua)))
                    for i in xrange(num_threads)
                ]
                for w in workers:
                    w.start()
                for w in workers:
                    w.join()

    if any((cli_parsed.vnc, cli_parsed.rdp)):
        log._LOG_LEVEL = log.Level.ERROR
        multi_total, targets = dbm.get_incomplete_vnc_rdp()
        if multi_total > 0:
            print ''
            print 'Starting VNC/RDP Requests ({0} Hosts)'.format(
                str(multi_total))

            app = QtGui.QApplication(sys.argv)
            timer = QTimer()
            timer.start(10)
            timer.timeout.connect(lambda: None)

            # add qt4 reactor
            import qt4reactor
            qt4reactor.install()
            from twisted.internet import reactor

            for target in targets:
                if os.path.dirname(cli_parsed.d) != os.path.dirname(
                        target.screenshot_path):
                    target.set_paths(cli_parsed.d)
                tdbm = db_manager.DB_Manager(cli_parsed.d + '/ew.db')
                if target.proto == 'vnc':
                    reactor.connectTCP(
                        target.remote_system, target.port,
                        vnc_module.RFBScreenShotFactory(
                            target.screenshot_path, reactor, app, target,
                            tdbm))
                else:
                    reactor.connectTCP(
                        target.remote_system, int(target.port),
                        rdp_module.RDPScreenShotFactory(
                            reactor, app, 1200, 800, target.screenshot_path,
                            cli_parsed.timeout, target, tdbm))
            reactor.runReturn()
            app.exec_()

    if display is not None:
        display.stop()
    results = dbm.get_complete_http()
    vnc_rdp = dbm.get_complete_vnc_rdp()
    dbm.close()
    m.shutdown()
    write_vnc_rdp_data(cli_parsed, vnc_rdp)
    sort_data_and_write(cli_parsed, results)
Example #35
0
class DualRelay(PluginBase, Ui_DualRelay):
    qtcb_monoflop = pyqtSignal(int, bool)

    def __init__(self, *args):
        PluginBase.__init__(self, BrickletDualRelay, *args)

        self.setupUi(self)

        self.dr = self.device

        self.has_monoflop = self.firmware_version >= (1, 1, 1)

        self.qtcb_monoflop.connect(self.cb_monoflop)
        self.dr.register_callback(self.dr.CALLBACK_MONOFLOP_DONE,
                                  self.qtcb_monoflop.emit)

        self.dr1_button.clicked.connect(self.dr1_clicked)
        self.dr2_button.clicked.connect(self.dr2_clicked)

        self.go1_button.clicked.connect(self.go1_clicked)
        self.go2_button.clicked.connect(self.go2_clicked)

        self.r1_monoflop = False
        self.r2_monoflop = False

        self.r1_timebefore = 500
        self.r2_timebefore = 500

        self.a1_pixmap = load_masked_pixmap(
            'plugin_system/plugins/dual_relay/relay_a1.bmp')
        self.a2_pixmap = load_masked_pixmap(
            'plugin_system/plugins/dual_relay/relay_a2.bmp')
        self.b1_pixmap = load_masked_pixmap(
            'plugin_system/plugins/dual_relay/relay_b1.bmp')
        self.b2_pixmap = load_masked_pixmap(
            'plugin_system/plugins/dual_relay/relay_b2.bmp')

        self.update_timer = QTimer()
        self.update_timer.timeout.connect(self.update)
        self.update_timer.setInterval(50)

        if not self.has_monoflop:
            self.go1_button.setText("Go (FW Versiom >= 1.1.1 required)")
            self.go2_button.setText("Go (FW Versiom >= 1.1.1 required)")
            self.go1_button.setEnabled(False)
            self.go2_button.setEnabled(False)

    def get_state_async(self, state):
        width = self.dr1_button.width()
        if self.dr1_button.minimumWidth() < width:
            self.dr1_button.setMinimumWidth(width)

        width = self.dr2_button.width()
        if self.dr2_button.minimumWidth() < width:
            self.dr2_button.setMinimumWidth(width)

        dr1, dr2 = state
        if dr1:
            self.dr1_button.setText('Switch Off')
            self.dr1_image.setPixmap(self.a1_pixmap)
        else:
            self.dr1_button.setText('Switch On')
            self.dr1_image.setPixmap(self.b1_pixmap)
        if dr2:
            self.dr2_button.setText('Switch Off')
            self.dr2_image.setPixmap(self.a2_pixmap)
        else:
            self.dr2_button.setText('Switch On')
            self.dr2_image.setPixmap(self.b2_pixmap)

    def get_monoflop_async(self, monoflop, index):
        state, time, time_remaining = monoflop
        if index == 1:
            if time > 0:
                self.r1_timebefore = time
                self.time1_spinbox.setValue(self.r1_timebefore)
            if time_remaining > 0:
                if not state:
                    self.state1_combobox.setCurrentIndex(0)
                self.r1_monoflop = True
                self.time1_spinbox.setEnabled(False)
                self.state1_combobox.setEnabled(False)
        elif index == 2:
            state, time, time_remaining = self.dr.get_monoflop(2)
            if time > 0:
                self.r2_timebefore = time
                self.time2_spinbox.setValue(self.r2_timebefore)
            if time_remaining > 0:
                if not state:
                    self.state2_combobox.setCurrentIndex(1)
                self.r2_monoflop = True
                self.time2_spinbox.setEnabled(False)
                self.state2_combobox.setEnabled(False)

    def start(self):
        async_call(self.dr.get_state, None, self.get_state_async,
                   self.increase_error_count)
        if self.has_monoflop:
            async_call(self.dr.get_monoflop, 1,
                       lambda x: self.get_monoflop_async(x, 1),
                       self.increase_error_count)
            async_call(self.dr.get_monoflop, 2,
                       lambda x: self.get_monoflop_async(x, 2),
                       self.increase_error_count)
            self.update_timer.start()

    def stop(self):
        self.update_timer.stop()

    def destroy(self):
        pass

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletDualRelay.DEVICE_IDENTIFIER

    def get_state_dr1_clicked(self, state):
        dr1, dr2 = state

        try:
            self.dr.set_state(not dr1, dr2)
        except ip_connection.Error:
            return

        self.r1_monoflop = False
        self.time1_spinbox.setValue(self.r1_timebefore)
        self.time1_spinbox.setEnabled(True)
        self.state1_combobox.setEnabled(True)

    def dr1_clicked(self):
        width = self.dr1_button.width()
        if self.dr1_button.minimumWidth() < width:
            self.dr1_button.setMinimumWidth(width)

        if 'On' in self.dr1_button.text():
            self.dr1_button.setText('Switch Off')
            self.dr1_image.setPixmap(self.a1_pixmap)
        else:
            self.dr1_button.setText('Switch On')
            self.dr1_image.setPixmap(self.b1_pixmap)

        async_call(self.dr.get_state, None, self.get_state_dr1_clicked,
                   self.increase_error_count)

    def get_state_dr2_clicked(self, state):
        dr1, dr2 = state

        try:
            self.dr.set_state(dr1, not dr2)
        except ip_connection.Error:
            return

        self.r2_monoflop = False
        self.time2_spinbox.setValue(self.r2_timebefore)
        self.time2_spinbox.setEnabled(True)
        self.state2_combobox.setEnabled(True)

    def dr2_clicked(self):
        width = self.dr2_button.width()
        if self.dr2_button.minimumWidth() < width:
            self.dr2_button.setMinimumWidth(width)

        if 'On' in self.dr2_button.text():
            self.dr2_button.setText('Switch Off')
            self.dr2_image.setPixmap(self.a2_pixmap)
        else:
            self.dr2_button.setText('Switch On')
            self.dr2_image.setPixmap(self.b2_pixmap)

        async_call(self.dr.get_state, None, self.get_state_dr2_clicked,
                   self.increase_error_count)

    def go1_clicked(self):
        time = self.time1_spinbox.value()
        state = self.state1_combobox.currentIndex() == 0
        try:
            if self.r1_monoflop:
                time = self.r1_timebefore
            else:
                self.r1_timebefore = self.time1_spinbox.value()

            self.dr.set_monoflop(1, state, time)

            self.r1_monoflop = True
            self.time1_spinbox.setEnabled(False)
            self.state1_combobox.setEnabled(False)

            if state:
                self.dr1_button.setText('Switch Off')
                self.dr1_image.setPixmap(self.a1_pixmap)
            else:
                self.dr1_button.setText('Switch On')
                self.dr1_image.setPixmap(self.b1_pixmap)
        except ip_connection.Error:
            return

    def go2_clicked(self):
        time = self.time2_spinbox.value()
        state = self.state2_combobox.currentIndex() == 0
        try:
            if self.r2_monoflop:
                time = self.r2_timebefore
            else:
                self.r2_timebefore = self.time2_spinbox.value()

            self.dr.set_monoflop(2, state, time)

            self.r2_monoflop = True
            self.time2_spinbox.setEnabled(False)
            self.state2_combobox.setEnabled(False)

            if state:
                self.dr2_button.setText('Switch Off')
                self.dr2_image.setPixmap(self.a2_pixmap)
            else:
                self.dr2_button.setText('Switch On')
                self.dr2_image.setPixmap(self.b2_pixmap)
        except ip_connection.Error:
            return

    def cb_monoflop(self, relay, state):
        if relay == 1:
            self.r1_monoflop = False
            self.time1_spinbox.setValue(self.r1_timebefore)
            self.time1_spinbox.setEnabled(True)
            self.state1_combobox.setEnabled(True)
            if state:
                self.dr1_button.setText('Switch Off')
                self.dr1_image.setPixmap(self.a1_pixmap)
            else:
                self.dr1_button.setText('Switch On')
                self.dr1_image.setPixmap(self.b1_pixmap)
        else:
            self.r2_monoflop = False
            self.time2_spinbox.setValue(self.r2_timebefore)
            self.time2_spinbox.setEnabled(True)
            self.state2_combobox.setEnabled(True)
            if state:
                self.dr2_button.setText('Switch Off')
                self.dr2_image.setPixmap(self.a2_pixmap)
            else:
                self.dr2_button.setText('Switch On')
                self.dr2_image.setPixmap(self.b2_pixmap)

    def update_time_remaining(self, relay, time_remaining):
        if relay == 1:
            if self.r1_monoflop:
                self.time1_spinbox.setValue(time_remaining)
        elif relay == 2:
            if self.r2_monoflop:
                self.time2_spinbox.setValue(time_remaining)

    def update(self):
        if self.r1_monoflop:
            try:
                async_call(self.dr.get_monoflop, 1,
                           lambda a: self.update_time_remaining(1, a[2]),
                           self.increase_error_count)
            except ip_connection.Error:
                pass
        if self.r2_monoflop:
            try:
                async_call(self.dr.get_monoflop, 2,
                           lambda a: self.update_time_remaining(2, a[2]),
                           self.increase_error_count)
            except ip_connection.Error:
                pass
Example #36
0
class View(QtGui.QMainWindow, gui.Ui_Form):
    
    # Signals
    game = pyqtSignal()

    def __init__(self):
        super(self.__class__, self).__init__()

        self.setupUi(self)

        self.time1.setValue(1)
        self.time2.setValue(1)
        self.time1.setMaximum(1)
        self.time2.setMaximum(1)

        self.timer = QTimer(self)
        self.timer.timeout.connect(self.run)
        self.timer.start(1)  # Bei Autostart wirklich 1 ms da kein System im Hintergrund ist

        self.logo.setPixmap(QtGui.QPixmap("/home/pi/Public/bilder/logoS.png"))
        self.logoR.setPixmap(QtGui.QPixmap("/home/pi/Public/bilder/logo.png"))
        self.hintergrund.setPixmap(QtGui.QPixmap("/home/pi/Public/bilder/bg.png"))
        
        
    # Slot
    @pyqtSlot()
    def run(self):
        global mode
        global videoStart
        global explainTextStep
        global startGame
        if mode is 0:  # Savemode
            """
            Hier werden alle Werte zurück gesetzt
            """
            videoStart = True
            setInterrupt(13)
            explainTextStep = 0
            startGame = False
            self.startBildschirm.setVisible(True)
            mode = 1
        elif mode is 1:  # Startbildschirm
            pass
        elif mode is 2:  # Übergang Erklärphase
            removeInterrupt(13)
            setInterrupt(11)            
            self.startBildschirm.setVisible(False)
            self.sensorTexte.setVisible(True)
            mode = 3
        elif mode is 3:  # Erklärphase
            """
            Text anzeigen durch "explainTextStep"
            """
            if explainTextStep is 5:
                if not startGame:
                    startGame = True
                    setInterrupt(13)
                    removeInterrupt(11)
                    self.text.setText("Start Game")
            # Texte Anzeigen lassen
            else:
                self.text.setText(str(explainTextStep))
            pass
        elif mode is 4:  # Übergang Spielphase
            removeInterrupt(11)
            removeInterrupt(13)
            self.sensorTexte.setVisible(False)
            self.startBildschirm.setVisible(False)
            mode = 5
        elif mode is 5:  # Spielphase
            if videoStart:
                self.player = OMXPlayer('/home/pi/Public/Videos/teil1Neu.mp4')        
                self.time1.setMaximum(int(self.player.duration()))
                self.time2.setMaximum(int(self.player.duration()))
                self.player.set_video_pos(260, 300, 1690, 1080)
                videoStart = False
            if self.player.is_playing():                
                restTime = int(self.player.duration())-int(self.player.position())
                self.time1.setValue(restTime)
                self.time2.setValue(restTime)
                pass
                # Spielläuft
            else:
                # Spielfertig
                self.player.quit()
                mode = 0
        else:
            pass
Example #37
0
class EventEngine(object):
    """事件驱动引擎

    事件驱动引擎中所有的变量都设置为了私有,这是为了防止不小心
    从外部修改了这些变量的值或状态,导致bug。

    变量说明
    __queue:私有变量,事件队列
    __active:私有变量,事件引擎开关
    __thread:私有变量,事件处理线程
    __timer:私有变量,计时器
    __handlers:私有变量,事件处理函数字典

    方法说明
    __run: 私有方法,事件处理线程连续运行用
    __process: 私有方法,处理事件,调用注册在引擎中的监听函数
    __onTimer:私有方法,计时器固定事件间隔触发后,向事件队列中存入计时器事件
    start: 公共方法,启动引擎
    stop:公共方法,停止引擎
    register:公共方法,向引擎中注册监听函数
    unregister:公共方法,向引擎中注销监听函数
    put:公共方法,向事件队列中存入新的事件

    事件监听函数必须定义为输入参数仅为一个event对象,即:

    函数
    def func(event)

    对象方法
    def method(self, event)

    """

    # --------------------------------
    def __init__(self):
        # 事件队列
        self.__queue = Queue()
        # 事件引擎开关
        self.__active = False
        # 事件处理线程
        self.__thread = Thread(target=self.__run)
        # 计时器,用于触发计时器事件
        self.__timer = QTimer()
        self.__timer.timeout.connect(self.__onTimer)
        # __handlers在这里是一个字典,用于保存对应的事件调用关系
        # 其中每个键对应的值是一个列表,列表中保存了对该事件进行监听的函数
        self.__handlers = {}

    # --------------------------------
    def __run(self):
        """引擎运行"""
        while self.__active == True:
            try:
                event = self.__queue.get(block=True,
                                         timeout=1)  # 获取事件的阻塞时间设为1秒
                self.__process(event)
            except Empty:
                pass

    # --------------------------
    def __process(self, event):
        """处理事件"""
        # 检查是否存在对该事件进行监听的处理函数
        print self.__queue
        if event.type_ in self.__handlers:
            # 若存在,则按顺序将事件传递给处理函数执行
            [handler(event) for handler in self.__handlers[event.type_]]

    # ----------------------------------
    def __onTimer(self):
        """向事件队列中存入计时器事件"""
        # 创建计时器事件
        event = Event(type_=EVENT_TIMER)
        # 向队列中存入计时器事件
        self.put(event)

    # ---------------------------------------
    def start(self):
        """引擎启动"""
        # 将引擎设为启动
        self.__active = True
        # 启动事件处理线程
        self.__thread.start()
        # 启动计时器,计时器时间间隔默认设为0.6秒
        self.__timer.start(600)

    # ---------------------------
    def stop(self):
        """停止引擎"""
        # 将引擎设为停止
        self.__active = False
        # 停止计时器
        self.__timer.stop()
        # 等待事件处理线程退出
        self.__thread.join()

    # -----------------------------------------
    def register(self, type_, handler):
        """注册事件处理函数监听"""
        # 尝试获取该事件类型对应的处理函数列表,若无则创建
        try:
            handlerList = self.__handlers[type_]
        except KeyError:
            handlerList = []
            self.__handlers[type_] = handlerList
        # 若要注册的处理器不在该事件的处理器列表中,则注册该事件
        if handler not in handlerList:
            handlerList.append(handler)
            # print 'handlerList'
            # print handlerList

    # ----------------------------
    def unregister(self, type_, handler):
        """注销事件处理函数监听"""
        try:
            handlerList = self.__handlers[type_]
            # 如果该函数存在于列表中,则移除
            if handler in handlerList:
                handlerList.remove(handler)
            # 如果函数列表为空,则从引擎中移除该事件类型
            if not handlerList:
                del self.__handlers[type_]
        except KeyError:
            pass

    # ---------------------------------------
    def put(self, event):
        """向事件队列中存入事件"""
        self.__queue.put(event)
    def __init__(self, parent=None):
        """
        Args:
            parent:
        """
        super(AnalogGaugeWidget, self).__init__(parent)

        self.use_timer_event = False
        self.black = QColor(0, 0, 0, 255)

        # self.valueColor = QColor(50, 50, 50, 255)
        # self.set_valueColor(50, 50, 50, 255)
        # self.NeedleColor = QColor(50, 50, 50, 255)
        self.set_NeedleColor(50, 50, 50, 255)
        self.NeedleColorReleased = self.NeedleColor
        # self.NeedleColorDrag = QColor(255, 0, 00, 255)
        self.set_NeedleColorDrag(255, 0, 00, 255)

        self.set_ScaleValueColor(50, 50, 50, 255)
        self.set_DisplayValueColor(50, 50, 50, 255)

        # self.CenterPointColor = QColor(50, 50, 50, 255)
        self.set_CenterPointColor(50, 50, 50, 255)

        # self.valueColor = black
        # self.black = QColor(0, 0, 0, 255)

        self.value_needle_count = 1
        self.value_needle = QObject
        self.change_value_needle_style([
            QPolygon([
                QPoint(4, 4),
                QPoint(-4, 4),
                QPoint(-3, -120),
                QPoint(0, -126),
                QPoint(3, -120)
            ])
        ])

        self.value_min = 0
        self.value_max = 1000
        self.value = self.value_min
        self.value_offset = 0
        self.value_needle_snapzone = 0.05
        self.last_value = 0

        # self.value2 = 0
        # self.value2Color = QColor(0, 0, 0, 255)

        self.gauge_color_outer_radius_factor = 1
        self.gauge_color_inner_radius_factor = 0.95
        self.center_horizontal_value = 0
        self.center_vertical_value = 0
        self.debug1 = None
        self.debug2 = None
        self.scale_angle_start_value = 135
        self.scale_angle_size = 270
        self.angle_offset = 0

        # self.scala_main_count = 10
        self.set_scala_main_count(10)
        self.scala_subdiv_count = 5

        self.pen = QPen(QColor(0, 0, 0))
        self.font = QFont('Decorative', 20)

        self.scale_polygon_colors = []
        self.set_scale_polygon_colors([[.00, Qt.red], [.1, Qt.yellow],
                                       [.15, Qt.green], [1, Qt.transparent]])

        # initialize Scale value text
        # self.enable_scale_text = True
        self.set_enable_ScaleText(True)
        self.scale_fontname = "Decorative"
        self.initial_scale_fontsize = 15
        self.scale_fontsize = self.initial_scale_fontsize

        # initialize Main value text
        self.enable_value_text = True
        self.value_fontname = "Decorative"
        self.initial_value_fontsize = 40
        self.value_fontsize = self.initial_value_fontsize
        self.text_radius_factor = 0.7

        # En/disable scale / fill
        # self.enable_barGraph = True
        self.set_enable_barGraph(True)
        # self.enable_filled_Polygon = True
        self.set_enable_filled_Polygon(True)

        self.enable_CenterPoint = True
        self.enable_fine_scaled_marker = True
        self.enable_big_scaled_marker = True

        self.needle_scale_factor = 0.8
        self.enable_Needle_Polygon = True

        # necessary for resize
        self.setMouseTracking(False)

        # QTimer sorgt für neu Darstellung alle X ms
        # evtl performance hier verbessern mit self.update() und self.use_timer_event = False
        # todo: self.update als default ohne ueberpruefung, ob self.use_timer_event gesetzt ist oder nicht
        # Timer startet alle 10ms das event paintEvent
        if self.use_timer_event:
            timer = QTimer(self)
            timer.timeout.connect(self.update)
            timer.start(10)
        else:
            self.update()

        self.setWindowTitle("Analog Gauge")

        # self.connect(self, SIGNAL("resize()"), self.rescaleMethod)

        # self.resize(300 , 300)
        self.rescale_method()
Example #39
0
class Listener(QWidget):
    def __init__(self, core_file_name):
        super(Listener, self).__init__()
        self.core_file_name = core_file_name

        self.setup_ui()
        self.setup_timers()

        port = SERIAL_PORT
        self.serial = serial.Serial(port, BAUDE_RATE, timeout=0)
        self.incoming_data = []

        self.imu = IMU(PLATFORM_SPECIFIC_QUOTIENTS['stm'])
        self.stroke = Stroke()
        self.selector = Selector(self.core_file_name)

        self.acceleration_filter = AperiodicFilter(ACCELERATION_TIME_CONST)

        self.stroke.widget = self.display
        self.stroke.on_done = self.get_stroke

        self.previous_time = None

        self.data_buffer = ''

        self.init_selector()


    def setup_ui(self):
        self.resize(500, 500)
        self.out = QLabel(self)
        self.out.setMinimumHeight(100)
        font = QFont()
        font.setPixelSize(80)
        self.out.setFont(font)
        self.grid = QGridLayout(self)
        self.display = StrokeWidget()
        self.letter_selector = QComboBox()
        self.grid.addWidget(self.display, 0, 0, 1, 1)
        self.grid.addWidget(self.letter_selector, 1, 0, 1, 1)
        self.grid.addWidget(self.out, 2, 0, 1, 1)

    def setup_timers(self):
        self.serial_timer = QTimer()
        self.serial_timer.setInterval(SERIAL_INTERVAL)
        self.serial_timer.timeout.connect(self.get_data)
        self.serial_timer.start()

        self.process_timer = QTimer()
        self.process_timer.setInterval(PROCESS_INTERVAL)
        self.process_timer.timeout.connect(self.process)
        self.process_timer.start()

        self.display_timer = QTimer()
        self.display_timer.setInterval(DISPLAY_TIMEOUT)
        self.display_timer.setSingleShot(True)
        self.display_timer.timeout.connect(self.set_background)


    def init_selector(self):
        sel_lines = self.selector.letters_dict.keys()
        sel_lines.insert(0, 'new strokes')
        sel_lines.insert(0, 'free run')
        self.letter_selector.addItems(sel_lines)
        self.letter_selector.currentIndexChanged.connect(self.set_background)

    def set_background(self):
        letter = str(self.letter_selector.currentText())
        self.display.set_background(self.core_file_name, letter)

    def store_stroke(self, key, stroke, existing=True):
        file_name = '{key}{time}.txt'.format(key=key, time=int(time()))
        file_path = os.path.join(LEARNED_FOLDER, file_name)
        np.savetxt(file_path, stroke)
        if existing:
            self.display.set_background(self.core_file_name, key, color='g')
            self.display_timer.start()        

    def get_stroke(self, data):
        stroke = data['stroke']
        dimention = data['dimention']
        if dimention < MIN_DIMENTION:
            print 'too small'
            return

        letter = str(self.letter_selector.currentText())
        if letter == 'new strokes':
            self.store_stroke('_', stroke, existing=False)
            print 'recorded'

        try:
            letters = self.selector.check_stroke(stroke)
        except: #TODO: check unify_stroke
            return

        if letters:
            self.out.setText(self.out.text()+letters[0])

        if letter == 'free run' and letters:
            self.store_stroke(letters[0], stroke)
        elif letter in letters:
            self.store_stroke(letter, stroke)

    def process(self):
        local_data_storage = deepcopy(self.incoming_data)
        self.incoming_data = []

        for data in local_data_storage:
            if self.previous_time is None:
                self.previous_time = data[0]
                continue

            data[0], self.previous_time = data[0] - self.previous_time, data[0]

            if data[0] < MAX_DATA_TIMELAPSE:
                self.imu.calc(data)
                gyro = np.linalg.norm(np.array([data[7:]]))
                accel = self.imu.get_global_acceleration()

                accel = self.acceleration_filter.set_input(accel, data[0])

                accel_magnitude = np.linalg.norm(accel)

                if accel_magnitude > ACCELERATION_RESET:
                    self.execute_spell()

                Yr = self.imu.get_y_direction()

                self.stroke.set_data(Yr, gyro)

                self.stroke.process_size(data[0], accel)

        self.setVisible(not self.imu.in_calibration)

    def execute_spell(self):
        self.out.setText('')

    def get_data(self):
        try:
            self.data_buffer += self.serial.read(self.serial.inWaiting())
            if self.data_buffer == '':
                return
            data_pieces = self.data_buffer.split(BUFFER_DELIMITER)

            # Put incomplete piece back to the buffer
            self.data_buffer = data_pieces.pop(-1)

            # If there are no complete data pieces - return from function
            if not data_pieces:
                return

            # Else - get the last of the pieces and discard the rest
            line = data_pieces[-1]

            result = [float(d) for d in line.split()]
            if len(result) != 9:
                raise ValueError('Nine pieces of data should be provided.')
            new_line = [time()] + result
            self.incoming_data.append(new_line)
        except KeyboardInterrupt:
            raise
        except Exception as e:
            # Something went wrong... nobody cares.
            print e
Example #40
0
class RunDialog(QDialog):
    def __init__(self, run_model, parent):
        QDialog.__init__(self, parent)
        self.setWindowFlags(Qt.Window)
        self.setWindowFlags(self.windowFlags()
                            & ~Qt.WindowContextHelpButtonHint)
        self.setModal(True)
        self.setWindowModality(Qt.WindowModal)
        self.setWindowTitle("Simulations")

        assert isinstance(run_model, BaseRunModel)
        self._run_model = run_model

        ert = None
        if isinstance(run_model, BaseRunModel):
            ert = run_model.ert()

        self.simulations_tracker = SimulationsTracker()
        states = self.simulations_tracker.getStates()
        self.state_colors = {state.name: state.color for state in states}
        self.state_colors['Success'] = self.state_colors["Finished"]
        self.state_colors['Failure'] = self.state_colors["Failed"]

        self.total_progress = SimpleProgress()

        status_layout = QHBoxLayout()
        status_layout.addStretch()
        self.__status_label = QLabel()
        status_layout.addWidget(self.__status_label)
        status_layout.addStretch()
        status_widget_container = QWidget()
        status_widget_container.setLayout(status_layout)

        self.progress = Progress()
        self.progress.setIndeterminateColor(self.total_progress.color)
        for state in states:
            self.progress.addState(state.state, QColor(*state.color),
                                   100.0 * state.count / state.total_count)

        legend_layout = QHBoxLayout()
        self.legends = {}
        for state in states:
            self.legends[state] = Legend("%s (%d/%d)", QColor(*state.color))
            self.legends[state].updateLegend(state.name, 0, 0)
            legend_layout.addWidget(self.legends[state])

        legend_widget_container = QWidget()
        legend_widget_container.setLayout(legend_layout)

        self.running_time = QLabel("")

        self.plot_tool = PlotTool()
        self.plot_tool.setParent(None)
        self.plot_button = QPushButton(self.plot_tool.getName())
        self.plot_button.clicked.connect(self.plot_tool.trigger)
        self.plot_button.setEnabled(ert is not None)

        self.kill_button = QPushButton("Kill simulations")
        self.done_button = QPushButton("Done")
        self.done_button.setHidden(True)
        self.restart_button = QPushButton("Restart")
        self.restart_button.setHidden(True)
        self.show_details_button = QPushButton("Details")
        self.show_details_button.setCheckable(True)

        size = 20
        spin_movie = resourceMovie("ide/loading.gif")
        spin_movie.setSpeed(60)
        spin_movie.setScaledSize(QSize(size, size))
        spin_movie.start()

        self.processing_animation = QLabel()
        self.processing_animation.setMaximumSize(QSize(size, size))
        self.processing_animation.setMinimumSize(QSize(size, size))
        self.processing_animation.setMovie(spin_movie)

        button_layout = QHBoxLayout()
        button_layout.addWidget(self.processing_animation)
        button_layout.addWidget(self.running_time)
        button_layout.addStretch()
        button_layout.addWidget(self.show_details_button)
        button_layout.addWidget(self.plot_button)
        button_layout.addWidget(self.kill_button)
        button_layout.addWidget(self.done_button)
        button_layout.addWidget(self.restart_button)
        button_widget_container = QWidget()
        button_widget_container.setLayout(button_layout)

        self.detailed_progress = DetailedProgressWidget(
            self, self.state_colors)
        self.detailed_progress.setVisible(False)
        self.dummy_widget_container = QWidget(
        )  #Used to keep the other widgets from stretching

        layout = QVBoxLayout()
        layout.addWidget(self.total_progress)
        layout.addWidget(status_widget_container)
        layout.addWidget(self.progress)
        layout.addWidget(legend_widget_container)
        layout.addWidget(self.detailed_progress)
        layout.addWidget(self.dummy_widget_container)
        layout.addWidget(button_widget_container)

        layout.setStretch(0, 0)
        layout.setStretch(1, 0)
        layout.setStretch(2, 0)
        layout.setStretch(3, 0)
        layout.setStretch(4, 1)
        layout.setStretch(5, 1)
        layout.setStretch(6, 0)

        self.setLayout(layout)

        self.kill_button.clicked.connect(self.killJobs)
        self.done_button.clicked.connect(self.accept)
        self.restart_button.clicked.connect(self.restart_failed_realizations)
        self.show_details_button.clicked.connect(self.toggle_detailed_progress)

        self.__updating = False
        self.__update_queued = False
        self.__simulation_started = False

        self.__update_timer = QTimer(self)
        self.__update_timer.setInterval(500)
        self.__update_timer.timeout.connect(self.updateRunStatus)
        self._simulations_argments = {}

    def closeEvent(self, QCloseEvent):
        if not self.checkIfRunFinished():
            #Kill jobs if dialog is closed
            if self.killJobs() != QMessageBox.Yes:
                QCloseEvent.ignore()

    def startSimulation(self, arguments):

        self._simulations_argments = arguments

        if not 'prev_successful_realizations' in self._simulations_argments:
            self._simulations_argments['prev_successful_realizations'] = 0
        self._run_model.reset()

        def run():
            self._run_model.startSimulations(self._simulations_argments)

        simulation_thread = Thread(name="ert_gui_simulation_thread")
        simulation_thread.setDaemon(True)
        simulation_thread.run = run
        simulation_thread.start()

        self.__update_timer.start()

    def checkIfRunFinished(self):
        if self._run_model.isFinished():
            self.hideKillAndShowDone()

            if self._run_model.hasRunFailed():
                error = self._run_model.getFailMessage()
                QMessageBox.critical(
                    self, "Simulations failed!",
                    "The simulation failed with the following error:\n\n%s" %
                    error)

            return True
        return False

    def updateProgress(self):

        total_count = self._run_model.getQueueSize()
        queue_status = self._run_model.getQueueStatus()
        states = self.simulations_tracker.getStates()

        for state in states:
            state.count = 0
            state.total_count = total_count

        for state in states:
            for queue_state in queue_status:
                if queue_state in state.state:
                    state.count += queue_status[queue_state]

            self.progress.updateState(state.state,
                                      100.0 * state.count / state.total_count)
            self.legends[state].updateLegend(state.name, state.count,
                                             state.total_count)

    def updateRunStatus(self):
        self.__status_label.setText(self._run_model.getPhaseName())

        if self.checkIfRunFinished():
            self.total_progress.setProgress(self._run_model.getProgress())
            self.detailed_progress.set_progress(
                *self._run_model.getDetailedProgress())
            self.updateProgress()
            return

        self.total_progress.setProgress(self._run_model.getProgress())

        if self._run_model.isIndeterminate():
            self.progress.setIndeterminate(True)
            states = self.simulations_tracker.getStates()
            for state in states:
                self.legends[state].updateLegend(state.name, 0, 0)

        else:
            if self.detailed_progress and self.detailed_progress.isVisible():
                self.detailed_progress.set_progress(
                    *self._run_model.getDetailedProgress())
            else:
                self._run_model.updateDetailedProgress(
                )  #update information without rendering

            self.progress.setIndeterminate(False)
            self.updateProgress()

        self.setRunningTime()

    def setRunningTime(self):
        days = 0
        hours = 0
        minutes = 0
        seconds = self._run_model.getRunningTime()

        if seconds >= 60:
            minutes, seconds = divmod(seconds, 60)

        if minutes >= 60:
            hours, minutes = divmod(minutes, 60)

        if hours >= 24:
            days, hours = divmod(hours, 24)

        if days > 0:
            self.running_time.setText(
                "Running time: %d days %d hours %d minutes %d seconds" %
                (days, hours, minutes, seconds))
        elif hours > 0:
            self.running_time.setText(
                "Running time: %d hours %d minutes %d seconds" %
                (hours, minutes, seconds))
        elif minutes > 0:
            self.running_time.setText("Running time: %d minutes %d seconds" %
                                      (minutes, seconds))
        else:
            self.running_time.setText("Running time: %d seconds" % seconds)

    def killJobs(self):

        msg = "Are you sure you want to kill the currently running simulations?"
        if self._run_model.getQueueStatus().get(
                JobStatusType.JOB_QUEUE_UNKNOWN, 0) > 0:
            msg += "\n\nKilling a simulation with unknown status will not kill the realizations already submitted!"
        kill_job = QMessageBox.question(self, "Kill simulations?", msg,
                                        QMessageBox.Yes | QMessageBox.No)

        if kill_job == QMessageBox.Yes:
            if self._run_model.killAllSimulations():
                self.reject()
        return kill_job

    def hideKillAndShowDone(self):
        self.__update_timer.stop()
        self.processing_animation.hide()
        self.kill_button.setHidden(True)
        self.done_button.setHidden(False)
        self.detailed_progress.set_progress(
            *self._run_model.getDetailedProgress())
        self.restart_button.setVisible(self.has_failed_realizations())
        self.restart_button.setEnabled(self._run_model.support_restart)

    def has_failed_realizations(self):
        completed = self._run_model.completed_realizations_mask
        initial = self._run_model.initial_realizations_mask
        for (index, successful) in enumerate(completed):
            if initial[index] and not successful:
                return True
        return False

    def count_successful_realizations(self):
        """
        Counts the realizations completed in the prevoius ensemble run
        :return:
        """
        completed = self._run_model.completed_realizations_mask
        return completed.count(True)

    def create_mask_from_failed_realizations(self):
        """
        Creates a BoolVector mask representing the failed realizations
        :return: Type BoolVector
        """
        completed = self._run_model.completed_realizations_mask
        initial = self._run_model.initial_realizations_mask
        inverted_mask = BoolVector(default_value=False)
        for (index, successful) in enumerate(completed):
            inverted_mask[index] = initial[index] and not successful
        return inverted_mask

    def restart_failed_realizations(self):

        msg = QMessageBox(self)
        msg.setIcon(QMessageBox.Information)
        msg.setText(
            "Note that workflows will only be executed on the restarted realizations and that this might have unexpected consequences."
        )
        msg.setWindowTitle("Restart Failed Realizations")
        msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
        result = msg.exec_()

        if result == QMessageBox.Ok:
            self.restart_button.setVisible(False)
            self.kill_button.setVisible(True)
            self.done_button.setVisible(False)
            active_realizations = self.create_mask_from_failed_realizations()
            self._simulations_argments[
                'active_realizations'] = active_realizations
            self._simulations_argments[
                'prev_successful_realizations'] += self.count_successful_realizations(
                )
            self.startSimulation(self._simulations_argments)

    def toggle_detailed_progress(self):

        self.detailed_progress.setVisible(not (
            self.detailed_progress.isVisible()))
        self.dummy_widget_container.setVisible(not (
            self.detailed_progress.isVisible()))
        self.adjustSize()
Example #41
0
    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
Example #42
0
class Downloader(QObject):

    MAX_CONNECTION = 2
    DEFAULT_CACHE_EXPIRATION = 24  # hours

    NOT_FOUND = 0

    NO_ERROR = 0
    TIMEOUT_ERROR = 4
    UNKNOWN_ERROR = -1

    def __init__(self, parent=None):
        QObject.__init__(self, parent)
        self.queue = []
        self.requestingUrls = []
        self.replies = []

        self.eventLoop = QEventLoop()
        self.sync = False
        self.fetchedFiles = {}
        self.clearCounts()

        self.timer = QTimer()
        self.timer.setSingleShot(True)
        self.timer.timeout.connect(self.fetchTimedOut)

        self.userAgent = "Mozilla/5.0"
        self.errorStatus = Downloader.NO_ERROR

    def clearCounts(self):
        self.fetchSuccesses = 0
        self.fetchErrors = 0
        self.cacheHits = 0

    def fetchTimedOut(self):
        self.log("Downloader.timeOut()")
        self.abort()
        self.errorStatus = Downloader.TIMEOUT_ERROR

    def abort(self):
        # clear queue and abort sent requests
        self.queue = []
        self.timer.stop()
        for reply in self.replies:
            reply.abort()
        self.errorStatus = Downloader.UNKNOWN_ERROR

    def replyFinished(self):
        reply = self.sender()
        url = reply.request().url().toString()
        self.log("replyFinished: %s" % url)
        if url not in self.fetchedFiles:
            self.fetchedFiles[url] = None
        self.requestingUrls.remove(url)
        self.replies.remove(reply)
        isFromCache = 0
        httpStatusCode = reply.attribute(
            QNetworkRequest.HttpStatusCodeAttribute)
        if reply.error() == QNetworkReply.NoError:
            self.fetchSuccesses += 1
            if reply.attribute(QNetworkRequest.SourceIsFromCacheAttribute):
                self.cacheHits += 1
                isFromCache = 1
            elif not reply.hasRawHeader("Cache-Control"):
                cache = QgsNetworkAccessManager.instance().cache()
                if cache:
                    metadata = cache.metaData(reply.request().url())
                    #self.log("Expiration date: " + metadata.expirationDate().toString().encode("utf-8"))
                    if metadata.expirationDate().isNull():
                        metadata.setExpirationDate(
                            QDateTime.currentDateTime().addSecs(
                                self.DEFAULT_CACHE_EXPIRATION * 60 * 60))
                        cache.updateMetaData(metadata)
                        self.log(
                            "Default expiration date has been set: %s (%d h)" %
                            (url, self.DEFAULT_CACHE_EXPIRATION))

            if reply.isReadable():
                data = reply.readAll()
                self.fetchedFiles[url] = data
            else:
                qDebug("http status code: " + str(httpStatusCode))
        else:
            if self.sync and httpStatusCode == 404:
                self.fetchedFiles[url] = self.NOT_FOUND
            self.fetchErrors += 1
            if self.errorStatus == self.NO_ERROR:
                self.errorStatus = self.UNKNOWN_ERROR

        self.emit(SIGNAL('replyFinished(QString, int, int)'), url,
                  reply.error(), isFromCache)
        reply.deleteLater()

        if debug_mode:
            qDebug("queue: %d, requesting: %d" %
                   (len(self.queue), len(self.requestingUrls)))

        if len(self.queue) + len(self.requestingUrls) == 0:
            # all replies have been received
            if self.sync:
                self.logT("eventLoop.quit()")
                self.eventLoop.quit()
            else:
                self.timer.stop()
        elif len(self.queue) > 0:
            # start fetching the next file
            self.fetchNext()
        self.log("replyFinished End: %s" % url)

    def fetchNext(self):
        if len(self.queue) == 0:
            return
        url = self.queue.pop(0)
        self.log("fetchNext: %s" % url)

        request = QNetworkRequest(QUrl(url))
        request.setRawHeader("User-Agent", self.userAgent)
        reply = QgsNetworkAccessManager.instance().get(request)
        reply.finished.connect(self.replyFinished)
        self.requestingUrls.append(url)
        self.replies.append(reply)
        return reply

    def fetchFiles(self, urlList, timeoutSec=0):
        self.log("fetchFiles()")
        self.sync = True
        self.queue = []
        self.clearCounts()
        self.errorStatus = Downloader.NO_ERROR
        self.fetchedFiles = {}

        if len(urlList) == 0:
            return self.fetchedFiles

        for url in urlList:
            self.addToQueue(url)

        for i in range(self.MAX_CONNECTION):
            self.fetchNext()

        if timeoutSec > 0:
            self.timer.setInterval(timeoutSec * 1000)
            self.timer.start()

        self.logT("eventLoop.exec_(): " + str(self.eventLoop))
        self.eventLoop.exec_()
        self.log("fetchFiles() End: %d" % self.errorStatus)
        if timeoutSec > 0:
            self.timer.stop()
        return self.fetchedFiles

    def addToQueue(self, url):
        if url in self.queue:
            return False
        self.queue.append(url)
        return True

    def queueCount(self):
        return len(self.queue)

    def finishedCount(self):
        return len(self.fetchedFiles)

    def unfinishedCount(self):
        return len(self.queue) + len(self.requestingUrls)

    def log(self, msg):
        if debug_mode:
            qDebug(msg)

    def logT(self, msg):
        if debug_mode:
            qDebug("%s: %s" % (str(threading.current_thread()), msg))

    def fetchFilesAsync(self, urlList, timeoutSec=0):
        self.log("fetchFilesAsync()")
        self.sync = False
        self.queue = []
        self.clearCounts()
        self.errorStatus = Downloader.NO_ERROR
        self.fetchedFiles = {}

        if len(urlList) == 0:
            return self.fetchedFiles

        for url in urlList:
            self.addToQueue(url)

        for i in range(self.MAX_CONNECTION):
            self.fetchNext()

        if timeoutSec > 0:
            self.timer.setInterval(timeoutSec * 1000)
            self.timer.start()
Example #43
0
class _CameraWidget(QWidget):
    imagecaptured = pyqtSignal(QPixmap)
    done = pyqtSignal()

    def __init__(self, parent=None):
        super(_CameraWidget, self).__init__(parent)
        self.cameralabel = QLabel()
        self.cameralabel.setScaledContents(True)
        self.setLayout(QGridLayout())
        self.toolbar = QToolBar()
        spacer = QWidget()
        # spacer.setMinimumWidth(30)
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.toolbar.setIconSize(QSize(48, 48))
        self.toolbar.addWidget(spacer)
        self.swapaction = self.toolbar.addAction(QIcon(":/widgets/cameraswap"), "Swap Camera")
        self.swapaction.triggered.connect(self.swapcamera)
        self.cameralabel.mouseReleaseEvent = self.takeimage
        self.layout().setContentsMargins(0, 0, 0, 0)
        self.layout().addWidget(self.toolbar)
        self.layout().addWidget(self.cameralabel)
        self.timer = QTimer()
        self.timer.setInterval(20)
        self.timer.timeout.connect(self.showimage)
        self.cam = None
        self.pixmap = None
        self.currentdevice = 1

    def swapcamera(self):
        self.stop()
        if self.currentdevice == 0:
            self.start(1)
        else:
            self.start(0)

    def showimage(self):
        if self.cam is None:
            return

        img = self.cam.getImage()
        self.image = ImageQt(img)
        pixmap = QPixmap.fromImage(self.image)
        self.cameralabel.setPixmap(pixmap)

    def takeimage(self, *args):
        self.timer.stop()
        img = self.cam.getImage()
        self.image = ImageQt(img)
        self.pixmap = QPixmap.fromImage(self.image)
        self.cameralabel.setPixmap(self.pixmap)
        self.imagecaptured.emit(self.pixmap)
        self.done.emit()

    @property
    def camera_res(self):
        width, height = tuple(roam.config.settings['camera_res'].split(','))
        return width, height

    def start(self, dev=1):
        try:
            self.cam = vc.Device(dev)
            try:
                width, height = self.camera_res
                self.cam.setResolution(int(width), int(height))
            except KeyError:
                pass
            self.currentdevice = dev
        except vidcap.error:
            if dev == 0:
                utils.error("Could not start camera")
                raise CameraError("Could not start camera")
            self.start(dev=0)
            return

        roam.config.settings['camera'] = self.currentdevice
        self.timer.start()

    def stop(self):
        self.timer.stop()
        del self.cam
        self.cam = None
class LockinThermometerWidget(Ui.Ui_Form, QWidget):
    def __init__(self, parent=None):
        super(LockinThermometerWidget, self).__init__(parent)
        self.setupUi(self)
        self.setWindowTitle('Lockin Thermometer')
        self.timer = None
        self.Rthermometer = float('nan')


        '''
        Not sure if DateAxisItem is available anymore
        '''
        axis = pg.AxisItem(orientation='bottom')
        self.plot = pg.PlotWidget(axisItems={'bottom': axis})
        self.plot.setBackground('w')
        self.plot.plotItem.showGrid(x=True, y=True)
        self.plot.addLegend()
        self.verticalLayout.addWidget(self.plot)
        self.curve = pg.PlotCurveItem(name='X', symbol='o', pen='b')
        self.plot.addItem(self.curve)
        self.clearPb.clicked.connect(self.clearData)
        self.clearData()
        self.plotYAxisCombo.currentIndexChanged.connect(self.updatePlot)
        
        self.sr830 = None
        self.runPb.clicked.connect(self.run)
        self.parameterItems = [self.attenuatorGainSb, self.sourceImpedanceSb, self.driveResistanceSb, self.leadResistanceSb, self.preampGainSb, self.sensorVoltageSb]
        self.savePb.clicked.connect(self.saveParameterSet)
        self.loadPb.clicked.connect(self.loadParameterSet)
        self.deletePb.clicked.connect(self.deleteParameterSet)
        self.attenuatorAttenuationSb.valueChanged.connect(self.updateAttenuatorGain)
        self.attenuatorGainSb.valueChanged.connect(self.updateAttenuatorAttenuation)
        self.sensorVoltageIndicator.setUnit('V')
        self.sensorCurrentIndicator.setUnit('A')
        self.sensorPowerIndicator.setUnit('W')

        sr830 = SR830(None)
        sr830.sensitivity.populateEnumComboBox(self.minSensitivityCombo)
        
        self.loadParameterSets()
        self.restoreSettings()
        self.hkSub = HousekeepingSubscriber(parent = self)
        self.hkSub.adrResistanceReceived.connect(self.collectAdrResistance)
        self.hkSub.start()
        self.adrResistanceIndicator.setUnit(u'Ω')
        self.adrResistanceIndicator.setPrecision(5)
        self.publisher = None
        
        combo = self.calibrationCombo
        combo.addItem('RuOx 600')
        combo.addItem('RuOx 2005')
        combo.addItem('RuOx Bus (Shuo)')
        combo.addItem('RuOx Chip (InsideBox)')
        combo.setItemData(0, 'Nominal sensor calibration for RuOx 600 series', Qt.ToolTipRole)
        combo.setItemData(1, 'Calibration for RuOx sensor #2005 series', Qt.ToolTipRole)
        combo.setItemData(2, 'Cross-calibration against RuOx #2005 by Shuo (not so good above ~300mK)', Qt.ToolTipRole)
        combo.setItemData(3, 'Cross-calibration against RuOx #2005 by Yu', Qt.ToolTipRole)
        
        self.selectCalibration()
        combo.currentIndexChanged.connect(self.selectCalibration)
        

    def selectCalibration(self):
        cal = self.calibrationCombo.currentText()
        if cal == 'RuOx 600':
            self.calibration = RuOx600()
        elif cal == 'RuOx 2005':
            self.calibration = RuOx2005()
        elif cal == 'RuOx Bus (Shuo)':
            self.calibration = RuOxBus()
        elif cal == 'RuOx Chip (InsideBox)':
            self.calibration = RuOxBox()

    def collectAdrResistance(self, R):
        self.Rthermometer = R
        self.adrResistanceIndicator.setValue(R)
        
        
    def updateAttenuatorGain(self, v):
        sb = self.attenuatorGainSb
        block = sb.blockSignals(True)
        sb.setValue(1./v)
        sb.blockSignals(block)
        
    def updateAttenuatorAttenuation(self, v):
        sb = self.attenuatorAttenuationSb
        block = sb.blockSignals(True)
        sb.setValue(1./v)
        sb.blockSignals(block)
        
    def saveParameterSet(self):
        s = QSettings()
        s.beginGroup('ParameterSets')
        name = self.configCombo.currentText()
        s.beginGroup(name)
        s.setValue('adjustExcitation', self.adjustExcitationCb.isChecked())
        s.setValue('sensorName', self.sensorNameLe.text())
        s.setValue('sr830Visa', self.visaCombo.currentText())
        s.setValue('autoRanging', self.autoRangingCb.isChecked())
        s.setValue('minSensitivity', self.minSensitivityCombo.currentCode())
        for item in self.parameterItems:
            s.setValue(item.objectName(), item.value())
        s.endGroup()
        s.endGroup()
        
    def loadParameterSet(self):
        s = QSettings()
        name = self.configCombo.currentText()
        s.beginGroup('ParameterSets')
        if not name in s.childGroups():
            dlg = QErrorMessage(self)
            dlg.setWindowTitle('Error')
            dlg.showMessage('No saved parameters available for %s' % name)
            return
        s.beginGroup(name)
        for item in self.parameterItems:
            item.setValue(s.value(item.objectName(), item.value(), type=float))
        self.adjustExcitationCb.setChecked(s.value('adjustExcitation', False, type=bool))
        self.sensorNameLe.setText(s.value('sensorName', '', type=QString))
        self.visaCombo.setCurrentIndex(self.visaCombo.findText(s.value('sr830Visa', 'GPIB0::12', type=QString)))
        self.autoRangingCb.setChecked(s.value('autoRanging', True, type=bool))
        self.minSensitivityCombo.setCurrentCodeSilently(s.value('minSensitivity', 0, type=int))
        s.endGroup()
        s.endGroup()
        
    def loadParameterSets(self):
        s = QSettings()
        s.beginGroup('ParameterSets')
        names = s.childGroups()
        self.configCombo.addItems(names)
        
    def deleteParameterSet(self):
        i = self.configCombo.currentIndex()
        name = self.configCombo.itemText(i)        
        
        s = QSettings()
        s.beginGroup('ParameterSets')
        s.beginGroup(name)
        s.remove('')
        s.endGroup()
        s.endGroup()
        
        self.configCombo.removeItem(i)
        
        
    def closeEvent(self, event):
        if self.timer:
            self.timer.stop()
            
        self.saveSettings()
        self.hkSub.stop()
        self.hkSub.wait(1000)
        
    def restoreSettings(self):
        s = QSettings()
        #visa = s.value('visa', QString(), type=QString)
        #i = self.visaCombo.findText(visa)
        #elf.visaCombo.setCurrentIndex(i)
        self.configCombo.setCurrentIndex(self.configCombo.findText(s.value('parameterSet', '', type=QString)))
        if len(self.configCombo.currentText()):
            self.loadParameterSet()
        #self.sensorNameLe.setText(s.value('sensorName', '', type=QString))
        
    def saveSettings(self):
        s = QSettings()
        #s.setValue('visa', self.visaCombo.currentText())
        s.setValue('parameterSet', self.configCombo.currentText())
        #s.setValue('sensorName', self.sensorNameLe.text())
        
    def enableWidgets(self, enable):
        self.visaCombo.setEnabled(enable)
        self.attenuatorGroupBox.setEnabled(enable)
        self.seriesResistanceGroupBox.setEnabled(enable)
        self.preampGroupBox.setEnabled(enable)
        self.sensorNameLe.setEnabled(enable)
        self.loadPb.setEnabled(enable)
        self.savePb.setEnabled(enable)
        self.deletePb.setEnabled(enable)
        self.configCombo.setEnabled(enable)
        
    def run(self):
        if self.sr830 is not None:
            self.stop()
        else:
            self.start()

    def stop(self):
        self.timer.stop()
        self.timer = None
        self.sr830 = None     
        self.runPb.setText('Start')
        self.enableWidgets(True)
        del self.publisher; self.publisher = None
        
    def sensorName(self):
        return str(self.sensorNameLe.text())
        
    def start(self):
        sensorName = self.sensorName()
        self.setWindowTitle('Lock-In Thermometer %s' % sensorName )
        #setAppId(sensorName)
        
        if sensorName == 'BusThermometer':
            icon = QIcon('Icons/LockinThermometer_Bus.ico')
        elif sensorName == 'RuOx2005Thermometer':
            icon = QIcon('Icons/LockinThermometer_BoxOutside.ico')
        elif sensorName == 'BoxThermometer':
            icon = QIcon('Icons/LockinThermometer_BoxInside2.ico')
        else:
            icon = QIcon('Icons/LockinThermometer.ico')

        self.setWindowIcon(icon)

        visa = str(self.visaCombo.currentText())
        self.sr830 = SR830(visa)
        #self.sr830.debug = True

        self.sr830.readAll()
        self.sr830.sineOut.caching = False # Disable caching on this
        
        Sockets = {'BusThermometer':PubSub.LockinThermometerAdr,
                  'RuOx2005Thermometer':PubSub.LockinThermometerRuOx2005,
                  'BoxThermometer':PubSub.LockinThermometerBox}
        socket = Sockets[sensorName]
        self.publisher = ZmqPublisher('LockinThermometer', socket)
        
        self.runPb.setText('Stop')
        self.timer = QTimer()
        self.timer.setInterval(1000)
        self.timer.timeout.connect(self.snapSignal)
        self.timer.start()
        self.enableWidgets(False)
        self.rangeChangedTime = 0
        self.exChangedTime = 0
        t = time.time()
        timeString = time.strftime('%Y%m%d-%H%M%S', time.localtime(t))
        dateString = time.strftime('%Y%m%d')
        sensorName = str(self.sensorNameLe.text())

        s = QSettings('WiscXrayAstro', application='ADR3RunInfo')
        path = str(s.value('runPath', '', type=str))
        fileName = os.path.join(path, '%s_%s.dat' % (sensorName, dateString))
        if not os.path.isfile(fileName): # Maybe create new file
            with open(fileName, 'a+') as f:
                f.write('#LockinThermometer.py\n')
                f.write('#Date=%s\n' % timeString)
                f.write('#SensorName=%s\n' % sensorName)
                f.write('#SR830=%s\n' % self.sr830.visaId())
                f.write('#AttenuatorGain=%f\n' % self.attenuatorGainSb.value())
                f.write('#AttenuatorSourceImpedance=%f\n' % self.sourceImpedanceSb.value())
                f.write('#DriveResistance=%f\n' % self.driveResistanceSb.value())
                f.write('#LeadResistance=%f\n' % self.leadResistanceSb.value())
                f.write('#PreampGain=%f\n' % self.preampGainSb.value())
                f.write('#DesiredExcitation=%f\n' % self.sensorVoltageSb.value())
                k = self.sr830.allSettingValues()
                for key,value in k.iteritems():
                    f.write('#SR830/%s=%s\n' % (key,value))
                f.write('#'+'\t'.join(['time', 'VsineOut', 'X', 'Y', 'f', 'Sensitivity', 'RxCalc', 'Rtherm'])+'\n')
        self.fileName = fileName
        
    def snapSignal(self):
        t = time.time()
        self.sr830.snapSignal()
        VsineOut = self.sr830.sineOut.value
        X = self.sr830.X
        Y = self.sr830.Y
        f = self.sr830.f

        rangeChangeAge = t - self.rangeChangedTime
        exChangeAge = t - self.exChangedTime
        
        sensitivity = self.sr830.sensitivity.value
        
        if self.autoRangingCb.isChecked():
            self.sr830.checkStatus()
            minCode = self.minSensitivityCombo.currentCode()
            currentCode = self.sr830.sensitivity.code
            if self.sr830.overload and rangeChangeAge > 10:
                self.sr830.sensitivity.code = currentCode+1
                self.rangeChangeTime = t
            elif X > 0.9*sensitivity and rangeChangeAge > 10:
                self.sr830.sensitivity.code = currentCode+1
                self.rangeChangedTime = t
            elif X < 0.3*sensitivity and rangeChangeAge > 10:
                if  currentCode > minCode:
                    self.sr830.sensitivity.code = currentCode - 1
                    self.rangeChangedTime = t
            elif currentCode < minCode:
                self.sr830.sensitivity.code = minCode
                self.rangeChangedTime = t
                    
        
        G1 = self.attenuatorGainSb.value()
        G2 = self.preampGainSb.value()
        Rsource = self.sourceImpedanceSb.value()
        Rd = self.driveResistanceSb.value()
        Rl = self.leadResistanceSb.value()
        Rs = Rsource+Rd+Rl

        Vx = X / G2
        
        Vex = VsineOut * G1 # Real excitation
        self.sensorVoltageIndicator.setValue(Vx)

        
        Rx = Rs / (Vex/Vx-1.)
        I = Vx / Rx
        self.sensorCurrentIndicator.setValue(I)
        P = Vx*I
        Temp = self.calibration.calculateTemperature([Rx])[0] # @todo This is really a crutch
        Tbase = self.calibration.correctForReadoutPower(Temp, P)
        
        if self.publisher is not None:
            if rangeChangeAge > 10 and exChangeAge > 10 and Temp == Temp and Temp > 0 and Temp < 10:
                self.publisher.publishDict(self.sensorName(), {'t': t, 'R': Rx, 'T': Temp, 'P': P, 'Tbase': Tbase})
                #self.publisher.publish('ADR_Sensor_R', Rx)
                #self.publisher.publish('ADR_Temperature', Temp)

        # Log data
        with open(self.fileName, 'a+') as of:
            of.write('%.3f\t%.3f\t%.5E\t%.5E\t%.3f\t%.1E\t%.5E\t%.5E\n' % (t, VsineOut, X, Y, f, sensitivity, Rx, self.Rthermometer))

        self.ts.append(t)
        self.xs.append(X)
        self.ys.append(Y)
        self.fs.append(f)
        self.VsineOuts.append(VsineOut)
        self.Rs.append(Rx)
        self.Vxs.append(Vx)
        self.Ps.append(P)
        self.Ts.append(Temp)
        self.Tbases.append(Tbase)

        self.sensorIndicator.setValue(Rx)
        self.temperatureIndicator.setKelvin(Temp)
        self.baseTempIndicator.setKelvin(Tbase)
        self.sensorPowerIndicator.setValue(P)
        self.updateLed.flashOnce()
        self.updatePlot()

        # Not sure where this code came from. Seems questionable (FJ)
        # if len(self.Ts) > 2 :
        #     dTdt = abs((self.Ts[-1] - self.Ts[-2]) / (self.ts[-1] - self.ts[-2]))
        #     if dTdt > 0.1:
        #         self.temperatureIndicator.setKelvin('N/A')
        #         self.stop()
        
        
        # Perhaps change excitation
        if exChangeAge < 10 or rangeChangeAge < 10 or not self.adjustExcitationCb.isChecked():
            return
        VxDesired = self.sensorVoltageSb.value()
        IDesired = VxDesired / Rx
        VexDesired = IDesired*(Rx+Rs)
        change = (VexDesired-Vex)/Vex
        tolerance = 1E-2*self.toleranceSb.value()
        if abs(change) < tolerance:
            return
        
        VsineOutDesired = VexDesired / G1 # This is what we would like to see
        # What we actually get may be something different
        Vnew = min(5,max(VsineOutDesired,0.004))
        if tolerance == 0 and abs(Vnew - VsineOut) > 0.009:   # If a large step is required, do it slowly
            Vnew = (3.*VsineOut+1.*Vnew)/4.
        
        if abs(Vnew - VsineOut) < 0.002:
            return
        self.exChangedTime = t
        self.sr830.sineOut.value = Vnew

        
        
    def clearData(self):
        self.ts = []
        self.xs = []
        self.ys = []
        self.fs = []
        self.Rs = []
        self.Ps = []
        self.VsineOuts = []
        self.Vxs = []
        self.Ts = []
        self.Tbases = []
        self.updatePlot()
        
    def updatePlot(self):
        yAxis = self.plotYAxisCombo.currentText()
        pl = self.plot
        if yAxis == 'X':
            y = self.xs
            pl.setLabel('left', 'Lock-in X', 'V')
        elif yAxis == 'Y':
            y = self.ys
            pl.setLabel('left', 'Lock-in Y', 'V')
        elif yAxis == 'R':
            y = self.Rs
            pl.setLabel('left', 'R sensor', u'Ω')
        elif yAxis == 'V sine out':
            y = self.VsineOuts
            pl.setLabel('left', 'V sine out', 'V')
        elif yAxis == 'V sensor':
            y = self.Vxs
            pl.setLabel('left', 'V sensor', 'V')
        elif yAxis == 'P sensor':
            y = self.Ps
            pl.setLabel('left', 'P sensor', 'W')
        elif yAxis == 'Sensor temperature':
            y = self.Ts
            pl.setLabel('left', 'T sensor', 'K')
        elif yAxis == 'Base temperature':
            y = self.Tbases
            pl.setLabel('left', 'T base', 'K')
        elif yAxis == '':
            return
            
        x = self.ts
        self.curve.setData(x, y)
Example #45
0
class CalibrateGyroscopeBias(QWidget, Ui_calibrate_gyroscope_bias):
    TYPE_GYR_BIAS = 5
    NUM_AVG = 5000
    qtcb_callback = pyqtSignal(int, int, int)

    def __init__(self, parent):
        QWidget.__init__(self)

        self.setupUi(self)

        self.parent = parent
        self.imu = parent.parent.imu

        self.set_default()
        self.start_button.clicked.connect(self.next_state)
        self.i = 0
        self.t = 0

        self.state = 0
        self.temperature_raw = 0
        self.t_raw_start_low = 0
        self.t_raw_end_high = 0

        self.gyr_sum = [0, 0, 0]
        self.gyr_bias_low = [0, 0, 0]
        self.gyr_bias_high = [0, 0, 0]

        self.update_timer = QTimer()
        self.update_timer.timeout.connect(self.update_temperature)
        self.update_timer.setInterval(1000)

        self.qtcb_callback.connect(self.callback)

    def start(self):
        self.update_temperature()
        self.update_timer.start()
        self.imu.register_callback(self.imu.CALLBACK_ANGULAR_VELOCITY,
                                   self.qtcb_callback.emit)

    def stop(self):
        self.update_timer.stop()
        self.imu.set_angular_velocity_period(0)

    def update_temperature(self):
        self.temperature_raw = self.imu.get_imu_temperature()
        t_str = "%.2f" % (self.temperature_raw / 100.0)

        if self.state < 2:
            self.t_low.setText(t_str)
        else:
            self.t_high.setText(t_str)

    def set_default(self):
        self.gyr_sum = [0, 0, 0]
        self.gyr_bias = [0, 0, 0]
        text = """For the gyroscope bias calibration the IMU Brick has \
to lie still for about 5 seconds. As soon as you press "Start Calibration" \
the calibration will begin.

Make sure that the IMU Brick lies absolutely still during the calibration. \
Don't make vibrations by walking around and don't type on your keyboard \
if possible place the IMU Brick on another desk. Even small vibrations can \
deteriorate this calibration significantly.

The gyroscope bias is highly dependent on the temperature, so you have to \
calibrate the bias two times with different temperatures. The first \
measurement should be with a low temperature and the second with a high one. \
The temperature difference should be at least 5%cC. If you have \
a temperature where the IMU Brick is mostly used, you should use this \
temperature for one of the sampling points.
""" % 0xB0

        self.text_label.setText(text)
        self.start_button.setText("Start Calibration Low Temperature")

    def calc(self):
        if self.state == 2:
            for i in range(3):
                self.gyr_bias_low[i] = self.gyr_sum[i] / self.NUM_AVG

                if i == 0:
                    self.bias_low_x.setText(str(self.gyr_bias_low[i]))
                elif i == 1:
                    self.bias_low_y.setText(str(self.gyr_bias_low[i]))
                elif i == 2:
                    self.bias_low_z.setText(str(self.gyr_bias_low[i]))
        else:
            for i in range(3):
                self.gyr_bias_high[i] = self.gyr_sum[i] / self.NUM_AVG

                if i == 0:
                    self.bias_high_x.setText(str(self.gyr_bias_high[i]))
                elif i == 1:
                    self.bias_high_y.setText(str(self.gyr_bias_high[i]))
                elif i == 2:
                    self.bias_high_z.setText(str(self.gyr_bias_high[i]))

    def next_state(self):
        self.state += 1
        if self.state == 5:
            self.state = 0

        if self.state == 0:
            self.gyr_sum = [0, 0, 0]
            self.update_temperature()
            self.imu.set_angular_velocity_period(0)
            bias = [
                self.gyr_bias_low[0], self.gyr_bias_low[1],
                self.gyr_bias_low[2],
                (self.t_raw_start_low + self.t_raw_end_low) / 2,
                self.gyr_bias_high[0], self.gyr_bias_high[1],
                self.gyr_bias_high[2],
                (self.t_raw_start_high + self.t_raw_end_high) / 2, 0, 0
            ]

            self.imu.set_calibration(self.TYPE_GYR_BIAS, bias)
            self.parent.refresh_values()

            self.bias_low_x.setText("?")
            self.bias_low_y.setText("?")
            self.bias_low_z.setText("?")
            self.t_low.setText("?")
            self.bias_high_x.setText("?")
            self.bias_high_y.setText("?")
            self.bias_high_z.setText("?")
            self.t_high.setText("?")

            self.set_default()
        elif self.state == 1:
            self.update_timer.stop()
            self.t_raw_start_low = self.imu.get_imu_temperature()
            bias = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
            self.imu.set_calibration(self.TYPE_GYR_BIAS, bias)
            self.parent.refresh_values()

            self.imu.set_angular_velocity_period(1)
            self.text_label.setText("Waiting...")
            self.start_button.setEnabled(False)
        elif self.state == 2:
            self.t_raw_end_low = self.imu.get_imu_temperature()
            self.calc()
            self.update_temperature()
            self.update_timer.start()
            self.start_button.setText("Start Calibration High Temperature")
            self.text_label.setText("""Now wait for the temperature to rise. \
A temperature difference of at least 5%cC is recommended.

The calibration will again take 5 seconds and the IMU Brick needs to lie
absolutely still.""" % 0xB0)
        elif self.state == 3:
            self.update_timer.stop()
            self.t_raw_start_high = self.imu.get_imu_temperature()
            self.imu.set_angular_velocity_period(1)
            self.text_label.setText("Waiting...")
            self.start_button.setEnabled(False)
        elif self.state == 4:
            self.t_raw_end_high = self.imu.get_imu_temperature()
            self.calc()
            self.text_label.setText("""Ready. To save the calibration \
press "Save Calibration" """)
            self.start_button.setText("Save Calibration")

    def callback(self, gyr_x, gyr_y, gyr_z):
        if self.i == 0:
            self.t = time.time()
            self.gyr_sum = [0, 0, 0]

        if not self.start_button.isEnabled():
            self.text_label.setText("Calibrating: " + str(self.i) + '/' +
                                    str(self.NUM_AVG))
        else:
            return

        self.gyr_sum[0] -= gyr_x
        self.gyr_sum[1] -= gyr_y
        self.gyr_sum[2] -= gyr_z

        self.i += 1

        if self.i == self.NUM_AVG:
            self.imu.set_angular_velocity_period(0)
            self.start_button.setEnabled(True)
            self.next_state()
            self.i = 0
Example #46
0
class Transformation(visionModule):
    '''
    classdocs
    '''
    __imgScene = None
    __imgSceneTh = None

    __calibrated = False
    __calibrating = False

    __basisMatrix = array([[1, 0], [0, 1]])
    __offset = array([0, 0])

    def __init__(self, gui=None, imageGrabber=None, config=None):
        '''
        Constructor
        '''
        super(Transformation, self).__init__(gui=gui,
                                             imageGrabber=imageGrabber,
                                             config=config)
        self.__calibrated = False
        self.__calibrating = False
        self.__basisMatrix = array([[1, 0], [0, 1]])
        self.__offset = array([0, 0])

        if self._gui != None:
            self.__initGui()

        if self._config != None:
            cfgFile = self._config.getConfigValue("CONFIGURATION",
                                                  "cfgTransformation")
            if cfgFile != None and self.__loadConfigData(cfgFile):
                self._gui.status("Loaded transformtaion config.")
                mrLogger.logInfo("Loaded transformation config file " +
                                 str(cfgFile))

    def __initGui(self):
        '''
        Initiates gui
        '''
        # initiate scene
        self.__gview = self._gui.getObj("imgTransformation")
        self.__scene = QGraphicsScene()
        self.__gview.setScene(self.__scene)

        self.__gviewTh = self._gui.getObj("imgTransformationThreshold")
        self.__sceneTh = QGraphicsScene()
        self.__gviewTh.setScene(self.__sceneTh)

        # create listeners
        self._gui.connect("cmdCalibrateTransformation", "clicked()",
                          self.__calibrateTransformation)
        self._gui.connect("cmdSaveTransformation", "clicked()",
                          self.saveSettings)
        self._gui.connect("cmdLoadTransformation", "clicked()",
                          self.loadSetting)

        # start timer
        self.__sceneImgTimer = QTimer()
        self.__sceneImgTimer.timeout.connect(self._showImage)
        self.__sceneImgTimer.start(100)

    def saveSettings(self):
        '''
        Save Settings
        '''
        # stop video
        active = self._imageGrabber.isActive()
        self._imageGrabber.stopVideo()

        options = copy(self._gui.dialogOptionsDef)
        options['type'] = self._gui.dialogTypes['FileSave']
        options['title'] = "Save configuration"
        options['filetypes'] = "Configuration (*cfg *mr)"
        src = str(self._gui.dialog(options))

        if len(src) > 0:
            # check path
            if not src.endswith(".cfg"):
                src += ".cfg"

            # save data to file
            data = {
                'basismatrix': self.__basisMatrix,
                'offset': self.__offset,
                'calibrated': self.__calibrated
            }

            dump(data, open(src, "wb"))
            self._gui.status("Configuration saved to: " + src)

        # restore video streaming mode
        if active:
            self._imageGrabber.startVideo()

    def loadSetting(self):
        '''
        Load Settings
        '''
        # stop video
        active = self._imageGrabber.isActive()
        self._imageGrabber.stopVideo()

        # get path
        options = copy(self._gui.dialogOptionsDef)
        options['filetypes'] = "config file (*cfg)"
        src = str(self._gui.dialog(options))

        if self.__loadConfigData(src):
            self._gui.status("Tranformation config loaded.")

        # restore video streaming mode
        if active:
            self._imageGrabber.startVideo()

    def __loadConfigData(self, src):
        '''
        Loads config data from file
        '''
        if len(src) > 0 and isfile(src):
            # load file
            data = load(open(src, "rb"))

            if 'basismatrix' in data:
                self.__basisMatrix = data['basismatrix']
            if 'offset' in data:
                self.__offset = data['offset']
            if 'calibrated' in data:
                self.__calibrated = data['calibrated']

            return True

        return False

    def isCalibrated(self):
        '''
        @return: True if image is calibrated
        '''
        return self.__calibrated

    def isCalibrating(self):
        '''
        @return: True if calibration is in progress
        '''
        return self.__calibrating

    def startCalibration(self):
        '''
        Starts calibration of transformation
        '''
        if not self.isCalibrating():
            start_new_thread(self.__calibrateTransformation, ())

    def __calibrateTransformation(self):
        '''
        Calculates transformation values
        '''
        if self._img == None:
            return

        self._gui.status("Calibrating transformation...")
        self.__calibrating = True
        img = self._img
        '''
        Preprocessing image:
        '''
        try:
            # get data
            th = self._gui.getObj("sliderThesholdCircles").value()
            cannyUp = self._gui.getObj("sliderCirclesCannyUp").value()
            thCircles = self._gui.getObj("sliderThesholdCircles2").value()
            minRadius = (
                float(str(self._gui.getObj("txtCirclesRadiusMin").text())) /
                100.0) * img.shape[0]
            maxRadius = (
                float(str(self._gui.getObj("txtCirclesRadiusMax").text())) /
                100.0) * img.shape[0]
            minDist = (
                float(str(self._gui.getObj("txtCirclesDistanceMin").text())) /
                100.0) * img.shape[0]
            blur = 5

            # blur image for better result
            gimg = cvtColor(img, COLOR_RGB2GRAY)
            gimg = medianBlur(gimg, blur)

            # create binary image
            gimg = threshold(gimg, th, 255, THRESH_BINARY)[1]
            self.__imgSceneTh = gimg
            '''
            Searching for circles by using Hough-Transformation:
            '''
            circles = HoughCircles(gimg,
                                   CV_HOUGH_GRADIENT,
                                   1,
                                   int(minDist),
                                   param1=cannyUp,
                                   param2=thCircles,
                                   minRadius=int(minRadius),
                                   maxRadius=int(maxRadius))
            circles = around(circles).astype(int16)
            centers = circles[0][:, :3]
            '''
            Identifying corners of playing field by evaluating centers of circles:
            Existence of 4 points are mandatory!
            '''
            vlnr = argsort(centers[:, 0], )

            pts_left = centers[vlnr[:2], :]
            pts_right = centers[vlnr[2:], :]

            # defining points for coordinate system
            # left:
            p00 = pts_left[argsort(pts_left[:, 1])[0], :]
            p01 = pts_left[argsort(pts_left[:, 1])[1], :]
            # right:
            p10 = pts_right[argsort(pts_right[:, 0])[0], :]
            p11 = pts_right[argsort(pts_right[:, 0])[1], :]

            # correcting axes with aritmethic mean. p00 and p11 are set
            # vertical:
            a_v1 = p01 - p00
            a_v2 = p11 - p10
            a_v = (a_v1 + a_v2) / 2
            # horizontal:
            a_h1 = p10 - p00
            a_h2 = p11 - p01
            a_h = (a_h1 + a_h2) / 2

            # correcting other corners
            p10c = p00 + a_h
            p01c = p11 - a_h

            # paint lines and circles
            circle(img, (p00[0], p00[1]), p00[2], (255, 0, 0), 2)
            circle(img, (p11[0], p11[1]), p11[2], (255, 0, 0), 2)
            circle(img, (p10[0], p10[1]), p10[2], (255, 0, 0), 2)
            circle(img, (p01[0], p01[1]), p01[2], (255, 0, 0), 2)

            line(img, (p00[0], p00[1]), (p01c[0], p01c[1]), (0, 255, 0), 2)
            line(img, (p00[0], p00[1]), (p10c[0], p10c[1]), (0, 255, 0), 2)
            line(img, (p10c[0], p10c[1]), (p11[0], p11[1]), (0, 255, 0), 2)
            line(img, (p01c[0], p01c[1]), (p11[0], p11[1]), (0, 255, 0), 2)

            self.__imgScene = img
            '''
            Setting Offset and Basismatrix
            '''
            self.__offset = array([p00[0], p00[1]])
            self.__basisMatrix = array([[a_v[0], a_h[0]], [a_v[1], a_h[1]]])

        except:
            self._gui.status("Error while calibrating transformation")

        self.__calibrating = False
        self._gui.status("Calibration finished.")

        pass

    def transformatePoint(self, point=array([0, 0])):
        '''
        Transformates a point into local coordinates space
        @param point: Tuple (x,y) of points coordinates to transform
        @return: Tuple (x,y) of transformed coordinates
        '''

        A = self.__basisMatrix
        O = self.__offset

        # Creating reference to origin of coordinates space
        b = point - O
        transformation = solve(A, b)

        return transformation

    def transformObjects(self, objs=[]):
        '''
        Transforms a list of vision objects
        @param objs: List of vision objects
        @return: List of transformed vision objects
        '''
        for obj in objs:
            center = self.transformatePoint(array(obj['center']))
            center = (center[1], center[0])
            obj['center'] = center

    def _showImage(self):
        '''
        Shows image
        '''
        if not self.isCalibrated() or self.isCalibrating():
            self._updateScene(self.__gview,
                              self.__scene,
                              self.__imgScene,
                              convert=False,
                              keepRatio=True)
            self._updateScene(self.__gviewTh,
                              self.__sceneTh,
                              self.__imgSceneTh,
                              convert=True,
                              keepRatio=True)
Example #47
0
 def createTimer(self):
     timer = QTimer()
     timer.start()
     self.timers[timer.timerId()] = timer
     print >> sys.stderr, 'Created new timer with ID', timer.timerId()
     return timer
Example #48
0
class MainWindow(QMainWindow):
    def __init__(self, labeltool, parent=None):
        QMainWindow.__init__(self, parent)

        self.idletimer = QTimer()
        self.loader = None

        self.labeltool = labeltool
        self.setupGui()
        self.loadApplicationSettings()
        self.onAnnotationsLoaded()

    # Slots
    def onPluginLoaded(self, action):
        self.ui.menuPlugins.addAction(action)

    def onStatusMessage(self, message=''):
        self.statusBar().showMessage(message, 5000)

    def onModelDirtyChanged(self, dirty):
        postfix = "[+]" if dirty else ""
        if self.labeltool.getCurrentFilename() is not None:
            self.setWindowTitle("%s - %s %s" % \
                (APP_NAME, QFileInfo(self.labeltool.getCurrentFilename()).fileName(), postfix))
        else:
            self.setWindowTitle("%s - Unnamed %s" % (APP_NAME, postfix))

    def onMousePositionChanged(self, x, y):
        self.posinfo.setText("%d, %d" % (x, y))

    def startBackgroundLoading(self):
        self.stopBackgroundLoading(forced=True)
        self.loader = BackgroundLoader(self.labeltool.model(),
                                       self.statusBar(), self.sb_progress)
        self.idletimer.timeout.connect(self.loader.load)
        self.loader.finished.connect(self.stopBackgroundLoading)
        self.statusBar().addWidget(self.sb_progress)
        self.sb_progress.show()
        self.idletimer.start()

    def stopBackgroundLoading(self, forced=False):
        if not forced:
            self.statusBar().showMessage("Background loading finished", 5000)
        self.idletimer.stop()
        if self.loader is not None:
            self.idletimer.timeout.disconnect(self.loader.load)
            self.statusBar().removeWidget(self.sb_progress)
            self.loader = None

    def onAnnotationsLoaded(self):
        self.labeltool.model().dirtyChanged.connect(self.onModelDirtyChanged)
        self.onModelDirtyChanged(self.labeltool.model().dirty())
        self.treeview.setModel(self.labeltool.model())
        self.scene.setModel(self.labeltool.model())
        self.selectionmodel = QItemSelectionModel(self.labeltool.model())
        self.treeview.setSelectionModel(self.selectionmodel)
        self.treeview.selectionModel().currentChanged.connect(
            self.labeltool.setCurrentImage)
        self.property_editor.onModelChanged(self.labeltool.model())
        self.startBackgroundLoading()

    def onCurrentImageChanged(self):
        new_image = self.labeltool.currentImage()
        self.scene.setCurrentImage(new_image)
        self.onFitToWindowModeChanged()
        self.treeview.scrollTo(new_image.index())

        img = self.labeltool.getImage(new_image)

        if img == None:
            self.controls.setFilename("")
            self.selectionmodel.setCurrentIndex(
                new_image.index(),
                QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows)
            return

        h = img.shape[0]
        w = img.shape[1]
        self.image_resolution.setText("%dx%d" % (w, h))

        # TODO: This info should be obtained from AnnotationModel or LabelTool
        if isinstance(new_image, FrameModelItem):
            self.controls.setFrameNumAndTimestamp(new_image.framenum(),
                                                  new_image.timestamp())
        elif isinstance(new_image, ImageFileModelItem):
            self.controls.setFilename(os.path.basename(new_image['filename']))

        self.selectionmodel.setCurrentIndex(
            new_image.index(),
            QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows)

    def onFitToWindowModeChanged(self):
        if self.options["Fit-to-window mode"].isChecked():
            self.view.fitInView()

    def onScaleChanged(self, scale):
        self.zoominfo.setText("%.2f%%" % (100 * scale, ))

    def initShortcuts(self, HOTKEYS):
        self.shortcuts = []

        for hotkey in HOTKEYS:
            assert len(hotkey) >= 2
            key = hotkey[0]
            fun = hotkey[1]
            desc = ""
            if len(hotkey) > 2:
                desc = hotkey[2]
            if type(fun) == str:
                fun = import_callable(fun)

            hk = QAction(desc, self)
            hk.setShortcut(QKeySequence(key))
            hk.setEnabled(True)
            if hasattr(fun, '__call__'):
                hk.triggered.connect(bind(fun, self.labeltool))
            else:
                hk.triggered.connect(
                    compose_noargs([bind(f, self.labeltool) for f in fun]))
            self.ui.menuShortcuts.addAction(hk)
            self.shortcuts.append(hk)

    def initOptions(self):
        self.options = {}
        for o in ["Fit-to-window mode"]:
            action = QAction(o, self)
            action.setCheckable(True)
            self.ui.menuOptions.addAction(action)
            self.options[o] = action

    ###
    ### GUI/Application setup
    ###___________________________________________________________________________________________
    def setupGui(self):
        self.ui = uic.loadUi(os.path.join(GUIDIR, "labeltool.ui"), self)

        # get inserters and items from labels
        # FIXME for handling the new-style config correctly
        inserters = dict([
            (label['attributes']['class'], label['inserter'])
            for label in config.LABELS
            if 'class' in label.get('attributes', {}) and 'inserter' in label
        ])
        items = dict([
            (label['attributes']['class'], label['item'])
            for label in config.LABELS
            if 'class' in label.get('attributes', {}) and 'item' in label
        ])

        # Property Editor
        self.property_editor = PropertyEditor(config.LABELS)
        self.ui.dockProperties.setWidget(self.property_editor)

        # Scene
        self.scene = AnnotationScene(self.labeltool,
                                     items=items,
                                     inserters=inserters)
        self.property_editor.insertionModeStarted.connect(
            self.scene.onInsertionModeStarted)
        self.property_editor.insertionModeEnded.connect(
            self.scene.onInsertionModeEnded)

        # SceneView
        self.view = GraphicsView(self)
        self.view.setSizePolicy(QSizePolicy.MinimumExpanding,
                                QSizePolicy.MinimumExpanding)
        self.view.setScene(self.scene)

        self.central_widget = QWidget()
        self.central_layout = QVBoxLayout()
        self.controls = ControlButtonWidget()
        self.controls.back_button.clicked.connect(self.labeltool.gotoPrevious)
        self.controls.forward_button.clicked.connect(self.labeltool.gotoNext)

        self.central_layout.addWidget(self.controls)
        self.central_layout.addWidget(self.view)
        self.central_widget.setLayout(self.central_layout)
        self.setCentralWidget(self.central_widget)

        self.initShortcuts(config.HOTKEYS)
        self.initOptions()

        self.treeview = AnnotationTreeView()
        self.treeview.setSizePolicy(QSizePolicy.MinimumExpanding,
                                    QSizePolicy.Preferred)
        self.ui.dockAnnotations.setWidget(self.treeview)

        self.scene.selectionChanged.connect(self.scene.onSelectionChanged)
        self.treeview.selectedItemsChanged.connect(
            self.scene.onSelectionChangedInTreeView)

        self.posinfo = QLabel("-1, -1")
        self.posinfo.setFrameStyle(QFrame.StyledPanel)
        self.statusBar().addPermanentWidget(self.posinfo)
        self.scene.mousePositionChanged.connect(self.onMousePositionChanged)

        self.image_resolution = QLabel("[no image]")
        self.image_resolution.setFrameStyle(QFrame.StyledPanel)
        self.statusBar().addPermanentWidget(self.image_resolution)

        self.zoominfo = QLabel()
        self.zoominfo.setFrameStyle(QFrame.StyledPanel)
        self.statusBar().addPermanentWidget(self.zoominfo)
        self.view.scaleChanged.connect(self.onScaleChanged)
        self.onScaleChanged(self.view.getScale())

        self.sb_progress = QProgressBar()

        # View menu
        self.ui.menu_Views.addAction(self.ui.dockProperties.toggleViewAction())
        self.ui.menu_Views.addAction(
            self.ui.dockAnnotations.toggleViewAction())

        # Show the UI.  It is important that this comes *after* the above
        # adding of custom widgets, especially the central widget.  Otherwise the
        # dock widgets would be far to large.
        self.ui.show()

        ## connect action signals
        self.connectActions()

    def connectActions(self):
        ## File menu
        self.ui.actionNew.triggered.connect(self.fileNew)
        self.ui.actionOpen.triggered.connect(self.fileOpen)
        self.ui.actionSave.triggered.connect(self.fileSave)
        self.ui.actionSave_As.triggered.connect(self.fileSaveAs)
        self.ui.actionExit.triggered.connect(self.close)

        ## View menu
        self.ui.actionLocked.toggled.connect(self.onViewsLockedChanged)

        ## Help menu
        self.ui.action_About.triggered.connect(self.about)

        ## Navigation
        self.ui.action_Add_Image.triggered.connect(self.addMediaFile)
        self.ui.actionNext.triggered.connect(self.labeltool.gotoNext)
        self.ui.actionPrevious.triggered.connect(self.labeltool.gotoPrevious)
        self.ui.actionZoom_In.triggered.connect(
            functools.partial(self.view.setScaleRelative, 1.2))
        self.ui.actionZoom_Out.triggered.connect(
            functools.partial(self.view.setScaleRelative, 1 / 1.2))

        ## Connections to LabelTool
        self.labeltool.pluginLoaded.connect(self.onPluginLoaded)
        self.labeltool.statusMessage.connect(self.onStatusMessage)
        self.labeltool.annotationsLoaded.connect(self.onAnnotationsLoaded)
        self.labeltool.currentImageChanged.connect(self.onCurrentImageChanged)

        ## options menu
        self.options["Fit-to-window mode"].changed.connect(
            self.onFitToWindowModeChanged)

    def loadApplicationSettings(self):
        settings = QSettings()
        size = settings.value("MainWindow/Size", QSize(800, 600))
        pos = settings.value("MainWindow/Position", QPoint(10, 10))
        state = settings.value("MainWindow/State")
        locked = settings.value("MainWindow/ViewsLocked", False)
        if isinstance(size, QVariant): size = size.toSize()
        if isinstance(pos, QVariant): pos = pos.toPoint()
        if isinstance(state, QVariant): state = state.toByteArray()
        if isinstance(locked, QVariant): locked = locked.toBool()
        self.resize(size)
        self.move(pos)
        self.restoreState(state)
        self.ui.actionLocked.setChecked(bool(locked))

    def saveApplicationSettings(self):
        settings = QSettings()
        settings.setValue("MainWindow/Size", self.size())
        settings.setValue("MainWindow/Position", self.pos())
        settings.setValue("MainWindow/State", self.saveState())
        settings.setValue("MainWindow/ViewsLocked",
                          self.ui.actionLocked.isChecked())
        if self.labeltool.getCurrentFilename() is not None:
            filename = self.labeltool.getCurrentFilename()
        else:
            filename = None
        settings.setValue("LastFile", filename)

    def okToContinue(self):
        if self.labeltool.model().dirty():
            reply = QMessageBox.question(
                self, "%s - Unsaved Changes" % (APP_NAME),
                "Save unsaved changes?",
                QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel)
            if reply == QMessageBox.Cancel:
                return False
            elif reply == QMessageBox.Yes:
                return self.fileSave()
        return True

    def fileNew(self):
        if self.okToContinue():
            self.labeltool.clearAnnotations()

    def fileOpen(self):
        if not self.okToContinue():
            return
        path = '.'
        filename = self.labeltool.getCurrentFilename()
        if (filename is not None) and (len(filename) > 0):
            path = QFileInfo(filename).path()

        format_str = ' '.join(self.labeltool.getAnnotationFilePatterns())
        fname = QFileDialog.getOpenFileName(
            self, "%s - Load Annotations" % APP_NAME, path,
            "%s annotation files (%s)" % (APP_NAME, format_str))
        if len(str(fname)) > 0:
            self.labeltool.loadAnnotations(fname)

    def fileSave(self):
        filename = self.labeltool.getCurrentFilename()
        if filename is None:
            return self.fileSaveAs()
        return self.labeltool.saveAnnotations(filename)

    def fileSaveAs(self):
        fname = '.'  # self.annotations.filename() or '.'
        format_str = ' '.join(self.labeltool.getAnnotationFilePatterns())
        fname = QFileDialog.getSaveFileName(
            self, "%s - Save Annotations" % APP_NAME, fname,
            "%s annotation files (%s)" % (APP_NAME, format_str))

        if len(str(fname)) > 0:
            return self.labeltool.saveAnnotations(str(fname))
        return False

    def addMediaFile(self):
        path = '.'
        filename = self.labeltool.getCurrentFilename()
        if (filename is not None) and (len(filename) > 0):
            path = QFileInfo(filename).path()

        image_types = [
            '*.jpg', '*.bmp', '*.png', '*.pgm', '*.ppm', '*.ppm', '*.tif',
            '*.gif'
        ]
        video_types = ['*.mp4', '*.mpg', '*.mpeg', '*.avi', '*.mov', '*.vob']
        format_str = ' '.join(image_types + video_types)
        fnames = QFileDialog.getOpenFileNames(
            self, "%s - Add Media File" % APP_NAME, path,
            "Media files (%s)" % (format_str, ))

        item = None
        for fname in fnames:
            if len(str(fname)) == 0:
                continue

            fname = str(fname)

            if os.path.isabs(fname):
                fname = os.path.relpath(fname, str(path))

            for pattern in image_types:
                if fnmatch.fnmatch(fname, pattern):
                    item = self.labeltool.addImageFile(fname)

        if item is None:
            return self.labeltool.addVideoFile(fname)

        return item

    def onViewsLockedChanged(self, checked):
        features = QDockWidget.AllDockWidgetFeatures
        if checked:
            features = QDockWidget.NoDockWidgetFeatures

        self.ui.dockProperties.setFeatures(features)
        self.ui.dockAnnotations.setFeatures(features)

    ###
    ### global event handling
    ###______________________________________________________________________________
    def closeEvent(self, event):
        if self.okToContinue():
            self.saveApplicationSettings()
        else:
            event.ignore()

    def about(self):
        QMessageBox.about(
            self, "About %s" % APP_NAME, """<b>%s</b> version %s
             <p>This labeling application for computer vision research
             was developed at the CVHCI research group at KIT.
             <p>For more details, visit our homepage: <a href="%s">%s</a>""" %
            (APP_NAME, __version__, ORGANIZATION_DOMAIN, ORGANIZATION_DOMAIN))
Example #49
0
class MainWindow(QMainWindow, Ui_MainWindow):
    qtcb_enumerate = pyqtSignal(str, str, 'char', type((0, )), type((0, )),
                                int, int)
    qtcb_connected = pyqtSignal(int)
    qtcb_disconnected = pyqtSignal(int)

    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)

        self.setupUi(self)

        signal.signal(signal.SIGINT, self.exit_brickv)
        signal.signal(signal.SIGTERM, self.exit_brickv)

        self.async_thread = async_start_thread(self)

        self.setWindowTitle("Brick Viewer " + config.BRICKV_VERSION)

        self.tree_view_model_labels = ['Name', 'UID', 'Position', 'FW Version']
        self.tree_view_model = QStandardItemModel(self)
        self.tree_view.setModel(self.tree_view_model)
        self.tree_view.doubleClicked.connect(self.item_double_clicked)
        self.set_tree_view_defaults()

        # Remove dummy tab
        self.tab_widget.removeTab(1)

        self.name = '<unknown>'
        self.uid = '<unknown>'
        self.version = (0, 0, 0)

        self.disconnect_times = []

        self.qtcb_enumerate.connect(self.cb_enumerate)
        self.qtcb_connected.connect(self.cb_connected)
        self.qtcb_disconnected.connect(self.cb_disconnected)

        self.ipcon = IPConnection()
        self.ipcon.register_callback(IPConnection.CALLBACK_ENUMERATE,
                                     self.qtcb_enumerate.emit)
        self.ipcon.register_callback(IPConnection.CALLBACK_CONNECTED,
                                     self.qtcb_connected.emit)
        self.ipcon.register_callback(IPConnection.CALLBACK_DISCONNECTED,
                                     self.qtcb_disconnected.emit)

        self.current_device_info = None
        self.flashing_window = None
        self.advanced_window = None
        self.data_logger_window = None
        self.delayed_refresh_updates_timer = QTimer()
        self.delayed_refresh_updates_timer.timeout.connect(
            self.delayed_refresh_updates)
        self.delayed_refresh_updates_timer.setInterval(500)
        self.reset_view()
        self.button_advanced.setDisabled(True)

        self.tab_widget.currentChanged.connect(self.tab_changed)
        self.tab_widget.setMovable(True)
        self.tab_widget.tabBar().installEventFilter(self)

        self.button_connect.clicked.connect(self.connect_clicked)
        self.button_flashing.clicked.connect(self.flashing_clicked)
        self.button_advanced.clicked.connect(self.advanced_clicked)
        self.button_data_logger.clicked.connect(self.data_logger_clicked)
        self.plugin_manager = PluginManager()

        # host info
        self.host_infos = config.get_host_infos(config.HOST_INFO_COUNT)
        self.host_index_changing = True

        for host_info in self.host_infos:
            self.combo_host.addItem(host_info.host)

        self.last_host = None
        self.combo_host.currentIndexChanged.connect(self.host_index_changed)

        self.spinbox_port.setValue(self.host_infos[0].port)
        self.spinbox_port.valueChanged.connect(self.port_changed)

        self.checkbox_authentication.stateChanged.connect(
            self.authentication_state_changed)

        self.label_secret.hide()
        self.edit_secret.hide()
        self.edit_secret.setEchoMode(QLineEdit.Password)
        self.edit_secret.textEdited.connect(self.secret_changed)

        self.checkbox_secret_show.hide()
        self.checkbox_secret_show.stateChanged.connect(
            self.secret_show_state_changed)

        self.checkbox_remember_secret.hide()
        self.checkbox_remember_secret.stateChanged.connect(
            self.remember_secret_state_changed)

        self.checkbox_authentication.setChecked(
            self.host_infos[0].use_authentication)
        self.edit_secret.setText(self.host_infos[0].secret)
        self.checkbox_remember_secret.setChecked(
            self.host_infos[0].remember_secret)

        self.host_index_changing = False

        # auto-reconnect
        self.label_auto_reconnects.hide()
        self.auto_reconnects = 0

        # RED Session losts
        self.label_red_session_losts.hide()
        self.red_session_losts = 0

    # override QMainWindow.closeEvent
    def closeEvent(self, event):
        if not self.exit_logger():
            event.ignore()
            return

        self.exit_brickv()

    def exit_brickv(self, signl=None, frme=None):
        if self.current_device_info is not None:
            self.current_device_info.plugin.stop_plugin()
            self.current_device_info.plugin.destroy_plugin()

        self.update_current_host_info()
        config.set_host_infos(self.host_infos)

        self.do_disconnect()

        if signl != None and frme != None:
            print("Received SIGINT or SIGTERM, shutting down.")
            sys.exit()

    def exit_logger(self):
        exitBrickv = True
        if (self.data_logger_window is not None) and (
                self.data_logger_window.data_logger_thread is not None) and (
                    not self.data_logger_window.data_logger_thread.stopped):
            quit_msg = "The Data Logger is running. Are you sure you want to exit the program?"
            reply = QMessageBox.question(self, 'Message', quit_msg,
                                         QMessageBox.Yes, QMessageBox.No)

            if reply == QMessageBox.Yes:
                self.data_logger_window.data_logger_thread.stop()
            else:
                exitBrickv = False

        return exitBrickv

    def host_index_changed(self, i):
        if i < 0:
            return

        self.host_index_changing = True

        self.spinbox_port.setValue(self.host_infos[i].port)
        self.checkbox_authentication.setChecked(
            self.host_infos[i].use_authentication)
        self.edit_secret.setText(self.host_infos[i].secret)
        self.checkbox_remember_secret.setChecked(
            self.host_infos[i].remember_secret)

        self.host_index_changing = False

    def port_changed(self, value):
        self.update_current_host_info()

    def authentication_state_changed(self, state):
        visible = state == Qt.Checked

        self.label_secret.setVisible(visible)
        self.edit_secret.setVisible(visible)
        self.checkbox_secret_show.setVisible(visible)
        self.checkbox_remember_secret.setVisible(visible)

        self.update_current_host_info()

    def secret_changed(self):
        self.update_current_host_info()

    def secret_show_state_changed(self, state):
        if state == Qt.Checked:
            self.edit_secret.setEchoMode(QLineEdit.Normal)
        else:
            self.edit_secret.setEchoMode(QLineEdit.Password)

        self.update_current_host_info()

    def remember_secret_state_changed(self, state):
        self.update_current_host_info()

    def tab_changed(self, i):
        if not hasattr(self.tab_widget.widget(i), '_info'):
            new_current_device_info = None
        else:
            new_current_device_info = self.tab_widget.widget(i)._info
            new_current_device_info.plugin.start_plugin()

        # stop the now deselected plugin, if there is one that's running
        if self.current_device_info is not None:
            self.current_device_info.plugin.stop_plugin()

        self.current_device_info = new_current_device_info

    def update_current_host_info(self):
        if self.host_index_changing:
            return

        i = self.combo_host.currentIndex()

        if i < 0:
            return

        #self.host_infos[i].host = self.combo_host.currentText()
        self.host_infos[i].port = self.spinbox_port.value()
        self.host_infos[
            i].use_authentication = self.checkbox_authentication.isChecked()
        self.host_infos[i].secret = self.edit_secret.text()
        self.host_infos[
            i].remember_secret = self.checkbox_remember_secret.isChecked()

    def remove_all_device_infos(self):
        for device_info in infos.get_device_infos():
            self.remove_device_info(device_info.uid)

    def remove_device_info(self, uid):
        tab_id = self.tab_for_uid(uid)
        device_info = infos.get_info(uid)

        device_info.plugin.stop_plugin()
        device_info.plugin.destroy_plugin()

        if tab_id >= 0:
            self.tab_widget.removeTab(tab_id)

        # ensure that the widget gets correctly destroyed. otherwise QWidgets
        # tend to leak as Python is not able to collect their PyQt object
        tab_window = device_info.tab_window
        device_info.tab_window = None

        # If we reboot the RED Brick, the tab_window sometimes is
        # already None here
        if tab_window != None:
            tab_window.hide()
            tab_window.setParent(None)

        plugin = device_info.plugin
        device_info.plugin = None

        if plugin != None:
            plugin.hide()
            plugin.setParent(None)

        infos.remove_info(uid)

    def reset_view(self):
        self.tab_widget.setCurrentIndex(0)
        self.remove_all_device_infos()
        self.update_tree_view()

    def do_disconnect(self):
        self.auto_reconnects = 0
        self.label_auto_reconnects.hide()

        self.red_session_losts = 0
        self.label_red_session_losts.hide()

        self.reset_view()
        async_next_session()

        # force garbage collection, to ensure that all plugin related objects
        # got destroyed before disconnect is called. this is especially
        # important for the RED Brick plugin because its relies on releasing
        # the the RED Brick API objects in the __del__ method as a last resort
        # to avoid leaking object references. but this only works if garbage
        # collection is done before disconnect is called
        gc.collect()

        try:
            self.ipcon.disconnect()
        except:
            pass

    def do_authenticate(self, is_auto_reconnect):
        if not self.checkbox_authentication.isChecked():
            return True

        try:
            secret = self.edit_secret.text().encode('ascii')
        except:
            self.do_disconnect()

            QMessageBox.critical(
                self, 'Connection',
                'Authentication secret cannot contain non-ASCII characters.',
                QMessageBox.Ok)
            return False

        self.ipcon.set_auto_reconnect(
            False)  # don't auto-reconnect on authentication error

        try:
            self.ipcon.authenticate(secret)
        except:
            self.do_disconnect()

            if is_auto_reconnect:
                extra = ' after auto-reconnect'
            else:
                extra = ''

            QMessageBox.critical(
                self, 'Connection', 'Could not authenticate' + extra +
                '. Check secret and ensure ' +
                'authentication for Brick Daemon is enabled.', QMessageBox.Ok)
            return False

        self.ipcon.set_auto_reconnect(True)

        return True

    def flashing_clicked(self):
        if self.flashing_window is None:
            self.flashing_window = FlashingWindow(self)

        self.flashing_window.show()
        self.flashing_window.refresh_updates_clicked()

    def advanced_clicked(self):
        if self.advanced_window is None:
            self.advanced_window = AdvancedWindow(self)

        self.advanced_window.show()

    def data_logger_clicked(self):
        if self.data_logger_window is None:
            self.data_logger_window = DataLoggerWindow(self)

        self.data_logger_window.show()

    def connect_clicked(self):
        if self.ipcon.get_connection_state(
        ) == IPConnection.CONNECTION_STATE_DISCONNECTED:
            try:
                self.last_host = self.combo_host.currentText()
                self.button_connect.setDisabled(True)
                self.button_connect.setText("Connecting ...")
                self.button_connect.repaint()
                QApplication.processEvents()
                self.ipcon.connect(self.last_host, self.spinbox_port.value())
            except:
                self.button_connect.setDisabled(False)
                self.button_connect.setText("Connect")
                QMessageBox.critical(
                    self, 'Connection',
                    'Could not connect. Please check host, check ' +
                    'port and ensure that Brick Daemon is running.')
        else:
            self.do_disconnect()

    def item_double_clicked(self, index):
        position_index = index.sibling(index.row(), 2)

        if position_index.isValid() and position_index.data().startswith(
                'Ext'):
            index = index.parent()

        uid_index = index.sibling(index.row(), 1)

        if uid_index.isValid():
            self.show_plugin(uid_index.data())

    def create_tab_window(self, device_info):
        tab_window = TabWindow(self.tab_widget, device_info.name, self.untab)
        tab_window._info = device_info
        tab_window.set_callback_on_tab(lambda index:
            self.ipcon.get_connection_state() == IPConnection.CONNECTION_STATE_PENDING and \
                self.tab_widget.setTabEnabled(index, False))

        layout = QVBoxLayout(tab_window)
        info_bar = QHBoxLayout()

        # uid
        info_bar.addWidget(QLabel('UID:'))

        label = QLabel('{0}'.format(device_info.uid))
        label.setTextInteractionFlags(Qt.TextSelectableByMouse
                                      | Qt.TextSelectableByKeyboard)

        info_bar.addWidget(label)
        info_bar.addSpacerItem(QSpacerItem(1, 1, QSizePolicy.Expanding))

        # connected uid
        if device_info.connected_uid != '0':
            info_bar.addWidget(QLabel('Connected to:'))

            button = QToolButton()
            button.setText(device_info.connected_uid)
            button.clicked.connect(
                lambda: self.show_plugin(device_info.connected_uid))

            info_bar.addWidget(button)
            info_bar.addSpacerItem(QSpacerItem(1, 1, QSizePolicy.Expanding))

        # position
        info_bar.addWidget(QLabel('Position:'))
        info_bar.addWidget(QLabel('{0}'.format(device_info.position.upper())))

        info_bar.addSpacerItem(QSpacerItem(1, 1, QSizePolicy.Expanding))

        # firmware version
        label_version_name = QLabel('Version:')
        label_version = QLabel('...')

        if not device_info.plugin.has_custom_version(label_version_name,
                                                     label_version):
            label_version_name.setText('FW Version:')
            label_version.setText(
                infos.get_version_string(device_info.plugin.firmware_version))

        info_bar.addWidget(label_version_name)
        info_bar.addWidget(label_version)

        info_bar.addSpacerItem(QSpacerItem(1, 1, QSizePolicy.Expanding))

        # timeouts
        info_bar.addWidget(QLabel('Timeouts:'))
        label_timeouts = QLabel('0')
        info_bar.addWidget(label_timeouts)

        layout.addLayout(info_bar)

        # actions
        actions = device_info.plugin.get_actions()

        if actions != None:
            if type(actions) == QAction:
                button = QPushButton(actions.text())
                button.clicked.connect(actions.trigger)
            else:
                button = QToolButton()
                button.setText(actions[0])
                button.setPopupMode(QToolButton.InstantPopup)
                button.setToolButtonStyle(Qt.ToolButtonTextOnly)
                button.setArrowType(Qt.DownArrow)
                button.setAutoRaise(True)

                menu = QMenu(actions[0])
                button.setMenu(menu)

                for action in actions[1]:
                    menu.addAction(action)

            info_bar.addSpacerItem(QSpacerItem(40, 20, QSizePolicy.Expanding))
            info_bar.addWidget(button)

        line = QFrame()
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)

        device_info.plugin.label_timeouts = label_timeouts
        device_info.plugin.layout().setContentsMargins(0, 0, 0, 0)

        layout.addWidget(line)
        layout.addWidget(device_info.plugin)

        return tab_window

    def tab_move(self, event):
        # visualize rearranging of tabs (if allowed by tab_widget)
        if self.tab_widget.isMovable():
            if event.type(
            ) == QEvent.MouseButtonPress and event.button() & Qt.LeftButton:
                QApplication.setOverrideCursor(QCursor(Qt.SizeHorCursor))

            elif event.type(
            ) == QEvent.MouseButtonRelease and event.button() & Qt.LeftButton:
                QApplication.restoreOverrideCursor()

        return False

    def untab(self, tab_index):
        tab = self.tab_widget.widget(tab_index)
        tab.untab()
        tab._info.plugin.start_plugin()
        self.tab_widget.setCurrentIndex(0)

    def eventFilter(self, source, event):
        if source is self.tab_widget.tabBar():
            return self.tab_move(event)

        return False

    def tab_for_uid(self, uid):
        for i in range(1, self.tab_widget.count()):
            try:
                if self.tab_widget.widget(i)._info.uid == uid:
                    return i
            except:
                pass

        return -1

    def show_plugin(self, uid):
        i = self.tab_for_uid(uid)
        tab_window = infos.get_info(uid).tab_window

        if i > 0 and self.tab_widget.isTabEnabled(i):
            self.tab_widget.setCurrentIndex(i)

        QApplication.setActiveWindow(tab_window)

        tab_window.show()
        tab_window.activateWindow()
        tab_window.raise_()

    def cb_enumerate(self, uid, connected_uid, position, hardware_version,
                     firmware_version, device_identifier, enumeration_type):
        if self.ipcon.get_connection_state(
        ) != IPConnection.CONNECTION_STATE_CONNECTED:
            # ignore enumerate callbacks that arrived after the connection got closed
            return

        if enumeration_type in [
                IPConnection.ENUMERATION_TYPE_AVAILABLE,
                IPConnection.ENUMERATION_TYPE_CONNECTED
        ]:
            device_info = infos.get_info(uid)
            something_changed_ref = [False]

            if device_info == None:
                if device_identifier == BrickMaster.DEVICE_IDENTIFIER:
                    device_info = infos.BrickMasterInfo()
                elif device_identifier == BrickRED.DEVICE_IDENTIFIER:
                    device_info = infos.BrickREDInfo()
                elif position in ('a', 'b', 'c', 'd', 'A', 'B', 'C', 'D'):
                    position = position.lower()
                    device_info = infos.BrickletInfo()
                else:
                    device_info = infos.BrickInfo()
                    something_changed_ref[0] = True

            def set_device_info_value(name, value):
                if getattr(device_info, name) != value:
                    setattr(device_info, name, value)
                    something_changed_ref[0] = True

            set_device_info_value('uid', uid)
            set_device_info_value('connected_uid', connected_uid)
            set_device_info_value('position', position)
            set_device_info_value('hardware_version', hardware_version)
            set_device_info_value('firmware_version_installed',
                                  firmware_version)
            set_device_info_value('device_identifier', device_identifier)
            set_device_info_value('protocol_version', 2)
            set_device_info_value('enumeration_type', enumeration_type)

            if device_info.type == 'bricklet':
                for brick_info in infos.get_brick_infos():
                    if brick_info.uid == device_info.connected_uid:
                        if brick_info.bricklets[position] != device_info:
                            brick_info.bricklets[position] = device_info
                            something_changed_ref[0] = True
            elif device_info.type == 'brick':
                for bricklet_info in infos.get_bricklet_infos():
                    if bricklet_info.connected_uid == device_info.uid:
                        if device_info.bricklets[
                                bricklet_info.position] != bricklet_info:
                            device_info.bricklets[
                                bricklet_info.position] = bricklet_info
                            something_changed_ref[0] = True

            if device_info.plugin == None:
                self.plugin_manager.create_plugin_instance(
                    device_identifier, self.ipcon, device_info)

                device_info.tab_window = self.create_tab_window(device_info)
                device_info.tab_window.setWindowFlags(Qt.Widget)
                device_info.tab_window.tab()

                infos.add_info(device_info)

                something_changed_ref[0] = True

            if something_changed_ref[0]:
                self.update_tree_view()
        elif enumeration_type == IPConnection.ENUMERATION_TYPE_DISCONNECTED:
            for device_info in infos.get_device_infos():
                if device_info.uid == uid:
                    self.tab_widget.setCurrentIndex(0)
                    self.remove_device_info(device_info.uid)

                if device_info.type == 'brick':
                    for port in device_info.bricklets:
                        if device_info.bricklets[
                                port] and device_info.bricklets[
                                    port].uid == uid:
                            device_info.bricklets[port] = None

            self.update_tree_view()

    def hack_to_remove_red_brick_tab(self, red_brick_uid):
        for device_info in infos.get_device_infos():
            if device_info.uid == red_brick_uid:
                self.tab_widget.setCurrentIndex(0)
                self.remove_device_info(device_info.uid)

                self.red_session_losts += 1
                self.label_red_session_losts.setText(
                    'RED Brick Session Loss Count: {0}'.format(
                        self.red_session_losts))
                self.label_red_session_losts.show()

                break

        self.update_tree_view()

    def cb_connected(self, connect_reason):
        self.disconnect_times = []

        self.update_ui_state()

        if connect_reason == IPConnection.CONNECT_REASON_REQUEST:
            self.auto_reconnects = 0
            self.label_auto_reconnects.hide()

            self.red_session_losts = 0
            self.label_red_session_losts.hide()

            self.ipcon.set_auto_reconnect(True)

            index = self.combo_host.findText(self.last_host)

            if index >= 0:
                self.combo_host.removeItem(index)

                host_info = self.host_infos[index]

                del self.host_infos[index]
                self.host_infos.insert(0, host_info)
            else:
                index = self.combo_host.currentIndex()

                host_info = self.host_infos[index].duplicate()
                host_info.host = self.last_host

                self.host_infos.insert(0, host_info)

            self.combo_host.insertItem(-1, self.last_host)
            self.combo_host.setCurrentIndex(0)

            while self.combo_host.count() > config.HOST_INFO_COUNT:
                self.combo_host.removeItem(self.combo_host.count() - 1)

            if not self.do_authenticate(False):
                return

            try:
                self.ipcon.enumerate()
            except:
                self.update_ui_state()
        elif connect_reason == IPConnection.CONNECT_REASON_AUTO_RECONNECT:
            self.auto_reconnects += 1
            self.label_auto_reconnects.setText(
                'Auto-Reconnect Count: {0}'.format(self.auto_reconnects))
            self.label_auto_reconnects.show()

            if not self.do_authenticate(True):
                return

            try:
                self.ipcon.enumerate()
            except:
                self.update_ui_state()
        else:
            try:
                self.ipcon.enumerate()
            except:
                self.update_ui_state()

    def cb_disconnected(self, disconnect_reason):
        if disconnect_reason == IPConnection.DISCONNECT_REASON_REQUEST:
            self.auto_reconnects = 0
            self.label_auto_reconnects.hide()

            self.red_session_losts = 0
            self.label_red_session_losts.hide()

        if disconnect_reason == IPConnection.DISCONNECT_REASON_REQUEST or not self.ipcon.get_auto_reconnect(
        ):
            self.update_ui_state()
        elif len(self.disconnect_times
                 ) >= 3 and self.disconnect_times[-3] < time.time() + 1:
            self.disconnect_times = []
            self.ipcon.set_auto_reconnect(False)
            self.update_ui_state()
            self.reset_view()

            QMessageBox.critical(
                self, 'Connection',
                'Stopped automatic reconnecting due to multiple connection errors in a row.'
            )
        else:
            self.disconnect_times.append(time.time())
            self.update_ui_state(IPConnection.CONNECTION_STATE_PENDING)

    def set_tree_view_defaults(self):
        self.tree_view_model.setHorizontalHeaderLabels(
            self.tree_view_model_labels)
        self.tree_view.expandAll()
        self.tree_view.setColumnWidth(0, 250)
        self.tree_view.setColumnWidth(1, 85)
        self.tree_view.setColumnWidth(2, 85)
        self.tree_view.setColumnWidth(3, 90)
        self.tree_view.setExpandsOnDoubleClick(False)
        self.tree_view.setSortingEnabled(True)
        self.tree_view.header().setSortIndicator(2, Qt.AscendingOrder)

    def update_ui_state(self, connection_state=None):
        # FIXME: need to call processEvents() otherwise get_connection_state()
        #        might return the wrong value
        QApplication.processEvents()

        if connection_state is None:
            connection_state = self.ipcon.get_connection_state()

        self.button_connect.setDisabled(False)
        self.button_flashing.setDisabled(False)

        if connection_state == IPConnection.CONNECTION_STATE_DISCONNECTED:
            self.button_connect.setText('Connect')
            self.combo_host.setDisabled(False)
            self.spinbox_port.setDisabled(False)
            self.checkbox_authentication.setDisabled(False)
            self.edit_secret.setDisabled(False)
            self.button_advanced.setDisabled(True)
        elif connection_state == IPConnection.CONNECTION_STATE_CONNECTED:
            self.button_connect.setText("Disconnect")
            self.combo_host.setDisabled(True)
            self.spinbox_port.setDisabled(True)
            self.checkbox_authentication.setDisabled(True)
            self.edit_secret.setDisabled(True)
            self.update_advanced_window()

            # restart all pause plugins
            for info in infos.get_device_infos():
                info.plugin.resume_plugin()
        elif connection_state == IPConnection.CONNECTION_STATE_PENDING:
            self.button_connect.setText('Abort Pending Automatic Reconnect')
            self.combo_host.setDisabled(True)
            self.spinbox_port.setDisabled(True)
            self.checkbox_authentication.setDisabled(True)
            self.edit_secret.setDisabled(True)
            self.button_advanced.setDisabled(True)
            self.button_flashing.setDisabled(True)

            # pause all running plugins
            for info in infos.get_device_infos():
                info.plugin.pause_plugin()

        enable = connection_state == IPConnection.CONNECTION_STATE_CONNECTED

        for i in range(1, self.tab_widget.count()):
            self.tab_widget.setTabEnabled(i, enable)

        for device_info in infos.get_device_infos():
            device_info.tab_window.setEnabled(enable)

        QApplication.processEvents()

    def update_tree_view(self):
        sis = self.tree_view.header().sortIndicatorSection()
        sio = self.tree_view.header().sortIndicatorOrder()

        self.tree_view_model.clear()

        for info in infos.get_brick_infos():
            parent = [
                QStandardItem(info.name),
                QStandardItem(info.uid),
                QStandardItem(info.position.upper()),
                QStandardItem('.'.join(
                    map(str, info.firmware_version_installed)))
            ]

            for item in parent:
                item.setFlags(item.flags() & ~Qt.ItemIsEditable)

            self.tree_view_model.appendRow(parent)

            for port in sorted(info.bricklets):
                if info.bricklets[port] and info.bricklets[
                        port].protocol_version == 2:
                    child = [
                        QStandardItem(info.bricklets[port].name),
                        QStandardItem(info.bricklets[port].uid),
                        QStandardItem(info.bricklets[port].position.upper()),
                        QStandardItem('.'.join(
                            map(
                                str, info.bricklets[port].
                                firmware_version_installed)))
                    ]
                    for item in child:
                        item.setFlags(item.flags() & ~Qt.ItemIsEditable)
                    parent[0].appendRow(child)

            if info.can_have_extension:
                extensions = []
                if info.extensions['ext0'] != None:
                    extensions.append((info.extensions['ext0'], 'Ext0'))
                if info.extensions['ext1'] != None:
                    extensions.append((info.extensions['ext1'], 'Ext1'))

                for extension in extensions:
                    child = [
                        QStandardItem(extension[0].name),
                        QStandardItem(''),
                        QStandardItem(extension[1]),
                        QStandardItem('')
                    ]
                    for item in child:
                        item.setFlags(item.flags() & ~Qt.ItemIsEditable)
                    parent[0].appendRow(child)

        self.set_tree_view_defaults()
        self.tree_view.header().setSortIndicator(sis, sio)
        self.update_advanced_window()
        self.delayed_refresh_updates_timer.start()

    def update_advanced_window(self):
        self.button_advanced.setEnabled(len(infos.get_brick_infos()) > 0)

    def delayed_refresh_updates(self):
        self.delayed_refresh_updates_timer.stop()

        if self.flashing_window is not None and self.flashing_window.isVisible(
        ):
            self.flashing_window.refresh_updates_clicked()
Example #50
0
class Barometer(PluginBase):
    def __init__(self, *args):
        PluginBase.__init__(self, BrickletBarometer, *args)

        self.barometer = self.device

        has_calibrate = self.firmware_version == (1, 0, 0)
        has_averaging = self.firmware_version >= (2, 0, 1)

        self.moving_average_pressure = 25
        self.average_pressure = 10
        self.average_temperature = 10

        self.cbe_air_pressure = CallbackEmulator(
            self.barometer.get_air_pressure, self.cb_air_pressure,
            self.increase_error_count)
        self.cbe_altitude = CallbackEmulator(self.barometer.get_altitude,
                                             self.cb_altitude,
                                             self.increase_error_count)

        self.air_pressure_label = AirPressureLabel()

        self.altitude_label = AltitudeLabel()

        self.chip_temperature_label = ChipTemperatureLabel()
        if has_calibrate:
            self.chip_temperature_label.setAlignment(Qt.AlignCenter)

        self.current_air_pressure = None
        self.current_altitude = None

        plot_list = [['', Qt.red, self.get_current_air_pressure]]
        self.air_pressure_plot_widget = PlotWidget('Air Pressure [mbar]',
                                                   plot_list)

        plot_list = [['', Qt.darkGreen, self.get_current_altitude]]
        self.altitude_plot_widget = PlotWidget('Altitude [m]', plot_list)

        if has_calibrate:
            self.calibrate_button = QPushButton('Calibrate Altitude')
            self.calibrate_button.clicked.connect(self.calibrate_clicked)
        else:
            self.get_reference_button = QPushButton('Get')
            self.get_reference_button.clicked.connect(
                self.get_reference_clicked)
            self.set_reference_button = QPushButton('Set')
            self.set_reference_button.clicked.connect(
                self.set_reference_clicked)
            self.reference_label = QLabel('Reference Air Pressure [mbar]:')
            self.reference_edit = QLineEdit()
            self.get_reference_clicked()

        if has_averaging:
            self.avg_pressure_box = QSpinBox()
            self.avg_pressure_box.setMinimum(0)
            self.avg_pressure_box.setMaximum(10)
            self.avg_pressure_box.setSingleStep(1)
            self.avg_pressure_box.setValue(10)
            self.avg_temperature_box = QSpinBox()
            self.avg_temperature_box.setMinimum(0)
            self.avg_temperature_box.setMaximum(255)
            self.avg_temperature_box.setSingleStep(1)
            self.avg_temperature_box.setValue(10)
            self.avg_moving_pressure_box = QSpinBox()
            self.avg_moving_pressure_box.setMinimum(0)
            self.avg_moving_pressure_box.setMaximum(25)
            self.avg_moving_pressure_box.setSingleStep(1)
            self.avg_moving_pressure_box.setValue(25)

            self.avg_pressure_box.editingFinished.connect(
                self.avg_pressure_box_finished)
            self.avg_temperature_box.editingFinished.connect(
                self.avg_temperature_box_finished)
            self.avg_moving_pressure_box.editingFinished.connect(
                self.avg_moving_pressure_box_finished)

        layout_h1 = QHBoxLayout()
        layout_h1.addStretch()
        layout_h1.addWidget(self.air_pressure_label)
        layout_h1.addStretch()

        layout_v1 = QVBoxLayout()
        layout_v1.addLayout(layout_h1)
        layout_v1.addWidget(self.air_pressure_plot_widget)

        layout_h2 = QHBoxLayout()
        layout_h2.addStretch()
        layout_h2.addWidget(self.altitude_label)
        layout_h2.addStretch()

        layout_v2 = QVBoxLayout()
        layout_v2.addLayout(layout_h2)
        layout_v2.addWidget(self.altitude_plot_widget)

        if has_calibrate:
            layout_h3 = QHBoxLayout()
            layout_h3.addWidget(self.chip_temperature_label)
            layout_h3.addWidget(self.calibrate_button)
        else:
            layout_h3 = QHBoxLayout()
            layout_h3.addWidget(self.reference_label)
            layout_h3.addWidget(self.reference_edit)
            layout_h3.addWidget(self.get_reference_button)
            layout_h3.addWidget(self.set_reference_button)

            layout_v3 = QVBoxLayout()
            layout_v3.addWidget(self.chip_temperature_label)
            layout_v3.addLayout(layout_h3)

        if has_averaging:
            line1 = QFrame()
            line1.setFrameShape(QFrame.VLine)
            line1.setFrameShadow(QFrame.Sunken)
            line2 = QFrame()
            line2.setFrameShape(QFrame.VLine)
            line2.setFrameShadow(QFrame.Sunken)

            layout_h4 = QHBoxLayout()
            layout_h4.addWidget(QLabel('Air Pressure Moving Average Length:'))
            layout_h4.addWidget(self.avg_moving_pressure_box)
            layout_h4.addWidget(line1)
            layout_h4.addWidget(QLabel('Air Pressure Average Length:'))
            layout_h4.addWidget(self.avg_pressure_box)
            layout_h4.addWidget(line2)
            layout_h4.addWidget(QLabel('Temperate Average Length:'))
            layout_h4.addWidget(self.avg_temperature_box)

        layout_h1 = QHBoxLayout()
        layout_h1.addLayout(layout_v1)
        layout_h1.addLayout(layout_v2)

        layout = QVBoxLayout(self)
        layout.addLayout(layout_h1)

        if has_calibrate:
            layout.addLayout(layout_h3)
        else:
            layout.addLayout(layout_v3)

        if has_averaging:
            lineh = QFrame()
            lineh.setFrameShape(QFrame.HLine)
            lineh.setFrameShadow(QFrame.Sunken)
            layout.addWidget(lineh)
            layout.addLayout(layout_h4)

        self.chip_temp_timer = QTimer()
        self.chip_temp_timer.timeout.connect(self.update_chip_temp)
        self.chip_temp_timer.setInterval(100)

    def start(self):
        async_call(self.barometer.get_air_pressure, None, self.cb_air_pressure,
                   self.increase_error_count)
        async_call(self.barometer.get_altitude, None, self.cb_altitude,
                   self.increase_error_count)

        self.cbe_air_pressure.set_period(100)
        self.cbe_altitude.set_period(100)

        async_call(self.barometer.get_averaging, None, self.cb_averaging,
                   self.increase_error_count)

        self.air_pressure_plot_widget.stop = False
        self.altitude_plot_widget.stop = False

        self.update_chip_temp()
        self.chip_temp_timer.start()

    def stop(self):
        self.cbe_air_pressure.set_period(0)
        self.cbe_altitude.set_period(0)

        self.air_pressure_plot_widget.stop = True
        self.altitude_plot_widget.stop = True

        self.chip_temp_timer.stop()

    def destroy(self):
        pass

    def get_url_part(self):
        return 'barometer'

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletBarometer.DEVICE_IDENTIFIER

    def cb_averaging(self, avg):
        moving_average_pressure, average_pressure, average_temperature = avg
        self.moving_average_pressure = moving_average_pressure
        self.average_pressure = average_pressure
        self.average_temperature = average_temperature

        self.avg_moving_pressure_box.setValue(moving_average_pressure)
        self.avg_pressure_box.setValue(average_pressure)
        self.avg_temperature_box.setValue(average_temperature)

    def avg_pressure_box_finished(self):
        self.average_pressure = self.avg_pressure_box.value()
        self.save_new_averaging()

    def avg_temperature_box_finished(self):
        self.average_temperature = self.avg_temperature_box.value()
        self.save_new_averaging()

    def avg_moving_pressure_box_finished(self):
        self.moving_average_pressure = self.avg_moving_pressure_box.value()
        self.save_new_averaging()

    def save_new_averaging(self):
        self.barometer.set_averaging(self.moving_average_pressure,
                                     self.average_pressure,
                                     self.average_temperature)

    def calibrate_clicked(self):
        try:
            # Call set_reference_air_pressure that has the same function ID as
            # calibrate_altitude the extra parameter will just be ignored
            self.barometer.set_reference_air_pressure(0)
        except ip_connection.Error:
            pass

    def get_reference_clicked_async(self, reference):
        r = str(reference / 1000.0)
        self.reference_edit.setText(r)

    def get_reference_clicked(self):
        async_call(self.barometer.get_reference_air_pressure, None,
                   self.get_reference_clicked_async, self.increase_error_count)

    def set_reference_clicked(self):
        try:
            r = round(float(self.reference_edit.text()) * 1000)
        except:
            self.reference_edit.setText('Invalid input')
            return

        try:
            self.barometer.set_reference_air_pressure(r)
        except ip_connection.Error:
            self.reference_edit.setText(
                'Error while setting reference air pressure')
            return

    def get_current_air_pressure(self):
        return self.current_air_pressure

    def get_current_altitude(self):
        return self.current_altitude

    def update_chip_temp_async(self, temp):
        t = temp / 100.0
        self.chip_temperature_label.setText('%.2f' % t)

    def update_chip_temp(self):
        async_call(self.barometer.get_chip_temperature, None,
                   self.update_chip_temp_async, self.increase_error_count)

    def cb_air_pressure(self, air_pressure):
        self.current_air_pressure = air_pressure / 1000.0
        self.air_pressure_label.setText('%.3f' % self.current_air_pressure)

    def cb_altitude(self, altitude):
        self.current_altitude = altitude / 100.0
        self.altitude_label.setText('%.2f' % self.current_altitude,
                                    '%.2f' % (self.current_altitude / 0.3048))
Example #51
0
class LI3DSPlugin_Arduino(ILI3DSPlugin_Tabs):
    # Qt Signals
    signal_arduino_state_start_on = pyqtSignal()
    signal_arduino_state_start_off = pyqtSignal()

    def __init__(self, *args, **kwargs):
        """

        :param args:
        :param kwargs:
        """
        super(LI3DSPlugin_Arduino, self).__init__(*args, **kwargs)

        # tab: Arduino
        self.states.set_state('arduino', 'flash')
        self.states.set_state('arduino', 'start')
        self.states.set_state('arduino', 'pause')

        self.gui.widget.pushButton_arduino_start.clicked[bool].connect(self.on_pushButton_arduino_start_clicked)
        self.gui.widget.pushButton_arduino_flash.clicked[bool].connect(self.on_pushButton_arduino_flash_clicked)
        self.gui.widget.pushButton_arduino_pause.clicked[bool].connect(self.on_pushButton_arduino_pause_clicked)
        #
        self._update_arduino_states_pixmaps()

        # Arduino - States
        self._update_gui_arduino_states_timer = QTimer()
        self._update_gui_arduino_states_timer.timeout.connect(self._on_update_gui_arduino_states_timer)
        self._update_gui_arduino_states_timer.setInterval(500)
        # Arduino - Diagnostics
        self._update_gui_arduino_diags_timer = QTimer()
        self._update_gui_arduino_diags_timer.timeout.connect(self._on_update_gui_arduino_diagnostics_timer)
        self._update_gui_arduino_diags_timer.setInterval(500)

        self._update_gui_arduino_states_timer.start()
        self._update_gui_arduino_diags_timer.start()

        # url:
        # ps: le tableau t2_t3_t4[3] est converti par rosmsg comme un chr()*3 (par soucy d'optimisation j'imagine).
        # Du coup, on ne recupere pas directement la valeur de l'entier mais la correspondance char.
        self.map_arduino_to_qt_ros_msg = {
            '/GPS/Clock/t2': lambda msg: ord(msg.t2_t3_t4[0]),
            '/GPS/Clock/t3': lambda msg: ord(msg.t2_t3_t4[1]),
            '/GPS/Clock/t4': lambda msg: ord(msg.t2_t3_t4[2]),
            '/GPS/PPS': lambda msg: 0,
            '/CamLight/nb_trigs': lambda msg: msg.num_trigs_for_pics,
            '/CamLight/states/boot': lambda msg: msg.state_boot
        }
        # '/CamLight/time_between_pics': lambda msg: msg.time_between_pics,

        # ---------------------------------
        # PUBLISHERS
        # ---------------------------------
        self._pub_arduino_commands, self._msg_arduino_commands = self.ros.find_publisher('/Arduino/sub/cmds')
        # ---------------------------------

        # ---------------------------------
        # SUBSCRIBERS
        # ---------------------------------
        # Arduino States
        self._sub_arduino_states = self.ros.subscribe_to_topic(
            '/Arduino/pub/states',
            self._cb_arduino_states, queue_size=10
        )

        self._msg_arduino_states = None

        self._play_sound = True
        rp = rospkg.RosPack()
        self.path_to_sound = path_to_sound = os.path.join(rp.get_path('rqt_li3ds'), 'resource',
                                                          'Click2-Sebastian-759472264.wav')
        # urls:
        # - https://github.com/Katee/quietnet/issues/18
        # - http://stackoverflow.com/questions/17657103/how-to-play-wav-file-in-python
        # - http://soundbible.com/1705-Click2.html
        self._sounds = {
            'click': AudioFile(path_to_sound)
        }
        self.li3ds_plugin.loginfo('arduino', 'path_to_sound: %s' % path_to_sound)

    def _update_arduino_states_pixmaps(self):
        """
        """
        self.gui.update_label_pixmap_onoff('arduino', 'flash')
        self.gui.update_label_pixmap_onoff('arduino', 'start')
        self.gui.update_label_pixmap_onoff('arduino', 'pause')

    @pyqtSlot(bool)
    def on_pushButton_arduino_start_clicked(self, checked):
        rospy.loginfo("[Arduino][Commands] - 'Start' button pushed!")
        #
        state = self.states.switch_state('arduino', 'start',
                                         update_label_pixmap=self.gui.update_label_pixmap_onoff, update_ros=True)
        #
        self.gui.widget.pushButton_arduino_start.setText(str(('Disable' if state else 'Enable') + ' Start'))

    @pyqtSlot(bool)
    def on_pushButton_arduino_flash_clicked(self, checked):
        rospy.loginfo("[Arduino][Commands] - 'Flash' button pushed!")
        state = self.states.switch_state('arduino', 'flash',
                                         update_label_pixmap=self.gui.update_label_pixmap_onoff, update_ros=True)
        self.gui.widget.pushButton_arduino_flash.setText(str(('Disable' if state else 'Enable') + ' Flash'))

    @pyqtSlot(bool)
    def on_pushButton_arduino_pause_clicked(self, checked):
        rospy.loginfo("[Arduino][Commands] - 'Pause' button pushed!")
        state = self.states.switch_state('arduino', 'pause',
                                         update_label_pixmap=self.gui.update_label_pixmap_onoff, update_ros=True)
        self.gui.widget.pushButton_arduino_pause.setText(str(('Disable' if state else 'Enable') + ' Pause'))

    def _on_update_gui_arduino_states_timer(self):
        """

        """
        # Synch
        _msg_arduino_states = self._msg_arduino_states
        #
        if _msg_arduino_states:
            self.gui.widget.textEdit_arduino_flash.setText(str(_msg_arduino_states.state_flash))
            self.gui.widget.textEdit_arduino_pause.setText(str(_msg_arduino_states.state_pause))
            self.gui.widget.textEdit_arduino_start.setText(str(_msg_arduino_states.state_start))

    def _on_update_gui_arduino_diagnostics_timer(self):
        """
        Synchronisation du QTreeWidget 'self.gui.widget.treeWidget_arduino_diag' avec les valeurs dans le message ROS
         'self._msg_arduino_states' contenant les etats de l'Arduino.
        """
        if self._msg_arduino_states:
            root_path = ''
            for qt_item, path_to_qt_item in iternodes(
                    self.gui.widget.treeWidget_arduino_diag,
                    lambda t: zip([t.topLevelItem(topLevel) for topLevel in range(t.topLevelItemCount())],
                                  [root_path] * t.topLevelItemCount()),
                    lambda t: [t.child(id_child) for id_child in range(t.childCount())]
            ):
                # print('%s' % path_to_node)
                lambda_get_value_from_msg = self.map_arduino_to_qt_ros_msg.get(path_to_qt_item, lambda msg: None)
                value_in_ros_msg = lambda_get_value_from_msg(self._msg_arduino_states)
                if value_in_ros_msg is not None:
                    qt_item.setText(1, str(value_in_ros_msg))

    def _cb_arduino_states(self, msg):
        """

        :param msg:
        :type msg: arduino_msgs.msg.states
        """
        # rospy.loginfo("_cb_arduino_states - type(msg): %s" % type(msg))
        self._msg_arduino_states = msg

        if msg.state_start:
            self.signal_arduino_state_start_on.emit()
        else:
            self.signal_arduino_state_start_off.emit()

        if self._play_sound & msg.state_start & (not msg.state_pause):
            self._sounds['click'].play()

    def connect_signal(self, signal, cb):
        """

        :param signal:
        :param cb:
        :return:
        """
        # self.__class__.__dict__.get(signal).connect(cb)
        # self.__class__.__dict__.get('signal_arduino_state_start_on').connect(cb)
        self.signal_arduino_state_start_on.connect(cb)

    def _publish_arduino_states(self):
        """

        """
        msg = self._msg_arduino_commands()
        #
        msg.update_clock = False
        msg.t2_t3_t4 = [0] * 3
        #
        msg.state_flash = self.states.get_state('arduino', 'flash')
        msg.state_start = self.states.get_state('arduino', 'start')
        msg.state_pause = self.states.get_state('arduino', 'pause')
        #
        msg.state_boot = self.states.get_state('camlight', 'boot')
        #
        self._pub_arduino_commands.publish(msg)

    def state_updated(self):
        """

        :return:

        """
        try:
            if self._pub_arduino_commands:
                self._publish_arduino_states()
        except AttributeError as e:
            rospy.logwarn('_state_updated()')
Example #52
0
class PolarConnect:
    def __init__(self):
        self.server = WebServer(self.handler)
        self.log = None
        if API_LOG_PATH is not None:
            self.log = open(API_LOG_PATH, 'w')

        try:
            self.server.listen()

            self.timer = QTimer()
            self.timer.timeout.connect(self.advance)
            self.timer.start(TICK_INTERVAL)
        except:
            QMessageBox.critical(
                self.window(), 'PolarConnect',
                'Failed to listen on port {}.\nMake sure it is available and is not in use.'
                .format(NET_PORT))

    def advance(self):
        self.server.advance()

    def handler(self, request):
        if self.log is not None:
            self.log.write('[request]\n')
            json.dump(request, self.log, indent=4, sort_keys=True)
            self.log.write('\n\n')

        name = request.get('action', '')
        version = request.get('version', 4)
        params = request.get('params', {})
        reply = {'result': None, 'error': None}

        try:
            method = None

            for methodName, methodInst in inspect.getmembers(
                    self, predicate=inspect.ismethod):
                apiVersionLast = 0
                apiNameLast = None

                if getattr(methodInst, 'api', False):
                    for apiVersion, apiName in getattr(methodInst, 'versions',
                                                       []):
                        if apiVersionLast < apiVersion <= version:
                            apiVersionLast = apiVersion
                            apiNameLast = apiName

                    if apiNameLast is None and apiVersionLast == 0:
                        apiNameLast = methodName

                    if apiNameLast is not None and apiNameLast == name:
                        method = methodInst
                        break

            if method is None:
                raise Exception('unsupported action')
            else:
                reply['result'] = methodInst(**params)
        except Exception as e:
            reply['error'] = str(e)

        if version <= 4:
            reply = reply['result']

        if self.log is not None:
            self.log.write('[reply]\n')
            json.dump(reply, self.log, indent=4, sort_keys=True)
            self.log.write('\n\n')

        return reply

    def download(self, url):
        try:
            (code, contents) = download(url)
        except Exception as e:
            raise Exception('{} download failed with error {}'.format(
                url, str(e)))
        if code == 200:
            return contents
        else:
            raise Exception('{} download failed with return code {}'.format(
                url, code))

    def window(self):
        return aqt.mw

    def reviewer(self):
        reviewer = self.window().reviewer
        if reviewer is None:
            raise Exception('reviewer is not available')
        else:
            return reviewer

    def collection(self):
        collection = self.window().col
        if collection is None:
            raise Exception('collection is not available')
        else:
            return collection

    def decks(self):
        decks = self.collection().decks
        if decks is None:
            raise Exception('decks are not available')
        else:
            return decks

    def scheduler(self):
        scheduler = self.collection().sched
        if scheduler is None:
            raise Exception('scheduler is not available')
        else:
            return scheduler

    def database(self):
        database = self.collection().db
        if database is None:
            raise Exception('database is not available')
        else:
            return database

    def media(self):
        media = self.collection().media
        if media is None:
            raise Exception('media is not available')
        else:
            return media

    def startEditing(self):
        self.window().requireReset()

    def stopEditing(self):
        if self.collection() is not None:
            self.window().maybeReset()

    def createNote(self, note):
        collection = self.collection()

        model = collection.models.byName(note['modelName'])
        if model is None:
            raise Exception('model was not found: {}'.format(
                note['modelName']))

        deck = collection.decks.byName(note['deckName'])
        if deck is None:
            raise Exception('deck was not found: {}'.format(note['deckName']))

        ankiNote = anki.notes.Note(collection, model)
        ankiNote.model()['did'] = deck['id']
        ankiNote.tags = note['tags']

        for name, value in note['fields'].items():
            if name in ankiNote:
                ankiNote[name] = value

        allowDuplicate = False
        if 'options' in note:
            if 'allowDuplicate' in note['options']:
                allowDuplicate = note['options']['allowDuplicate']
                if type(allowDuplicate) is not bool:
                    raise Exception(
                        'option parameter \'allowDuplicate\' must be boolean')

        duplicateOrEmpty = ankiNote.dupeOrEmpty()
        if duplicateOrEmpty == 1:
            raise Exception('cannot create note because it is empty')
        elif duplicateOrEmpty == 2:
            if not allowDuplicate:
                raise Exception('cannot create note because it is a duplicate')
            else:
                return ankiNote
        elif duplicateOrEmpty == False:
            return ankiNote
        else:
            raise Exception('cannot create note for unknown reason')

    #
    # Miscellaneous
    #

    @api()
    def version(self):
        return API_VERSION

    @api()
    def upgrade(self):
        response = QMessageBox.question(self.window(), 'PolarConnect',
                                        'Upgrade to the latest version?',
                                        QMessageBox.Yes | QMessageBox.No)

        if response == QMessageBox.Yes:
            try:
                data = self.download(URL_UPGRADE)
                path = os.path.splitext(__file__)[0] + '.py'
                with open(path, 'w') as fp:
                    fp.write(makeStr(data))
                QMessageBox.information(
                    self.window(), 'PolarConnect',
                    'Upgraded to the latest version, please restart Anki.')
                return True
            except Exception as e:
                QMessageBox.critical(self.window(), 'PolarConnect',
                                     'Failed to download latest version.')
                raise e

        return False

    @api()
    def sync(self):
        self.window().onSync()

    @api()
    def multi(self, actions):
        return list(map(self.handler, actions))

    #
    # Decks
    #

    @api()
    def deckNames(self):
        return self.decks().allNames()

    @api()
    def deckNamesAndIds(self):
        decks = {}
        for deck in self.deckNames():
            decks[deck] = self.decks().id(deck)

        return decks

    @api()
    def getDecks(self, cards):
        decks = {}
        for card in cards:
            did = self.database().scalar('select did from cards where id=?',
                                         card)
            deck = self.decks().get(did)['name']
            if deck in decks:
                decks[deck].append(card)
            else:
                decks[deck] = [card]

        return decks

    @api()
    def createDeck(self, deck):
        try:
            self.startEditing()
            did = self.decks().id(deck)
        finally:
            self.stopEditing()

        return did

    @api()
    def changeDeck(self, cards, deck):
        self.startEditing()

        did = self.collection().decks.id(deck)
        mod = anki.utils.intTime()
        usn = self.collection().usn()

        # normal cards
        scids = anki.utils.ids2str(cards)
        # remove any cards from filtered deck first
        self.collection().sched.remFromDyn(cards)

        # then move into new deck
        self.collection().db.execute(
            'update cards set usn=?, mod=?, did=? where id in ' + scids, usn,
            mod, did)
        self.stopEditing()

    @api()
    def deleteDecks(self, decks, cardsToo=False):
        try:
            self.startEditing()
            decks = filter(lambda d: d in self.deckNames(), decks)
            for deck in decks:
                did = self.decks().id(deck)
                self.decks().rem(did, cardsToo)
        finally:
            self.stopEditing()

    @api()
    def getDeckConfig(self, deck):
        if not deck in self.deckNames():
            return False

        collection = self.collection()
        did = collection.decks.id(deck)
        return collection.decks.confForDid(did)

    @api()
    def saveDeckConfig(self, config):
        collection = self.collection()

        config['id'] = str(config['id'])
        config['mod'] = anki.utils.intTime()
        config['usn'] = collection.usn()

        if not config['id'] in collection.decks.dconf:
            return False

        collection.decks.dconf[config['id']] = config
        collection.decks.changed = True
        return True

    @api()
    def setDeckConfigId(self, decks, configId):
        configId = str(configId)
        for deck in decks:
            if not deck in self.deckNames():
                return False

        collection = self.collection()
        if not configId in collection.decks.dconf:
            return False

        for deck in decks:
            did = str(collection.decks.id(deck))
            aqt.mw.col.decks.decks[did]['conf'] = configId

        return True

    @api()
    def cloneDeckConfigId(self, name, cloneFrom='1'):
        configId = str(cloneFrom)
        if not configId in self.collection().decks.dconf:
            return False

        config = self.collection().decks.getConf(configId)
        return self.collection().decks.confId(name, config)

    @api()
    def removeDeckConfigId(self, configId):
        configId = str(configId)
        collection = self.collection()
        if configId == 1 or not configId in collection.decks.dconf:
            return False

        collection.decks.remConf(configId)
        return True

    @api()
    def storeMediaFile(self, filename, data):
        self.deleteMediaFile(filename)
        self.media().writeData(filename, base64.b64decode(data))

    @api()
    def retrieveMediaFile(self, filename):
        filename = os.path.basename(filename)
        filename = normalize('NFC', filename)
        filename = self.media().stripIllegal(filename)

        path = os.path.join(self.media().dir(), filename)
        if os.path.exists(path):
            with open(path, 'rb') as file:
                return base64.b64encode(file.read()).decode('ascii')

        return False

    @api()
    def deleteMediaFile(self, filename):
        self.media().syncDelete(filename)

    @api()
    def addNote(self, note):
        ankiNote = self.createNote(note)

        audio = note.get('audio')
        if audio is not None and len(audio['fields']) > 0:
            try:
                data = self.download(audio['url'])
                skipHash = audio.get('skipHash')
                if skipHash is None:
                    skip = False
                else:
                    m = hashlib.md5()
                    m.update(data)
                    skip = skipHash == m.hexdigest()

                if not skip:
                    for field in audio['fields']:
                        if field in ankiNote:
                            ankiNote[field] += u'[sound:{}]'.format(
                                audio['filename'])

                    self.media().writeData(audio['filename'], data)
            except Exception as e:
                errorMessage = str(e).replace("&", "&amp;").replace(
                    "<", "&lt;").replace(">", "&gt;")
                for field in audio['fields']:
                    if field in ankiNote:
                        ankiNote[field] += errorMessage

        collection = self.collection()
        self.startEditing()
        collection.addNote(ankiNote)
        collection.autosave()
        self.stopEditing()

        return ankiNote.id

    @api()
    def canAddNote(self, note):
        try:
            return bool(self.createNote(note))
        except:
            return False

    @api()
    def updateNoteFields(self, note):
        ankiNote = self.collection().getNote(note['id'])
        if ankiNote is None:
            raise Exception('note was not found: {}'.format(note['id']))

        for name, value in note['fields'].items():
            if name in ankiNote:
                ankiNote[name] = value

        ankiNote.flush()

    @api()
    def addTags(self, notes, tags, add=True):
        self.startEditing()
        self.collection().tags.bulkAdd(notes, tags, add)
        self.stopEditing()

    @api()
    def removeTags(self, notes, tags):
        return self.addTags(notes, tags, False)

    @api()
    def getTags(self):
        return self.collection().tags.all()

    @api()
    def suspend(self, cards, suspend=True):
        for card in cards:
            if self.suspended(card) == suspend:
                cards.remove(card)

        if len(cards) == 0:
            return False

        scheduler = self.scheduler()
        self.startEditing()
        if suspend:
            scheduler.suspendCards(cards)
        else:
            scheduler.unsuspendCards(cards)
        self.stopEditing()

        return True

    @api()
    def unsuspend(self, cards):
        self.suspend(cards, False)

    @api()
    def suspended(self, card):
        card = self.collection().getCard(card)
        return card.queue == -1

    @api()
    def areSuspended(self, cards):
        suspended = []
        for card in cards:
            suspended.append(self.suspended(card))

        return suspended

    @api()
    def areDue(self, cards):
        due = []
        for card in cards:
            if self.findCards('cid:{} is:new'.format(card)):
                due.append(True)
            else:
                date, ivl = self.collection().db.all(
                    'select id/1000.0, ivl from revlog where cid = ?',
                    card)[-1]
                if ivl >= -1200:
                    due.append(
                        bool(self.findCards('cid:{} is:due'.format(card))))
                else:
                    due.append(date - ivl <= time())

        return due

    @api()
    def getIntervals(self, cards, complete=False):
        intervals = []
        for card in cards:
            if self.findCards('cid:{} is:new'.format(card)):
                intervals.append(0)
            else:
                interval = self.collection().db.list(
                    'select ivl from revlog where cid = ?', card)
                if not complete:
                    interval = interval[-1]
                intervals.append(interval)

        return intervals

    @api()
    def modelNames(self):
        return self.collection().models.allNames()

    @api()
    def modelNamesAndIds(self):
        models = {}
        for model in self.modelNames():
            models[model] = int(self.collection().models.byName(model)['id'])

        return models

    @api()
    def modelNameFromId(self, modelId):
        model = self.collection().models.get(modelId)
        if model is None:
            raise Exception('model was not found: {}'.format(modelId))
        else:
            return model['name']

    @api()
    def modelFieldNames(self, modelName):
        model = self.collection().models.byName(modelName)
        if model is None:
            raise Exception('model was not found: {}'.format(modelName))
        else:
            return [field['name'] for field in model['flds']]

    @api()
    def modelFieldsOnTemplates(self, modelName):
        model = self.collection().models.byName(modelName)
        if model is None:
            raise Exception('model was not found: {}'.format(modelName))

        templates = {}
        for template in model['tmpls']:
            fields = []
            for side in ['qfmt', 'afmt']:
                fieldsForSide = []

                # based on _fieldsOnTemplate from aqt/clayout.py
                matches = re.findall('{{[^#/}]+?}}', template[side])
                for match in matches:
                    # remove braces and modifiers
                    match = re.sub(r'[{}]', '', match)
                    match = match.split(':')[-1]

                    # for the answer side, ignore fields present on the question side + the FrontSide field
                    if match == 'FrontSide' or side == 'afmt' and match in fields[
                            0]:
                        continue
                    fieldsForSide.append(match)

                fields.append(fieldsForSide)

            templates[template['name']] = fields

        return templates

    @api()
    def deckNameFromId(self, deckId):
        deck = self.collection().decks.get(deckId)
        if deck is None:
            raise Exception('deck was not found: {}'.format(deckId))
        else:
            return deck['name']

    @api()
    def findNotes(self, query=None):
        if query is None:
            return []
        else:
            return list(map(int, self.collection().findNotes(query)))

    @api()
    def findCards(self, query=None):
        if query is None:
            return []
        else:
            return list(map(int, self.collection().findCards(query)))

    @api()
    def cardsInfo(self, cards):
        result = []
        for cid in cards:
            try:
                card = self.collection().getCard(cid)
                model = card.model()
                note = card.note()
                fields = {}
                for info in model['flds']:
                    order = info['ord']
                    name = info['name']
                    fields[name] = {
                        'value': note.fields[order],
                        'order': order
                    }

                result.append({
                    'cardId': card.id,
                    'fields': fields,
                    'fieldOrder': card.ord,
                    'question': card._getQA()['q'],
                    'answer': card._getQA()['a'],
                    'modelName': model['name'],
                    'deckName': self.deckNameFromId(card.did),
                    'css': model['css'],
                    'factor': card.factor,
                    #This factor is 10 times the ease percentage,
                    # so an ease of 310% would be reported as 3100
                    'interval': card.ivl,
                    'note': card.nid
                })
            except TypeError as e:
                # Anki will give a TypeError if the card ID does not exist.
                # Best behavior is probably to add an 'empty card' to the
                # returned result, so that the items of the input and return
                # lists correspond.
                result.append({})

        return result

    @api()
    def notesInfo(self, notes):
        result = []
        for nid in notes:
            try:
                note = self.collection().getNote(nid)
                model = note.model()

                fields = {}
                for info in model['flds']:
                    order = info['ord']
                    name = info['name']
                    fields[name] = {
                        'value': note.fields[order],
                        'order': order
                    }

                result.append({
                    'noteId':
                    note.id,
                    'tags':
                    note.tags,
                    'fields':
                    fields,
                    'modelName':
                    model['name'],
                    'cards':
                    self.collection().db.list(
                        'select id from cards where nid = ? order by ord',
                        note.id)
                })
            except TypeError as e:
                # Anki will give a TypeError if the note ID does not exist.
                # Best behavior is probably to add an 'empty card' to the
                # returned result, so that the items of the input and return
                # lists correspond.
                result.append({})

        return result

    @api()
    def cardsToNotes(self, cards):
        return self.collection().db.list(
            'select distinct nid from cards where id in ' +
            anki.utils.ids2str(cards))

    @api()
    def guiBrowse(self, query=None):
        browser = aqt.dialogs.open('Browser', self.window())
        browser.activateWindow()

        if query is not None:
            browser.form.searchEdit.lineEdit().setText(query)
            if hasattr(browser, 'onSearch'):
                browser.onSearch()
            else:
                browser.onSearchActivated()

        return list(map(int, browser.model.cards))

    @api()
    def guiAddCards(self):
        addCards = aqt.dialogs.open('AddCards', self.window())
        addCards.activateWindow()

    @api()
    def guiReviewActive(self):
        return self.reviewer().card is not None and self.window(
        ).state == 'review'

    @api()
    def guiCurrentCard(self):
        if not self.guiReviewActive():
            raise Exception('Gui review is not currently active.')

        reviewer = self.reviewer()
        card = reviewer.card
        model = card.model()
        note = card.note()

        fields = {}
        for info in model['flds']:
            order = info['ord']
            name = info['name']
            fields[name] = {'value': note.fields[order], 'order': order}

        if card is not None:
            return {
                'cardId': card.id,
                'fields': fields,
                'fieldOrder': card.ord,
                'question': card._getQA()['q'],
                'answer': card._getQA()['a'],
                'buttons': [b[0] for b in reviewer._answerButtonList()],
                'modelName': model['name'],
                'deckName': self.deckNameFromId(card.did),
                'css': model['css'],
                'template': card.template()['name']
            }

    @api()
    def guiStartCardTimer(self):
        if not self.guiReviewActive():
            return False

        card = self.reviewer().card

        if card is not None:
            card.startTimer()
            return True
        else:
            return False

    @api()
    def guiShowQuestion(self):
        if self.guiReviewActive():
            self.reviewer()._showQuestion()
            return True
        else:
            return False

    @api()
    def guiShowAnswer(self):
        if self.guiReviewActive():
            self.window().reviewer._showAnswer()
            return True
        else:
            return False

    @api()
    def guiAnswerCard(self, ease):
        if not self.guiReviewActive():
            return False

        reviewer = self.reviewer()
        if reviewer.state != 'answer':
            return False
        if ease <= 0 or ease > self.scheduler().answerButtons(reviewer.card):
            return False

        reviewer._answerCard(ease)
        return True

    @api()
    def guiDeckOverview(self, name):
        collection = self.collection()
        if collection is not None:
            deck = collection.decks.byName(name)
            if deck is not None:
                collection.decks.select(deck['id'])
                self.window().onOverview()
                return True

        return False

    @api()
    def guiDeckBrowser(self):
        self.window().moveToState('deckBrowser')

    @api()
    def guiDeckReview(self, name):
        if self.guiDeckOverview(name):
            self.window().moveToState('review')
            return True
        else:
            return False

    @api()
    def guiExitAnki(self):
        timer = QTimer()

        def exitAnki():
            timer.stop()
            self.window().close()

        timer.timeout.connect(exitAnki)
        timer.start(
            1000)  # 1s should be enough to allow the response to be sent.

    @api()
    def addNotes(self, notes):
        results = []
        for note in notes:
            try:
                results.append(self.addNote(note))
            except Exception:
                results.append(None)

        return results

    @api()
    def canAddNotes(self, notes):
        results = []
        for note in notes:
            results.append(self.canAddNote(note))

        return results
Example #53
0
class RestDialog(QDialog):
    def __init__(self, parent):
        super(RestDialog, self).__init__(parent)

        self.setWindowFlags(Qt.FramelessWindowHint | Qt.Window)
        self.setAttribute(Qt.WA_TranslucentBackground)

        self.secs = 0
        self.pr = RoundProgress(self)
        self.pr.setObjectName("rest_progress")
        self.pr.setFixedSize(QSize(200, 200))

        self.btn_continue = QPushButton(_("IGNORE REST"), self)
        self.btn_continue.setFixedSize(QSize(100, 30))
        self.btn_continue.setObjectName("btn_ignore_rest")
        if not ProfileConfig.donate_alerted:
            self.btn_continue.setIcon(QIcon(
                QPixmap(":/Icon/icons/dollar.png")))
        self.btn_continue.clicked.connect(self.on_btn_ignore_rest)

        self.a = 0
        self.total_secs = 0

        self.timer = QTimer()
        self.timer.setInterval(1000)
        self.timer.timeout.connect(self.to)

        self.l = QVBoxLayout(self)
        self.l.addWidget(self.pr, 0, Qt.AlignCenter)
        self.l.addWidget(self.btn_continue, 0, Qt.AlignCenter)

    def to(self):
        self.a += 1
        self.total_secs -= 1
        self.pr.setValue(self.a)

        min = self.total_secs // MIN_SECS
        secs = self.total_secs - min * MIN_SECS

        self.pr.label.setText(
            u"<center>" + _("REST") + u"<br>" +
            u"{}:{}".format(str(min).zfill(2),
                            str(secs).zfill(2)) + u"</center>")

        if self.total_secs <= 0:
            self.timer.stop()
            self.accept()

    def start(self, secs):
        self.total_secs = secs
        self.a = 0
        self.pr.setRange(0, self.total_secs)
        self.timer.start()

    # noinspection PyMethodOverriding
    def exec_(self, tomato_min):
        self.start(
            UserConfig.BREAK_MINUTES.get(str(tomato_min) + "MIN", 5) *
            MIN_SECS)
        return super(RestDialog, self).exec_()

    def reject(self):
        if self.timer.isActive():
            self.timer.stop()
        super(RestDialog, self).reject()

    def on_btn_ignore_rest(self, ):
        if not ProfileConfig.donate_alerted:
            DialogDonate(mw).exec_()
            ProfileConfig.donate_alerted = True
            self.btn_continue.setIcon(QIcon())

        if askUser(
                u"""
                <p>""" + _("IGNORE REST QUESTION") + u"""</p>
                """, self):
            self.reject()
Example #54
0
class _FileWatcher(QObject):
    """File watcher.
    
    QFileSystemWatcher notifies client about any change (file access mode, modification date, etc.)
    But, we need signal, only after file contents had been changed
    """
    modified = pyqtSignal(bool)
    removed = pyqtSignal(bool)

    def __init__(self, path):
        QObject.__init__(self)
        self._contents = None
        self._watcher = QFileSystemWatcher()
        self._timer = None
        self._path = path
        self.setPath(path)
        self.enable()

    def __del__(self):
        self._stopTimer()

    def enable(self):
        """Enable signals from the watcher
        """
        self._watcher.fileChanged.connect(self._onFileChanged)

    def disable(self):
        """Disable signals from the watcher
        """
        self._watcher.fileChanged.disconnect(self._onFileChanged)
        self._stopTimer()

    def setContents(self, contents):
        """Set file contents. Watcher uses it to compare old and new contents of the file.
        """
        self._contents = contents
        # Qt File watcher may work incorrectly, if file was not existing, when it started
        self.setPath(self._path)

    def setPath(self, path):
        """Path had been changed or file had been created. Set new path
        """
        if self._watcher.files():
            self._watcher.removePaths(self._watcher.files())
        if path is not None and os.path.isfile(path):
            self._watcher.addPath(path)
        self._path = path

    def _emitModifiedStatus(self):
        """Emit self.modified signal with right status
        """
        isModified = self._contents != self._safeRead(self._path)
        self.modified.emit(isModified)

    def _onFileChanged(self):
        """File changed. Emit own signal, if contents changed
        """
        if os.path.exists(self._path):
            self._emitModifiedStatus()
        else:
            self.removed.emit(True)
            self._startTimer()

    def _startTimer(self):
        """Init a timer.
        It is used for monitoring file after deletion.
        Git removes file, than restores it.
        """
        if self._timer is None:
            self._timer = QTimer()
            self._timer.setInterval(500)
            self._timer.timeout.connect(self._onCheckIfDeletedTimer)
        self._timer.start()

    def _stopTimer(self):
        """Stop timer, if exists
        """
        if self._timer is not None:
            self._timer.stop()

    def _onCheckIfDeletedTimer(self):
        """Check, if file has been restored
        """
        if os.path.exists(self._path):
            self.removed.emit(False)
            self._emitModifiedStatus()
            self.setPath(
                self._path
            )  # restart Qt file watcher after file has been restored
            self._stopTimer()

    def _safeRead(self, path):
        """Read file. Ignore exceptions
        """
        try:
            with open(path, 'rb') as file:
                return file.read()
        except (OSError, IOError):
            return None
Example #55
0
class Principal(QMainWindow, ui_principal.Ui_Principal):
    def __init__(self, parent=None):

        QMainWindow.__init__(self)
        self.setupUi(self)

        print(pg.__version__)

        self.sb = SerialDAQ()  #'/dev/pts/6')

        while not self.sb.connected:

            msg = QMessageBox.critical(None, "Advertencia",
                                       u"La interfaz no está conectada",
                                       QMessageBox.Retry | QMessageBox.Abort)

            if msg == QMessageBox.Retry:
                self.sb.open()
            else:
                sys.exit(1)

        self.updateTimer = QTimer()
        self.updateTimer.timeout.connect(self.update)

        # Asigna valores iniciales por defecto a los parámetros de cada canal
        for i in range(NUM_CANALES):

            str_pendiente = 'pendiente_' + str(i + 1)
            pendiente = getattr(self, str_pendiente)

            str_ordenada = 'ordenada_' + str(i + 1)
            ordenada = getattr(self, str_ordenada)

            str_nombre = 'nombre_' + str(i + 1)
            nombre = getattr(self, str_nombre)

            str_unidad = 'unidad_' + str(i + 1)
            unidad = getattr(self, str_unidad)

            pendiente.setText(str(PENDIENTE_DEF))
            ordenada.setText(str(0.0))

            nombre.setText('Canal ' + str(i + 1))
            unidad.setText('Volt')

            self.sb.config_analog(i + 1,
                                  name=nombre.text(),
                                  activate=False,
                                  calib=(float(ordenada.text()),
                                         float(pendiente.text())))
        self.sb.activate_analog(1)
        self.midiendo = False
        self.guardado = True

        self.vent_grafico = []
        self.grafico = []

        self.actionMedir.triggered.connect(self.medir)
        self.actionGuardar.triggered.connect(self.guardar)
        self.actionSalir.triggered.connect(self.close)

        pg.setConfigOption('background', 'w')
        pg.setConfigOption('foreground', 'k')

    def guardar(self):

        self.guardado = True

    def medir(self):

        if not self.midiendo:
            if not self.guardado:
                msg = QMessageBox.critical(None, "Advertencia",
                                           u"Se perderán los datos actuales",
                                           QMessageBox.Ok | QMessageBox.Cancel)
                if msg == QMessageBox.Cancel:
                    return

            self.guardado = False
            self.midiendo = True

            self.vent_grafico = []
            self.grafico = []
            self.sb.clear_analog()

            print(u'Iniciando medición')
            self.actionMedir.setIconText('Detener')

            self.frecuencia = self.frecuenciaSpinBox.value()
            self.num_ventana = 0

            self.cur_range = 0

            print "Frecuencia deseada =", 1. / self.frecuencia
            print "Frecuencia deseada =", int(
                10000. / self.frecuencia) * 0.0001
            self.timestamp = 1.065 * 0.0001 * int(
                10000. / self.frecuencia) * np.arange(0, self.sb.bufsize)

            for i in range(NUM_CANALES):

                gb = getattr(self, 'groupBox_' + str(i + 1))
                nombre = getattr(self, 'nombre_' + str(i + 1))

                str_pendiente = 'pendiente_' + str(i + 1)
                pendiente = getattr(self, str_pendiente)

                str_ordenada = 'ordenada_' + str(i + 1)
                ordenada = getattr(self, str_ordenada)

                self.sb.config_analog(i + 1,
                                      name=nombre.text(),
                                      activate=gb.isChecked(),
                                      calib=(float(ordenada.text()),
                                             float(pendiente.text())))

                if self.sb.channel_active[i]:

                    print('Canal {0} activo.'.format(str(i + 1), ))

                    self.vent_grafico.append(Grafico(self, self.num_ventana))

                    self.num_ventana += 1
                    self.grafico.append(self.vent_grafico[i].graphicsView.plot(
                        autoDownsample=False,
                        clipToView=True,
                        antialias=True,
                        pen=pg.mkPen('r', width=1.),
                        symbol='o',
                        symbolSize=4,
                        symbolPen=pg.mkPen('r', width=1),
                        symbolBrush=pg.mkBrush('r')))
                    title = 'Canal {0}: '.format(str(i + 1)) + \
                            self.sb.channel_name[i]

                    self.vent_grafico[i].setWindowTitle(title)
                    self.vent_grafico[i].graphicsView.setYRange(
                        0., self.sb.channel_calib[i][1] * 2**ADC_BITS)
                    # self.vent_grafico[i].graphicsView.setXRange(0., TIME_RANGE )

                    #.setLimits(maxXRange=100, minXRange=50)
                    #self.grafico[i].setDownsampling(auto=True)
                    #                    self.vent_grafico[i].graphicsView.setXRange(0., 50.)
                    self.vent_grafico[i].show()

                else:

                    print('Canal {0} inactivo.'.format(str(i + 1), ))
                    self.grafico.append(None)
                    self.vent_grafico.append(None)

            self.sb.start_continuous(self.frecuencia)

            self.updateTimer.start(50)  #1./self.frecuencia*1000)

        else:
            self.midiendo = False
            print(u'Deteniendo medición')
            self.actionMedir.setIconText('Medir')

            self.updateTimer.stop()
            self.sb.update_analog()
            self.sb.stop()

            # self.vent_grafico = []
            #

    def update(self):

        self.sb.update_analog()

        new_range = False

        if (self.sb.channel_pointer /
                self.frecuencia) / TIME_RANGE > self.cur_range:
            self.cur_range += 1
            new_range = True
        # print self.cur_range
        for i in range(NUM_CANALES):

            if self.sb.channel_active[i]:
                #                if new_range:
                #                    self.vent_grafico[i].graphicsView.setXRange((self.cur_range - 1) * TIME_RANGE, self.cur_range * TIME_RANGE )

                self.grafico[i].setData(
                    self.timestamp[0:self.sb.channel_pointer],
                    self.sb.channel_data[i][0:self.sb.channel_pointer])

    def closeEvent(self, event):

        if not self.guardado:
            msg = QMessageBox.critical(None, "Salir",
                                       u"Se perderán los datos actuales",
                                       QMessageBox.Ok | QMessageBox.Cancel)
            if msg == QMessageBox.Cancel:
                event.ignore()
                return

        for ventana in self.vent_grafico:
            if ventana is not None:
                ventana.destroy()

        event.accept()
Example #56
0
class CustomCodeFrame(QFrame):
    poke_code = pyqtSignal(str, int,
                           QByteArray)  # code_set_label, code_id, new_bytes
    log = pyqtSignal(str, str)  # msg, color

    def __init__(self, code_set, parent=None):
        super(CustomCodeFrame, self).__init__(parent)
        self.cs = code_set

        self.tmr_reset_bg_clr = QTimer(self)
        self.tmr_reset_bg_clr.setInterval(500)  # ms
        self.tmr_reset_bg_clr.timeout.connect(self.resetBGColor)

        self.txt_label = QLineEdit(self)
        self.txt_label.setMaximumWidth(160)
        self.txt_label.setPlaceholderText('Label')

        self.txt_codes = QPlainTextEdit(self)
        self.txt_codes.setMaximumHeight(66)
        font = QFont('Monospace')
        font.setStyleHint(QFont.TypeWriter)
        self.txt_codes.setFont(font)
        self.txt_codes.cursorPositionChanged.connect(self.resetBGColor)

        icon_height = self.txt_label.height() * 8 / 15

        self.btn_poke = QPushButton(self)
        self.btn_poke.setIcon(QIcon('img/flaticon/draw39.png'))
        self.btn_poke.setIconSize(QSize(icon_height, icon_height))
        self.btn_poke.setFixedSize(QSize(icon_height * 1.5, icon_height * 1.5))
        self.btn_poke.setAutoFillBackground(True)
        self.btn_poke.setStyleSheet('background-color: white')
        self.btn_poke.setToolTip('Poke memory')
        self.btn_poke.clicked.connect(self.onPoke)

        self.layout = QHBoxLayout(self)
        self.layout.addWidget(self.txt_label)
        self.layout.setAlignment(self.txt_label, Qt.AlignTop)
        self.layout.addWidget(self.txt_codes)
        self.layout.setAlignment(self.txt_codes, Qt.AlignTop)
        self.layout.addWidget(self.btn_poke)
        self.layout.setAlignment(self.btn_poke, Qt.AlignTop)
        self.layout.setContentsMargins(0, 2, 0, 2)

    def setAlternateBGColor(self):
        self.setStyleSheet(
            'CustomCodeFrame { background-color:rgb(248,248,248) }')

    def setErrorBGColor(self):
        self.txt_codes.setStyleSheet('background-color: rgb(255,128,128)')
        self.tmr_reset_bg_clr.start()

    def resetBGColor(self):
        if self.tmr_reset_bg_clr.isActive():
            self.tmr_reset_bg_clr.stop()
            self.txt_codes.setStyleSheet('background-color: white')

    @pyqtSlot()
    def onPoke(self):
        try:
            parse_custom_codes(self.cs, str(self.txt_codes.toPlainText()))
        except SyntaxError, e:
            self.log.emit(str(e), 'red')
            self.setErrorBGColor()
            return

        if len(self.cs.c) <= 0:
            self.log.emit('POKE failed: no codes found', 'red')
            self.setErrorBGColor()
            return

        # Sequentially poke codes
        for code in self.cs.c:
            raw_bytes = struct.pack('>Q', code.dft_value)[-code.num_bytes:]
            self.poke_code.emit(code.label, code.id, QByteArray(raw_bytes))
Example #57
0
class Plugin:
    """Plugin interface
    """
    def __init__(self):
        core.restoreSession.connect(self._onRestoreSession)
        core.aboutToTerminate.connect(self._saveSession)
        self._timer = QTimer(core)
        self._timer.timeout.connect(self._autoSaveSession)
        self._timer.setInterval(_AUTO_SAVE_INTERVAL_MS)
        self._timer.start()

    def del_(self):
        """Explicitly called destructor
        """
        core.restoreSession.disconnect(self._onRestoreSession)
        core.aboutToTerminate.disconnect(self._saveSession)

    def _onRestoreSession(self):
        """Enki initialisation finished.
        Now restore session
        """
        # if have documents except 'untitled' new doc, don't restore session
        if core.workspace().currentDocument() is not None:
            return

        if not os.path.exists(_SESSION_FILE_PATH):
            return

        session = enki.core.json_wrapper.load(_SESSION_FILE_PATH, 'session',
                                              None)

        if session is not None:
            for filePath in session['opened']:
                if os.path.exists(filePath):
                    core.workspace().openFile(filePath)

            if session['current'] is not None:
                document = self._documentForPath(session['current'])
                if document is not None:  # document might be already deleted
                    core.workspace().setCurrentDocument(document)

            if 'project' in session:
                path = session['project']
                if path is not None and os.path.isdir(path):
                    core.project().open(path)

    def _documentForPath(self, filePath):
        """Find document by it's file path.
        Raises ValueError, if document hasn't been found
        """
        for document in core.workspace().documents():
            if document.filePath() is not None and \
               document.filePath() == filePath:
                return document

        return None

    def _saveSession(self, showWarnings=True):
        """Enki is going to be terminated.
        Save session
        """
        fileList = [
            document.filePath() for document in core.workspace().documents()
            if document.filePath() is not None and os.path.exists(
                document.filePath()) and not '/.git/' in document.filePath()
            and not (document.fileName().startswith('svn-commit')
                     and document.fileName().endswith('.tmp'))
        ]

        if not fileList:
            return

        currentPath = None
        if core.workspace().currentDocument() is not None:
            currentPath = core.workspace().currentDocument().filePath()

        session = {
            'current': currentPath,
            'opened': fileList,
            'project': core.project().path()
        }

        enki.core.json_wrapper.dump(_SESSION_FILE_PATH, 'session', session,
                                    showWarnings)

    def _autoSaveSession(self):
        self._saveSession(showWarnings=False)
Example #58
0
class Plot2DDataWidget(QWidget):
    def __init__(self,
                 parent=None,
                 measdata=[[1, 3, 2], [3, 5, 7]],
                 header=["index", "prime numbers"],
                 SymbolSize=10,
                 linecolor='y',
                 pointcolor='b',
                 title='Plot Window'):
        # This class derivates from a Qt MainWindow so we have to call
        # the class builder ".__init__()"
        #QMainWindow.__init__(self)
        QWidget.__init__(self)
        # "self" is now a Qt Mainwindow, then we load the user interface
        # generated with QtDesigner and call it self.ui
        self.ui = Plot2DDataWidget_Ui.Ui_Plot2DData()
        # Now we have to feed the GUI building method of this object (self.ui)
        # with a Qt Mainwindow, but the widgets will actually be built as children
        # of this object (self.ui)
        self.ui.setupUi(self)
        self.setWindowTitle(title)
        self.x_index = 0
        self.y_index = 0
        self.curve = self.ui.plot_area.plot(pen=linecolor)
        self.curve.setSymbolBrush(pointcolor)
        self.curve.setSymbol('o')
        self.curve.setSymbolSize(SymbolSize)

        self.parent = parent
        self.measdata = measdata
        self.header = header
        self.update_dropdown_boxes(header)

        self.update_plot_timer = QTimer()
        self.update_plot_timer.setSingleShot(
            True
        )  #The timer would not wait for the completion of the task otherwise
        self.update_plot_timer.timeout.connect(self.autoupdate)

        if self.ui.auto_upd.isChecked(): self.autoupdate()

    def update_timer_timeout(self, msec):
        self.update_plot_timer.setInterval(msec)

    def updateX(self, value):
        self.x_index = value
        #self.update_plot() #that was the bug
        #This created a loop because update_plot called check_connection
        #which called update_dropdown_boxes, which cleared the x_axis_box
        #which triggered a call to updateX

    def updateY(self, value):
        self.y_index = value
        #self.update_plot()

    def change_line_color(self, color=None):
        #yellow 4294967040
        if color == None:
            color = QColorDialog.getColor(QColor(4294967040), None,
                                          'Line color',
                                          QColorDialog.ShowAlphaChannel)
        if color.isValid():
            self.curve.setPen(color)

    def change_point_color(self, color=None):
        #blue 4279259391
        if color == None:
            color = QColorDialog.getColor(QColor(4279259391), None,
                                          'Point color',
                                          QColorDialog.ShowAlphaChannel)
        if color.isValid():
            self.curve.setSymbolBrush(color)

    def change_symbol_size(self, value):
        self.curve.setSymbolSize(value)

    def check_connection(self, state=1):
        """check if the pointer to the Master dataset to display (self.measdata in Main.py) has changed"""
        if state and hasattr(self.parent, "measdata"):
            if self.parent.measdata != self.measdata:
                self.measdata = self.parent.measdata
            if self.parent.current_header != self.header:
                self.update_dropdown_boxes(self.parent.current_header)
            #print "Reestablishing connection"

    def autoupdate(self, state=1):
        if state:
            self.update_plot()
            self.update_plot_timer.start(
                self.ui.refresh_rate.value() *
                1000)  #The value must be converted to milliseconds
        else:
            self.update_plot_timer.stop()

    def update_plot(self):
        """plot the data columns selected in the drop-down menu boxes"""
        if self.ui.autoconnect.isChecked(): self.check_connection()
        if self.x_index != -1 and self.y_index != -1 and self.measdata[
                self.x_index] != [] and self.measdata[self.y_index] != []:
            self.curve.setData(self.measdata[self.x_index],
                               self.measdata[self.y_index])

    def update_dropdown_boxes(self, header):
        """Update the drop-down boxes that select the content of the plot"""
        self.ui.x_axis_box.clear()
        self.ui.x_axis_box.addItems(header)
        self.ui.y_axis_box.clear()
        self.ui.y_axis_box.addItems(header)
        self.header = header
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qgis.core import *
from qgis.gui import *
from qgis.utils import iface
from PyQt4.QtCore import QTimer

timer = QTimer()

timer.setInterval(10000)
QObject.connect(timer, SIGNAL("timeout()"),
qgis.utils.iface.mapCanvas().refreshAllLayers)
timer.start()
Example #60
0
class Pager(QObject):
    """Provides an interface for paging in a View by page number.
    
    Pages are numbered starting with 1 in this api!
    
    """
    currentPageChanged = pyqtSignal(int)
    pageCountChanged = pyqtSignal(int)
    
    def __init__(self, view):
        """Initializes the Pager with the View.
        
        Also connects with the Surface of the View and its Layout,
        so don't interchange them after initializing the Pager.
        
        """
        super(Pager, self).__init__(view)
        self._currentPage = 0
        self._pageCount = 0
        self._blockLevel = 0
        self._pageNumSet = False
        self._updateTimer = QTimer(
            singleShot=True, interval=100, timeout=self._updatePageNumber)
        
        # connect
        view.installEventFilter(self)
        view.surface().installEventFilter(self)
        view.surface().pageLayout().changed.connect(self._layoutChanged)
        
        # Connect to the kineticScrollingEnabled signal to avoid unneeded updates.
        view.kineticScrollingActive.connect(self.blockListening)
        
    def currentPage(self):
        """Returns the current page number (0 if there are no pages)."""
        return self._currentPage
        
    def setCurrentPage(self, num):
        """Shows the specified page number."""
        changed, self._currentPage = self._currentPage != num, num
        self._pageNumSet = True
        self.blockListening(True)
        self.view().gotoPageNumber(num - 1)
        self.blockListening(False)
        if changed:
            self.currentPageChanged.emit(self._currentPage)
        
    def pageCount(self):
        """Returns the number of pages."""
        return self._pageCount
    
    def view(self):
        return self.parent()
    
    def _layoutChanged(self):
        """Called internally whenever the layout is updated."""
        layout = self.view().surface().pageLayout()
        self._pageCount, old = len(layout), self._pageCount
        if old != self._pageCount:
            self.pageCountChanged.emit(self._pageCount)
        self._updatePageNumber()
    
    def _updatePageNumber(self):
        """Called internally on layout change or view resize or surface move."""
        self._currentPage, old = self.view().currentPageNumber() + 1, self._currentPage
        if self._currentPage == 0 and self._pageCount > 0:
            # the view may not be initialized
            self._currentPage = 1
        if old != self._currentPage:
            self.currentPageChanged.emit(self._currentPage)

    def blockListening(self, block):
        """Block/unblock listening to event, used to avoid multiple updates when we know lots
        of events are going to be sent to the pager.
        
        Blocking can be nested, only the outermost unblock will really unblock the event processing."""
        if block:
            self._blockLevel += 1
        else:
            self._blockLevel -= 1
        
        if self._blockLevel == 0:
            if self._pageNumSet:
                self._pageNumSet = False
            else:
                self._updatePageNumber()

    def eventFilter(self, obj, ev):
        if (self._blockLevel == 0 and
            ((ev.type() == QEvent.Resize and obj is self.view())
             or (ev.type() == QEvent.Move and obj is self.view().surface()))
            and not self._updateTimer.isActive()):
            self._updateTimer.start()
        return False