Example #1
0
 def start_ss(self):
     self.timer = QTimer()
     self.timer.timeout.connect(self.update_img)
     self.timer.start(self.slide_delay * 1000)
     self.ss_timer = QTimer()
     self.ss_timer.timeout.connect(self.update_img)
     self.ss_timer.start(60000)
Example #2
0
    def shutdown(self, status=0):
        """Try to shutdown everything cleanly.

        For some reason lastWindowClosing sometimes seem to get emitted twice,
        so we make sure we only run once here.

        Args:
            status: The status code to exit with.
        """
        if self._shutting_down:
            return
        self._shutting_down = True
        log.destroy.debug("Shutting down with status {}...".format(status))
        deferrer = False
        for win_id in objreg.window_registry:
            prompter = objreg.get('prompter', None, scope='window',
                                  window=win_id)
            if prompter is not None and prompter.shutdown():
                deferrer = True
        if deferrer:
            # If shutdown was called while we were asking a question, we're in
            # a still sub-eventloop (which gets quitted now) and not in the
            # main one.
            # This means we need to defer the real shutdown to when we're back
            # in the real main event loop, or we'll get a segfault.
            log.destroy.debug("Deferring real shutdown because question was "
                              "active.")
            QTimer.singleShot(0, functools.partial(self._shutdown, status))
        else:
            # If we have no questions to shut down, we are already in the real
            # event loop, so we can shut down immediately.
            self._shutdown(status)
Example #3
0
class GUI_Timer(QMainWindow):
    def __init__(self):
        super(QMainWindow, self).__init__()
        self.ui = Ui_ToF_Timer()
        self.ui.setupUi(self)
        self.timer = QTimer(self);
        self.timer.timeout.connect(self.update)
        self.timer.start(1000);
        
    def update(self):
        ok = False
        A = findWindow("Measurement Progress")
        if len(A)>0:
            B = findWindow(C="Edit", parent=A[0])
            if len(B)>0:
                AnalTime = int(getText(B[2]).replace(",",""))
                TotScans = int(getText(B[1]).replace(",",""))
                Scans = int(getText(B[0]).replace(",",""))
                self.ui.label_2.setText("Scans: {} / {}".format(Scans, TotScans));
                self.ui.label_3.setText("Analysis Time: {} s".format(AnalTime));
                self.ui.progressBar.setValue(Scans);
                self.ui.progressBar.setMaximum(TotScans);
                ok = True
        if not ok:
            self.ui.label.setText("Remaining time: Unavailable (measurement not in progress?)")
            return
        if Scans>0:
            r = AnalTime*(TotScans-Scans)/Scans;
            h = int(r//3600)
            m = int((r-h*3600)//60)
            s = int(r-h*3600-m*60)
            self.ui.label.setText("Remaining time: {:02d}:{:02d}:{:02d}".format(h,m,s));
        else:
            self.ui.label.setText("Remaining time: Unknown");
Example #4
0
    def extract(self, location: Location, directory_watcher, stdio) -> Optional[ArchiveExtractor]:
        extractor = self._extractors.get(location, None)
        if extractor is not None:
            return extractor  # extraction already running or queued

        outdir = self._make_extractor_outdir(location)

        if not os.path.isdir(outdir):
            extractor = ArchiveExtractor(stdio.get_stdio_name(location.origin()), outdir)
            self._extractors[location] = extractor
            extractor.sig_started.connect(lambda extractor:
                                          self._on_archive_extractor_started(extractor))
            extractor.sig_finished.connect(lambda extractor, d=directory_watcher:
                                           self._on_archive_extractor_finished(extractor, d))

            if self.get_running_extractor_count() < self._max_extractors:
                extractor.start()
            else:
                self._queued_extractors.append(extractor)

            return extractor
        else:
            status_file = os.path.join(outdir, "status.json")
            status = ExtractorStatus.from_file(status_file)

            if status.status() == ExtractorResult.FAILURE:
                def send_message(dw=directory_watcher, message=status.message()):
                    dw.sig_message.emit(status.message())

                # FIXME: this is a bit of a crude hack to
                # communicate the message to the user
                QTimer.singleShot(0, send_message)
                logger.error("%s: archive exist, but is broken: %s", location, status.message())

            return None
Example #5
0
 def test_normal_exec(self):
     """Test exec_ without double-executing."""
     self.loop = qtutils.EventLoop()
     QTimer.singleShot(100, self._assert_executing)
     QTimer.singleShot(200, self.loop.quit)
     self.loop.exec_()
     assert not self.loop._executing
Example #6
0
 def __send(self, fx, lang, fn, data):
     """
     Private method to send a job request to one of the clients.
     
     @param fx remote function name to execute (str)
     @param lang language to connect to (str)
     @param fn filename for identification (str)
     @param data function argument(s) (any basic datatype)
     """
     connection = self.connections.get(lang)
     if connection is None:
         if fx != 'INIT':
             # Avoid growing recursion deep which could itself result in an
             # exception
             QTimer.singleShot(
                 0,
                 lambda: self.serviceNotAvailable.emit(
                     fx, lang, fn, self.tr(
                         '{0} not configured.').format(lang)))
         # Reset flag and continue processing queue
         self.isWorking = None
         self.__processQueue()
     else:
         packedData = json.dumps([fx, fn, data])
         if sys.version_info[0] == 3:
             packedData = bytes(packedData, 'utf-8')
         header = struct.pack(
             b'!II', len(packedData), adler32(packedData) & 0xffffffff)
         connection.write(header)
         connection.write(packedData)
Example #7
0
 def on_newConnection(self):
     """
     Private slot for new incomming connections from the clients.
     """
     connection = self.nextPendingConnection()
     if not connection.waitForReadyRead(1000):
         return
     lang = connection.read(64)
     if sys.version_info[0] == 3:
         lang = lang.decode('utf-8')
     # Avoid hanging of eric on shutdown
     if self.connections.get(lang):
         self.connections[lang].close()
     if self.isWorking == lang:
         self.isWorking = None
     self.connections[lang] = connection
     connection.readyRead.connect(
         lambda x=lang: self.__receive(x))
     connection.disconnected.connect(
         lambda x=lang: self.on_disconnectSocket(x))
         
     for (fx, lng), args in self.services.items():
         if lng == lang:
             # Register service with modulepath and module
             self.enqueueRequest('INIT', lng, fx, args[:2])
     
     # Syntax check the open editors again
     try:
         vm = e5App().getObject("ViewManager")
     except KeyError:
         return
     for editor in vm.getOpenEditors():
         if editor.getLanguage() == lang:
             QTimer.singleShot(0, editor.checkSyntax)
Example #8
0
 def mouseMoveEvent(self, evt):
     """
     Protected method to handle mouse move events.
     
     @param evt reference to the mouse move event (QMouseEvent)
     """
     if self.count() == 1:
         return
     
     E5WheelTabBar.mouseMoveEvent(self, evt)
     
     if Preferences.getHelp("ShowPreview"):
         # Find the tab under the mouse
         i = 0
         tabIndex = -1
         while i < self.count() and tabIndex == -1:
             if self.tabRect(i).contains(evt.pos()):
                 tabIndex = i
             i += 1
         
         # If found and not the current tab then show tab preview
         if tabIndex != -1 and \
            tabIndex != self.currentIndex() and \
            self.__currentTabPreviewIndex != tabIndex and \
            evt.buttons() == Qt.NoButton:
             self.__currentTabPreviewIndex = tabIndex
             QTimer.singleShot(200, self.__showTabPreview)
         
         # If current tab or not found then hide previous tab preview
         if tabIndex == self.currentIndex() or \
            tabIndex == -1:
             if self.__previewPopup is not None:
                 self.__previewPopup.hide()
             self.__currentTabPreviewIndex = -1
Example #9
0
    def search(self, text, flags):
        """Search for text in the current page.

        Args:
            text: The text to search for.
            flags: The QWebPage::FindFlags.
        """
        log.webview.debug("Searching with text '{}' and flags "
                          "0x{:04x}.".format(text, int(flags)))
        widget = self.currentWidget()
        old_scroll_pos = widget.scroll_pos
        found = widget.findText(text, flags)
        if not found and not flags & QWebPage.HighlightAllOccurrences and text:
            message.error(self._win_id, "Text '{}' not found on "
                          "page!".format(text), immediately=True)
        else:
            backward = int(flags) & QWebPage.FindBackward

            def check_scroll_pos():
                """Check if the scroll position got smaller and show info."""
                if not backward and widget.scroll_pos < old_scroll_pos:
                    message.info(self._win_id, "Search hit BOTTOM, continuing "
                                 "at TOP", immediately=True)
                elif backward and widget.scroll_pos > old_scroll_pos:
                    message.info(self._win_id, "Search hit TOP, continuing at "
                                 "BOTTOM", immediately=True)
            # We first want QWebPage to refresh.
            QTimer.singleShot(0, check_scroll_pos)
Example #10
0
 def __finish(self):
     """
     Private slot called when the process finished or the user pressed
     the button.
     """
     if self.process is not None and \
        self.process.state() != QProcess.NotRunning:
         self.process.terminate()
         QTimer.singleShot(2000, self.process.kill)
         self.process.waitForFinished(3000)
     
     self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
     self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
     self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
     
     self.inputGroup.setEnabled(False)
     self.inputGroup.hide()
     
     if len(self.changeListsDict) == 0:
         self.changeLists.addItem(self.tr("No changelists found"))
         self.buttonBox.button(QDialogButtonBox.Close).setFocus(
             Qt.OtherFocusReason)
     else:
         self.changeLists.addItems(sorted(self.changeListsDict.keys()))
         self.changeLists.setCurrentRow(0)
         self.changeLists.setFocus(Qt.OtherFocusReason)
Example #11
0
    def __init__(self, filepath=None):
        QObject.__init__(self)
        QTimer.singleShot(0, self.__launchTimerTimedOut)
        self.prefs = Preferences()
        self.prefs.load()
        global APP_PREFS
        APP_PREFS = self.prefs
        locale = QLocale.system()
        dateFormat = self.prefs.dateFormat
        decimalSep = locale.decimalPoint()
        groupingSep = locale.groupSeparator()
        cachePath = QStandardPaths.standardLocations(QStandardPaths.CacheLocation)[0]
        DateEdit.DATE_FORMAT = dateFormat
        self.model = MoneyGuruModel(
            view=self, date_format=dateFormat, decimal_sep=decimalSep,
            grouping_sep=groupingSep, cache_path=cachePath
        )
        self.mainWindow = MainWindow(app=self)
        self.preferencesPanel = PreferencesPanel(self.mainWindow, app=self)
        self.aboutBox = AboutBox(self.mainWindow, self)
        self.initialFilePath = None
        if filepath and op.exists(filepath):
            self.initialFilePath = filepath
        elif self.prefs.recentDocuments:
            self.initialFilePath = self.prefs.recentDocuments[0]

        self.finishedLaunching.connect(self.applicationFinishedLaunching)
        QCoreApplication.instance().aboutToQuit.connect(self.applicationWillTerminate)
Example #12
0
    def load(self, name, temp=False):
        """Load a named session.

        Args:
            name: The name of the session to load.
            temp: If given, don't set the current session.
        """
        path = self._get_session_path(name, check_exists=True)
        try:
            with open(path, encoding='utf-8') as f:
                data = yaml.load(f, Loader=YamlLoader)
        except (OSError, UnicodeDecodeError, yaml.YAMLError) as e:
            raise SessionError(e)
        log.sessions.debug("Loading session {} from {}...".format(name, path))
        for win in data['windows']:
            window = mainwindow.MainWindow(geometry=win['geometry'])
            window.show()
            tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                        window=window.win_id)
            tab_to_focus = None
            for i, tab in enumerate(win['tabs']):
                new_tab = tabbed_browser.tabopen()
                self._load_tab(new_tab, tab)
                if tab.get('active', False):
                    tab_to_focus = i
            if tab_to_focus is not None:
                tabbed_browser.setCurrentIndex(tab_to_focus)
            if win.get('active', False):
                QTimer.singleShot(0, tabbed_browser.activateWindow)
        self.did_load = True
        if not name.startswith('_') and not temp:
            self._current = name
Example #13
0
    def newScreenshot(self):
        if self.hideThisWindowCheckBox.isChecked():
            self.hide()
        self.newScreenshotButton.setDisabled(True)

        QTimer.singleShot(self.delaySpinBox.value() * 1000,
                self.shootScreen)
Example #14
0
class NPGPull(ZMQPull):

    def __init__(self, host, port, imgModel, table, opts, flags):
        ZMQPull.__init__(self, host, port, opts=[], flags=flags)
        self.socketTimer = QTimer()
        self.socketTimer.timeout.connect(self.receive)
        self.imgModel = imgModel
        self.table = table

    def start(self):
        self.connect()
        self.socketTimer.start(100)

    def stop(self):
        self.close()
        self.socketTimer.stop()

    def receive(self):

        try:
            data = self.puller.recv_json(flags=zmq.NOBLOCK)
            fn = str(data['fn'].strip())
            path = str(data['path'])
            index = int(data['index'])
            total = int(data['total'])
            N = int(data['processed'])
            hit = int(data['hit'])
            self.imgModel.updateData(fn, path, int(index))
            self.table.progress((total, N, hit))
            return
        except zmq.error.Again:
            return
Example #15
0
 def __finish(self):
     """
     Private slot called when the process finished or the user pressed
     the button.
     """
     if self.process is not None and \
        self.process.state() != QProcess.NotRunning:
         self.process.terminate()
         QTimer.singleShot(2000, self.process.kill)
         self.process.waitForFinished(3000)
     
     self.inputGroup.setEnabled(False)
     self.inputGroup.hide()
     
     self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
     self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
     self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
     self.buttonBox.button(QDialogButtonBox.Close).setFocus(
         Qt.OtherFocusReason)
     
     if self.patchesList.topLevelItemCount() == 0:
         # no patches present
         self.__generateItem(
             0, "", self.tr("no patches found"), "", True)
     self.__resizeColumns()
     self.__resort()
Example #16
0
    def execute(self):
        if not self.timer.isActive() or self.is_date_changed:
            QTimer.singleShot(500, self.setTime)
            self.timer.stop()

        index = self.ui.countryList.currentIndex()
        ctx.installData.timezone = self.ui.countryList.itemData(index)
        ctx.logger.debug("Time zone selected as %s " % ctx.installData.timezone)

        if ctx.flags.install_type == ctx.STEP_BASE:
            #FIXME:Refactor hacky code
            ctx.installData.rootPassword = ctx.consts.default_password
            ctx.installData.hostName = yali.util.product_release()
            if ctx.storageInitialized:
                disks = filter(lambda d: not d.format.hidden, ctx.storage.disks)
                if len(disks) == 1:
                    ctx.storage.clearPartDisks = [disks[0].name]
                    ctx.mainScreen.step_increment = 2
                else:
                    ctx.mainScreen.step_increment = 1
                return True
            else:
                self.pds_messagebox.setMessage(_("Storage Devices initialising..."))
                self.pds_messagebox.animate(start=MIDCENTER, stop=MIDCENTER)
                ctx.mainScreen.step_increment = 0
                self.pthread.start()
                QTimer.singleShot(2, self.startStorageInitialize)
                return False

        return True
 def __init__(self):
     """
     Constructor
     """
     super(SnapshotFreehandGrabber, self).__init__(
         None,
         Qt.X11BypassWindowManagerHint | Qt.WindowStaysOnTopHint |
         Qt.FramelessWindowHint | Qt.Tool)
     
     self.__selection = QPolygon()
     self.__mouseDown = False
     self.__newSelection = False
     self.__handleSize = 10
     self.__showHelp = True
     self.__grabbing = False
     self.__dragStartPoint = QPoint()
     self.__selectionBeforeDrag = QPolygon()
     self.__locale = QLocale()
     
     self.__helpTextRect = QRect()
     self.__helpText = self.tr(
         "Select a region using the mouse. To take the snapshot,"
         " press the Enter key or double click. Press Esc to quit.")
     
     self.__pixmap = QPixmap()
     self.__pBefore = QPoint()
     
     self.setMouseTracking(True)
     
     QTimer.singleShot(200, self.__initialize)
Example #18
0
def startShellGui(workflow_cmdline_args, preinit_funcs, postinit_funcs):
    """
    Create an application and launch the shell in it.
    """

    """
    The next two lines fix the following xcb error on Ubuntu by calling X11InitThreads before loading the QApplication:
       [xcb] Unknown request in queue while dequeuing
       [xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
       [xcb] Aborting, sorry about that.
       python: ../../src/xcb_io.c:178: dequeue_pending_request: Assertion !xcb_xlib_unknown_req_in_deq failed.
    """
    platform_str = platform.platform().lower()
    if 'ubuntu' in platform_str or 'fedora' in platform_str or 'debian' in platform_str:
        QApplication.setAttribute(Qt.AA_X11InitThreads, True)

    if ilastik.config.cfg.getboolean("ilastik", "debug"):
        QApplication.setAttribute(Qt.AA_DontUseNativeMenuBar, True)

    app = QApplication([])
    _applyStyleSheet(app)

    splashScreen.showSplashScreen()
    app.processEvents()
    QTimer.singleShot( 0, functools.partial(launchShell, workflow_cmdline_args, preinit_funcs, postinit_funcs ) )
    QTimer.singleShot( 0, splashScreen.hideSplashScreen)

    return app.exec_()
Example #19
0
    def _setup(self):
        core.pe.photo.PLAT_SPECIFIC_PHOTO_CLASS = PlatSpecificPhoto
        self._setupActions()
        self._update_options()
        self.recentResults = Recent(self, 'recentResults')
        self.recentResults.mustOpenItem.connect(self.model.load_from)
        self.resultWindow = None
        self.details_dialog = None
        self.directories_dialog = DirectoriesDialog(self)
        self.progress_window = ProgressWindow(self.directories_dialog, self.model.progress_window)
        self.problemDialog = ProblemDialog(parent=self.directories_dialog, model=self.model.problem_dialog)
        self.ignoreListDialog = IgnoreListDialog(parent=self.directories_dialog, model=self.model.ignore_list_dialog)
        self.deletionOptions = DeletionOptions(parent=self.directories_dialog, model=self.model.deletion_options)
        self.about_box = AboutBox(self.directories_dialog, self)

        self.directories_dialog.show()
        self.model.load()

        self.SIGTERM.connect(self.handleSIGTERM)

        # The timer scheme is because if the nag is not shown before the application is
        # completely initialized, the nag will be shown before the app shows up in the task bar
        # In some circumstances, the nag is hidden by other window, which may make the user think
        # that the application haven't launched.
        QTimer.singleShot(0, self.finishedLaunching)
Example #20
0
    def _click(self, elem, context):
        """Click an element.

        Args:
            elem: The QWebElement to click.
            context: The HintContext to use.
        """
        target_mapping = {
            Target.normal: usertypes.ClickTarget.normal,
            Target.current: usertypes.ClickTarget.normal,
            Target.tab_fg: usertypes.ClickTarget.tab,
            Target.tab_bg: usertypes.ClickTarget.tab_bg,
            Target.window: usertypes.ClickTarget.window,
            Target.hover: usertypes.ClickTarget.normal,
        }
        if config.get('tabs', 'background-tabs'):
            target_mapping[Target.tab] = usertypes.ClickTarget.tab_bg
        else:
            target_mapping[Target.tab] = usertypes.ClickTarget.tab
        # FIXME Instead of clicking the center, we could have nicer heuristics.
        # e.g. parse (-webkit-)border-radius correctly and click text fields at
        # the bottom right, and everything else on the top left or so.
        # https://github.com/The-Compiler/qutebrowser/issues/70
        pos = elem.rect_on_view().center()
        action = "Hovering" if context.target == Target.hover else "Clicking"
        log.hints.debug("{} on '{}' at {}/{}".format(
            action, elem, pos.x(), pos.y()))
        self.start_hinting.emit(target_mapping[context.target])
        if context.target in [Target.tab, Target.tab_fg, Target.tab_bg,
                              Target.window]:
            modifiers = Qt.ControlModifier
        else:
            modifiers = Qt.NoModifier
        events = [
            QMouseEvent(QEvent.MouseMove, pos, Qt.NoButton, Qt.NoButton,
                        Qt.NoModifier),
        ]
        if context.target != Target.hover:
            events += [
                QMouseEvent(QEvent.MouseButtonPress, pos, Qt.LeftButton,
                            Qt.LeftButton, modifiers),
                QMouseEvent(QEvent.MouseButtonRelease, pos, Qt.LeftButton,
                            Qt.NoButton, modifiers),
            ]

        if context.target in [Target.normal, Target.current]:
            # Set the pre-jump mark ', so we can jump back here after following
            tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                        window=self._win_id)
            tabbed_browser.set_mark("'")

        if context.target == Target.current:
            elem.remove_blank_target()
        for evt in events:
            self.mouse_event.emit(evt)
        if elem.is_text_input() and elem.is_editable():
            QTimer.singleShot(0, functools.partial(
                elem.webFrame().page().triggerAction,
                QWebPage.MoveToEndOfDocument))
        QTimer.singleShot(0, self.stop_hinting.emit)
Example #21
0
    def wait(self, time_ms, callback, onredirect=None, onerror=None):
        """
        Wait for time_ms, then run callback.

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

        If onerror is True then the timer is cancelled if a render error
        happens. If onerror is callable then in case of a render error the
        timer is cancelled and this callable is called.
        """
        timer = QTimer()
        timer.setSingleShot(True)
        timer_callback = functools.partial(self._on_wait_timeout,
            timer=timer,
            callback=callback,
        )
        timer.timeout.connect(timer_callback)

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

        timer.start(time_ms)
        self._active_timers.add(timer)
        if onredirect:
            self._timers_to_cancel_on_redirect[timer] = onredirect
        if onerror:
            self._timers_to_cancel_on_error[timer] = onerror
Example #22
0
    def loadSettings(self, firstTime):
        qsettings   = QSettings()
        websettings = self.ui.webview.settings()

        self.fSavedSettings = {
            # WebView
            MOD_KEY_WEBVIEW_INSPECTOR:      qsettings.value(MOD_KEY_WEBVIEW_INSPECTOR,      MOD_DEFAULT_WEBVIEW_INSPECTOR,      type=bool),
            MOD_KEY_WEBVIEW_SHOW_INSPECTOR: qsettings.value(MOD_KEY_WEBVIEW_SHOW_INSPECTOR, MOD_DEFAULT_WEBVIEW_SHOW_INSPECTOR, type=bool)
        }

        inspectorEnabled = self.fSavedSettings[MOD_KEY_WEBVIEW_INSPECTOR] and not USING_LIVE_ISO

        websettings.setAttribute(QWebSettings.DeveloperExtrasEnabled, inspectorEnabled)

        if firstTime:
            self.restoreGeometry(qsettings.value("Geometry", ""))

            if inspectorEnabled and self.fSavedSettings[MOD_KEY_WEBVIEW_SHOW_INSPECTOR]:
                QTimer.singleShot(1000, self.ui.webinspector.show)

        self.ui.act_file_inspect.setVisible(inspectorEnabled)

        if self.fIdleTimerId != 0:
            self.killTimer(self.fIdleTimerId)

        self.fIdleTimerId = self.startTimer(MOD_DEFAULT_MAIN_REFRESH_INTERVAL)
Example #23
0
    def cancel(self):
        self.widget.hide()
        self.busy.show()

        self.actionLabel.setText(i18n("<b>Cancelling operation...</b>"))
        self.disableCancel()
        QTimer.singleShot(100, self.iface.cancel)
Example #24
0
    def __init__(self, sc_state):
        super(SC_QtGUIModule, self).__init__(sc_state, "qt_gui", "qt_gui module")
        self.__app = QApplication([])
        
        self.mapWidget = MapWidget()
        self.mapWidget.show()

        self.__dashboardDialog = DashboardDialog(self.sc_state)
        self.__dashboardDialog.show()

        #periodic updates...
        self.__updater = QTimer()
        self.__updater.setInterval(500)
        self.__updater.timeout.connect(self.time_to_update)
        self.__updater.start();

        #more frequent updates...
        self.__updaterFrequent = QTimer()
        self.__updaterFrequent.setInterval(40)
        self.__updaterFrequent.timeout.connect(self.time_to_update_frequent)
        self.__updaterFrequent.start();

        #zoom to default location:
        self.mapWidget.zoomTo(16, 35.716888, -120.7646408)

        #slots
        self.mapWidget.getView().just_selected_uav.connect(self.on_uav_select)
    def test_collector(self):
        app = QApplication([])

        try:
            vfs = StdioFilesystem("/tmp")
            metadata_collector = MetaDataCollector(vfs)

            def on_metadata(filename, metadata):
                print(filename)
                print(metadata)
                print()

            metadata_collector.sig_metadata_ready.connect(on_metadata)

            metadata_collector.request_metadata(Location.from_path("dirtools/fileview/icons/noun_409399_cc.png"))

            QTimer.singleShot(500, metadata_collector.close)
            QTimer.singleShot(1500, app.quit)

            app.exec()
        except Exception as err:
            print(err)
        finally:
            metadata_collector.close()
            vfs.close()
            def cb_import_extract(result):
                script_instance = script_instance_ref[0]

                if script_instance != None:
                    aborted = script_instance.abort
                else:
                    aborted = False

                script_instance_ref[0] = None

                if aborted:
                    return

                if not report_script_result(result, 'Import Error', 'Could not extract archive',
                                            before_message_box=self.progress.close):
                    return

                def cb_restart_reboot_shutdown(result):
                    self.progress.close()

                    report_script_result(result, 'Import Error', 'Could not reboot RED Brick to finish program import')

                # step 4/4: reboot
                self.progress.setLabelText('Step 4 of 4: Rebooting RED Brick')
                self.progress.setRange(0, 0)

                self.script_manager.execute_script('restart_reboot_shutdown_systemd',
                                                   cb_restart_reboot_shutdown, ['1'])

                def close_progress():
                    # use a closure to capture self and ansure that it's safe
                    # to call this even if the tab was official destroyed already
                    self.progress.close()

                QTimer.singleShot(1500, close_progress)
Example #27
0
 def __init__(self, emacs_xid, minibuffer_height):
     super(TrayView, self).__init__()
     self.emacs_xid = int(emacs_xid)
     self.minibuffer_height = int(minibuffer_height)
     
     self.setWindowFlags(Qt.FramelessWindowHint)
     self.setAttribute(Qt.WA_TranslucentBackground, True)
     self.setAttribute(Qt.WA_TransparentForMouseEvents, True)
     self.setAttribute(Qt.WA_ShowWithoutActivating, True)
     self.setContentsMargins(0, 0, 0, 0)
     self.setFocusPolicy(Qt.NoFocus)
     
     self.update_time_timer = QTimer()
     self.update_time_timer.timeout.connect(self.update_time)
     self.update_time_timer.start(1000)
     
     self.update_cursor_pos_timer = QTimer()
     self.update_cursor_pos_timer.timeout.connect(self.update_cursor_pos)
     self.update_cursor_pos_timer.start(10)
     
     self.time_string = self.get_current_time()
     self.pos_string = ""
     self.percent_string = ""
     self.info_string = ""
     self.info_width = 0
     self.padding = 3
     self.font = QtGui.QFont()
     
     self.minibuffer_x = 0
     self.minibuffer_y = 0
     self.minibuffer_w = 0
     self.minibuffer_h = 0
Example #28
0
    def play(self, fromStart=True, force=False):
        item = self.targetObject()

        # If the item that this animation controls in currently under the
        # control of another animation, stop that animation first.
        if item.currentAnimation is not None:
            item.currentAnimation.stop()

        item.currentAnimation = self

        if Colors.noAnimations and not force:
            # If animations are disabled just move to the end position.
            item.setPos(self.endValue())
        else:
            if self.isVisible():
                # If the item is already visible, start the animation from the
                # item's current position rather than from the start.
                self.setStartValue(item.pos())

            if fromStart:
                self.setCurrentTime(0)
                item.setPos(self.startValue())

        if self._inOrOut == DemoItemAnimation.ANIM_IN:
            item.setRecursiveVisible(True)

        if not Colors.noAnimations or force:
            if self._startDelay:
                QTimer.singleShot(self._startDelay, self.start)
            else:
                self.start()
Example #29
0
    def _call_cb(self, callback, found, text, flags, caller):
        """Call the given callback if it's non-None.

        Delays the call via a QTimer so the website is re-rendered in between.

        Args:
            callback: What to call
            found: If the text was found
            text: The text searched for
            flags: The flags searched with
            caller: Name of the caller.
        """
        found_text = 'found' if found else "didn't find"
        # Removing FindWrapsAroundDocument to get the same logging as with
        # QtWebEngine
        debug_flags = debug.qflags_key(
            QWebPage, flags & ~QWebPage.FindWrapsAroundDocument,
            klass=QWebPage.FindFlag)
        if debug_flags != '0x0000':
            flag_text = 'with flags {}'.format(debug_flags)
        else:
            flag_text = ''
        log.webview.debug(' '.join([caller, found_text, text, flag_text])
                          .strip())
        if callback is not None:
            QTimer.singleShot(0, functools.partial(callback, found))
Example #30
0
    def slot_handlePatchbayClientAddedCallback(self, clientId, clientIcon, pluginId, clientName):
        pcSplit = patchcanvas.SPLIT_UNDEF
        pcIcon  = patchcanvas.ICON_APPLICATION

        if clientIcon == PATCHBAY_ICON_PLUGIN:
            pcIcon = patchcanvas.ICON_PLUGIN
        if clientIcon == PATCHBAY_ICON_HARDWARE:
            pcIcon = patchcanvas.ICON_HARDWARE
        elif clientIcon == PATCHBAY_ICON_CARLA:
            pass
        elif clientIcon == PATCHBAY_ICON_DISTRHO:
            pcIcon = patchcanvas.ICON_DISTRHO
        elif clientIcon == PATCHBAY_ICON_FILE:
            pcIcon = patchcanvas.ICON_FILE

        patchcanvas.addGroup(clientId, clientName, pcSplit, pcIcon)

        QTimer.singleShot(0, self.fMiniCanvasPreview.update)

        if pluginId < 0:
            return
        if pluginId >= self.fPluginCount:
            print("sorry, can't map this plugin to canvas client", pluginId, self.fPluginCount)
            return

        patchcanvas.setGroupAsPlugin(clientId, pluginId, bool(self.host.get_plugin_info(pluginId)['hints'] & PLUGIN_HAS_CUSTOM_UI))
Example #31
0
def play_turn():
    disable_advance()
    global game_over
    if game_over:
        return
    gui.set_label(3, "Remaining game time: " + str(round(scene.total_time, 2)))
    if scene.check_win_condition():
        game_over = True
        gui.set_label(3, "Game ended")
        return
    if scene.total_time < 0 or (scene.total_time < scene.turn_time and
                                (scene.turn % 2) == 1):
        # Tie breaker
        game_over = True
        gui.set_label(3, "Game ended")
        gui.set_label(4, "")
        scene.determine_winner()
        return
    scene.turn += 1
    if scene.turn % 2 == 1:
        color = Qt.blue
    else:
        color = Qt.red
    gui.set_label(0, "Turn: " + str(scene.turn), color)
    gui.set_label(3, "Remaining game time: " + str(round(scene.total_time, 2)))
    scene.path = []
    if scene.turn % 2 == 0:
        path_name = gui.get_field(1)
        team_robots = scene.red_robots
        opponent_robots = scene.blue_robots
        data = scene.red_data
    else:
        path_name = gui.get_field(2)
        team_robots = scene.blue_robots
        opponent_robots = scene.red_robots
        data = scene.blue_data

    spec = importlib.util.spec_from_file_location(path_name, path_name)
    gp = util.module_from_spec(spec)
    spec.loader.exec_module(gp)
    params = [scene.path]

    params.extend([
        copy_list.copy_robots(team_robots),
        copy_list.copy_robots(opponent_robots),
        copy_list.copy_bonuses(scene.bonuses), data, scene.total_time
    ])
    print("Player " + str(scene.turn % 2 + 1) + " turn started")
    worker = Worker(gp.play_turn, params)
    worker.signals.finished.connect(process_turn)
    global t
    t = scene.turn_time
    countdown()
    global timer
    timer = QTimer()
    timer.setInterval(100)
    timer.timeout.connect(countdown)
    timer.start()
    global t0
    t0 = time.perf_counter()
    threadpool.start(worker)
 def start_timer(self, interval):
     self.interval = interval
     self.startTime = time.time()
     QTimer.start(self, interval, True)
Example #33
0
 def set_timeout(self, timeout):
     """Hide the widget after the given timeout."""
     QTimer.singleShot(timeout, self._on_timeout)
Example #34
0
class MyWindow(QMainWindow, form_class):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.show()

        self.kiwoom = Kiwoom()
        self.kiwoom.comm_connect()
        self.wrapper = KiwoomWrapper(self.kiwoom)
        if self.kiwoom.get_login_info("GetServerGubun"):
            self.server_gubun = "모의투자"
        else:
            self.server_gubun = "실제투자"

        print("server 구분: %s"% (self.server_gubun ))

        self.code_list = self.kiwoom.get_code_list("0")
        print("Length of Code_List : %s" %(len(self.code_list)))

        self.setAccountComboBox()
        self.codeLineEdit.textChanged.connect(self.set_code_name)
        self.orderBtn.clicked.connect(self.send_order)
        self.inquiryBtn.clicked.connect(self.inquiry_balance)

        # 자동 주문
        # 자동 주문을 활성화 하려면 True로 설정
        self.is_automatic_order = True
        self.in_processing = False

        # 자동 선정 종목 리스트 테이블 설정
        self.set_automated_stocks()
        self.inquiry_balance()


        # # 메인 타이머
        self.timer = QTimer(self)
        self.timer.start(1000)
        self.timer.timeout.connect(self.timeout)
        #
        # # 자동 주문
        # self.timer_stock = QTimer(self)
        # self.timer_stock.start(1000*21)
        # self.timer_stock.timeout.connect(self.timeout)

        # 잔고 및 보유종목 조회 타이머
        self.inquiryTimer = QTimer(self)
        self.inquiryTimer.start(1000*10)
        self.inquiryTimer.timeout.connect(self.timeout)

    def timeout(self):
        """ 타임아웃 이벤트가 발생하면 호출되는 메서드 """
        # 어떤 타이머에 의해서 호출되었는지 확인
        sender = self.sender()
        if self.in_processing:
            return
        # 메인 타이머
        if id(sender) == id(self.timer):
            current_time = QTime.currentTime().toString("hh:mm:ss")
            # 상태바 설정
            state = ""
            if self.kiwoom.get_connect_state() == 1:
                state = self.server_gubun + " 서버 연결됨"
            else:
                state = "서버 미연결"
            self.statusbar.showMessage("현재시간: " + current_time + " | " + state)
            # log
            if self.kiwoom.msg:
                self.logTextEdit.append(self.kiwoom.msg)
                self.kiwoom.msg = ""
        elif id(sender) == id(self.timer_stock):
            automatic_order_time = QTime.currentTime().toString("hhmm")
            # 자동 주문 실행
            # 1100은 11시 00분을 의미합니다.
            print("current time: %d" % int(automatic_order_time))
            if self.is_automatic_order and int(automatic_order_time) >= 900 and int(automatic_order_time) <= 930:
                self.is_automatic_order = False
                self.automatic_order()
                self.set_automated_stocks()
        # 실시간 조회 타이머
        else:
            if self.realtimeCheckBox.isChecked():
                self.inquiry_balance()

    def set_code_name(self):
        """ 종목코드에 해당하는 한글명을 codeNameLineEdit에 설정한다. """
        try:
            code = self.codeLineEdit.text()

            if code in self.code_list:
                code_name = self.kiwoom.get_master_code_name(code)
                self.codeNameLineEdit.setText(code_name)
        except Exception as  error :
            print(error)


    def setAccountComboBox(self):
        """ accountComboBox에 계좌번호를 설정한다. """

        try:
            cnt = int(self.kiwoom.get_login_info("ACCOUNT_CNT"))
            accountList = self.kiwoom.get_login_info("ACCNO").split(';')
            self.accountComboBox.addItems(accountList[0:cnt])
        except (KiwoomConnectError, ParameterTypeError, ParameterValueError) as e:
            self.show_dialog('Critical', e)

    def send_order(self):
        """ 키움서버로 주문정보를 전송한다. """
        order_type_table = {'신규매수': 1, '신규매도': 2, '매수취소': 3, '매도취소': 4}
        hoga_type_table = {'지정가': "00", '시장가': "03"}

        account = self.accountComboBox.currentText()
        order_type = order_type_table[self.orderTypeComboBox.currentText()]
        code = self.codeLineEdit.text()
        hoga_type = hoga_type_table[self.hogaTypeComboBox.currentText()]
        qty = self.qtySpinBox.value()
        price = self.priceSpinBox.value()

        try:
            self.kiwoom.send_order("수동주문", "0101", account, order_type, code, qty, price, hoga_type, "")
        except (ParameterTypeError, KiwoomProcessingError) as e:
            self.show_dialog('Critical', e)

    def inquiry_balance(self):
        """ 예수금상세현황과 계좌평가잔고내역을 요청후 테이블에 출력한다. """
        self.in_processing = True
        #self.inquiryTimer.stop()
        #self.timer_stock.stop()

        try:
            # ____ 주의 _____ :  아래를 request하기 전에 password은 tray icon에서 지정한다.

            # 예수금상세현황요청
            print("계좌번호 : %s"%(self.accountComboBox.currentText()))
            self.kiwoom.set_input_value("계좌번호", self.accountComboBox.currentText())
            self.kiwoom.set_input_value("비밀번호", "0000")
            self.kiwoom.set_input_value("비밀번호입력매체구분", "00")
            # 조회구분 = 1:추정조회, 2:일반조회
            self.kiwoom.set_input_value("조회구분", "2")
            self.kiwoom.comm_rq_data("예수금상세현황요청", "opw00001", 0, "2000")

            # 계좌평가잔고내역요청 - opw00018 은 한번에 20개의 종목정보를 반환
            self.kiwoom.set_input_value("계좌번호", self.accountComboBox.currentText())
            self.kiwoom.set_input_value("비밀번호", "0000")
            self.kiwoom.set_input_value("비밀번호입력매체구분", "00")
            # 조회구분 = 1:합산, 2:개별
            self.kiwoom.set_input_value("조회구분", "2")
            self.kiwoom.comm_rq_data("계좌평가잔고내역요청", "opw00018", 0, "2000")
            while self.kiwoom.inquiry == '2':
                time.sleep(0.2)
                self.kiwoom.set_input_value("계좌번호", self.accountComboBox.currentText())
                self.kiwoom.set_input_value("비밀번호", "0000")
                self.kiwoom.set_input_value("비밀번호입력매체구분", "00")
                self.kiwoom.set_input_value("조회구분", "2")
                self.kiwoom.comm_rq_data("계좌평가잔고내역요청", "opw00018", 2, "2")
        except (ParameterTypeError, ParameterValueError, KiwoomProcessingError) as e:
            self.show_dialog('Critical', e)

        # accountEvaluationTable 테이블에 정보 출력

        item = QTableWidgetItem(self.kiwoom.data_opw00001)
        item.setTextAlignment(Qt.AlignVCenter | Qt.AlignRight)
        self.accountEvaluationTable.setItem(0, 0, item)

        for i in range(1, 6):
            item = QTableWidgetItem(self.kiwoom.data_opw00018['account_evaluation'][i-1])
            item.setTextAlignment(Qt.AlignVCenter | Qt.AlignRight)
            self.accountEvaluationTable.setItem(0, i, item)

        self.accountEvaluationTable.resizeRowsToContents()

        # Item list
        item_count = len(self.kiwoom.data_opw00018['stocks'])
        self.stocksTable.setRowCount(item_count)

        with open('../data/stocks_in_account.txt', 'wt', encoding='utf-8') as f_stock:
            f_stock.write('%s\n'%self.kiwoom.data_opw00001)
            for i in range(item_count):
                row = self.kiwoom.data_opw00018['stocks'][i]
                for j in range(len(row)-1):
                    f_stock.write('%s,'%row[j].replace(',', ''))
                    if j == len(row)-2:
                        f_stock.write('%s,'%row[-1])
                    item = QTableWidgetItem(row[j])
                    item.setTextAlignment(Qt.AlignVCenter | Qt.AlignRight)
                    self.stocksTable.setItem(i, j, item)
                f_stock.write('\n')

        self.stocksTable.resizeRowsToContents()

        # 데이터 초기화
        self.kiwoom.opw_data_reset()

        self.in_processing = False
        # inquiryTimer 재시작
        #self.inquiryTimer.start(1000*10)
        #self.timer_stock.start(1000*100)


    # 경고창
    def show_dialog(self, grade, error):
        grade_table = {'Information': 1, 'Warning': 2, 'Critical': 3, 'Question': 4}

        dialog = QMessageBox()
        dialog.setIcon(grade_table[grade])
        dialog.setText(error.msg)
        dialog.setWindowTitle(grade)
        dialog.setStandardButtons(QMessageBox.Ok)
        dialog.exec_()

    def set_automated_stocks(self):
        file_list = ["../data/sell_list.txt", "../data/buy_list.txt"]
        automated_stocks = []

        try:
            for file in file_list:
                # utf-8로 작성된 파일을
                # cp949 환경에서 읽기위해서 encoding 지정
                with open(file, 'rt', encoding='utf-8') as f:
                    stocks_list = f.readlines()
                    automated_stocks += stocks_list
        except Exception as e:
            print(e)
            e.msg = "set_automated_stocks() 에러"
            self.show_dialog('Critical', e)
            return

        # 테이블 행수 설정
        cnt = len(automated_stocks)
        self.automatedStocksTable.setRowCount(cnt)

        # 테이블에 출력
        for i in range(cnt):
            stocks = automated_stocks[i].split(';')
            for j in range(len(stocks)):
                if j == 1:
                    name = self.kiwoom.get_master_code_name(stocks[j].rstrip())
                    item = QTableWidgetItem(name)
                else:
                    item = QTableWidgetItem(stocks[j].rstrip())
                item.setTextAlignment(Qt.AlignVCenter | Qt.AlignCenter)
                self.automatedStocksTable.setItem(i, j, item)
        self.automatedStocksTable.resizeRowsToContents()

    def automatic_order(self):
        file_list = ["..\data\sell_list.txt", "..\data\buy_list.txt"]
        hoga_type_table = {'지정가': "00", '시장가': "03"}
        account = self.accountComboBox.currentText()
        automated_stocks = []
        self.in_processing = True
        # 파일읽기
        try:
            for file in file_list:
                # utf-8로 작성된 파일을
                # cp949 환경에서 읽기위해서 encoding 지정
                with open(file, 'rt', encoding='utf-8') as f:
                    stocks_list = f.readlines()
                    automated_stocks += stocks_list
        except Exception as e:
            print(e)
            #e.msg = "automatic_order() 에러"
            #self.show_dialog('Critical', e)
            return

        cnt = len(automated_stocks)

        # 주문하기
        buy_result = []
        sell_result = []

        for i in range(cnt):
            time.sleep(0.3)
            stocks = automated_stocks[i].split(';')

            code = stocks[1]
            hoga = stocks[2]
            qty = stocks[3]
            price = stocks[4]

            try:
                if stocks[5].rstrip() == '매수전':
                    self.kiwoom.send_order("자동매수주문", "0101", account, 1, code, int(qty), int(price), hoga_type_table[hoga], "")
                    print("order_no: ", self.kiwoom.order_no)

                    # 주문 접수시
                    if self.kiwoom.order_no:
                        buy_result += automated_stocks[i].replace("매수전", "매수완료")
                        self.kiwoom.order_no = ""
                    # 주문 미접수시
                    else:
                        buy_result += automated_stocks[i]

                # 참고: 해당 종목을 현재도 보유하고 있다고 가정함.
                elif stocks[5].rstrip() == '매도전':
                    self.kiwoom.send_order("자동매도주문", "0101", account, 2, code, int(qty), 0, hoga_type_table[hoga], "")
                    print("order_no: ", self.kiwoom.order_no)

                    # 주문 접수시
                    if self.kiwoom.order_no:
                        sell_result += automated_stocks[i].replace("매도전", "매도완료")
                        self.kiwoom.order_no = ""
                    # 주문 미접수시
                    else:
                        sell_result += automated_stocks[i]
                elif stocks[5].rstrip() == '매수완료':
                    buy_result += automated_stocks[i]
                elif stocks[5].rstrip() == '매도완료':
                    sell_result += automated_stocks[i]

            except (ParameterTypeError, KiwoomProcessingError) as e:
                #self.show_dialog('Critical', e)
                print(e)

        # 잔고및 보유종목 디스플레이 갱신
        self.inquiry_balance()

        # 결과저장하기
        for file, result in zip(file_list, [sell_result, buy_result]):
            with open(file, 'wt', encoding='utf-8') as f:
                for data in result:
                    f.write(data)
        self.in_processing = False
Example #35
0
 def __init__(self, parent=None):
     super(MainWindow, self).__init__()
     self.statusBar().showMessage("Move Dial to Deform Microphone Voice !.")
     self.setWindowTitle(__doc__)
     self.setMinimumSize(240, 240)
     self.setMaximumSize(480, 480)
     self.resize(self.minimumSize())
     self.setWindowIcon(QIcon.fromTheme("audio-input-microphone"))
     self.tray = QSystemTrayIcon(self)
     self.center()
     QShortcut("Ctrl+q", self, activated=lambda: self.close())
     self.menuBar().addMenu("&File").addAction("Quit", lambda: exit())
     self.menuBar().addMenu("Sound").addAction(
         "STOP !", lambda: call('killall rec', shell=True))
     windowMenu = self.menuBar().addMenu("&Window")
     windowMenu.addAction("Hide", lambda: self.hide())
     windowMenu.addAction("Minimize", lambda: self.showMinimized())
     windowMenu.addAction("Maximize", lambda: self.showMaximized())
     windowMenu.addAction("Restore", lambda: self.showNormal())
     windowMenu.addAction("FullScreen", lambda: self.showFullScreen())
     windowMenu.addAction("Center", lambda: self.center())
     windowMenu.addAction("Top-Left", lambda: self.move(0, 0))
     windowMenu.addAction("To Mouse", lambda: self.move_to_mouse_position())
     # widgets
     group0 = QGroupBox("Voice Deformation")
     self.setCentralWidget(group0)
     self.process = QProcess(self)
     self.process.error.connect(
         lambda: self.statusBar().showMessage("Info: Process Killed", 5000))
     self.control = QDial()
     self.control.setRange(-10, 20)
     self.control.setSingleStep(5)
     self.control.setValue(0)
     self.control.setCursor(QCursor(Qt.OpenHandCursor))
     self.control.sliderPressed.connect(
         lambda: self.control.setCursor(QCursor(Qt.ClosedHandCursor)))
     self.control.sliderReleased.connect(
         lambda: self.control.setCursor(QCursor(Qt.OpenHandCursor)))
     self.control.valueChanged.connect(
         lambda: self.control.setToolTip(f"<b>{self.control.value()}"))
     self.control.valueChanged.connect(lambda: self.statusBar().showMessage(
         f"Voice deformation: {self.control.value()}", 5000))
     self.control.valueChanged.connect(self.run)
     self.control.valueChanged.connect(lambda: self.process.kill())
     # Graphic effect
     self.glow = QGraphicsDropShadowEffect(self)
     self.glow.setOffset(0)
     self.glow.setBlurRadius(99)
     self.glow.setColor(QColor(99, 255, 255))
     self.control.setGraphicsEffect(self.glow)
     self.glow.setEnabled(False)
     # Timer to start
     self.slider_timer = QTimer(self)
     self.slider_timer.setSingleShot(True)
     self.slider_timer.timeout.connect(self.on_slider_timer_timeout)
     # an icon and set focus
     QLabel(self.control).setPixmap(
         QIcon.fromTheme("audio-input-microphone").pixmap(32))
     self.control.setFocus()
     QVBoxLayout(group0).addWidget(self.control)
     self.menu = QMenu(__doc__)
     self.menu.addAction(__doc__).setDisabled(True)
     self.menu.setIcon(self.windowIcon())
     self.menu.addSeparator()
     self.menu.addAction(
         "Show / Hide", lambda: self.hide()
         if self.isVisible() else self.showNormal())
     self.menu.addAction("STOP !", lambda: call('killall rec', shell=True))
     self.menu.addSeparator()
     self.menu.addAction("Quit", lambda: exit())
     self.tray.setContextMenu(self.menu)
     self.make_trayicon()
Example #36
0
class MainWindow(QMainWindow):
    """Voice Changer main window."""
    def __init__(self, parent=None):
        super(MainWindow, self).__init__()
        self.statusBar().showMessage("Move Dial to Deform Microphone Voice !.")
        self.setWindowTitle(__doc__)
        self.setMinimumSize(240, 240)
        self.setMaximumSize(480, 480)
        self.resize(self.minimumSize())
        self.setWindowIcon(QIcon.fromTheme("audio-input-microphone"))
        self.tray = QSystemTrayIcon(self)
        self.center()
        QShortcut("Ctrl+q", self, activated=lambda: self.close())
        self.menuBar().addMenu("&File").addAction("Quit", lambda: exit())
        self.menuBar().addMenu("Sound").addAction(
            "STOP !", lambda: call('killall rec', shell=True))
        windowMenu = self.menuBar().addMenu("&Window")
        windowMenu.addAction("Hide", lambda: self.hide())
        windowMenu.addAction("Minimize", lambda: self.showMinimized())
        windowMenu.addAction("Maximize", lambda: self.showMaximized())
        windowMenu.addAction("Restore", lambda: self.showNormal())
        windowMenu.addAction("FullScreen", lambda: self.showFullScreen())
        windowMenu.addAction("Center", lambda: self.center())
        windowMenu.addAction("Top-Left", lambda: self.move(0, 0))
        windowMenu.addAction("To Mouse", lambda: self.move_to_mouse_position())
        # widgets
        group0 = QGroupBox("Voice Deformation")
        self.setCentralWidget(group0)
        self.process = QProcess(self)
        self.process.error.connect(
            lambda: self.statusBar().showMessage("Info: Process Killed", 5000))
        self.control = QDial()
        self.control.setRange(-10, 20)
        self.control.setSingleStep(5)
        self.control.setValue(0)
        self.control.setCursor(QCursor(Qt.OpenHandCursor))
        self.control.sliderPressed.connect(
            lambda: self.control.setCursor(QCursor(Qt.ClosedHandCursor)))
        self.control.sliderReleased.connect(
            lambda: self.control.setCursor(QCursor(Qt.OpenHandCursor)))
        self.control.valueChanged.connect(
            lambda: self.control.setToolTip(f"<b>{self.control.value()}"))
        self.control.valueChanged.connect(lambda: self.statusBar().showMessage(
            f"Voice deformation: {self.control.value()}", 5000))
        self.control.valueChanged.connect(self.run)
        self.control.valueChanged.connect(lambda: self.process.kill())
        # Graphic effect
        self.glow = QGraphicsDropShadowEffect(self)
        self.glow.setOffset(0)
        self.glow.setBlurRadius(99)
        self.glow.setColor(QColor(99, 255, 255))
        self.control.setGraphicsEffect(self.glow)
        self.glow.setEnabled(False)
        # Timer to start
        self.slider_timer = QTimer(self)
        self.slider_timer.setSingleShot(True)
        self.slider_timer.timeout.connect(self.on_slider_timer_timeout)
        # an icon and set focus
        QLabel(self.control).setPixmap(
            QIcon.fromTheme("audio-input-microphone").pixmap(32))
        self.control.setFocus()
        QVBoxLayout(group0).addWidget(self.control)
        self.menu = QMenu(__doc__)
        self.menu.addAction(__doc__).setDisabled(True)
        self.menu.setIcon(self.windowIcon())
        self.menu.addSeparator()
        self.menu.addAction(
            "Show / Hide", lambda: self.hide()
            if self.isVisible() else self.showNormal())
        self.menu.addAction("STOP !", lambda: call('killall rec', shell=True))
        self.menu.addSeparator()
        self.menu.addAction("Quit", lambda: exit())
        self.tray.setContextMenu(self.menu)
        self.make_trayicon()

    def run(self):
        """Run/Stop the QTimer."""
        if self.slider_timer.isActive():
            self.slider_timer.stop()
        self.glow.setEnabled(True)
        call('killall rec ; killall play', shell=True)
        self.slider_timer.start(3000)

    def on_slider_timer_timeout(self):
        """Run subprocess to deform voice."""
        self.glow.setEnabled(False)
        value = int(self.control.value()) * 100
        command = 'play -q -V0 "|rec -q -V0 -n -d -R riaa bend pitch {}"'.format(
            value)
        print("Voice Deformation Value: " + str(value))
        print("Voice Deformation Command: " + str(command))
        self.process.start(command)
        if self.isVisible():
            self.statusBar().showMessage("Minimizing to System TrayIcon", 3000)
            print("Minimizing Main Window to System TrayIcon now...")
            sleep(3)

    def center(self):
        """Center Window on the Current Screen,with Multi-Monitor support."""
        window_geometry = self.frameGeometry()
        mousepointer_position = QApplication.desktop().cursor().pos()
        screen = QApplication.desktop().screenNumber(mousepointer_position)
        centerPoint = QApplication.desktop().screenGeometry(screen).center()
        window_geometry.moveCenter(centerPoint)
        self.move(window_geometry.topLeft())

    def move_to_mouse_position(self):
        """Center the Window on the Current Mouse position."""
        window_geometry = self.frameGeometry()
        window_geometry.moveCenter(QApplication.desktop().cursor().pos())
        self.move(window_geometry.topLeft())

    def make_trayicon(self):
        """Make a Tray Icon."""
        if self.windowIcon() and __doc__:
            self.tray.setIcon(self.windowIcon())
            self.tray.setToolTip(__doc__)
            self.tray.activated.connect(
                lambda: self.hide() if self.isVisible() else self.showNormal())
            return self.tray.show()
Example #37
0
 def __init__(self, document):
     self._updateTimer = QTimer(singleShot=True, timeout=self.slotTimeout)
     self._variables = self.readVariables()
     document.contentsChange.connect(self.slotContentsChange)
     document.closed.connect(self._updateTimer.stop) # just to be sure
Example #38
0
class Example(QWidget):
    def __init__(self):
        super().__init__()
        QWidget.__init__(self)
        self.initUI()

    def frontPos(self, x, y):
        self.frontX = x
        self.frontY = y
        self.label_front.move(self.frontX - 35, self.frontY - 35)

    def initUI(self):
        self.btn1 = QPushButton("GO!", self)
        self.setWindowIcon(QtGui.QIcon('img/logo.png'))

        self.label_back = QLabel(self)
        pixmap = QPixmap('img/t10_v1_back.png')
        self.label_back.setPixmap(pixmap)
        self.label_back.setGeometry(0, 0, 560, 560)

        self.label_front = QLabel(self)
        self.label_front.setStyleSheet("background-color:#111111;")
        self.label_front.setGeometry(0, 0, 70, 70)

        self.btn1.clicked.connect(self.btn1Click)
        self.btn1.setGeometry(10, 580, 130, 40)

        self.frontX = 0
        self.frontY = 0
        self.stepX = 0
        self.stepY = 0

        self.frontPos(40, 40)

        self.timer = QTimer(self)
        self.timer.timeout.connect(self.timerEvent)

        self.setGeometry(300, 300, 560, 640)
        self.setWindowTitle('zadanie 10')
        self.show()

    def timerEvent(self):
        self.frontPos(self.frontX + self.stepX, self.frontY + self.stepY)

        if self.frontY <= 80 and self.frontX >= 280:
            self.stepX = 0
            self.stepY = 5

        if self.frontY >= 120 and self.frontY < 160 and self.frontX < 320:
            self.stepX = 5
            self.stepY = 0

        if self.frontY <= 160 and self.frontX >= 440:
            self.stepX = 0
            self.stepY = 5

        if self.frontY >= 520 and self.frontX >= 400:
            self.stepX = -5
            self.stepY = 0

        if self.frontY >= 480 and self.frontX >= 320 and self.frontX <= 360:
            self.stepX = 0
            self.stepY = -5

        if self.frontY > 240 and self.frontY <= 280 and self.frontX >= 320 and self.frontX <= 400:
            self.stepX = -5
            self.stepY = 0

        if self.frontY > 240 and self.frontX <= 40:
            self.stepX = 0
            self.stepY = 5

        if self.frontY >= 520 and self.frontX <= 80:
            self.stepX = 0
            self.stepY = 0
            self.timer.stop()

    def btn1Click(self):
        self.frontPos(40, 40)
        self.stepX = 5
        self.stepY = 0
        self.timer.start(20)
    def __init__(self):
        super().__init__()

        # Other attributes...
        self.segmentation = None
        self.createdInputs = list()
        self.URLLabel = list()
        self.selectedURLLabel = list()
        self.newURL = u''
        self.newAnnotationKey = u''
        self.newAnnotationValue = u''
        self.infoBox = InfoBox(widget=self.controlArea)
        self.sendButton = SendButton(
            widget=self.controlArea,
            master=self,
            callback=self.sendData,
            infoBoxAttribute='infoBox',
            sendIfPreCallback=self.updateGUI,
        )
        self.advancedSettings = AdvancedSettings(
            widget=self.controlArea,
            master=self,
            callback=self.sendButton.settingsChanged,
        )

        # GUI...

        # Advanced settings checkbox...
        self.advancedSettings.draw()

        # BASIC GUI...

        # Basic URL box
        basicURLBox = gui.widgetBox(
            widget=self.controlArea,
            box=u'Source',
            orientation='vertical',
            addSpace=False,
        )
        basicURLBoxLine1 = gui.widgetBox(
            widget=basicURLBox,
            box=False,
            orientation='horizontal',
        )
        gui.lineEdit(
            widget=basicURLBoxLine1,
            master=self,
            value='URL',
            orientation='horizontal',
            label=u'URL:',
            labelWidth=101,
            callback=self.sendButton.settingsChanged,
            tooltip=(u"The URL whose content will be imported."),
        )
        gui.separator(widget=basicURLBox, height=3)
        advancedEncodingsCombobox = gui.comboBox(
            widget=basicURLBox,
            master=self,
            value='encoding',
            items=getPredefinedEncodings(),
            sendSelectedValue=True,
            orientation='horizontal',
            label=u'Encoding:',
            labelWidth=101,
            callback=self.sendButton.settingsChanged,
            tooltip=(u"Select URL's encoding."),
        )
        addSeparatorAfterDefaultEncodings(advancedEncodingsCombobox)
        addAutoDetectEncoding(advancedEncodingsCombobox)
        gui.separator(widget=basicURLBox, height=3)
        self.advancedSettings.basicWidgets.append(basicURLBox)
        self.advancedSettings.basicWidgetsAppendSeparator()

        # ADVANCED GUI...

        # URL box
        URLBox = gui.widgetBox(
            widget=self.controlArea,
            box=u'Sources',
            orientation='vertical',
            addSpace=False,
        )
        URLBoxLine1 = gui.widgetBox(
            widget=URLBox,
            box=False,
            orientation='horizontal',
            addSpace=True,
        )
        self.fileListbox = gui.listBox(
            widget=URLBoxLine1,
            master=self,
            value='selectedURLLabel',
            labels='URLLabel',
            callback=self.updateURLBoxButtons,
            tooltip=(u"The list of URLs whose content will be imported.\n"
                     u"\nIn the output segmentation, the content of each\n"
                     u"URL appears in the same position as in the list.\n"
                     u"\nColumn 1 shows the URL.\n"
                     u"Column 2 shows the associated annotation (if any).\n"
                     u"Column 3 shows the associated encoding."),
        )
        font = QFont()
        font.setFamily('Courier')
        font.setStyleHint(QFont.Courier)
        font.setPixelSize(12)
        self.fileListbox.setFont(font)
        URLBoxCol2 = gui.widgetBox(
            widget=URLBoxLine1,
            orientation='vertical',
        )
        self.moveUpButton = gui.button(
            widget=URLBoxCol2,
            master=self,
            label=u'Move Up',
            callback=self.moveUp,
            tooltip=(u"Move the selected URL upward in the list."),
        )
        self.moveDownButton = gui.button(
            widget=URLBoxCol2,
            master=self,
            label=u'Move Down',
            callback=self.moveDown,
            tooltip=(u"Move the selected URL downward in the list."),
        )
        self.removeButton = gui.button(
            widget=URLBoxCol2,
            master=self,
            label=u'Remove',
            callback=self.remove,
            tooltip=(u"Remove the selected URL from the list."),
        )
        self.clearAllButton = gui.button(
            widget=URLBoxCol2,
            master=self,
            label=u'Clear All',
            callback=self.clearAll,
            tooltip=(u"Remove all URLs from the list."),
        )
        self.exportButton = gui.button(
            widget=URLBoxCol2,
            master=self,
            label=u'Export List',
            callback=self.exportList,
            tooltip=(u"Open a dialog for selecting a file where the URL\n"
                     u"list can be exported in JSON format."),
        )
        self.importButton = gui.button(
            widget=URLBoxCol2,
            master=self,
            label=u'Import List',
            callback=self.importList,
            tooltip=(u"Open a dialog for selecting an URL list to\n"
                     u"import (in JSON format). URLs from this list will\n"
                     u"be added to those already imported."),
        )
        URLBoxLine2 = gui.widgetBox(
            widget=URLBox,
            box=False,
            orientation='vertical',
        )
        # Add URL box
        addURLBox = gui.widgetBox(
            widget=URLBoxLine2,
            box=True,
            orientation='vertical',
            addSpace=False,
        )
        gui.lineEdit(
            widget=addURLBox,
            master=self,
            value='newURL',
            orientation='horizontal',
            label=u'URL(s):',
            labelWidth=101,
            callback=self.updateGUI,
            tooltip=(u"The URL(s) that will be added to the list when\n"
                     u"button 'Add' is clicked.\n\n"
                     u"Successive URLs must be separated with ' / ' \n"
                     u"(space + slash + space). Their order in the list\n"
                     u" will be the same as in this field."),
        )
        gui.separator(widget=addURLBox, height=3)
        basicEncodingsCombobox = gui.comboBox(
            widget=addURLBox,
            master=self,
            value='encoding',
            items=getPredefinedEncodings(),
            sendSelectedValue=True,
            orientation='horizontal',
            label=u'Encoding:',
            labelWidth=101,
            callback=self.updateGUI,
            tooltip=(u"Select URL's encoding."),
        )
        addSeparatorAfterDefaultEncodings(basicEncodingsCombobox)
        addAutoDetectEncoding(basicEncodingsCombobox)
        self.encoding = self.encoding
        gui.separator(widget=addURLBox, height=3)
        gui.lineEdit(
            widget=addURLBox,
            master=self,
            value='newAnnotationKey',
            orientation='horizontal',
            label=u'Annotation key:',
            labelWidth=101,
            callback=self.updateGUI,
            tooltip=(u"This field lets you specify a custom annotation\n"
                     u"key associated with each URL that is about to be\n"
                     u"added to the list."),
        )
        gui.separator(widget=addURLBox, height=3)
        gui.lineEdit(
            widget=addURLBox,
            master=self,
            value='newAnnotationValue',
            orientation='horizontal',
            label=u'Annotation value:',
            labelWidth=101,
            callback=self.updateGUI,
            tooltip=(u"This field lets you specify the annotation value\n"
                     u"associated with the above annotation key."),
        )
        gui.separator(widget=addURLBox, height=3)
        self.addButton = gui.button(
            widget=addURLBox,
            master=self,
            label=u'Add',
            callback=self.add,
            tooltip=(u"Add the URL currently displayed in the 'URL'\n"
                     u"text field to the list."),
        )
        self.advancedSettings.advancedWidgets.append(URLBox)
        self.advancedSettings.advancedWidgetsAppendSeparator()

        # Options box...
        optionsBox = gui.widgetBox(
            widget=self.controlArea,
            box=u'Options',
            orientation='vertical',
            addSpace=False,
        )
        optionsBoxLine1 = gui.widgetBox(
            widget=optionsBox,
            box=False,
            orientation='horizontal',
        )
        gui.checkBox(
            widget=optionsBoxLine1,
            master=self,
            value='importURLs',
            label=u'Import URLs with key:',
            labelWidth=180,
            callback=self.sendButton.settingsChanged,
            tooltip=(u"Import URLs as annotations."),
        )
        self.importURLsKeyLineEdit = gui.lineEdit(
            widget=optionsBoxLine1,
            master=self,
            value='importURLsKey',
            orientation='horizontal',
            callback=self.sendButton.settingsChanged,
            tooltip=(u"Annotation key for importing URLs."),
        )
        gui.separator(widget=optionsBox, height=3)
        optionsBoxLine2 = gui.widgetBox(
            widget=optionsBox,
            box=False,
            orientation='horizontal',
        )
        gui.checkBox(
            widget=optionsBoxLine2,
            master=self,
            value='autoNumber',
            label=u'Auto-number with key:',
            labelWidth=180,
            callback=self.sendButton.settingsChanged,
            tooltip=(u"Annotate URLs with increasing numeric indices."),
        )
        self.autoNumberKeyLineEdit = gui.lineEdit(
            widget=optionsBoxLine2,
            master=self,
            value='autoNumberKey',
            orientation='horizontal',
            callback=self.sendButton.settingsChanged,
            tooltip=(u"Annotation key for URL auto-numbering."),
        )
        gui.separator(widget=optionsBox, height=3)
        self.advancedSettings.advancedWidgets.append(optionsBox)
        self.advancedSettings.advancedWidgetsAppendSeparator()

        gui.rubber(self.controlArea)

        # Send button...
        self.sendButton.draw()

        # Info box...
        self.infoBox.draw()

        self.adjustSizeWithTimer()
        QTimer.singleShot(0, self.sendButton.sendIf)
Example #40
0
 def export_to_pdf(self, **kwargs):
     p = partial(self._export, "pdf:writer_pdf_Export", ".pdf", **kwargs)
     QTimer.singleShot(0, p)
Example #41
0
class TimeoutProgressBar(QProgressBar):

    timeout = pyqtSignal()

    def __init__(self, parent=None, timeout=10000):
        super().__init__(parent)
        self.timeout_interval = timeout
        self.timer = QTimer()
        self.timer.setSingleShot(False)
        self.timer.setInterval(100)  # update the progress bar tick

        connect(self.timer.timeout, self._update)
        self.setMaximum(self.timeout_interval)

    def _update(self):
        self.setValue(self.value() + self.timer.interval())
        if self.value() >= self.maximum():
            self.timer.stop()
            self.timeout.emit()

    def start(self):
        self.setValue(0)
        self.timer.start()

    def stop(self):
        self.setValue(0)
        self.timer.stop()
Example #42
0
class DownloadsPage(QWidget):
    """
    This class is responsible for managing all items on the downloads page.
    The downloads page shows all downloads and specific details about a download.
    """
    received_downloads = pyqtSignal(object)

    def __init__(self):
        QWidget.__init__(self)
        self.export_dir = None
        self.filter = DOWNLOADS_FILTER_ALL
        self.download_widgets = {}  # key: infohash, value: QTreeWidgetItem
        self.downloads = None
        self.downloads_timer = QTimer()
        self.downloads_timeout_timer = QTimer()
        self.downloads_last_update = 0
        self.selected_items = None
        self.dialog = None
        self.downloads_request_mgr = TriblerRequestManager()
        self.request_mgr = None
        self.loading_message_widget = None

    def showEvent(self, QShowEvent):
        """
        When the downloads tab is clicked, we want to update the downloads list immediately.
        """
        super(DownloadsPage, self).showEvent(QShowEvent)
        self.stop_loading_downloads()
        self.schedule_downloads_timer(True)

    def initialize_downloads_page(self):
        self.window().downloads_tab.initialize()
        self.window().downloads_tab.clicked_tab_button.connect(self.on_downloads_tab_button_clicked)

        self.window().start_download_button.clicked.connect(self.on_start_download_clicked)
        self.window().stop_download_button.clicked.connect(self.on_stop_download_clicked)
        self.window().remove_download_button.clicked.connect(self.on_remove_download_clicked)
        self.window().play_download_button.clicked.connect(self.on_play_download_clicked)

        self.window().downloads_list.itemSelectionChanged.connect(self.on_download_item_clicked)

        self.window().downloads_list.customContextMenuRequested.connect(self.on_right_click_item)

        self.window().download_details_widget.initialize_details_widget()
        self.window().download_details_widget.hide()

        self.window().downloads_filter_input.textChanged.connect(self.on_filter_text_changed)

        self.window().downloads_list.header().resizeSection(12, 146)

        if not self.window().vlc_available:
            self.window().play_download_button.setHidden(True)

    def tray_set_tooltip(self, message):
        """
        Set a tooltip message for the tray icon, if possible.

        :param message: the message to display on hover
        """
        if self.window().tray_icon:
            try:
                self.window().tray_icon.setToolTip(message)
            except RuntimeError as e:
                logging.error("Failed to set tray tooltip: %s", str(e))

    def tray_show_message(self, title, message):
        """
        Show a message at the tray icon, if possible.

        :param title: the title of the message
        :param message: the message to display
        """
        if self.window().tray_icon:
            try:
                self.window().tray_icon.showMessage(title, message)
            except RuntimeError as e:
                logging.error("Failed to set tray message: %s", str(e))


    def on_filter_text_changed(self, text):
        self.window().downloads_list.clearSelection()
        self.window().download_details_widget.hide()
        self.update_download_visibility()

    def start_loading_downloads(self):
        self.window().downloads_list.setSelectionMode(QAbstractItemView.NoSelection)
        self.loading_message_widget = QTreeWidgetItem()
        self.window().downloads_list.addTopLevelItem(self.loading_message_widget)
        self.window().downloads_list.setItemWidget(self.loading_message_widget, 2,
                                                   LoadingListItem(self.window().downloads_list))
        self.schedule_downloads_timer(now=True)

    def schedule_downloads_timer(self, now=False):
        self.downloads_timer = QTimer()
        self.downloads_timer.setSingleShot(True)
        self.downloads_timer.timeout.connect(self.load_downloads)
        self.downloads_timer.start(0 if now else 1000)

        self.downloads_timeout_timer = QTimer()
        self.downloads_timeout_timer.setSingleShot(True)
        self.downloads_timeout_timer.timeout.connect(self.on_downloads_request_timeout)
        self.downloads_timeout_timer.start(16000)

    def on_downloads_request_timeout(self):
        self.downloads_request_mgr.cancel_request()
        self.schedule_downloads_timer()

    def stop_loading_downloads(self):
        self.downloads_timer.stop()
        self.downloads_timeout_timer.stop()

    def load_downloads(self):
        url = "downloads?get_pieces=1"
        if self.window().download_details_widget.currentIndex() == 3:
            url += "&get_peers=1"
        elif self.window().download_details_widget.currentIndex() == 1:
            url += "&get_files=1"

        if not self.isHidden() or (time.time() - self.downloads_last_update > 30):
            # Update if the downloads page is visible or if we haven't updated for longer than 30 seconds
            self.downloads_last_update = time.time()
            priority = "LOW" if self.isHidden() else "HIGH"
            self.downloads_request_mgr.cancel_request()
            self.downloads_request_mgr = TriblerRequestManager()
            self.downloads_request_mgr.perform_request(url, self.on_received_downloads, priority=priority)

    def on_received_downloads(self, downloads):
        if not downloads:
            return  # This might happen when closing Tribler
        loading_widget_index = self.window().downloads_list.indexOfTopLevelItem(self.loading_message_widget)
        if loading_widget_index > -1:
            self.window().downloads_list.takeTopLevelItem(loading_widget_index)
            self.window().downloads_list.setSelectionMode(QAbstractItemView.ExtendedSelection)

        self.downloads = downloads

        self.total_download = 0
        self.total_upload = 0

        download_infohashes = set()

        items = []
        for download in downloads["downloads"]:
            if download["infohash"] in self.download_widgets:
                item = self.download_widgets[download["infohash"]]
            else:
                item = DownloadWidgetItem()
                self.download_widgets[download["infohash"]] = item
                items.append(item)

            item.update_with_download(download)

            # Update video player with download info
            video_infohash = self.window().video_player_page.active_infohash
            if video_infohash != "" and download["infohash"] == video_infohash:
                self.window().video_player_page.update_with_download_info(download)

            self.total_download += download["speed_down"]
            self.total_upload += download["speed_up"]

            download_infohashes.add(download["infohash"])

            if self.window().download_details_widget.current_download is not None and \
                    self.window().download_details_widget.current_download["infohash"] == download["infohash"]:
                self.window().download_details_widget.current_download = download
                self.window().download_details_widget.update_pages()

        self.window().downloads_list.addTopLevelItems(items)
        for item in items:
            self.window().downloads_list.setItemWidget(item, 2, item.bar_container)

        # Check whether there are download that should be removed
        for infohash, item in self.download_widgets.items():
            if infohash not in download_infohashes:
                index = self.window().downloads_list.indexOfTopLevelItem(item)
                self.window().downloads_list.takeTopLevelItem(index)
                del self.download_widgets[infohash]

        self.tray_set_tooltip("Down: %s, Up: %s" % (format_speed(self.total_download), format_speed(self.total_upload)))
        self.update_download_visibility()
        self.schedule_downloads_timer()

        # Update the top download management button if we have a row selected
        if len(self.window().downloads_list.selectedItems()) > 0:
            self.on_download_item_clicked()

        self.update_credit_mining_disk_usage()

        self.received_downloads.emit(downloads)

    def update_download_visibility(self):
        for i in range(self.window().downloads_list.topLevelItemCount()):
            item = self.window().downloads_list.topLevelItem(i)
            filter_match = self.window().downloads_filter_input.text().lower() in item.download_info["name"].lower()
            is_creditmining = item.download_info["credit_mining"]
            if self.filter == DOWNLOADS_FILTER_CREDITMINING:
                item.setHidden(not is_creditmining or not filter_match)
            else:
                item.setHidden(not item.get_raw_download_status() in DOWNLOADS_FILTER_DEFINITION[self.filter] or \
                               not filter_match or is_creditmining)

    def on_downloads_tab_button_clicked(self, button_name):
        if button_name == "downloads_all_button":
            self.filter = DOWNLOADS_FILTER_ALL
        elif button_name == "downloads_downloading_button":
            self.filter = DOWNLOADS_FILTER_DOWNLOADING
        elif button_name == "downloads_completed_button":
            self.filter = DOWNLOADS_FILTER_COMPLETED
        elif button_name == "downloads_active_button":
            self.filter = DOWNLOADS_FILTER_ACTIVE
        elif button_name == "downloads_inactive_button":
            self.filter = DOWNLOADS_FILTER_INACTIVE
        elif button_name == "downloads_creditmining_button":
            self.filter = DOWNLOADS_FILTER_CREDITMINING

        self.window().downloads_list.clearSelection()
        self.window().download_details_widget.hide()
        self.update_download_visibility()
        self.update_credit_mining_disk_usage()

    def update_credit_mining_disk_usage(self):
        on_credit_mining_tab = self.filter == DOWNLOADS_FILTER_CREDITMINING
        self.window().diskspace_usage.setVisible(on_credit_mining_tab)

        if not on_credit_mining_tab or not self.window().tribler_settings or not self.downloads:
            return

        bytes_max = self.window().tribler_settings["credit_mining"]["max_disk_space"]
        bytes_used = 0
        for download in self.downloads["downloads"]:
            if download["credit_mining"] and \
               download["status"] in ("DLSTATUS_DOWNLOADING", "DLSTATUS_SEEDING",
                                      "DLSTATUS_STOPPED", "DLSTATUS_STOPPED_ON_ERROR"):
                bytes_used += download["progress"] * download["size"]
        self.window().diskspace_usage.setText("Current disk space usage %s / %s" % (format_size(float(bytes_used)),
                                                                                    format_size(float(bytes_max))))

    @staticmethod
    def start_download_enabled(download_widgets):
        return any([download_widget.get_raw_download_status() == DLSTATUS_STOPPED
                    for download_widget in download_widgets])

    @staticmethod
    def stop_download_enabled(download_widgets):
        return any([download_widget.get_raw_download_status() not in [DLSTATUS_STOPPED, DLSTATUS_STOPPED_ON_ERROR]
                    for download_widget in download_widgets])

    @staticmethod
    def force_recheck_download_enabled(download_widgets):
        return any([download_widget.get_raw_download_status() not in
                    [DLSTATUS_METADATA, DLSTATUS_HASHCHECKING, DLSTATUS_WAITING4HASHCHECK]
                    for download_widget in download_widgets])

    def on_download_item_clicked(self):
        selected_count = len(self.window().downloads_list.selectedItems())
        if selected_count == 0:
            self.window().play_download_button.setEnabled(False)
            self.window().remove_download_button.setEnabled(False)
            self.window().start_download_button.setEnabled(False)
            self.window().stop_download_button.setEnabled(False)
            self.window().download_details_widget.hide()
        elif selected_count == 1:
            self.selected_items = self.window().downloads_list.selectedItems()
            self.window().play_download_button.setEnabled(True)
            self.window().remove_download_button.setEnabled(True)
            self.window().start_download_button.setEnabled(DownloadsPage.start_download_enabled(self.selected_items))
            self.window().stop_download_button.setEnabled(DownloadsPage.stop_download_enabled(self.selected_items))

            self.window().download_details_widget.update_with_download(self.selected_items[0].download_info)
            self.window().download_details_widget.show()
        else:
            self.selected_items = self.window().downloads_list.selectedItems()
            self.window().play_download_button.setEnabled(False)
            self.window().remove_download_button.setEnabled(True)
            self.window().start_download_button.setEnabled(DownloadsPage.start_download_enabled(self.selected_items))
            self.window().stop_download_button.setEnabled(DownloadsPage.stop_download_enabled(self.selected_items))
            self.window().download_details_widget.hide()

    def on_start_download_clicked(self):
        for selected_item in self.selected_items:
            infohash = selected_item.download_info["infohash"]
            self.request_mgr = TriblerRequestManager()
            self.request_mgr.perform_request("downloads/%s" % infohash, self.on_download_resumed,
                                             method='PATCH', data="state=resume")

    def on_download_resumed(self, json_result):
        if json_result and 'modified' in json_result:
            for selected_item in self.selected_items:
                if selected_item.download_info["infohash"] == json_result["infohash"]:
                    selected_item.download_info['status'] = "DLSTATUS_DOWNLOADING"
                    selected_item.update_item()
                    self.on_download_item_clicked()

    def on_stop_download_clicked(self):
        for selected_item in self.selected_items:
            infohash = selected_item.download_info["infohash"]
            self.request_mgr = TriblerRequestManager()
            self.request_mgr.perform_request("downloads/%s" % infohash, self.on_download_stopped,
                                             method='PATCH', data="state=stop")

    def on_play_download_clicked(self):
        self.window().left_menu_button_video_player.click()
        selected_item = self.selected_items[:1]
        if selected_item and \
           self.window().video_player_page.active_infohash != selected_item[0].download_info["infohash"]:
            self.window().video_player_page.play_media_item(selected_item[0].download_info["infohash"], -1)

    def on_download_stopped(self, json_result):
        if json_result and "modified" in json_result:
            for selected_item in self.selected_items:
                if selected_item.download_info["infohash"] == json_result["infohash"]:
                    selected_item.download_info['status'] = "DLSTATUS_STOPPED"
                    selected_item.update_item()
                    self.on_download_item_clicked()

    def on_remove_download_clicked(self):
        self.dialog = ConfirmationDialog(self, "Remove download", "Are you sure you want to remove this download?",
                                         [('remove download', BUTTON_TYPE_NORMAL),
                                          ('remove download + data', BUTTON_TYPE_NORMAL),
                                          ('cancel', BUTTON_TYPE_CONFIRM)])
        self.dialog.button_clicked.connect(self.on_remove_download_dialog)
        self.dialog.show()

    def on_remove_download_dialog(self, action):
        if action != 2:
            for selected_item in self.selected_items:
                infohash = selected_item.download_info["infohash"]

                # Reset video player if necessary before doing the actual request
                if self.window().video_player_page.active_infohash == infohash:
                    self.window().video_player_page.reset_player()

                self.request_mgr = TriblerRequestManager()
                self.request_mgr.perform_request("downloads/%s" % infohash, self.on_download_removed,
                                                 method='DELETE', data="remove_data=%d" % action)

        self.dialog.close_dialog()
        self.dialog = None

    def on_download_removed(self, json_result):
        if json_result and "removed" in json_result:
            self.load_downloads()
            self.window().download_details_widget.hide()

    def on_force_recheck_download(self):
        for selected_item in self.selected_items:
            infohash = selected_item.download_info["infohash"]
            self.request_mgr = TriblerRequestManager()
            self.request_mgr.perform_request("downloads/%s" % infohash, self.on_forced_recheck,
                                             method='PATCH', data='state=recheck')

    def on_forced_recheck(self, result):
        if result and "modified" in result:
            for selected_item in self.selected_items:
                if selected_item.download_info["infohash"] == result["infohash"]:
                    selected_item.download_info['status'] = "DLSTATUS_HASHCHECKING"
                    selected_item.update_item()
                    self.on_download_item_clicked()

    def change_anonymity(self, hops):
        for selected_item in self.selected_items:
            infohash = selected_item.download_info["infohash"]
            self.request_mgr = TriblerRequestManager()
            self.request_mgr.perform_request("downloads/%s" % infohash, lambda _: None,
                                             method='PATCH', data='anon_hops=%d' % hops)

    def on_explore_files(self):
        for selected_item in self.selected_items:
            path = os.path.normpath(os.path.join(self.window().tribler_settings['download_defaults']['saveas'],
                                                 selected_item.download_info["destination"]))
            QDesktopServices.openUrl(QUrl.fromLocalFile(path))

    def on_export_download(self):
        self.export_dir = QFileDialog.getExistingDirectory(self, "Please select the destination directory", "",
                                                           QFileDialog.ShowDirsOnly)

        selected_item = self.selected_items[:1]
        if len(self.export_dir) > 0 and selected_item:
            # Show confirmation dialog where we specify the name of the file
            torrent_name = selected_item[0].download_info['name']
            self.dialog = ConfirmationDialog(self, "Export torrent file",
                                             "Please enter the name of the torrent file:",
                                             [('SAVE', BUTTON_TYPE_NORMAL), ('CANCEL', BUTTON_TYPE_CONFIRM)],
                                             show_input=True)
            self.dialog.dialog_widget.dialog_input.setPlaceholderText('Torrent file name')
            self.dialog.dialog_widget.dialog_input.setText("%s.torrent" % torrent_name)
            self.dialog.dialog_widget.dialog_input.setFocus()
            self.dialog.button_clicked.connect(self.on_export_download_dialog_done)
            self.dialog.show()

    def on_export_download_dialog_done(self, action):
        selected_item = self.selected_items[:1]
        if action == 0 and selected_item:
            filename = self.dialog.dialog_widget.dialog_input.text()
            self.request_mgr = TriblerRequestManager()
            self.request_mgr.download_file("downloads/%s/torrent" % selected_item[0].download_info['infohash'],
                                           lambda data: self.on_export_download_request_done(filename, data))

        self.dialog.close_dialog()
        self.dialog = None

    def on_export_download_request_done(self, filename, data):
        dest_path = os.path.join(self.export_dir, filename)
        try:
            torrent_file = open(dest_path, "wb")
            torrent_file.write(data)
            torrent_file.close()
        except IOError as exc:
            ConfirmationDialog.show_error(self.window(),
                                          "Error when exporting file",
                                          "An error occurred when exporting the torrent file: %s" % str(exc))
        else:
            self.tray_show_message("Torrent file exported", "Torrent file exported to %s" % dest_path)

    def on_right_click_item(self, pos):
        item_clicked = self.window().downloads_list.itemAt(pos)
        if not item_clicked or self.selected_items is None:
            return

        if item_clicked not in self.selected_items:
            self.selected_items.append(item_clicked)

        menu = TriblerActionMenu(self)

        start_action = QAction('Start', self)
        stop_action = QAction('Stop', self)
        remove_download_action = QAction('Remove download', self)
        force_recheck_action = QAction('Force recheck', self)
        export_download_action = QAction('Export .torrent file', self)
        explore_files_action = QAction('Explore files', self)

        no_anon_action = QAction('No anonymity', self)
        one_hop_anon_action = QAction('One hop', self)
        two_hop_anon_action = QAction('Two hops', self)
        three_hop_anon_action = QAction('Three hops', self)

        start_action.triggered.connect(self.on_start_download_clicked)
        start_action.setEnabled(DownloadsPage.start_download_enabled(self.selected_items))
        stop_action.triggered.connect(self.on_stop_download_clicked)
        stop_action.setEnabled(DownloadsPage.stop_download_enabled(self.selected_items))
        remove_download_action.triggered.connect(self.on_remove_download_clicked)
        force_recheck_action.triggered.connect(self.on_force_recheck_download)
        force_recheck_action.setEnabled(DownloadsPage.force_recheck_download_enabled(self.selected_items))
        export_download_action.triggered.connect(self.on_export_download)
        explore_files_action.triggered.connect(self.on_explore_files)

        no_anon_action.triggered.connect(lambda: self.change_anonymity(0))
        one_hop_anon_action.triggered.connect(lambda: self.change_anonymity(1))
        two_hop_anon_action.triggered.connect(lambda: self.change_anonymity(2))
        three_hop_anon_action.triggered.connect(lambda: self.change_anonymity(3))

        menu.addAction(start_action)
        menu.addAction(stop_action)

        if self.window().vlc_available and len(self.selected_items) == 1:
            play_action = QAction('Play', self)
            play_action.triggered.connect(self.on_play_download_clicked)
            menu.addAction(play_action)
        menu.addSeparator()
        menu.addAction(remove_download_action)
        menu.addSeparator()
        menu.addAction(force_recheck_action)
        menu.addSeparator()
        menu.addAction(export_download_action)
        menu.addSeparator()
        menu_anon_level = menu.addMenu("Change anonymity")
        menu_anon_level.addAction(no_anon_action)
        menu_anon_level.addAction(one_hop_anon_action)
        menu_anon_level.addAction(two_hop_anon_action)
        menu_anon_level.addAction(three_hop_anon_action)
        menu.addAction(explore_files_action)

        menu.exec_(self.window().downloads_list.mapToGlobal(pos))
Example #43
0
 def export_to_odt(self, **kwargs):
     p = partial(self._export, "odt", ".odt", **kwargs)
     QTimer.singleShot(0, p)
Example #44
0
class DeviceSelectWindow(QFrame):
    '''自定义窗口'''
    # 知识点:
    # 1.为了得到返回值用到了自定义的信号/槽
    # 2.为了显示动态数字,使用了计时器

    before_close_signal = pyqtSignal(str, str)  # 自定义信号(int类型)

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

        self.sec = 0
        self.setWindowTitle('自定义窗口')
        self.move(0,0)
        self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint | Qt.Tool)
        # self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
        # dialog.setWindowFlags(QtCore.Qt.Widget)  # 取消置顶
        self.setWindowOpacity(0.9)  # 设置窗口透明度
        # self.setAttribute(QtCore.Qt.WA_TranslucentBackground)  # 设置窗口背景透明
        self.setWindowFlag(QtCore.Qt.FramelessWindowHint)  # 隐藏边框

        # self.send_message_btn = QPushButton(self, text="发送")
        # self.send_message_btn.setObjectName('send_message_btn')

        self.close_btn = QPushButton(self)
        self.close_btn.setText("×")

        self.close_btn.setObjectName("close_btn")

        #
        # self.layout_message_tip = QVBoxLayout(self)
        # self.layout_message_tip.setObjectName("layout_message_tip")
        # self.layout_message_tip.addWidget(self.send_message_btn)
        self.close_btn.setGeometry(5, 20, 20, 20)
        # 30
        # 50

        # self.setLayout(self.layout_message_tip)

        # 显示选择目标设备按钮
        self.device_list_widget = QListWidget(self)

        self.device_list_widget.setFlow(QListWidget.LeftToRight)
        self.device_list_widget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.device_list_widget.setFrameShape(QListWidget.NoFrame)
        self.device_list_widget.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.device_list_widget.clicked.connect(lambda: self.device_clicked_list_widget_fun())


        # self.setStyleSheet('''
        #     .QWidget{
        #         border:2px solid darkGray;
        #         border-top-right-radius:15px;
        #         border-top-left-radius:15px;
        #         border-bottom-right-radius:15px;
        #         border-bottom-left-radius:15px;
        #         background:white;
        #     }''')
        self.send_type = ''
        self.timer = QTimer()

        # self.send_message_btn.clicked.connect(self.send_message_function)
        self.close_btn.clicked.connect(self.close_self)

        self.timer.timeout.connect(self.update)  # 每次计时结束,触发update

    def start(self, device_list, send_type):
        self.send_type = send_type
        self.sec = 1
        self.timer.start(1000)
        print(len(device_list))

        for one_device in device_list:
            print(one_device)
            one_device = json.loads(one_device)
            item = QListWidgetItem(self.device_list_widget)
            item.setSizeHint(QSize(device_select_item_width, device_select_item_height))
            item.setText(one_device['name'][0:3] + '.')
            item.setWhatsThis(one_device['name'])
            self.device_list_widget.addItem(item)
        #

        self.device_list_widget.setGeometry(30, 10, len(device_list) * device_select_item_width, device_select_height)
        # self.send_message_btn.setGeometry(30 + len(device_list) * device_select_item_width, 10, 40, 40)
        self.resize(50 + len(device_list) * device_select_item_width, 60)

        self.setStyleSheet('''
                    QPushButton#close_btn{
                        background:red;
                        border:1px solid darkGray;
                        border-top-right-radius:10px;
                        border-top-left-radius:10px;
                        border-bottom-right-radius:10px;
                        border-bottom-left-radius:10px;
                        color:white;
                    }
                    QPushButton#close_btn:hover{
                        color:red;
                        background:white;
                    }
                    QListWidget{
                        text-transform: uppercase;
                        text-align: center;
                    }
                    QListWidget::Item{
                        border:2px solid white;
                        border-top-right-radius:20px;
                        border-top-left-radius:20px;
                        border-bottom-right-radius:20px;
                        border-bottom-left-radius:20px;
                        background:yellow;
                        margin-left: 5px;
                        margin-right: 5px;
                    }
                    QListWidget::Item:hover{
                        background:skyblue;
                        color:white;
                    }
                    DeviceSelectWindow{
                        border:2px solid darkGray;
                        border-top-right-radius:15px;
                        border-top-left-radius:15px;
                        border-bottom-right-radius:15px;
                        border-bottom-left-radius:15px;
                        background:white;
                    }
                ''')
        desktop = QApplication.desktop()
        self.move(desktop.width() * 0.6, desktop.height() * 0.4)
        """
        QSS::
setStyleSheet('QListWidget{border:1px solid gray; color:black; }'
'QListWidget::Item{padding-top:-2px; padding-bottom:-1px;}'
"QListWidget::Item:hover{background:skyblue;padding-top:0px; padding-bottom:0px; }"
"QListWidget::item:selected{background:lightgray; color:red; }"
"QListWidget::item:selected:!active{active{border-width:0px;background:lightgreen; }")
                    QPushButton#send_message_btn{
                        background:red;
                        border:1px solid darkGray;
                        border-top-right-radius:20px;
                        border-top-left-radius:20px;
                        border-bottom-right-radius:20px;
                        border-bottom-left-radius:20px;
                        color:white;
                    }
                    QPushButton#send_message_btn:hover{
                        color:red;
                        background:white;
                    }
"""

    def update(self):
        self.sec += 1
        if self.sec == 6:
            self.timer.stop()
            self.before_close_signal.emit('-1', '-1')  # 发送信号,带参数 0
            self.hide()

    def close_self(self):
        self.timer.stop()
        self.before_close_signal.emit('-1', '-1')  # 发送信号,带参数 0
        self.hide()


    # def send_message_function(self):
    #     self.timer.stop()
    #     self.before_close_signal.emit(1)  # 发送信号,带参数 1
    #     self.sec = 0
    #     self.hide()

    # # 默认关闭事件
    # def closeEvent(self, e):
    #     self.timer.stop()
    #     self.before_close_signal.emit(0)  # 发送信号,带参数 0
    #     self.sec = 0
    #     self.hide()

    def device_clicked_list_widget_fun(self):
        self.hide()
        self.timer.stop()
        select_device = self.device_list_widget.currentItem().whatsThis()
        print('device_list_widget 已选择:{}'.format(select_device))

        self.device_list_widget.clear()
        self.before_close_signal.emit(select_device, self.send_type)  # 发送信号,带参数 1
Example #45
0
class ScrapWidget(QWidget):
    def __init__(self):
        super().__init__()

        self.ui = Ui_ScrapWidget()
        self.ui.setupUi(self)

        self.configuration = None
        self.operation = None
        self.typingTimer = QTimer()

        # self.ui.lineEdit_addr.setText("qaconsultants.com")
        self.ui.treeWidget_scrap.expandToDepth(0)

        self.ui.btn_scrap.clicked.connect(self.btnScrapSite)
        self.ui.btn_conf.clicked.connect(self.btnLoadConfiguration)

        # self.ui.btn_scrap.setEnabled(False)
        self.ui.lineEdit_addr.textChanged.connect(self._startTypingTimer)
        self.typingTimer.timeout.connect(self._endTypingTimer)

    def btnLoadConfiguration(self):

        self.configuration = ConfigurationDialog()
        self.configuration.signalConfigurationDict.connect(
            self.loadConfiguration)  #type:ignore
        self.configuration.show()

    def loadConfiguration(self, configuraitonDict: Dict):
        print(json.dumps(configuraitonDict, indent=2))

    def _startTypingTimer(self):
        self.typingTimer.start(1000)

    def _endTypingTimer(self):

        if not self.ui.lineEdit_addr.text():
            self.ui.btn_addrPrefix.setStyleSheet(
                "background-color: white; color: black")

    def _checkValidAddr(self, a0: str) -> bool:

        if not a0:
            self.ui.btn_addrPrefix.setStyleSheet(
                "background-color: white; color: black")
            return False
        else:
            if not Scrap.checkUrlValid(a0):
                logger.error(f"{a0} not valid url")
                self.ui.btn_addrPrefix.setStyleSheet(
                    "background-color: red; color: black")
                return False

            else:
                self.ui.btn_addrPrefix.setStyleSheet(
                    "background-color: green; color: black")
                return True

    def _consoleLog(self, msg: str):
        self.ui.textBrowser_console.append(msg)

    def btnScrapSite(self):

        url = self.ui.lineEdit_addr.text()
        if url[-1] == '/':
            pass
        else:
            url += '/'
        addr = "https://" + url
        addr = addr.lower()

        if not self._checkValidAddr(addr):
            return

        driver = self.ui.comboBox_driver.currentText()
        tDevice = self.ui.comboBox_targetDevice.currentText()
        navDepth = int(self.ui.spinBox_navDepth.text())
        headless = self.ui.chk_headless.isChecked()
        screenshots = self.ui.chk_screenshots.isChecked()
        config = {}
        config['headless'] = self.ui.chk_headless.isChecked()
        self.operation = OperationScrapSite("sqlite/wac.db",
                                            addr,
                                            navDepth,
                                            driver,
                                            tDevice,
                                            screenshots,
                                            configuration=config)
        self.operation.signalConsole.connect(self._consoleLog)
        self.operation.signalData.connect(self._showScrapData)
        self.operation.start()

    #
    def setUrlTotal(self, value: int = 0):
        self.ui.treeWidget_scrap.topLevelItem(0).setText(1, str(value))

    def setUrlDomain(self, value: int = 0):
        self.ui.treeWidget_scrap.topLevelItem(0).child(0).setText(
            1, str(value))

    def setUrlExternal(self, value: int = 0):
        self.ui.treeWidget_scrap.topLevelItem(0).child(1).setText(
            1, str(value))

    def setUrlInvalid(self, value: int = 0):
        self.ui.treeWidget_scrap.topLevelItem(0).child(2).setText(
            1, str(value))

    def setUrlErrors(self, value: int = 0):
        self.ui.treeWidget_scrap.topLevelItem(0).child(3).setText(
            1, str(value))

    def setImagesTotal(self, value: int = 0):
        self.ui.treeWidget_scrap.topLevelItem(1).setText(1, str(value))

    def setImagesScrapped(self, value: int = 0):
        self.ui.treeWidget_scrap.topLevelItem(1).child(0).setText(
            1, str(value))

    def setImagesDownloaded(self, value: int = 0):
        self.ui.treeWidget_scrap.topLevelItem(1).child(1).setText(
            1, str(value))

    def setImagesScreenshot(self, value: int = 0):
        self.ui.treeWidget_scrap.topLevelItem(1).child(2).setText(
            1, str(value))

    def setImagesErrors(self, value: int = 0):
        self.ui.treeWidget_scrap.topLevelItem(1).child(3).setText(
            1, str(value))

    def getUrlTotal(self) -> int:
        return int(self.ui.treeWidget_scrap.topLevelItem(0).text(1))

    def getUrlDomain(self) -> int:
        return int(self.ui.treeWidget_scrap.topLevelItem(0).child(0).text(1))

    def getUrlExternal(self) -> int:
        return int(self.ui.treeWidget_scrap.topLevelItem(0).child(1).text(1))

    def getUrlInvalid(self) -> int:
        return int(self.ui.treeWidget_scrap.topLevelItem(0).child(2).text(1))

    def getUrlErrors(self) -> int:
        return int(self.ui.treeWidget_scrap.topLevelItem(0).child(3).text(1))

    def getImagesTotal(self) -> int:
        return int(self.ui.treeWidget_scrap.topLevelItem(1).text(1))

    def getImagesScrapped(self) -> int:
        return int(self.ui.treeWidget_scrap.topLevelItem(1).child(0).text(1))

    def getImagesDownloaded(self) -> int:
        return int(self.ui.treeWidget_scrap.topLevelItem(1).child(1).text(1))

    def getImagesScreenshot(self) -> int:
        return int(self.ui.treeWidget_scrap.topLevelItem(1).child(2).text(1))

    def getImagesErrors(self) -> int:
        return int(self.ui.treeWidget_scrap.topLevelItem(1).child(3).text(1))

    def _showScrapData(self, data: Dict) -> None:
        print("data")
        print(data)
        try:
            self.setUrlTotal(data['urlTotal'])
            self.setUrlDomain(data['urlDomain'])
            self.setUrlErrors(data['urlErrors'])
            self.setUrlExternal(data['urlExternal'])
            self.setUrlInvalid(data['urlInvalid'])

            self.setImagesTotal(data['imgTotal'])
            self.setImagesDownloaded(data['imgDownloaded'])
            self.setImagesErrors(data['imgErrors'])
            self.setImagesScrapped(data['imgScrapped'])
            self.setImagesScreenshot(data['imgScreenshoted'])
        except Exception as e:
            pass
Example #46
0
class OctoPrintOutputDevice(NetworkedPrinterOutputDevice):
    def __init__(self, instance_id: str, address: str, port: int,
                 properties: dict, **kwargs) -> None:
        super().__init__(device_id=instance_id,
                         address=address,
                         properties=properties,
                         **kwargs)

        self._address = address
        self._port = port
        self._path = properties.get(b"path", b"/").decode("utf-8")
        if self._path[-1:] != "/":
            self._path += "/"
        self._id = instance_id
        self._properties = properties  # Properties dict as provided by zero conf

        self._gcode_stream = None  # type: Optional[Union[StringIO, BytesIO]]

        self._auto_print = True
        self._forced_queue = False

        # We start with a single extruder, but update this when we get data from octoprint
        self._number_of_extruders_set = False
        self._number_of_extruders = 1

        # Try to get version information from plugin.json
        plugin_file_path = os.path.join(
            os.path.dirname(os.path.abspath(__file__)), "plugin.json")
        try:
            with open(plugin_file_path) as plugin_file:
                plugin_info = json.load(plugin_file)
                plugin_version = plugin_info["version"]
        except:
            # The actual version info is not critical to have so we can continue
            plugin_version = "Unknown"
            Logger.logException(
                "w", "Could not get version information for the plugin")

        self._user_agent_header = "User-Agent".encode()
        self._user_agent = (
            "%s/%s %s/%s" %
            (CuraApplication.getInstance().getApplicationName(),
             CuraApplication.getInstance().getVersion(), "OctoPrintPlugin",
             plugin_version)
        )  # NetworkedPrinterOutputDevice defines this as string, so we encode this later

        self._api_prefix = "api/"
        self._api_header = "X-Api-Key".encode()
        self._api_key = b""

        self._protocol = "https" if properties.get(
            b'useHttps') == b"true" else "http"
        self._base_url = "%s://%s:%d%s" % (self._protocol, self._address,
                                           self._port, self._path)
        self._api_url = self._base_url + self._api_prefix

        self._basic_auth_header = "Authorization".encode()
        self._basic_auth_data = None
        basic_auth_username = properties.get(b"userName", b"").decode("utf-8")
        basic_auth_password = properties.get(b"password", b"").decode("utf-8")
        if basic_auth_username and basic_auth_password:
            data = base64.b64encode(
                ("%s:%s" % (basic_auth_username,
                            basic_auth_password)).encode()).decode("utf-8")
            self._basic_auth_data = ("basic %s" % data).encode()

        try:
            major_api_version = CuraApplication.getInstance().getAPIVersion(
            ).getMajor()
        except AttributeError:
            # UM.Application.getAPIVersion was added for API > 6 (Cura 4)
            # Since this plugin version is only compatible with Cura 3.5 and newer, it is safe to assume API 5
            major_api_version = 5

        if major_api_version <= 5:
            # In Cura 3.x, the monitor item only shows the camera stream
            self._monitor_view_qml_path = os.path.join(
                os.path.dirname(os.path.abspath(__file__)), "qml",
                "MonitorItem3x.qml")
        else:
            # In Cura 4.x, the monitor item shows the camera stream as well as the monitor sidebar
            self._monitor_view_qml_path = os.path.join(
                os.path.dirname(os.path.abspath(__file__)), "qml",
                "MonitorItem4x.qml")

        name = self._id
        matches = re.search(r"^\"(.*)\"\._octoprint\._tcp.local$", name)
        if matches:
            name = matches.group(1)

        self.setPriority(
            2
        )  # Make sure the output device gets selected above local file output
        self.setName(name)
        self.setShortDescription(
            i18n_catalog.i18nc("@action:button", "Print with OctoPrint"))
        self.setDescription(
            i18n_catalog.i18nc("@properties:tooltip", "Print with OctoPrint"))
        self.setIconName("print")
        self.setConnectionText(
            i18n_catalog.i18nc("@info:status",
                               "Connected to OctoPrint on {0}").format(
                                   self._id))

        self._post_reply = None

        self._progress_message = None  # type: Union[None, Message]
        self._error_message = None  # type: Union[None, Message]
        self._connection_message = None  # type: Union[None, Message]

        self._queued_gcode_commands = []  # type: List[str]
        self._queued_gcode_timer = QTimer()
        self._queued_gcode_timer.setInterval(0)
        self._queued_gcode_timer.setSingleShot(True)
        self._queued_gcode_timer.timeout.connect(self._sendQueuedGcode)

        # TODO; Add preference for update intervals
        self._update_fast_interval = 2000
        self._update_slow_interval = 10000
        self._update_timer = QTimer()
        self._update_timer.setInterval(self._update_fast_interval)
        self._update_timer.setSingleShot(False)
        self._update_timer.timeout.connect(self._update)

        self._psucontrol_timer = QTimer()
        self._psucontrol_timer.setInterval(
            20000)  # TODO; Add preference for timer interval
        self._psucontrol_timer.setSingleShot(True)
        self._psucontrol_timer.timeout.connect(self._startPrint)

        self._show_camera = True
        self._camera_mirror = False
        self._camera_rotation = 0
        self._camera_url = ""
        self._camera_shares_proxy = False

        self._sd_supported = False  # supports storing gcode on sd card in printer
        self._ufp_supported = False  # supports .ufp files in addition to raw .gcode files

        self._plugin_data = {}  #type: Dict[str, Any]

        self._output_controller = GenericOutputController(self)

    def getProperties(self) -> Dict[bytes, bytes]:
        return self._properties

    @pyqtSlot(str, result=str)
    def getProperty(self, key: str) -> str:
        key_b = key.encode("utf-8")
        if key_b in self._properties:
            return self._properties.get(key_b, b"").decode("utf-8")
        else:
            return ""

    ##  Get the unique key of this machine
    #   \return key String containing the key of the machine.
    @pyqtSlot(result=str)
    def getId(self) -> str:
        return self._id

    ##  Set the API key of this OctoPrint instance
    def setApiKey(self, api_key: str) -> None:
        self._api_key = api_key.encode()

    ##  Name of the instance (as returned from the zeroConf properties)
    @pyqtProperty(str, constant=True)
    def name(self) -> str:
        return self._name

    ##  Version (as returned from the zeroConf properties)
    @pyqtProperty(str, constant=True)
    def octoprintVersion(self) -> str:
        return self._properties.get(b"version", b"").decode("utf-8")

    ## IPadress of this instance
    @pyqtProperty(str, constant=True)
    def ipAddress(self) -> str:
        return self._address

    ## IPadress of this instance
    #  Overridden from NetworkedPrinterOutputDevice because OctoPrint does not
    #  send the ip address with zeroconf
    @pyqtProperty(str, constant=True)
    def address(self) -> str:
        return self._address

    ## port of this instance
    @pyqtProperty(int, constant=True)
    def port(self) -> int:
        return self._port

    ## path of this instance
    @pyqtProperty(str, constant=True)
    def path(self) -> str:
        return self._path

    ## absolute url of this instance
    @pyqtProperty(str, constant=True)
    def baseURL(self) -> str:
        return self._base_url

    cameraOrientationChanged = pyqtSignal()

    @pyqtProperty("QVariantMap", notify=cameraOrientationChanged)
    def cameraOrientation(self) -> Dict[str, Any]:
        return {
            "mirror": self._camera_mirror,
            "rotation": self._camera_rotation,
        }

    cameraUrlChanged = pyqtSignal()

    @pyqtProperty("QUrl", notify=cameraUrlChanged)
    def cameraUrl(self) -> QUrl:
        return QUrl(self._camera_url)

    def setShowCamera(self, show_camera: bool) -> None:
        if show_camera != self._show_camera:
            self._show_camera = show_camera
            self.showCameraChanged.emit()

    showCameraChanged = pyqtSignal()

    @pyqtProperty(bool, notify=showCameraChanged)
    def showCamera(self) -> bool:
        return self._show_camera

    def _update(self) -> None:
        ## Request 'general' printer data
        self.get("printer", self._onRequestFinished)

        ## Request print_job data
        self.get("job", self._onRequestFinished)

    def _createEmptyRequest(self,
                            target: str,
                            content_type: Optional[str] = "application/json"
                            ) -> QNetworkRequest:
        request = QNetworkRequest(QUrl(self._api_url + target))
        request.setRawHeader(self._user_agent_header,
                             self._user_agent.encode())
        request.setRawHeader(self._api_header, self._api_key)
        if content_type is not None:
            request.setHeader(QNetworkRequest.ContentTypeHeader,
                              "application/json")
        if self._basic_auth_data:
            request.setRawHeader(self._basic_auth_header,
                                 self._basic_auth_data)
        return request

    def close(self) -> None:
        self.setConnectionState(
            cast(ConnectionState, UnifiedConnectionState.Closed))
        if self._progress_message:
            self._progress_message.hide()
        if self._error_message:
            self._error_message.hide()
        self._update_timer.stop()

    ##  Start requesting data from the instance
    def connect(self) -> None:
        self._createNetworkManager()

        self.setConnectionState(
            cast(ConnectionState, UnifiedConnectionState.Connecting))
        self._update(
        )  # Manually trigger the first update, as we don't want to wait a few secs before it starts.

        Logger.log("d", "Connection with instance %s with url %s started",
                   self._id, self._base_url)
        self._update_timer.start()

        self._last_response_time = None
        self._setAcceptsCommands(False)
        self.setConnectionText(
            i18n_catalog.i18nc("@info:status",
                               "Connecting to OctoPrint on {0}").format(
                                   self._id))

        ## Request 'settings' dump
        self.get("settings", self._onRequestFinished)

    ##  Stop requesting data from the instance
    def disconnect(self) -> None:
        Logger.log("d", "Connection with instance %s with url %s stopped",
                   self._id, self._base_url)
        self.close()

    def pausePrint(self) -> None:
        self._sendJobCommand("pause")

    def resumePrint(self) -> None:
        if not self._printers[0].activePrintJob:
            return

        if self._printers[0].activePrintJob.state == "paused":
            self._sendJobCommand("pause")
        else:
            self._sendJobCommand("start")

    def cancelPrint(self) -> None:
        self._sendJobCommand("cancel")

    def requestWrite(self,
                     nodes: List["SceneNode"],
                     file_name: Optional[str] = None,
                     limit_mimetypes: bool = False,
                     file_handler: Optional["FileHandler"] = None,
                     **kwargs: str) -> None:
        global_container_stack = CuraApplication.getInstance(
        ).getGlobalContainerStack()
        if not global_container_stack:
            return

        # Make sure post-processing plugin are run on the gcode
        self.writeStarted.emit(self)

        # Get the g-code through the GCodeWriter plugin
        # This produces the same output as "Save to File", adding the print settings to the bottom of the file
        if not self._ufp_supported:
            gcode_writer = cast(
                MeshWriter,
                PluginRegistry.getInstance().getPluginObject("GCodeWriter"))
            self._gcode_stream = StringIO()
        else:
            gcode_writer = cast(
                MeshWriter,
                PluginRegistry.getInstance().getPluginObject("UFPWriter"))
            self._gcode_stream = BytesIO()

        if not gcode_writer.write(self._gcode_stream, None):
            Logger.log("e",
                       "GCodeWrite failed: %s" % gcode_writer.getInformation())
            return

        if self._error_message:
            self._error_message.hide()
            self._error_message = None

        if self._progress_message:
            self._progress_message.hide()
            self._progress_message = None

        self._auto_print = parseBool(
            global_container_stack.getMetaDataEntry("octoprint_auto_print",
                                                    True))
        self._forced_queue = False

        use_psu_control = parseBool(
            global_container_stack.getMetaDataEntry("octoprint_psu_control",
                                                    False))

        if self.activePrinter.state == "offline" and "psucontrol" in self._plugin_data and use_psu_control:
            self._sendCommandToApi("plugin/psucontrol", "turnPSUOn")
            Logger.log("d", "PSU control 'on' command sent")
            self._psucontrol_timer.start()
            return

        elif self.activePrinter.state not in ["idle", ""]:
            Logger.log(
                "d", "Tried starting a print, but current state is %s" %
                self.activePrinter.state)
            if not self._auto_print:
                # Allow queueing the job even if OctoPrint is currently busy if autoprinting is disabled
                self._error_message = None
            elif self.activePrinter.state == "offline":
                self._error_message = Message(
                    i18n_catalog.i18nc(
                        "@info:status",
                        "The printer is offline. Unable to start a new job."))
            else:
                self._error_message = Message(
                    i18n_catalog.i18nc(
                        "@info:status",
                        "OctoPrint is busy. Unable to start a new job."))

            if self._error_message:
                self._error_message.addAction(
                    "Queue", i18n_catalog.i18nc("@action:button", "Queue job"),
                    "",
                    i18n_catalog.i18nc(
                        "@action:tooltip",
                        "Queue this print job so it can be printed later"))
                self._error_message.actionTriggered.connect(self._queuePrint)
                self._error_message.show()
                return

        self._startPrint()

    def _queuePrint(self,
                    message_id: Optional[str] = None,
                    action_id: Optional[str] = None) -> None:
        if self._error_message:
            self._error_message.hide()
        self._forced_queue = True
        self._startPrint()

    def _startPrint(self) -> None:
        global_container_stack = CuraApplication.getInstance(
        ).getGlobalContainerStack()
        if not global_container_stack:
            return

        if self._auto_print and not self._forced_queue:
            CuraApplication.getInstance().getController().setActiveStage(
                "MonitorStage")

            # cancel any ongoing preheat timer before starting a print
            try:
                self._printers[0].stopPreheatTimers()
            except AttributeError:
                # stopPreheatTimers was added after Cura 3.3 beta
                pass

        self._progress_message = Message(
            i18n_catalog.i18nc("@info:status", "Sending data to OctoPrint"), 0,
            False, -1)
        self._progress_message.addAction(
            "Cancel", i18n_catalog.i18nc("@action:button", "Cancel"), "", "")
        self._progress_message.actionTriggered.connect(self._cancelSendGcode)
        self._progress_message.show()

        job_name = CuraApplication.getInstance().getPrintInformation(
        ).jobName.strip()
        if job_name is "":
            job_name = "untitled_print"
        extension = "gcode" if not self._ufp_supported else "ufp"
        file_name = "%s.%s" % (job_name, extension)

        ##  Create multi_part request
        post_parts = []  # type: List[QHttpPart]

        ##  Create parts (to be placed inside multipart)
        post_part = QHttpPart()
        post_part.setHeader(QNetworkRequest.ContentDispositionHeader,
                            "form-data; name=\"select\"")
        post_part.setBody(b"true")
        post_parts.append(post_part)

        if self._auto_print and not self._forced_queue:
            post_part = QHttpPart()
            post_part.setHeader(QNetworkRequest.ContentDispositionHeader,
                                "form-data; name=\"print\"")
            post_part.setBody(b"true")
            post_parts.append(post_part)

        gcode_body = self._gcode_stream.getvalue()
        try:
            # encode StringIO result to bytes
            gcode_body = gcode_body.encode()
        except AttributeError:
            # encode BytesIO is already byte-encoded
            pass

        post_part = QHttpPart()
        post_part.setHeader(
            QNetworkRequest.ContentDispositionHeader,
            "form-data; name=\"file\"; filename=\"%s\"" % file_name)
        post_part.setBody(gcode_body)
        post_parts.append(post_part)

        destination = "local"
        if self._sd_supported and parseBool(
                global_container_stack.getMetaDataEntry(
                    "octoprint_store_sd", False)):
            destination = "sdcard"

        try:
            ##  Post request + data
            post_request = self._createEmptyRequest("files/" + destination)
            self._post_reply = self.postFormWithParts(
                "files/" + destination,
                post_parts,
                on_finished=self._onRequestFinished,
                on_progress=self._onUploadProgress)

        except IOError:
            self._progress_message.hide()
            self._error_message = Message(
                i18n_catalog.i18nc("@info:status",
                                   "Unable to send data to OctoPrint."))
            self._error_message.show()
        except Exception as e:
            self._progress_message.hide()
            Logger.log(
                "e",
                "An exception occurred in network connection: %s" % str(e))

        self._gcode_stream = None  # type: Optional[Union[StringIO, BytesIO]]

    def _cancelSendGcode(self,
                         message_id: Optional[str] = None,
                         action_id: Optional[str] = None) -> None:
        if self._post_reply:
            Logger.log("d", "Stopping upload because the user pressed cancel.")
            try:
                self._post_reply.uploadProgress.disconnect(
                    self._onUploadProgress)
            except TypeError:
                pass  # The disconnection can fail on mac in some cases. Ignore that.

            self._post_reply.abort()
            self._post_reply = None
        if self._progress_message:
            self._progress_message.hide()

    def sendCommand(self, command: str) -> None:
        self._queued_gcode_commands.append(command)
        self._queued_gcode_timer.start()

    # Send gcode commands that are queued in quick succession as a single batch
    def _sendQueuedGcode(self) -> None:
        if self._queued_gcode_commands:
            self._sendCommandToApi("printer/command",
                                   self._queued_gcode_commands)
            Logger.log("d", "Sent gcode command to OctoPrint instance: %s",
                       self._queued_gcode_commands)
            self._queued_gcode_commands = []  # type: List[str]

    def _sendJobCommand(self, command: str) -> None:
        self._sendCommandToApi("job", command)
        Logger.log("d", "Sent job command to OctoPrint instance: %s", command)

    def _sendCommandToApi(self, end_point: str,
                          commands: Union[str, List[str]]) -> None:
        if isinstance(commands, list):
            data = json.dumps({"commands": commands})
        else:
            data = json.dumps({"command": commands})
        self.post(end_point, data, self._onRequestFinished)

    ## Overloaded from NetworkedPrinterOutputDevice.post() to backport https://github.com/Ultimaker/Cura/pull/4678
    def post(self,
             url: str,
             data: Union[str, bytes],
             on_finished: Optional[Callable[[QNetworkReply], None]],
             on_progress: Optional[Callable[[int, int], None]] = None) -> None:
        self._validateManager()

        request = self._createEmptyRequest(url)
        self._last_request_time = time()

        if not self._manager:
            Logger.log("e", "Could not find manager.")
            return

        body = data if isinstance(data,
                                  bytes) else data.encode()  # type: bytes
        reply = self._manager.post(request, body)
        if on_progress is not None:
            reply.uploadProgress.connect(on_progress)
        self._registerOnFinishedCallback(reply, on_finished)

    ##  Handler for all requests that have finished.
    def _onRequestFinished(self, reply: QNetworkReply) -> None:
        if reply.error() == QNetworkReply.TimeoutError:
            Logger.log("w", "Received a timeout on a request to the instance")
            self._connection_state_before_timeout = self._connection_state
            self.setConnectionState(
                cast(ConnectionState, UnifiedConnectionState.Error))
            return

        if self._connection_state_before_timeout and reply.error(
        ) == QNetworkReply.NoError:  #  There was a timeout, but we got a correct answer again.
            if self._last_response_time:
                Logger.log(
                    "d",
                    "We got a response from the instance after %s of silence",
                    time() - self._last_response_time)
            self.setConnectionState(self._connection_state_before_timeout)
            self._connection_state_before_timeout = None

        if reply.error() == QNetworkReply.NoError:
            self._last_response_time = time()

        http_status_code = reply.attribute(
            QNetworkRequest.HttpStatusCodeAttribute)
        if not http_status_code:
            # Received no or empty reply
            return

        error_handled = False

        if reply.operation() == QNetworkAccessManager.GetOperation:
            if self._api_prefix + "printer" in reply.url().toString(
            ):  # Status update from /printer.
                if not self._printers:
                    self._createPrinterList()

                # An OctoPrint instance has a single printer.
                printer = self._printers[0]
                update_pace = self._update_slow_interval

                if http_status_code == 200:
                    update_pace = self._update_fast_interval

                    if not self.acceptsCommands:
                        self._setAcceptsCommands(True)
                        self.setConnectionText(
                            i18n_catalog.i18nc(
                                "@info:status",
                                "Connected to OctoPrint on {0}").format(
                                    self._id))

                    if self._connection_state == UnifiedConnectionState.Connecting:
                        self.setConnectionState(
                            cast(ConnectionState,
                                 UnifiedConnectionState.Connected))
                    try:
                        json_data = json.loads(
                            bytes(reply.readAll()).decode("utf-8"))
                    except json.decoder.JSONDecodeError:
                        Logger.log(
                            "w",
                            "Received invalid JSON from octoprint instance.")
                        json_data = {}

                    if "temperature" in json_data:
                        if not self._number_of_extruders_set:
                            self._number_of_extruders = 0
                            while "tool%d" % self._number_of_extruders in json_data[
                                    "temperature"]:
                                self._number_of_extruders += 1

                            if self._number_of_extruders > 1:
                                # Recreate list of printers to match the new _number_of_extruders
                                self._createPrinterList()
                                printer = self._printers[0]

                            if self._number_of_extruders > 0:
                                self._number_of_extruders_set = True

                        # Check for hotend temperatures
                        for index in range(0, self._number_of_extruders):
                            extruder = printer.extruders[index]
                            if ("tool%d" % index) in json_data["temperature"]:
                                hotend_temperatures = json_data["temperature"][
                                    "tool%d" % index]
                                target_temperature = hotend_temperatures[
                                    "target"] if hotend_temperatures[
                                        "target"] is not None else -1
                                actual_temperature = hotend_temperatures[
                                    "actual"] if hotend_temperatures[
                                        "actual"] is not None else -1
                                extruder.updateTargetHotendTemperature(
                                    target_temperature)
                                extruder.updateHotendTemperature(
                                    actual_temperature)
                            else:
                                extruder.updateTargetHotendTemperature(0)
                                extruder.updateHotendTemperature(0)

                        if "bed" in json_data["temperature"]:
                            bed_temperatures = json_data["temperature"]["bed"]
                            actual_temperature = bed_temperatures[
                                "actual"] if bed_temperatures[
                                    "actual"] is not None else -1
                            printer.updateBedTemperature(actual_temperature)
                            target_temperature = bed_temperatures[
                                "target"] if bed_temperatures[
                                    "target"] is not None else -1
                            printer.updateTargetBedTemperature(
                                target_temperature)
                        else:
                            printer.updateBedTemperature(-1)
                            printer.updateTargetBedTemperature(0)

                    printer_state = "offline"
                    if "state" in json_data:
                        flags = json_data["state"]["flags"]
                        if flags["error"] or flags["closedOrError"]:
                            printer_state = "error"
                        elif flags["paused"] or flags["pausing"]:
                            printer_state = "paused"
                        elif flags["printing"]:
                            printer_state = "printing"
                        elif flags["cancelling"]:
                            printer_state = "aborted"
                        elif flags["ready"] or flags["operational"]:
                            printer_state = "idle"
                    printer.updateState(printer_state)

                elif http_status_code == 401:
                    printer.updateState("offline")
                    if printer.activePrintJob:
                        printer.activePrintJob.updateState("offline")
                    self.setConnectionText(
                        i18n_catalog.i18nc(
                            "@info:status",
                            "OctoPrint on {0} does not allow access to print").
                        format(self._id))
                    error_handled = True

                elif http_status_code == 409:
                    if self._connection_state == UnifiedConnectionState.Connecting:
                        self.setConnectionState(
                            cast(ConnectionState,
                                 UnifiedConnectionState.Connected))

                    printer.updateState("offline")
                    if printer.activePrintJob:
                        printer.activePrintJob.updateState("offline")
                    self.setConnectionText(
                        i18n_catalog.i18nc(
                            "@info:status",
                            "The printer connected to OctoPrint on {0} is not operational"
                        ).format(self._id))
                    error_handled = True

                elif http_status_code == 502 or http_status_code == 503:
                    printer.updateState("offline")
                    if printer.activePrintJob:
                        printer.activePrintJob.updateState("offline")
                    self.setConnectionText(
                        i18n_catalog.i18nc(
                            "@info:status",
                            "OctoPrint on {0} is not running").format(
                                self._id))
                    error_handled = True

                else:
                    printer.updateState("offline")
                    if printer.activePrintJob:
                        printer.activePrintJob.updateState("offline")
                    Logger.log("w", "Received an unexpected returncode: %d",
                               http_status_code)

                if update_pace != self._update_timer.interval():
                    self._update_timer.setInterval(update_pace)

            elif self._api_prefix + "job" in reply.url().toString(
            ):  # Status update from /job:
                if not self._printers:
                    return  # Ignore the data for now, we don't have info about a printer yet.
                printer = self._printers[0]

                if http_status_code == 200:
                    try:
                        json_data = json.loads(
                            bytes(reply.readAll()).decode("utf-8"))
                    except json.decoder.JSONDecodeError:
                        Logger.log(
                            "w",
                            "Received invalid JSON from octoprint instance.")
                        json_data = {}

                    if printer.activePrintJob is None:
                        print_job = PrintJobOutputModel(
                            output_controller=self._output_controller)
                        printer.updateActivePrintJob(print_job)
                    else:
                        print_job = printer.activePrintJob

                    print_job_state = "offline"
                    if "state" in json_data:
                        if json_data["state"] == "Error":
                            print_job_state = "error"
                        elif json_data["state"] == "Pausing":
                            print_job_state = "pausing"
                        elif json_data["state"] == "Paused":
                            print_job_state = "paused"
                        elif json_data["state"] == "Printing":
                            print_job_state = "printing"
                        elif json_data["state"] == "Cancelling":
                            print_job_state = "abort"
                        elif json_data["state"] == "Operational":
                            print_job_state = "ready"
                            printer.updateState("idle")
                    print_job.updateState(print_job_state)

                    print_time = json_data["progress"]["printTime"]
                    if print_time:
                        print_job.updateTimeElapsed(print_time)
                        if json_data["progress"][
                                "completion"]:  # not 0 or None or ""
                            print_job.updateTimeTotal(
                                print_time /
                                (json_data["progress"]["completion"] / 100))
                        else:
                            print_job.updateTimeTotal(0)
                    else:
                        print_job.updateTimeElapsed(0)
                        print_job.updateTimeTotal(0)

                    print_job.updateName(json_data["job"]["file"]["name"])
                else:
                    pass  # See generic error handler below

            elif self._api_prefix + "settings" in reply.url().toString(
            ):  # OctoPrint settings dump from /settings:
                if http_status_code == 200:
                    try:
                        json_data = json.loads(
                            bytes(reply.readAll()).decode("utf-8"))
                    except json.decoder.JSONDecodeError:
                        Logger.log(
                            "w",
                            "Received invalid JSON from octoprint instance.")
                        json_data = {}

                    if "feature" in json_data and "sdSupport" in json_data[
                            "feature"]:
                        self._sd_supported = json_data["feature"]["sdSupport"]

                    if "webcam" in json_data and "streamUrl" in json_data[
                            "webcam"]:
                        self._camera_shares_proxy = False
                        stream_url = json_data["webcam"]["streamUrl"]
                        if not stream_url:  #empty string or None
                            self._camera_url = ""
                        elif stream_url[:4].lower() == "http":  # absolute uri
                            self._camera_url = stream_url
                        elif stream_url[:2] == "//":  # protocol-relative
                            self._camera_url = "%s:%s" % (self._protocol,
                                                          stream_url)
                        elif stream_url[:
                                        1] == ":":  # domain-relative (on another port)
                            self._camera_url = "%s://%s%s" % (
                                self._protocol, self._address, stream_url)
                        elif stream_url[:
                                        1] == "/":  # domain-relative (on same port)
                            self._camera_url = "%s://%s:%d%s" % (
                                self._protocol, self._address, self._port,
                                stream_url)
                            self._camera_shares_proxy = True
                        else:
                            Logger.log("w", "Unusable stream url received: %s",
                                       stream_url)
                            self._camera_url = ""

                        Logger.log("d", "Set OctoPrint camera url to %s",
                                   self._camera_url)
                        self.cameraUrlChanged.emit()

                        if "rotate90" in json_data["webcam"]:
                            self._camera_rotation = -90 if json_data["webcam"][
                                "rotate90"] else 0
                            if json_data["webcam"]["flipH"] and json_data[
                                    "webcam"]["flipV"]:
                                self._camera_mirror = False
                                self._camera_rotation += 180
                            elif json_data["webcam"]["flipH"]:
                                self._camera_mirror = True
                                self._camera_rotation += 180
                            elif json_data["webcam"]["flipV"]:
                                self._camera_mirror = True
                            else:
                                self._camera_mirror = False
                            self.cameraOrientationChanged.emit()

                    if "plugins" in json_data:
                        self._plugin_data = json_data["plugins"]

                        if "UltimakerFormatPackage" in self._plugin_data:
                            try:
                                ufp_writer_plugin = PluginRegistry.getInstance(
                                ).getPluginObject("UFPWriter")
                                self._ufp_supported = True
                                Logger.log("d", "Instance supports UFP files")
                            except PluginNotFoundError:
                                Logger.log(
                                    "w",
                                    "Instance supports UFP files, but UFPWriter is not available"
                                )

        elif reply.operation() == QNetworkAccessManager.PostOperation:
            if self._api_prefix + "files" in reply.url().toString(
            ):  # Result from /files command:
                if http_status_code == 201:
                    Logger.log(
                        "d", "Resource created on OctoPrint instance: %s",
                        reply.header(
                            QNetworkRequest.LocationHeader).toString())
                else:
                    pass  # See generic error handler below

                reply.uploadProgress.disconnect(self._onUploadProgress)
                if self._progress_message:
                    self._progress_message.hide()

                if self._forced_queue or not self._auto_print:
                    location = reply.header(QNetworkRequest.LocationHeader)
                    if location:
                        file_name = QUrl(
                            reply.header(QNetworkRequest.LocationHeader).
                            toString()).fileName()
                        message = Message(
                            i18n_catalog.i18nc(
                                "@info:status",
                                "Saved to OctoPrint as {0}").format(file_name))
                    else:
                        message = Message(
                            i18n_catalog.i18nc("@info:status",
                                               "Saved to OctoPrint"))
                    message.addAction(
                        "open_browser",
                        i18n_catalog.i18nc("@action:button", "OctoPrint..."),
                        "globe",
                        i18n_catalog.i18nc("@info:tooltip",
                                           "Open the OctoPrint web interface"))
                    message.actionTriggered.connect(self._openOctoPrint)
                    message.show()

            elif self._api_prefix + "job" in reply.url().toString(
            ):  # Result from /job command (eg start/pause):
                if http_status_code == 204:
                    Logger.log("d", "Octoprint job command accepted")
                else:
                    pass  # See generic error handler below

            elif self._api_prefix + "printer/command" in reply.url().toString(
            ):  # Result from /printer/command (gcode statements):
                if http_status_code == 204:
                    Logger.log("d", "Octoprint gcode command(s) accepted")
                else:
                    pass  # See generic error handler below

        else:
            Logger.log("d",
                       "OctoPrintOutputDevice got an unhandled operation %s",
                       reply.operation())

        if not error_handled and http_status_code >= 400:
            # Received an error reply
            error_string = bytes(reply.readAll()).decode("utf-8")
            if not error_string:
                error_string = reply.attribute(
                    QNetworkRequest.HttpReasonPhraseAttribute)
            if self._error_message:
                self._error_message.hide()
            self._error_message = Message(error_string,
                                          title=i18n_catalog.i18nc(
                                              "@label", "OctoPrint error"))
            self._error_message.show()
            return

    def _onUploadProgress(self, bytes_sent: int, bytes_total: int) -> None:
        if not self._progress_message:
            return

        if bytes_total > 0:
            # Treat upload progress as response. Uploading can take more than 10 seconds, so if we don't, we can get
            # timeout responses if this happens.
            self._last_response_time = time()

            progress = bytes_sent / bytes_total * 100
            previous_progress = self._progress_message.getProgress()
            if progress < 100:
                if previous_progress is not None and progress > previous_progress:
                    self._progress_message.setProgress(progress)
            else:
                self._progress_message.hide()
                self._progress_message = Message(
                    i18n_catalog.i18nc("@info:status",
                                       "Storing data on OctoPrint"), 0, False,
                    -1)
                self._progress_message.show()
        else:
            self._progress_message.setProgress(0)

    def _createPrinterList(self) -> None:
        printer = PrinterOutputModel(
            output_controller=self._output_controller,
            number_of_extruders=self._number_of_extruders)
        printer.updateName(self.name)
        self._printers = [printer]
        self.printersChanged.emit()

    def _openOctoPrint(self,
                       message_id: Optional[str] = None,
                       action_id: Optional[str] = None) -> None:
        QDesktopServices.openUrl(QUrl(self._base_url))
Example #47
0
                         light_secondary=theme.startswith('light'),
                         extra=self.extra)

        self.main.statusbar.showMessage(f'Theme: theme')


T0 = 1000

if __name__ == "__main__":

    # ----------------------------------------------------------------------
    def take_screenshot():
        pixmap = frame.main.grab()
        pixmap.save(os.path.join('screenshots', f'{theme}.png'))
        print(f'Saving {theme}')

    try:
        theme = sys.argv[1]
        QTimer.singleShot(T0, take_screenshot)
        QTimer.singleShot(T0 * 2, app.closeAllWindows)
    except:
        theme = 'default'

    # Set theme on in itialization
    apply_stylesheet(app, theme + '.xml', light_secondary=('light' in theme))

    frame = RuntimeStylesheets()
    frame.main.show()

    app.exec_()
Example #48
0
    def create_objects(self):
        if not (self.isValid() and self.shareWidget.initialized):
            self.invalid_count += 1
            print('ND: Context not valid in create_objects, or shareWidget not yet initialized')
            QTimer.singleShot(100, self.create_objects)
            return

        # Make the nd widget context current, necessary when create_objects is not called from initializeGL
        self.makeCurrent()

        # Use the same font as the radarwidget
        self.font = self.shareWidget.font.copy()
        self.font.init_shader(self.text_shader)

        edge = np.zeros(120, dtype=np.float32)
        edge[0:120:2] = 1.4 * np.sin(np.radians(np.arange(-60, 60, 2)))
        edge[1:120:2] = 1.4 * np.cos(np.radians(np.arange(-60, 60, 2)))
        self.edge = VertexAttributeObject(gl.GL_LINE_STRIP, vertex=edge, color=white)

        arcs = []
        for i in range(1, 4):
            for angle in range(-60, 60, max(2, 6 - 2 * i)):
                arcs.append(float(i) * 0.35 * sin(radians(angle)))
                arcs.append(float(i) * 0.35 * cos(radians(angle)))
                if i == 4:
                    arcs.append(float(i) * 0.35 * sin(radians(angle + 2)))
                    arcs.append(float(i) * 0.35 * cos(radians(angle + 2)))
        arcs = np.array(arcs, dtype=np.float32)
        self.arcs = VertexAttributeObject(gl.GL_LINES, vertex=arcs, color=white)

        mask = []
        for angle in range(-60, 60, 2):
            mask.append(1.4 * sin(radians(angle)))
            mask.append(10.0)
            mask.append(1.4 * sin(radians(angle)))
            mask.append(1.4 * cos(radians(angle)))
        mask = np.array(mask, dtype=np.float32)
        self.mask = VertexAttributeObject(gl.GL_TRIANGLE_STRIP, vertex=mask, color=black)

        ticks = np.zeros(288, dtype=np.float32)
        for i in range(72):
            ticktop = 1.46 if i % 6 == 0 else (1.44 if i % 2 == 0 else 1.42)
            ticks[4*i  :4*i+2] = (1.4 * sin(radians(i * 5)), 1.4 * cos(radians(i * 5)))
            ticks[4*i+2:4*i+4] = (ticktop * sin(radians(i * 5)), ticktop * cos(radians(i * 5)))
        self.ticks = VertexAttributeObject(gl.GL_LINES, vertex=ticks, color=white)

        ticklbls = np.zeros(24 * 36, dtype=np.float32)
        texcoords = np.zeros(36 * 36, dtype=np.float32)

        for i in range(36):
            if i % 3 == 0:
                w, h, y = 0.045, 0.09, 1.48
            else:
                w, h, y = 0.035, 0.07, 1.46
            tmp = [(-w, h+y), (-w, y), (0.0, h+y), (0.0, h+y), (-w, y), (0.0, y),
                   (0.0, h+y), (0.0, y), (w, h+y), (w, h+y), (0.0, y), (w, y)]

            # numerics start at ASCII 48
            c1 = i / 10 + 48
            c2 = i % 10 + 48
            texcoords[36*i:36*i+18]    = [0, 0, c1, 0, 1, c1, 1, 0, c1, 1, 0, c1, 0, 1, c1, 1, 1, c1]
            texcoords[36*i+18:36*i+36] = [0, 0, c2, 0, 1, c2, 1, 0, c2, 1, 0, c2, 0, 1, c2, 1, 1, c2]
            angle = radians(10 * (36 - i))
            rot = np.array([[cos(angle), -sin(angle)], [sin(angle), cos(angle)]])
            for j in range(12):
                ticklbls[24*i+2*j:24*i+2*j+2] = rot.dot(tmp[j])

        self.ticklbls = VertexAttributeObject(gl.GL_TRIANGLES, vertex=ticklbls, color=white, texcoords=texcoords)

        vown = np.array([0.0, 0.0, 0.0, -0.12, 0.065, -0.03, -0.065, -0.03, 0.022, -0.1, -0.022, -0.1], dtype=np.float32)
        self.ownship = VertexAttributeObject(gl.GL_LINES, vertex=vown, color=yellow)

        self.spdlabel_text = self.font.prepare_text_string('GS    TAS', 0.05, white, (-0.98, 1.6))
        self.spdlabel_val  = self.font.prepare_text_string('  000    000', 0.05, green, (-0.97, 1.6))

        self.waypoints = VertexAttributeObject.copy(self.shareWidget.waypoints)
        self.wptlabels = VertexAttributeObject.copy(self.shareWidget.wptlabels)
        self.airports  = VertexAttributeObject.copy(self.shareWidget.airports)
        self.aptlabels = VertexAttributeObject.copy(self.shareWidget.aptlabels)
        self.protectedzone = VertexAttributeObject.copy(self.shareWidget.protectedzone)
        self.ac_symbol = VertexAttributeObject.copy(self.shareWidget.ac_symbol)
        self.aclabels = VertexAttributeObject.copy(self.shareWidget.aclabels)

        # Unbind VAO, VBO
        VertexAttributeObject.unbind_all()

        # Done initializing
        self.initialized = True
Example #49
0
    def __init__(self, instance_id: str, address: str, port: int,
                 properties: dict, **kwargs) -> None:
        super().__init__(device_id=instance_id,
                         address=address,
                         properties=properties,
                         **kwargs)

        self._address = address
        self._port = port
        self._path = properties.get(b"path", b"/").decode("utf-8")
        if self._path[-1:] != "/":
            self._path += "/"
        self._id = instance_id
        self._properties = properties  # Properties dict as provided by zero conf

        self._gcode_stream = None  # type: Optional[Union[StringIO, BytesIO]]

        self._auto_print = True
        self._forced_queue = False

        # We start with a single extruder, but update this when we get data from octoprint
        self._number_of_extruders_set = False
        self._number_of_extruders = 1

        # Try to get version information from plugin.json
        plugin_file_path = os.path.join(
            os.path.dirname(os.path.abspath(__file__)), "plugin.json")
        try:
            with open(plugin_file_path) as plugin_file:
                plugin_info = json.load(plugin_file)
                plugin_version = plugin_info["version"]
        except:
            # The actual version info is not critical to have so we can continue
            plugin_version = "Unknown"
            Logger.logException(
                "w", "Could not get version information for the plugin")

        self._user_agent_header = "User-Agent".encode()
        self._user_agent = (
            "%s/%s %s/%s" %
            (CuraApplication.getInstance().getApplicationName(),
             CuraApplication.getInstance().getVersion(), "OctoPrintPlugin",
             plugin_version)
        )  # NetworkedPrinterOutputDevice defines this as string, so we encode this later

        self._api_prefix = "api/"
        self._api_header = "X-Api-Key".encode()
        self._api_key = b""

        self._protocol = "https" if properties.get(
            b'useHttps') == b"true" else "http"
        self._base_url = "%s://%s:%d%s" % (self._protocol, self._address,
                                           self._port, self._path)
        self._api_url = self._base_url + self._api_prefix

        self._basic_auth_header = "Authorization".encode()
        self._basic_auth_data = None
        basic_auth_username = properties.get(b"userName", b"").decode("utf-8")
        basic_auth_password = properties.get(b"password", b"").decode("utf-8")
        if basic_auth_username and basic_auth_password:
            data = base64.b64encode(
                ("%s:%s" % (basic_auth_username,
                            basic_auth_password)).encode()).decode("utf-8")
            self._basic_auth_data = ("basic %s" % data).encode()

        try:
            major_api_version = CuraApplication.getInstance().getAPIVersion(
            ).getMajor()
        except AttributeError:
            # UM.Application.getAPIVersion was added for API > 6 (Cura 4)
            # Since this plugin version is only compatible with Cura 3.5 and newer, it is safe to assume API 5
            major_api_version = 5

        if major_api_version <= 5:
            # In Cura 3.x, the monitor item only shows the camera stream
            self._monitor_view_qml_path = os.path.join(
                os.path.dirname(os.path.abspath(__file__)), "qml",
                "MonitorItem3x.qml")
        else:
            # In Cura 4.x, the monitor item shows the camera stream as well as the monitor sidebar
            self._monitor_view_qml_path = os.path.join(
                os.path.dirname(os.path.abspath(__file__)), "qml",
                "MonitorItem4x.qml")

        name = self._id
        matches = re.search(r"^\"(.*)\"\._octoprint\._tcp.local$", name)
        if matches:
            name = matches.group(1)

        self.setPriority(
            2
        )  # Make sure the output device gets selected above local file output
        self.setName(name)
        self.setShortDescription(
            i18n_catalog.i18nc("@action:button", "Print with OctoPrint"))
        self.setDescription(
            i18n_catalog.i18nc("@properties:tooltip", "Print with OctoPrint"))
        self.setIconName("print")
        self.setConnectionText(
            i18n_catalog.i18nc("@info:status",
                               "Connected to OctoPrint on {0}").format(
                                   self._id))

        self._post_reply = None

        self._progress_message = None  # type: Union[None, Message]
        self._error_message = None  # type: Union[None, Message]
        self._connection_message = None  # type: Union[None, Message]

        self._queued_gcode_commands = []  # type: List[str]
        self._queued_gcode_timer = QTimer()
        self._queued_gcode_timer.setInterval(0)
        self._queued_gcode_timer.setSingleShot(True)
        self._queued_gcode_timer.timeout.connect(self._sendQueuedGcode)

        # TODO; Add preference for update intervals
        self._update_fast_interval = 2000
        self._update_slow_interval = 10000
        self._update_timer = QTimer()
        self._update_timer.setInterval(self._update_fast_interval)
        self._update_timer.setSingleShot(False)
        self._update_timer.timeout.connect(self._update)

        self._psucontrol_timer = QTimer()
        self._psucontrol_timer.setInterval(
            20000)  # TODO; Add preference for timer interval
        self._psucontrol_timer.setSingleShot(True)
        self._psucontrol_timer.timeout.connect(self._startPrint)

        self._show_camera = True
        self._camera_mirror = False
        self._camera_rotation = 0
        self._camera_url = ""
        self._camera_shares_proxy = False

        self._sd_supported = False  # supports storing gcode on sd card in printer
        self._ufp_supported = False  # supports .ufp files in addition to raw .gcode files

        self._plugin_data = {}  #type: Dict[str, Any]

        self._output_controller = GenericOutputController(self)
Example #50
0
class QualityManager(QObject):

    qualitiesUpdated = pyqtSignal()

    def __init__(self,
                 container_registry: "ContainerRegistry",
                 parent=None) -> None:
        super().__init__(parent)
        self._application = Application.getInstance()  # type: CuraApplication
        self._material_manager = self._application.getMaterialManager()
        self._container_registry = container_registry

        self._empty_quality_container = self._application.empty_quality_container
        self._empty_quality_changes_container = self._application.empty_quality_changes_container

        # For quality lookup
        self._machine_nozzle_buildplate_material_quality_type_to_quality_dict = {
        }  # type: Dict[str, QualityNode]

        # For quality_changes lookup
        self._machine_quality_type_to_quality_changes_dict = {
        }  # type: Dict[str, QualityNode]

        self._default_machine_definition_id = "fdmprinter"

        self._container_registry.containerMetaDataChanged.connect(
            self._onContainerMetadataChanged)
        self._container_registry.containerAdded.connect(
            self._onContainerMetadataChanged)
        self._container_registry.containerRemoved.connect(
            self._onContainerMetadataChanged)

        # When a custom quality gets added/imported, there can be more than one InstanceContainers. In those cases,
        # we don't want to react on every container/metadata changed signal. The timer here is to buffer it a bit so
        # we don't react too many time.
        self._update_timer = QTimer(self)
        self._update_timer.setInterval(300)
        self._update_timer.setSingleShot(True)
        self._update_timer.timeout.connect(self._updateMaps)

    def initialize(self) -> None:
        # Initialize the lookup tree for quality profiles with following structure:
        # <machine> -> <nozzle> -> <buildplate> -> <material>
        # <machine> -> <material>

        self._machine_nozzle_buildplate_material_quality_type_to_quality_dict = {
        }  # for quality lookup
        self._machine_quality_type_to_quality_changes_dict = {
        }  # for quality_changes lookup

        quality_metadata_list = self._container_registry.findContainersMetadata(
            type="quality")
        for metadata in quality_metadata_list:
            if metadata["id"] == "empty_quality":
                continue

            definition_id = metadata["definition"]
            quality_type = metadata["quality_type"]

            root_material_id = metadata.get("material")
            nozzle_name = metadata.get("variant")
            buildplate_name = metadata.get("buildplate")
            is_global_quality = metadata.get("global_quality", False)
            is_global_quality = is_global_quality or (
                root_material_id is None and nozzle_name is None
                and buildplate_name is None)

            # Sanity check: material+variant and is_global_quality cannot be present at the same time
            if is_global_quality and (root_material_id or nozzle_name):
                ConfigurationErrorMessage.getInstance().addFaultyContainers(
                    metadata["id"])
                continue

            if definition_id not in self._machine_nozzle_buildplate_material_quality_type_to_quality_dict:
                self._machine_nozzle_buildplate_material_quality_type_to_quality_dict[
                    definition_id] = QualityNode()
            machine_node = cast(
                QualityNode, self.
                _machine_nozzle_buildplate_material_quality_type_to_quality_dict[
                    definition_id])

            if is_global_quality:
                # For global qualities, save data in the machine node
                machine_node.addQualityMetadata(quality_type, metadata)
                continue

            current_node = machine_node
            intermediate_node_info_list = [
                nozzle_name, buildplate_name, root_material_id
            ]
            current_intermediate_node_info_idx = 0

            while current_intermediate_node_info_idx < len(
                    intermediate_node_info_list):
                node_name = intermediate_node_info_list[
                    current_intermediate_node_info_idx]
                if node_name is not None:
                    # There is specific information, update the current node to go deeper so we can add this quality
                    # at the most specific branch in the lookup tree.
                    if node_name not in current_node.children_map:
                        current_node.children_map[node_name] = QualityNode()
                    current_node = cast(QualityNode,
                                        current_node.children_map[node_name])

                current_intermediate_node_info_idx += 1

            current_node.addQualityMetadata(quality_type, metadata)

        # Initialize the lookup tree for quality_changes profiles with following structure:
        # <machine> -> <quality_type> -> <name>
        quality_changes_metadata_list = self._container_registry.findContainersMetadata(
            type="quality_changes")
        for metadata in quality_changes_metadata_list:
            if metadata["id"] == "empty_quality_changes":
                continue

            machine_definition_id = metadata["definition"]
            quality_type = metadata["quality_type"]

            if machine_definition_id not in self._machine_quality_type_to_quality_changes_dict:
                self._machine_quality_type_to_quality_changes_dict[
                    machine_definition_id] = QualityNode()
            machine_node = self._machine_quality_type_to_quality_changes_dict[
                machine_definition_id]
            machine_node.addQualityChangesMetadata(quality_type, metadata)

        Logger.log("d", "Lookup tables updated.")
        self.qualitiesUpdated.emit()

    def _updateMaps(self) -> None:
        self.initialize()

    def _onContainerMetadataChanged(self,
                                    container: InstanceContainer) -> None:
        self._onContainerChanged(container)

    def _onContainerChanged(self, container: InstanceContainer) -> None:
        container_type = container.getMetaDataEntry("type")
        if container_type not in ("quality", "quality_changes"):
            return

        # update the cache table
        self._update_timer.start()

    # Updates the given quality groups' availabilities according to which extruders are being used/ enabled.
    def _updateQualityGroupsAvailability(self, machine: "GlobalStack",
                                         quality_group_list) -> None:
        used_extruders = set()
        for i in range(machine.getProperty("machine_extruder_count", "value")):
            if str(i) in machine.extruders and machine.extruders[str(
                    i)].isEnabled:
                used_extruders.add(str(i))

        # Update the "is_available" flag for each quality group.
        for quality_group in quality_group_list:
            is_available = True
            if quality_group.node_for_global is None:
                is_available = False
            if is_available:
                for position in used_extruders:
                    if position not in quality_group.nodes_for_extruders:
                        is_available = False
                        break

            quality_group.is_available = is_available

    # Returns a dict of "custom profile name" -> QualityChangesGroup
    def getQualityChangesGroups(self, machine: "GlobalStack") -> dict:
        machine_definition_id = getMachineDefinitionIDForQualitySearch(
            machine.definition)

        machine_node = self._machine_quality_type_to_quality_changes_dict.get(
            machine_definition_id)
        if not machine_node:
            Logger.log(
                "i",
                "Cannot find node for machine def [%s] in QualityChanges lookup table",
                machine_definition_id)
            return dict()

        # Update availability for each QualityChangesGroup:
        # A custom profile is always available as long as the quality_type it's based on is available
        quality_group_dict = self.getQualityGroups(machine)
        available_quality_type_list = [
            qt for qt, qg in quality_group_dict.items() if qg.is_available
        ]

        # Iterate over all quality_types in the machine node
        quality_changes_group_dict = dict()
        for quality_type, quality_changes_node in machine_node.quality_type_map.items(
        ):
            for quality_changes_name, quality_changes_group in quality_changes_node.children_map.items(
            ):
                quality_changes_group_dict[
                    quality_changes_name] = quality_changes_group
                quality_changes_group.is_available = quality_type in available_quality_type_list

        return quality_changes_group_dict

    #
    # Gets all quality groups for the given machine. Both available and none available ones will be included.
    # It returns a dictionary with "quality_type"s as keys and "QualityGroup"s as values.
    # Whether a QualityGroup is available can be unknown via the field QualityGroup.is_available.
    # For more details, see QualityGroup.
    #
    def getQualityGroups(self,
                         machine: "GlobalStack") -> Dict[str, QualityGroup]:
        machine_definition_id = getMachineDefinitionIDForQualitySearch(
            machine.definition)

        # This determines if we should only get the global qualities for the global stack and skip the global qualities for the extruder stacks
        has_machine_specific_qualities = machine.getHasMachineQuality()

        # To find the quality container for the GlobalStack, check in the following fall-back manner:
        #   (1) the machine-specific node
        #   (2) the generic node
        machine_node = self._machine_nozzle_buildplate_material_quality_type_to_quality_dict.get(
            machine_definition_id)
        # Check if this machine has specific quality profiles for its extruders, if so, when looking up extruder
        # qualities, we should not fall back to use the global qualities.
        has_extruder_specific_qualities = False
        if machine_node:
            if machine_node.children_map:
                has_extruder_specific_qualities = True

        default_machine_node = self._machine_nozzle_buildplate_material_quality_type_to_quality_dict.get(
            self._default_machine_definition_id)

        nodes_to_check = []  # type: List[QualityNode]
        if machine_node is not None:
            nodes_to_check.append(machine_node)
        if default_machine_node is not None:
            nodes_to_check.append(default_machine_node)

        # Iterate over all quality_types in the machine node
        quality_group_dict = {}
        for node in nodes_to_check:
            if node and node.quality_type_map:
                quality_node = list(node.quality_type_map.values())[0]
                is_global_quality = parseBool(
                    quality_node.getMetaDataEntry("global_quality", False))
                if not is_global_quality:
                    continue

                for quality_type, quality_node in node.quality_type_map.items(
                ):
                    quality_group = QualityGroup(
                        quality_node.getMetaDataEntry("name", ""),
                        quality_type)
                    quality_group.node_for_global = quality_node
                    quality_group_dict[quality_type] = quality_group
                break

        buildplate_name = machine.getBuildplateName()

        # Iterate over all extruders to find quality containers for each extruder
        for position, extruder in machine.extruders.items():
            nozzle_name = None
            if extruder.variant.getId() != "empty_variant":
                nozzle_name = extruder.variant.getName()

            # This is a list of root material IDs to use for searching for suitable quality profiles.
            # The root material IDs in this list are in prioritized order.
            root_material_id_list = []
            has_material = False  # flag indicating whether this extruder has a material assigned
            root_material_id = None
            if extruder.material.getId() != "empty_material":
                has_material = True
                root_material_id = extruder.material.getMetaDataEntry(
                    "base_file")
                # Convert possible generic_pla_175 -> generic_pla
                root_material_id = self._material_manager.getRootMaterialIDWithoutDiameter(
                    root_material_id)
                root_material_id_list.append(root_material_id)

                # Also try to get the fallback material
                material_type = extruder.material.getMetaDataEntry("material")
                fallback_root_material_id = self._material_manager.getFallbackMaterialIdByMaterialType(
                    material_type)
                if fallback_root_material_id:
                    root_material_id_list.append(fallback_root_material_id)

            # Here we construct a list of nodes we want to look for qualities with the highest priority first.
            # The use case is that, when we look for qualities for a machine, we first want to search in the following
            # order:
            #   1. machine-nozzle-buildplate-and-material-specific qualities if exist
            #   2. machine-nozzle-and-material-specific qualities if exist
            #   3. machine-nozzle-specific qualities if exist
            #   4. machine-material-specific qualities if exist
            #   5. machine-specific global qualities if exist, otherwise generic global qualities
            #      NOTE: We DO NOT fail back to generic global qualities if machine-specific global qualities exist.
            #            This is because when a machine defines its own global qualities such as Normal, Fine, etc.,
            #            it is intended to maintain those specific qualities ONLY. If we still fail back to the generic
            #            global qualities, there can be unimplemented quality types e.g. "coarse", and this is not
            #            correct.
            # Each points above can be represented as a node in the lookup tree, so here we simply put those nodes into
            # the list with priorities as the order. Later, we just need to loop over each node in this list and fetch
            # qualities from there.
            node_info_list_0 = [
                nozzle_name, buildplate_name, root_material_id
            ]  # type: List[Optional[str]]
            nodes_to_check = []

            # This function tries to recursively find the deepest (the most specific) branch and add those nodes to
            # the search list in the order described above. So, by iterating over that search node list, we first look
            # in the more specific branches and then the less specific (generic) ones.
            def addNodesToCheck(node: Optional[QualityNode],
                                nodes_to_check_list: List[QualityNode],
                                node_info_list, node_info_idx: int) -> None:
                if node is None:
                    return

                if node_info_idx < len(node_info_list):
                    node_name = node_info_list[node_info_idx]
                    if node_name is not None:
                        current_node = node.getChildNode(node_name)
                        if current_node is not None and has_material:
                            addNodesToCheck(current_node, nodes_to_check_list,
                                            node_info_list, node_info_idx + 1)

                if has_material:
                    for rmid in root_material_id_list:
                        material_node = node.getChildNode(rmid)
                        if material_node:
                            nodes_to_check_list.append(material_node)
                            break

                nodes_to_check_list.append(node)

            addNodesToCheck(machine_node, nodes_to_check, node_info_list_0, 0)

            # The last fall back will be the global qualities (either from the machine-specific node or the generic
            # node), but we only use one. For details see the overview comments above.

            if machine_node is not None and machine_node.quality_type_map:
                nodes_to_check += [machine_node]
            elif default_machine_node is not None:
                nodes_to_check += [default_machine_node]

            for node_idx, node in enumerate(nodes_to_check):
                if node and node.quality_type_map:
                    if has_extruder_specific_qualities:
                        # Only include variant qualities; skip non global qualities
                        quality_node = list(node.quality_type_map.values())[0]
                        is_global_quality = parseBool(
                            quality_node.getMetaDataEntry(
                                "global_quality", False))
                        if is_global_quality:
                            continue

                    for quality_type, quality_node in node.quality_type_map.items(
                    ):
                        if quality_type not in quality_group_dict:
                            quality_group = QualityGroup(
                                quality_node.getMetaDataEntry("name", ""),
                                quality_type)
                            quality_group_dict[quality_type] = quality_group

                        quality_group = quality_group_dict[quality_type]
                        if position not in quality_group.nodes_for_extruders:
                            quality_group.nodes_for_extruders[
                                position] = quality_node

                # If the machine has its own specific qualities, for extruders, it should skip the global qualities
                # and use the material/variant specific qualities.
                if has_extruder_specific_qualities:
                    if node_idx == len(nodes_to_check) - 1:
                        break

        # Update availabilities for each quality group
        self._updateQualityGroupsAvailability(machine,
                                              quality_group_dict.values())

        return quality_group_dict

    def getQualityGroupsForMachineDefinition(
            self, machine: "GlobalStack") -> Dict[str, QualityGroup]:
        machine_definition_id = getMachineDefinitionIDForQualitySearch(
            machine.definition)

        # To find the quality container for the GlobalStack, check in the following fall-back manner:
        #   (1) the machine-specific node
        #   (2) the generic node
        machine_node = self._machine_nozzle_buildplate_material_quality_type_to_quality_dict.get(
            machine_definition_id)
        default_machine_node = self._machine_nozzle_buildplate_material_quality_type_to_quality_dict.get(
            self._default_machine_definition_id)
        nodes_to_check = [machine_node, default_machine_node]

        # Iterate over all quality_types in the machine node
        quality_group_dict = dict()
        for node in nodes_to_check:
            if node and node.quality_type_map:
                for quality_type, quality_node in node.quality_type_map.items(
                ):
                    quality_group = QualityGroup(
                        quality_node.getMetaDataEntry("name", ""),
                        quality_type)
                    quality_group.node_for_global = quality_node
                    quality_group_dict[quality_type] = quality_group
                break

        return quality_group_dict

    def getDefaultQualityType(
            self, machine: "GlobalStack") -> Optional[QualityGroup]:
        preferred_quality_type = machine.definition.getMetaDataEntry(
            "preferred_quality_type")
        quality_group_dict = self.getQualityGroups(machine)
        quality_group = quality_group_dict.get(preferred_quality_type)
        return quality_group

    #
    # Methods for GUI
    #

    #
    # Remove the given quality changes group.
    #
    @pyqtSlot(QObject)
    def removeQualityChangesGroup(
            self, quality_changes_group: "QualityChangesGroup") -> None:
        Logger.log("i", "Removing quality changes group [%s]",
                   quality_changes_group.name)
        removed_quality_changes_ids = set()
        for node in quality_changes_group.getAllNodes():
            container_id = node.getMetaDataEntry("id")
            self._container_registry.removeContainer(container_id)
            removed_quality_changes_ids.add(container_id)

        # Reset all machines that have activated this quality changes to empty.
        for global_stack in self._container_registry.findContainerStacks(
                type="machine"):
            if global_stack.qualityChanges.getId(
            ) in removed_quality_changes_ids:
                global_stack.qualityChanges = self._empty_quality_changes_container
        for extruder_stack in self._container_registry.findContainerStacks(
                type="extruder_train"):
            if extruder_stack.qualityChanges.getId(
            ) in removed_quality_changes_ids:
                extruder_stack.qualityChanges = self._empty_quality_changes_container

    #
    # Rename a set of quality changes containers. Returns the new name.
    #
    @pyqtSlot(QObject, str, result=str)
    def renameQualityChangesGroup(self,
                                  quality_changes_group: "QualityChangesGroup",
                                  new_name: str) -> str:
        Logger.log("i", "Renaming QualityChangesGroup[%s] to [%s]",
                   quality_changes_group.name, new_name)
        if new_name == quality_changes_group.name:
            Logger.log("i", "QualityChangesGroup name [%s] unchanged.",
                       quality_changes_group.name)
            return new_name

        new_name = self._container_registry.uniqueName(new_name)
        for node in quality_changes_group.getAllNodes():
            container = node.getContainer()
            if container:
                container.setName(new_name)

        quality_changes_group.name = new_name

        self._application.getMachineManager().activeQualityChanged.emit()
        self._application.getMachineManager().activeQualityGroupChanged.emit()

        return new_name

    #
    # Duplicates the given quality.
    #
    @pyqtSlot(str, "QVariantMap")
    def duplicateQualityChanges(self, quality_changes_name: str,
                                quality_model_item) -> None:
        global_stack = self._application.getGlobalContainerStack()
        if not global_stack:
            Logger.log(
                "i",
                "No active global stack, cannot duplicate quality changes.")
            return

        quality_group = quality_model_item["quality_group"]
        quality_changes_group = quality_model_item["quality_changes_group"]
        if quality_changes_group is None:
            # create global quality changes only
            new_quality_changes = self._createQualityChanges(
                quality_group.quality_type, quality_changes_name, global_stack,
                None)
            self._container_registry.addContainer(new_quality_changes)
        else:
            new_name = self._container_registry.uniqueName(
                quality_changes_name)
            for node in quality_changes_group.getAllNodes():
                container = node.getContainer()
                if not container:
                    continue
                new_id = self._container_registry.uniqueName(container.getId())
                self._container_registry.addContainer(
                    container.duplicate(new_id, new_name))

    ##  Create quality changes containers from the user containers in the active stacks.
    #
    #   This will go through the global and extruder stacks and create quality_changes containers from
    #   the user containers in each stack. These then replace the quality_changes containers in the
    #   stack and clear the user settings.
    @pyqtSlot(str)
    def createQualityChanges(self, base_name: str) -> None:
        machine_manager = Application.getInstance().getMachineManager()

        global_stack = machine_manager.activeMachine
        if not global_stack:
            return

        active_quality_name = machine_manager.activeQualityOrQualityChangesName
        if active_quality_name == "":
            Logger.log(
                "w",
                "No quality container found in stack %s, cannot create profile",
                global_stack.getId())
            return

        machine_manager.blurSettings.emit()
        if base_name is None or base_name == "":
            base_name = active_quality_name
        unique_name = self._container_registry.uniqueName(base_name)

        # Go through the active stacks and create quality_changes containers from the user containers.
        stack_list = [global_stack] + list(global_stack.extruders.values())
        for stack in stack_list:
            user_container = stack.userChanges
            quality_container = stack.quality
            quality_changes_container = stack.qualityChanges
            if not quality_container or not quality_changes_container:
                Logger.log(
                    "w",
                    "No quality or quality changes container found in stack %s, ignoring it",
                    stack.getId())
                continue

            quality_type = quality_container.getMetaDataEntry("quality_type")
            extruder_stack = None
            if isinstance(stack, ExtruderStack):
                extruder_stack = stack
            new_changes = self._createQualityChanges(quality_type, unique_name,
                                                     global_stack,
                                                     extruder_stack)
            from cura.Settings.ContainerManager import ContainerManager
            ContainerManager.getInstance()._performMerge(
                new_changes, quality_changes_container, clear_settings=False)
            ContainerManager.getInstance()._performMerge(
                new_changes, user_container)

            self._container_registry.addContainer(new_changes)

    #
    # Create a quality changes container with the given setup.
    #
    def _createQualityChanges(
            self, quality_type: str, new_name: str, machine: "GlobalStack",
            extruder_stack: Optional["ExtruderStack"]) -> "InstanceContainer":
        base_id = machine.definition.getId(
        ) if extruder_stack is None else extruder_stack.getId()
        new_id = base_id + "_" + new_name
        new_id = new_id.lower().replace(" ", "_")
        new_id = self._container_registry.uniqueName(new_id)

        # Create a new quality_changes container for the quality.
        quality_changes = InstanceContainer(new_id)
        quality_changes.setName(new_name)
        quality_changes.setMetaDataEntry("type", "quality_changes")
        quality_changes.setMetaDataEntry("quality_type", quality_type)

        # If we are creating a container for an extruder, ensure we add that to the container
        if extruder_stack is not None:
            quality_changes.setMetaDataEntry(
                "position", extruder_stack.getMetaDataEntry("position"))

        # If the machine specifies qualities should be filtered, ensure we match the current criteria.
        machine_definition_id = getMachineDefinitionIDForQualitySearch(
            machine.definition)
        quality_changes.setDefinition(machine_definition_id)

        quality_changes.setMetaDataEntry("setting_version",
                                         self._application.SettingVersion)
        return quality_changes
Example #51
0
class Account(QObject):
    """The account API provides a version-proof bridge to use Ultimaker Accounts

    Usage:

    .. code-block:: python

      from cura.API import CuraAPI
      api = CuraAPI()
      api.account.login()
      api.account.logout()
      api.account.userProfile    # Who is logged in
    """

    # The interval in which sync services are automatically triggered
    SYNC_INTERVAL = 60.0  # seconds
    Q_ENUMS(SyncState)

    loginStateChanged = pyqtSignal(bool)
    """Signal emitted when user logged in or out"""

    accessTokenChanged = pyqtSignal()
    syncRequested = pyqtSignal()
    """Sync services may connect to this signal to receive sync triggers.
    Services should be resilient to receiving a signal while they are still syncing,
    either by ignoring subsequent signals or restarting a sync.
    See setSyncState() for providing user feedback on the state of your service. 
    """
    lastSyncDateTimeChanged = pyqtSignal()
    syncStateChanged = pyqtSignal(int)  # because SyncState is an int Enum
    manualSyncEnabledChanged = pyqtSignal(bool)
    updatePackagesEnabledChanged = pyqtSignal(bool)

    CLIENT_SCOPES = "account.user.read drive.backup.read drive.backup.write packages.download " \
                    "packages.rating.read packages.rating.write connect.cluster.read connect.cluster.write " \
                    "library.project.read library.project.write cura.printjob.read cura.printjob.write " \
                    "cura.mesh.read cura.mesh.write"

    def __init__(self, application: "CuraApplication", parent=None) -> None:
        super().__init__(parent)
        self._application = application
        self._new_cloud_printers_detected = False

        self._error_message = None  # type: Optional[Message]
        self._logged_in = False
        self._sync_state = SyncState.IDLE
        self._manual_sync_enabled = False
        self._update_packages_enabled = False
        self._update_packages_action = None  # type: Optional[Callable]
        self._last_sync_str = "-"

        self._callback_port = 32118
        self._oauth_root = UltimakerCloudConstants.CuraCloudAccountAPIRoot

        self._oauth_settings = OAuth2Settings(
            OAUTH_SERVER_URL=self._oauth_root,
            CALLBACK_PORT=self._callback_port,
            CALLBACK_URL="http://localhost:{}/callback".format(
                self._callback_port),
            CLIENT_ID="um----------------------------ultimaker_cura",
            CLIENT_SCOPES=self.CLIENT_SCOPES,
            AUTH_DATA_PREFERENCE_KEY="general/ultimaker_auth_data",
            AUTH_SUCCESS_REDIRECT="{}/app/auth-success".format(
                self._oauth_root),
            AUTH_FAILED_REDIRECT="{}/app/auth-error".format(self._oauth_root))

        self._authorization_service = AuthorizationService(
            self._oauth_settings)

        # Create a timer for automatic account sync
        self._update_timer = QTimer()
        self._update_timer.setInterval(int(self.SYNC_INTERVAL * 1000))
        # The timer is restarted explicitly after an update was processed. This prevents 2 concurrent updates
        self._update_timer.setSingleShot(True)
        self._update_timer.timeout.connect(self.sync)

        self._sync_services = {}  # type: Dict[str, int]
        """contains entries "service_name" : SyncState"""

    def initialize(self) -> None:
        self._authorization_service.initialize(
            self._application.getPreferences())
        self._authorization_service.onAuthStateChanged.connect(
            self._onLoginStateChanged)
        self._authorization_service.onAuthenticationError.connect(
            self._onLoginStateChanged)
        self._authorization_service.accessTokenChanged.connect(
            self._onAccessTokenChanged)
        self._authorization_service.loadAuthDataFromPreferences()

    @pyqtProperty(int, notify=syncStateChanged)
    def syncState(self):
        return self._sync_state

    def setSyncState(self, service_name: str, state: int) -> None:
        """ Can be used to register sync services and update account sync states

        Contract: A sync service is expected exit syncing state in all cases, within reasonable time

        Example: `setSyncState("PluginSyncService", SyncState.SYNCING)`
        :param service_name: A unique name for your service, such as `plugins` or `backups`
        :param state: One of SyncState
        """
        prev_state = self._sync_state

        self._sync_services[service_name] = state

        if any(val == SyncState.SYNCING
               for val in self._sync_services.values()):
            self._sync_state = SyncState.SYNCING
            self._setManualSyncEnabled(False)
        elif any(val == SyncState.ERROR
                 for val in self._sync_services.values()):
            self._sync_state = SyncState.ERROR
            self._setManualSyncEnabled(True)
        else:
            self._sync_state = SyncState.SUCCESS
            self._setManualSyncEnabled(False)

        if self._sync_state != prev_state:
            self.syncStateChanged.emit(self._sync_state)

            if self._sync_state == SyncState.SUCCESS:
                self._last_sync_str = datetime.now().strftime("%d/%m/%Y %H:%M")
                self.lastSyncDateTimeChanged.emit()

            if self._sync_state != SyncState.SYNCING:
                # schedule new auto update after syncing completed (for whatever reason)
                if not self._update_timer.isActive():
                    self._update_timer.start()

    def setUpdatePackagesAction(self, action: Callable) -> None:
        """ Set the callback which will be invoked when the user clicks the update packages button

        Should be invoked after your service sets the sync state to SYNCING and before setting the
        sync state to SUCCESS.

        Action will be reset to None when the next sync starts
        """
        self._update_packages_action = action
        self._update_packages_enabled = True
        self.updatePackagesEnabledChanged.emit(self._update_packages_enabled)

    def _onAccessTokenChanged(self):
        self.accessTokenChanged.emit()

    @property
    def is_staging(self) -> bool:
        """Indication whether the given authentication is applied against staging or not."""

        return "staging" in self._oauth_root

    @pyqtProperty(bool, notify=loginStateChanged)
    def isLoggedIn(self) -> bool:
        return self._logged_in

    def _onLoginStateChanged(self,
                             logged_in: bool = False,
                             error_message: Optional[str] = None) -> None:
        if error_message:
            if self._error_message:
                self._error_message.hide()
            Logger.log("w", "Failed to login: %s", error_message)
            self._error_message = Message(
                error_message,
                title=i18n_catalog.i18nc("@info:title", "Login failed"),
                message_type=Message.MessageType.ERROR)
            self._error_message.show()
            self._logged_in = False
            self.loginStateChanged.emit(False)
            if self._update_timer.isActive():
                self._update_timer.stop()
            return

        if self._logged_in != logged_in:
            self._logged_in = logged_in
            self.loginStateChanged.emit(logged_in)
            if logged_in:
                self._setManualSyncEnabled(False)
                self._sync()
            else:
                if self._update_timer.isActive():
                    self._update_timer.stop()

    def _sync(self) -> None:
        """Signals all sync services to start syncing

        This can be considered a forced sync: even when a
        sync is currently running, a sync will be requested.
        """

        self._update_packages_action = None
        self._update_packages_enabled = False
        self.updatePackagesEnabledChanged.emit(self._update_packages_enabled)
        if self._update_timer.isActive():
            self._update_timer.stop()
        elif self._sync_state == SyncState.SYNCING:
            Logger.debug(
                "Starting a new sync while previous sync was not completed")

        self.syncRequested.emit()

    def _setManualSyncEnabled(self, enabled: bool) -> None:
        if self._manual_sync_enabled != enabled:
            self._manual_sync_enabled = enabled
            self.manualSyncEnabledChanged.emit(enabled)

    @pyqtSlot()
    @pyqtSlot(bool)
    def login(self, force_logout_before_login: bool = False) -> None:
        """
        Initializes the login process. If the user is logged in already and force_logout_before_login is true, Cura will
        logout from the account before initiating the authorization flow. If the user is logged in and
        force_logout_before_login is false, the function will return, as there is nothing to do.

        :param force_logout_before_login: Optional boolean parameter
        :return: None
        """
        if self._logged_in:
            if force_logout_before_login:
                self.logout()
            else:
                # Nothing to do, user already logged in.
                return
        self._authorization_service.startAuthorizationFlow(
            force_logout_before_login)

    @pyqtProperty(str, notify=loginStateChanged)
    def userName(self):
        user_profile = self._authorization_service.getUserProfile()
        if not user_profile:
            return None
        return user_profile.username

    @pyqtProperty(str, notify=loginStateChanged)
    def profileImageUrl(self):
        user_profile = self._authorization_service.getUserProfile()
        if not user_profile:
            return None
        return user_profile.profile_image_url

    @pyqtProperty(str, notify=accessTokenChanged)
    def accessToken(self) -> Optional[str]:
        return self._authorization_service.getAccessToken()

    @pyqtProperty("QVariantMap", notify=loginStateChanged)
    def userProfile(self) -> Optional[Dict[str, Optional[str]]]:
        """None if no user is logged in otherwise the logged in  user as a dict containing containing user_id, username and profile_image_url """

        user_profile = self._authorization_service.getUserProfile()
        if not user_profile:
            return None
        return user_profile.__dict__

    @pyqtProperty(str, notify=lastSyncDateTimeChanged)
    def lastSyncDateTime(self) -> str:
        return self._last_sync_str

    @pyqtProperty(bool, notify=manualSyncEnabledChanged)
    def manualSyncEnabled(self) -> bool:
        return self._manual_sync_enabled

    @pyqtProperty(bool, notify=updatePackagesEnabledChanged)
    def updatePackagesEnabled(self) -> bool:
        return self._update_packages_enabled

    @pyqtSlot()
    @pyqtSlot(bool)
    def sync(self, user_initiated: bool = False) -> None:
        if user_initiated:
            self._setManualSyncEnabled(False)

        self._sync()

    @pyqtSlot()
    def onUpdatePackagesClicked(self) -> None:
        if self._update_packages_action is not None:
            self._update_packages_action()

    @pyqtSlot()
    def popupOpened(self) -> None:
        self._setManualSyncEnabled(True)

    @pyqtSlot()
    def logout(self) -> None:
        if not self._logged_in:
            return  # Nothing to do, user isn't logged in.

        self._authorization_service.deleteAuthData()
Example #52
0
class SegmentDisplay4x7(PluginBase, Ui_SegmentDisplay4x7):
    qtcb_finished = pyqtSignal()
    STYLE_OFF = QColor(Qt.gray)
    STYLE_ON = [
        QColor(0x88, 0, 0),
        QColor(0x99, 0, 0),
        QColor(0xAA, 0, 0),
        QColor(0xBB, 0, 0),
        QColor(0xCC, 0, 0),
        QColor(0xDD, 0, 0),
        QColor(0xEE, 0, 0),
        QColor(0xFF, 0, 0)
    ]

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

        self.setupUi(self)

        self.sd4x7 = self.device

        self.qtcb_finished.connect(self.cb_counter_finished)
        self.sd4x7.register_callback(self.sd4x7.CALLBACK_COUNTER_FINISHED,
                                     self.qtcb_finished.emit)

        self.digit0 = [
            self.digit0_segment0, self.digit0_segment1, self.digit0_segment2,
            self.digit0_segment3, self.digit0_segment4, self.digit0_segment5,
            self.digit0_segment6
        ]
        self.digit1 = [
            self.digit1_segment0, self.digit1_segment1, self.digit1_segment2,
            self.digit1_segment3, self.digit1_segment4, self.digit1_segment5,
            self.digit1_segment6
        ]
        self.digit2 = [
            self.digit2_segment0, self.digit2_segment1, self.digit2_segment2,
            self.digit2_segment3, self.digit2_segment4, self.digit2_segment5,
            self.digit2_segment6
        ]
        self.digit3 = [
            self.digit3_segment0, self.digit3_segment1, self.digit3_segment2,
            self.digit3_segment3, self.digit3_segment4, self.digit3_segment5,
            self.digit3_segment6
        ]
        self.points = [self.point0, self.point1]

        self.digits = [
            self.digit0, self.digit1, self.digit2, self.digit3, self.points
        ]
        self.digit_state = [[False] * 7, [False] * 7, [False] * 7, [False] * 7,
                            [False] * 2]

        self.all_buttons = []
        self.all_buttons.extend(self.points)
        self.all_buttons.extend(self.digit0)
        self.all_buttons.extend(self.digit1)
        self.all_buttons.extend(self.digit2)
        self.all_buttons.extend(self.digit3)

        self.brightness = 7
        self.box_brightness.currentIndexChanged.connect(
            self.brightness_changed)
        self.button_all_segments_on.clicked.connect(
            self.all_segments_on_clicked)
        self.button_all_segments_off.clicked.connect(
            self.all_segments_off_clicked)
        self.button_start.clicked.connect(self.start_clicked)

        def get_clicked_func(digit, segment):
            return lambda: self.button_clicked(digit, segment)

        for d in range(4):
            for i in range(7):
                button = self.digits[d][i]
                button.initialize(self.STYLE_ON, self.STYLE_OFF)

                button.clicked.connect(get_clicked_func(d, i))

        for i in range(2):
            button = self.points[i]
            button.initialize(self.STYLE_ON, self.STYLE_OFF, style='circular')
            button.clicked.connect(get_clicked_func(4, i))

        self.counter_timer = QTimer(self)
        self.counter_timer.timeout.connect(self.update_counter)
        self.counter_timer.setInterval(100)

    def all_segments_on_clicked(self):
        self.counter_timer.stop()
        value = ([0xFF, 0xFF, 0xFF, 0xFF], self.brightness, True)
        self.sd4x7.set_segments(*value)
        self.get_segments_async(value)

    def all_segments_off_clicked(self):
        self.counter_timer.stop()
        value = ([0, 0, 0, 0], self.brightness, False)
        self.sd4x7.set_segments(*value)
        self.get_segments_async(value)

    def cb_counter_finished(self):
        self.counter_timer.stop()
        async_call(self.sd4x7.get_segments, None, self.get_segments_async,
                   self.increase_error_count)

    def update_counter(self):
        async_call(self.sd4x7.get_segments, None, self.get_segments_async,
                   self.increase_error_count)

    def start_clicked(self):
        fr = self.box_from.value()
        to = self.box_to.value()
        increment = self.box_increment.value()
        length = self.box_length.value()

        self.counter_timer.start()

        if (length == 0) or (increment == 0) or (increment > 0
                                                 and fr > to) or (increment < 0
                                                                  and fr < to):
            return

        self.sd4x7.start_counter(fr, to, increment, length)

    def brightness_changed(self, brightness):
        if self.brightness != brightness:
            self.brightness = brightness

            self.update_colors()
            self.update_segments()

    def update_colors(self):
        if self.digit_state[4][0]:
            self.digits[4][0].switch_on(self.brightness)
            self.digits[4][1].switch_on(self.brightness)

        for d in range(4):
            for s in range(7):
                if self.digit_state[d][s]:
                    self.digits[d][s].switch_on(self.brightness)

    def button_clicked(self, digit, segment):
        self.counter_timer.stop()
        if digit == 4:
            if self.digit_state[4][0]:
                self.digits[4][0].switch_off()
                self.digits[4][1].switch_off()
                self.digit_state[4][0] = False
                self.digit_state[4][1] = False
            else:
                self.digits[4][0].switch_on(self.brightness)
                self.digits[4][1].switch_on(self.brightness)
                self.digit_state[4][0] = True
                self.digit_state[4][1] = True
        else:
            if self.digit_state[digit][segment]:
                self.digits[digit][segment].switch_off()
                self.digit_state[digit][segment] = False
            else:
                self.digits[digit][segment].switch_on(self.brightness)
                self.digit_state[digit][segment] = True

        self.update_segments()

    def update_segments(self):
        segments = [0, 0, 0, 0]
        for d in range(4):
            for s in range(7):
                if self.digit_state[d][s]:
                    segments[d] |= (1 << s)

        self.sd4x7.set_segments(segments, self.brightness,
                                self.digit_state[4][0])

    def get_segments_async(self, value):
        segments, brightness, colon = value

        self.brightness = brightness
        self.box_brightness.setCurrentIndex(self.brightness)

        if colon:
            self.digit_state[4][0] = True
            self.digits[4][0].switch_on(self.brightness)
            self.digit_state[4][0] = True
            self.digits[4][1].switch_on(self.brightness)
        else:
            self.digit_state[4][0] = False
            self.digits[4][0].switch_off()
            self.digit_state[4][0] = False
            self.digits[4][1].switch_off()

        for d in range(4):
            for s in range(7):
                if segments[d] & (1 << s):
                    self.digit_state[d][s] = True
                    self.digits[d][s].switch_on(self.brightness)
                else:
                    self.digit_state[d][s] = False
                    self.digits[d][s].switch_off()

    def start(self):
        async_call(self.sd4x7.get_segments, None, self.get_segments_async,
                   self.increase_error_count)

    def stop(self):
        self.counter_timer.stop()

    def destroy(self):
        pass

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletSegmentDisplay4x7.DEVICE_IDENTIFIER
Example #53
0
class Q3DController(QObject):

    # requests
    BUILD_SCENE_ALL = 1  # build scene
    BUILD_SCENE = 2  # build scene, but do not update background color, coordinates display mode and so on

    def __init__(self, settings=None, thread=None, parent=None):
        super().__init__(parent)

        if settings is None:
            defaultSettings = {}
            settings = ExportSettings()
            settings.loadSettings(defaultSettings)

            err_msg = settings.checkValidity()
            if err_msg:
                logMessage("Invalid settings: " + err_msg)

        self.settings = settings
        self.builder = ThreeJSBuilder(settings)

        self.iface = Q3DControllerInterface(self)
        self.enabled = True
        self.aborted = False  # layer export aborted
        self.updating = False
        self.updatingLayerId = None
        self.layersNeedUpdate = False
        self.mapCanvas = None

        self.requestQueue = []
        self.timer = QTimer(self)
        self.timer.setInterval(1)
        self.timer.setSingleShot(True)

        # move to worker thread
        if thread:
            self.moveToThread(thread)

        self.timer.timeout.connect(self._processRequests)

        self.MSG1 = "Press ESC key to abort processing"

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

    def connectToIface(self, iface):
        """iface: Q3DInterface or its subclass"""
        self.iface.connectToIface(iface)

    def disconnectFromIface(self):
        self.iface.disconnectFromIface()
        # self.iface = Mock()

    def connectToMapCanvas(self, canvas):
        self.mapCanvas = canvas
        self.mapCanvas.renderComplete.connect(self._requestSceneUpdate)
        self.mapCanvas.extentsChanged.connect(self.updateExtent)

    def disconnectFromMapCanvas(self):
        if self.mapCanvas:
            self.mapCanvas.renderComplete.disconnect(self._requestSceneUpdate)
            self.mapCanvas.extentsChanged.disconnect(self.updateExtent)
            self.mapCanvas = None

    def abort(self):
        if self.updating and not self.aborted:
            self.aborted = True
            self.iface.showMessage("Aborting processing...")

    def setPreviewEnabled(self, enabled):
        self.enabled = enabled
        self.iface.runScript("app.resume();" if enabled else "app.pause();")

        elem = "document.getElementById('cover')"
        self.iface.runScript("{}.style.display = '{}';".format(
            elem, "none" if enabled else "block"))
        if not enabled:
            self.iface.runScript(
                "{}.innerHTML = '<img src=\"../Qgis2threejs.png\">';".format(
                    elem))
        else:
            self.buildScene()

    def buildScene(self,
                   update_scene_all=True,
                   build_layers=True,
                   build_scene=True,
                   update_extent=True,
                   base64=False):
        if self.updating:
            logMessage(
                "Previous building is still in progress. Cannot start to build scene."
            )
            return

        self.updating = True
        self.settings.base64 = base64
        self.layersNeedUpdate = self.layersNeedUpdate or build_layers

        self.iface.showMessage(self.MSG1)
        self.iface.progress(0, "Updating scene")

        if update_extent and self.mapCanvas:
            self.builder.settings.setMapCanvas(self.mapCanvas)

        if build_scene:
            self.iface.loadJSONObject(self.builder.buildScene(False))

        if update_scene_all:
            sp = self.settings.sceneProperties()
            # automatic z shift adjustment
            self.iface.runScript("Q3D.Config.autoZShift = {};".format(
                "true" if sp.get("checkBox_autoZShift") else "false"))

            # update background color
            params = "{0}, 1".format(
                sp.get("colorButton_Color",
                       0)) if sp.get("radioButton_Color") else "0, 0"
            self.iface.runScript("setBackgroundColor({0});".format(params))

            # coordinate display (geographic/projected)
            if sp.get("radioButton_WGS84", False):
                self.iface.loadScriptFile(pluginDir("js/proj4js/proj4.js"))
            else:
                self.iface.runScript("proj4 = undefined;",
                                     "// proj4 not enabled")

        if build_layers:
            self.iface.runScript('loadStart("LYRS", true);')

            layers = self.settings.getLayerList()
            for idx, layer in enumerate(
                    sorted(layers, key=lambda lyr: lyr.geomType)):
                self.iface.progress(idx / len(layers) * 100, "Updating layers")
                if layer.updated or (self.layersNeedUpdate and layer.visible):
                    ret = self._buildLayer(layer)
                    if not ret or self.aborted:
                        break
            self.iface.runScript('loadEnd("LYRS");')

            if not self.aborted:
                self.layersNeedUpdate = False

        self.updating = False
        self.updatingLayerId = None
        self.aborted = False
        self.iface.progress()
        self.iface.clearMessage()
        self.settings.base64 = False
        return True

    def buildLayer(self, layer):
        if isinstance(layer, dict):
            layer = Layer.fromDict(layer)

        if self.updating:
            logMessage(
                'Previous building is still in progress. Cannot start building layer "{}".'
                .format(layer.name))
            return False

        self.updating = True
        self.updatingLayerId = layer.layerId
        self.iface.showMessage(self.MSG1)
        self.iface.runScript('loadStart("LYR", true);')

        aborted = self._buildLayer(layer)

        self.iface.runScript('loadEnd("LYR");')
        self.updating = False
        self.updatingLayerId = None
        self.aborted = False
        self.iface.clearMessage()

        return aborted

    def _buildLayer(self, layer):
        self.iface.runScript('loadStart("L{}");  // {}'.format(
            layer.jsLayerId, layer.name))
        pmsg = "Building {0}...".format(layer.name)
        self.iface.progress(0, pmsg)

        if layer.properties.get("comboBox_ObjectType") == "Model File":
            self.iface.loadModelLoaders()

        ts0 = time.time()
        tss = []
        i = 0
        for builder in self.builder.builders(layer):
            self.iface.progress(i / (i + 4) * 100, pmsg)
            if self.aborted:
                self.iface.runScript("loadAborted();")
                logMessage("***** layer building aborted *****", False)
                return False
            ts1 = time.time()
            obj = builder.build()
            ts2 = time.time()
            self.iface.loadJSONObject(obj)
            ts3 = time.time()
            tss.append([ts2 - ts1, ts3 - ts2])
            QgsApplication.processEvents(
            )  # NOTE: process events only for the calling thread
            i += 1

        layer.updated = False

        self.iface.runScript('loadEnd("L{}");'.format(layer.jsLayerId))
        self.iface.progress()

        if DEBUG_MODE:
            msg = "updating {0} costed {1:.3f}s:\n{2}".format(
                layer.name,
                time.time() - ts0,
                "\n".join(["{:.3f} {:.3f}".format(ts[0], ts[1])
                           for ts in tss]))
            logMessage(msg, False)
        return True

    def hideLayer(self, layer):
        self.iface.runScript('hideLayer("{}")'.format(layer.jsLayerId))

    def hideAllLayers(self):
        self.iface.runScript("hideAllLayers()")

    def processRequests(self):
        self.timer.stop()
        if self.requestQueue:
            self.timer.start()

    def _processRequests(self):
        if not self.enabled or self.updating or not self.requestQueue:
            return

        try:
            if self.BUILD_SCENE_ALL in self.requestQueue:
                self.requestQueue.clear()
                self.buildScene()

            elif self.BUILD_SCENE in self.requestQueue:
                self.requestQueue.clear()
                self.buildScene(update_scene_all=False)

            else:
                layer = self.requestQueue.pop(0)
                if layer.visible:
                    self.buildLayer(layer)
                else:
                    self.hideLayer(layer)

        except Exception as e:
            import traceback
            logMessage(traceback.format_exc())

            self.iface.showMessageBar()

        self.processRequests()

    def requestSceneUpdate(self, properties=0, update_all=True):
        if DEBUG_MODE:
            logMessage("Scene update was requested: {}".format(properties))

        if isinstance(properties, dict):
            self.settings.setSceneProperties(properties)

        self.requestQueue.append(
            self.BUILD_SCENE_ALL if update_all else self.BUILD_SCENE)

        if self.updating:
            self.abort()
        else:
            self.processRequests()

    def requestLayerUpdate(self, layer):
        if DEBUG_MODE:
            logMessage("Layer update for {} was requested.".format(
                layer.layerId))

        # update layer properties and its state in export settings
        lyr = self.settings.getItemByLayerId(layer.layerId)
        if lyr is None:
            return

        layer.copyTo(lyr)

        self.requestQueue = [
            i for i in self.requestQueue if i.layerId != layer.layerId
        ]

        if self.updatingLayerId == layer.layerId:
            self.requestQueue.append(layer)
            self.abort()

        elif layer.visible:
            self.requestQueue.append(layer)

            if not self.updating:
                self.processRequests()

        else:
            # immediately hide the layer
            self.hideLayer(layer)

    def clearExportSettings(self):
        self.settings.clear()
        self.settings.updateLayerList()
        self.requestSceneUpdate()
        self.hideAllLayers()

    def _requestSceneUpdate(self, _=None):
        self.requestSceneUpdate(update_all=False)

    def updateExtent(self):
        self.layersNeedUpdate = True
        self.requestQueue.clear()
        if self.updating:
            self.abort()
Example #54
0
class IndustrialPTC(COMCUPluginBase):
    def __init__(self, *args):
        super().__init__(BrickletIndustrialPTC, *args)

        self.ptc = self.device

        self.str_connected = 'Sensor is <font color="green">connected</font>'
        self.str_not_connected = 'Sensor is <font color="red">not connected</font>'

        self.cbe_temperature = CallbackEmulator(self.ptc.get_temperature, None,
                                                self.cb_temperature,
                                                self.increase_error_count)

        self.wire_label = QLabel('Wire Type:')
        self.wire_combo = QComboBox()
        self.wire_combo.addItem('2-Wire')
        self.wire_combo.addItem('3-Wire')
        self.wire_combo.addItem('4-Wire')

        self.noise_label = QLabel('Noise Rejection Filter:')
        self.noise_combo = QComboBox()
        self.noise_combo.addItem('50 Hz')
        self.noise_combo.addItem('60 Hz')

        self.connected_label = QLabel(self.str_connected)

        self.current_temperature = CurveValueWrapper()  # float, °C

        self.wire_combo.currentIndexChanged.connect(
            self.wire_combo_index_changed)
        self.noise_combo.currentIndexChanged.connect(
            self.noise_combo_index_changed)

        plots = [('Temperature', Qt.red, self.current_temperature,
                  '{} °C'.format)]
        self.plot_widget = PlotWidget('Temperature [°C]',
                                      plots,
                                      extra_key_widgets=[self.connected_label],
                                      y_resolution=0.01)

        hlayout = QHBoxLayout()
        hlayout.addWidget(self.wire_label)
        hlayout.addWidget(self.wire_combo)
        hlayout.addStretch()
        hlayout.addWidget(self.noise_label)
        hlayout.addWidget(self.noise_combo)

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

        layout = QVBoxLayout(self)
        layout.addWidget(self.plot_widget)
        layout.addWidget(line)
        layout.addLayout(hlayout)

        self.connected_timer = QTimer(self)
        self.connected_timer.timeout.connect(self.update_connected)
        self.connected_timer.setInterval(1000)

    def start(self):
        async_call(self.ptc.is_sensor_connected, None,
                   self.is_sensor_connected_async, self.increase_error_count)
        async_call(self.ptc.get_noise_rejection_filter, None,
                   self.get_noise_rejection_filter_async,
                   self.increase_error_count)
        async_call(self.ptc.get_wire_mode, None, self.get_wire_mode_async,
                   self.increase_error_count)

        self.connected_timer.start()

        self.cbe_temperature.set_period(100)

        self.plot_widget.stop = False

    def stop(self):
        self.connected_timer.stop()

        self.cbe_temperature.set_period(0)

        self.plot_widget.stop = True

    def destroy(self):
        pass

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

    def update_connected(self):
        async_call(self.ptc.is_sensor_connected, None,
                   self.is_sensor_connected_async, self.increase_error_count)

    def wire_combo_index_changed(self, index):
        async_call(self.ptc.set_wire_mode, index + 2, None,
                   self.increase_error_count)

    def noise_combo_index_changed(self, index):
        async_call(self.ptc.set_noise_rejection_filter, index, None,
                   self.increase_error_count)

    def is_sensor_connected_async(self, connected):
        if connected:
            self.connected_label.setText(self.str_connected)
        else:
            self.connected_label.setText(self.str_not_connected)

    def get_noise_rejection_filter_async(self, filter_option):
        self.noise_combo.setCurrentIndex(filter_option)

    def get_wire_mode_async(self, mode):
        self.wire_combo.setCurrentIndex(mode - 2)

    def cb_temperature(self, temperature):
        self.current_temperature.value = temperature / 100.0

    def cb_resistance(self, resistance):
        resistance_str = str(round(resistance * 3900.0 / (1 << 15), 1))
        self.resistance_label.setText(resistance_str)
Example #55
0
    def __init__(self, *args):
        PluginBase.__init__(self, BrickletSegmentDisplay4x7, *args)

        self.setupUi(self)

        self.sd4x7 = self.device

        self.qtcb_finished.connect(self.cb_counter_finished)
        self.sd4x7.register_callback(self.sd4x7.CALLBACK_COUNTER_FINISHED,
                                     self.qtcb_finished.emit)

        self.digit0 = [
            self.digit0_segment0, self.digit0_segment1, self.digit0_segment2,
            self.digit0_segment3, self.digit0_segment4, self.digit0_segment5,
            self.digit0_segment6
        ]
        self.digit1 = [
            self.digit1_segment0, self.digit1_segment1, self.digit1_segment2,
            self.digit1_segment3, self.digit1_segment4, self.digit1_segment5,
            self.digit1_segment6
        ]
        self.digit2 = [
            self.digit2_segment0, self.digit2_segment1, self.digit2_segment2,
            self.digit2_segment3, self.digit2_segment4, self.digit2_segment5,
            self.digit2_segment6
        ]
        self.digit3 = [
            self.digit3_segment0, self.digit3_segment1, self.digit3_segment2,
            self.digit3_segment3, self.digit3_segment4, self.digit3_segment5,
            self.digit3_segment6
        ]
        self.points = [self.point0, self.point1]

        self.digits = [
            self.digit0, self.digit1, self.digit2, self.digit3, self.points
        ]
        self.digit_state = [[False] * 7, [False] * 7, [False] * 7, [False] * 7,
                            [False] * 2]

        self.all_buttons = []
        self.all_buttons.extend(self.points)
        self.all_buttons.extend(self.digit0)
        self.all_buttons.extend(self.digit1)
        self.all_buttons.extend(self.digit2)
        self.all_buttons.extend(self.digit3)

        self.brightness = 7
        self.box_brightness.currentIndexChanged.connect(
            self.brightness_changed)
        self.button_all_segments_on.clicked.connect(
            self.all_segments_on_clicked)
        self.button_all_segments_off.clicked.connect(
            self.all_segments_off_clicked)
        self.button_start.clicked.connect(self.start_clicked)

        def get_clicked_func(digit, segment):
            return lambda: self.button_clicked(digit, segment)

        for d in range(4):
            for i in range(7):
                button = self.digits[d][i]
                button.initialize(self.STYLE_ON, self.STYLE_OFF)

                button.clicked.connect(get_clicked_func(d, i))

        for i in range(2):
            button = self.points[i]
            button.initialize(self.STYLE_ON, self.STYLE_OFF, style='circular')
            button.clicked.connect(get_clicked_func(4, i))

        self.counter_timer = QTimer(self)
        self.counter_timer.timeout.connect(self.update_counter)
        self.counter_timer.setInterval(100)
Example #56
0
File: sigmet.py Project: jpli/tafor
 def showEvent(self, event):
     # 检查必要配置是否完成
     if isConfigured('SIGMET'):
         self.currentSegment.head.updateState()
     else:
         QTimer.singleShot(0, self.showConfigError)
 def reconnect(self):
     self.resetPort()
     QTimer.singleShot(3000, self.serialchooser.serialConnect)
Example #58
0
    def initialize_player(self):
        vlc_available = True
        vlc = None
        try:
            from TriblerGUI import vlc
        except OSError:
            vlc_available = False

        if vlc and vlc.plugin_path:
            os.environ['VLC_PLUGIN_PATH'] = vlc.plugin_path

        if not vlc_available:
            # VLC is not available, we hide the video player button
            self.window().vlc_available = False
            self.window().left_menu_button_video_player.setHidden(True)
            return

        self.instance = vlc.Instance()
        self.mediaplayer = self.instance.media_player_new()
        self.window().video_player_widget.should_hide_video_widgets.connect(
            self.hide_video_widgets)
        self.window().video_player_widget.should_show_video_widgets.connect(
            self.show_video_widgets)
        self.window(
        ).video_player_position_slider.should_change_video_position.connect(
            self.on_should_change_video_time)
        self.window().video_player_volume_slider.valueChanged.connect(
            self.on_volume_change)
        self.window().video_player_volume_slider.setValue(
            self.mediaplayer.audio_get_volume())
        self.window().video_player_volume_slider.setFixedWidth(0)

        self.window().video_player_play_pause_button.clicked.connect(
            self.on_play_pause_button_click)
        self.window().video_player_volume_button.clicked.connect(
            self.on_volume_button_click)
        self.window().video_player_full_screen_button.clicked.connect(
            self.on_full_screen_button_click)

        # Create play/pause and volume button images
        self.play_icon = QIcon(QPixmap(get_image_path("play.png")))
        self.pause_icon = QIcon(QPixmap(get_image_path("pause.png")))
        self.volume_on_icon = QIcon(QPixmap(get_image_path("volume_on.png")))
        self.volume_off_icon = QIcon(QPixmap(get_image_path("volume_off.png")))
        self.window().video_player_play_pause_button.setIcon(self.play_icon)
        self.window().video_player_volume_button.setIcon(self.volume_on_icon)
        self.window().video_player_full_screen_button.setIcon(
            QIcon(QPixmap(get_image_path("full_screen.png"))))
        self.window().video_player_info_button.setIcon(
            QIcon(QPixmap(get_image_path("info.png"))))
        self.window().video_player_info_button.hide()

        if sys.platform.startswith('linux'):
            self.mediaplayer.set_xwindow(
                self.window().video_player_widget.winId())
        elif sys.platform == "win32":
            self.mediaplayer.set_hwnd(
                self.window().video_player_widget.winId())
        elif sys.platform == "darwin":
            self.mediaplayer.set_nsobject(
                int(self.window().video_player_widget.winId()))

        self.manager = self.mediaplayer.event_manager()
        self.manager.event_attach(vlc.EventType.MediaPlayerBuffering,
                                  self.on_vlc_player_buffering)
        self.manager.event_attach(vlc.EventType.MediaPlayerPlaying,
                                  self.on_vlc_player_playing)

        self.update_timer = QTimer()
        self.update_timer.timeout.connect(self.on_update_timer_tick)
        self.update_timer.start(500)

        self.window().left_menu_playlist.playing_item_change.connect(
            self.change_playing_index)
        self.window().left_menu_playlist.item_should_play.connect(
            self.on_play_pause_button_click)
        self.window().left_menu_playlist.list_loaded.connect(
            self.on_files_list_loaded)
        self.window().video_player_play_pause_button.setEnabled(False)
Example #59
0
if __name__ == "__main__":
    scene_file = ""
    red_file = ""
    blue_file = ""
    autoplay = False
    import sys
    if len(sys.argv) >= 4:
        scene_file = sys.argv[1]
        red_file = sys.argv[2]
        blue_file = sys.argv[3]
    if len(sys.argv) >= 5:
        autoplay = True
    t0 = None
    t = None
    timer = QTimer()
    game_over = False
    app = QtWidgets.QApplication(sys.argv)
    gui = GUI()
    scene = Scene(gui)
    gui.set_program_name("Multi-robot Motion Planning Game")
    gui.set_field(0, scene_file)
    gui.set_field(1, red_file)
    gui.set_field(2, blue_file)
    gui.set_logic(0, set_up_scene)
    gui.set_logic(3, set_scene_file)
    gui.set_logic(4, set_red_file)
    gui.set_logic(5, set_blue_file)
    gui.set_button_text(0, "Load scene")
    gui.set_button_text(1, "Unavailable")
    gui.set_button_text(2, "Unavailable")
 def __init__(self, parent=None):
     QTimer.__init__(self, parent)
     self.startTime = 0
     self.interval = 0