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)
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)
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");
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
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
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)
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)
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
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)
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)
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)
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
def newScreenshot(self): if self.hideThisWindowCheckBox.isChecked(): self.hide() self.newScreenshotButton.setDisabled(True) QTimer.singleShot(self.delaySpinBox.value() * 1000, self.shootScreen)
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
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()
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)
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_()
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)
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)
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
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)
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)
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)
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
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()
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))
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))
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)
def set_timeout(self, timeout): """Hide the widget after the given timeout.""" QTimer.singleShot(timeout, self._on_timeout)
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
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()
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()
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
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)
def export_to_pdf(self, **kwargs): p = partial(self._export, "pdf:writer_pdf_Export", ".pdf", **kwargs) QTimer.singleShot(0, p)
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()
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))
def export_to_odt(self, **kwargs): p = partial(self._export, "odt", ".odt", **kwargs) QTimer.singleShot(0, p)
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
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
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))
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_()
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
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)
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
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()
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
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()
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)
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 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)
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)
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