def save_image_as(self): img = self.get_selection().toImage() if img.isNull(): QMessageBox.critical(self, self.tr('Error'), self.tr('No image was selected!')) return self.hide() formats = { self.tr('Portable Network Graphics (*.png)'): 'png', self.tr('Joint Photographic Experts Group (*.jpg *.jpeg)'): 'jpg', self.tr('Graphics Interchange Format (*.gif)'): 'gif', self.tr('Bitmap (*.bmp)'): 'bmp', self.tr('All Images (*.png *.jpg *.gif *.bmp)'): 'all' } file_format = None destination = QFileDialog.getSaveFileName(self, 'Save image', '', ';;'.join(formats.keys())) if isinstance(destination, tuple): destination, file_format = destination file_format = formats[file_format] if file_format == 'all': file_format = None if not file_format: file_format = destination.rsplit('.', 1)[-1] if destination: if file_format not in formats.values(): file_format = 'png' if not destination.endswith('.' + file_format): destination += '.' + file_format img.save(destination, file_format, 0 if file_format == 'png' else 90) self.reject()
def onDictyExpressLink(self, link): if not self.data: return selectedIndexes = self.treeWidget.selectedIndexes() if not len(selectedIndexes): QMessageBox.information(self, "No gene ids selected", "Please select some genes and try again.") return model = self.treeWidget.model() mapToSource = model.mapToSource selectedRows = self.treeWidget.selectedIndexes() selectedRows = [mapToSource(index).row() for index in selectedRows] model = model.sourceModel() selectedGeneids = [self.row2geneinfo[row] for row in selectedRows] selectedIds = [self.geneinfo[i][0] for i in selectedGeneids] selectedIds = set(selectedIds) def fix(ddb): if ddb.startswith("DDB"): if not ddb.startswith("DDB_G"): ddb = ddb.replace("DDB", "DDB_G") return ddb return None genes = [fix(gene) for gene in selectedIds if fix(gene)] url = str(link) % " ".join(genes) QDesktopServices.openUrl(QUrl(url))
def show_report(self): """ Raise the report window. """ self.create_report_html() from orangewidget.report.owreport import HAVE_REPORT report = self._get_designated_report_view() if not HAVE_REPORT and not report.have_report_warning_shown: QMessageBox.critical( None, "Missing Component", "Orange can not display reports, because your installation " "contains neither WebEngine nor WebKit.\n\n" "If you installed Orange with conda or pip, try using another " "PyQt distribution. " "If you installed Orange with a standard installer, please " "report this bug." ) report.have_report_warning_shown = True # Should really have a signal `report_ready` or similar to decouple # the implementations. report.make_report(self) report.show() report.raise_()
def track_user_stats(): reply = get_usage_track_conf() if reply=='ask later': m = QMessageBox( QMessageBox.Question, "User tracking", "Do you give us permission to track which country you are from and how many times you use this application? " \ "This will contribute to the support of this software.", QMessageBox.Yes | QMessageBox.No | QMessageBox.NoRole ) ask_later_btn = m.addButton("Ask me later", QMessageBox.NoRole) m.setEscapeButton(ask_later_btn) reply = m.exec_() if reply == QMessageBox.No: set_usage_track_conf('no-track') elif reply == QMessageBox.Yes: set_usage_track_conf('track') reply = 'track' elif reply == QMessageBox.NoButton: set_usage_track_conf('ask later') if reply=='track': register_access()
def __export(self): """Export annotations to a file.""" try: if conf.PYFORMS_DIALOGS_OPTIONS: filename, ffilter = QFileDialog.getSaveFileName( parent=self, caption="Export annotations file", directory="untitled.csv", filter="CSV Files (*.csv);;CSV Matrix Files (*.csv)", options=conf.PYFORMS_DIALOGS_OPTIONS) else: filename, ffilter = QFileDialog.getSaveFileName( parent=self, caption="Export annotations file", directory="untitled.csv", filter="CSV Files (*.csv);;CSV Matrix Files (*.csv)") filename = str(filename) ffilter = str(ffilter) if filename != "": with open(filename, 'w') as csvfile: spamwriter = csv.writer(csvfile, dialect='excel') if ffilter == 'CSV Files (*.csv)': self._time.export_events_to_csvwriter(spamwriter) elif ffilter == 'CSV Matrix Files (*.csv)': self._time.exportmatrix_events_to_csvwriter(spamwriter) except Exception as e: traceback.print_exc() m = QMessageBox(QMessageBox.Critical, 'Error', str(e)) m.exec_()
def message(icon, text, title=None, informative_text=None, details=None, buttons=None, default_button=None, exc_info=False, parent=None): """Show a message helper function. """ if title is None: title = "Message" if not text: text = "I am neither a postman nor a doctor." if buttons is None: buttons = QMessageBox.Ok if details is None and exc_info: details = traceback.format_exc(limit=20) mbox = QMessageBox(icon, title, text, buttons, parent) if informative_text: mbox.setInformativeText(informative_text) if details: mbox.setDetailedText(details) dtextedit = mbox.findChild(QTextEdit) if dtextedit is not None: dtextedit.setWordWrapMode(QTextOption.NoWrap) if default_button is not None: mbox.setDefaultButton(default_button) return mbox.exec()
def save_plot(data, file_formats, filename=""): _LAST_DIR_KEY = "directories/last_graph_directory" _LAST_FILTER_KEY = "directories/last_graph_filter" settings = QSettings() start_dir = settings.value(_LAST_DIR_KEY, filename) if not start_dir or \ (not os.path.exists(start_dir) and not os.path.exists(os.path.split(start_dir)[0])): start_dir = os.path.expanduser("~") last_filter = settings.value(_LAST_FILTER_KEY, "") filename, writer, filter = \ filedialogs.get_file_name(start_dir, last_filter, file_formats) if not filename: return try: writer.write(filename, data) except Exception as e: mb = QMessageBox( None, windowTitle="Error", text='Error occurred while saving file "{}": {}'.format(filename, e), detailedText=traceback.format_exc(), icon=QMessageBox.Critical) mb.exec_() else: settings.setValue(_LAST_DIR_KEY, os.path.split(filename)[0]) settings.setValue(_LAST_FILTER_KEY, filter)
def copy_to_clipboard(self): img = self.get_selection() if img.isNull(): QMessageBox.critical(self, self.tr('Error'), self.tr('No image was selected!')) return QApplication.clipboard().setPixmap(img) self.reject()
def onDictyExpressLink(self, link): if not self.data: return selectedIndexes = self.treeWidget.selectedIndexes() if not len(selectedIndexes): QMessageBox.information( self, "No gene ids selected", "Please select some genes and try again." ) return model = self.treeWidget.model() mapToSource = model.mapToSource selectedRows = self.treeWidget.selectedIndexes() selectedRows = [mapToSource(index).row() for index in selectedRows] model = model.sourceModel() selectedGeneids = [self.row2geneinfo[row] for row in selectedRows] selectedIds = [self.geneinfo[i][0] for i in selectedGeneids] selectedIds = set(selectedIds) def fix(ddb): if ddb.startswith("DDB"): if not ddb.startswith("DDB_G"): ddb = ddb.replace("DDB", "DDB_G") return ddb return None genes = [fix(gene) for gene in selectedIds if fix(gene)] url = str(link) % " ".join(genes) QDesktopServices.openUrl(QUrl(url))
def save_plot(data, file_formats, filename=""): _LAST_DIR_KEY = "directories/last_graph_directory" _LAST_FILTER_KEY = "directories/last_graph_filter" settings = QSettings() start_dir = settings.value(_LAST_DIR_KEY, filename) if not start_dir or \ (not os.path.exists(start_dir) and not os.path.exists(os.path.split(start_dir)[0])): start_dir = os.path.expanduser("~") last_filter = settings.value(_LAST_FILTER_KEY, "") filename, writer, filter = \ filedialogs.open_filename_dialog_save(start_dir, last_filter, file_formats) if not filename: return try: writer.write(filename, data) except OSError as e: mb = QMessageBox( None, windowTitle="Error", text='Error occurred while saving file "{}": {}'.format(filename, e), detailedText=traceback.format_exc(), icon=QMessageBox.Critical) mb.exec_() else: settings.setValue(_LAST_DIR_KEY, os.path.split(filename)[0]) settings.setValue(_LAST_FILTER_KEY, filter)
def reset_widget_settings(self): mb = QMessageBox( self, windowTitle="Clear settings", text="Orange needs to be restarted for the changes to take effect.", icon=QMessageBox.Information, informativeText="Press OK to close Orange now.", standardButtons=QMessageBox.Ok | QMessageBox.Cancel, ) res = mb.exec() if res == QMessageBox.Ok: # Touch a finely crafted file inside the settings directory. # The existence of this file is checked by the canvas main # function and is deleted there. from orangewidget.settings import widget_settings_dir dirname = widget_settings_dir() try: os.makedirs(dirname, exist_ok=True) except (FileExistsError, PermissionError): return with open(os.path.join(dirname, "DELETE_ON_START"), "a"): pass if not self.close(): QMessageBox( self, text= "Settings will still be reset at next application start", icon=QMessageBox.Information).exec()
def question(self, msg, title=None, buttons=['no', 'yes']): btns = None for btn in buttons: if btn.lower() == 'cancel': b = QMessageBox.Cancel elif btn.lower() == 'no': b = QMessageBox.No elif btn.lower() == 'yes': b = QMessageBox.Yes elif btn.lower() == 'no_all': b = QMessageBox.NoToAll elif btn.lower() == 'yes_all': b = QMessageBox.YesToAll if btns is None: btns = b else: btns |= b m = QMessageBox(QMessageBox.Question, title, msg, btns) reply = m.exec_() if reply == QMessageBox.Cancel: return 'cancel' elif reply == QMessageBox.No: return 'no' elif reply == QMessageBox.Yes: return 'yes' elif reply == QMessageBox.NoToAll: return 'no_all' elif reply == QMessageBox.YesToAll: return 'yes_all' return None
def browse_files(self, in_demos=False): if in_demos: start_file = get_sample_datasets_dir() if not os.path.exists(start_file): QMessageBox.information( None, "File", "Cannot find the directory with documentation data sets") return else: start_file = self.last_path() or os.path.expanduser("~/") filenames = QFileDialog.getOpenFileNames(self, 'Open Multiple Data Files', start_file, self.dlg_formats) if isinstance(filenames, tuple): # has a file description filenames = filenames[0] if not filenames: return for f in filenames: self.add_path(f) self.lb.addItem(f) self._update_sheet_combo() self.load_data()
def ask_save_report(self): """ Ask whether to save the report or not. Returns: `QDialog.Rejected` if user cancels, `QDialog.Accepted` otherwise """ workflow = self.current_document().scheme() if not isinstance(workflow, WidgetsScheme) or not workflow.has_report(): return QDialog.Accepted report = workflow.report_view() if not report.is_changed(): return QDialog.Accepted mBox = QMessageBox( self, windowTitle="Report window", icon=QMessageBox.Question, text="The report contains unsaved changes.", informativeText="Would you like to save the report?", standardButtons=QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel, ) mBox.setDefaultButton(QMessageBox.Save) answ = mBox.exec() if answ == QMessageBox.Cancel: return QDialog.Rejected if answ == QMessageBox.Save: return report.save_report() return QDialog.Accepted
def browse_file(self, in_demos=False): if in_demos: start_file = get_sample_datasets_dir() if not os.path.exists(start_file): QMessageBox.information( None, "File", "Cannot find the directory with documentation datasets", ) return else: start_file = self.last_path() or os.path.expanduser("~/") readers = [ f for f in FileFormat.formats if getattr(f, "read", None) and getattr(f, "EXTENSIONS", None) ] filename, reader, _ = open_filename_dialog(start_file, None, readers) if not filename: return self.add_path(filename) if reader is not None: self.recent_paths[0].file_format = reader.qualified_name() self.source = self.LOCAL_FILE self.load_data()
def _parse_var_defs(self, js): if not isinstance(js, dict) or set(js) != {"categorical", "numeric"}: raise InvalidFileFormat try: renames = { var_name: desc["rename"] for repo in js.values() for var_name, desc in repo.items() if "rename" in desc } # js is an object coming from json file that can be manipulated by # the user, so there are too many things that can go wrong. # Catch all exceptions, therefore. except Exception as exc: raise InvalidFileFormat from exc if not all(isinstance(val, str) for val in chain(renames, renames.values())): raise InvalidFileFormat renamed_vars = { renames.get(desc.var.name, desc.var.name) for desc in chain(self.disc_descs, self.cont_descs) } if len(renamed_vars) != len(self.disc_descs) + len(self.cont_descs): QMessageBox.warning( self, "Duplicated variable names", "Variables will not be renamed due to duplicated names.") for repo in js.values(): for desc in repo.values(): desc.pop("rename", None) # First, construct all descriptions; assign later, after we know # there won't be exceptions due to invalid file format both_descs = [] warnings = [] for old_desc, repo, desc_type in ( (self.disc_descs, "categorical", DiscAttrDesc), (self.cont_descs, "numeric", ContAttrDesc)): var_by_name = {desc.var.name: desc.var for desc in old_desc} new_descs = {} for var_name, var_data in js[repo].items(): var = var_by_name.get(var_name) if var is None: continue # This can throw InvalidFileFormat new_descs[var_name], warn = desc_type.from_dict(var, var_data) warnings += warn both_descs.append(new_descs) self.disc_descs = [both_descs[0].get(desc.var.name, desc) for desc in self.disc_descs] self.cont_descs = [both_descs[1].get(desc.var.name, desc) for desc in self.cont_descs] if warnings: QMessageBox.warning( self, "Invalid definitions", "\n".join(warnings)) self.disc_model.set_data(self.disc_descs) self.cont_model.set_data(self.cont_descs) self.unconditional_commit()
def __interpolate_btn_event(self): #store a temporary path for interpolation visualization if len(self._sel_pts) >= 2: mode = None if self._interpolation_mode.value=='Auto' else self._interpolation_mode.value #store a temporary path for interpolation visualization self.interpolate_range( self._sel_pts[0], self._sel_pts[-1], interpolation_mode=mode) self.mainwindow._player.refresh() else: QMessageBox.about(self, "Error", "You need to select 2 frames.")
def __derivate_data(self): for i in range(1, len(self)): a = self[i-1] b = self[i] if a is not None and b is not None: self._values[i-1] = b-a else: self._values[i-1] = 0 QMessageBox.about(self, "Info", "Operation complete.")
def cleanLine(self, track_index=None): if track_index is not None or self._selected is not None: track_index = track_index if track_index is not None else self._selected.track if len(self._tracks) > track_index: self._tracks[track_index].clear() self._selected = None self.repaint() else: QMessageBox.about(self, "Error", "You must select a timebar first") return
def save_project(self, project_path=None): try: if project_path is None: project_path = QFileDialog.getExistingDirectory(self, "Select the project directory") if project_path is not None and str(project_path)!='': project_path = str(project_path) self.save({}, project_path) except Exception as e: QMessageBox.critical(self, "Error", str(e))
def share_clipboard(self): mime = QApplication.clipboard().mimeData() try: wnd = ShareDialog(self, mime=mime) except ValueError as e: QMessageBox.critical(self, self.tr('Error'), str(e)) return else: wnd.show() wnd.exec_()
def show_survey(): # If run for the first time, open a browser tab with a survey settings = QSettings() show_survey = settings.value("startup/show-survey", True, type=bool) if show_survey: question = QMessageBox( QMessageBox.Question, 'Orange Survey', 'We would like to know more about how our software is used.\n\n' 'Would you care to fill our short 1-minute survey?', QMessageBox.Yes | QMessageBox.No) question.setDefaultButton(QMessageBox.Yes) later = question.addButton('Ask again later', QMessageBox.NoRole) question.setEscapeButton(later) def handle_response(result): if result == QMessageBox.Yes: success = QDesktopServices.openUrl( QUrl("https://orange.biolab.si/survey/short.html")) settings.setValue("startup/show-survey", not success) else: settings.setValue("startup/show-survey", result != QMessageBox.No) question.finished.connect(handle_response) question.show() return question
def __del_path_btn_event(self): #store a temporary path for interpolation visualization if len(self._sel_pts) == 2: reply = QMessageBox.question(self, 'Confirmation', "Are you sure you want to delete this path?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: #store a temporary path for interpolation visualization start, end = self._sel_pts[0], self._sel_pts[1] self.delete_range(start, end) self.calculate_tmp_interpolation() self.mainwindow._player.refresh() else: QMessageBox.about(self, "Error", "You need to select 2 frames.")
def save_project(self, project_path=None): try: if project_path is None: project_path = QFileDialog.getExistingDirectory( self, "Select the project directory") if project_path is not None and str(project_path) != '': project_path = str(project_path) self.save({}, project_path) except Exception as e: QMessageBox.critical(self, "Error", str(e))
def message(icon, text, title=None, informative_text=None, details=None, buttons=None, default_button=None, exc_info=False, parent=None): """Show a message helper function. """ if title is None: title = "Message" if not text: text = "I am neither a postman nor a doctor." if buttons is None: buttons = QMessageBox.Ok if details is None and exc_info: details = traceback.format_exc(limit=20) mbox = QMessageBox(icon, title, text, buttons, parent) if informative_text: mbox.setInformativeText(informative_text) if details: mbox.setDetailedText(details) if default_button is not None: mbox.setDefaultButton(default_button) return mbox.exec_()
def save_project(self, project_path=None): try: if project_path is None: dialog = QFileDialog() dialog.setLabelText(QFileDialog.Accept, 'Save') project_path = dialog.getExistingDirectory( self, caption="Select the project directory to save") if project_path is not None and str(project_path) != '': project_path = str(project_path) self.save({}, project_path) except Exception as e: traceback.print_exc() QMessageBox.critical(self, "Error", str(e))
def __export_2_csv_matrix(self): QMessageBox.warning( self, "Important!", 'Please note that this file cannot be imported after.') filename, _ = QFileDialog.getSaveFileName( parent=self, caption="Export matrix file", directory="untitled.csv", filter="CSV Files (*.csv)", options=QFileDialog.DontUseNativeDialog) if filename != "": with open(filename, 'w') as csvfile: spamwriter = csv.writer(csvfile, dialect='excel') self._time.exportmatrix_events_to_csvwriter(spamwriter)
def message_restart(parent): icon = QMessageBox.Information buttons = QMessageBox.Ok | QMessageBox.Cancel title = 'Information' text = 'Orange needs to be restarted for the changes to take effect.' msg_box = QMessageBox(icon, title, text, buttons, parent) msg_box.setDefaultButton(QMessageBox.Ok) msg_box.setInformativeText('Press OK to close Orange now.') msg_box.button(QMessageBox.Cancel).setText('Close later') return msg_box.exec_()
def acceptChanges(self): state = self.getCurrentState() oldState = self.colorSchemas[self.selectedSchemaIndex][1] if state == oldState: QDialog.accept(self) else: # if we change the default schema, we must save it under a new name if self.colorSchemas[self.selectedSchemaIndex][0] == "Default": if (QMessageBox.information( self, "Question", "The color schema has changed. Save?", QMessageBox.Yes | QMessageBox.Discard, ) == QMessageBox.Discard): QDialog.reject(self) else: self.selectedSchemaIndex = self.schemaCombo.count() - 1 self.schemaCombo.setCurrentIndex(self.selectedSchemaIndex) self.paletteSelected() QDialog.accept(self) # simply save the new users schema else: self.colorSchemas[self.selectedSchemaIndex] = [ self.colorSchemas[self.selectedSchemaIndex][0], state, ] QDialog.accept(self)
def __remove_current_track_evt(self): reply = QMessageBox.question( self, 'Confirm', "Are you sure you want to remove the row and its events?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: self._time.remove_selected_track()
def __cleanLine(self): reply = QMessageBox.question( self, 'Confirm', "Are you sure you want to clean all the events on this track?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: self._time.cleanLine(self._time.current_mouseover_track)
def get_save_filename(self): # pragma: no cover if sys.platform == "darwin": def remove_star(filt): return filt.replace(" (*.", " (.") else: def remove_star(filt): return filt no_ext_filters = {remove_star(f): f for f in self._valid_filters()} filename = self._initial_start_dir() while True: dlg = QFileDialog( None, "Save File", filename, ";;".join(no_ext_filters)) dlg.setAcceptMode(dlg.AcceptSave) dlg.selectNameFilter(remove_star(self._default_valid_filter())) dlg.setOption(QFileDialog.DontConfirmOverwrite) if dlg.exec() == QFileDialog.Rejected: return "", "" filename = dlg.selectedFiles()[0] selected_filter = no_ext_filters[dlg.selectedNameFilter()] filename = self._replace_extension( filename, self._extension_from_filter(selected_filter)) if not os.path.exists(filename) or QMessageBox.question( self, "Overwrite file?", f"File {os.path.split(filename)[1]} already exists.\n" "Overwrite?") == QMessageBox.Yes: return filename, selected_filter
def get_save_filename(self): # pragma: no cover if sys.platform == "darwin": def remove_star(filt): return filt.replace(" (*.", " (.") else: def remove_star(filt): return filt no_ext_filters = {remove_star(f): f for f in self.valid_filters()} filename = self.initial_start_dir() while True: dlg = QFileDialog(None, "Save File", filename, ";;".join(no_ext_filters)) dlg.setAcceptMode(dlg.AcceptSave) dlg.selectNameFilter(remove_star(self.default_valid_filter())) dlg.setOption(QFileDialog.DontConfirmOverwrite) if dlg.exec() == QFileDialog.Rejected: return "", "" filename = dlg.selectedFiles()[0] selected_filter = no_ext_filters[dlg.selectedNameFilter()] filename = self._replace_extension( filename, self._extension_from_filter(selected_filter)) if not os.path.exists(filename) or QMessageBox.question( self, "Overwrite file?", f"File {os.path.split(filename)[1]} already exists.\n" "Overwrite?") == QMessageBox.Yes: return filename, selected_filter
def compare_versions(latest): current = current_version() version = pkg_resources.parse_version if version(latest) <= version(current): return question = QMessageBox(QMessageBox.Information, UPDATE_AVAILABLE_TITLE, UPDATE_AVAILABLE_MESSAGE.format( current_version=current, latest_version=latest), textFormat=Qt.RichText) ok = question.addButton('Download Now', question.AcceptRole) question.setDefaultButton(ok) question.addButton('Remind Later', question.RejectRole) question.finished.connect(lambda: question.clickedButton() == ok and QDesktopServices.openUrl(QUrl(DOWNLOAD_URL))) question.show()
def browse_file(self, in_demos=False): if in_demos: start_file = get_sample_datasets_dir() if not os.path.exists(start_file): QMessageBox.information( None, "File", "Cannot find the directory with documentation datasets") return else: start_file = self.last_path() or os.path.expanduser("~/") filename, _ = QFileDialog.getOpenFileName( self, 'Open Distance File', start_file, "(*.dst)") if not filename: return self.add_path(filename) self.open_file()
def load(self): fname, _ = QFileDialog.getOpenFileName( self, "File name", self._start_dir(), "Variable definitions (*.colors)") if not fname: return try: with open(fname) as f: js = json.load(f) #: dict self._parse_var_defs(js) except IOError: QMessageBox.critical(self, "File error", "File cannot be opened.") return except (json.JSONDecodeError, InvalidFileFormat): QMessageBox.critical(self, "File error", "Invalid file format.") return
def __open_track_properties_evt(self): """ This controls makes possible the edition of a track in the timeline, based on the position of the mouse. Updates: - Track label - Track default color """ current_track = self._time.current_mouseover_track parent = self._time # Tracks info dict and index i = current_track # Save current default color to override with selected track color timeline_default_color = parent.color try: parent.color = self._time._tracks[current_track].color except Exception as e: error_message = ("You tried to edit an empty track.", "\n", "Initialize it by creating an event first.") QMessageBox.warning(parent, "Attention!", "".join(error_message)) return e # Create dialog dialog = TimelinePopupWindow(parent, i) dialog.setModal(True) # to disable main application window # If dialog is accepted, update dict info if dialog._ui.exec_() == dialog.Accepted: # Update label if dialog.behavior is not None: self._time._tracks[i].title = dialog.behavior # Update color if self._time._tracks[i].color != dialog.color: for delta in self._time._tracks[i].events: delta.color = dialog.color self._time._tracks[i].color = dialog.color self._time.repaint() else: pass # Restore timeline default color parent.color = timeline_default_color
def compare_versions(latest): if LooseVersion(latest) <= LooseVersion(current): return question = QMessageBox( QMessageBox.Information, 'Orange Update Available', 'A newer version of Orange is available.<br><br>' '<b>Current version:</b> {}<br>' '<b>Latest version:</b> {}'.format(current, latest), textFormat=Qt.RichText) ok = question.addButton('Download Now', question.AcceptRole) question.setDefaultButton(ok) question.addButton('Remind Later', question.RejectRole) question.finished.connect( lambda: question.clickedButton() == ok and QDesktopServices. openUrl(QUrl("https://orange.biolab.si/download/"))) question.show()
def browse_file(self, in_demos=False): if in_demos: start_file = get_sample_datasets_dir() if not os.path.exists(start_file): QMessageBox.information( None, "File", "Cannot find the directory with documentation data sets") return else: start_file = self.last_path() or os.path.expanduser("~/") filename, _ = QFileDialog.getOpenFileName( self, 'Open Distance File', start_file, "(*.dst)") if not filename: return self.add_path(filename) self.open_file()
def browse_file(self, in_demos=False): if in_demos: start_file = get_sample_datasets_dir() if not os.path.exists(start_file): QMessageBox.information( None, "File", "Cannot find the directory with documentation data sets") return else: start_file = self.last_path() or os.path.expanduser("~/") filename, _ = QFileDialog.getOpenFileName( self, 'Open Orange Data File', start_file, dialog_formats()) if not filename: return self.add_path(filename) self.source = self.LOCAL_FILE self.load_data()
def value(self, value): self.form.setUpdatesEnabled(False) if value is None: self.stop() self.videoControl.setEnabled(False) self.refresh() self._video_widget.reset() if value == 0: self._value = cv2.VideoCapture(0) elif isinstance(value, str) and value: open_multiplefiles = self._multiple_files if open_multiplefiles: open_multiplefiles = len(MultipleVideoCapture.search_files(value))>0 if open_multiplefiles: msg = "Multiple files were found with the same name, do you wish to combine then in a single video?\n\n" for filepath in MultipleVideoCapture.search_files(value): msg += "- {filename}\n".format(filename=os.path.basename(filepath)) reply = QMessageBox( QMessageBox.Question, 'Open multiple files', msg, QMessageBox.No | QMessageBox.Yes ).exec_() if reply == QMessageBox.Yes: open_multiplefiles = True else: open_multiplefiles = False if open_multiplefiles: self._value = MultipleVideoCapture(value) else: self._value = cv2.VideoCapture(value) else: self._value = value if self._value and value != 0: self.videoProgress.setMinimum(0) self.videoProgress.setValue(0) self.videoProgress.setMaximum( self._value.get(7)) self.videoFrames.setMinimum(0) self.videoFrames.setValue(0) self.videoFrames.setMaximum( self._value.get(7)) if self._value: self.videoControl.setEnabled(True) self.refresh() self.form.setUpdatesEnabled(True)
def register_hotkeys(self): if self._hotkey is not None: self.rebuild_menu() self._hotkey.unregister(winid=self.winId()) hotkey_bindings = { settings['hotkey/clipboard']: (self.share_clipboard, self._action_clip), settings['hotkey/screenshot']: (self.capture_screen, self._action_screen) } for hotkey, (callback, action) in hotkey_bindings.items(): if hotkey: if self._hotkey.register(hotkey, callback, self.winId()): sequence = QKeySequence(hotkey) if hotkey else QKeySequence() action.setShortcut(sequence) else: QMessageBox.critical(self, 'Error', 'Could not bind {} hotkey!\n' 'Key combination {} is probably already in use.' .format(const.APP_NAME, hotkey)) else: qDebug('Hotkeys are not supported on this platform')
def browse_file(self, in_demos=False): if in_demos: start_file = get_sample_datasets_dir() if not os.path.exists(start_file): QMessageBox.information( None, "File", "Cannot find the directory with documentation datasets") return else: start_file = self.last_path() or os.path.expanduser("~/") readers = [f for f in FileFormat.formats if getattr(f, 'read', None) and getattr(f, "EXTENSIONS", None)] filename, reader, _ = open_filename_dialog(start_file, None, readers) if not filename: return self.add_path(filename) if reader is not None: self.recent_paths[0].file_format = reader.qualified_name() self.source = self.LOCAL_FILE self.load_data()
def save_plot(data, file_formats, filename=""): _LAST_DIR_KEY = "directories/last_graph_directory" _LAST_FILTER_KEY = "directories/last_graph_filter" settings = QSettings() start_dir = settings.value(_LAST_DIR_KEY, filename) if not start_dir or \ (not os.path.exists(start_dir) and not os.path.exists(os.path.split(start_dir)[0])): start_dir = os.path.expanduser("~") last_filter = settings.value(_LAST_FILTER_KEY, "") filename, writer, filter = \ filedialogs.get_file_name(start_dir, last_filter, file_formats) if not filename: return try: writer.write(filename, data) except Exception as e: QMessageBox.critical( None, "Error", 'Error occurred while saving file "{}": {}'.format(filename, e)) else: settings.setValue(_LAST_DIR_KEY, os.path.split(filename)[0]) settings.setValue(_LAST_FILTER_KEY, filter)
def compare_versions(latest): version = pkg_resources.parse_version if version(latest) <= version(current): return question = QMessageBox( QMessageBox.Information, 'Orange Update Available', 'A newer version of Orange is available.<br><br>' '<b>Current version:</b> {}<br>' '<b>Latest version:</b> {}'.format(current, latest), textFormat=Qt.RichText) ok = question.addButton('Download Now', question.AcceptRole) question.setDefaultButton(ok) question.addButton('Remind Later', question.RejectRole) question.finished.connect( lambda: question.clickedButton() == ok and QDesktopServices.openUrl(QUrl("https://orange.biolab.si/download/"))) question.show()
def start(): try: pyforms.start_app( VideoAnnotator, geometry=conf.MAIN_WINDOW_GEOMETRY ) except Exception as e: report = traceback.format_exc() app = QApplication(sys.argv) m = QMessageBox( QMessageBox.Question, "Send report", "<h2>Would you like to send us a report of the bug?</h2>" "This will help us improving the software." "<p>{bug}</p>".format( bug=str(e) ), QMessageBox.Yes | QMessageBox.No ) reply = m.exec_() if reply==QMessageBox.Yes: try: app_id = conf.USERSTATS_APP_ID reg_id = get_mac() os_name = platform.platform() version = pythonvideoannotator.__version__ data = {'app-id': app_id, 'reg-id': reg_id, 'os-name' : os_name, 'version': version, 'report': report} url = "{}/register-bug".format(conf.USERSTATS_URL) request = Request(url, urlencode(data).encode()) urlopen(request).read().decode() except Exception as ex: print("Could not register new access", ex ) exit() app.exec_()
def acceptChanges(self): state = self.getCurrentState() oldState = self.colorSchemas[self.selectedSchemaIndex][1] if state == oldState: QDialog.accept(self) else: # if we change the default schema, we must save it under a new name if self.colorSchemas[self.selectedSchemaIndex][0] == "Default": if QMessageBox.information( self, 'Question', 'The color schema has changed. Save?', QMessageBox.Yes | QMessageBox.Discard) == QMessageBox.Discard: QDialog.reject(self) else: self.selectedSchemaIndex = self.schemaCombo.count() - 1 self.schemaCombo.setCurrentIndex(self.selectedSchemaIndex) self.paletteSelected() QDialog.accept(self) # simply save the new users schema else: self.colorSchemas[self.selectedSchemaIndex] = \ [self.colorSchemas[self.selectedSchemaIndex][0], state] QDialog.accept(self)
def __init__(self, parent=None, *, mime=None, image=None): QDialog.__init__(self, parent) self.setupUi(self) self._backend = None self._backend_controls = {} self._label_anonymous = self.tr('Anonymous') self._label_select_login = self.tr('Select Login') self._available_backends = [] data = None file_name = None if image: self._share_type = Bi.Image data = image elif mime: if mime.hasImage(): self._share_type = Bi.Image data = mime.imageData() elif mime.hasUrls(): urls = mime.urls() if len(urls) == 1: file_path = os.path.realpath(urls[0].toLocalFile()) if not os.path.isfile(file_path): raise ValueError(self.tr('Directories can not be shared')) file_size = os.path.getsize(file_path) file_name = os.path.basename(file_path) if file_size > const.BIG_FILE_WARNING_SIZE: file_name = os.path.basename(file_path) nice_size = format_size(file_size) result = QMessageBox.warning(self, self.tr('Warning'), self.tr('File "{file_name}" {nice_size}.\n' 'Are you sure you want to continue?').format(**locals()), QMessageBox.Yes | QMessageBox.Abort) if result == QMessageBox.Abort: QTimer.singleShot(0, self.reject) return if file_has_extension(file_path, ('png', 'jpg', 'jpeg', 'bmp', 'gif')): image = QPixmap(file_path) else: image = None if not image or image.isNull(): data = read_text_from_file(file_path) if data: self._share_type = Bi.Text else: self._share_type = Bi.File data = file_path else: self._share_type = Bi.Image data = image else: raise ValueError(self.tr('Can not share more than one file')) elif mime.hasText(): self._share_type = Bi.Text data = mime.text() else: raise RuntimeError() if not data: raise ValueError(self.tr('There is no content in your clipboard.\nCopy something in order to share it.')) if self._share_type == Bi.Image: if not file_name: file_name = '{}-{}.png'.format('screenshot' if image else 'image', int(time())) if data.width() > self.image_preview.width() or data.height() > self.image_preview.height(): preview = data.scaled(self.image_preview.size(), Qt.KeepAspectRatio) else: preview = data if isinstance(preview, QImage): preview = QPixmap.fromImage(preview) self.image_preview.setPixmap(preview) self.preview_stack.setCurrentIndex(0) buf = QBuffer() data.save(buf, 'png', 100) data = buf.data().data() elif self._share_type == Bi.Text: if not file_name: file_name = 'file-{}.txt'.format(int(time())) self.text_preview.setPlainText(dedent_text_and_truncate(data, 128)) self.preview_stack.setCurrentIndex(1) elif self._share_type == Bi.File: if not file_name: file_name = 'file-{}.bin'.format(int(time())) self.text_preview.setPlainText(self.tr('No preview available')) self.preview_stack.setCurrentIndex(1) self._file_name = file_name self._data = data self.populate_backends() self.share.pressed.connect(self.share_item) self.add_login.pressed.connect(self.on_add_login) self.logout.pressed.connect(self.logout_selected) self.login_list.currentIndexChanged.connect(self.select_login) min_height = self.backend_selector.minimumSizeHint().height() if os.name == 'nt': # On windows tab widget and font are rather small min_height -= 5 for el in (self.add_login, self.login_list, self.logout, self.share): font = el.font() font.setPointSize(12) el.setFont(font) self.login_list.setFixedHeight(self.add_login.height() - 2) self.backend_selector.setFixedHeight(min_height) self.backend_selector.currentChanged.connect(self.select_backend) if self.backend_selector.height() < self.add_login.height(): # Move tab widget down based on size of controls on the right. Makes widgets below seem to belong to the # selected tab. self.backend_selector.move(0, self.add_login.height() - self.backend_selector.height()) self.resize(self.width(), 0) self.setWindowState((self.windowState() & ~Qt.WindowMinimized) | Qt.WindowActive) self.raise_() self.activateWindow()
def load(self, data, project_path=None): try: self._project.load(data, project_path) except FileNotFoundError as e: QMessageBox.critical(self, "Error", str(e))
def main(argv=None): if argv is None: argv = sys.argv usage = "usage: %prog [options] [workflow_file]" parser = optparse.OptionParser(usage=usage) parser.add_option("--no-discovery", action="store_true", help="Don't run widget discovery " "(use full cache instead)") parser.add_option("--force-discovery", action="store_true", help="Force full widget discovery " "(invalidate cache)") parser.add_option("--clear-widget-settings", action="store_true", help="Remove stored widget setting") parser.add_option("--no-welcome", action="store_true", help="Don't show welcome dialog.") parser.add_option("--no-splash", action="store_true", help="Don't show splash screen.") parser.add_option("-l", "--log-level", help="Logging level (0, 1, 2, 3, 4)", type="int", default=1) parser.add_option("--style", help="QStyle to use", type="str", default=None) parser.add_option("--stylesheet", help="Application level CSS style sheet to use", type="str", default="orange.qss") parser.add_option("--qt", help="Additional arguments for QApplication", type="str", default=None) (options, args) = parser.parse_args(argv[1:]) levels = [logging.CRITICAL, logging.ERROR, logging.WARN, logging.INFO, logging.DEBUG] # Fix streams before configuring logging (otherwise it will store # and write to the old file descriptors) fix_win_pythonw_std_stream() # Try to fix fonts on OSX Mavericks fix_osx_10_9_private_font() # File handler should always be at least INFO level so we need # the application root level to be at least at INFO. root_level = min(levels[options.log_level], logging.INFO) rootlogger = logging.getLogger(canvas.__name__) rootlogger.setLevel(root_level) # Initialize SQL query and execution time logger (in SqlTable) sql_level = min(levels[options.log_level], logging.INFO) make_sql_logger(sql_level) # Standard output stream handler at the requested level stream_hander = logging.StreamHandler() stream_hander.setLevel(level=levels[options.log_level]) rootlogger.addHandler(stream_hander) log.info("Starting 'Orange Canvas' application.") qt_argv = argv[:1] if options.style is not None: qt_argv += ["-style", options.style] if options.qt is not None: qt_argv += shlex.split(options.qt) qt_argv += args log.debug("Starting CanvasApplicaiton with argv = %r.", qt_argv) app = CanvasApplication(qt_argv) # NOTE: config.init() must be called after the QApplication constructor config.init() clear_settings_flag = os.path.join( config.widget_settings_dir(), "DELETE_ON_START") if options.clear_widget_settings or \ os.path.isfile(clear_settings_flag): log.info("Clearing widget settings") shutil.rmtree( config.widget_settings_dir(), ignore_errors=True) file_handler = logging.FileHandler( filename=os.path.join(config.log_dir(), "canvas.log"), mode="w" ) file_handler.setLevel(root_level) rootlogger.addHandler(file_handler) # intercept any QFileOpenEvent requests until the main window is # fully initialized. # NOTE: The QApplication must have the executable ($0) and filename # arguments passed in argv otherwise the FileOpen events are # triggered for them (this is done by Cocoa, but QApplicaiton filters # them out if passed in argv) open_requests = [] def onrequest(url): log.info("Received an file open request %s", url) open_requests.append(url) app.fileOpenRequest.connect(onrequest) settings = QSettings() stylesheet = options.stylesheet stylesheet_string = None if stylesheet != "none": if os.path.isfile(stylesheet): stylesheet_string = open(stylesheet, "rb").read() else: if not os.path.splitext(stylesheet)[1]: # no extension stylesheet = os.path.extsep.join([stylesheet, "qss"]) pkg_name = canvas.__name__ resource = "styles/" + stylesheet if pkg_resources.resource_exists(pkg_name, resource): stylesheet_string = \ pkg_resources.resource_string(pkg_name, resource).decode() base = pkg_resources.resource_filename(pkg_name, "styles") pattern = re.compile( r"^\s@([a-zA-Z0-9_]+?)\s*:\s*([a-zA-Z0-9_/]+?);\s*$", flags=re.MULTILINE ) matches = pattern.findall(stylesheet_string) for prefix, search_path in matches: QDir.addSearchPath(prefix, os.path.join(base, search_path)) log.info("Adding search path %r for prefix, %r", search_path, prefix) stylesheet_string = pattern.sub("", stylesheet_string) else: log.info("%r style sheet not found.", stylesheet) # Add the default canvas_icons search path dirpath = os.path.abspath(os.path.dirname(canvas.__file__)) QDir.addSearchPath("canvas_icons", os.path.join(dirpath, "icons")) canvas_window = CanvasMainWindow() canvas_window.setWindowIcon(config.application_icon()) if stylesheet_string is not None: canvas_window.setStyleSheet(stylesheet_string) if not options.force_discovery: reg_cache = cache.registry_cache() else: reg_cache = None widget_discovery = qt.QtWidgetDiscovery(cached_descriptions=reg_cache) widget_registry = qt.QtWidgetRegistry() widget_discovery.found_category.connect( widget_registry.register_category ) widget_discovery.found_widget.connect( widget_registry.register_widget ) want_splash = \ settings.value("startup/show-splash-screen", True, type=bool) and \ not options.no_splash if want_splash: pm, rect = config.splash_screen() splash_screen = SplashScreen(pixmap=pm, textRect=rect) splash_screen.setFont(QFont("Helvetica", 12)) color = QColor("#FFD39F") def show_message(message): splash_screen.showMessage(message, color=color) widget_discovery.discovery_start.connect(splash_screen.show) widget_discovery.discovery_process.connect(show_message) widget_discovery.discovery_finished.connect(splash_screen.hide) log.info("Running widget discovery process.") cache_filename = os.path.join(cache_dir(), "widget-registry.pck") if options.no_discovery: widget_registry = pickle.load(open(cache_filename, "rb")) widget_registry = qt.QtWidgetRegistry(widget_registry) else: widget_discovery.run(config.widgets_entry_points()) # Store cached descriptions cache.save_registry_cache(widget_discovery.cached_descriptions) pickle.dump(WidgetRegistry(widget_registry), open(cache_filename, "wb")) set_global_registry(widget_registry) canvas_window.set_widget_registry(widget_registry) canvas_window.show() canvas_window.raise_() want_welcome = \ settings.value("startup/show-welcome-screen", True, type=bool) \ and not options.no_welcome # Process events to make sure the canvas_window layout has # a chance to activate (the welcome dialog is modal and will # block the event queue, plus we need a chance to receive open file # signals when running without a splash screen) app.processEvents() app.fileOpenRequest.connect(canvas_window.open_scheme_file) if want_welcome and not args and not open_requests: canvas_window.welcome_dialog() elif args: log.info("Loading a scheme from the command line argument %r", args[0]) canvas_window.load_scheme(args[0]) elif open_requests: log.info("Loading a scheme from an `QFileOpenEvent` for %r", open_requests[-1]) canvas_window.load_scheme(open_requests[-1].toLocalFile()) # If run for the first time, open a browser tab with a survey show_survey = settings.value("startup/show-survey", True, type=bool) if show_survey: question = QMessageBox( QMessageBox.Question, 'Orange Survey', 'We would like to know more about how our software is used.\n\n' 'Would you care to fill our short 1-minute survey?', QMessageBox.Yes | QMessageBox.No) question.setDefaultButton(QMessageBox.Yes) later = question.addButton('Ask again later', QMessageBox.NoRole) question.setEscapeButton(later) def handle_response(result): if result == QMessageBox.Yes: success = QDesktopServices.openUrl( QUrl("http://orange.biolab.si/survey/short.html")); settings.setValue("startup/show-survey", not success) else: settings.setValue("startup/show-survey", result != QMessageBox.No) question.finished.connect(handle_response) question.show() # Tee stdout and stderr into Output dock log_view = canvas_window.log_view() stdout = TextStream() stdout.stream.connect(log_view.write) if sys.stdout: stdout.stream.connect(sys.stdout.write) stdout.flushed.connect(sys.stdout.flush) stderr = TextStream() error_writer = log_view.formated(color=Qt.red) stderr.stream.connect(error_writer.write) if sys.stderr: stderr.stream.connect(sys.stderr.write) stderr.flushed.connect(sys.stderr.flush) log.info("Entering main event loop.") try: with patch('sys.excepthook', ExceptHook(stream=stderr, canvas=canvas_window, handledException=handle_exception)),\ patch('sys.stderr', stderr),\ patch('sys.stdout', stdout): status = app.exec_() except BaseException: log.error("Error in main event loop.", exc_info=True) canvas_window.deleteLater() app.processEvents() app.flush() del canvas_window # Collect any cycles before deleting the QApplication instance gc.collect() del app return status
def fix_extension(ext, format, suggested_ext, suggested_format): dlg = QMessageBox( QMessageBox.Warning, "Mismatching extension", "Extension '{}' does not match the chosen file format, {}.\n\n" "Would you like to fix this?".format(ext, format)) role = QMessageBox.AcceptRole change_ext = \ suggested_ext and \ dlg.addButton("Change extension to " + suggested_ext, role) change_format =\ suggested_format and \ dlg.addButton("Save as " + suggested_format, role) cancel = dlg.addButton("Back", role) dlg.setEscapeButton(cancel) dlg.exec() if dlg.clickedButton() == cancel: return fix_extension.CANCEL elif dlg.clickedButton() == change_ext: return fix_extension.CHANGE_EXT elif dlg.clickedButton() == change_format: return fix_extension.CHANGE_FORMAT
def offerSave(self): if (Dirty and QMessageBox.question(self, "%s - Unsaved Changes" % AppName, "Save unsaved changes?", QMessageBox.Yes|QMessageBox.No) == QMessageBox.Yes): self.save()
def get_table(self): curIdx = self.tablecombo.currentIndex() if curIdx <= 0: if self.database_desc: self.database_desc["Table"] = "(None)" self.data_desc_table = None return if self.tablecombo.itemText(curIdx) != "Custom SQL": self.table = self.tables[self.tablecombo.currentIndex()] self.database_desc["Table"] = self.table if "Query" in self.database_desc: del self.database_desc["Query"] what = self.table else: what = self.sql = self.sqltext.toPlainText() self.table = "Custom SQL" if self.materialize: import psycopg2 if not self.materialize_table_name: self.Error.connection( "Specify a table name to materialize the query") return try: with self.backend.execute_sql_query("DROP TABLE IF EXISTS " + self.materialize_table_name): pass with self.backend.execute_sql_query("CREATE TABLE " + self.materialize_table_name + " AS " + self.sql): pass with self.backend.execute_sql_query("ANALYZE " + self.materialize_table_name): pass except (psycopg2.ProgrammingError, BackendError) as ex: self.Error.connection(str(ex)) return try: table = SqlTable(dict(host=self.host, port=self.port, database=self.database, user=self.username, password=self.password), what, backend=type(self.backend), inspect_values=False) except BackendError as ex: self.Error.connection(str(ex)) return self.Error.connection.clear() sample = False if table.approx_len() > LARGE_TABLE and self.guess_values: confirm = QMessageBox(self) confirm.setIcon(QMessageBox.Warning) confirm.setText("Attribute discovery might take " "a long time on large tables.\n" "Do you want to auto discover attributes?") confirm.addButton("Yes", QMessageBox.YesRole) no_button = confirm.addButton("No", QMessageBox.NoRole) sample_button = confirm.addButton("Yes, on a sample", QMessageBox.YesRole) confirm.exec() if confirm.clickedButton() == no_button: self.guess_values = False elif confirm.clickedButton() == sample_button: sample = True self.Information.clear() if self.guess_values: QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) if sample: s = table.sample_time(1) domain = s.get_domain(inspect_values=True) self.Information.data_sampled() else: domain = table.get_domain(inspect_values=True) QApplication.restoreOverrideCursor() table.domain = domain if self.download: if table.approx_len() > MAX_DL_LIMIT: QMessageBox.warning( self, 'Warning', "Data is too big to download.\n" "Consider using the Data Sampler widget to download " "a sample instead.") self.download = False elif table.approx_len() > AUTO_DL_LIMIT: confirm = QMessageBox.question( self, 'Question', "Data appears to be big. Do you really " "want to download it to local memory?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if confirm == QMessageBox.No: self.download = False if self.download: table.download_data(MAX_DL_LIMIT) table = Table(table) return table