class ColumnResizer(QObject):
	def __init__(self):
		super(ColumnResizer, self).__init__()

		self._widgets = []
		self._gridColumnInfoList = []
		self._updateTimer = QTimer(self)
		self._updateTimer.setSingleShot(True)
		self._updateTimer.setInterval(0)
		self._updateTimer.timeout.connect(self._updateWidth)

	# Public methods

	def addWidgetsFromLayout(self, layout, column):
		"""
		:type layout: QGridLayout
		:type column: int
		"""
		assert column >= 0
		if isinstance(layout, QGridLayout):
			self._addWidgetsFromGridLayout(layout, column)
		else:
			print "ColumnResizerResizer does not support layouts of type:", type(layout)

	def eventFilter(self, obj, event):
		"""
		Overrides QObject.eventFilter()
		"""
		if event.type() == QEvent.Resize:
			self._scheduleWidthUpdate()
		return False

	# Private methods

	@Slot()
	def _updateWidth(self):
		width = 0
		for widget in self._widgets:
			width = max(widget.sizeHint().width(), width)
		for info in self._gridColumnInfoList:
			info[0].setColumnMinimumWidth(info[1], width)

	def _addWidget(self, widget):
		self._widgets.append(widget)
		widget.installEventFilter(self)
		self._scheduleWidthUpdate()

	def _addWidgetsFromGridLayout(self, layout, column):
		for row in range(layout.rowCount()):
			item = layout.itemAtPosition(row, column)
			if not item:
				continue
			widget = item.widget()
			if not widget:
				continue
			self._addWidget(widget)
		self._gridColumnInfoList.append([layout, column])

	def _scheduleWidthUpdate(self):
		self._updateTimer.start()
Exemplo n.º 2
0
    def test_encode_wrong_order_id(self):
        # python test_edit_timetracks.py TestEditTimetracks.test_encode_wrong_order_id
        app = self.app
        widget = self.widget
        today = date.today()
        widget.set_employee_and_date(self.employee.employee_id, today)
        QTest.keyEvent(QTest.Click, app.focusWidget(), Qt.Key_F5, Qt.ShiftModifier) # modifier, delay
        app.processEvents()

        QTest.keyEvent(QTest.Click, app.focusWidget(), Qt.Key_9) # modifier, delay
        app.processEvents()
        QTest.keyEvent(QTest.Click, app.focusWidget(), Qt.Key_9) # modifier, delay
        app.processEvents()
        QTest.keyEvent(QTest.Click, app.focusWidget(), Qt.Key_9) # modifier, delay
        app.processEvents()

        timer = QTimer()
        timer.timeout.connect(self._click_order_inexistant_box)
        timer.setSingleShot(True)
        timer.start(250)
        self.test_sucess = False

        QTest.keyEvent(QTest.Click, app.focusWidget(), Qt.Key_Enter)
        app.processEvents()

        assert self.test_sucess
Exemplo n.º 3
0
class WidgetFader(object):
    '''
    For a given widget in the UI, this fader attaches a timer 
    that hides that widget after a specified interval
    '''
    
    def make_active(self):
        '''
        shows the widget then sets the hide timer
        '''
        self.controls.show()
        self.timer.start(self.time_out)
    
    def make_inactive(self):
        self.controls.hide()

    def __init__(self, controls, time_out=1500):
        '''
        Constructor
        '''
        self.timer = QTimer()
        self.timer.timeout.connect(self.make_inactive)
        self.timer.setSingleShot(True)
        
        self.time_out = time_out
        self.controls = controls
        self.controls.hide()
Exemplo n.º 4
0
 def statusBarTimer(self):
   q = self.q
   ret = QTimer(q)
   ret.setSingleShot(True)
   ret.setInterval(5000)
   ret.timeout.connect(q.statusBar().hide)
   return ret
Exemplo n.º 5
0
class WidgetFader(object):
    '''
    For a given widget in the UI, this fader attaches a timer 
    that hides that widget after a specified interval
    '''
    def make_active(self):
        '''
        shows the widget then sets the hide timer
        '''
        self.controls.show()
        self.timer.start(self.time_out)

    def make_inactive(self):
        self.controls.hide()

    def __init__(self, controls, time_out=1500):
        '''
        Constructor
        '''
        self.timer = QTimer()
        self.timer.timeout.connect(self.make_inactive)
        self.timer.setSingleShot(True)

        self.time_out = time_out
        self.controls = controls
        self.controls.hide()
Exemplo n.º 6
0
    def test_print_preorder(self):
        # python test_integration.py TestEditOrderParts.test_print_preorder

        app = self.app
        widget = self.widget
        self._make_basic_preorder()
        self._encode_imputable_operation("Description2")
        self._encode_imputable_operation("Description3")
        QTest.keyEvent(QTest.Click, app.focusWidget(), Qt.Key_S,
                       Qt.ControlModifier)  # modifier, delay
        app.processEvents()

        # We're going to have a modal dialog for the
        # preorder print. So we prepare to click on it.

        timer = QTimer()
        timer.timeout.connect(self._fill_preorder_print_dialog)
        timer.setSingleShot(True)
        timer.start(250)

        self.prepare_to_click_dialog("set_preorder_sent_state", 3)
        widget.preorderPrint()

        order = dao.order_dao.find_by_id(widget._current_order.order_id)
        self.assertEqual("ZuluHeader", order.preorder_print_note)
        self.assertEqual("ZuluFooter", order.preorder_print_note_footer)
class Panel(QWidget):
    def __init__(self, parent=None, instr=None, lock=None, title="Instrument Panel"):
        # This class derivates from a Qt Widget so we have to call
        # the class builder ".__init__()"
        QWidget.__init__(self)
        # "self" is now a Qt Widget, then we load the user interface
        # generated with QtDesigner and call it self.ui
        self.ui = Keithley6221_Ui.Ui_Panel()
        # Now we have to feed the GUI building method of this object (self.ui)
        # with the current Qt Widget 'self', but the widgets from the design will actually be built as children
        # of the object self.ui
        self.ui.setupUi(self)
        self.setWindowTitle(title)
        self.reserved_access_to_instr = lock
        self.instr = instr
        self.monitor_timer = QTimer()
        # The timer would not wait for the completion of the task otherwise
        self.monitor_timer.setSingleShot(True)
        self.monitor_timer.timeout.connect(self.monitor)
        self.firsttime = 0
        # bug: if the box is checked in the .ui file, the system freezes
        # if self.ui.monitor.isChecked():self.monitor()

    def monitor(self, state=1):
        if state != 1:
            self.monitor_timer.stop()
        elif state and not (self.monitor_timer.isActive()):
            with self.reserved_access_to_instr:
                I = self.instr.query_current_source_amplitude()
                Vcomp = self.instr.query_voltage_compliance()
                outstate = self.instr.query_output_ON()
            self.ui.I_disp.setText(str(I * 1e6) + u" μA")
            self.ui.V_disp.setText(str(Vcomp) + " V")
            self.ui.outputON.setChecked(outstate)
            self.monitor_timer.start(self.ui.refresh_rate.value() * 1000)

    def update_timer_timeout(self, secs):
        # The value must be converted to milliseconds
        self.monitor_timer.setInterval(secs * 1000)

    def change_I(self, value=0):
        with self.reserved_access_to_instr:
            self.instr.set_current_source_amplitude(value * 1e6)

    def change_V_comp(self, value=0):
        with self.reserved_access_to_instr:
            self.instr.set_voltage_compliance(value)

    def switch_output(self, value=False):
        if value:
            with self.reserved_access_to_instr:
                self.instr.output_ON()
        else:
            with self.reserved_access_to_instr:
                self.instr.output_OFF()

    def reset_inst(self):
        with self.reserved_access_to_instr:
            self.instr.reset()
Exemplo n.º 8
0
    def test_change_order_customer(self):
        customer2 = self._customer_dao.make(
            "AAAA")  # Name chosen so it happens first int he customer dialog
        self._customer_dao.save(customer2)

        app = self.app
        widget = self.widget
        mw = self.mw
        self._make_basic_preorder()

        self._encode_imputable_operation("Description2")
        self._encode_imputable_operation("Description3")

        QTest.keyEvent(QTest.Click, app.focusWidget(), Qt.Key_S,
                       Qt.ControlModifier)  # modifier, delay
        app.processEvents()

        # Make sure the test is set up correctly
        preorder = self.order_dao.find_by_id_frozen(
            widget._current_order.order_id)
        assert preorder.customer_id == self.customer.customer_id

        # We're going to have a modal dialog for the new
        # customer name. So we prepare to click on it.

        timer = QTimer()
        timer.timeout.connect(self._lookup)
        timer.setSingleShot(True)
        timer.start(1000)

        widget.change_customer()
        # app.exec_() # Wait for the timer to shoot

        mainlog.debug("test_change_order_customer" * 10)
        mainlog.debug(app.focusWidget())

        widget.setFocus(
            Qt.OtherFocusReason)  # This refocus was introduced for linux
        app.processEvents()

        QTest.keyEvent(QTest.Click, app.focusWidget(), Qt.Key_S,
                       Qt.ControlModifier)  # modifier, delay
        app.processEvents()

        mainlog.debug("test_change_order_customer")

        preorder = self.order_dao.find_by_id_frozen(
            widget._current_order.order_id)
        assert preorder.customer_id == customer2.customer_id

        mainlog.debug("test_change_order_customer")

        self.order_dao.delete(preorder.order_id)
        self.dao.customer_dao.delete(customer2.customer_id)
Exemplo n.º 9
0
    def test_change_order_customer_cancelled(self):
        customer2 = self._customer_dao.make(
            "AAAA")  # Name chosen so it happens first int he customer dialog
        self._customer_dao.save(customer2)

        app = self.app
        widget = self.widget
        mw = self.mw
        self._make_basic_preorder()

        self._encode_imputable_operation("Description2")
        self._encode_imputable_operation("Description3")

        QTest.keyEvent(QTest.Click, app.focusWidget(), Qt.Key_S,
                       Qt.ControlModifier)  # modifier, delay
        app.processEvents()

        # Make sure the test is set up correctly
        preorder = self.order_dao.find_by_id_frozen(
            widget._current_order.order_id)
        assert preorder.customer_id == self.customer.customer_id

        # We're going to have a modal dialog for the new
        # customer name. So we prepare to click on it.

        timer = QTimer()
        timer.timeout.connect(self._cancel_dialog)
        timer.setSingleShot(True)
        timer.start(1000)  # Had 250, my linux seems to prefer 1000

        widget.change_customer()  # blocks
        app.processEvents()
        # app.exec_() # Wait for the timer to shoot

        widget.setFocus(
            Qt.OtherFocusReason)  # This refocus was introduced for linux

        for i in range(1000):
            app.processEvents()  # Linux needs a break

        mainlog.debug("Pressing ctrl-S on this widget : {}".format(
            app.focusWidget()))
        # app.exec_()

        QTest.keyEvent(QTest.Click, app.focusWidget(), Qt.Key_S,
                       Qt.ControlModifier)  # modifier, delay
        app.processEvents()

        preorder = self.order_dao.find_by_id_frozen(
            widget._current_order.order_id)
        assert preorder.customer_id == self.customer.customer_id

        self.order_dao.delete(preorder.order_id)
        self.dao.customer_dao.delete(customer2.customer_id)
Exemplo n.º 10
0
 def onLoopRequested(loopRequest):
     print 'l: ', l
     if l:
         l.pop()
         led.toggle(not led.isToggled())
     ledTimer = QTimer(toggleObject)
     ledTimer.setSingleShot(True)
     ledTimer.setInterval(200)
     ledTimer.timeout.connect(
         partial(loopRequest.completeRequest, True if l else False))
     ledTimer.start()
     if not l: l.extend(range(20))
Exemplo n.º 11
0
class MyGlWidget(QGLWidget):
    "PySideApp uses Qt library to create an opengl context, listen to keyboard events, and clean up"

    def __init__(self, renderer, glformat, app):
        "Creates an OpenGL context and a window, and acquires OpenGL resources"
        super(MyGlWidget, self).__init__(glformat)
        self.renderer = renderer
        self.app = app
        # Use a timer to rerender as fast as possible
        self.timer = QTimer(self)
        self.timer.setSingleShot(True)
        self.timer.setInterval(0)
        self.timer.timeout.connect(self.render_vr)
        # Accept keyboard events
        self.setFocusPolicy(Qt.StrongFocus)

    def __enter__(self):
        "setup for RAII using 'with' keyword"
        return self

    def __exit__(self, type_arg, value, traceback):
        "cleanup for RAII using 'with' keyword"
        self.dispose_gl()

    def initializeGL(self):
        if self.renderer is not None:
            self.renderer.init_gl()
        self.timer.start()

    def paintGL(self):
        "render scene one time"
        self.renderer.render_scene()
        self.swapBuffers()  # Seems OK even in single-buffer mode

    def render_vr(self):
        self.makeCurrent()
        self.paintGL()
        self.doneCurrent()
        self.timer.start()  # render again real soon now

    def disposeGL(self):
        if self.renderer is not None:
            self.makeCurrent()
            self.renderer.dispose_gl()
            self.doneCurrent()

    def keyPressEvent(self, event):
        "press ESCAPE to quit the application"
        key = event.key()
        if key == Qt.Key_Escape:
            self.app.quit()
Exemplo n.º 12
0
    def test_change_order_part_state(self):
        order = self._make_order()

        order_part = self._order_part_dao.make(order)
        order_part.description = u"Part 2"
        order_part.position = 2
        self._order_part_dao.save(order_part)

        order_part = self._order_part_dao.make(order)
        order_part.description = u"Part 3"
        order_part.position = 3
        self._order_part_dao.save(order_part)

        self._order_dao.change_order_state(
            order.order_id, OrderStatusType.order_ready_for_production)

        # self.order_overview_widget.month_today()
        self.order_overview_widget.refresh_action()
        self.order_overview_widget.retake_focus()
        # self.app.exec_()

        # Select the first order part (we assume they are properly ordered)
        v = self.order_overview_widget.current_orders_overview.table_view
        v.setCurrentIndex(v.model().index(0, 0))
        QTest.mouseMove(v)

        # QTest.mouseClick(self.order_overview_widget.current_orders_overview.table_view,
        #                  Qt.RightButton, delay=500)

        # self.order_overview_widget.current_orders_overview.popup_parts()

        timer = QTimer()
        timer.timeout.connect(self._click_context_menu)
        timer.setSingleShot(True)
        timer.start(1000)

        # I can't have the menu to popup using museClicks, so I
        # do it this way. FIXME Taht's not right because nothing prooves
        # that my context menu is shown on mouse clicks...
        self.app.sendEvent(
            self.order_overview_widget.current_orders_overview.table_view,
            QContextMenuEvent(QContextMenuEvent.Keyboard, QPoint(10, 10)))

        # self.app.exec_()

        order = self.order_dao.find_by_id(order.order_id)
        self.assertEqual(OrderPartStateType.aborted, order.parts[0].state)
        self.assertEqual(OrderPartStateType.ready_for_production,
                         order.parts[1].state)
        self.assertEqual(OrderPartStateType.ready_for_production,
                         order.parts[2].state)
Exemplo n.º 13
0
class MyGlWidget(QGLWidget):
    "PySideApp uses Qt library to create an opengl context, listen to keyboard events, and clean up"

    def __init__(self, renderer, glformat, app):
        "Creates an OpenGL context and a window, and acquires OpenGL resources"
        super(MyGlWidget, self).__init__(glformat)
        self.renderer = renderer
        self.app = app
        # Use a timer to rerender as fast as possible
        self.timer = QTimer(self)
        self.timer.setSingleShot(True)
        self.timer.setInterval(0)
        self.timer.timeout.connect(self.render_vr)
        # Accept keyboard events
        self.setFocusPolicy(Qt.StrongFocus)

    def __enter__(self):
        "setup for RAII using 'with' keyword"
        return self

    def __exit__(self, type_arg, value, traceback):
        "cleanup for RAII using 'with' keyword"
        self.dispose_gl()

    def initializeGL(self):
        if self.renderer is not None:
            self.renderer.init_gl()
        self.timer.start()

    def paintGL(self):
        "render scene one time"
        self.renderer.render_scene()
        self.swapBuffers() # Seems OK even in single-buffer mode
        
    def render_vr(self):
        self.makeCurrent()
        self.paintGL()
        self.doneCurrent()
        self.timer.start() # render again real soon now

    def disposeGL(self):
        if self.renderer is not None:
            self.makeCurrent()
            self.renderer.dispose_gl()
            self.doneCurrent()

    def keyPressEvent(self, event):
        "press ESCAPE to quit the application"
        key = event.key()
        if key == Qt.Key_Escape:
            self.app.quit()
Exemplo n.º 14
0
 def downlaod(self, url, timeout=60):
     loop = QEventLoop()
     timer = QTimer()
     timer.setSingleShot(True)
     timer.timeout.connect(loop.quit)
     self.loadFinished.connect(loop.quit)
     self.load(QUrl(url))
     timer.start(timeout * 1000)
     loop.exec_()
     if timer.isActive():
         timer.stop()
         return self.html()
     else:
         print 'Request timed out: ' + url
Exemplo n.º 15
0
 def onLoopRequested(loopRequest):
     print 'l: ', l
     if l:
         l.pop()
         led.toggle(not led.isToggled())
     ledTimer = QTimer(toggleObject)
     ledTimer.setSingleShot(True)
     ledTimer.setInterval(200)
     ledTimer.timeout.connect(
         partial(
             loopRequest.completeRequest,
             True if l else False
         )
     )
     ledTimer.start()
     if not l: l.extend(range(20))
Exemplo n.º 16
0
class Browser(QWidget):
    def __init__(self):
        super(Browser, self).__init__()

        self.layout = QStackedLayout(self)
        self.layout.setStackingMode(QStackedLayout.StackAll)

        self.hostname = os.uname()[1]

        self.timer = QTimer()
        self.timer.setSingleShot(False)
        self.timer.start(2000)

        self._init_sites()

        self.remote_shell = RemoteShell(self)

        self.connect(self.timer, SIGNAL("timeout()"), self, SLOT("show_next()"))
        self.show_next()

    def _init_sites(self):
        self.sites = list()
        self.site_id = -1

        url = QUrl("https://www.qt.io/developers/")
        self.sites.append(Site(self, url, 5, 1))

        url = QUrl("https://wiki.qt.io/PySide")
        self.sites.append(Site(self, url, 5, 1))

        url = QUrl("https://www.python.org/")
        self.sites.append(Site(self, url, 5, 1))

    @property
    def current_site(self):
        return self.sites[self.site_id]

    def show_next(self):
        self.timer.stop()
        previous_id = self.site_id
        self.site_id = (self.site_id + 1) % len(self.sites)
        current_site = self.current_site
        self.timer.start(current_site.time * 1000)
        current_site.show()
        print("show " + current_site.url.toString().encode())
        if previous_id >= 0:
            self.sites[previous_id].hide()
Exemplo n.º 17
0
 def open(self, url, timeout=60):
     """Wait for download to complete and return result"""
     loop = QEventLoop()
     timer = QTimer()
     timer.setSingleShot(True)
     timer.timeout.connect(loop.quit)
     self.loadFinished.connect(loop.quit)
     self.load(QUrl(url))
     timer.start(timeout * 1000)
     loop.exec_() # delay here until download finished
     if timer.isActive():
         # downloaded successfully
         timer.stop()
         return self.html()
     else:
         # timed out
         print 'Request timed out:', url
Exemplo n.º 18
0
 def open(self, url, timeout=60):
     """Wait for download to complete and return result"""
     loop = QEventLoop()
     timer = QTimer()
     timer.setSingleShot(True)
     timer.timeout.connect(loop.quit)
     self.loadFinished.connect(loop.quit)
     self.load(QUrl(url))
     timer.start(timeout * 1000)
     loop.exec_()  # delay here until download finished
     if timer.isActive():
         # downloaded successfully
         timer.stop()
         return self.html()
     else:
         # timed out
         print 'Request timed out:', url
Exemplo n.º 19
0
    def open(self, url, timeout=60):
        """wait for download to complete and return result"""
        loop = QEventLoop()
        timer = QTimer()
        timer.setSingleShot(True)  # True表示触发定时器后,仅执行事件一次
        timer.timeout.connect(loop.quit)  # 若超时,则连接loop.quit,退出事件循环
        self.loadFinished.connect(loop.quit)
        self.load(url)
        timer.start(timeout * 1000)  # 定时器以ms为单位,设置超时时间为60s
        loop.exec_()  # 等待网页加载完成后,在执行后面的代码

        if timer.isActive():
            # downloaded successfully
            timer.stop()
            return self.html()
        else:
            # timed out
            print 'Request timed out:', url
class Render(QWebView):
    def __init__(self, url, filename, image_crop, translate_page, parent=None):
        super(Render, self).__init__(parent)
        self.image_crop = image_crop
        self.fileName = time.strftime("%Y%m%d%H%M%S",
                                      time.localtime()) + "_test.jpg"
        self.finished = False

        # Settings
        s = self.page().settings()
        s.setAttribute(QWebSettings.AutoLoadImages, True)
        s.setAttribute(QWebSettings.PluginsEnabled, True)
        s.setAttribute(QWebSettings.JavascriptEnabled, True)
        s.setAttribute(QWebSettings.JavaEnabled, False)
        s.setAttribute(QWebSettings.JavascriptCanOpenWindows, False)
        s.setAttribute(QWebSettings.DeveloperExtrasEnabled, True)

        #self.page().mainFrame().setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff)
        self.page().mainFrame().setScrollBarPolicy(Qt.Vertical,
                                                   Qt.ScrollBarAlwaysOff)

        self.timerScreen = QTimer()
        self.timerScreen.setInterval(10000)
        self.timerScreen.setSingleShot(True)
        self.timerScreen.timeout.connect(self.takeScreenshot)

        self.loadFinished.connect(self.timerScreen.start)
        self.load(QUrl(url))

    @Slot(QNetworkReply)
    def takeScreenshot(self):
        [x, y, width, height] = self.image_crop
        frame = self.page().mainFrame()
        size = frame.contentsSize()
        size.setWidth(1000)
        size.setHeight(2000)
        self.page().setViewportSize(size)
        image = QImage(self.page().viewportSize(), QImage.Format_ARGB32)
        painter = QPainter(image)
        frame.render(painter)
        painter.end()
        image1 = image.copy(x, y, width, height)
        image1.save(self.fileName)
        self.finished = True
class Render(QWebView):
    def __init__(self, url, filename, image_crop, translate_page, parent=None):
        super(Render, self).__init__(parent)
        self.image_crop = image_crop
        self.fileName = time.strftime("%Y%m%d%H%M%S",time.localtime()) +"_test.jpg" 
        self.finished = False

        # Settings
        s = self.page().settings()
        s.setAttribute(QWebSettings.AutoLoadImages, True)
        s.setAttribute(QWebSettings.PluginsEnabled, True)
        s.setAttribute(QWebSettings.JavascriptEnabled, True)
        s.setAttribute(QWebSettings.JavaEnabled, False)
        s.setAttribute(QWebSettings.JavascriptCanOpenWindows, False)
        s.setAttribute(QWebSettings.DeveloperExtrasEnabled, True)    

        #self.page().mainFrame().setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff)
        self.page().mainFrame().setScrollBarPolicy(Qt.Vertical, Qt.ScrollBarAlwaysOff)

        self.timerScreen = QTimer()
        self.timerScreen.setInterval(10000)
        self.timerScreen.setSingleShot(True)
        self.timerScreen.timeout.connect(self.takeScreenshot)

        self.loadFinished.connect(self.timerScreen.start)
        self.load(QUrl(url)) 

    @Slot(QNetworkReply)           
    def takeScreenshot(self):        
        [x,y,width,height] = self.image_crop
        frame = self.page().mainFrame()
        size = frame.contentsSize()
        size.setWidth(1000)
        size.setHeight(2000)
        self.page().setViewportSize(size)
        image = QImage(self.page().viewportSize(), QImage.Format_ARGB32)
        painter = QPainter(image)
        frame.render(painter)
        painter.end()
        image1 = image.copy(x,y,width,height)
        image1.save(self.fileName)
        self.finished = True
Exemplo n.º 22
0
 def _create_timer(self, interval, single_shot, handler):
     timer = QTimer()
     timer.setInterval(1000 * interval)
     timer.setSingleShot(single_shot)
     self._timers.add(timer)
     wref = weakref.ref(timer)
     def callback():
         timer = wref()
         if single_shot and timer:
             timer.stop()
             self._timers.discard(timer)
         self._processor.submit(handler)
     timer.timeout.connect(callback)
     def cancel():
         timer = wref()
         if timer:
             timer.stop()
             self._timers.discard(timer)
     handler.cancel_callback = cancel
     timer.start()
     return timer
Exemplo n.º 23
0
class SearchReplaceLabel(SearchHighlighterLabel):
  
  replace_committed = Signal(str, str)
  
  def __init__(self, text, replaceColor=Qt.yellow, highlightColor=Qt.red, replaceTimeout=2):
    super(SearchReplaceLabel, self).__init__(text, highlightColor)
    self._replace_color = replaceColor
    self.replace_committed.connect(self._replaceText)
    self._replacement_fade_timer = QTimer()
    self._replacement_fade_timer.setSingleShot(replaceTimeout)
    self._replacement_fade_timer.timeout.connect(self._putOriginalText)
    
  def _replaceText(self, before, after):
    self.setText(self._original_text) # replace formatting after recent find activity
    self._original_text = self._original_text.replace(before, after)
    replacement = self._original_text.replace(before, "<font color='{0}'>{1}</font>".\
                                              format(self._getColorString(self._replace_color), after))
    self.setText(replacement)
    self._replacement_fade_timer.start()
    
  def _putOriginalText(self):
    self.setText(self._original_text)
Exemplo n.º 24
0
class GlobalTimer:
    """All parsing and highlighting is done in main loop thread.
    If parsing is being done for long time, main loop gets blocked.
    Therefore SyntaxHighlighter controls, how long parsign is going, and, if too long,
    schedules timer and releases main loop.
    One global timer is used by all Qutepart instances, because main loop time usage
    must not depend on opened files count
    """
    
    def __init__(self):
        self._timer = QTimer()
        self._timer.setSingleShot(True)
        self._timer.timeout.connect(self._onTimer)
        
        self._scheduledCallbacks = []
    
    def isActive(self):
        return self._timer.isActive()
    
    def scheduleCallback(self, callback):
        if not callback in self._scheduledCallbacks:
            self._scheduledCallbacks.append(callback)
            self._timer.start()
    
    def unScheduleCallback(self, callback):
        if callback in self._scheduledCallbacks:
            self._scheduledCallbacks.remove(callback)
        if not self._scheduledCallbacks:
            self._timer.stop()
    
    def isCallbackScheduled(self, callback):
        return callback in self._scheduledCallbacks
    
    def _onTimer(self):
        if self._scheduledCallbacks:
            callback = self._scheduledCallbacks.pop()
            callback()
        if self._scheduledCallbacks:
            self._timer.start()
Exemplo n.º 25
0
class GlobalTimer:
    """All parsing and highlighting is done in main loop thread.
    If parsing is being done for long time, main loop gets blocked.
    Therefore SyntaxHighlighter controls, how long parsign is going, and, if too long,
    schedules timer and releases main loop.
    One global timer is used by all Qutepart instances, because main loop time usage
    must not depend on opened files count
    """
    def __init__(self):
        self._timer = QTimer()
        self._timer.setSingleShot(True)
        self._timer.timeout.connect(self._onTimer)

        self._scheduledCallbacks = []

    def isActive(self):
        return self._timer.isActive()

    def scheduleCallback(self, callback):
        if not callback in self._scheduledCallbacks:
            self._scheduledCallbacks.append(callback)
            self._timer.start()

    def unScheduleCallback(self, callback):
        if callback in self._scheduledCallbacks:
            self._scheduledCallbacks.remove(callback)
        if not self._scheduledCallbacks:
            self._timer.stop()

    def isCallbackScheduled(self, callback):
        return callback in self._scheduledCallbacks

    def _onTimer(self):
        if self._scheduledCallbacks:
            callback = self._scheduledCallbacks.pop()
            callback()
        if self._scheduledCallbacks:
            self._timer.start()
Exemplo n.º 26
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 _onTimer(self):
        method = self._scheduledMethods.pop()
        method()
        if self._scheduledMethods:
            self._timer.start(self._IDLE_TIMEOUT_MS)
Exemplo n.º 27
0
class QtOneSecondTimer(OneSecondTimer):
    """
    Concrete implementation of the timer based on Qt classes
    """

    def __init__(self):
        OneSecondTimer.__init__(self)
        self.__timer = QTimer()
        self.__timer.setInterval(1000)
        self.__timer.setSingleShot(False)
        self.__timer.timeout.connect(self._timerElapsed)

    def start(self):
        """Start the timer"""
        self.__timer.start()

    def _timerElapsed(self):
        """Process notification from the timer"""
        self.elapsed.fire()

    def stop(self):
        """Stop the timer"""
        self.__timer.stop()
Exemplo n.º 28
0
    def test_delete_order_happy(self):
        app = self.app
        widget = self.widget
        mw = self.mw
        self._make_basic_preorder()

        QTest.keyEvent(QTest.Click, app.focusWidget(), Qt.Key_S,
                       Qt.ControlModifier)  # modifier, delay
        app.processEvents()

        deleted_order_id = widget._current_order.order_id

        # We're going to have a modal dialog for the new
        # customer name. So we prepare to click on it.

        timer = QTimer()
        timer.timeout.connect(self._accept_dialog)
        timer.setSingleShot(True)
        timer.start(250)

        widget.delete_button_clicked()

        assert not self.order_dao.find_by_id_frozen(deleted_order_id,
                                                    resilient=True)
Exemplo n.º 29
0
class _CompletionList(QListView):
    """Completion list widget
    """
    closeMe = pyqtSignal()
    itemSelected = pyqtSignal(int)
    tabPressed = pyqtSignal()
    
    _MAX_VISIBLE_ROWS = 20  # no any technical reason, just for better UI
    
    _ROW_MARGIN = 6
    
    def __init__(self, qpart, model):
        QListView.__init__(self, qpart.viewport())
        self.setItemDelegate(HTMLDelegate(self))
        
        self._qpart = qpart
        self.setFont(qpart.font())
        
        self.setCursor(QCursor(Qt.PointingHandCursor))
        self.setFocusPolicy(Qt.NoFocus)
        
        self.setModel(model)
        
        self._selectedIndex = -1
        
        # if cursor moved, we shall close widget, if its position (and model) hasn't been updated
        self._closeIfNotUpdatedTimer = QTimer()
        self._closeIfNotUpdatedTimer.setInterval(200)
        self._closeIfNotUpdatedTimer.setSingleShot(True)

        self._closeIfNotUpdatedTimer.timeout.connect(self._afterCursorPositionChanged)
        
        qpart.installEventFilter(self)
        
        qpart.cursorPositionChanged.connect(self._onCursorPositionChanged)
        
        self.clicked.connect(lambda index: self.itemSelected.emit(index.row()))
        
        self.updateGeometry()
        self.show()
        
        qpart.setFocus()
    
    def __del__(self):
        """Without this empty destructor Qt prints strange trace
            QObject::startTimer: QTimer can only be used with threads started with QThread
        when exiting
        """
        pass
    
    def del_(self):
        """Explicitly called destructor.
        Removes widget from the qpart
        """
        self._closeIfNotUpdatedTimer.stop()
        self._qpart.removeEventFilter(self)
        self._qpart.cursorPositionChanged.disconnect(self._onCursorPositionChanged)
        
        # if object is deleted synchronously, Qt crashes after it on events handling
        QTimer.singleShot(0, lambda: self.setParent(None))

    def sizeHint(self):
        """QWidget.sizeHint implementation
        Automatically resizes the widget according to rows count
        
        FIXME very bad algorithm. Remove all this margins, if you can
        """
        width = max([self.fontMetrics().width(word) \
                        for word in self.model().words])
        width = width * 1.4  # FIXME bad hack. invent better formula
        width += 30  # margin
        
        # drawn with scrollbar without +2. I don't know why
        rowCount = min(self.model().rowCount(), self._MAX_VISIBLE_ROWS)
        height = (self.sizeHintForRow(0) * rowCount) + self._ROW_MARGIN

        return QSize(width, height)

    def minimumHeight(self):
        """QWidget.minimumSizeHint implementation
        """
        return self.sizeHintForRow(0) + self._ROW_MARGIN

    def _horizontalShift(self):
        """List should be plased such way, that typed text in the list is under
        typed text in the editor
        """
        strangeAdjustment = 2  # I don't know why. Probably, won't work on other systems and versions
        return self.fontMetrics().width(self.model().typedText()) + strangeAdjustment

    def updateGeometry(self):
        """Move widget to point under cursor
        """
        WIDGET_BORDER_MARGIN = 5
        SCROLLBAR_WIDTH = 30  # just a guess
        
        sizeHint = self.sizeHint()
        width = sizeHint.width()
        height = sizeHint.height()

        cursorRect = self._qpart.cursorRect()
        parentSize = self.parentWidget().size()
        
        spaceBelow = parentSize.height() - cursorRect.bottom() - WIDGET_BORDER_MARGIN
        spaceAbove = cursorRect.top() - WIDGET_BORDER_MARGIN
        
        if height <= spaceBelow or \
           spaceBelow > spaceAbove:
            yPos = cursorRect.bottom()
            if height > spaceBelow and \
               spaceBelow > self.minimumHeight():
                height = spaceBelow
                width = width + SCROLLBAR_WIDTH
        else:
            if height > spaceAbove and \
               spaceAbove > self.minimumHeight():
                height = spaceAbove
                width = width + SCROLLBAR_WIDTH
            yPos = max(3, cursorRect.top() - height)

        xPos = cursorRect.right() - self._horizontalShift()
        
        if xPos + width + WIDGET_BORDER_MARGIN > parentSize.width():
            xPos = max(3, parentSize.width() - WIDGET_BORDER_MARGIN - width)
        
        self.setGeometry(xPos, yPos, width, height)
        self._closeIfNotUpdatedTimer.stop()
    
    def _onCursorPositionChanged(self):
        """Cursor position changed. Schedule closing.
        Timer will be stopped, if widget position is being updated
        """
        self._closeIfNotUpdatedTimer.start()

    def _afterCursorPositionChanged(self):
        """Widget position hasn't been updated after cursor position change, close widget
        """
        self.closeMe.emit()

    def eventFilter(self, object, event):
        """Catch events from qpart
        Move selection, select item, or close themselves
        """
        if event.type() == QEvent.KeyPress and event.modifiers() == Qt.NoModifier:
            if event.key() == Qt.Key_Escape:
                self.closeMe.emit()
                return True
            elif event.key() == Qt.Key_Down:
                if self._selectedIndex + 1 < self.model().rowCount():
                    self._selectItem(self._selectedIndex + 1)
                return True
            elif event.key() == Qt.Key_Up:
                if self._selectedIndex - 1 >= 0:
                    self._selectItem(self._selectedIndex - 1)
                return True
            elif event.key() in (Qt.Key_Enter, Qt.Key_Return):
                if self._selectedIndex != -1:
                    self.itemSelected.emit(self._selectedIndex)
                    return True
            elif event.key() == Qt.Key_Tab:
                self.tabPressed.emit()
                return True
        elif event.type() == QEvent.FocusOut:
            self.closeMe.emit()

        return False

    def _selectItem(self, index):
        """Select item in the list
        """
        self._selectedIndex = index
        self.setCurrentIndex(self.model().createIndex(index, 0))
Exemplo n.º 30
0
from PySide.QtCore import QTimer

from maya import cmds
from maya.OpenMaya import MEventMessage
from maya.api.OpenMaya import MFn

import mampy
from mampy.core.selectionlist import DagpathList
from mampy.core.exceptions import NothingSelected

logger = logging.getLogger(__name__)


TIMER = QTimer()
TIMER.setSingleShot(True)
TIMER_SET = False
SELECT_CHANGE_EVENT = None
HIDDEN_CHILDREN = set()


def is_isolated():
    return cmds.isolateSelect(get_active_panel(), q=True, state=True)


def on_selection_changed(*args):
    if TIMER.isActive():
        TIMER.stop()

    if not get_selected_objects():
        return
Exemplo n.º 31
0
class QtReactor(posixbase.PosixReactorBase):
    implements(IReactorFDSet)

    def __init__(self):
        self._reads = {}
        self._writes = {}
        self._notifiers = {}
        self._timer = QTimer()
        self._timer.setSingleShot(True)
        QObject.connect(self._timer, SIGNAL("timeout()"), self.iterate)

        if QCoreApplication.instance() is None:
            # Application Object has not been started yet
            self.qApp=QCoreApplication([])
            self._ownApp=True
        else:
            self.qApp = QCoreApplication.instance()
            self._ownApp=False
        self._blockApp = None
        posixbase.PosixReactorBase.__init__(self)


    def _add(self, xer, primary, type):
        """
Private method for adding a descriptor from the event loop.

It takes care of adding it if new or modifying it if already added
for another state (read -> read/write for example).
"""
        if xer not in primary:
            primary[xer] = TwistedSocketNotifier(None, self, xer, type)


    def addReader(self, reader):
        """
Add a FileDescriptor for notification of data available to read.
"""
        self._add(reader, self._reads, QSocketNotifier.Read)


    def addWriter(self, writer):
        """
Add a FileDescriptor for notification of data available to write.
"""
        self._add(writer, self._writes, QSocketNotifier.Write)


    def _remove(self, xer, primary):
        """
Private method for removing a descriptor from the event loop.

It does the inverse job of _add, and also add a check in case of the fd
has gone away.
"""
        if xer in primary:
            notifier = primary.pop(xer)
            notifier.shutdown()

        
    def removeReader(self, reader):
        """
Remove a Selectable for notification of data available to read.
"""
        self._remove(reader, self._reads)


    def removeWriter(self, writer):
        """
Remove a Selectable for notification of data available to write.
"""
        self._remove(writer, self._writes)


    def removeAll(self):
        """
Remove all selectables, and return a list of them.
"""
        rv = self._removeAll(self._reads, self._writes)
        return rv


    def getReaders(self):
        return self._reads.keys()


    def getWriters(self):
        return self._writes.keys()


    def callLater(self,howlong, *args, **kargs):
        rval = super(QtReactor,self).callLater(howlong, *args, **kargs)
        self.reactorInvocation()
        return rval


    def reactorInvocation(self):
        self._timer.stop()
        self._timer.setInterval(0)
        self._timer.start()
        

    def _iterate(self, delay=None, fromqt=False):
        """See twisted.internet.interfaces.IReactorCore.iterate.
"""
        self.runUntilCurrent()
        self.doIteration(delay, fromqt)

    iterate = _iterate

    def doIteration(self, delay=None, fromqt=False):
        'This method is called by a Qt timer or by network activity on a file descriptor'
        
        if not self.running and self._blockApp:
            self._blockApp.quit()
        self._timer.stop()
        delay = max(delay, 1)
        if not fromqt:
            self.qApp.processEvents(QEventLoop.AllEvents, delay * 1000)
        if self.timeout() is None:
            timeout = 0.1
        elif self.timeout() == 0:
            timeout = 0
        else:
            timeout = self.timeout()
        self._timer.setInterval(timeout * 1000)
        self._timer.start()


    def runReturn(self, installSignalHandlers=True):
        self.startRunning(installSignalHandlers=installSignalHandlers)
        self.reactorInvocation()


    def run(self, installSignalHandlers=True):
        if self._ownApp:
            self._blockApp = self.qApp
        else:
            self._blockApp = QEventLoop()
        self.runReturn()
        self._blockApp.exec_()
Exemplo n.º 32
0
 def ocrWindowTimer(self): # periodically check selected window
   ret = QTimer(self.q)
   ret.setSingleShot(False)
   #ret.setInterval(2000) # TODO: Allow change this value
   ret.timeout.connect(self.ocrWindow)
   return ret
Exemplo n.º 33
0
class Loader(QMainWindow):
    def __init__(self, parent=None):
        super(Loader, self).__init__(parent)

        self.initUI()

    def updateDeviceList(self):
        self.statusBar().showMessage("Device list updating...",
                                     timeout=STATUS_BAR_TIMEOUT)
        self.deviceListWidget.updateList()
        self.statusBar().showMessage("Device list updated finished!",
                                     timeout=STATUS_BAR_TIMEOUT)

    def getFileName(self, ext):
        fname = QFileDialog.getOpenFileName(self, 'Open file', '/home')
        # if fname[0]:
        #     f = open(fname[0], 'r')

        #     with f:
        #         data = f.read()
        #         self.textEdit.setText(data)

    def initUI(self):

        # textEdit = QTextEdit()
        # self.setCentralWidget(textEdit)

        # self.setStyleSheet("QGroupBox {  border: 1px solid gray; padding: 5px;}");

        # Action to quit program
        exitAction = QAction(QIcon(None), 'Quit', self)
        exitAction.setShortcut('Ctrl+Q')
        exitAction.setStatusTip('Exit application')
        exitAction.triggered.connect(self.close)

        # # Action to update device list
        # self.refreshAction = QAction(QIcon('img/reload.png'), 'Refresh', self)
        # self.refreshAction.setShortcut('F5')
        # self.refreshAction.setStatusTip('Refresh list of connected devices.')
        # self.refreshAction.triggered.connect(self.updateDeviceList)

        # Action to show program information
        helpAction = QAction(QIcon(None), 'Help', self)
        helpAction.setShortcut('F1')
        helpAction.triggered.connect(self.showHelpDialog)

        # Action to help
        aboutAction = QAction(QIcon(None), 'About', self)
        aboutAction.triggered.connect(self.showAboutDialog)

        self.statusBar()

        # Add the file menu
        menubar = self.menuBar()
        fileMenu = menubar.addMenu('&File')
        # fileMenu.addAction(self.refreshAction)
        fileMenu.addAction(exitAction)
        fileMenu = menubar.addMenu('&Help')
        fileMenu.addAction(helpAction)
        fileMenu.addAction(aboutAction)

        # # Add the toolbar
        # toolbar = self.addToolBar('Exit')
        # # toolbar.addAction(self.refreshAction)
        # toolbar.setMovable(False)

        # Add the main windows widgets
        self.deviceListWidget = DeviceList(self.programDeviceHandler,
                                           self.infoDeviceHandler,
                                           self.resetDeviceHandler)
        self.fileSelectorWidget = FileSelector()

        self.setStyleSheet("""
            QStatusBar {
                border-top: 1px solid #CCC;
            }
            QToolBar {
                border-top: 1px solid #DDD;
                border-bottom: 1px solid #CCC;
            }
        """)

        gbox = QGroupBox("Connected USB devices:")
        gboxLayout = QVBoxLayout()
        gboxLayout.addWidget(self.deviceListWidget)
        gbox.setLayout(gboxLayout)

        self.refreshEvent = QTimer()
        self.refreshEvent.setInterval(1250)
        self.refreshEvent.timeout.connect(self.USBUpdate)
        self.refreshEvent.start()

        layout = QVBoxLayout()
        layout.addWidget(self.fileSelectorWidget)
        layout.addWidget(gbox)
        self.setCentralWidget(QWidget())
        self.centralWidget().setLayout(layout)

        self.setMinimumSize(620, 700)
        self.setMaximumWidth(620)
        self.setWindowFlags(Qt.Window | Qt.WindowMinimizeButtonHint
                            | Qt.WindowCloseButtonHint)

        self.setGeometry(300, 300, 350, 250)
        self.setWindowTitle('keyplus layout and firmware loader')
        self.show()

    def process_layout(self, layout_json_obj, layout_file, device_id):
        try:
            settings_gen = layout.parser.SettingsGenerator(
                layout_json_obj, None)
            layout_data = settings_gen.gen_layout_section(device_id)
            settings_data = settings_gen.gen_settings_section(device_id)
            return layout_data, settings_data
        except (layout.parser.ParseError,
                layout.parser.ParseKeycodeError) as err:
            error_msg_box(str(err))
            self.statusBar().showMessage(
                'Error parsing "{}"'.format(layout_file),
                timeout=STATUS_BAR_TIMEOUT * 2)
            return None, None

    def abort_update(self, target_device):
        try:
            target_device.close()
        except:
            pass

        self.deviceListWidget.updateList()

    @Slot(str)
    def programDeviceHandler(self, device_path):
        target_device = self.tryOpenDevicePath(device_path)

        if target_device == None:
            self.abort_update(target_device)
            return

        programmingMode = self.fileSelectorWidget.getProgramingInfo()

        if is_bootloader_device(
                target_device
        ) and programmingMode != FileSelector.ScopeFirmware:
            error_msg_box(
                "Can only upload firmware while bootloader is running. "
                "Either reset it, or upload a firmware hex instead")
            self.abort_update(target_device)
            return

        if programmingMode == FileSelector.ScopeLayout:
            self.statusBar().showMessage("Started updating layout",
                                         timeout=STATUS_BAR_TIMEOUT)

            layout_file = self.fileSelectorWidget.getLayoutFile()

            if layout_file == '':
                error_msg_box("No layout file given.")
                self.abort_update(target_device)
                return
            else:
                pass

            layout_json_obj = None
            with open(layout_file) as file_obj:
                try:
                    layout_json_obj = yaml.safe_load(file_obj.read())
                except Exception as err:
                    error_msg_box("Syntax error in yaml file: " + str(err))
                    self.abort_update(target_device)
                    return

            device_info = protocol.get_device_info(target_device)
            layout_data, settings_data = self.process_layout(
                layout_json_obj, layout_file, device_info.id)
            if layout_data == None or settings_data == None:
                return

            protocol.update_layout_section(target_device, layout_data)
            protocol.update_settings_section(target_device,
                                             settings_data,
                                             keep_rf=True)
            protocol.reset_device(target_device)

            self.statusBar().showMessage("Finished updating layout",
                                         timeout=STATUS_BAR_TIMEOUT)
        elif programmingMode == FileSelector.ScopeDevice:
            layout_file = self.fileSelectorWidget.getRFLayoutFile()
            rf_file = self.fileSelectorWidget.getRFFile()
            target_id = self.fileSelectorWidget.getTargetID()

            self.statusBar().showMessage("Started updating RF settings",
                                         timeout=STATUS_BAR_TIMEOUT)

            if layout_file == '':
                error_msg_box("No layout file given.")
                self.abort_update(target_device)
                return
            elif rf_file == '':
                error_msg_box("No RF settings file given.")
                self.abort_update(target_device)
                return
            elif target_id == None:
                error_msg_box("No device id file given.")
                self.abort_update(target_device)
                return

            layout_json_obj = None
            rf_json_obj = None
            with open(layout_file) as file_obj:
                try:
                    layout_json_obj = yaml.safe_load(file_obj.read())
                except Exception as err:
                    error_msg_box("Syntax error in yaml file: " + str(err))
                    self.abort_update(target_device)
                    return
            with open(rf_file) as file_obj:
                try:
                    rf_json_obj = yaml.safe_load(file_obj.read())
                except Exception as err:
                    error_msg_box("Syntax error in yaml file: " + str(err))
                    self.abort_update(target_device)
                    return

            try:
                settings_gen = layout.parser.SettingsGenerator(
                    layout_json_obj, rf_json_obj)
            except ParseError as err:
                error_msg_box("Error Generating RF settings data: " + str(err))
                self.abort_update(target_device)
                return

            layout_data = settings_gen.gen_layout_section(target_id)
            settings_data = settings_gen.gen_settings_section(target_id)

            protocol.update_settings_section(target_device, settings_data)
            protocol.update_layout_section(target_device, layout_data)
            protocol.reset_device(target_device)

            self.statusBar().showMessage("Finished updating RF settings",
                                         timeout=STATUS_BAR_TIMEOUT)

        elif programmingMode == FileSelector.ScopeFirmware:
            fw_file = self.fileSelectorWidget.getFirmwareFile()

            self.statusBar().showMessage("Starting update firmware",
                                         timeout=STATUS_BAR_TIMEOUT)

            if fw_file == '':
                error_msg_box("No firmware file given.")
            else:

                if is_xusb_bootloader_device(target_device):
                    self.program_xusb_boot_firmware_hex(target_device, fw_file)
                elif is_keyplus_device(target_device):
                    try:
                        serial_num = target_device.serial_number
                        boot_vid, boot_pid = protocol.enter_bootloader(
                            target_device)

                        self.bootloaderProgramTimer = QTimer()
                        self.bootloaderProgramTimer.setInterval(3000)
                        self.bootloaderProgramTimer.setSingleShot(True)
                        self.bootloaderProgramTimer.timeout.connect(
                            lambda: self.programFirmwareHex(
                                boot_vid, boot_pid, serial_num, fw_file))
                        self.bootloaderProgramTimer.start()
                    except (easyhid.HIDException,
                            protocol.KBProtocolException):
                        error_msg_box(
                            "Programming hex file failed: '{}'".format(
                                fw_file))
        else:
            try:
                target_device.close()
            except:
                pass
            raise Exception("Unimplementend programming mode")

    def programFirmwareHex(self, boot_vid, boot_pid, serial_num, file_name):
        device = None

        for i in range(1):
            en = easyhid.Enumeration(vid=boot_vid, pid=boot_pid).find()

            # Look for devices with matching serial_num number
            for dev in en:
                if dev.serial_number == serial_num:
                    device = dev
                    break

            # if a device was found with matching vid:pid, but it doesn't have
            # a matching serial_num number, then assume that the bootloader/firmware
            # doesn't set the serial_num number to the same value, so just program
            # the first matching device
            if len(en) != 0:
                device = en[0]
                break

        if device == None:
            error_msg_box("Couldn't connect to the device's bootloader")
            return
        else:
            if self.tryOpenDevice(device): return

            self.program_xusb_boot_firmware_hex(device, file_name)
        self.statusBar().showMessage("Finished updating firmware",
                                     timeout=STATUS_BAR_TIMEOUT)

    def program_xusb_boot_firmware_hex(self, device, file_name):
        try:
            xusb_boot.write_hexfile(device, file_name)
        except xusb_boot.BootloaderException as err:
            error_msg_box("Error programming the bootloader to hex file: " +
                          str(err))
        finally:
            device.close()

    def tryOpenDevicePath(self, device_path):
        try:
            device = easyhid.Enumeration().find(path=device_path)[0]
            device.open()
            return device
        except:
            msg_box(
                description="Failed to open device! Check it is still present "
                "and you have permission to write to it.",
                title="USB Device write error")
            return None

    def tryOpenDevice(self, device):
        try:
            device.open()
            return False
        except:
            msg_box(
                description="Failed to open device! Check it is still present "
                "and you have permission to write to it.",
                title="USB Device write error")
            return True

    @Slot(str)
    def resetDeviceHandler(self, device_path):
        device = self.tryOpenDevicePath(device_path)
        if device == None: return

        if is_keyplus_device(device):
            protocol.reset_device(device)
        elif is_xusb_bootloader_device(device):
            xusb_boot.reset(device)
        elif is_nrf24lu1p_bootloader_device(device):
            print("TODO: reset: ", device_path, file=sys.stderr)
        else:
            print("Can't reset device: ", device_path, file=sys.stderr)

    @Slot(str)
    def infoDeviceHandler(self, device_path):
        device = self.tryOpenDevicePath(device_path)
        if device == None: return

        settingsInfo = protocol.get_device_info(device)
        firmwareInfo = protocol.get_firmware_info(device)
        rfInfo = protocol.get_rf_info(device)
        if firmwareInfo.has_at_least_version('0.2.2'):
            errorInfo = protocol.get_error_info(device)
        else:
            errorInfo = None
        device.close()

        header = ["Attribute", "Value"]
        device_settings = [
            ("Device ID", settingsInfo.id),
            ("Device name", settingsInfo.device_name_str()),
            ("Device serial number", device.serial_number),
            ("Last layout update", settingsInfo.timestamp_str()),
            ("Default report mode", settingsInfo.default_report_mode_str()),
            ("Matrix scan mode", settingsInfo.scan_mode_str()),
            ("Matrix columns", settingsInfo.col_count),
            ("Matrix rows", settingsInfo.row_count),
            ("Settings stored CRC", hex(settingsInfo.crc)),
            ("Settings computed CRC", hex(settingsInfo.computed_crc)),
            ("USB", not (settingsInfo.has_usb_disabled()
                         or not firmwareInfo.has_fw_support_usb())),
            ("I2C", not (settingsInfo.has_i2c_disabled()
                         or not firmwareInfo.has_fw_support_i2c())),
            ("nRF24 wireless",
             not (settingsInfo.has_nrf24_disabled()
                  or not firmwareInfo.has_fw_support_nrf24())),
            ("Unifying mouse",
             not (settingsInfo.has_unifying_mouse_disabled()
                  or not firmwareInfo.has_fw_support_unifying())),
            ("Bluetooth",
             not (settingsInfo.has_bluetooth_disabled()
                  or not firmwareInfo.has_fw_support_bluetooth())),
            ("RF pipe0", binascii.hexlify(rfInfo.pipe0).decode('ascii')),
            ("RF pipe1", binascii.hexlify(rfInfo.pipe1).decode('ascii')),
            ("RF pipe2", "{:02x}".format(rfInfo.pipe2)),
            ("RF pipe3", "{:02x}".format(rfInfo.pipe3)),
            ("RF pipe4", "{:02x}".format(rfInfo.pipe4)),
            ("RF pipe5", "{:02x}".format(rfInfo.pipe5)),
            ("RF channel", str(rfInfo.channel)),
            ("RF auto retransmit count", str(rfInfo.arc)),
            ("RF data rate", protocol.data_rate_to_str(rfInfo.data_rate)),
        ]

        firmware_settings = [
            ("Firmware version",
             "{}.{}.{}".format(firmwareInfo.version_major,
                               firmwareInfo.version_minor,
                               firmwareInfo.version_patch)),
            ("Firmware build date",
             str(datetime.datetime.fromtimestamp(firmwareInfo.timestamp))),
            ("Firmware git hash", "{:08x}".format(firmwareInfo.git_hash)),
            ("Layout storage size", firmwareInfo.layout_flash_size),
            ("Bootloader VID", "{:04x}".format(firmwareInfo.bootloader_vid)),
            ("Bootloader PID", "{:04x}".format(firmwareInfo.bootloader_pid)),
            ("Support scanning", firmwareInfo.has_fw_support_scanning()),
            ("Support scanning col to row",
             firmwareInfo.has_fw_support_scanning_col_row()),
            ("Support scanning row to col",
             firmwareInfo.has_fw_support_scanning_row_col()),
            ("Media keys", firmwareInfo.has_fw_support_key_media()),
            ("Mouse keys", firmwareInfo.has_fw_support_key_mouse()),
            ("Layer keys", firmwareInfo.has_fw_support_key_layers()),
            ("Sticky keys", firmwareInfo.has_fw_support_key_sticky()),
            ("Tap keys", firmwareInfo.has_fw_support_key_tap()),
            ("Hold keys", firmwareInfo.has_fw_support_key_hold()),
            ("Support 6KRO", firmwareInfo.has_fw_support_6kro()),
            ("Support NKRO", firmwareInfo.has_fw_support_key_hold()),
            ("Support indicator LEDs",
             firmwareInfo.has_fw_support_led_indicators()),
            ("Support LED backlighting",
             firmwareInfo.has_fw_support_led_backlighting()),
            ("Support ws2812 LEDs", firmwareInfo.has_fw_support_led_ws2812()),
            ("Support USB", firmwareInfo.has_fw_support_usb()),
            ("Support nRF24 wireless", firmwareInfo.has_fw_support_nrf24()),
            ("Support Unifying", firmwareInfo.has_fw_support_unifying()),
            ("Support I2C", firmwareInfo.has_fw_support_i2c()),
            ("Support Bluetooth", firmwareInfo.has_fw_support_bluetooth()),
        ]

        if errorInfo:
            error_codes = []
            for code in errorInfo.get_error_codes():
                error_codes.append((errorInfo.error_code_to_name(code), code))
        else:
            error_codes = [
                ('Error codes require firmware version 0.2.2 or greater', )
            ]

        self.info_window = DeviceInformationWindow(
            self,
            header,
            device_settings,
            firmware_settings,
            error_codes,
        )
        self.info_window.setModal(True)
        self.info_window.exec_()

        self.deviceListWidget.updateList()

    def USBUpdate(self):
        self.deviceListWidget.updateList()

    def showAboutDialog(self):
        QMessageBox.about(self, "About keyplus Loader", """
The keyplus layout and firmware loader.
""")

    def showHelpDialog(self):
        QMessageBox.about(
            self, "keyplus Loader Help", """
This is the layout and firmware loader for the keyplus keyboard firmware.

The layout files are *.yaml files. For documentation and examples see here: TODO

The rf files are *.yaml files. For documentation and examples see here: TODO

The firmware loader accepts *.hex files. For the latest keyplus firmware see here: TODO

""")
Exemplo n.º 34
0
class Fight(QObject):
    def __init__(self, mw):
        super().__init__()

        self._mw = mw

        # Кнопка "Отнять у слабого"
        self._css_path_button_fight = "div[class='button-big btn f1']"

        # Кнопка поедания Сникерса
        self._css_path_button_snikers = 'div[onclick*=snikers]'

        # Кнопка использования Тонуса
        self._css_path_button_use_tonus = 'div[onclick*=tonus]'

        # Таймер для ожидания загрузки страницы с выбором противника
        self._timer_enemy_load = QTimer()
        self._timer_enemy_load.setInterval(333)
        self._timer_enemy_load.timeout.connect(self._check_enemy_load)

        # Таймер для поиска противника
        self._timer_next_enemy = QTimer()
        self._timer_next_enemy.setInterval(1000)
        self._timer_next_enemy.setSingleShot(True)
        self._timer_next_enemy.timeout.connect(self._next_enemy)

        # Информация о противнике: имя, уровень, url
        self.enemy_name = None
        self.enemy_level = None
        self.enemy_url = None

        # Выигрыш / проигрыш. Если проигрыш, self.is_winner будет равен False
        self.received_money = None

        # True если победили мы, False если противник и None если ничья
        self.is_winner = None

        # Минимальная разница в уровне с противником. Эта величина вычитается из текущего уровня персонажа.
        self.min_diff_levels = 0

        # Максимальная разница в уровне с противником. Эта величина добавляется к текущему уровню персонажа.
        # Нельзя нападать на противника, у которого уровень больше трех от нашего
        self.max_diff_levels = 3

    # Сигнал вызывается, когда противник на странице найден -- например, страница загрузилась
    _enemy_load_finished = Signal()

    # Сигнал вызывается, когда противник подходит для нападения
    _enemy_found = Signal()

    def is_ready(self):
        """Возвращает True, если вызов метода run будет иметь смысл -- можем напасть, иначе False."""

        try:
            # TODO: для того, чтобы метод self.fight.is_ready() работал правильно, текущим адресом должны
            # быть Закоулки -- метод has_snikers, используемый в is_ready работает только в Закоулках
            # Идем в Закоулки
            self._mw.alley()

            # TODO: рефакторинг с self._timeout_fight()
            if self._timeout_fight() is not None:
                logger.info('Напасть можно будет через %s секунд.', self._timeout_fight())

            logger.info('self._timeout_fight() = %s.', self._timeout_fight())
            logger.info('self.has_snickers() = %s.', self.has_snickers())
            logger.info('self.is_ready() = %s.', self._timeout_fight() is None or self.has_snickers())

            # True, если таймер закончился или есть Сникерс
            return self._timeout_fight() is None or self.has_snickers()

        except MoswarClosedError:
            raise

        except Exception as e:
            raise MoswarBotError(e)

        return False

    def _timeout_fight(self):
        """Функция возвращает количество оставшихся секунд до возможности напасть.
        Если секунд осталось 0 или меньше 0, то вернется None."""

        for timeout in self._mw.doc.findAll('[id*=timeout]'):
            timer = timeout.attribute('timer')
            if timer and 'alley' in timeout.attribute('href'):
                timer = int(timer)
                return timer if timer > 0 else None

    def run(self):
        """Функция для нападения на игроков.

        Ищем слабого горожанина (заброшенного персонажа) -- не нужно привлекать внимание к боту.
        Уровень противника в пределах нашего +/- 1
        """

        try:
            if self._mw._used:
                logger.warn('Бот в данный момент занят процессом "%s". Выхожу из функции.', self._mw._used_process)
                return

            self._mw._used_process = "Нападение на игроков"
            logger.debug('Выполняю задание "%s".', self._mw._used_process)

            self._mw.alley()

            # TODO: оптимиизровать использование сникерсов -- если они есть, сразу использовать и нападать и так,
            # пока не будут потрачены все

            if not self.is_ready():
                logger.debug('Нападать еще нельзя.')
                return

            self._mw._used = True

            # TODO: если есть тонус, использовать, чтобы сразу напасть
            # TODO: флаг на разрешение использования тонуса, чтобы сразу напасть
            # self.use_tonus()

            # Если не получилось съесть Сникерс, восстанавливаем по старинке
            if not self.eat_snickers():
                if self._mw.current_hp() < self._mw.max_hp():
                    self._mw.restore_hp.run()

            logger.debug('Нажимаю на кнопку "Отнять у слабого".')
            # TODO: в одном из запусков дальше этой строки, похоже дело не пошло, возможно, страница с кнопкой
            # не прогрузилась

            # Кликаем на кнопку "Отнять у слабого"
            self._mw.click_tag(self._css_path_button_fight)

            # Если не нашли подходящего противника, смотрим следующего
            if not self._check_enemy():
                self._timer_next_enemy.start()

                # Ожидаем пока противник не будет найден
                loop = QEventLoop()
                self._enemy_found.connect(loop.quit)
                loop.exec_()

            logger.debug('Нападаем на "%s" [%s]: %s.', self.enemy_name, self.enemy_level, self.enemy_url)

            # Кликаем на кнопку "Напасть"
            self._mw.click_tag('.button-fight a')

            # Перемотка битвы
            forward = '#controls-forward'

            # Ждем пока после клика прогрузится страница и появится элемент
            Waitable(self._mw).wait(forward)

            # Перематываем бой
            self._mw.click_tag(forward)

            # Обрабатываем результаты боя
            self.handle_results()

        except MoswarClosedError:
            raise

        except Exception as e:
            raise MoswarBotError(e)

        finally:
            self._mw._used = False

    def name_winner(self):
        """Функция возвращает имя победителя в драке."""

        try:
            name = self._mw.doc.findFirst('.result div').toPlainText()
            name = name.replace('Победитель:', '')
            name = name[:name.rindex('[')]
            return name.strip()
        except Exception as e:
            raise MoswarElementIsMissError(e)

    def handle_results(self):
        """Обработка результата боя."""

        result = '.result'

        # Ждем пока после клика прогрузится страница и появится элемент
        Waitable(self._mw).wait(result)

        # Найдем элемент, в котором будут все результаты боя
        result = self._mw.doc.findFirst(result)

        if 'Ничья!' in result.toPlainText():
            self.is_winner = None
            self.received_money = 0
            logger.debug('Результат боя: Ничья.')
            return

        # Проверим по именам кто победил
        self.is_winner = self._mw.name() == self.name_winner()

        tugriki = result.findFirst('.tugriki').toPlainText().replace(',', '')
        tugriki = int(tugriki)
        self.received_money = tugriki

        # Сначала покажем выигранные монет и опыт, потом все остальное. Список используется для того, чтобы
        # порядок вывода результата боя был в порядке добавления элементов в этот список
        result_item_keys = ['Монеты', 'Опыт']

        result_dict = {
            'Монеты': tugriki,
            'Опыт': result.findFirst('.expa').toPlainText(),
        }

        neft = result.findFirst('.neft')
        if not neft.isNull():
            result_item_keys.append('Нефть')
            result_dict['Нефть'] = int(neft.toPlainText())

        # Искры не всегда будут -- обычно перед праздниками они появляются
        sparkles = result.findFirst('.sparkles')
        if not sparkles.isNull():
            result_item_keys.append('Искры')
            result_dict['Искры'] = sparkles.toPlainText()

        for img in result.findAll('.object-thumb'):
            obj = img.findFirst('img').attribute('alt')
            count = img.findFirst('.count').toPlainText()

            result_dict[obj] = count
            result_item_keys.append(obj)

        result_list = list()
        for key in result_item_keys:
            result_list.append('  {}: {}'.format(key, result_dict[key]))

        result_str = 'Результат боя:'
        if not self.is_winner:
            result_str += ' Бой проигран. Вся награда достается противнику.'

        result_str += '\n'
        result_str += '\n'.join(result_list)

        logger.debug(result_str)

    # TODO: работает только в Закоулках
    def has_tonus(self):
        """Функция возвратит True, если можно использовать Тонус для сброса таймера, иначе False."""

        button = self._mw.doc.findFirst(self._css_path_button_use_tonus)
        return not button.isNull()

    def use_tonus(self):
        """Функция для использования Тонуса, для сброса таймаута между драками.
        Возвращает True, если получилось, иначе False."""

        if self.has_tonus():
            logger.debug('Использую Тонус.')
            self._mw.click_tag(self._css_path_button_use_tonus)

            # TODO: если Тонуса будет не хватать, то появится окошко с предложением восстановить за плату

            # Ждем пока после клика прогрузится страница и появится элемент
            Waitable(self._mw).wait(self._css_path_button_use_tonus)
            return True

        return False

    # TODO: работает только в Закоулках
    def has_snickers(self):
        """Функция возвратит True, если можно съесть Сникерс, иначе False."""

        button = self._mw.doc.findFirst(self._css_path_button_snikers)
        return not button.isNull()

    def eat_snickers(self):
        """Функция для съедания Сникерса. Возвращает True, если получилось съесть, иначе False."""

        if self.has_snickers():
            logger.debug('Съедаю сникерс.')
            self._mw.click_tag(self._css_path_button_snikers)

            # Ждем пока после клика прогрузится страница и появится элемент
            Waitable(self._mw).wait(self._css_path_button_fight)
            return True

        return False

    def _check_enemy_load(self):
        """Функция для ожидания загрузки страницы с выбором противника."""

        enemy = self._mw.doc.findFirst('.fighter2')

        # Если нашли элемент, описывающий противника
        if not enemy.isNull():
            self._enemy_load_finished.emit()
            self._timer_enemy_load.stop()

    def _check_enemy(self):
        """Функция ищет противника на текущей странице и проверяет его тип и уровень.
        Возвращает True если нашелся подходящий противник, иначе False.

        """

        self._timer_enemy_load.start()

        loop = QEventLoop()
        self._enemy_load_finished.connect(loop.quit)
        loop.exec_()

        enemy = self._mw.doc.findFirst('.fighter2')

        # Определим тип противника -- нам нужен горожанин (нпс)
        is_npc = enemy.findFirst('.npc')
        is_npc = not is_npc.isNull()

        # Узнаем уровень противника
        level = enemy.findFirst('.level')
        level = level.toPlainText()
        level = level.replace('[', '').replace(']', '')
        level = int(level)

        # Гиперссылка на профиль противника
        a = enemy.findFirst('a')

        # Имя противника
        name = a.toPlainText()

        # Адрес противника
        url = urljoin(self._mw.moswar_url, a.attribute('href'))

        my_level = self._mw.level()

        # TODO: добавить ограничение на количество попыток найти гражданина, перед тем как напасть на игрока

        # Проверяем, что уровень противника находится в пределе диапазона
        check_level = my_level - self.min_diff_levels <= level <= my_level + self.max_diff_levels

        found = is_npc and check_level
        if found:
            self.enemy_name = name
            self.enemy_level = level
            self.enemy_url = url

        return found

    def _next_enemy(self):
        """Функция для поиска следующего противника."""

        logger.debug('Ищем следующего противника.')

        # Кликаем на кнопку "Искать другого"
        self._mw.click_tag(".button-search a")

        # Если нашли противника
        if self._check_enemy():
            self._enemy_found.emit()
            self._timer_next_enemy.stop()
        else:
            # Ищем дальше
            self._timer_next_enemy.start()
Exemplo n.º 35
0
class QTReactor(PosixReactorBase):
    """
    Qt based reactor.
    """
    implements(IReactorFDSet)

    _timer = None

    def __init__(self):
        self._reads = {}
        self._writes = {}
        self._timer=QTimer()
        self._timer.setSingleShot(True)
        if QCoreApplication.startingUp():
            self.qApp=QCoreApplication([])
            self._ownApp=True
        else:
            self.qApp = QCoreApplication.instance()
            self._ownApp=False
        self._blockApp = None
        self._readWriteQ=[]

        """ some debugging instrumentation """
        self._doSomethingCount=0

        PosixReactorBase.__init__(self)

    def addReader(self, reader):
        if not reader in self._reads:
            self._reads[reader] = TwistedSocketNotifier(self, reader,
                                                       QSocketNotifier.Read)


    def addWriter(self, writer):
        if not writer in self._writes:
            self._writes[writer] = TwistedSocketNotifier(self, writer,
                                                        QSocketNotifier.Write)


    def removeReader(self, reader):
        if reader in self._reads:
            #self._reads[reader].shutdown()
            #del self._reads[reader]
            self._reads.pop(reader).shutdown()

    def removeWriter(self, writer):
        if writer in self._writes:
            self._writes[writer].shutdown()
            #del self._writes[writer]
            self._writes.pop(writer)


    def removeAll(self):
        return self._removeAll(self._reads, self._writes)


    def getReaders(self):
        return self._reads.keys()


    def getWriters(self):
        return self._writes.keys()

    def callLater(self,howlong, *args, **kargs):
        rval = super(QTReactor,self).callLater(howlong, *args, **kargs)
        self.reactorInvocation()
        return rval

    def crash(self):
        super(QTReactor,self).crash()

    def iterate(self,delay=0.0):
        t=self.running # not sure I entirely get the state of running
        self.running=True
        self._timer.stop() # in case its not (rare?)
        try:
            if delay == 0.0:
                self.reactorInvokePrivate()
                self._timer.stop() # supports multiple invocations
            else:
                endTime = delay + time.time()
                self.reactorInvokePrivate()
                while True:
                    t = endTime - time.time()
                    if t <= 0.0: return
                    self.qApp.processEvents(QEventLoop.AllEvents |
                                      QEventLoop.WaitForMoreEvents,t*1010)
        finally:
            self.running=t

    def addReadWrite(self,t):
        self._readWriteQ.append(t)

    def runReturn(self, installSignalHandlers=True):
        QObject.connect(self._timer, SIGNAL("timeout()"),
                        self.reactorInvokePrivate)
        self.startRunning(installSignalHandlers=installSignalHandlers)
        self._timer.start(0)

    def run(self, installSignalHandlers=True):
        try:
            if self._ownApp:
                self._blockApp=self.qApp
            else:
                self._blockApp = fakeApplication()
            self.runReturn(installSignalHandlers)
            self._blockApp.exec_()
        finally:
            self._timer.stop() # should already be stopped

    def reactorInvocation(self):
        self._timer.setInterval(0)

    def reactorInvokePrivate(self):
        if not self.running:
            self._blockApp.quit()
        self._doSomethingCount += 1
        self.runUntilCurrent()
        t = self.timeout()
        if t is None: t=0.1
        else: t = min(t,0.1)
        self._timer.setInterval(t*1010)
        self.qApp.processEvents() # could change interval
        self._timer.start()

    def doIteration(self):
        assert False, "doiteration is invalid call"
Exemplo n.º 36
0
class InfoBar(object):
    """Adds a info bar to the bottom of the main window"""

    # Should be stored and restored from uistate.ini
    infoSettings = {
        "showCPU": True,
        "showMemory": True,
        "showDisk": True,
        "showNetwork": True
    }

    def __init__(self):

        global gEnableResourceMonitoring
        self.enableResourceMonitoring = gEnableResourceMonitoring
        self.bar = hiero.ui.mainWindow().statusBar()

        self.updateMonitorIntervalMS = gUpdateIntervalMS  # The monitor update time in milliseconds.
        self.timer = QTimer()
        self.timer.setSingleShot(False)
        self.timer.timeout.connect(self.updateStatusBar)

        self.currentDiskIOBytes = psutil.disk_io_counters().read_bytes
        self.currentNetworkBytesReceived = psutil.net_io_counters().bytes_recv

        # This observes the current pid (the App process id) via psutil, and reports back
        if self.enableResourceMonitoring:
            self.processHelper = PSUtilProcessWrapper()

        # The frameServer instance
        self.frameServerInstance = nukestudio.frameServer

        # Initialise the Status Bar
        self.setupUI()

        # We haven't started monitoring at this point
        self.isMonitoring = False

        # Begin monitoring after a few secs to give frame server time to start up properly
        QTimer.singleShot(gInitialDelayMS, self.startMonitoring)

    def getLatestStyleSheet(self):
        styleFile = os.path.join(cwd, "style.stylesheet")
        with open(styleFile, "r") as fh:
            return fh.read()

    def hide(self):
        """Hide the info bar"""
        self.bar.setHidden(True)

    def show(self):
        """Show the info bar"""
        self.bar.setHidden(False)

    def rendersExistInQueue(self):
        """Return whether renders exist in the Frame server queue"""
        return len(self.frameServerInstance.renderQueue.requestsInProgress) > 0

    def _handleServerUnreachable(self):
        """This is called when the server becomes unreachable"""
        print "[WARNING]: Nuke Frame Server was not reachable."
        self.frameserverStatusLabel.setPixmap(QPixmap("icons:Offline.png"))
        self.restartServerButton.setHidden(False)

    def _setResourcesLabelColour(self, memRatio, cpuUsage):
        """Sets the Resources label to be red if the memory usage gets too high"""
        if memRatio > 0.9:
            color = QColor(Qt.red)
            alpha = 220
            values = "{r}, {g}, {b}, {a}".format(r=color.red(),
                                                 g=color.green(),
                                                 b=color.blue(),
                                                 a=alpha)
            #self.nukeResourcesLabel.setStyleSheet("QLabel { vertical-align: middle; font: 10pt; color: rgba("+values+"); }")
        else:
            #self.nukeResourcesLabel.setStyleSheet("QLabel { vertical-align: middle; font: 10pt; }")
            return

    def restartServerAsync(self):
        self.frameServerInstance.stop()
        self.frameServerInstance.start()
        QTimer.singleShot(3000, self.startMonitoring)

    def restartServer(self):
        """Called to restart the Nuke Frame Server, done asynchronously"""
        self.stopMonitoring()
        self.restartServerButton.setHidden(True)
        #self.nukeResourcesLabel.setText("Re-Starting Frame Server...")
        QTimer.singleShot(150, self.restartServerAsync)

    # Displays the resources label, based on settings.
    def buildResourcesLabel(self):
        if self.isMonitoring:
            print "Building resources Label..."

    def updateResourcesStatusLabel(self):
        """Updates the Memory Label String"""

        if self.enableResourceMonitoring:
            if self.memoryString.isVisible():
                self.updateMemoryLayout()

            if self.cpuString.isVisible():
                self.updateCPULayout()

            if self.diskString.isVisible():
                self.updateDiskLayout()

            if self.networkString.isVisible():
                self.updateNetworkLayout()

            #totalSystemMemoryGB = self.processHelper.totalSystemMemory()
            #memRatio = currentMemUsageGB / totalSystemMemoryGB
            # This little test makes the label red if the memory usage exceeds 90% of the maximum allowed
            #self._setResourcesLabelColour( memRatio, currentCPUUsageAsPercentatge )

    def updateMemoryLayout(self):
        currentMemUsageGB = self.processHelper.nukeMemoryUsageInGB()
        currentMemUsageAsPercentage = self.processHelper.nukeMemoryUsageAsPercentage(
        )
        self.memoryString.setText(
            "%.2f GB (%.1f%%)" %
            (currentMemUsageGB, currentMemUsageAsPercentage))

    def updateCPULayout(self):
        currentCPUUsageAsPercentatge = self.processHelper.nukeCPUUsageAsPercentage(
        )
        self.cpuString.setText("%.1f%%" % currentCPUUsageAsPercentatge)

    def updateDiskLayout(self):
        diskMBPerSec = self._diskMBPerSec()
        self.diskString.setText("%.2f MB/s" % diskMBPerSec)

    def updateNetworkLayout(self):
        networkMBPerSec = self._networkMBPerSec()
        self.networkString.setText("%.2f MB/s" % networkMBPerSec)

    def _diskMBPerSec(self):
        """Returns Total Disk Read+Write speed in MB/s"""
        oldBytes = self.currentDiskIOBytes
        DISKS = psutil.disk_io_counters(perdisk=True)
        readWriteBytes = [(DISKS[disk].read_bytes, DISKS[disk].write_bytes)
                          for disk in DISKS.keys()]
        newBytes = sum([sum(x) for x in zip(*readWriteBytes)])
        bytesDiff = newBytes - oldBytes
        self.currentDiskIOBytes = newBytes
        bytesPerSecond = (newBytes -
                          oldBytes) / (self.updateMonitorIntervalMS / 1000)
        MBPerSecond = bytesToMB(bytesPerSecond)
        return MBPerSecond

    def _networkMBPerSec(self):
        """Returns Total Network Read+Write speed in MB/s"""
        oldBytes = self.currentNetworkBytesReceived

        NET = psutil.net_io_counters(pernic=True)
        readWriteBytes = [(NET[adapter].bytes_recv, NET[adapter].bytes_sent)
                          for adapter in NET.keys()]
        newBytes = sum([sum(x) for x in zip(*readWriteBytes)])
        bytesDiff = newBytes - oldBytes
        self.currentNetworkBytesReceived = newBytes
        bytesPerSecond = (newBytes -
                          oldBytes) / (self.updateMonitorIntervalMS / 1000)
        MBPerSecond = bytesToMB(bytesPerSecond)
        return MBPerSecond

    def setupUI(self):
        """Initialise the UI"""

        self.bar.setStyleSheet(self.getLatestStyleSheet())
        #self.bar.setFixedHeight(30)
        self.frameserverStatusLabel = QLabel("")

        # Resources
        self.cpuIconPath = os.path.join(gIconPath, "cpu.png")
        self.memoryIconPath = os.path.join(gIconPath, "memory.png")
        self.diskReadIconPath = os.path.join(gIconPath, "disk_read.png")
        self.networkReadIconPath = os.path.join(gIconPath, "net_read.png")

        # MEMORY SECTION
        self.memoryImageButton = QPushButton(
            QPixmap(
                (self.memoryIconPath)).scaledToHeight(20,
                                                      Qt.SmoothTransformation),
            "")
        self.memoryImageButton.setObjectName("show_button_memory")
        self.memoryImageButton.setToolTip(
            "Click to toggle monitoring of 'Real Memory' usage")
        self.memoryString = QLabel("MEMORY (GB)")
        self.memoryString.setToolTip(
            "'Real Memory' usage of this Nuke Session")
        self.memoryImageButton.clicked.connect(
            lambda: self.show_button_clicked(self.memoryString))

        # CPU SECTION
        self.cpuImageButton = QPushButton(
            QPixmap(
                (self.cpuIconPath)).scaledToHeight(20,
                                                   Qt.SmoothTransformation),
            "")
        self.cpuImageButton.setObjectName("show_button_cpu")
        self.cpuImageButton.setToolTip(
            "Click to toggle monitoring of CPU usage of this Nuke Session")
        self.cpuString = QLabel("CPU (%)")
        self.cpuString.setToolTip("CPU usage of this Nuke Session")
        self.cpuImageButton.clicked.connect(
            lambda: self.show_button_clicked(self.cpuString))

        # DISK SECTION
        self.diskImageButton = QPushButton(
            QPixmap((self.diskReadIconPath)).scaledToHeight(
                20, Qt.SmoothTransformation), "")
        self.diskImageButton.setObjectName("show_button_disk")
        self.diskImageButton.setToolTip(
            "Click to toggle monitoring of Disk Read+Write usage for this machine"
        )
        self.diskString = QLabel("DISK (MB/s)")
        self.diskImageButton.clicked.connect(
            lambda: self.show_button_clicked(self.diskString))
        self.diskString.setToolTip("Disk Read+Write usage for this machine")

        # NETWORK SECTION
        self.networkImageButton = QPushButton(
            QPixmap((self.networkReadIconPath)).scaledToHeight(
                20, Qt.SmoothTransformation), "")
        self.networkImageButton.setObjectName("show_button_network")
        self.networkImageButton.setToolTip(
            "Click to toggle monitoring of Network Read+Write traffic")
        self.networkString = QLabel("NETWORK (MB/s)")
        self.networkString.setToolTip(
            "Total Network Read+Write traffic for this machine")
        self.networkImageButton.clicked.connect(
            lambda: self.show_button_clicked(self.networkString))

        # Settings Button - Displays what options should be shown in the Status Bar
        self.settingsButton = QPushButton()
        self.settingsButton.setIcon(QIcon("icons:Settings.png"))
        self.settingsButton.clicked.connect(self.showSettings)

        # Build the layout based on Preferences
        #self.cpuWidget.setVisible(self.infoSettings['showCPU'])
        #self.memoryWidget.setVisible(self.infoSettings['showMemory'])
        #self.diskWidget.setVisible(self.infoSettings['showDisk'])
        #self.networkWidget.setVisible(self.infoSettings['showNetwork'])

        self.restartServerButton = QPushButton(
            QPixmap("icons:TransformRotateRight.png").scaledToHeight(
                20, Qt.SmoothTransformation), "")
        self.restartServerButton.setFixedHeight(16)
        self.restartServerButton.clicked.connect(self.restartServer)
        self.restartServerButton.setHidden(True)
        self.restartServerButton.setFlat(True)
        self.restartServerButton.setToolTip(
            "Click here to restart the Nuke Frameserver")
        self.frameServerIsRendering = False

        self.spinnerMovie = QMovie("icons:RenderingSpinner.gif")
        self.spinnerMovie.start()

        self.bar.addPermanentWidget(self.cpuImageButton)
        self.bar.addPermanentWidget(self.cpuString)
        self.bar.addPermanentWidget(self.memoryImageButton)
        self.bar.addPermanentWidget(self.memoryString)
        self.bar.addPermanentWidget(self.diskImageButton)
        self.bar.addPermanentWidget(self.diskString)
        self.bar.addPermanentWidget(self.networkImageButton)
        self.bar.addPermanentWidget(self.networkString)
        self.bar.addPermanentWidget(self.frameserverStatusLabel)
        self.bar.addPermanentWidget(self.restartServerButton)
        self.bar.addPermanentWidget(self.settingsButton)

    def show_button_clicked(self, sender):
        sender.setVisible(not sender.isVisible())

    def _updateUIForServerIsRunning(self):
        """Updates the UI for when the server is reachable"""
        #self.frameserverStatusLabel.setToolTip("Nuke Frame Server is reachable")
        self.getFrameServerWorkers()
        self.frameserverStatusLabel.setPixmap(QPixmap("icons:OK.png"))
        self.restartServerButton.setHidden(True)

    def showSettings(self):
        dialog = SettingsDialog()
        dialog.show()

    # Returns a nicely formatted list of Frame Server workers
    def getFrameServerWorkers(self):
        statusString = str(self.frameServerInstance.getStatus(1000))
        workers = re.findall("workerStatus \{.*?\}", statusString)

        if len(workers) == 0:
            self.frameserverStatusLabel.setToolTip(
                "Unable to determine number of frame server workers.")
            return

        prettyWorkersString = "Frame Server Status (%i workers):\n" % len(
            workers) + "\n".join(workers)
        self.frameserverStatusLabel.setToolTip(prettyWorkersString)

    def updateStatusBar(self):
        """Updates the Status bar widgets depending on whether the frameServer is reachable"""

        #print "Status: ", str(self.frameServerInstance.getStatus(10))

        # DEBUG - Stylesheet Changes can be applied here and seen live
        #self.bar.setStyleSheet( self.getLatestStyleSheet() )

        try:
            isRunning = self.frameServerInstance.isRunning(0.25)

            if isRunning and not self.rendersExistInQueue():
                self._updateUIForServerIsRunning()
                self.frameServerIsRendering = False

            elif isRunning and self.rendersExistInQueue():
                if self.frameServerIsRendering == False:
                    self.frameServerIsRendering = True
                    self.frameserverStatusLabel.setPixmap(None)
                    self.frameserverStatusLabel.setMovie(self.spinnerMovie)

            else:
                self._handleServerUnreachable()

            self.updateResourcesStatusLabel()

        except:
            self._handleServerUnreachable()
            self.updateResourcesStatusLabel()

    def startMonitoring(self):
        """This timer fires every X milliseconds to update the status."""
        self.timer.start(self.updateMonitorIntervalMS)
        self.isMonitoring = True

    def stopMonitoring(self):
        """Stops the monitoring process"""
        self.timer.stop()
        self.isMonitoring = False
Exemplo n.º 37
0
    app = QApplication(sys.argv)
    win = app.desktop().screenGeometry()
    cfg = config.XiboConfig(arg.config)

    signal.signal(signal.SIGINT, lambda s, f: app.quit())

    if  not os.path.isfile(arg.config):
        print
        print 'The configuration file %s is not exists.' % arg.config
        print 'Creating default configuration ...'
        cfg.save()
        print "Please edit the '%s' file and then rerun xibopy again." % arg.config
        print
        sys.exit(0)

    r = -1
    with ui.XiboWindow(cfg) as w:
        t = QTimer()
        t.setSingleShot(True)
        t.timeout.connect(w.showFullScreen)
        t.start(1000)
        w.setGeometry(win)
        w.show()
        r = app.exec_()
        print 'Exiting, please wait ...'

    sys.exit(r)

#
#
#
Exemplo n.º 38
0
class Jaime(QObject,Singleton):
    
    instance = None
    logger = None
    
    def __init__(self):
        if Jaime.instance:
            raise Exception("Can't call to constructor with another instance created")
        
        self.tabs_widget = QTabWidget()
        self.view = QWebView()
        self.page = QWebPage()
        self.config = SafeConfigParser()        
        Logger.getLoggerFor(self.__class__)
        
        self.tabs_widget.insertTab(0,self.view,'label')
        self.tabs = {}        
        
        self.graph_file = None
        
        self.close_tab_timer = QTimer()
        self.close_tab_timer.setSingleShot(False)
        #cada 30 segundos se cierra un tab
        self.close_tab_timer.setInterval(10000)
        self.view.setPage(self.page)
        self.tabs['mainTab'] = self.view
        
        self.network_manager = CustomNetworkAccessManager.getInstance()        
        self.navigator = Navigator.getInstance()
        self.route_node = YahooRouteNode.getInstance()
        self.graph_parser = GraphParser.getInstance()        
        self.page.setNetworkAccessManager(self.network_manager)
        
    def loadConfig(self,config_file):
        self.config.read(config_file)
    
    def loadParam(self,name,value):
        name = name.strip()
#         print 'get param [%s]' % name
        if not self.config.has_section('PARAMS'):
#             print 'cree la seccion'
            self.config.add_section('PARAMS')
            
        self.config.set('PARAMS',name.strip(),value)        
#         print 'seteo %s a %s ' %  (name,value)
    
    def getParam(self,name,default=None):
        
        name = name.strip()
#         print 'get param [%s]' % name
        if self.config.has_section('PARAMS') and \
                self.config.has_option('PARAMS',name):
#             print 'get param 1 %s' % name
            return self.config.get('PARAMS',name)
        if default != None:
            return default
        return None
    
    def toggleDelegationPolicy(self, delegate=None):
        if self.page.linkDelegationPolicy() == QWebPage.DontDelegateLinks or \
                ( isinstance(delegate,bool) and delegate ):
            self.logger.info('cambio a delegate links')            
            self.page.setLinkDelegationPolicy(QWebPage.DelegateAllLinks) 
        
        elif self.page.linkDelegationPolicy() == QWebPage.DelegateAllLinks or \
                ( isinstance(delegate,bool) and not delegate ):
            self.logger.info('cambio a dont delegate links')
            self.page.setLinkDelegationPolicy(QWebPage.DontDelegateLinks)
        
        else:
            self.logger.warn("Can't set delegation policy")

    def setGraph(self,filename):
        
        self.graph_file = filename
    
    def start(self):
        self.logger.info('---------------------------- Jaime start work ---------------------------------')                    
        self.logger.info('Graph file = %s' % self.graph_file)                    
        if self.config.has_section('PARAMS') :
            self.logger.info('[PARAMS]')                    
            for name,value in self.config.items('PARAMS'):
                self.logger.info('        %s = %s' % (name,value))
        
        self.page.setNetworkAccessManager(self.network_manager)
        self.page.loadFinished.connect(self.navigator.processPageLoadFinished)
        self.page.loadStarted.connect(self.navigator.processLoadStarted)
        self.page.linkClicked.connect(self.openLinkOnTab)
        
        self.close_tab_timer.timeout.connect(self.closeOpenTab)
        
        self.graph_parser.loadGraph(self.graph_file)
        
        if not self.navigator.takeEntryPoint():
            self.finishWork()           
            
        self.tabs_widget.show()
#         self.tabs_widget.showMaximized()
        
    def finishWork(self):
        self.logger.info('Jaime termina su funcionamiento')                    
        QApplication.closeAllWindows()
    
    def openLinkOnTab(self,link):        
        l = len(self.tabs)
        new_tab_key = 'newTab_%s' % time.time()
        self.tabs[new_tab_key] =  QWebView()
        self.tabs[new_tab_key].load(link)
        self.tabs_widget.insertTab(self.tabs_widget.count(),self.tabs[new_tab_key],new_tab_key)        
        if self.close_tab_timer.timerId() == -1  :
            self.logger.info('starteo el close_tab_timer')
            self.close_tab_timer.start()
        
    def closeOpenTab(self):
        if len(self.tabs) == 1  and self.close_tab_timer.timerId() != -1  :
            self.logger.info('stopeo el close_tab_timer')
            self.close_tab_timer.stop()
            return
        
        ks = self.tabs.keys()
        ks.remove('mainTab')
        ks.sort()
        last_key = ks[0]
        index = None
        for i in range(len(self.tabs)):
            if self.tabs_widget.tabText(i) == last_key:
                index = i
                break
        if index: 
            del self.tabs[last_key]
            self.tabs_widget.removeTab(index)
        else:
#             print 'stopeo el close_tab_timer'
            self.logger.error('no se encontro tab para remover con nombre %s' % last_key)
Exemplo n.º 39
0
class Macro_editor(QWidget):
    def __init__(self,parent=None,title='Macro editor'):
        # This class derivates from a Qt Widget so we have to call
        # the class builder ".__init__()"
        QWidget.__init__(self)
        # "self" is now a Qt Widget, then we instantiate the user interface
        # generated with QtDesigner and call it self.ui
        self.ui = Ui_Macro_editor()
        # Now we have to feed the GUI building method of this object (self.ui)
        # with a reference to the Qt Widget where it will appear, i.e. itself
        # but the elements of the GUI will actually be children of the GUI (i.e of self.ui not of self)
        self.ui.setupUi(self)
        self.setWindowTitle(title)
        
        # List the Macro command that will be loaded and available
        # into the Macro editor.
        # Once you have created a new Macro command class in this file
        # you must add it in this list for it to be available in 
        # the Macro editor.
        # You may also remove commands from this list if you want to deactivate them
        self.valid_list_of_commands=[
                                    AngleCommand(),
                                    CommentsCommand(),
                                    WaitCommand(),
                                    WaitForEpoch(),
                                    SetFieldCommand(),
                                    WaitForHStableCommand(),
                                    WaitForMeasureCommand(),
                                    SetPersistFieldCommand(),
                                    SetTempCommand(),
                                    SetHeaterCommand(),
                                    WaitForTStableCommand(),
                                    SetTempVTICommand(),
                                    SetVTIHeaterCommand(),
                                    SetSaveFileCommand(),
                                    StartMeasureCommand(),
                                    StopMeasureCommand(),
                                    EmailCommand(),
                                    EmailFileCommand(),
                                    EmailDirCommand(),
                                    SetICommand(),
                                    SetVCommand()]        
        
        ### Dirty FIX: the macro editor is in a layout and a group box which somehow
        ### put it way down the list of children, so we need the 6th order parent of that to get to the main !
        ##self.main=self.parent().parent().parent().parent().parent().parent()
        ### FIXED:the main class now simply gives a link to itself when it instantiates the Macro Editor
        ### this has the added benefit of keeping track of which class may use the main
        self.main=parent
        self.macro_isActive=False
        
        self.macro_timer = QTimer()
        #Use a single shot timer in between commands
        #otherwise it may fire again before the task is completed
        self.macro_timer.setSingleShot(True)
        self.macro_timer.timeout.connect(self.next_command)
               
        #initiate syntax highlighting for the macro editor
        self.highlighter = MacroHighlighter(self.ui.macro_textbox.document(),self.valid_list_of_commands)
        
        #update the list of available macro commands in the user interface
        model=QStandardItemModel()
        parentItem = model.invisibleRootItem()
        for command in self.valid_list_of_commands:
            parentItem.appendRow(QStandardItem(command.label))
        self.ui.macrocommandtree.setModel(model)
                 
    def save_macro(self):
        #the static method calls the native file system method
        fileName = QFileDialog.getSaveFileName(self,"Save Macro",dir= "./Macro",filter="Macro file (*.mac)")
        #open() does not work with 'unicode' type object, conversion is needed 
        fileName=fileName[0].encode('utf8')
        if fileName!="":
            #get the macro text from frontpanel text box
            mac_unicode=self.ui.macro_textbox.toPlainText()
            #print fileName
            #(u'C:/Python27/Lib/site-packages/pyqtgraph/examples/test.txt', u'All Files (*.*)')
            #WARNING: write() and open() do not work with 'unicode' type object
            #they have to be converted to a string first (i.e. a list of bytes)
            savefile=open(fileName,'w')
            savefile.write(mac_unicode.encode('utf8'))
            savefile.close()
                
    def open_macro(self):
        fileName = QFileDialog.getOpenFileName(self,"Open Macro",dir= "./Macro",filter="Macro file (*.mac)")
        #open() does not work with 'unicode' type object, conversion is needed 
        fileName=fileName[0].encode('utf8')
        if fileName!="":
            open_file=open(fileName,'r')
            self.ui.macro_textbox.setPlainText(unicode(open_file.read(-1),encoding='utf-8')) #'-1' to read the whole file at once
            open_file.close()

    def run_macro(self):
        if not(self.macro_isActive):
            self.macro_isActive=True
            self.current_macro=self.ui.macro_textbox.toPlainText().encode('utf8').split('\n')
            self.current_line=0
            self.cur_mac_max=len(self.current_macro)
            #single shot timer
            print "Starting Macro"
            self.macro_timer.start(0)
    
    def next_command(self):
        stdwtime=500
        if self.current_line<self.cur_mac_max:
            #update the info line with the line being analyzed
            action=self.current_macro[self.current_line]
            self.ui.mac_curr_line.setText("line "+str(self.current_line)+": "+action)
            
            next_move=1
            wait_time=500
            for command in self.valid_list_of_commands:
                #run the command, if command matches the line being analyzed
                if command.regexp.indexIn(action)!=-1:
                    command.run(self.main)
                    next_move=command.next_move
                    wait_time=command.wait_time
                    break #break the for loop
            #go to line N+next_move of the current macro, after wait_time milliseconds
            self.current_line+=next_move
            self.macro_timer.start(wait_time)
        else:
            #end of macro reached
            self.stop_macro()
            
    def stop_macro(self):
        self.macro_timer.stop()
        self.macro_isActive=False
        #TODO : signal/slot !!!
        if self.main.measurements_thread.isAlive(): 
            self.main.stop_measurements()
        print "End of Macro"
Exemplo n.º 40
0
class Quiz(QFrame):
     
    def __init__(self, options, parent=None):
        super(Quiz, self).__init__(parent)
        
        self.options = options
        
        """Session Info"""
        self.status = QFrame()
        #session message
        self.status.message = QLabel(u'')
        #achievements
        self.status.achievements = Achievements()
        self.status.info = QLabel(u'')
        self.status.progress = QProgressBar()
        self.status.layout = QVBoxLayout()
        #layout
        self.status.layout.addWidget(self.status.info)
        self.status.layout.addWidget(self.status.progress)
        self.status.layout.addWidget(self.status.message)
        self.status.setLayout(self.status.layout)
        #mouse event filter
        self.status.filter = StatusFilter(self.status)
        self.status.setAttribute(Qt.WA_Hover, True)
        self.status.installEventFilter(self.status.filter)

        """Items Info"""
        self.info = QFrame()
        self.info.reading = QLabel(u'')
        self.info.item = QLabel(u'')
        self.info.components = QLabel(u'')

        separator_one = QFrame()
        separator_one.setFrameShape(QFrame.HLine)
        separator_one.setFrameShadow(QFrame.Sunken)
        
        separator_two = QFrame()
        separator_two.setFrameShape(QFrame.HLine)
        separator_two.setFrameShadow(QFrame.Sunken)
        
        self.info.layout = QVBoxLayout()
        self.info.layout.addWidget(self.info.reading)
        self.info.layout.addWidget(separator_one)
        self.info.layout.addWidget(self.info.item)
        self.info.layout.addWidget(separator_two)
        self.info.layout.addWidget(self.info.components)
        self.info.setLayout(self.info.layout)
        
        """Verbose Info"""
        self.allInfo = QFrame()
        self.allInfo.layout = QGridLayout()
        self.allInfo.setLayout(self.allInfo.layout)
        #the rest is (should be) generated on the fly
        
        """Kanji info"""
        self.kanjiInfo = QFrame()
        self.kanjiInfo.layout = QVBoxLayout()
        self.kanjiInfo.info = QLabel(u'')
        self.kanjiInfo.layout.addWidget(self.kanjiInfo.info)
        self.kanjiInfo.setLayout(self.kanjiInfo.layout)
        
        """Kanji groups"""
        self.kanjiGroups = QFrame()
        self.kanjiGroups.layout = QVBoxLayout()
        self.kanjiGroups.info = QLabel(u'')
        self.kanjiGroups.layout.addWidget(self.kanjiGroups.info)
        self.kanjiGroups.setLayout(self.kanjiGroups.layout)
        
        """Global Flags"""
        #self.correct = False
        
        """Quiz Dialog"""
        self.filter = Filter()
        ####    visual components    ###
        self.countdown = QProgressBar()
        self.sentence = QLabel(u'')
        
        self.var_1st = QPushButton(u'')
        self.var_2nd = QPushButton(u'')
        self.var_3rd = QPushButton(u'')
        self.var_4th = QPushButton(u'')

        self.answered = QPushButton(u'')
        self.answered.hide()
                
        ###    layouts    ####
        self.layout_vertical = QVBoxLayout()        #main
        self.layout_horizontal = QHBoxLayout()      #buttons
        
        self.layout_horizontal.addWidget(self.var_1st)
        self.layout_horizontal.addWidget(self.var_2nd)
        self.layout_horizontal.addWidget(self.var_3rd)
        self.layout_horizontal.addWidget(self.var_4th)
        
        self.layout_vertical.addWidget(self.countdown)
        self.layout_vertical.addWidget(self.sentence)
        self.layout_vertical.addLayout(self.layout_horizontal)
        
        self.layout_horizontal.addWidget(self.answered)

        self.setLayout(self.layout_vertical)

        ###    utility components    ###
        self.trayIcon = QSystemTrayIcon(self)
        self.trayMenu = QMenu()
        
        self.gifLoading = QMovie('../res/cube.gif')
        self.gifLoading.frameChanged.connect(self.updateTrayIcon)
        
        ### initializing ###
        self.initializeResources()
        
        ### timers ###
        self.nextQuizTimer = QTimer()
        self.nextQuizTimer.setSingleShot(True)
        self.nextQuizTimer.timeout.connect(self.showQuiz)
        
        self.countdownTimer = QTimer()
        self.countdownTimer.setSingleShot(True)
        self.countdownTimer.timeout.connect(self.timeIsOut)
        
        self.trayUpdater = None
        #self.trayUpdater = RepeatTimer(1.0, self.updateTrayTooltip, self.options.getRepetitionInterval() * 60)
        self.remaining = 0
        
        """Start!"""
        if self.options.isQuizStartingAtLaunch():
            self.waitUntilNextTimeslot()
            self.trayIcon.setToolTip('Quiz has started automatically!')
            self.pauseAction.setText('&Pause')
            self.trayIcon.showMessage('Loading complete! (took ~'+ str(self.loadingTime.seconds) + ' seconds) Quiz underway.', 
                                      'Lo! Quiz already in progress!'  + self.loadingStatus, QSystemTrayIcon.MessageIcon.Warning, 10000)
        else:
            self.trayIcon.setToolTip('Quiz is not initiated!')
            self.trayIcon.showMessage('Loading complete! (took ~' + str(self.loadingTime.seconds) + ' seconds) Standing by.', 
                                      'Quiz has not started yet! If you wish, you could start it manually or enable autostart by default.'  + self.loadingStatus, 
                                      QSystemTrayIcon.MessageIcon.Information, 10000 )
            
        self.setWindowIcon(QIcon(PATH_TO_RES + ICONS + 'suzu.png'))
        """Test calls here:"""
        ###    ...    ###
        #self.connect(self.hooker, SIGNAL('noQdict'), self.noQdict)
        self.gem = self.saveGeometry()
        
    def startUpdatingTrayTooltip(self):
        self.remaining = self.nextQuizTimer.interval()
        
        if self.trayUpdater is not None and self.trayUpdater.isAlive():
            self.trayUpdater.cancel()
            
        self.trayUpdater = RepeatTimer(1.0, self.updateTrayTooltip, self.options.getRepetitionInterval() * 60)
        self.trayUpdater.start()
        
    def updateTrayTooltip(self):
        self.remaining -= UPDATE_FREQ
        self.trayIcon.setToolTip('Next quiz in ' + (str(self.remaining/UPDATE_FREQ) + ' seconds'))

#    def noQdict(self):
#        self.showSessionMessage('Nope, cannot show quick dictionary during actual quiz.')
        
####################################
#    Initialization procedures     #
####################################

    def initializeResources(self):
        
        """Initialize Options"""
#        self.options = Options()
        self.loadingStatus = u''
        
        self.qload = QuickLoad(self.options)
        if self.options.isLoadingOnStart():
            self.qload.exec_()
        
        """Pre-initialization"""
        self.animationTimer = ()
        self.progressTimer = ()
        self.grid_layout =()
        
        """Initialize Statistics"""
        self.stats = Stats()
        
        """Config Here"""
        self.initializeComposition()
        self.initializeComponents()
        self.setMenus()
        self.trayIcon.show()
        #self.startTrayLoading()
        
        """"Initialize Dictionaries    (will take a some time!)"""
        time_start = datetime.now()
        
        self.trayIcon.showMessage('Loading...', 'Initializing dictionaries', QSystemTrayIcon.MessageIcon.Information, 20000 )
        # kanji composition #
        if self.options.isLoadingRadk(): self.rdk = RadkDict()
        else: self.loadingStatus += '--> Radikt disabled!\n'
        # edict dictionary
        if self.options.isLoadingEdict():
            edict_file = resource_filename('cjktools_data', 'dict/je_edict')
            self.edict = auto_format.load_dictionary(edict_file)
        else: 
            self.edict = None
            self.loadingStatus += '--> Edict disabled!\n'
        # kanjidict dictionary #
        if self.options.isLoadingKdict(): self.kjd = kanjidic.Kanjidic()
        else: 
            self.kjd = None
            self.loadingStatus += '--> Kanjidict disabled!\n'
        # Kanji.Odyssey groups #
        self.groups = KanjiGrouper()
        if self.options.isLoadingGroups(): self.groups.loadgroupsFromDump()
        else: self.loadingStatus += '--> Kanji.Odyssey disabled!\n'
        
        """Initializing srs system"""
        self.trayIcon.showMessage('Loading...', 'Initializing databases', QSystemTrayIcon.MessageIcon.Information, 20000 )
        self.srs = srsScheduler()
        if self.options.isLoadingDb(): self.srs.initializeCurrentSession(self.options.getQuizMode(), self.options.getSessionSize())
        else: self.loadingStatus += '--> Database disabled!\n'
        
        """Jmdict lookup"""
        self.jmdict = DictionaryLookup()
        if self.options.isLoadingJmdict(): 
            self.jmdict.loadJmdictFromDumpRegex()
            self.jmdict.joinTables()
        else: self.loadingStatus += '--> Jmdict disabled!\n'
                
        """Manual add dialog"""
        self.manualAddDialog = ManualAdd(self.srs.db)
        
        if self.loadingStatus != '': self.loadingStatus = '\n\n' + self.loadingStatus
        
        time_end = datetime.now()
        self.loadingTime =  time_end - time_start

####################################
#    Composition and appearance    #
####################################

    def initializeComposition(self):
        
        """Main Dialog"""
        self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
        self.setFocusPolicy(Qt.StrongFocus)
        self.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
        #NB: This font will be used in buttons
        self.setFont(QFont(Fonts.TukusiMyoutyouProLB, self.options.getQuizFontSize()))

        desktop = QApplication.desktop().screenGeometry()
        self.setGeometry(QRect(desktop.width() - H_INDENT, desktop.height() - V_INDENT, D_WIDTH, D_HEIGHT))
        
        self.setStyleSheet("QWidget { background-color: rgb(252, 252, 252); }")
        
        """Info dialog"""
        self.info.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
        self.info.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
        self.info.setGeometry(QRect(desktop.width() - H_INDENT - I_WIDTH - I_INDENT, desktop.height() - V_INDENT, I_WIDTH, I_HEIGHT))
        
        self.info.setStyleSheet("QWidget { background-color: rgb(252, 252, 252); }")
        
        """Verbose info dialog"""
        self.allInfo.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
        self.allInfo.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
        self.allInfo.setGeometry(QRect(desktop.width() - H_INDENT - I_WIDTH - I_INDENT, desktop.height() - V_INDENT, I_WIDTH, I_HEIGHT))
        
        self.allInfo.setStyleSheet("QWidget { background-color: rgb(252, 252, 252); }")
        
        """Session message"""
        self.status.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
        self.status.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
        self.status.setGeometry(QRect(desktop.width() - H_INDENT, desktop.height() - V_INDENT - S_HEIGHT - S_INDENT - S_CORRECTION, S_WIDTH, S_HEIGHT))
        self.status.setMinimumSize(S_WIDTH, S_HEIGHT)
#        self.status.setMinimumWidth(S_WIDTH)
        
        self.status.setStyleSheet("QWidget { background-color: rgb(252, 252, 252); }")
        
        self.setMask(roundCorners(self.rect(),5))
#        self.status.setMask(roundCorners(self.status.rect(),5))
        #self.info.setMask(roundCorners(self.info.rect(),5))
        #self.allInfo.setMask(roundCorners(self.allInfo.rect(),5))
        
        """Kanji info"""
        self.kanjiInfo.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
        self.kanjiInfo.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
        self.kanjiInfo.setGeometry(QRect(desktop.width() - H_INDENT - K_WIDTH - K_INDENT, desktop.height() - V_INDENT, K_WIDTH, K_HEIGHT))
        
        self.kanjiInfo.setStyleSheet("QWidget { background-color: rgb(252, 252, 252); }")
        
        """Kanji groups"""
        self.kanjiGroups.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
        self.kanjiGroups.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
        self.kanjiGroups.setGeometry(QRect(desktop.width() - H_INDENT - G_WIDTH - G_INDENT, desktop.height() - V_INDENT, G_WIDTH, G_HEIGHT))
        
        self.kanjiGroups.setStyleSheet("QWidget { background-color: rgb(250, 250, 250); }")
        
#        self.setMask(roundCorners(self.rect(),5))
#        self.status.setMask(roundCorners(self.status.rect(),5))

    def initializeComponents(self):
        self.countdown.setMaximumHeight(6)
        self.countdown.setRange(0, self.options.getCountdownInterval() * 100)
        self.countdown.setTextVisible(False)
        self.countdown.setStyleSheet("QProgressbar { background-color: rgb(255, 255, 255); }")
        
        #self.setFont(QFont(Fonts.SyoutyouProEl, 40))#self.options.getQuizFontSize()))
        
        self.sentence.setAlignment(Qt.AlignmentFlag.AlignCenter)
        #self.sentence.setFont(QFont(Fonts.HiragiNoMarugotoProW4, self.options.getSentenceFontSize()))
        self.sentence.setFont(QFont(self.options.getSentenceFont(), self.options.getSentenceFontSize()))
        
        self.sentence.setWordWrap(True)
        self.trayIcon.setIcon(QIcon(PATH_TO_RES + TRAY + 'active.png'))
        
        self.status.message.setFont(QFont('Cambria', self.options.getMessageFontSize()))
        self.status.layout.setAlignment(Qt.AlignCenter)
        self.status.message.setWordWrap(False)
        self.status.message.setAlignment(Qt.AlignCenter)
        self.status.layout.setMargin(0)
        
        self.status.info.setHidden(True)
        self.status.progress.setHidden(True)
        self.status.progress.setMaximumHeight(10)
        self.status.progress.setRange(0, self.status.achievements.threshold)
        self.status.layout.setAlignment(Qt.AlignCenter)
        self.status.info.setAlignment(Qt.AlignCenter)
        self.status.info.setFont(QFont(Fonts.RyuminPr5, 13))
        self.status.info.setWordWrap(False)
        
        self.status.gem = self.status.saveGeometry()
        
        self.info.item.setFont(QFont(Fonts.HiragiNoMyoutyouProW3, 36))
        self.info.reading.setFont(QFont(Fonts.HiragiNoMyoutyouProW3, 16))
        self.info.components.setFont((QFont(Fonts.HiragiNoMyoutyouProW3, 14)))
        #self.info.item.setWordWrap(True)
        self.info.components.setWordWrap(True)
        #self.info.layout.setAlignment(Qt.AlignCenter)
        self.info.layout.setMargin(0)
        #self.info.layout.setSizeConstraint(self.info.layout.SetFixedSize)       #NB: would work nice, if the anchor point was in right corner
        
        self.info.reading.setAlignment(Qt.AlignCenter)
        self.info.item.setAlignment(Qt.AlignCenter)
        self.info.components.setAlignment(Qt.AlignCenter)
        
        #self.info.setLayoutDirection(Qt.RightToLeft)
        
        self.info.reading.setStyleSheet("QLabel { color: rgb(155, 155, 155); }")
        self.info.components.setStyleSheet("QLabel { color: rgb(100, 100, 100); }")
        
        self.kanjiInfo.info.setFont(QFont(Fonts.MSMyoutyou, 14.5))
        self.kanjiInfo.info.setAlignment(Qt.AlignCenter)
        self.kanjiInfo.info.setWordWrap(True)
        self.kanjiInfo.layout.setMargin(0)
        
        self.kanjiGroups.info.setFont(QFont(Fonts.MSMyoutyou, 18.5))
        self.kanjiGroups.info.setAlignment(Qt.AlignCenter)
        self.kanjiGroups.info.setWordWrap(True)
        self.kanjiGroups.layout.setMargin(0)
        
        #NB: ...
        self.answered.setMaximumWidth(D_WIDTH)
        self.answered.setFont(QFont('Calibri', 11))


####################################
#        Updating content          #
####################################        
    def updateContent(self):
        
        """Resetting multi-label sentence"""
        if self.grid_layout != ():
            for i in range(0, self.grid_layout.count()):
                    self.grid_layout.itemAt(i).widget().hide()
            self.layout_vertical.removeItem(self.grid_layout)
            self.grid_layout.setParent(None)
            self.update()
        if self.sentence.isHidden():    
            self.sentence.show()
        self.showButtonsQuiz()
        
        """Getting actual content"""
        self.srs.getNextItem()
              
        example = self.srs.getCurrentExample()
        
        # checking for no example case
        if example is None:
            self.manualAddDialog.setProblemKanji(self.srs.getCurrentItemKanji())
            done = self.manualAddDialog.exec_()
            
            if done == 0:
                self.updateContent()
            elif done == 1:
                self.updateContent()
            else:
                pass
        else:
            example = example.replace(self.srs.getWordFromExample(), u"<font color='blue'>" + self.srs.getWordFromExample() + u"</font>")
            
            # checking sentence length
            if len(self.srs.currentExample.sentence) > SENTENCE_MAX: self.sentence.setFont(QFont(self.options.getSentenceFont(), MIN_FONT_SIZE))
            else: self.sentence.setFont(QFont(self.options.getSentenceFont(), self.options.getSentenceFontSize()))
            
            #temporary debug info:
#            print len(example), self.sentence.font()
            
            self.sentence.setText(example)
            
            readings = self.srs.getQuizVariants()

            changeFont = False
            for item in readings:
                if len(item) > BUTTON_KANA_MAX : changeFont = True
                
            try:
                for i in range(0, self.layout_horizontal.count()):
                        if i > 3: break
                        self.layout_horizontal.itemAt(i).widget().setText(u'')
                        
                        if changeFont:
                            self.layout_horizontal.itemAt(i).widget().setStyleSheet('QPushButton { font-family: ' + self.options.getQuizFont() + '; font-size: 11pt; }')
                        else:
                            self.layout_horizontal.itemAt(i).widget().setStyleSheet('QPushButton { font-family: ' + self.options.getQuizFont() + '; font-size: %spt; }' % self.options.getQuizFontSize())
                            
                        self.layout_horizontal.itemAt(i).widget().setText(readings[i])
            except:
                log.debug(u'Not enough quiz variants for ' + self.srs.getCurrentItem())
        
    def getReadyPostLayout(self):
        self.sentence.hide()
        self.update()
        
        self.grid_layout = QGridLayout()
        self.grid_layout.setSpacing(0)
        self.labels = []
        
        columns_mod = 0
        #font size depending on sentence length
        if len(self.srs.currentExample.sentence) > SENTENCE_MAX: font =  QFont(self.options.getSentenceFont(), MIN_FONT_SIZE); columns_mod = 6
        else: font = QFont(self.options.getSentenceFont(), self.options.getSentenceFontSize())
        
        #row, column, rows span, columns span, max columns
        i = 0; j = 0; r = 1; c = 1; n = COLUMNS_MAX + columns_mod
        for word in self.srs.parseCurrentExample():
            label = QLabel(word)
            label.setFont(font)
            
            label.setAttribute(Qt.WA_Hover, True)
            label.installEventFilter(self.filter)
            self.labels.append(label)
            
            if len(label.text()) > 1: c = len(label.text())
            else: c = 1
            #Don't ask, really
            if j + c > n: i = i + 1; j = 0
            
            self.grid_layout.addWidget(self.labels.pop(), i, j, r, c)       #NB: Ehh, pop should remove label from list, shouldn't it?
            
            if j <= n: j = j + c
            else: j = 0; i = i + 1
        
        self.grid_layout.setAlignment(Qt.AlignCenter)
        self.layout_vertical.insertLayout(1, self.grid_layout)

        self.update()
        
    def hideButtonsQuiz(self):
        self.var_1st.hide()
        self.var_2nd.hide()
        self.var_3rd.hide()
        self.var_4th.hide()
        
        self.answered.clicked.connect(self.hideQuizAndWaitForNext)
        self.answered.show()
        
    def showButtonsQuiz(self):
        self.var_1st.show()
        self.var_2nd.show()
        self.var_3rd.show()
        self.var_4th.show()
        
        self.answered.hide()
        self.answered.disconnect()
        
####################################
#        Timers and animations     #
####################################

    def waitUntilNextTimeslot(self):
        #if self.nextQuizTimer.isActive():   self.nextQuizTimer.stop()
        self.nextQuizTimer.start(self.options.getRepetitionInterval() * 60 * 1000)  #options are in minutes    NB: how do neatly I convert minutes to ms?
        self.startUpdatingTrayTooltip()
        
    def beginCountdown(self):
        self.trayIcon.setToolTip('Quiz in progress!')
        self.pauseAction.setText('&Pause')
#        self.pauseAction.setShortcut('P')
        
        self.countdownTimer.start(self.options.getCountdownInterval() * 1000)

        self.progressTimer = RepeatTimer(0.01, self.updateCountdownBar, self.options.getCountdownInterval() * 100)
        self.progressTimer.start()
        
    def updateCountdownBar(self):
        self.countdown.setValue(self.countdown.value() - 1)
        #print self.countdown.value()
        self.countdown.update()         #NB: without .update() recursive repaint crushes qt

    def fade(self):
        if self.windowOpacity() == 1:
            self.animationTimer = RepeatTimer(0.025, self.fadeOut, 40)
            self.animationTimer.start()
        else:
            self.animationTimer = RepeatTimer(0.025, self.fadeIn, 40)
            self.animationTimer.start()
    
    def fadeIn(self):
        self.setWindowOpacity(self.windowOpacity() + 0.1)
        
    def fadeOut(self):
        self.setWindowOpacity(self.windowOpacity() - 0.1)
        
    def stopCountdown(self):
        self.progressTimer.cancel()
        self.countdownTimer.stop()
        self.countdown.setValue(0)
        
####################################
#        Actions and events        #
####################################    
    
    def setMenus(self):
        
        self.showQuizAction = QAction('&Quiz me now!', self, triggered=self.showQuiz)
        self.showQuizAction.setIcon(QIcon(PATH_TO_RES + TRAY + NOW_ICON))
        self.trayMenu.addAction(self.showQuizAction)
        
        self.pauseAction = QAction('&Start quiz!', self, triggered=self.pauseQuiz)
        self.pauseAction.setIcon(QIcon(PATH_TO_RES + TRAY + START_ICON))
        self.trayMenu.addAction(self.pauseAction)
        
        self.trayMenu.addSeparator()
        
        self.quickDictAction = QAction('Quick &dictionary', self, triggered=self.showQuickDict)
        self.quickDictAction.setIcon(QIcon(PATH_TO_RES + TRAY + DICT_ICON))
        self.trayMenu.addAction(self.quickDictAction)
        
        self.optionsAction = QAction('&Options', self, triggered=self.showOptions)
        self.optionsAction.setIcon(QIcon(PATH_TO_RES + TRAY + OPTIONS_ICON))
        self.trayMenu.addAction(self.optionsAction)
        
        self.quickLoadAction = QAction('Quick &load', self, triggered=self.showQuickLoad)
        self.quickLoadAction.setIcon(QIcon(PATH_TO_RES + TRAY + LOAD_ICON))
        self.trayMenu.addAction(self.quickLoadAction)
        
        self.trayMenu.addSeparator()
        
        self.aboutAction = QAction('&About', self, triggered=self.showAbout)
        self.aboutAction.setIcon(QIcon(PATH_TO_RES + TRAY + ABOUT_ICON))
        self.trayMenu.addAction(self.aboutAction)
        
        self.globalStatsAction = QAction('&Global statistics', self, triggered=self.showGlobalStatistics)
        self.globalStatsAction.setIcon(QIcon(PATH_TO_RES + TRAY + STAT_ICON))
        self.trayMenu.addAction(self.globalStatsAction)
        
        self.utilAction = QAction('U&tilities', self, triggered=self.showToolsDialog)
        self.utilAction.setIcon(QIcon(PATH_TO_RES + TRAY + UTILS_ICON))
        self.trayMenu.addAction(self.utilAction)
        
        self.trayMenu.addSeparator()
        
        self.quitAction = QAction('&Exit', self, triggered=self.saveAndExit)
        self.quitAction.setIcon(QIcon(PATH_TO_RES + TRAY + CLOSE_ICON))
        self.trayMenu.addAction(self.quitAction)
        

        self.trayIcon.setContextMenu(self.trayMenu)
        self.trayIcon.activated.connect(self.onTrayIconActivated)

    def onTrayIconActivated(self, reason):
        '''
        if reason == QSystemTrayIcon.DoubleClick:
            print 'tray icon double clicked'
        '''
        if reason == QSystemTrayIcon.Trigger:
            if self.isHidden():
                self.trayIcon.showMessage('Current session statistics:', 'Running time:\t\t' + self.stats.getRunningTime() + 
                                          '\nItems seen:\t\t' + str(self.stats.totalItemSeen) + 
                                          '\nCorrect answers:\t\t' + str(self.stats.answeredCorrect) +
                                          '\nWrong answers:\t\t' + self.stats.getIncorrectAnswersCount() +
                                          '\nCorrect ratio:\t\t' + self.stats.getCorrectRatioPercent() +
                                          #'\nQuiz total time:\t\t' + self.stats.getQuizActive() +
                                          '\nQuiz paused time:\t\t' + self.stats.getPausedTime() +
                                          '\nTotal pondering time:\t' + self.stats.getMusingsTime() +
                                          '\nTotal post-quiz time:\t' + self.stats.getQuizTime() +
                                          '\nAverage pondering:\t' + self.stats.getAverageMusingTime() +
                                          '\nAverage post-quiz:\t' + self.stats.getAveragePostQuizTime(), 
                                          QSystemTrayIcon.MessageIcon.Information, 20000)
    
    def setButtonsActions(self):

        if self.var_1st.text() == self.srs.getCorrectAnswer():
                self.var_1st.clicked.connect(self.correctAnswer)
        else:
                self.var_1st.clicked.connect(self.wrongAnswer)
               
        if self.var_2nd.text() == self.srs.getCorrectAnswer():
                self.var_2nd.clicked.connect(self.correctAnswer)
        else:
                self.var_2nd.clicked.connect(self.wrongAnswer)
                
        if self.var_3rd.text() == self.srs.getCorrectAnswer():
                self.var_3rd.clicked.connect(self.correctAnswer)
        else:
                self.var_3rd.clicked.connect(self.wrongAnswer)
                
        if self.var_4th.text() == self.srs.getCorrectAnswer():
                self.var_4th.clicked.connect(self.correctAnswer)
        else:
                self.var_4th.clicked.connect(self.wrongAnswer)
                
        self.var_1st.setShortcut('1')
        self.var_2nd.setShortcut('2')
        self.var_3rd.setShortcut('3')
        self.var_4th.setShortcut('4')
                
    def resetButtonsActions(self):
        self.var_1st.disconnect()
        self.var_2nd.disconnect()
        self.var_3rd.disconnect()
        self.var_4th.disconnect()
        
    def postAnswerActions(self):
        self.stats.musingsStopped()
        self.stats.postQuizStarted()
        
        self.stopCountdown()
        self.hideButtonsQuiz()
        
        self.getReadyPostLayout()
        
    def refocusQuiz(self):
        self.answered.setShortcut('Space')
        self.activateWindow()
        self.answered.setFocus()
        
    def correctAnswer(self):
        self.postAnswerActions()
        
        self.srs.answeredCorrect()
        self.stats.quizAnsweredCorrect()
        
        self.checkTranslationSize(self.srs.getCurrentSentenceTranslation())

        self.status.achievements.correctAnswer()
        self.showSessionMessage(u'<font color=green>Correct: ' + self.srs.getCorrectAnswer() + '</font>\t|\tNext quiz: ' + self.srs.getNextQuizTime() 
                                + '\t|\t<font color=' + self.srs.getLeitnerGradeAndColor()['color'] +  '>Grade: ' + self.srs.getLeitnerGradeAndColor()['grade'] 
                                + ' (' + self.srs.getLeitnerGradeAndColor()['name'] + ')<font>')
        self.refocusQuiz()
        
    def wrongAnswer(self):
        self.postAnswerActions()
        
        self.srs.answeredWrong()
        self.stats.quizAnsweredWrong()
        
        self.checkTranslationSize(self.srs.getCurrentSentenceTranslation())
        
        self.status.achievements.wrongAnswer()
        self.showSessionMessage(u'<font color=tomato>Wrong! Should be: '+ self.srs.getCorrectAnswer() + '</font>\t|\tNext quiz: ' + self.srs.getNextQuizTime()
                                + '\t|\t<font color=' + self.srs.getLeitnerGradeAndColor()['color'] +  '>Grade: ' + self.srs.getLeitnerGradeAndColor()['grade'] 
                                + ' (' + self.srs.getLeitnerGradeAndColor()['name'] + ')<font>')
        self.refocusQuiz()
            
    def timeIsOut(self):
        self.stats.musingsStopped()
        self.stats.postQuizStarted()
        
        QTimer.singleShot(50, self.hideButtonsQuiz)     #NB: slight artificial lag to prevent recursive repaint crush (when mouse is suddenly over repainted button)
        self.getReadyPostLayout()
        
        self.srs.answeredWrong()
        self.stats.quizAnsweredWrong()

        self.checkTranslationSize(self.srs.getCurrentSentenceTranslation())
        
        self.status.achievements.wrongAnswer()
        self.showSessionMessage(u'<font color=tomato>Timeout! Should be: ' + self.srs.getCorrectAnswer() + '</font>\t|\tNext quiz: ' + self.srs.getNextQuizTime()
                                + '\t|\t<font color=' + self.srs.getLeitnerGradeAndColor()['color'] +  '>Grade: ' + self.srs.getLeitnerGradeAndColor()['grade'] 
                                + ' (' + self.srs.getLeitnerGradeAndColor()['name'] + ')<font>')    
        self.refocusQuiz()
        
    def checkTranslationSize(self, translation):
        if len(translation) > TRANSLATION_CHARS_LIMIT:
            self.answered.setStyleSheet('QPushButton { font-size: 9pt; }')
            
            space_indices = [i for i, value in enumerate(translation) if value == ' ']
            find_nearest_index = lambda value,list : min(list, key = lambda x:abs(x - value))
            nearest_index = find_nearest_index(TRANSLATION_CHARS_LIMIT, space_indices)
            translation = translation[:nearest_index] + '\n' + translation[nearest_index + 1:]
        else:
            self.answered.setStyleSheet('QPushButton { font-size: 11pt; }')
        
        self.answered.setText(translation)
    
    def hideQuizAndWaitForNext(self):
        self.stats.postQuizEnded()
        
        self.status.hide()
        self.info.hide()
        self.allInfo.hide()
        self.resetButtonsActions()
        
        self.setWindowOpacity(1)
        self.fade()
        QTimer.singleShot(1000, self.hide)
        self.waitUntilNextTimeslot()
        self.updater.mayUpdate = True
 
    def pauseQuiz(self):
        if self.isHidden():
            if self.pauseAction.text() == '&Pause':
                self.nextQuizTimer.stop()
                self.pauseAction.setText('&Unpause')
#                self.pauseAction.setShortcut('U')
                self.trayIcon.setToolTip('Quiz paused!')
                
                self.trayIcon.setIcon(QIcon(PATH_TO_RES + TRAY + 'inactive.png'))
                self.trayUpdater.cancel()
                self.pauseAction.setIcon(QIcon(PATH_TO_RES + TRAY + START_ICON))
                self.stats.pauseStarted()
                
                self.updater.mayUpdate = True
                
            elif self.pauseAction.text() == '&Start quiz!':
                self.waitUntilNextTimeslot()
                self.pauseAction.setText('&Pause')
#                self.pauseAction.setShortcut('P')
                self.trayIcon.setToolTip('Quiz in progress!')
                
                self.trayIcon.setIcon(QIcon(PATH_TO_RES + TRAY + 'active.png'))
                self.pauseAction.setIcon(QIcon(PATH_TO_RES + TRAY + PAUSE_ICON))
            else:
                self.waitUntilNextTimeslot()
                self.pauseAction.setText('&Pause')
#                self.pauseAction.setShortcut('P')
                self.trayIcon.setToolTip('Quiz in progress!')
                
                self.trayIcon.setIcon(QIcon(PATH_TO_RES + TRAY + 'active.png'))
                self.pauseAction.setIcon(QIcon(PATH_TO_RES + TRAY + PAUSE_ICON))
                self.stats.pauseEnded()
                
                self.updater.mayUpdate = False
        else:
            self.showSessionMessage(u'Sorry, cannot pause while quiz in progress!')
 
    def showQuiz(self):
        if self.isHidden():
            self.updateContent()
            self.setButtonsActions()
            
            #self.restoreGeometry(self.gem)
            self.trayIcon.setIcon(QIcon(PATH_TO_RES + TRAY + 'active.png'))
            
            self.show()
            self.setWindowOpacity(0)
            self.fade()

            self.countdown.setValue(self.options.getCountdownInterval() * 100)
            self.beginCountdown()
            self.stats.musingsStarted()
            
            if self.nextQuizTimer.isActive():   self.nextQuizTimer.stop()
            self.updater.mayUpdate = False
        else:
            self.showSessionMessage(u'Quiz is already underway!')
         
    def showOptions(self):
        self.optionsDialog.show()
        
    def showAbout(self):
        self.about.show()
        
    def showQuickDict(self):
        self.qdict.showQDict = True
        
    def showGlobalStatistics(self):
        self.statistics.show()
        
    def showToolsDialog(self):
        self.tools.show()
        
    def showQuickLoad(self):
        self.qload.show()
        
    def startTrayLoading(self):
        self.gifLoading.start()
        #self.iconTimer = QTimer()
        #self.iconTimer.timeout.connect(self.updateTrayIcon)
        #self.iconTimer.start(100)
        
    def stopTrayLoading(self):
        self.gifLoading.stop()
        
    def updateTrayIcon(self):
        self.trayIcon.setIcon(self.gifLoading.currentPixmap())
        
    def showSessionMessage(self, message):
        """Shows info message"""
        self.status.message.setText(message)
        if self.status.achievements.achieved is not None:
            self.status.info.setText(self.status.achievements.achieved[1] + '\t( ' + self.status.achievements.achieved[0] + ' )')
            self.status.progress.hide()
            self.status.move(self.status.x(), self.status.y() - 15)
            self.status.info.show()
#            self.status.setMask(roundCorners(self.status.rect(),5))
        else:
            self.status.info.setText(u'')
            self.status.info.hide()
            self.status.restoreGeometry(self.status.gem)
#            self.status.setMask(roundCorners(self.status.rect(),5))
#        print self.status.y()
        self.status.adjustSize()
        self.status.show()
 
    def saveAndExit(self):
        self.hide()
        self.status.hide()
        self.allInfo.hide()
        self.kanjiInfo.hide()
        
        self.trayIcon.showMessage('Shutting down...', 'Saving session', QSystemTrayIcon.MessageIcon.Information, 20000 )
        
        if self.countdownTimer.isActive():
                self.countdownTimer.stop()
        if self.nextQuizTimer.isActive():
                self.nextQuizTimer.stop()
        if self.progressTimer != () and self.progressTimer.isAlive():
                self.progressTimer.cancel()
        if self.trayUpdater is not None and self.trayUpdater.isAlive() :
                self.trayUpdater.cancel()    
            
        self.rehash.checkSessionResults()
        
        self.srs.endCurrentSession(self.stats)
        self.trayIcon.hide()

        self.hooker.stop()

        self.updater.stop()
        self.optionsDialog.close()
        self.about.close()
        self.qdict.close()
        self.close()        
        
    def addReferences(self, about, options, qdict, updater, tools, statistics, web, rehash):
        self.about = about
        self.optionsDialog = options
        self.qdict = qdict
        self.updater = updater
        self.tools = tools
        self.statistics = statistics
        self.status.web = web
        self.rehash = rehash
        
    def initGlobalHotkeys(self):
        def toggleWidgetFlag(): self.qdict.showQDict = True
        self.hooker = GlobalHotkeyManager(toggleWidgetFlag , 'Q')
        self.hooker.setDaemon(True)
        self.hooker.start()
        
    def showEvent(self, event):
        self.restoreGeometry(self.gem)
Exemplo n.º 41
0
class InfoBar(object):
  """Adds a info bar to the bottom of the main window"""

  # Should be stored and restored from uistate.ini
  infoSettings = {"showCPU": True,
                 "showMemory": True,
                 "showDisk": True,
                 "showNetwork": True
                 }
  
  def __init__(self):

    global gEnableResourceMonitoring
    self.enableResourceMonitoring  = gEnableResourceMonitoring
    self.bar = hiero.ui.mainWindow().statusBar()

    self.updateMonitorIntervalMS = gUpdateIntervalMS # The monitor update time in milliseconds.
    self.timer = QTimer()
    self.timer.setSingleShot(False)
    self.timer.timeout.connect(self.updateStatusBar)

    self.currentDiskIOBytes = psutil.disk_io_counters().read_bytes
    self.currentNetworkBytesReceived = psutil.net_io_counters().bytes_recv

    # This observes the current pid (the App process id) via psutil, and reports back
    if self.enableResourceMonitoring:
      self.processHelper = PSUtilProcessWrapper()

    # The frameServer instance
    self.frameServerInstance = nukestudio.frameServer

    # Initialise the Status Bar
    self.setupUI()

    # We haven't started monitoring at this point
    self.isMonitoring = False

    # Begin monitoring after a few secs to give frame server time to start up properly
    QTimer.singleShot(gInitialDelayMS, self.startMonitoring)

  def getLatestStyleSheet(self):
    styleFile = os.path.join( cwd, "style.stylesheet")
    with open(styleFile, "r") as fh:
      return fh.read()

  def hide(self):
    """Hide the info bar"""
    self.bar.setHidden(True)

  def show(self):
    """Show the info bar"""  
    self.bar.setHidden(False)
    
  def rendersExistInQueue(self):
    """Return whether renders exist in the Frame server queue"""
    return len(self.frameServerInstance.renderQueue.requestsInProgress) > 0

  def _handleServerUnreachable(self):
    """This is called when the server becomes unreachable"""
    print "[WARNING]: Nuke Frame Server was not reachable."
    self.frameserverStatusLabel.setPixmap(QPixmap("icons:Offline.png"));
    self.restartServerButton.setHidden(False)  

  def _setResourcesLabelColour(self, memRatio, cpuUsage):

    """Sets the Resources label to be red if the memory usage gets too high"""
    if memRatio > 0.9:
      color  = QColor( Qt.red )
      alpha  = 220
      values = "{r}, {g}, {b}, {a}".format(r = color.red(),
                                           g = color.green(),
                                           b = color.blue(),
                                           a = alpha
                                           )
      #self.nukeResourcesLabel.setStyleSheet("QLabel { vertical-align: middle; font: 10pt; color: rgba("+values+"); }")
    else:
      #self.nukeResourcesLabel.setStyleSheet("QLabel { vertical-align: middle; font: 10pt; }")
      return


  def restartServerAsync(self):
    self.frameServerInstance.stop()
    self.frameServerInstance.start()
    QTimer.singleShot(3000, self.startMonitoring)

  def restartServer(self):
    """Called to restart the Nuke Frame Server, done asynchronously"""
    self.stopMonitoring()
    self.restartServerButton.setHidden(True)
    #self.nukeResourcesLabel.setText("Re-Starting Frame Server...")
    QTimer.singleShot(150, self.restartServerAsync)

  # Displays the resources label, based on settings.
  def buildResourcesLabel(self):
    if self.isMonitoring:
      print "Building resources Label..."

  def updateResourcesStatusLabel(self):
    """Updates the Memory Label String"""

    if self.enableResourceMonitoring:
      if self.memoryString.isVisible():
        self.updateMemoryLayout()

      if self.cpuString.isVisible():
        self.updateCPULayout()

      if self.diskString.isVisible():
        self.updateDiskLayout()

      if self.networkString.isVisible():
        self.updateNetworkLayout()

      #totalSystemMemoryGB = self.processHelper.totalSystemMemory()
      #memRatio = currentMemUsageGB / totalSystemMemoryGB
      # This little test makes the label red if the memory usage exceeds 90% of the maximum allowed
      #self._setResourcesLabelColour( memRatio, currentCPUUsageAsPercentatge )

  def updateMemoryLayout(self):
    currentMemUsageGB = self.processHelper.nukeMemoryUsageInGB()
    currentMemUsageAsPercentage = self.processHelper.nukeMemoryUsageAsPercentage()
    self.memoryString.setText("%.2f GB (%.1f%%)" % (currentMemUsageGB, currentMemUsageAsPercentage))

  def updateCPULayout(self):
    currentCPUUsageAsPercentatge = self.processHelper.nukeCPUUsageAsPercentage()
    self.cpuString.setText("%.1f%%" % currentCPUUsageAsPercentatge)

  def updateDiskLayout(self):
    diskMBPerSec = self._diskMBPerSec()
    self.diskString.setText("%.2f MB/s" % diskMBPerSec)

  def updateNetworkLayout(self):
    networkMBPerSec = self._networkMBPerSec()
    self.networkString.setText("%.2f MB/s" % networkMBPerSec)

  def _diskMBPerSec(self):
    """Returns Total Disk Read+Write speed in MB/s"""
    oldBytes = self.currentDiskIOBytes
    DISKS = psutil.disk_io_counters(perdisk=True)
    readWriteBytes =[(DISKS[disk].read_bytes, DISKS[disk].write_bytes) for disk in DISKS.keys()]
    newBytes = sum([sum(x) for x in zip(*readWriteBytes)])
    bytesDiff = newBytes-oldBytes
    self.currentDiskIOBytes = newBytes
    bytesPerSecond = (newBytes-oldBytes)/(self.updateMonitorIntervalMS/1000)
    MBPerSecond = bytesToMB(bytesPerSecond)
    return MBPerSecond

  def _networkMBPerSec(self):
    """Returns Total Network Read+Write speed in MB/s"""
    oldBytes = self.currentNetworkBytesReceived

    NET = psutil.net_io_counters(pernic=True)
    readWriteBytes =[(NET[adapter].bytes_recv, NET[adapter].bytes_sent) for adapter in NET.keys()]
    newBytes = sum([sum(x) for x in zip(*readWriteBytes)])
    bytesDiff = newBytes-oldBytes
    self.currentNetworkBytesReceived = newBytes
    bytesPerSecond = (newBytes-oldBytes)/(self.updateMonitorIntervalMS/1000)
    MBPerSecond = bytesToMB(bytesPerSecond)
    return MBPerSecond

  def setupUI(self):
    """Initialise the UI"""

    self.bar.setStyleSheet( self.getLatestStyleSheet() )
    #self.bar.setFixedHeight(30)
    self.frameserverStatusLabel = QLabel("")

    # Resources
    self.cpuIconPath = os.path.join(gIconPath, "cpu.png")
    self.memoryIconPath = os.path.join(gIconPath, "memory.png")
    self.diskReadIconPath = os.path.join(gIconPath, "disk_read.png")
    self.networkReadIconPath = os.path.join(gIconPath, "net_read.png")

    # MEMORY SECTION
    self.memoryImageButton = QPushButton(QPixmap((self.memoryIconPath)).scaledToHeight(20, Qt.SmoothTransformation),"")
    self.memoryImageButton.setObjectName("show_button_memory")
    self.memoryImageButton.setToolTip("Click to toggle monitoring of 'Real Memory' usage")
    self.memoryString = QLabel("MEMORY (GB)")
    self.memoryString.setToolTip("'Real Memory' usage of this Nuke Session")
    self.memoryImageButton.clicked.connect(lambda: self.show_button_clicked(self.memoryString))

    # CPU SECTION
    self.cpuImageButton = QPushButton(QPixmap((self.cpuIconPath)).scaledToHeight(20, Qt.SmoothTransformation),"")
    self.cpuImageButton.setObjectName("show_button_cpu")
    self.cpuImageButton.setToolTip("Click to toggle monitoring of CPU usage of this Nuke Session")
    self.cpuString = QLabel("CPU (%)")
    self.cpuString.setToolTip("CPU usage of this Nuke Session")
    self.cpuImageButton.clicked.connect(lambda: self.show_button_clicked(self.cpuString))

    # DISK SECTION
    self.diskImageButton = QPushButton(QPixmap((self.diskReadIconPath)).scaledToHeight(20, Qt.SmoothTransformation),"")
    self.diskImageButton.setObjectName("show_button_disk")
    self.diskImageButton.setToolTip("Click to toggle monitoring of Disk Read+Write usage for this machine")
    self.diskString = QLabel("DISK (MB/s)")
    self.diskImageButton.clicked.connect(lambda: self.show_button_clicked(self.diskString))
    self.diskString.setToolTip("Disk Read+Write usage for this machine")

    # NETWORK SECTION
    self.networkImageButton = QPushButton(QPixmap((self.networkReadIconPath)).scaledToHeight(20, Qt.SmoothTransformation),"")
    self.networkImageButton.setObjectName("show_button_network")
    self.networkImageButton.setToolTip("Click to toggle monitoring of Network Read+Write traffic")
    self.networkString = QLabel("NETWORK (MB/s)")
    self.networkString.setToolTip("Total Network Read+Write traffic for this machine")
    self.networkImageButton.clicked.connect(lambda: self.show_button_clicked(self.networkString))

    # Settings Button - Displays what options should be shown in the Status Bar
    self.settingsButton = QPushButton()
    self.settingsButton.setIcon(QIcon("icons:Settings.png"))
    self.settingsButton.clicked.connect(self.showSettings)

    # Build the layout based on Preferences
    #self.cpuWidget.setVisible(self.infoSettings['showCPU'])
    #self.memoryWidget.setVisible(self.infoSettings['showMemory'])
    #self.diskWidget.setVisible(self.infoSettings['showDisk'])
    #self.networkWidget.setVisible(self.infoSettings['showNetwork'])

    self.restartServerButton = QPushButton(QPixmap("icons:TransformRotateRight.png").scaledToHeight(20, Qt.SmoothTransformation),"")
    self.restartServerButton.setFixedHeight(16)    
    self.restartServerButton.clicked.connect(self.restartServer)
    self.restartServerButton.setHidden(True)
    self.restartServerButton.setFlat(True)
    self.restartServerButton.setToolTip("Click here to restart the Nuke Frameserver")
    self.frameServerIsRendering = False

    self.spinnerMovie = QMovie("icons:RenderingSpinner.gif")
    self.spinnerMovie.start()

    self.bar.addPermanentWidget(self.cpuImageButton)
    self.bar.addPermanentWidget(self.cpuString)
    self.bar.addPermanentWidget(self.memoryImageButton)
    self.bar.addPermanentWidget(self.memoryString)
    self.bar.addPermanentWidget(self.diskImageButton)
    self.bar.addPermanentWidget(self.diskString)
    self.bar.addPermanentWidget(self.networkImageButton)
    self.bar.addPermanentWidget(self.networkString)
    self.bar.addPermanentWidget(self.frameserverStatusLabel)
    self.bar.addPermanentWidget(self.restartServerButton)
    self.bar.addPermanentWidget(self.settingsButton)

  def show_button_clicked(self, sender):
    sender.setVisible(not sender.isVisible())

  def _updateUIForServerIsRunning(self):
    """Updates the UI for when the server is reachable"""
    #self.frameserverStatusLabel.setToolTip("Nuke Frame Server is reachable")
    self.getFrameServerWorkers()
    self.frameserverStatusLabel.setPixmap(QPixmap("icons:OK.png"))
    self.restartServerButton.setHidden(True)

  def showSettings(self):
      dialog = SettingsDialog()
      dialog.show()

  # Returns a nicely formatted list of Frame Server workers
  def getFrameServerWorkers(self):
    statusString = str(self.frameServerInstance.getStatus(1000))
    workers = re.findall("workerStatus \{.*?\}", statusString)

    if len(workers) == 0:
        self.frameserverStatusLabel.setToolTip("Unable to determine number of frame server workers.")
        return

    prettyWorkersString = "Frame Server Status (%i workers):\n" % len(workers) + "\n".join(workers)
    self.frameserverStatusLabel.setToolTip(prettyWorkersString)

  def updateStatusBar(self):
    """Updates the Status bar widgets depending on whether the frameServer is reachable"""

    #print "Status: ", str(self.frameServerInstance.getStatus(10))

    # DEBUG - Stylesheet Changes can be applied here and seen live
    #self.bar.setStyleSheet( self.getLatestStyleSheet() )

    try:
      isRunning = self.frameServerInstance.isRunning(0.25)

      if isRunning and not self.rendersExistInQueue():
        self._updateUIForServerIsRunning()
        self.frameServerIsRendering = False

      elif isRunning and self.rendersExistInQueue():
        if self.frameServerIsRendering == False:
          self.frameServerIsRendering = True
          self.frameserverStatusLabel.setPixmap(None)
          self.frameserverStatusLabel.setMovie(self.spinnerMovie)

      else:
        self._handleServerUnreachable()

      self.updateResourcesStatusLabel()

    except:
      self._handleServerUnreachable()
      self.updateResourcesStatusLabel()

  def startMonitoring(self):
    """This timer fires every X milliseconds to update the status."""
    self.timer.start(self.updateMonitorIntervalMS)
    self.isMonitoring = True

  def stopMonitoring(self):
    """Stops the monitoring process"""
    self.timer.stop()
    self.isMonitoring = False
Exemplo n.º 42
0
class Bar(QToolBar):

    clicked = Signal(str)

    def __init__(self, orientation=Qt.Horizontal, parent=None):
        super().__init__(parent)
        self.setOrientation(orientation)
        policy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed,
                             QSizePolicy.ButtonBox)
        policy.setHeightForWidth(True)
        policy.setWidthForHeight(True)
        self.setSizePolicy(policy)
        self.setFloatable(False)
        self.setToolTip("""<p><b>Goto Letter</b></p>
<p>Left-click a letter to navigate to the first entry starting with that
letter.</p>
<p>Right-click a letter to navigate to the first entry starting with the
most recently left-clicked letter, plus any subsequent right-clicked
letters, and this letter.</p>
<p>(One left-click or a fifth right-click clears the previous letters.)</p>
<p>For example, left-click <i>S</i> to go to the first “s” entry. Then
right-click <i>A</i> to go to the first “sa” entry, then right-click
<i>T</i> to go to the first “sat” entry.</p>""")
        self.timer = QTimer(self)
        self.timer.setSingleShot(True)
        self.timer.timeout.connect(self.onTimeout)
        size = self.font().pointSizeF()
        strategy = QFont.StyleStrategy(QFont.PreferOutline
                                       | QFont.PreferAntialias
                                       | QFont.PreferQuality)
        self.mainFont = QFont("courier new")
        self.mainFont.setFixedPitch(True)
        self.mainFont.setStyleStrategy(strategy)
        self.mainFont.setStyleHint(QFont.Monospace)
        self.mainFont.setPointSizeF(size * 1.5)
        self.mainFont.setBold(True)
        self.mainFont.setItalic(False)
        self.setFont(self.mainFont)
        self.smallFont = QFont("helvetica")
        self.smallFont.setStyleStrategy(strategy)
        self.smallFont.setStyleHint(QFont.Times)
        self.smallFont.setPointSizeF(size * 1.25)
        self.smallFont.setBold(False)
        self.smallFont.setItalic(False)
        self.letters = string.ascii_uppercase
        self.word = None

    def sizeHint(self):
        return self.minimumSizeHint()

    def minimumSizeHint(self):
        count = len(self.letters)
        widthAll = self.fontMetrics().width(self.letters) * H_GAP_PC
        widthW = self.fontMetrics().width("WW")
        heightOne = self.fontMetrics().height()
        if self.orientation == Qt.Vertical:
            return QSize(widthW, (heightOne * count) + HANDLE_OFFSET)
        return QSize(widthAll + HANDLE_OFFSET, heightOne * V_GAP_PC)

    def paintEvent(self, event):
        super().paintEvent(event)
        letterPen = QPen(Qt.darkGreen if self.isEnabled() else Qt.lightGray)
        wordPen = QPen(Qt.darkCyan if self.isEnabled() else Qt.lightGray)
        painter = QPainter(self)
        painter.setRenderHints(QPainter.TextAntialiasing)
        painter.setPen(letterPen)
        heightOne = self.fontMetrics().height()
        widthOne = self.fontMetrics().width("W")
        if self.orientation == Qt.Vertical:
            y = HANDLE_OFFSET
            for c in self.letters:
                rect = QRectF(X_OFFSET, y, widthOne, heightOne)
                painter.drawText(rect, Qt.AlignCenter, c)
                y += heightOne
            if self.word is not None:
                painter.setFont(self.smallFont)
                painter.setPen(wordPen)
                rect = self.rect().adjusted(0, HANDLE_OFFSET, -widthOne / 3, 0)
                painter.drawText(rect,
                                 Qt.AlignTop | Qt.AlignRight | Qt.TextWordWrap,
                                 "\n".join(self.word.lower()))
                painter.setPen(letterPen)
                painter.setFont(self.mainFont)
        else:
            widthOne *= H_GAP_PC
            x = HANDLE_OFFSET
            for c in self.letters:
                rect = QRectF(x, 0, widthOne, heightOne * V_GAP_PC)
                painter.drawText(rect, Qt.AlignCenter, c)
                x += widthOne
            if self.word is not None:
                painter.setFont(self.smallFont)
                painter.setPen(wordPen)
                rect = self.rect().adjusted(HANDLE_OFFSET, 0, 0, 0)
                painter.drawText(rect, Qt.AlignBottom | Qt.AlignLeft,
                                 self.word.lower())
                painter.setPen(letterPen)
                painter.setFont(self.mainFont)

    def mousePressEvent(self, event):
        if self.orientation == Qt.Vertical:
            if event.y() < HANDLE_OFFSET:
                event.ignore()
                return
            heightOne = self.fontMetrics().height()
            i = clamp(0, int((event.y() - HANDLE_OFFSET) / heightOne),
                      len(self.letters) - 1)
        else:
            if event.x() < HANDLE_OFFSET:
                event.ignore()
                return
            widthOne = self.fontMetrics().width("W") * H_GAP_PC
            i = clamp(0, int((event.x() - HANDLE_OFFSET) / widthOne),
                      len(self.letters) - 1)
        event.accept()
        word = self.letters[i]
        if event.button() == Qt.LeftButton or self.word is None:
            self.word = word
        elif event.button() == Qt.RightButton:
            if len(self.word) >= 4:
                self.word = word
            elif self.word is not None:
                self.word += word
        if self.word is not None:
            self.clicked.emit(self.word.lower())
            self.timer.start(10000)
        self.update()

    def contextMenuEvent(self, event):
        if ((self.orientation == Qt.Vertical and event.y() < HANDLE_OFFSET) or
            (self.orientation == Qt.Horizontal and event.x() < HANDLE_OFFSET)):
            event.ignore()
        else:
            event.accept()

    def setOrientation(self, orientation):
        self.orientation = orientation
        self.update()

    def heightForWidth(self, width):
        count = len(self.letters)
        heightOne = self.fontMetrics().height()
        widthAll = self.fontMetrics().width(self.letters) * H_GAP_PC
        if widthAll > width:  # Needs to be vertical
            return heightOne * count
        return heightOne * V_GAP_PC  # Needs to be horizontal

    def onTimeout(self):
        self.timer.stop()
        if self.word is not None:
            self.word = None
            self.update()
Exemplo n.º 43
0
class Browser(QWidget):
  def __init__(self):
    super(Browser, self).__init__()

    self.layout    = QStackedLayout(self)
    self.frontView = QWebView(self)
    self.backView  = QWebView(self)

    self.frontView.page().networkAccessManager().sslErrors.connect(self.onSslErrors)
    self.backView.page().networkAccessManager().sslErrors.connect(self.onSslErrors)

    self.hostname  = os.uname()[1]

    self.layout.setStackingMode(QStackedLayout.StackAll)
    self.layout.addWidget(self.frontView)
    self.layout.addWidget(self.backView)

    self.commands = {
      'help'          : self.cmdHelp,
      'refresh'       : self.cmdRefresh,
      'add'           : self.cmdAdd,
      'del'           : self.cmdDel,
      'list'          : self.cmdList,
      'zoom'          : self.cmdZoom,
      'fs'            : self.cmdFs,
      'exit'          : self.cmdExit,
      'next'          : self.cmdNext,
      'restart'       : self.cmdRestart,
      'upgrade'       : self.cmdUpgrade,
    }

    self.timer = QTimer()
    self.timer.setSingleShot(False)

    self.sites = list()
    self.siteId = -1

    self.socket = False

    url = QUrl("http://dmr.tokiogroup.com/rrs.php")
    self.sites.append(Site(url, 10, 1))

    url = QUrl("http://dmr.tokiogroup.com/lastheard.php")
    self.sites.append(Site(url, 10, 1))

    self.server = QTcpServer()
    self.server.listen(QHostAddress.Any, 4242)

    self.connect(self.server,     SIGNAL("newConnection()"),    self, SLOT("onConnection()"));
    self.connect(self.timer,      SIGNAL("timeout()"),          self, SLOT("goNext()"));

    self.goNext()
    self.goNext()

  def goNext(self):
    self.cmdNext(list())

  def onConnection(self):
    self.socket = self.server.nextPendingConnection()
    self.socket.write(self.hostname + ' % ')
    self.connect(self.socket, SIGNAL("readyRead()"), self, SLOT("onDataReceived()"));

  def print_(self, text):
    if (self.socket != False):
      self.socket.write(text + '\n')
    print(text)


  def onDataReceived(self):
    data = self.socket.readAll().data().strip()
    try:
      args = data.split(' ')
      map(lambda x : x.strip(), args)
      self.commands.get(args[0])(args)
    except Exception:
      self.print_('>> syntax error')
      self.printCommandsList()
    if self.socket.isOpen():
      self.socket.write(self.hostname + ' % ')

  def printCommandsList(self):
    self.print_('avaible commands:')
    for command in self.commands:
      self.print_('  ' + command)


  def onSslErrors(self, reply, errors):
    url = unicode(reply.url().toString())
    reply.ignoreSslErrors()

  # commands
  def cmdHelp(self, args):
    self.print_('>> help')
    self.printCommandsList()

  def cmdRefresh(self, args):
    self.print_('>> refresh ' + self.url.toString().encode())
    self.frontView.reload()

  def cmdAdd(self, args):
    self.print_('>> add ' + args[1] + ' ' + args[2] + ' ' + args[3])
    self.sites.append(Site(QUrl(args[1]), int(args[2], int(args[3]))))

  def cmdDel(self, args):
    self.print_('>> del ' + args[1])
    self.sites.pop(int(args[1]))

  def cmdList(self, args):
    self.print_('>> list')
    self.print_('current list:')
    sitesCount = len(self.sites)
    i = 0
    while i < sitesCount:
      self.print_('%1c[%1d] %2ds : %3s' % ((i==self.siteId) and '*' or ' ' ,i, self.sites[i].time, self.sites[i].url.toString().encode()))
      i = i + 1

  def cmdZoom(self, args):
    self.print_('>> zoom ' + args[1])
    self.frontView.setZoomFactor(float(args[1]))

  def cmdFs(self, args):
    self.print_('>> fs ' + args[1])
    if (args[1] == '1'):
      self.showFullScreen()
    else:
      self.showNormal()

  def cmdExit(self, args):
    self.print_('>> exit')
    self.socket.close()

  def cmdNext(self, args):
    self.timer.stop()
    self.timer.start(self.sites[self.siteId].time * 1000)
    self.siteId = (self.siteId + 1) % len(self.sites)
    print('>> next ' + self.sites[self.siteId].url.toString().encode())
    self.backView.show()
    self.frontView, self.backView = self.backView, self.frontView
    self.backView.load(self.sites[self.siteId].url)
    self.backView.setZoomFactor(self.sites[self.siteId].zoom)
    self.backView.hide()

  def cmdRestart(self, args):
    self.print_('>> restart')
    self.close()

  def cmdUpgrade(self, args):
    self.print_('>> upgrade')
    update = urllib.urlopen('https://raw.githubusercontent.com/tjardick/monitoring_browser/master/webkit.py').read()
    script = file('webkit.py', 'w')
    script.write(update)
    script.close()
    self.close()
Exemplo n.º 44
0
        self.windowTitle()  # generate exception


app = QApplication([])
app.setQuitOnLastWindowClosed(False)

lineEdit = LineEdit()
lineEdit.deleteLater()


if USE_SINGLESHOT:
    #QTimer.singleShot(1000, lineEdit.clear)
    #QTimer.singleShot(1000, lineEdit.purePythonMethod)
    QTimer.singleShot(1000, lineEdit.selectAll)  # pure C++ method
else:
    timer = QTimer(None)
    timer.setSingleShot(True)
    timer.setInterval(1000)
    timer.start()

    #timer.timeout.connect(lineEdit.clear)
    #timer.timeout.connect(lineEdit.purePythonMethod)
    timer.timeout.connect(lineEdit.selectAll)  # pure C++ method


QTimer.singleShot(2000, app.quit)

app.exec_()

print('~~~~ Application exited')
Exemplo n.º 45
0
class Navigator(Singleton,object):
    
    instance = None
    logger = None
    PATH_SEPARATOR = '-'
    
    JUMP_SIGNAL_PAGE_LOAD_FINISH = 'PAGE LOAD FINISH'
    JUMP_SIGNAL_REQUEST_LOAD_FINISH = 'REQUEST LOAD FINISH'
    
    CROSS_AXIS_METHOD_AJAX = 'AJAX'
    CROSS_AXIS_METHOD_FULL_LOAD = 'FULL LOAD'
    
    def __init__(self):
        self.network_manager = CustomNetworkAccessManager.getInstance()
        self.axis = []
        self.human_events = {}
        self.node_collected_data = {}
        self.last_url = None   
        self.current_url = QUrl()
        self.current_axis_id = None
        self.crossed_axis_method = None
        self.crossed_axes = []
        self.crossed_axes_string = ''
        
        self.cross_axis_delay = QTimer()
        self.cross_axis_delay.setSingleShot(True)
        self.cross_axis_delay.timeout.connect(self.crossedAxis)
        self.cross_axis_params = None
        
        self.loading_timeout = QTimer()
        self.loading_timeout.setSingleShot(True)
        self.loading_timeout.setInterval(30000)
        self.loading_timeout.timeout.connect(self.loadingTimeoutAction)
        
        self.inactivity_timeout = QTimer()
        self.inactivity_timeout.setSingleShot(True)
        self.inactivity_timeout.setInterval(10000)
        self.inactivity_timeout.timeout.connect(self.inactivityTimeoutAction)
        
        self.page_reloads = 0
        
        Logger.getLoggerFor(self.__class__)

    def takeEntryPoint(self):        
        g = GraphParser.getInstance()
        for ax in self.axis:
            self.logger.info('Axis : %s' % ax)
            
        if g.entry_point:
            self.logger.info('Taking the entry point %s' % g.entry_point)
            self.last_url = QUrl(g.entry_point)
            inst =  Jaime.getInstance()
            inst.view.load(QUrl(g.entry_point))    
            return True
        
        self.logger.error("Can't take entry point, graph has't entry point")
        return False
        
    def matchesSelector(self,axis):
        inst =  Jaime.getInstance()
        frame = inst.view.page().mainFrame()
        document = frame.documentElement()
        selector = axis.css_selector_condition
#         print 'document %s ' % document.evaluateJavaScript("""this.querySelector('%s')""" % selector)        
        ret = frame.findAllElements(selector)
        
        print '%s axis %s matches css selector ? %s' % (selector,axis,bool(ret.count()))
        self.logger.debug('axis %s matches css selector ? %s' % (axis,bool(ret.count())))
#         for i in range(ret.count()):
#             self.logger.error(ret.at(i).toInnerXml())
        return ret.count()
    
    def matches(self,axis):
        m_from = False
        m_to = False
        m_method = True
        m_selector = True
        m_route = True
        
        if axis.from_url is not None :            
            if isinstance(axis.from_url,str):
                m_from = axis.from_url == self.last_url.toString()
            elif axis.from_url.match(self.last_url.toString()):                
                m_from = True
        else:
            m_from = True
        
        if axis.to_url is not None:
            if isinstance(axis.to_url,str):
                m_to =  axis.to_url == self.current_url.toString()
            elif axis.to_url.match(self.current_url.toString()):
                m_to = True         
        else:
            m_to = True
        
#         print 'el axis %s tiene method %s, %s '  % (axis,
#                                                     axis.axis_method,
#                                                     self.crossed_axis_method
#                                                     )
        
        if self.crossed_axis_method == RouteAxis.CROSS_AXIS_METHOD_AJAX or \
                axis.axis_method :
            
            if self.crossed_axis_method != axis.axis_method:
                m_method = False           
        
        if axis.css_selector_condition:
            m_selector = axis.not_css_selector ^ bool(self.matchesSelector(axis))            
        
        if len(axis.previous_axis)>0:
            m_route = False
            for path_index in range(len(axis.previous_axis)):
                path =  string.join( axis.previous_axis[path_index], self.PATH_SEPARATOR)
                self.logger.debug( "matching axis (%s) with path %s" % (axis.id,path))
                if self.crossed_axes_string.find(path) == 0:
                    m_route = True 
                    break
        
        self.logger.debug("Matches (%s) %s\nfrom %s  to %s method %s selector %s route %s" % (axis.id,
                                                                                             axis.comment,
                                                                                             m_from,m_to,m_method,m_selector,m_route))
        return m_from and m_to and m_method and m_selector and m_route
    
    def crossedAxis(self,ajax=False):
        if self.cross_axis_params and self.cross_axis_params[0]: 
            ajax = True
            
        self.cross_axis_params = None
        self.crossed_axes_string = string.join(self.crossed_axes,self.PATH_SEPARATOR)
        self.logger.info("crossedAxis, path: \n%s" % string.join(self.crossed_axes,"\n"))
        if ajax:
            self.crossed_axis_method =  RouteAxis.CROSS_AXIS_METHOD_AJAX
        else:
            self.crossed_axis_method =  RouteAxis.CROSS_AXIS_METHOD_FULL_LOAD
            
        print 'Cruse un eje por %s ' % self.crossed_axis_method
        
        for ax in self.axis:
            if self.matches(ax):
                self.current_axis_id = ax.id
                # print 'current axis %s'  % ax.id
                self.logger.info('Axis matched %s' % ax)                
                self.startSecuence(ax)
                return
        self.logger.warning("Can't match any axis")                
        self.inactivity_timeout.start()            
    
    def collectData(self,id,collector,params):
        if not self.getAxis(id):
            self.logger.error("Can't collect data from inexistent axis")
            return 

        if id not  in self.node_collected_data:
            self.node_collected_data[id] = []
            
        self.node_collected_data[id].append((collector,params))
    
    def setAxis(self,route_axis,human_events):
        self.logger.info('setting axis %s ' % route_axis)
        if route_axis.id in self.human_events:
            raise Exception('Axis repetido')
        
        self.human_events[route_axis.id] = human_events
        self.axis.append(route_axis)
#         QtCore.QObject.disconnect(self.human_events[route_axis.id], 
#                                   QtCore.SIGNAL("finished()"), 
#                                   self.secuenceFinished)
        QtCore.QObject.connect(self.human_events[route_axis.id], 
                               QtCore.SIGNAL("finished()"), 
                               self.secuenceFinished)
    
    def startSecuence(self,axis):
        inst =  Jaime.getInstance()
        try :
            if axis.max_crosses > 0 and axis.max_crosses <= axis.cross_counter:
                self.logger.info('el axis supero la cantidad maxima de loops ')
                if axis.exit_point:
                    exit_axis = self.getAxis(axis.exit_point)
                    self.logger.info('Salto hacia el exit_axis %s' %  exit_axis)
                    self.startSecuence(exit_axis)
                else:
                    self.logger.error('No hay exit axis muero %s' % axis.exit_point)
                    inst =  Jaime.getInstance()
                    inst.finishWork()                    
            else:

                axis.cross_counter += 1
                h_ev = self.human_events[axis.id]            
                self.crossed_axes.insert(0,axis.id)
                if len(self.crossed_axes) >= 10: self.crossed_axes.pop()            
                self.logger.info('Stopeo el inactivity timeout')
                self.inactivity_timeout.stop()            
                if axis.id in self.node_collected_data:
                    inst.route_node.doWork(self.node_collected_data[axis.id])                    
                h_ev.fire()
                
        except Exception as e:
            # print 'Excepcion en startSecuence %s' % e
            self.logger.error(e)
            
    def getAxis(self,axis_id):
        for ax in self.axis:
            if ax.id == axis_id:
                return ax
        return None
    
    def secuenceFinished(self):
        self.logger.info('estarteo  el inactivity timeout' )
        self.inactivity_timeout.start()
    
    def inactivityTimeoutAction(self):
        
        inst =  Jaime.getInstance()
        self.logger.info('inactivity timeout action fired after %s seconds' % (self.inactivity_timeout.interval()/1000))
        
        if not len(self.crossed_axes):
            return 
        last_axis = self.crossed_axes[0]
        ax = self.getAxis(last_axis)
        
        retry_axis_id = ax.retry_axis
        retry_axis = self.getAxis(retry_axis_id)
        
        if retry_axis:
            self.logger.info('El axis %s tiene como retry axis a %s lo estarteo' % (ax.id,ax.retry_axis))
            self.startSecuence(retry_axis)
    
    def processLoadStarted(self):
        inst =  Jaime.getInstance()
        self.logger.info('Page started load to %s' % inst.view.url().toString())
        
#         print inst.page.mainFrame().requestedUrl()
        self.inactivity_timeout.stop()            
        self.loading_timeout.stop()
        self.loading_timeout.start()
        
        self.logger.info('Starting loading timeout and stopping inactivity timeout')        
        self.last_url = inst.view.url()
        
    def loadingTimeoutAction(self):
        self.logger.warning('Loading timeout fired')
        inst =  Jaime.getInstance()
        if (not inst.view.url().isEmpty() and re.match('http.?://',inst.view.url().toString()) ) \
                and not self.page_reloads:
            self.logger.info('Timeout fired, reloading last url %s' % inst.view.url().toString())
            self.page_reloads += 1            
            self.loading_timeout.stop()                    
            inst.view.reload()            
            
        else:
            self.logger.error("""Timeout fired, clossing jaime, there isn't last_url or max_reloads reatched""" )
            inst.finishWork()
                        
    def processPageLoadFinished(self,status):
        inst =  Jaime.getInstance()
        self.logger.info('Page finished load to %s with status %s ' % (inst.view.url().toString(),
                                                                       status))
        if status:
            self.current_url = inst.view.url()
            self.loading_timeout.stop()
            self.page_reloads = 0 
            self.logger.info('Stopping loading timeout')    
        else:
            self.current_url = QUrl()           
            
        self.testJumpRules(self.JUMP_SIGNAL_PAGE_LOAD_FINISH,
                           status)       
        
    def testJumpRules(self,signal,*args):
#         self.logger.info('Call to restJumpRules with signal %s' % signal)
#         print 'Call to restJumpRules %s' % ( signal)
        if signal == self.JUMP_SIGNAL_PAGE_LOAD_FINISH:
            print 'llamo a crosed axis'
            self.pushCrossedAxis()            
        
        elif signal == self.JUMP_SIGNAL_REQUEST_LOAD_FINISH:
            if not self.current_axis_id:
                return
            
            req_headers = args[0]
            rep_headers = args[1]
            
            ax = self.getAxis(self.current_axis_id)
#             print '%s tiene exit_method %s' % (ax,ax.axis_exit_method)
            if ax.axis_exit_method and  \
                    ax.axis_exit_method == RouteAxis.CROSS_AXIS_METHOD_AJAX:
                
                if 'X-Requested-With' in req_headers:
                    
                    if ax.axis_exit_method_toggled :
                        ax.axis_exit_method = ax.axis_exit_method_toggled
                        ax.axis_exit_method_toggled = None
                    
                    self.pushCrossedAxis(True)
    
    def pushCrossedAxis(self,*params):
        if self.cross_axis_delay.isActive() or \
                self.cross_axis_params is not None:
            self.logger.warning("""Can't push crossAxis call, there is another call in process""")
            return 
        
        self.cross_axis_params = params                
        
        ax = self.getAxis(self.current_axis_id)        
        
        if ax and  ax.delay_node_test: 
            delay = ax.delay_node_test
        else:
            delay = None
            
        if delay:            
            self.cross_axis_delay.setInterval(delay)
            self.cross_axis_delay.start()
            self.logger.info('Delaying %s seconds crossedAxis call ' % int( int(delay) /1000)  )            
        else:
            self.crossedAxis()
Exemplo n.º 46
0
class CfdFaceSelectWidget:
    def __init__(self, parent_widget, obj, allow_face_sel, allow_solid_sel,
                 allow_point_sel=False, allow_edge_sel=False):
        ui_path = os.path.join(os.path.dirname(__file__), "TaskPanelCfdListOfFaces.ui")
        self.parent_widget = parent_widget
        self.form = FreeCADGui.PySideUic.loadUi(ui_path, self.parent_widget)
        self.parent_widget.layout().addWidget(self.form)

        self.selecting_references = False
        self.recompute_timer = QTimer()
        self.recompute_timer.setSingleShot(True)
        self.recompute_timer.timeout.connect(self.recomputeDocument)

        self.obj = obj
        self.References = self.obj.References
        self.doc_name = self.obj.Document.Name
        self.view_object = self.obj.ViewObject

        self.allow_face_sel = allow_face_sel
        self.allow_solid_sel = allow_solid_sel
        self.allow_point_sel = allow_point_sel
        self.allow_edge_sel = allow_edge_sel
        self.selection_mode_solid = (not allow_face_sel) and allow_solid_sel
        sel_list = []
        sel_rb_list = []
        if allow_face_sel:
            sel_list.append("faces")
            sel_rb_list.append("Face")
        if allow_edge_sel:
            sel_list.append("edges")
            sel_rb_list.append("Edge")
        if allow_point_sel:
            sel_list.append("vertices")
            sel_rb_list.append("Vertex")
        sel_rb_text = ' / '.join(sel_rb_list)
        sel_msg = ""
        if len(sel_list) > 0:
            sel_msg = sel_list[0]
            if len(sel_list) > 1:
                for i in range(len(sel_list)-2):
                    sel_msg += ", " + sel_list[i+1]
                sel_msg += " and " + sel_list[-1]
        self.form.rb_standard.setText(sel_rb_text)

        self.selection_mode_std_print_message = "Select {} by single-clicking " \
                                                "on them.".format(sel_msg)
        self.selection_mode_solid_print_message = "Select solids by single-clicking on a face or edge which belongs " \
                                                  "to the solid."

        exclusive_sel = (not allow_solid_sel) or not (allow_face_sel or allow_edge_sel or allow_point_sel)
        self.form.labelSelection.setVisible(not exclusive_sel)
        self.form.rb_standard.setVisible(not exclusive_sel)
        self.form.rb_solid.setVisible(not exclusive_sel)
        self.form.rb_standard.toggled.connect(self.choose_selection_mode_standard)
        self.form.rb_solid.toggled.connect(self.choose_selection_mode_solid)

        self.form.listReferences.currentRowChanged.connect(self.setReferenceListSelection)
        self.form.buttonAddFace.clicked.connect(self.buttonAddFaceClicked)
        self.form.buttonAddFace.setCheckable(True)
        self.form.buttonRemoveFace.clicked.connect(self.buttonRemoveFaceClicked)

        # Face list selection
        self.form.faceList.clicked.connect(self.faceListSelection)
        self.form.shapeComboBox.currentIndexChanged.connect(self.faceListShapeChosen)
        self.form.faceListWidget.itemSelectionChanged.connect(self.faceHighlightChange)
        self.form.faceListWidget.itemChanged.connect(self.faceListItemChanged)
        self.form.selectAllButton.clicked.connect(self.selectAllButtonClicked)
        self.form.selectNoneButton.clicked.connect(self.selectNoneButtonClicked)
        self.form.doneButton.clicked.connect(self.closeFaceList)
        self.form.shapeComboBox.setToolTip("Choose a solid object from the drop down list and select one or more of "
                                           "the faces associated with the chosen solid.")

        self.solidsNames = ['None']
        self.solidsLabels = ['None']
        for i in FreeCADGui.ActiveDocument.Document.Objects:
            if "Shape" in i.PropertiesList:
                # Do not restrict to solids
                if not i.Name.startswith("CfdFluidBoundary"):
                    self.solidsNames.append(i.Name)
                    self.solidsLabels.append(i.Label)

        self.rebuildReferenceList()

        # First time, add any currently selected faces to list
        if len(self.References) == 0:
            self.addSelectionToRefList()
            self.scheduleRecompute()
            FreeCADGui.Selection.clearSelection()
            self.updateSelectionbuttonUI()

    def setReferenceListSelection(self, row):
        if row > -1:
            self.enableSelectingMode(False)
            docName = str(self.doc_name)
            doc = FreeCAD.getDocument(docName)
            ref = self.References[row]
            selection_object = doc.getObject(ref[0])
            FreeCADGui.Selection.addSelection(selection_object, [str(ref[1])])

    def addSelectionToRefList(self):
        """ Add currently selected objects to reference list. """
        for sel in FreeCADGui.Selection.getSelectionEx():
            if sel.HasSubObjects:
                for sub in sel.SubElementNames:
                    print("{} {}".format(sel.ObjectName, sub))
                    self.addSelection(sel.DocumentName, sel.ObjectName, sub)
        self.scheduleRecompute()

    def enableSelectingMode(self, selecting):
        self.selecting_references = selecting
        FreeCADGui.Selection.clearSelection()
        # start SelectionObserver and parse the function to add the References to the widget
        if self.selecting_references:
            FreeCADGui.Selection.addObserver(self)
        else:
            FreeCADGui.Selection.removeObserver(self)
        self.scheduleRecompute()
        self.updateSelectionbuttonUI()

    def buttonAddFaceClicked(self):
        self.selecting_references = not self.selecting_references
        if self.selecting_references:
            # Add any currently selected objects
            if len(FreeCADGui.Selection.getSelectionEx()) >= 1:
                self.addSelectionToRefList()
                self.selecting_references = False
        self.enableSelectingMode(self.selecting_references)

    def buttonRemoveFaceClicked(self):
        if not self.References:
            return
        if not self.form.listReferences.currentItem():
            return
        current_item_name = str(self.form.listReferences.currentItem().text())
        for ref in self.References:
            idx = self.solidsNames.index(ref[0])
            refname = self.solidsLabels[idx] + ':' + ref[1]
            if refname == current_item_name:
                self.References.remove(ref)
        self.rebuildReferenceList()
        self.scheduleRecompute()

    def choose_selection_mode_standard(self, state):
        self.selection_mode_solid = not state
        self.updateSelectionbuttonUI()

    def choose_selection_mode_solid(self, state):
        self.selection_mode_solid = state
        self.updateSelectionbuttonUI()

    def updateSelectionbuttonUI(self):
        self.form.buttonAddFace.setChecked(self.selecting_references)
        if self.selecting_references:
            if self.selection_mode_solid:  # print message on button click
                print_message = self.selection_mode_solid_print_message
            else:
                print_message = self.selection_mode_std_print_message
        else:
            print_message = ""
        self.form.labelHelpText.setText(print_message)

    def addSelection(self, doc_name, obj_name, sub, selected_point=None, as_is=False):
        """ Add the selected sub-element (face) of the part to the Reference list. Prevent selection in other
        document.
        """
        if FreeCADGui.activeDocument().Document.Name != self.doc_name:
            return
        selected_object = FreeCAD.getDocument(doc_name).getObject(obj_name)
        # On double click on a vertex of a solid sub is None and obj is the solid
        print('Selection: ' +
              selected_object.Shape.ShapeType + '  ' +
              selected_object.Name + ':' +
              sub + " @ " + str(selected_point))
        if hasattr(selected_object, "Shape") and sub:
            if sub.startswith('Solid'):  # getElement doesn't work for solids
                elt = selected_object.Shape.Solids[int(sub.lstrip('Solid')) - 1]
            else:
                elt = selected_object.Shape.getElement(sub)
            selection = None
            if as_is:
                selection = (selected_object.Name, sub)
            elif self.selection_mode_solid:
                # in solid selection mode use edges and faces for selection of a solid
                solid_to_add = None
                if elt.ShapeType == 'Edge':
                    found_edge = False
                    for i, s in enumerate(selected_object.Shape.Solids):
                        for e in s.Edges:
                            if elt.isSame(e):
                                if not found_edge:
                                    solid_to_add = 'Solid' + str(i + 1)
                                else:
                                    FreeCAD.Console.PrintMessage('Edge belongs to more than one solid\n')
                                    solid_to_add = None
                                found_edge = True
                elif elt.ShapeType == 'Face':
                    found_face = False
                    for i, s in enumerate(selected_object.Shape.Solids):
                        for e in s.Faces:
                            if elt.isSame(e):
                                if not found_face:
                                    solid_to_add = 'Solid' + str(i + 1)
                                else:
                                    FreeCAD.Console.PrintMessage('Face belongs to more than one solid\n')
                                    solid_to_add = None
                                found_face = True
                elif elt.ShapeType == 'Solid':
                    solid_to_add = sub
                if solid_to_add:
                    selection = (selected_object.Name, solid_to_add)
                    print('Selection element changed to Solid: ' +
                          selected_object.Shape.ShapeType + '  ' +
                          selection[0] + '  ' +
                          selection[1])
            else:
                # Allow Vertex, Edge, Face or just Face selection
                if (elt.ShapeType == 'Face' and self.allow_face_sel) or \
                        (elt.ShapeType == 'Edge' and self.allow_edge_sel) or \
                        (elt.ShapeType == 'Vertex' and self.allow_point_sel):
                    selection = (selected_object.Name, sub)
            if selection:
                if selection not in self.References:
                    self.References.append(selection)
                else:
                    FreeCAD.Console.PrintMessage(
                        selection[0] + ':' + selection[1] + ' already in reference list\n')
            self.rebuildReferenceList()
            self.scheduleRecompute()
        self.updateSelectionbuttonUI()

    def rebuildReferenceList(self):
        self.form.listReferences.clear()
        items = []
        remove_refs = []
        for ref in self.References:
            try:
                idx = self.solidsNames.index(ref[0])
            except ValueError:  # If solid doesn't exist anymore
                remove_refs.append(ref)
            else:
                item_name = self.solidsLabels[idx] + ':' + ref[1]
                items.append(item_name)
        for ref in remove_refs:
            self.References.remove(ref)
        if remove_refs:
            self.scheduleRecompute()
        for listItemName in items:
            self.form.listReferences.addItem(listItemName)
        # At the moment we assume order in listbox is the same as order of references
        self.form.listReferences.setSortingEnabled(False)

    def faceListSelection(self):
        self.form.stackedWidget.setCurrentIndex(1)
        self.form.shapeComboBox.clear()
        self.form.faceListWidget.clear()
        self.form.shapeComboBox.insertItems(1, self.solidsLabels)

    def faceListShapeChosen(self):
        ind = self.form.shapeComboBox.currentIndex()
        objectName = self.solidsNames[ind]
        if objectName != 'None':
            # Disable change notifications while we add new items
            self.form.faceListWidget.itemChanged.disconnect(self.faceListItemChanged)
            self.shapeObj = FreeCADGui.ActiveDocument.Document.getObject(objectName)
            self.hideObjects()
            refs = list(self.References)
            self.form.faceListWidget.clear()
            FreeCADGui.showObject(self.shapeObj)
            if self.allow_face_sel:
                self.listOfShapeFaces = self.shapeObj.Shape.Faces
                selected_faces = [ref[1] for ref in refs if ref[0] == objectName]
                for i in range(len(self.listOfShapeFaces)):
                    face_name = "Face" + str(i + 1)
                    item = QtGui.QListWidgetItem(face_name, self.form.faceListWidget)
                    item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
                    checked = face_name in selected_faces
                    if checked:
                        item.setCheckState(QtCore.Qt.Checked)
                    else:
                        item.setCheckState(QtCore.Qt.Unchecked)
                    self.form.faceListWidget.insertItem(i, item)
            if self.allow_solid_sel:
                self.listOfShapeSolids = self.shapeObj.Shape.Solids
                selected_solids = [ref[1] for ref in refs if ref[0] == objectName]
                for i in range(len(self.listOfShapeSolids)):
                    face_name = "Solid" + str(i + 1)
                    item = QtGui.QListWidgetItem(face_name, self.form.faceListWidget)
                    item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
                    checked = face_name in selected_solids
                    if checked:
                        item.setCheckState(QtCore.Qt.Checked)
                    else:
                        item.setCheckState(QtCore.Qt.Unchecked)
                    self.form.faceListWidget.insertItem(i, item)
            if self.allow_edge_sel:
                self.listOfShapeEdges = self.shapeObj.Shape.Edges
                selected_edges = [ref[1] for ref in refs if ref[0] == objectName]
                for i in range(len(self.listOfShapeEdges)):
                    face_name = "Edge" + str(i + 1)
                    item = QtGui.QListWidgetItem(face_name, self.form.faceListWidget)
                    item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
                    checked = face_name in selected_edges
                    if checked:
                        item.setCheckState(QtCore.Qt.Checked)
                    else:
                        item.setCheckState(QtCore.Qt.Unchecked)
                    self.form.faceListWidget.insertItem(i, item)
            if self.allow_point_sel:
                self.listOfShapeVertices = self.shapeObj.Shape.Vertexes
                selected_solids = [ref[1] for ref in refs if ref[0] == objectName]
                for i in range(len(self.listOfShapeVertices)):
                    face_name = "Vertex" + str(i + 1)
                    item = QtGui.QListWidgetItem(face_name, self.form.faceListWidget)
                    item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
                    checked = face_name in selected_solids
                    if checked:
                        item.setCheckState(QtCore.Qt.Checked)
                    else:
                        item.setCheckState(QtCore.Qt.Unchecked)
                    self.form.faceListWidget.insertItem(i, item)

            self.form.faceListWidget.itemChanged.connect(self.faceListItemChanged)

    def hideObjects(self):
        for i in FreeCADGui.ActiveDocument.Document.Objects:
            if "Shape" in i.PropertiesList:
                FreeCADGui.hideObject(i)
        self.view_object.show()

    def faceHighlightChange(self):
        FreeCADGui.Selection.clearSelection()
        FreeCADGui.Selection.addSelection(self.shapeObj, self.form.faceListWidget.currentItem().text())
        self.scheduleRecompute()

    def faceListItemChanged(self, item):
        object_name = self.solidsNames[self.form.shapeComboBox.currentIndex()]
        if object_name != 'None':
            face_name = item.text()
            if item.checkState() == QtCore.Qt.Checked:
                self.addSelection(self.doc_name, object_name, face_name, as_is=True)
            else:
                if not self.References:
                    return
                for ref in self.References:
                    if ref[0] == object_name and ref[1] == face_name:
                        self.References.remove(ref)
                self.rebuildReferenceList()
            self.scheduleRecompute()

    def selectAllButtonClicked(self):
        for i in range(self.form.faceListWidget.count()):
            item = self.form.faceListWidget.item(i)
            item.setCheckState(QtCore.Qt.Checked)

    def selectNoneButtonClicked(self):
        for i in range(self.form.faceListWidget.count()):
            item = self.form.faceListWidget.item(i)
            item.setCheckState(QtCore.Qt.Unchecked)

    def closeFaceList(self):
        self.form.stackedWidget.setCurrentIndex(0)
        # self.obj.ViewObject.show()

    def scheduleRecompute(self):
        """ Only do one (costly) recompute when done processing - call this in preference to document.recompute() """
        self.recompute_timer.start()

    def recomputeDocument(self):
        # Re-assign to force update of FreeCAD property
        self.obj.References = self.References
        FreeCAD.getDocument(self.doc_name).recompute()

    def closing(self):
        """ Call this on close to let the widget to its proper cleanup """
        FreeCADGui.Selection.removeObserver(self)

    def __del__(self):
        # Just in case, make sure any stray selection observer is removed before object deleted
        FreeCADGui.Selection.removeObserver(self)
Exemplo n.º 47
0
 def resizeTimer(self):
     ret = QTimer(self.q)
     ret.setSingleShot(True)
     ret.setInterval(200)
     ret.timeout.connect(self.updateSize)
     return ret
Exemplo n.º 48
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):
        if color==None:color=QColorDialog.getColor()
        if color.isValid():
            self.curve.setPen(color)
            
    def change_point_color(self,color=None):
        if color==None:color=QColorDialog.getColor()
        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
Exemplo n.º 49
0
class Recorder(QMainWindow):
    '''Main Window
     - menu toolbar to load and save session, open plotter and set server
     - dock widget holding session and run information
     - grid plot to stream current emg data of 16 channels
     - start, stop, progressbar and trigger for current run
    '''
    
    
    def __init__(self, parent=None):
        super(Recorder, self).__init__(parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        
        self.plotter = None
        self.session = None
        self.server = DelsysStation(parent=self)
        
        self.ui.dockWidget.setWidget(QWidget())
        
        self.dockLayout = QGridLayout(self.ui.dockWidget.widget())
        self.showSessionMeta = None
        self.showRunMeta = None
        self.plotWidget = None
        self.plots = []
        self.startTime = datetime.now()
        
        self.pinger = QTimer(self) # timer to read data from server whenever available
        self.runPinger = QTimer(self) # timer to call stop when run duration times out
        
        self.runPinger.setSingleShot(True)
        self.runPinger.timeout.connect(self.stop)
        self.pinger.timeout.connect(self.ping)
        self.kinectRecorder=None
        self.newpath=None
        self.notSavedState = False
        
    def clearDock(self):
        ''' clear session (dock widget elements)
        - remove showSessionMeta
        - remove showRunMeta
        - kill kinectRecorder
        - remove session
        
        if changes are not saved, ask
        '''
        if self.showSessionMeta is not None:
            reply = QMessageBox.question(self, 'QMessageBox.question()',
                                         'Do you want to first save the current session?',
                                         QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel)
            if reply == QMessageBox.Yes:
                self.save()
            elif reply == QMessageBox.Cancel:
                return 
            
            self.session = None
            self.dockLayout.removeWidget(self.showSessionMeta)
            self.dockLayout.removeWidget(self.showRunMeta)
            self.showSessionMeta.deleteLater()
            self.showRunMeta.deleteLater()
            self.showSessionMeta = None
            self.showRunMeta = None
            self.kinectRecorder.killRecorder()
            
    def preparePlots(self):
        '''arange 2x8 plots for each channel and
        set parameters
        '''
        if self.ui.frame.layout() is None:
            layout = QGridLayout()
            self.ui.frame.setLayout(layout)
        else:
            #########
            # reset #
            #########
            layout = self.ui.frame.layout()
            layout.removeWidget(self.plotWidget)
            self.plotWidget = None
            self.plots = []
        self.plotWidget = pg.GraphicsLayoutWidget(border=(100,100,100))
        layout.addWidget(self.plotWidget)
        
        for i in range(8):
            for k in range(2):
                self.plots.append(self.plotWidget.addPlot(title="EMG " + str(k+2*i+1)))
                self.plots[-1].plot(np.linspace(0,2,1000))
                self.plots[-1].setYRange(-0.0002, 0.0002)
            self.plotWidget.nextRow()
        
        self.plotWidget.show()
        
    def setServer(self):
        ''' open dialog to set server address
        e.g. localhost, 192.168.1.5
        '''
        text, ok = QInputDialog.getText(self, "Set server",
                'Enter server adress')
        if ok:
            self.server.host = text
            
    def newSession(self):
        ''' create new session:
        - clear dock
        - open dialog to set session parameters
        - create showSessionMeta, showRunMeta, kinectRecorder
        '''
        self.clearDock()
        
        sessionDialog = SessionDialog(self)
        if sessionDialog.exec_():
            newpath = os.path.join(sessionDialog.ui.leDir.text(), sessionDialog.ui.leName.text()) 
            if not os.path.isdir(newpath):
                os.makedirs(newpath)
            else:
                print('reusing folder')
                QMessageBox.information(self, 'Warning!', '''You\'re reusing the subject folder''',
            QMessageBox.Ok)
                
            self.session = Session(sessionDialog.ui.leName.text(),
                                   sessionDialog.ui.teBemerkung.toPlainText(),
                                   newpath)
            self.showSessionMeta = sessionView(self.session, self)
            self.showRunMeta = RunWidget(self)
            self.showRunMeta.ui.leCurrentRun.setText(str(len(self.session.runs)))
            
            try:
                self.kinectRecorder=KinectRecorder()
            except:
                print "no Kinect recording"
                self.kinectRecorder = None
                                        
            self.showSessionMeta.ui.showBemerkung.textChanged.connect(self.pendingSave)
            self.showRunMeta.ui.lwRuns.itemDoubleClicked.connect(self.openPlotter)
            self.dockLayout.addWidget(self.showSessionMeta)
            self.dockLayout.addWidget(self.showRunMeta)
            
            self.showRunMeta.show()
            self.showSessionMeta.show()
            self.preparePlots()
            self.ui.tbStart.setEnabled(True)
    
    def pendingSave(self):
        self.notSavedState = True
        self.setWindowTitle("PyTrigno(*)")
        
    def save(self):
        self.notSavedState = False
        self.setWindowTitle("PyTrigno")
        self.session.remarks = self.showSessionMeta.ui.showBemerkung.toPlainText()
        self.session.dump("ReadMe.txt")
        
    def startRun(self):
        ''' start a recording:
         - setup server
         - setup timer (if no eternity is toggled)
         - setup progress bar
         - setup buttons
         - setup session
         - start recorder
        '''
        #setup server
        self.server.exitFlag = False
        try:
            self.startTime = datetime.now()
            self.server.start()
        except:
            print("something went wrong")
            self.server.exitFlag = True
            raise socket.timeout("Could not connect to Delsys Station")
        else:
            if self.showRunMeta.ui.cbEternity.checkState() == 0:
                duration = self.showRunMeta.ui.timeEdit.time()
                d = duration.second() + duration.minute()*60
                
                self.runPinger.start(d*1000)
                self.ui.elapsedTime.setRange(0,d)
            elif self.showRunMeta.ui.cbEternity.checkState() == 2:
                self.ui.elapsedTime.setRange(0,0)
            
            self.pinger.start()
            
            self.ui.tbStop.setEnabled(True)
            self.ui.tbTrigger.setEnabled(True)
            self.ui.tbStart.setEnabled(False)
            
            name = self.showRunMeta.ui.leCurrentRun.text()
            self.session.addRun(name)
            if self.kinectRecorder is not None:
                self.kinectRecorder.startRecording(self.newpath+'\\'+name+'.oni')            
            self.ui.elapsedTime.setRange(0,d)
    
    def stop(self):
        ''' stop recording due to button press or timeout
        - setup buttons
        - stop timers
        - stop server
        - kill kinectRecorder
        - add item to list of runs
        '''
        self.ui.tbStop.setEnabled(False)
        self.ui.tbTrigger.setEnabled(False)
        self.ui.tbStart.setEnabled(True)
        self.ui.elapsedTime.reset()
        
        QListWidgetItem(self.showRunMeta.ui.leCurrentRun.text(),
                        self.showRunMeta.ui.lwRuns)
        
        self.showRunMeta.ui.leCurrentRun.setText(str(len(self.session.runs)))
        self.server.exitFlag = True
        self.server.stop()

        self.runPinger.stop()
        self.pinger.stop()
        
        self.session.stopRun(self.server.buffer)
        self.server.buffer = None
        if self.kinectRecorder is not None:
            self.kinectRecorder.stopRecording()
        self.server.flush()
        
    def trigger(self):
        ''' add a trigger '''
        print("trigger")
        trigger = self.server.buffer[0].shape[1]
        self.session.addTrigger(trigger)
        
    def ping(self):
        ''' update progress bar and plots everytime
        new data is available 
        '''
        elapsed = int((datetime.now()-self.startTime).total_seconds())
        self.ui.elapsedTime.setValue(elapsed)
        
        for p in range(len(self.plots)):
            if self.server.buffer[0].shape[1] < 5000:
                self.plots[p].plot(self.server.buffer[0][p], clear=True)
            else:
                self.plots[p].plot(self.server.buffer[0][p,-5000:], clear=True)
    
    def openPlotter(self, item=None):
        if self.plotter is None:
            self.plotter = Plotter()
        if item is not None:
            self.plotter.load([os.path.join(self.session.dir, item.text()) + ".pk"])
        self.plotter.show()
        
    def closeEvent(self, event):
        if self.notSavedState:
            reply = QMessageBox.question(self, 'QMessageBox.question()',
                                            'Do you want to first save the current session?',
                                            QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel)
        else:
            reply = QMessageBox.No

        if reply == QMessageBox.Yes:
            self.save()
        elif reply == QMessageBox.Cancel:
            event.ignore()
            return
      
        if not self.server.exitFlag:
            self.stop()
        event.accept()
Exemplo n.º 50
0
class Quiz(QFrame):
    def __init__(self, parent=None):
        super(Quiz, self).__init__(parent)
        """Session Info"""
        self.status = QFrame()
        ##session message
        self.status.message = QLabel(u'')
        self.status.layout = QHBoxLayout()
        self.status.layout.addWidget(self.status.message)
        self.status.setLayout(self.status.layout)
        ##mouse event filter
        #self.status.filter = StatusFilter()
        self.status.setAttribute(Qt.WA_Hover, True)
        #self.status.installEventFilter(self.status.filter)
        """Items Info"""
        self.info = QFrame()
        self.info.reading = QLabel(u'')
        self.info.item = QLabel(u'')
        self.info.components = QLabel(u'')

        self.info.translation = QLabel(u'')
        self.info.translation.setAlignment(Qt.AlignCenter)
        self.info.translation.setWordWrap(True)

        #        separator_one = QFrame()
        #        separator_one.setFrameShape(QFrame.HLine)
        #        separator_one.setFrameShadow(QFrame.Sunken)
        #
        #        separator_two = QFrame()
        #        separator_two.setFrameShape(QFrame.HLine)
        #        separator_two.setFrameShadow(QFrame.Sunken)

        self.info.layout = QVBoxLayout()
        self.info.layout.addWidget(self.info.translation)
        #        self.info.layout.addWidget(self.info.reading)
        #        self.info.layout.addWidget(separator_one)
        #        self.info.layout.addWidget(self.info.item)
        #        self.info.layout.addWidget(separator_two)
        #        self.info.layout.addWidget(self.info.components)
        self.info.setLayout(self.info.layout)
        """Verbose Info"""
        self.allInfo = QFrame()
        self.allInfo.layout = QGridLayout()
        self.allInfo.setLayout(self.allInfo.layout)
        #the rest is (should be) generated on the fly
        """Global Flags"""
        #self.correct = False
        """Quiz Dialog"""
        self.filter = Filter()
        ####    visual components    ###
        self.countdown = QProgressBar()
        self.sentence = QLabel(u'')

        #        self.var_1st = QPushButton(u'')
        #        self.var_2nd = QPushButton(u'')
        #        self.var_3rd = QPushButton(u'')
        #        self.var_4th = QPushButton(u'')

        self.isKnown = QPushButton(u'Good')
        self.isNotKnown = QPushButton(u'Again')

        self.answered = QPushButton(u'')
        self.answered.hide()

        ###    layouts    ####
        self.layout_vertical = QVBoxLayout()  #main
        self.layout_horizontal = QHBoxLayout()  #buttons

        #        self.layout_horizontal.addWidget(self.var_1st)
        #        self.layout_horizontal.addWidget(self.var_2nd)
        #        self.layout_horizontal.addWidget(self.var_3rd)
        #        self.layout_horizontal.addWidget(self.var_4th)

        self.layout_horizontal.addWidget(self.isKnown)
        self.layout_horizontal.addWidget(self.isNotKnown)

        self.layout_vertical.addWidget(self.countdown)
        self.layout_vertical.addWidget(self.sentence)
        self.layout_vertical.addLayout(self.layout_horizontal)

        self.layout_horizontal.addWidget(self.answered)

        self.setLayout(self.layout_vertical)

        ###    utility components    ###
        self.trayIcon = QSystemTrayIcon(self)
        self.trayMenu = QMenu()

        self.gifLoading = QMovie('../res/cube.gif')
        self.gifLoading.frameChanged.connect(self.updateTrayIcon)

        self.nextQuizTimer = QTimer()
        self.nextQuizTimer.setSingleShot(True)
        self.nextQuizTimer.timeout.connect(self.showQuiz)

        self.countdownTimer = QTimer()
        self.countdownTimer.setSingleShot(True)
        self.countdownTimer.timeout.connect(self.timeIsOut)

        ### initializing ###
        self.initializeResources()
        """Start!"""
        if self.options.isQuizStartingAtLaunch():
            self.waitUntilNextTimeslot()
            self.trayIcon.setToolTip('Quiz has started automatically!')
            self.pauseAction.setText('&Pause')
            self.trayIcon.showMessage(
                'Loading complete! (took ~' + str(self.loadingTime.seconds) +
                ' seconds) Quiz underway.', 'Lo! Quiz already in progress!',
                QSystemTrayIcon.MessageIcon.Warning, 10000)
        else:
            self.trayIcon.setToolTip('Quiz is not initiated!')
            self.trayIcon.showMessage(
                'Loading complete! (took ~' + str(self.loadingTime.seconds) +
                ' seconds) Standing by.',
                'Quiz has not started yet! If you wish, you could start it manually or enable autostart by default.',
                QSystemTrayIcon.MessageIcon.Information, 10000)
        """Test calls here:"""
        ###    ...    ###
        #self.connect(self.hooker, SIGNAL('noQdict'), self.noQdict)

    def noQdict(self):
        self.showSessionMessage(
            'Nope, cannot show quick dictionary during actual quiz.')

####################################
#    Initialization procedures     #
####################################

    def initializeResources(self):
        """Pre-initialization"""
        self.animationTimer = ()
        self.progressTimer = ()
        self.grid_layout = ()
        """Initialize Options"""
        self.options = Options()
        """Initialize Statistics"""
        self.stats = Stats()
        """Config Here"""
        self.initializeComposition()
        self.initializeComponents()
        self.setMenus()
        self.trayIcon.show()
        #self.startTrayLoading()
        """"Initialize Dictionaries    (will take a some time!)"""
        time_start = datetime.now()
        self.dict = EdictParser()
        self.dict.loadDict()

        self.morphy = get_morph(PATH_TO_RES + DICT_EN)

        self.trayIcon.showMessage(
            'Loading...', 'Initializing dictionaries',
            QSystemTrayIcon.MessageIcon.Information,
            20000)  #TODO: change into loading dialog... or not
        """Initializing srs system"""
        self.trayIcon.showMessage('Loading...', 'Initializing databases',
                                  QSystemTrayIcon.MessageIcon.Information,
                                  20000)
        self.srs = srsScheduler()
        self.srs.initializeAll()
        self.srs.initializeCurrentSession(self.options.getSessionSize())
        """Global hotkeys hook"""
        #TODO: add multiple hotkeys and fix stop()
        #self.hooker = GlobalHotkeyManager(toggleQDictFlag, 'Q')
        #        self.hooker = GlobalHotkeyManager(toggleWidgetFlag(self.qdict), 'Q')
        #        self.hooker.setDaemon(True) #temporarily, should work using stop()
        #        self.hooker.start()

        time_end = datetime.now()
        self.loadingTime = time_end - time_start

####################################
#    Composition and appearance    #
####################################

    def initializeComposition(self):
        """Main Dialog"""
        self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
        self.setFocusPolicy(Qt.StrongFocus)
        self.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
        #Font will appear in buttons
        self.setFont(
            QFont(self.options.getQuizFont(), self.options.getQuizFontSize()))

        desktop = QApplication.desktop().screenGeometry()
        self.setGeometry(
            QRect(desktop.width() - H_INDENT,
                  desktop.height() - V_INDENT, D_WIDTH, D_HEIGHT))

        self.setStyleSheet("QWidget { background-color: rgb(255, 255, 255); }")
        """Info dialog"""
        self.info.setWindowFlags(Qt.FramelessWindowHint
                                 | Qt.WindowStaysOnTopHint)
        self.info.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
        self.info.setGeometry(
            QRect(desktop.width() - H_INDENT - I_WIDTH - I_INDENT,
                  desktop.height() - V_INDENT, I_WIDTH, I_HEIGHT))
        self.info.setFixedSize(I_WIDTH, I_HEIGHT)

        self.info.setStyleSheet(
            "QWidget { background-color: rgb(255, 255, 255); }")
        """Verbose info dialog"""
        self.allInfo.setWindowFlags(Qt.FramelessWindowHint
                                    | Qt.WindowStaysOnTopHint)
        self.allInfo.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
        self.allInfo.setGeometry(
            QRect(desktop.width() - H_INDENT - I_WIDTH - I_INDENT,
                  desktop.height() - V_INDENT, I_WIDTH, I_HEIGHT))

        self.allInfo.setStyleSheet(
            "QWidget { background-color: rgb(255, 255, 255); }")
        """Session message"""
        self.status.setWindowFlags(Qt.FramelessWindowHint
                                   | Qt.WindowStaysOnTopHint)
        self.status.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
        self.status.setGeometry(
            QRect(
                desktop.width() - H_INDENT,
                desktop.height() - V_INDENT - S_HEIGHT - S_INDENT -
                S_CORRECTION, S_WIDTH, S_HEIGHT))

        self.status.setStyleSheet(
            "QWidget { background-color: rgb(255, 255, 255); }")

        self.setMask(roundCorners(self.rect(), 5))
        self.status.setMask(roundCorners(self.status.rect(), 5))
        #self.info.setMask(roundCorners(self.info.rect(),5))
        #self.allInfo.setMask(roundCorners(self.allInfo.rect(),5))

    def initializeComponents(self):
        self.countdown.setMaximumHeight(6)
        self.countdown.setRange(0, self.options.getCountdownInterval() * 100)
        self.countdown.setTextVisible(False)
        self.countdown.setStyleSheet(
            "QProgressbar { background-color: rgb(255, 255, 255); }")

        #self.setFont(QFont(Fonts.SyoutyouProEl, 40))#self.options.getQuizFontSize()))

        self.sentence.setAlignment(Qt.AlignmentFlag.AlignCenter)
        #self.sentence.setFont(QFont(Fonts.HiragiNoMarugotoProW4, self.options.getSentenceFontSize()))
        self.sentence.setFont(
            QFont(self.options.getSentenceFont(),
                  self.options.getSentenceFontSize()))

        self.sentence.setWordWrap(True)
        self.trayIcon.setIcon(QIcon(PATH_TO_RES + TRAY + 'active.png'))

        self.status.message.setFont(
            QFont('Cambria', self.options.getMessageFontSize()))
        self.status.layout.setAlignment(Qt.AlignCenter)
        self.status.message.setWordWrap(False)
        self.status.layout.setMargin(0)

        self.info.item.setFont(QFont(Fonts.HiragiNoMyoutyouProW3, 36))
        self.info.reading.setFont(QFont(Fonts.HiragiNoMyoutyouProW3, 16))
        self.info.components.setFont((QFont(Fonts.HiragiNoMyoutyouProW3, 14)))
        #self.info.item.setWordWrap(True)
        self.info.components.setWordWrap(True)
        #self.info.layout.setAlignment(Qt.AlignCenter)
        self.info.layout.setMargin(0)
        #self.info.layout.setSizeConstraint(self.info.layout.SetFixedSize)       #NB: would work nice, if the anchor point was in right corner

        self.info.reading.setAlignment(Qt.AlignCenter)
        self.info.item.setAlignment(Qt.AlignCenter)
        self.info.components.setAlignment(Qt.AlignCenter)

        #self.info.setLayoutDirection(Qt.RightToLeft)

        self.info.reading.setStyleSheet(
            "QLabel { color: rgb(155, 155, 155); }")
        self.info.components.setStyleSheet(
            "QLabel { color: rgb(100, 100, 100); }")

        self.info.gem = self.info.saveGeometry()

####################################
#        Updating content          #
####################################

    def updateContent(self):
        """Resetting multi-label sentence"""
        if self.grid_layout != ():
            for i in range(0, self.grid_layout.count()):
                self.grid_layout.itemAt(i).widget().hide()
            self.layout_vertical.removeItem(self.grid_layout)
            self.grid_layout.setParent(None)
            self.update()
        if self.sentence.isHidden():
            self.sentence.show()
        self.showButtonsQuiz()
        """Getting actual content"""
        self.srs.getNextItem()

        start = datetime.now()  #testing
        #example = self.srs.getCurrentExample().replace(self.srs.getWordFromExample(), u"<font color='blue'>" + self.srs.getWordFromExample() + u"</font>")
        example = self.srs.getCurrentExample().replace(
            self.srs.getCurrentItem(),
            u"<font color='blue'>" + self.srs.getCurrentItem() + u"</font>")
        print datetime.now() - start  #testing
        self.sentence.setText(example)

        #        start = datetime.now()  #testing
        #        readings = self.srs.getQuizVariants()
        #        print datetime.now() - start    #testing
        '''
        changeFont = False
        for item in readings:
            if len(item) > 5 : changeFont = True
            
        if changeFont: self.setStyleSheet('QWidget { font-size: 11pt; }')
        else:   self.setStyleSheet('QWidget { font-size: %spt; }' % self.options.getQuizFontSize())
        '''
        '''
        if len(readings) == 4:                  #NB: HERE LIES THE GREAT ERROR
            self.var_1st.setText(readings[0])
            self.var_2nd.setText(readings[1])
            self.var_3rd.setText(readings[2])
            self.var_4th.setText(readings[3])
        '''

#        try:
#            for i in range(0, self.layout_horizontal.count()):
#                    if i > 3: break
#                    self.layout_horizontal.itemAt(i).widget().setText(u'')
#                    #self.layout_horizontal.itemAt(i).setStyleSheet('QPushButton { font-size: 11pt; }')
#                    self.layout_horizontal.itemAt(i).widget().setText(readings[i])
#        except:
#            print 'Not enough quiz variants'
#TODO: log this

    def getReadyPostLayout(self):
        self.sentence.hide()
        self.update()

        self.grid_layout = QGridLayout()
        self.grid_layout.setSpacing(0)
        self.labels = []

        columns_mod = 0

        if len(self.srs.currentExample['eng']) > SENTENCE_MAX:
            font = QFont(self.options.getSentenceFont(), MIN_FONT_SIZE)
            columns_mod = 6
        else:
            font = QFont(self.options.getSentenceFont(),
                         self.options.getSentenceFontSize())

        #row, column, rows span, columns span, max columns
        i = 0
        j = 0
        r = 1
        c = 1
        n = COLUMNS_MAX + columns_mod
        for word in self.srs.parseCurrentExample():
            label = QLabel(word)
            #            label.setFont(QFont(self.options.getSentenceFont(), self.options.getSentenceFontSize()))
            label.setFont(font)

            label.setAttribute(Qt.WA_Hover, True)
            label.installEventFilter(self.filter)
            self.labels.append(label)

            if len(label.text()) > 1: c = len(label.text())
            else: c = 1
            #Don't ask, really
            if j + c > n:
                i = i + 1
                j = 0

            self.grid_layout.addWidget(self.labels.pop(), i, j, r, c)

            if j <= n: j = j + c
            else:
                j = 0
                i = i + 1

        self.grid_layout.setAlignment(Qt.AlignCenter)
        self.layout_vertical.insertLayout(1, self.grid_layout)

        self.update()

    def hideButtonsQuiz(self):
        self.isKnown.hide()
        self.isNotKnown.hide()

        self.answered.clicked.connect(self.hideQuizAndWaitForNext)
        self.answered.show()

    def showButtonsQuiz(self):
        self.isKnown.show()
        self.isNotKnown.show()

        self.answered.hide()
        self.answered.disconnect()

####################################
#        Timers and animations     #
####################################

    def waitUntilNextTimeslot(self):
        #if self.nextQuizTimer.isActive():   self.nextQuizTimer.stop()
        self.nextQuizTimer.start(
            self.options.getRepetitionInterval() * 60 * 1000
        )  #options are in minutes    NB: how do neatly I convert minutes to ms?

    def beginCountdown(self):
        self.trayIcon.setToolTip('Quiz in progress!')
        self.pauseAction.setText('&Pause')
        self.pauseAction.setShortcut('P')

        self.countdownTimer.start(self.options.getCountdownInterval() * 1000)

        self.progressTimer = RepeatTimer(
            0.01, self.updateCountdownBar,
            self.options.getCountdownInterval() * 100)
        self.progressTimer.start()

    def updateCountdownBar(self):
        self.countdown.setValue(self.countdown.value() - 1)
        #print self.countdown.value()
        self.countdown.update(
        )  #NB: without .update() recursive repaint crushes qt

    def fade(self):
        if self.windowOpacity() == 1:
            self.animationTimer = RepeatTimer(0.025, self.fadeOut, 40)
            self.animationTimer.start()
        else:
            self.animationTimer = RepeatTimer(0.025, self.fadeIn, 40)
            self.animationTimer.start()

    def fadeIn(self):
        self.setWindowOpacity(self.windowOpacity() + 0.1)

    def fadeOut(self):
        self.setWindowOpacity(self.windowOpacity() - 0.1)

    def stopCountdown(self):
        self.progressTimer.cancel()
        self.countdownTimer.stop()
        self.countdown.setValue(0)

####################################
#        Actions and events        #
####################################

    def setMenus(self):
        self.trayMenu.addAction(
            QAction('&Quiz me now!',
                    self,
                    shortcut="Q",
                    triggered=self.showQuiz))
        self.pauseAction = QAction('&Start quiz!',
                                   self,
                                   shortcut="S",
                                   triggered=self.pauseQuiz)
        self.trayMenu.addAction(self.pauseAction)
        self.trayMenu.addSeparator()
        self.trayMenu.addAction(
            QAction('Quick &dictionary',
                    self,
                    shortcut="D",
                    triggered=self.showQuickDict))
        self.trayMenu.addAction(
            QAction('&Global &statistics',
                    self,
                    shortcut="G",
                    triggered=self.showGlobalStatistics))
        self.trayMenu.addAction(
            QAction('&Options', self, shortcut="O",
                    triggered=self.showOptions))
        self.trayMenu.addAction(
            QAction('&About', self, shortcut="A", triggered=self.showAbout))
        self.trayMenu.addSeparator()
        self.trayMenu.addAction(
            QAction('&Exit', self, shortcut="E", triggered=self.saveAndExit))

        self.trayIcon.setContextMenu(self.trayMenu)
        self.trayIcon.activated.connect(self.onTrayIconActivated)

    #TODO: show session statistics
    def onTrayIconActivated(self, reason):
        '''
        if reason == QSystemTrayIcon.DoubleClick:
            print 'tray icon double clicked'
        '''
        if reason == QSystemTrayIcon.Trigger:
            if self.isHidden():
                self.trayIcon.showMessage(
                    'Current session statistics:',
                    'Running time:\t\t' + self.stats.getRunningTime() +
                    '\nItems seen:\t\t' + str(self.stats.totalItemSeen) +
                    '\nCorrect answers:\t\t' +
                    str(self.stats.answeredCorrect) + '\nWrong answers:\t\t' +
                    self.stats.getIncorrectAnswersCount() +
                    '\nCorrect ratio:\t\t' +
                    self.stats.getCorrectRatioPercent() +
                    #'\nQuiz total time:\t\t' + self.stats.getQuizActive() +
                    '\nQuiz paused time:\t\t' + self.stats.getPausedTime() +
                    '\nTotal pondering time:\t' + self.stats.getMusingsTime() +
                    '\nTotal post-quiz time:\t' + self.stats.getQuizTime() +
                    '\nAverage pondering:\t' +
                    self.stats.getAverageMusingTime() +
                    '\nAverage post-quiz:\t' +
                    self.stats.getAveragePostQuizTime(),
                    QSystemTrayIcon.MessageIcon.Information,
                    20000)

    def setButtonsActions(self):
        self.isKnown.clicked.connect(self.correctAnswer)
        self.isNotKnown.clicked.connect(self.wrongAnswer)

    def resetButtonsActions(self):
        self.isKnown.disconnect()
        self.isNotKnown.disconnect()

    def postAnswerActions(self):
        self.stats.musingsStopped()
        self.stats.postQuizStarted()

        self.stopCountdown()
        self.hideButtonsQuiz()

        self.getReadyPostLayout()

    def checkTranslationSize(self, translation):
        if len(translation) > TRANSLATION_CHARS_LIMIT:
            self.answered.setStyleSheet('QPushButton { font-size: 9pt; }')

            space_indices = [
                i for i, value in enumerate(translation) if value == ' '
            ]
            find_nearest_index = lambda value, list: min(
                list, key=lambda x: abs(x - value))
            nearest_index = find_nearest_index(TRANSLATION_CHARS_LIMIT,
                                               space_indices)
            translation = translation[:nearest_index] + '\n' + translation[
                nearest_index + 1:]
        else:
            self.answered.setStyleSheet('QPushButton { font-size: 11pt; }')

        self.answered.setText(translation)

    def correctAnswer(self):
        '''
        self.stats.musingsStopped()
        self.stats.postQuizStarted()
        
        self.stopCountdown()
        self.hideButtonsQuiz()
        
        self.getReadyPostLayout()
        '''
        self.postAnswerActions()

        self.srs.answeredCorrect()
        self.stats.quizAnsweredCorrect()
        #self.answered.setText(u"<font='Cambria'>" + self.srs.getCurrentSentenceTranslation() + "</font>")
        #        self.answered.setText(self.srs.getCurrentSentenceTranslation())

        self.checkTranslationSize(self.srs.getCurrentSentenceTranslation())

        #self.answered.setFont(QFont('Calibri', 11))
        self.showSessionMessage(
            u'<font color=green>Correct: OK</font>\t|\tNext quiz: ' +
            self.srs.getNextQuizTime() + '\t|\t<font color=' +
            self.srs.getLeitnerGradeAndColor()['color'] + '>Grade: ' +
            self.srs.getLeitnerGradeAndColor()['grade'] + ' (' +
            self.srs.getLeitnerGradeAndColor()['name'] + ')<font>')

        #self.answered.setShortcut('5')
        #self.setFocus()

    def wrongAnswer(self):
        '''
        self.stats.musingsStopped()
        self.stats.postQuizStarted()
        
        self.stopCountdown()
        self.hideButtonsQuiz()
        
        self.getReadyPostLayout()
        '''
        self.postAnswerActions()

        self.srs.answeredWrong()
        self.stats.quizAnsweredWrong()

        #        self.answered.setText(self.srs.getCurrentSentenceTranslation())

        self.checkTranslationSize(self.srs.getCurrentSentenceTranslation())

        #self.answered.setFont(QFont('Calibri', 11))
        #self.showSessionMessage(u"Wrong! Should be: <font style='font-family:" + Fonts.MSMyoutyou + "'>"
        #+ self.srs.getCorrectAnswer() + "</font> - Next quiz: " + self.srs.getNextQuizTime())
        self.showSessionMessage(
            u'<font color=tomato>Bad</font>\t|\tNext quiz: ' +
            self.srs.getNextQuizTime() + '\t|\t<font color=' +
            self.srs.getLeitnerGradeAndColor()['color'] + '>Grade: ' +
            self.srs.getLeitnerGradeAndColor()['grade'] + ' (' +
            self.srs.getLeitnerGradeAndColor()['name'] + ')<font>')

    def timeIsOut(self):
        self.stats.musingsStopped()
        self.stats.postQuizStarted()

        QTimer.singleShot(
            50, self.hideButtonsQuiz
        )  #NB: slight artificial lag to prevent recursive repaint crush, when mouse is suddenly over appearing button
        self.getReadyPostLayout()

        self.srs.answeredWrong()
        self.stats.quizAnsweredWrong()

        #self.showSessionMessage(u'Time is out! Correct answer is:' + self.srs.getCorrectAnswer())
        #        self.answered.setFont(QFont('Calibri', 11))
        #        self.answered.setText(self.srs.getCurrentSentenceTranslation())

        self.checkTranslationSize(self.srs.getCurrentSentenceTranslation())

        self.showSessionMessage(
            u'<font color=tomato>Timeout!</font>\t|\tNext quiz: ' +
            self.srs.getNextQuizTime() + '\t|\t<font color=' +
            self.srs.getLeitnerGradeAndColor()['color'] + '>Grade: ' +
            self.srs.getLeitnerGradeAndColor()['grade'] + ' (' +
            self.srs.getLeitnerGradeAndColor()['name'] + ')<font>')

    def hideQuizAndWaitForNext(self):
        self.stats.postQuizEnded()

        self.status.hide()
        self.info.hide()
        self.allInfo.hide()
        self.resetButtonsActions()

        self.setWindowOpacity(1)
        self.fade()
        QTimer.singleShot(1000, self.hide)
        self.waitUntilNextTimeslot()
        #self.updater.mayUpdate = True

    def pauseQuiz(self):
        if self.isHidden():
            if self.pauseAction.text() == '&Pause':
                self.nextQuizTimer.stop()
                self.pauseAction.setText('&Unpause')
                self.pauseAction.setShortcut('U')
                self.trayIcon.setToolTip('Quiz paused!')

                self.trayIcon.setIcon(
                    QIcon(PATH_TO_RES + TRAY + 'inactive.png'))
                self.stats.pauseStarted()

                #self.updater.mayUpdate = True

            elif self.pauseAction.text() == '&Start quiz!':
                self.waitUntilNextTimeslot()
                self.pauseAction.setText('&Pause')
                self.pauseAction.setShortcut('P')
                self.trayIcon.setToolTip('Quiz in progress!')

                self.trayIcon.setIcon(QIcon(PATH_TO_RES + TRAY + 'active.png'))
            else:
                self.waitUntilNextTimeslot()
                self.pauseAction.setText('&Pause')
                self.pauseAction.setShortcut('P')
                self.trayIcon.setToolTip('Quiz in progress!')

                self.trayIcon.setIcon(QIcon(PATH_TO_RES + TRAY + 'active.png'))
                self.stats.pauseEnded()

                #self.updater.mayUpdate = False
        else:
            self.showSessionMessage(
                u'Sorry, cannot pause while quiz in progress!')

    def showQuiz(self):
        if self.isHidden():
            self.updateContent()
            self.setButtonsActions()

            self.show()
            self.setWindowOpacity(0)
            self.fade()

            self.countdown.setValue(self.options.getCountdownInterval() * 100)
            self.beginCountdown()
            self.stats.musingsStarted()

            if self.nextQuizTimer.isActive(): self.nextQuizTimer.stop()
            #self.updater.mayUpdate = False
        else:
            self.showSessionMessage(u'Quiz is already underway!')

    def showOptions(self):
        self.optionsDialog.show()

    def showAbout(self):
        self.about.show()

    def showQuickDict(self):
        self.qdict.showQDict = True

    def showGlobalStatistics(self):
        print '...'

    def startTrayLoading(self):
        self.gifLoading.start()
        #self.iconTimer = QTimer()
        #self.iconTimer.timeout.connect(self.updateTrayIcon)
        #self.iconTimer.start(100)

    def stopTrayLoading(self):
        self.gifLoading.stop()

    def updateTrayIcon(self):
        self.trayIcon.setIcon(self.gifLoading.currentPixmap())

    def showSessionMessage(self, message):
        """Shows info message"""
        self.status.message.setText(message)
        self.status.show()
        #self.setFocus() #NB: does not work

    def saveAndExit(self):
        self.hide()
        self.status.hide()
        self.allInfo.hide()
        self.trayIcon.showMessage('Shutting down...', 'Saving session',
                                  QSystemTrayIcon.MessageIcon.Information,
                                  20000)
        #self.startTrayLoading()

        if self.countdownTimer.isActive():
            self.countdownTimer.stop()
        if self.nextQuizTimer.isActive():
            self.nextQuizTimer.stop()
        if self.progressTimer != () and self.progressTimer.isAlive():
            self.progressTimer.cancel()

        self.srs.endCurrentSession()
        self.trayIcon.hide()

        #        self.hooker.stop()

        #self.updater.stop()
        self.optionsDialog.close()
        self.about.close()
        #self.qdict.close()
        self.close()

    def addReferences(self, about, options, qdict, updater):
        self.about = about
        self.optionsDialog = options
        self.qdict = qdict
        self.updater = updater

    def initGlobalHotkeys(self):
        def toggleWidgetFlag():
            self.qdict.showQDict = True

        self.hooker = GlobalHotkeyManager(toggleWidgetFlag, 'Q')
        self.hooker.setDaemon(True)
        self.hooker.start()
Exemplo n.º 51
0
class MediaView(QObject):
    started_signal = Signal()
    finished_signal = Signal()

    def __init__(self, media, parent):
        super(MediaView, self).__init__(parent)
        self._parent = parent
        self._id = media['id']
        self._type = media['type']
        self._duration = media['duration']
        self._render = media['render']
        self._options = media['options']
        self._raws = media['raws']

        self._layout_id = media['_layout_id']
        self._schedule_id = media['_schedule_id']
        self._region_id = media['_region_id']
        self._save_dir = media['_save_dir']

        self._widget = None
        self._play_timer = QTimer(self)

        self._started = 0
        self._finished = 0

        self._errors = None
        # self.setObjectName('Media-%s-%s' % (self._type, self._id))
        # self._play_timer.setObjectName('%s-timer' % self.objectName())
        self._connect_signals()

    def _connect_signals(self):
        self.started_signal.connect(self.mark_started)
        self.finished_signal.connect(self.mark_finished)
        self._play_timer.setSingleShot(True)
        self.connect(self._play_timer, SIGNAL("timeout()"), self.stop)

    @staticmethod
    def make(media, parent):
        if 'type' not in media:
            return None

        if 'image' == media['type']:
            view = ImageMediaView(media, parent)
        elif 'video' == media['type']:
            view = VideoMediaView(media, parent)
        else:
            view = WebMediaView(media, parent)

        return view

    @Slot()
    def play(self):
        pass

    @Slot()
    def stop(self, delete_widget=False):
        if self.is_finished():
            return False
        if self._widget:
            tries = 10
            while tries > 0 and not self._widget.close():
                tries -= 1
                time.sleep(0.05)
            if delete_widget:
                del self._widget
                self._widget = None

        self.finished_signal.emit()
        return True

    @Slot()
    def mark_started(self):
        self._started = time.time()

    @Slot()
    def mark_finished(self):
        if not self.is_finished():
            self._finished = time.time()
            self._parent.queue_stats('media', self._started, self._finished,
                                     self._schedule_id, self._layout_id,
                                     self._id)

    def is_started(self):
        return self._started > 0

    def is_finished(self):
        return self._finished > 0

    def is_playing(self):
        return self.is_started() and not self.is_finished()

    def set_default_widget_prop(self):
        if self._widget is not None:
            self._widget.setAttribute(Qt.WA_DeleteOnClose, False)
            self._widget.setFocusPolicy(Qt.NoFocus)
            self._widget.setContextMenuPolicy(Qt.NoContextMenu)
            self._widget.setObjectName('%s-widget' % self.objectName())
Exemplo n.º 52
0
class MainView(QGraphicsView):
    """Graphic representation of a user created circuit schematic."""

    def __init__(self, parent):
        super(MainView, self).__init__(parent)
        self.setAcceptDrops(True)       # Accept dragged items.
        self.setMouseTracking(True)     # Allow mouseover effects.
        self.setDragMode(QGraphicsView.RubberBandDrag)  # rubber select
        self.setScene(QGraphicsScene(parent))
        self.isDrawing = False          # user currently not drawing
        self.mainCircuit = Circuit("Main", None)
        self.timer = QTimer()
        """A timer for forcing redraws."""
        self.timer.setInterval(200)
        self.timer.setSingleShot(True)
        self.timer.timeout.connect(self.setItemsInGrid)
        self.copyBuffer = None
        """A buffer for ctrl-c, ctrl-v copy operations."""
        self.clockPlug = None

    def batchRename(self):
        """Experimental function to rename multiple items at once."""
        sel = self.scene().selectedItems()
        if (
                not all([isinstance(i, sel[0].__class__) for i in sel])
                or (isinstance(sel[0].data, Plug)
                    and not all([
                        i.data.isInput == sel[0].data.isInput for i in sel]))):
            print("Error")
            return
        ret = QInputDialog.getText(self, "Set prefix", "Prefix :")
        if ret[1] and len(ret[0]):
            for i in self.scene().selectedItems():
                i.data.generate_name(None, ret[0])
                i.setupPaint()
        self.parent().optionsDock.widget().updateOptions()

    def clearCircuit(self):
        """Clears every item from the circuit designer."""
        for i in self.scene().items():
            # https://bugreports.qt-project.org/browse/PYSIDE-252
            if not isinstance(i, QGraphicsSimpleTextItem):
                self.scene().removeItem(i)
        if self.bgClockThread:
            self.bgClockThread.stop()
        self.mainCircuit.clear()

    def clockUpdate(self):
        """Updates the view at each clock tick."""
        for item in self.scene().items():
            if isinstance(item, PlugItem) or isinstance(item, WireItem):
                item.setupPaint()

    def closeEvent(self, e):
        """Overload in order to kill the clock thread."""
        if self.bgClockThread is not None:
            self.bgClockThread.exit()

    def contextMenuEvent(self, e):
        """Pops a contextual menu up on right-clicks"""
        item = self.itemAt(e.pos())
        if item:
            menu = QMenu(self)
            if isinstance(item, CircuitItem):
                pos = item.mapFromScene(self.mapToScene(e.pos()))
                plug = item.handleAtPos(pos)
                item = plug if plug else item
                menu.addAction(self.str_setName, lambda: self.getNewName(item))
            elif isinstance(item, PlugItem):
                if isinstance(item.data, Clock):
                    thread = item.data.clkThread
                    if thread.paused:
                        menu.addAction(
                            self.str_startClock, lambda: thread.unpause())
                    else:
                        menu.addAction(
                            self.str_pauseClock, lambda: thread.pause())
                menu.addAction(self.str_setName, lambda: self.getNewName(item))
                if item.data.isInput:
                    menu.addAction(
                        str(item.data.value), item.setAndUpdate)
            elif isinstance(item, WireItem):
                pos = item.mapFromScene(self.mapToScene(e.pos()))
                if item.handleAtPos(pos):
                    menu.addAction(
                        self.str_removeLast, lambda: item.removeLast())
            menu.popup(e.globalPos())

    def dragEnterEvent(self, e):
        """Accept drag events coming from ToolBox."""
        if isinstance(e.source(), ToolBox):
            e.accept()
        else:       # Refuse all other drags.
            e.ignore()

    def dragLeaveEvent(self, e):
        """Fixes bug: items are half dragged over self, then away. (#16)"""
        e.ignore()

    def dragMoveEvent(self, e):
        """Accept drag move events."""
        e.accept()

    def dropEvent(self, e):
        """Accept drop events."""
        model = QStandardItemModel()
        model.dropMimeData(
            e.mimeData(), Qt.CopyAction, 0, 0, QModelIndex())
        name = model.item(0).text()
        item = None
        if name in ['And', 'Or', 'Nand', 'Nor', 'Not', 'Xor', 'Xnor']:
            item = CircuitItem(
                getattr(engine.gates, name + 'Gate')(None, self.mainCircuit))
        elif name == 'RSFlipFlop':
            item = CircuitItem(RSFlipFlop(None, self.mainCircuit))
        elif name == 'JKFlipFlop':
            item = CircuitItem(JKFlipFlop(None, self.mainCircuit))
        elif name == self.str_I:
            item = PlugItem(Plug(True, None, self.mainCircuit))
        elif name == self.str_O:
            item = PlugItem(Plug(False, None, self.mainCircuit))
        elif name == self.str_Clock:
            if not self.clockPlug:
                self.clockPlug = Clock(self.mainCircuit)
                self.clockPlug.clkThread.set_extern(self.clockUpdate)
                item = PlugItem(self.clockPlug)
            else:
                self.write(self.str_onlyOneClock)
        elif model.item(0, 1).text() == 'user':
            c = Circuit(None, self.mainCircuit)
            f = open(filePath('user/') + name + '.crc', 'rb')
            children = pickle.load(f)
            f.close()
            for child in children:
                if isinstance(child[0], Plug):
                    child[0].owner = c
                    if child[0].isInput:
                        c.inputList.append(child[0])
                    else:
                        c.outputList.append(child[0])
                elif isinstance(child[0], Circuit):
                    child[0].owner = c
                    c.circuitList.append(child[0])
            c.category = name
            item = CircuitItem(c)
        if item:
            # Fixes the default behaviour of centering the first
            # item added to scene.
            if not len(self.scene().items()):
                self.scene().setSceneRect(0, 0, 1, 1)
            else:
                self.scene().setSceneRect(0, 0, 0, 0)
            self.scene().addItem(item)
            item.setupPaint()
            item.setPos(
                closestGridPoint(item.mapFromScene(self.mapToScene(e.pos()))))
            for i in self.scene().selectedItems():
                i.setSelected(False)
            item.setSelected(True)
            self.timer.start()

    def fillIO(self):
        """Experimental function to add as many global I/Os as still needed
        by the main circuit.
        """
        for item in self.scene().items():
            if isinstance(item, CircuitItem):
                pos = item.pos()
                rot = item.rotation()
                circuit = item.data
                off = 0
                for input in circuit.inputList:
                    if not input.sourcePlug:
                        i = PlugItem(Plug(True, None, self.mainCircuit))
                        self.scene().addItem(i)
                        x = (
                            (pos.x() if not rot % 180 else pos.y())
                            - 4 * GRIDSIZE * (1 if not rot % 360 else -1))
                        y = (pos.y() if not rot % 180 else pos.x()) + off
                        i.setPos(x, y)
                        i.setRotation(rot)
                        off += 2 * GRIDSIZE
                off = 0
                for output in circuit.outputList:
                    if not len(output.destinationPlugs):
                        i = PlugItem(Plug(False, None, self.mainCircuit))
                        self.scene().addItem(i)
                        i.setPos(pos.x() + 100, pos.y() + off)
                        off += 30

    def getNewName(self, item):
        """Shows a dialog, and sets item name to user input."""
        # ret = tuple string, bool
        ret = QInputDialog.getText(self, self.str_setName, self.str_name)
        if ret[1] and item.data.setName(ret[0]):    # Not canceled.
            item.update()
        self.parent().optionsDock.widget().updateOptions()

    def keyPressEvent(self, e):
        """Manages keyboard events."""
        scene = self.scene()
        selection = scene.selectedItems()
        # ESC, unselect all items
        if e.key() == Qt.Key_Escape:
            for item in selection:
                item.setSelected(False)
        # Del, suppression
        elif e.key() == Qt.Key_Delete:
            for item in selection:
                if isinstance(item, CircuitItem):
                    self.mainCircuit.remove(item.data)
                elif isinstance(item, Plug):
                    self.mainCircuit.remove(item.data)
                elif (
                        isinstance(item, WireItem)
                        and item.data['endIO'] is not None):
                    item.data['startIO'].disconnect(item.data['endIO'])
                scene.removeItem(item)
        # <- ->, item rotation.
        elif e.key() == Qt.Key_Left or e.key() == Qt.Key_Right:
            self.rotateItems(90 if e.key() == Qt.Key_Right else -90)
        # L, left align and even spacing
        elif e.key() == Qt.Key_L:
            left = min([item.scenePos().x() for item in selection])
            sel = sorted(selection, key=lambda i: i.scenePos().y())
            sel[0].setPos(left, sel[0].scenePos().y())
            for i in range(1, len(sel)):
                sel[i].setPos(
                    left,
                    sel[i - 1].sceneBoundingRect().bottom() + 2 * GRIDSIZE)
        # R, right align and even spacing
        elif e.key() == Qt.Key_R:
            right = max([item.scenePos().x() for item in selection])
            sel = sorted(selection, key=lambda i: i.scenePos().y())
            sel[0].setPos(right, sel[0].scenePos().y())
            for i in range(1, len(sel)):
                sel[i].setPos(
                    right,
                    sel[i - 1].sceneBoundingRect().bottom() + 2 * GRIDSIZE)
        # T, top align and even spacing
        elif e.key() == Qt.Key_T:
            top = min([item.scenePos().y() for item in selection])
            sel = sorted(selection, key=lambda i: i.scenePos().x())
            sel[0].setPos(sel[0].scenePos().x(), top)
            for i in range(1, len(sel)):
                sel[i].setPos(
                    sel[i - 1].sceneBoundingRect().right() + 2 * GRIDSIZE,
                    top)
        # B, bottom align and even spacing
        elif e.key() == Qt.Key_B:
            bottom = max([item.scenePos().y() for item in selection])
            sel = sorted(selection, key=lambda i: i.scenePos().x())
            sel[0].setPos(sel[0].scenePos().x(), bottom)
        # Ctrl-C, copy
        elif e.key() == Qt.Key_C and e.nativeModifiers() == 4:
            self.copyBuffer = copy(selection)
        # Ctrl-V, paste
        elif e.key() == Qt.Key_V and e.nativeModifiers() == 4:
            memo = {}
            for item in self.copyBuffer:
                if isinstance(item, PlugItem):
                    dc = deepcopy(item.data, memo)
                    self.mainCircuit.add(dc)
                    dc.generate_name(None)
                    i = PlugItem(dc)
                elif isinstance(item, CircuitItem):
                    dc = deepcopy(item.data, memo)
                    self.mainCircuit.add(dc)
                    dc.generate_name()
                    i = CircuitItem(dc)
                elif isinstance(item, WireItem):
                    dc = deepcopy(item.data, memo)
                    i = WireItem(dc['startIO'], dc['points'], dc['endIO'])
                self.scene().addItem(i)
                # TODO : +100 et pourquoi 100 et pas pi ou 5000?
                i.setPos(item.pos().x() + 100, item.pos().y() + 100)
                i.setRotation(item.rotation())
                i.setupPaint()
        for item in selection:
            item.setupPaint()

    def mouseMoveEvent(self, e):
        """Redraw CurrentWire; change cursor on mouseOver handles."""
        if self.isDrawing:
            self.currentWire.moveLastPoint(
                self.currentWire.mapFromScene(self.mapToScene(e.pos())))
        item = self.itemAt(e.pos())
        if item:
            pos = item.mapFromScene(self.mapToScene(e.pos()))
            isCircuit = isinstance(item, CircuitItem)
            if isCircuit or isinstance(item, PlugItem):
                handle = item.handleAtPos(pos)
                if handle:
                    if isCircuit:
                        item.setToolTip(handle.name)
                    self.setCursor(Qt.CursorShape.UpArrowCursor)
                    return
                elif isCircuit:
                    item.setToolTip(item.data.name)
            elif (isinstance(item, WireItem) and item.handleAtPos(pos) and
                    not self.isDrawing):
                self.setCursor(Qt.CursorShape.UpArrowCursor)
                return
        self.setCursor(Qt.CursorShape.ArrowCursor)
        super(MainView, self).mouseMoveEvent(e)

    def mousePressEvent(self, e):
        """Start Wire creation/extension."""
        # Reserve right-clicks for contextual menus.
        if e.buttons() == Qt.RightButton:
            super(MainView, self).mousePressEvent(e)
            return
        self.mouseEventStart = None
        item = self.itemAt(e.pos())
        if item:
            pos = item.mapFromScene(self.mapToScene(e.pos()))
            if isinstance(item, CircuitItem) or isinstance(item, PlugItem):
                plug = item.handleAtPos(pos)
                if plug:
                    self.isDrawing = True
                    p = closestGridPoint(self.mapToScene(e.pos()))
                    self.currentWire = WireItem(plug, [p, p])
                    self.scene().addItem(self.currentWire)
                    return   # no super(), prevents dragging/selecting
                elif (
                        isinstance(item, PlugItem) and item.data.isInput
                        and e.modifiers() & Qt.AltModifier):
                    item.setAndUpdate()
                    return
            elif isinstance(item, WireItem):
                if item.handleAtPos(pos):
                    self.currentWire = item
                    self.isDrawing = True
                    return   # no super(), prevents dragging/selecting
        # Didn't click a handle? We wanted to drag or select
        super(MainView, self).mousePressEvent(e)

    def mouseReleaseEvent(self, e):
        """Complete Wire segments. Connect Plugs."""
        # Ignore right-clicks.
        if e.buttons() == Qt.RightButton:
            super(MainView, self).mousePressEvent(e)
            return
        if self.isDrawing:
            self.currentWire.addPoint()
            self.isDrawing = False
            old = self.currentWire.zValue()
            self.currentWire.setZValue(-500000)  # to detect other wires
            item = self.itemAt(e.pos())
            self.currentWire.setZValue(old)
            if item:
                pos = item.mapFromScene(self.mapToScene(e.pos()))
                if isinstance(item, CircuitItem) or isinstance(item, PlugItem):
                    plug = item.handleAtPos(pos)
                    if (plug and
                            self.currentWire.handleAtPos(
                                self.currentWire.mapFromScene(
                                    self.mapToScene(e.pos())))):
                        if not self.currentWire.connect(plug):
                            self.currentWire.revert()
                        return
                elif (
                        isinstance(item, WireItem)
                        and item != self.currentWire and not item.complete):
                    if not self.currentWire.connect(item.data['startIO']):
                        self.currentWire.revert()
                    else:
                        p = self.currentWire.data['points'][-1]
                        points = item.data['points']
                        for i in range(len(points)):
                            a = points[i]
                            b = points[i + 1]
                            if (
                                    distance(a, p) + distance(p, b)
                                    == distance(a, b)):
                                points = points[0:i + 1]
                                points.reverse()
                                break
                        self.currentWire.data['points'].extend(
                            points)
                        self.scene().removeItem(item)
                        self.currentWire.setupPaint()
                        return
                elif isinstance(item, WireItem) and item.complete:
                    p = item.data['startIO']
                    p1 = item.data['endIO']
                    source = p if p1.sourcePlug == p else p1
                    if not self.currentWire.connect(source):
                        self.currentWire.revert()
                    #~ else: # test code
                        #~ print(self.currentWire.data)
            # Ugly hack to solve selection problems with multiple wireitems
            # on the same spot : the smallest area is selected.
            wires = sorted(
                [i for i in self.scene().items() if isinstance(i, WireItem)],
                key=
                lambda i: i.boundingRect().width() * i.boundingRect().height())
            for i in range(len(wires)):
                wires[i].setZValue(-i - 1)

            self.currentWire = None
        super(MainView, self).mouseReleaseEvent(e)

    def rotateItems(self, angle):
        """Rotates the current selection around its gravity center."""
        grp = self.scene().createItemGroup(self.scene().selectedItems())
        br = grp.sceneBoundingRect()
        grp.setTransformOriginPoint(
            br.left() + br.width() / 2, br.top() + br.height() / 2)
        grp.setRotation(grp.rotation() + angle)
        self.scene().destroyItemGroup(grp)
        # The item group doesn't transfer its rotation to its children
        # .setRotation() sets it correctly but rotates the item
        # .rotate() rotates the item back without setting it
        # rotate is deprecated, so this is far from ideal
        for item in self.scene().selectedItems():
            item.setRotation((item.rotation() + angle) % 360)
            item.rotate(-angle)

    def setItemsInGrid(self):
        """Correcting items pos to fit on the grid."""
        for item in self.scene().items():
            item.setPos(closestGridPoint(item.pos()))

    def write(self, message):
        """Briefly display a log WARNING."""
        scene = self.scene()
        msg = scene.addText(message)
        QTimer.singleShot(1500, lambda: scene.removeItem(msg))
class Panel(QWidget):
    def __init__(self,parent=None,instr=None,lock=None,title='Instrument Panel'):
        # This class derivates from a Qt Widget so we have to call
        # the class builder ".__init__()"
        QWidget.__init__(self)
        # "self" is now a Qt Widget, then we load the user interface
        # generated with QtDesigner and call it self.ui
        self.ui = Lakeshore340_Ui.Ui_Panel()
        # Now we have to feed the GUI building method of this object (self.ui)
        # with the current Qt Widget 'self', but the widgets from the design will actually be built as children
        # of the object self.ui
        self.ui.setupUi(self)
        self.setWindowTitle(title)
        self.reserved_access_to_instr=lock
        self.temp_controller=instr
        
        self.check_T_timer = QTimer()
        self.check_T_timer.setSingleShot(True)#The timer would not wait for the completion of the task otherwise
        self.check_T_timer.timeout.connect(self.autocheckT)
        
        if self.ui.checkTbox.isChecked():self.autocheckT()
    
    def checkT(self):
        with self.reserved_access_to_instr:
            T=self.temp_controller.query_temp(self.ui.temp_controller_channel.currentText())
        self.ui.T_display.setText(str(T)+" K")
    
    def autocheckT(self,state=1):
        if state:
            self.checkT()
            self.check_T_timer.start(self.ui.refresh_rate.value()*1000)#The value must be converted to milliseconds
        else:
            self.check_T_timer.stop()
    
    def update_timer_timeout(self,secs):
       self.check_T_timer.setInterval(int(secs*1000))
    
    def set_heater_range(self,value=0):
        if value in range(6): #check compatibility
            with self.reserved_access_to_instr:
                self.temp_controller.set_heater_range(value)
        
    def set_setpoint(self):
        loop=self.ui.temp_controller_loop.value()
        setpoint=self.ui.temp_controller_setpoint.value()
        with self.reserved_access_to_instr:
            #self.temp_controller.switch_ramp(loop,'off')
            self.temp_controller.set_setpoint(loop,setpoint)
        
    def stop_ramp(self):
        loop=self.ui.temp_controller_loop.value()
        with self.reserved_access_to_instr:            
            self.temp_controller.switch_ramp(loop,'off')
                
    def init_ramp(self):
        """After this function is called, the ramp will start the next time the setpoint is changed """
        loop=self.ui.temp_controller_loop.value()
        #setpoint=self.ui.temp_controller_setpoint.value()
        rate=self.ui.temp_controller_ramprate.value()
        with self.reserved_access_to_instr:            
            #self.temp_controller.set_setpoint(loop,setpoint)
            self.temp_controller.conf_ramp(loop,rate,'on')
                
    def PID_P_update(self,new_P_value):
        with self.reserved_access_to_instr:
            P,I,D=self.temp_controller.query_PID(1)            
            self.temp_controller.set_PID(1,new_P_value,I,D)

    def PID_I_update(self,new_I_value):
        with self.reserved_access_to_instr:
            P,I,D=self.temp_controller.query_PID(1)            
            self.temp_controller.set_PID(1,P,new_I_value,D)
            
    def PID_D_update(self,new_D_value):
        with self.reserved_access_to_instr:
            P,I,D=self.temp_controller.query_PID(1)            
            self.temp_controller.set_PID(1,P,I,new_D_value)
Exemplo n.º 54
0
class Thimblerig(QObject):
    """Класс для игры в наперстки в мосваре."""

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

        self._mw = mw

        # Таймер для отсчета раундов игры
        self._timer_round_thimble = QTimer()
        self._timer_round_thimble.setInterval(1000)
        self._timer_round_thimble.setSingleShot(True)
        self._timer_round_thimble.timeout.connect(self.nine_thimble)

        # Таймер для выбора наперстков
        self._timer_thimble = QTimer()
        self._timer_thimble.setInterval(1000)
        self._timer_thimble.timeout.connect(self.select_thimbles)

        # Варианты порядка открытия наперстков
        self._variants = [
            # С первого по третий ряд
            [0, 1, 2],
            [3, 4, 5],
            [6, 7, 8],

            # Диагонально
            [0, 4, 8],
            [6, 4, 2],
        ]

        # Номера наперстков, которые будет открывать бот
        self._thimble1, self._thimble2, self._thimble3 = 0, 0, 0

        self._ruda_count = 0
        self._thimble_round_count = 0

        # Сумма ниже которой играть не будем
        self.min_money = 3000

    finished_thimble_game = Signal()

    def _get_ruda_count(self):
        return self._ruda_count

    def _get_thimble_round_count(self):
        return self._thimble_round_count

    ruda_count = property(_get_ruda_count)

    thimble_round_count = property(_get_thimble_round_count)

    def run(self):
        """Игра в наперстки."""

        try:
            # Если в текущий бот в текущий момент занят и это не игра в Наперстки
            if self._mw._used and 'thimble' not in self._mw.current_url():
                logger.warn('Бот в данный момент занят процессом "%s". Выхожу из функции.', self._mw._used_process)
                return

            self._mw._used_process = "Игра в Наперстки"
            logger.debug('Выполняю задание "%s".', self._mw._used_process)

            self._mw.metro()

            if 'metro' in self._mw.current_url():
                # TODO: временное решение проблемы с закончившимися билетами, лучше через окно сделать
                holders = self._mw.doc.findFirst('.metro-thimble .holders')
                holders = holders.toPlainText().replace('Встреч с Моней на сегодня: ', '')
                if int(holders) == 0:
                    logger.warn('Закончились билеты для игры в Наперстки.')
                    # TODO: добавить is_ready
                    # TODO: is_ready указывает на следующий день
                    return

            self._mw._used = True

            t = time.clock()

            if 'thimble' in self._mw.current_url():
                logger.info('Игра в Наперстки уже была начала, продолжу играть.')
            else:
                # Эмулируем клик на кнопку "Начать играть"
                self._mw.click_tag('.metro-thimble .button .c')

            # # TODO: не работает, т.к. окно не сразу появляется
            # for el in self._mw.doc.findAll('.alert'):
            #     text = el.findFirst('#alert-text')
            #
            #     print(el, text.toPlainText())
            #     if not text.isNull() and 'Вы сегодня уже играли в наперстки с Моней Шацом' in text.toPlainText():
            #         # TODO: добавить is_ready
            #         # TODO: is_ready указывает на следующий день
            #         logger.warn('Закончились билеты для игры в наперстки.')
            #         self._mw._used = False
            #         return

            self._ruda_count = 0
            self._thimble_round_count = 0

            self._timer_round_thimble.start()

            # Ждем пока закончится игра
            loop = QEventLoop()
            self.finished_thimble_game.connect(loop.quit)
            loop.exec_()

            logger.debug('Длительность игры {:.1f} секунд'.format(time.clock() - t))
            logger.debug('Игра в наперстки закончилась за {} раундов'.format(self._thimble_round_count))
            logger.debug('Угадано {} руды. Потрачено {} тугриков.'.format(self._ruda_count,
                                                                          self._thimble_round_count * 1500))
            logger.debug('Удача {:.2f}%'.format(self._ruda_count / (self._thimble_round_count * 3) * 100))

            # Эмулируем клик на кнопку "Я наигрался, хватит"
            self._mw.go('thimble/leave')

        except MoswarClosedError:
            raise

        except Exception as e:
            raise MoswarBotError(e)

        finally:
            self._mw._used = False

    def nine_thimble(self):
        """Функция для начала игры в девять наперстков."""

        if self._mw.money() < self.min_money:
            self._timer_thimble.stop()
            logger.debug("Заканчиваю игру.")
            self.finished_thimble_game.emit()
            return

        self._thimble_round_count += 1

        # Выбираем кнопку для игры в 9 наперстков
        css_path = "#thimble-controls-buttons div[data-count='9']"
        self._mw.click_tag(css_path)

        # Выбираем случайный ряд наперстков
        numbers_thimble = random.choice(self._variants)

        # Порядок кликания на наперстки. Если True, то справа на лево
        right_to_left = random.choice([True, False])

        if right_to_left:
            numbers_thimble.sort(reverse=True)

        self._thimble1, self._thimble2, self._thimble3 = ["#thimble{}".format(i) for i in numbers_thimble]
        logger.info('Порядок открытия наперстков: {}, {}, {}'.format(self._thimble1, self._thimble2, self._thimble3))

        self._timer_thimble.start()

    def _check_click_thimble(self, css_path):
        """Функция, вернет True, если на Наперсток уже кликали."""

        tag = self._mw.doc.findFirst(css_path)
        attr = tag.attribute('class')

        # Проверяем, что на наперсток кликнули
        check = 'guessed' in attr or 'empty' in attr

        logger.info('Проверяем наперсток "%s". Атрибут элемента: "%s". -> "%s".', css_path, attr, check)
        return check

    def select_thimbles(self):
        """Функция для клика на наперстки."""

        doc = self._mw.doc

        # Количество оставшихся попыток. Для девяти наперсток их максимум будет 3
        left = doc.findFirst('#naperstki-left').toInnerXml()

        # Если количество попыток равно 0, то останавливаем таймер клика на наперстки
        if left == '0':
            self._timer_thimble.stop()

            # Получаем количество угаданной за раунд руды
            ruda = doc.findFirst('#naperstki-ruda').toPlainText()
            self._ruda_count += int(ruda)
            logger.info("Раунд {}. Угадано {} руды.".format(self._thimble_round_count, ruda))

            # Запускаем следующий раунд
            self._timer_round_thimble.start()
            return

        # Проверяем, что на наперсток не кликали и кликаем
        if not self._check_click_thimble(self._thimble1):
            self._mw.click_tag(self._thimble1)
        elif not self._check_click_thimble(self._thimble2):
            self._mw.click_tag(self._thimble2)
        elif not self._check_click_thimble(self._thimble3):
            self._mw.click_tag(self._thimble3)
Exemplo n.º 55
0
 def hoverTimer(self):
     ret = QTimer(self.q)
     ret.setInterval(400)
     ret.setSingleShot(False)
     ret.timeout.connect(self._hover)
     return ret
Exemplo n.º 56
0
class QtReactor(posixbase.PosixReactorBase):
    implements(IReactorFDSet)

    def __init__(self):
        self._reads = {}
        self._writes = {}
        self._notifiers = {}
        self._timer = QTimer()
        self._timer.setSingleShot(True)
        QObject.connect(self._timer, SIGNAL("timeout()"), self.iterate)

        if QCoreApplication.instance() is None:
            # Application Object has not been started yet
            self.qApp = QCoreApplication([])
            self._ownApp = True
        else:
            self.qApp = QCoreApplication.instance()
            self._ownApp = False
        self._blockApp = None
        posixbase.PosixReactorBase.__init__(self)

    def _add(self, xer, primary, type):
        """
Private method for adding a descriptor from the event loop.

It takes care of adding it if new or modifying it if already added
for another state (read -> read/write for example).
"""
        if xer not in primary:
            primary[xer] = TwistedSocketNotifier(None, self, xer, type)

    def addReader(self, reader):
        """
Add a FileDescriptor for notification of data available to read.
"""
        self._add(reader, self._reads, QSocketNotifier.Read)

    def addWriter(self, writer):
        """
Add a FileDescriptor for notification of data available to write.
"""
        self._add(writer, self._writes, QSocketNotifier.Write)

    def _remove(self, xer, primary):
        """
Private method for removing a descriptor from the event loop.

It does the inverse job of _add, and also add a check in case of the fd
has gone away.
"""
        if xer in primary:
            notifier = primary.pop(xer)
            notifier.shutdown()

    def removeReader(self, reader):
        """
Remove a Selectable for notification of data available to read.
"""
        self._remove(reader, self._reads)

    def removeWriter(self, writer):
        """
Remove a Selectable for notification of data available to write.
"""
        self._remove(writer, self._writes)

    def removeAll(self):
        """
Remove all selectables, and return a list of them.
"""
        rv = self._removeAll(self._reads, self._writes)
        return rv

    def getReaders(self):
        return self._reads.keys()

    def getWriters(self):
        return self._writes.keys()

    def callLater(self, howlong, *args, **kargs):
        rval = super(QtReactor, self).callLater(howlong, *args, **kargs)
        self.reactorInvocation()
        return rval

    def reactorInvocation(self):
        self._timer.stop()
        self._timer.setInterval(0)
        self._timer.start()

    def _iterate(self, delay=None, fromqt=False):
        """See twisted.internet.interfaces.IReactorCore.iterate.
"""
        self.runUntilCurrent()
        self.doIteration(delay, fromqt)

    iterate = _iterate

    def doIteration(self, delay=None, fromqt=False):
        'This method is called by a Qt timer or by network activity on a file descriptor'

        if not self.running and self._blockApp:
            self._blockApp.quit()
        self._timer.stop()
        delay = max(delay, 1)
        if not fromqt:
            self.qApp.processEvents(QEventLoop.AllEvents, delay * 1000)
        if self.timeout() is None:
            timeout = 0.1
        elif self.timeout() == 0:
            timeout = 0
        else:
            timeout = self.timeout()
        self._timer.setInterval(timeout * 1000)
        self._timer.start()

    def runReturn(self, installSignalHandlers=True):
        self.startRunning(installSignalHandlers=installSignalHandlers)
        self.reactorInvocation()

    def run(self, installSignalHandlers=True):
        if self._ownApp:
            self._blockApp = self.qApp
        else:
            self._blockApp = QEventLoop()
        self.runReturn()
        self._blockApp.exec_()
Exemplo n.º 57
0
class TextEditor(RWWidget, Ui_Form):
    """ Contains many features of popular text editors adapted for use with
    Ontologies such as syntax highlighting, and autocompletion. One column on
    the left of the text editor contains line numbers and another contains
    other contextual information such as whether a block of code has been
    hidden/collapsed and can be displayed/expanded later.  It also contains an
    incremental search and an interface to pySUMO's settings so font size and
    family can be changed at will.

    Variables:

    - syntax_highlighter: The syntax highlighter object for the text editor.

    Methods:
    
    - __init__: Initalizes the Object and the QPlainTextEdit
    - commit: Notifies other Widgets of changes.
    - show_autocomplete: Returns autocompletion choices.
    - getWidget: returns the QPlainTextEdit
    - numberbarPaint: Paints the numberbar
    - searchCompletion: Asks QCompleter if a whole word exists starting with user input
    - hideFrom: Starts hides all lines from the ()-block started by line
    - insertCompletion: Puts the selected Completion into the TextEditor
    """
    def __init__(self, mainwindow, settings=None):
        """ Initializes the text editor widget. """
        super(TextEditor, self).__init__(mainwindow)
        self.setupUi(self.mw)
        self.plainTextEdit.clear()
        self.plainTextEdit.setEnabled(False)
        self.plainTextEdit.show()
        self.highlighter = SyntaxHighlighter(self.plainTextEdit.document(),
                                             settings)
        self.initAutocomplete()

        self._initNumberBar()
        self.hidden = {}
        self.printer = QPrinter(QPrinterInfo.defaultPrinter())
        self.plainTextEdit.setTextCursor(
            self.plainTextEdit.cursorForPosition(QPoint(0, 0)))

        self.canUndo = False
        self.canRedo = False

        self.ontologySelector.setCurrentIndex(-1)

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

        #Connects
        self.getWidget().textChanged.connect(self.searchCompletion)
        self.plainTextEdit.undoAvailable.connect(self.setCanUndo)
        self.plainTextEdit.redoAvailable.connect(self.setCanRedo)

        self.ontologySelector.currentIndexChanged[int].connect(
            self.showOtherOntology)
        self.plainTextEdit.textChanged.connect(self.expandIfBracketRemoved)

        self.plainTextEdit.textChanged.connect(self.setTextChanged)

        self._updateOntologySelector()  #must be after connects

    @Slot()
    def setTextChanged(self):
        """Is called if the text changed signal is thrown and 
        sets a timer of 3 seconds to reparse the ontology. """
        self.timer.stop()
        self.timer.start(3000)

    def setCanUndo(self, b):
        self.canUndo = b

    def setCanRedo(self, b):
        self.canRedo = b

    def _print_(self):
        """ Creates a print dialog with the latest text"""
        dialog = QPrintDialog()
        if dialog.exec_() == QDialog.Accepted:
            doc = self.plainTextEdit.document()
            doc.print_(dialog.printer())

    def _quickPrint_(self):
        """ No dialog, just print"""
        if self.printer is None:
            return
        doc = self.plainTextEdit.document()
        doc.print_(self.printer)

    def _printPreview_(self):
        """ Create a print preview"""
        dialog = QPrintPreviewDialog()
        dialog.paintRequested.connect(self.plainTextEdit.print_)
        dialog.exec_()

    def saveOntology(self):
        """ Save the ontology to disk"""
        idx = self.ontologySelector.currentIndex()
        ontology = self.ontologySelector.itemData(idx)
        if ontology is None:
            return
        if type(ontology) is Ontology:
            ontology.save()

    def getActiveOntology(self):
        idx = self.ontologySelector.currentIndex()
        return self.ontologySelector.itemData(idx)

    def undo(self):
        if self.canUndo:
            self.plainTextEdit.undo()
            try:
                self.SyntaxController.add_ontology(
                    self.getActiveOntology(), self.plainTextEdit.toPlainText())
            except ParseError:
                return
            self.commit()
        else:
            super(TextEditor, self).undo()

    def redo(self):
        if self.canRedo:
            self.plainTextEdit.redo()
            try:
                self.SyntaxController.add_ontology(
                    self.getActiveOntology(), self.plainTextEdit.toPlainText())
            except ParseError:
                return
            self.commit()
        else:
            super(TextEditor, self).redo()

    def _initNumberBar(self):
        """ Init the number bar"""
        self.number_bar = NumberBar(self)
        self.number_bar.setMinimumSize(QSize(30, 0))
        self.number_bar.setObjectName("number_bar")
        self.gridLayout.addWidget(self.number_bar, 1, 0, 1, 1)
        self.plainTextEdit.blockCountChanged.connect(
            self.number_bar.adjustWidth)
        self.plainTextEdit.updateRequest.connect(
            self.number_bar.updateContents)

    @Slot(int)
    def jumpToLocation(self, location, ontology):
        if ontology == str(self.getActiveOntology()):
            textBlock = self.plainTextEdit.document().findBlockByNumber(
                location)
            pos = textBlock.position()
            textCursor = self.plainTextEdit.textCursor()
            textCursor.setPosition(pos)
            self.plainTextEdit.setTextCursor(textCursor)
            self.plainTextEdit.centerCursor()

    def _updateOntologySelector(self):
        """ Update the ontology selector where you can select which Ontology to show in the editor"""
        current = self.ontologySelector.currentText()
        self.ontologySelector.currentIndexChanged[int].disconnect(
            self.showOtherOntology)
        self.ontologySelector.clear()
        index = -1
        count = 0
        for i in self.getIndexAbstractor().ontologies:
            if current == i.name:
                index = count
            self.ontologySelector.addItem(i.name, i)
            count = count + 1
        self.ontologySelector.setCurrentIndex(index)
        # if index == -1 :
        # the ontology was removed.
        #    self.showOtherOntology(index)
        if index == -1:
            self.plainTextEdit.setEnabled(False)
            self.plainTextEdit.clear()
        self.ontologySelector.currentIndexChanged[int].connect(
            self.showOtherOntology)

    def setActiveOntology(self, ontology):
        index = -1
        count = 0
        for i in self.getIndexAbstractor().ontologies:
            if ontology.name == i.name:
                index = count
                break
            count = count + 1
        self.ontologySelector.setCurrentIndex(index)

    @Slot(int)
    def showOtherOntology(self, idx):
        """ Show other ontology in the plaintextedit
            
            Arguments:
            
            - idx: The id of the current Ontologyselector
        """
        dced = False
        try:
            self.plainTextEdit.textChanged.disconnect(self.setTextChanged)
        except RuntimeError:
            dced = True

        idx = self.ontologySelector.currentIndex()

        if idx == -1:
            self.plainTextEdit.setEnabled(False)
            self.plainTextEdit.clear()
            return
        ontologyname = self.ontologySelector.currentText()
        for i in self.getIndexAbstractor().ontologies:
            if i.name == ontologyname:
                self.plainTextEdit.setEnabled(True)
                self.getWidget().setPlainText(
                    self.getIndexAbstractor().get_ontology_file(i).getvalue())

                if not dced:
                    self.plainTextEdit.textChanged.connect(self.setTextChanged)

                return
        self.plainTextEdit.textChanged.connect(self.commit)
        assert False

    @Slot()
    def expandIfBracketRemoved(self):
        """ Check if a line with ( or ) was changed and expand the possible hidden lines   
        """
        current_line = self.getWidget().document().findBlock(
            self.getWidget().textCursor().position()).blockNumber() + 1
        if current_line in self.hidden:
            self.toggleVisibility(current_line)

    @Slot()
    def zoomIn(self):
        """ Increase the size of the font in the TextEditor
        
        """
        doc = self.getWidget().document()
        font = doc.defaultFont()
        font.setPointSize(font.pointSize() + 1)
        font = QFont(font)
        doc.setDefaultFont(font)

    @Slot()
    def zoomOut(self):
        """ Decrease the size of the font in the TextEditor"""
        doc = self.getWidget().document()
        font = doc.defaultFont()
        font.setPointSize(font.pointSize() - 1)
        font = QFont(font)
        doc.setDefaultFont(font)

    @Slot()
    def expandAll(self):
        """ Expands all hidden code blocks"""
        for see in list(self.hidden.keys()):
            self.toggleVisibility(see)

    @Slot()
    def collapseAll(self):
        """ Collapse all code blocks (where possible)"""
        block = self.getWidget().document().firstBlock()
        while block.isValid():
            if block.isVisible():
                if block.text().count("(") > block.text().count(")"):
                    self.toggleVisibility(block.blockNumber() + 1)
            block = block.next()

    def _hideLines(self, lines):
        for line in lines:
            if line == 0:
                continue
            block = self.getWidget().document().findBlockByNumber(line - 1)
            assert block.isVisible()
            block.setVisible(False)
            assert not block.isVisible(), "Problem with line %r" % (line)

    def _showLines(self, lines):
        """ Show the lines not visible starting by lines
        
        Arguments:
        
        - lines: The first line followed by an unvisible block
        
        """
        for line in lines:
            block = self.getWidget().document().findBlockByNumber(line - 1)
            block.setVisible(True)

    def getLayoutWidget(self):
        """ Returns the layout widget"""
        return self.widget

    def numberbarPaint(self, number_bar, event):
        """Paints the line numbers of the code file"""
        self.number_bar.link = []
        font_metrics = self.getWidget().fontMetrics()
        current_line = self.getWidget().document().findBlock(
            self.getWidget().textCursor().position()).blockNumber() + 1

        block = self.getWidget().firstVisibleBlock()
        line_count = block.blockNumber()
        painter = QPainter(self.number_bar)
        # TODO: second argument is color -> to settings
        painter.fillRect(self.number_bar.rect(),
                         self.getWidget().palette().base())

        # Iterate over all visible text blocks in the document.
        while block.isValid():
            line_count += 1
            text = str(line_count)
            block_top = self.getWidget().blockBoundingGeometry(
                block).translated(self.getWidget().contentOffset()).top()
            if not block.isVisible():
                block = block.next()
                while not block.isVisible():
                    line_count += 1
                    block = block.next()
                continue
            self.number_bar.link.append((block_top, line_count))
            # Check if the position of the block is out side of the visible
            # area.
            if block_top >= event.rect().bottom():
                break

            # We want the line number for the selected line to be bold.
            if line_count == current_line:
                font = painter.font()
                font.setBold(True)

            else:
                font = painter.font()
                font.setBold(False)
            # line opens a block
            if line_count in self.hidden:
                text += "+"
                font.setUnderline(True)
            elif block.text().count("(") > block.text().count(")"):
                text += "-"
                font.setUnderline(True)
            else:
                font.setUnderline(False)
            painter.setFont(font)
            # Draw the line number right justified at the position of the
            # line.
            paint_rect = QRect(0, block_top, self.number_bar.width(),
                               font_metrics.height())
            painter.drawText(paint_rect, Qt.AlignLeft, text)
            block = block.next()

        painter.end()

    def initAutocomplete(self):
        """Inits the QCompleter and gives him a list of words"""
        self.completer = QCompleter(
            list(
                OrderedDict.fromkeys(
                    re.split("\\W", self.plainTextEdit.toPlainText()))))
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        self.completer.setWidget(self.getWidget())
        self.completer.activated.connect(self.insertCompletion)

    def searchCompletion(self):
        """Searches for possible completion from QCompleter to the current text position"""
        tc = self.getWidget().textCursor()
        tc.movePosition(QTextCursor.PreviousCharacter, QTextCursor.KeepAnchor)
        if tc.selectedText() in string.whitespace:
            self.completer.popup().hide()
            return
        tc.movePosition(QTextCursor.StartOfWord, QTextCursor.KeepAnchor)

        beginning = tc.selectedText()
        if len(beginning) >= 3:
            self.completer.setCompletionPrefix(beginning)
            self.completer.complete()
        shortcut = QShortcut(QKeySequence("Ctrl+Enter"), self.getWidget(),
                             self.insertCompletion)

    def toggleVisibility(self, line):
        """ Shows or hides a line """
        if line in self.hidden:
            self._showLines(self.hidden[line])
            del self.hidden[line]
        else:
            self.hideFrom(line)

        # update views
        self.getWidget().hide()
        self.getWidget().show()
        self.number_bar.update()

    def hideFrom(self, line):
        """ Hides a block starting by line. Do nothing if not hidable"""
        block = self.getWidget().document().findBlockByNumber(line - 1)

        openB = block.text().count("(")
        closeB = block.text().count(")")
        startline = line
        # go to line >= line: block starts counting by 0
        block = self.getWidget().document().findBlockByNumber(line - 1)
        hidden = []
        assert block.isValid()
        while openB > closeB and block.isValid():
            assert block.isValid()
            block = block.next()
            line = block.blockNumber() + 1
            if block.isVisible():
                hidden.append(line)
            openB += block.text().count("(")
            closeB += block.text().count(")")

        if hidden == []:
            return
        self._hideLines(hidden)
        self.hidden[startline] = hidden

        # set current line in viewable area
        current_line = self.getWidget().document().findBlock(
            self.getWidget().textCursor().position()).blockNumber() + 1
        if (startline < current_line and current_line <= line):
            block = block.next()
            cursor = QTextCursor(block)
            self.getWidget().setTextCursor(cursor)

    @Slot(str)
    def insertCompletion(self, completion):
        """ Adds the completion to current text"""
        tc = self.getWidget().textCursor()
        tc.movePosition(QTextCursor.StartOfWord, QTextCursor.KeepAnchor)
        tc.removeSelectedText()
        tc.insertText(completion)

    def getWidget(self):
        """ Return the QPlainTextEdit Widget"""
        return self.plainTextEdit

    @Slot()
    def commit(self):
        """ Overrides commit from RWWidget. """

        idx = self.ontologySelector.currentIndex()
        if idx == -1:
            return
        ontology = self.ontologySelector.itemData(idx)
        if ontology is None:
            return
        try:
            QApplication.setOverrideCursor(Qt.BusyCursor)
            self.SyntaxController.add_ontology(
                ontology, self.plainTextEdit.toPlainText())
            QApplication.setOverrideCursor(Qt.ArrowCursor)
        except ParseError:
            return
        super(TextEditor, self).commit()

    @Slot()
    def refresh(self):
        """ Refreshes the content of the TextEditor (syncing with other widgets)"""
        textCursorPos = self.plainTextEdit.textCursor().position()
        super(TextEditor, self).refresh()
        dced = False
        try:
            self.plainTextEdit.textChanged.disconnect(self.setTextChanged)
        except RuntimeError:
            dced = True
        idx = self.ontologySelector.currentIndex()
        ontology = self.ontologySelector.itemData(idx)
        if ontology in self.IA.ontologies:
            f = self.IA.get_ontology_file(ontology)
            self.plainTextEdit.setPlainText(f.getvalue())
        if not dced:
            self.plainTextEdit.textChanged.connect(self.setTextChanged)
        cursor = self.plainTextEdit.textCursor()
        cursor.setPosition(textCursorPos)
        self.plainTextEdit.setTextCursor(cursor)
        self.plainTextEdit.centerCursor()