class LostFolderDialog(object): def __init__(self, parent, path, restoreFolder, dialog_id=0): super(LostFolderDialog, self).__init__() self._path = path self._restoreFolder = restoreFolder self._dialog_id = dialog_id self._dialog = QDialog( parent, Qt.Dialog | Qt.CustomizeWindowHint | Qt.WindowTitleHint) self._dialog.setAttribute(Qt.WA_MacFrameworkScaled) self._dialog.setWindowIcon(QIcon(':/images/icon.png')) self._ui = lost_folder_dialog.Ui_Dialog() self._ui.setupUi(self._dialog) self._ui.textLabel.setText(self._ui.textLabel.text().replace( '{PATH}', path)) self._connect_slots() def _connect_slots(self): ui = self._ui ui.tryAgainButton.clicked.connect(self._on_tryAgain) ui.restoreFolderButton.clicked.connect(self._on_restoreFolder) def show(self): self._dialog.raise_() self._dialog.exec_() def _on_tryAgain(self): if op.isdir(self._path): self._dialog.accept() def _on_restoreFolder(self): self._dialog.accept() self._restoreFolder(self._dialog_id, 0)
def accept(self): if self.result == 'XML': app = ET.Element('App') app.attrib['title'] = self.title child = ET.fromstring(self.formwidget.get()) app.append(child) self.data = ET.tostring(app) else: self.data = self.formwidget.get() QDialog.accept(self)
def accept(self) -> None: """ Called when the user clicks the "save" button. :return: None :rtype: NoneType """ self._project.setBackend(self.ui.backendEdit.currentText()) self._project.setName(self.ui.nameEdit.text()) self._project.setProjectDir(self.ui.locationEdit.text()) self._project.setDescription(self.ui.descriptionEdit.toPlainText()) self._project.setExecutableFile(self.ui.appEdit.text()) QDialog.accept(self)
def accept(self): """ Applies given information when the user clicks "OK" """ warningShown = False for tabNum in range(1, 2): # TODO: Change to 4 when done for planetNum in range(1, 6): planet = 'self.mainWindow.ui.pie' + str(planetNum) + 'series' spinBox = 'self.ui.planet' + str(planetNum) + 'Num' button = 'self.ui.planet' + str(planetNum) + 'Enable' if tabNum in (2, 3): planet += '_' + str(tabNum) spinBox += '_' + str(tabNum) button += '_' + str(tabNum) exec('checked = ' + button + '.isChecked()', locals()) exec('pE = ' + planet + '.enabled', locals()) if locals()['checked']: exec('pieces = ' + spinBox + '.value()', locals()) pcs = locals()['pieces'] exec('samePcNum = ' + planet + '.sum() == ' + str(pcs), locals()) if not locals()['pE']: exec(planet + '.setEnabled(' + str(pcs) + ')') elif not locals()['samePcNum']: if not warningShown: result = self.showChangeWarning() warningShown = True if result == QMessageBox.Cancel: return exec(planet + '.clear()') exec(planet + '.setEnabled(' + str(pcs) + ')') # Only other case is planet already being enabled with the same num of pcs, nothing to do. else: if locals()['pE']: if not warningShown: result = self.showChangeWarning() warningShown = True if result == QMessageBox.Cancel: return toDelete = [] for wo in self.mainWindow.machines[tabNum - 1].workOrders: if wo.planetNum == planetNum: toDelete.append(wo) for wo in toDelete: self.mainWindow.deleteWorkOrder(wo) toDelete.clear() exec(planet + '.setDisabled()') return QDialog.accept(self)
def accept(self): """ This method is called when the user clicks the "OK" button. It will validate all of the user's input and show error messages if any information is invalid. :emits: setApiCompiler if the api compiler setting was successfully accpeted :return: None :rtype: NoneType """ self.ui.error_label.setText("") errors = [] interpExe = self.ui.interpreterLocation.text() # Check for valid target application executable if not interpExe: errors.append("Need to select target application executable") else: if not isExecutable(interpExe): errors.append("Target application must be an executable file.") elif not appBitnessMatches(interpExe): pyBit = getPythonBitness() appBit = getExeBitness(interpExe) errors.append( "{} bit Python cannot control {} bit application".format( pyBit, appBit)) # Construct a set for documentation type setDocType = set() if self.ui.checkBoxDocx.isChecked(): setDocType.add(CompilationProfile.DocType.Doc) if self.ui.checkBoxHtml.isChecked(): setDocType.add(CompilationProfile.DocType.Html) if self.ui.checkBoxPdf.isChecked(): setDocType.add(CompilationProfile.DocType.Pdf) if self.ui.checkBoxEPub.isChecked(): setDocType.add(CompilationProfile.DocType.EPub) if len(setDocType) == 0: errors.append("You must select at least one documentation type.") # Construct a set for component resolution type setcompResOpts = set() if self.ui.checkBoxTokenExactMatch.isChecked(): setcompResOpts.add(MatchOption.ExactToken) if self.ui.checkBoxTokenCloseMatch.isChecked(): setcompResOpts.add(MatchOption.CloseToken) if self.ui.checkBoxPywinautoBestMatch.isChecked(): setcompResOpts.add(MatchOption.PWABestMatch) if len(setcompResOpts) == 0: errors.append( "You must select at least one component resolution type.") apiFolderDir = self.ui.apiLocation.text() interpExeDir = self.ui.interpreterLocation.text() theCompilationProfile = CompilationProfile(setDocType, setcompResOpts, apiFolderDir, interpExeDir) # if there are any errors, show them, then return. if len(errors) != 0: errMsg = "Errors:\n" for err in errors: errMsg += "\t" + err + "\n" self.ui.error_label.setText(errMsg) return # TODO: figure out why FindExecutable: There is no association for the file get printed self.setApiCompiler.emit(theCompilationProfile) c = Compiler(theCompilationProfile).compileAPI() return QDialog.accept(self)
class InsertLinkDialog(object): def __init__(self, parent, dp=None, signal_server_address=''): self._dialog = QDialog(parent) self._dp = dp self._parent = parent self._link = '' self._password = '' self._is_shared = True self._password_mode = False self._signal_server_address = signal_server_address self._dialog.setWindowIcon(QIcon(':/images/icon.png')) self._ui = Ui_insert_link_dialog() self._ui.setupUi(self._dialog) self._init_ui() self._cant_validate = tr("Cannot validate share link") def _init_ui(self): self._dialog.setAttribute(Qt.WA_MacFrameworkScaled) self._hide_error() self._ok_button = self._ui.ok_button self._ui.cancel_button.clicked.connect(self._dialog.reject) self._ok_button.clicked.connect(self._ok_clicked) self._ui.link_line_edit.textChanged.connect(self._text_changed) self._set_fonts() def _set_fonts(self): controls = [] controls.extend([c for c in self._dialog.findChildren(QLabel)]) controls.extend( [c for c in self._dialog.findChildren(QLineEdit)]) controls.extend( [c for c in self._dialog.findChildren(QPushButton)]) for control in controls: font = control.font() font_size = control.font().pointSize() * self._dp if font_size > 0: control.setFont(QFont(font.family(), font_size)) def _ok_clicked(self): validated = self._validate() if validated is None: self._change_mode() elif validated: if self._password_mode: self._password = self._ui.link_line_edit.text() else: self._link = self._ui.link_line_edit.text() self._dialog.accept() def _text_changed(self, *args, **kwargs): self._hide_error() def _validate(self): if self._is_shared: return self._validate_shared() else: return self._validate_network_file() def _validate_shared(self): if self._password_mode: return self._validate_password() if not self._validate_scheme(): return False return self._check_share_link() def _validate_scheme(self): share_url = self._ui.link_line_edit.text() pr = urlparse(share_url) success = pr.scheme in ('http', 'https', 'pvtbox') and pr.path share_hash = pr.path.split('/')[-1] success = success and share_hash and len(share_hash) == 32 if not success: self._show_error() return success def _check_share_link(self): self._lock_screen() share_url = self._link if self._password_mode \ else self._ui.link_line_edit.text() pr = urlparse(share_url) share_hash = pr.path.split('/')[-1] param_str = '' if self._password_mode: password = self._ui.link_line_edit.text() password = base64.b64encode( bytes(password, 'utf-8')).decode('utf-8') params = {"passwd": password} query = urlencode(params, encoding='utf-8') param_str = '?{}'.format(query) url = 'https://{}/ws/webshare/{}{}'.format( self._signal_server_address, share_hash, param_str) logger.debug("url %s", url) error = '' try: response = urlopen(url, timeout=1) status = response.status except HTTPError as e: logger.warning("Request to signal server returned error %s", e) status = e.code response = str(e.read(), encoding='utf-8') except URLError as e: logger.warning("Request to signal server returned url error %s", e) self._show_error(self._cant_validate) self._unlock_screen() return False logger.debug("request status %s", status) if status == 400: if self._password_mode: self._link += param_str success = True else: success, error = self._parse_response(response) if success is False: self._show_error(error) self._unlock_screen() return success def _parse_response(self, response): try: data = json.loads(response) err_code = data.get("errcode", '') info = data.get("info", '') if err_code == 'SHARE_WRONG_PASSWORD': success = None if not self._password_mode else False error = '' elif err_code == 'LOCKED_CAUSE_TOO_MANY_BAD_LOGIN': success = False error = tr('Locked after too many incorrect attempts') elif err_code == 'SHARE_NOT_FOUND': success = False error = '' else: success = False error = info if info else self._cant_validate except Exception as e: logger.warning("Can't parse response (%s). reason: %s", response, e) success = False error = self._cant_validate return success, error def _validate_password(self): if not self._ui.link_line_edit.text(): self._show_error() return False return self._check_share_link() def _validate_network_file(self): # place code to validate network file link here return False def _change_mode(self): assert not self._password_mode, \ "Must not be in password mode in changing mode" logger.debug("Changing to password mode") self._password_mode = True self._dialog.setWindowTitle(tr("Insert password")) self._link = self._ui.link_line_edit.text() self._ui.link_line_edit.setText('') self._ui.link_line_edit.setPlaceholderText(tr("Insert password here")) self._ui.link_line_edit.setEchoMode(QLineEdit.Password) self._hide_error() def _show_error(self, error_text=''): if not error_text: link_text = self._ui.link_line_edit.text() error_text = tr("Please insert share link") \ if not self._password_mode and not link_text \ else tr("Invalid link") if not self._password_mode \ else tr("Password can not be empty") if not link_text \ else tr("Wrong password") self._ui.error_label.setText(error_text) self._ui.link_line_edit.setFocus() def _hide_error(self): self._ui.error_label.setText('') self._ui.link_line_edit.setFocus() def _lock_screen(self): self._ok_button.setText(tr("Processing...")) self._dialog.setEnabled(False) self._dialog.repaint() def _unlock_screen(self): self._ok_button.setText(tr("Ok")) self._dialog.setEnabled(True) self._dialog.repaint() def show(self): logger.debug("Opening insert link dialog") if self._dialog.exec_() == QDialog.Rejected: self._link = '' self._password = '' self._is_shared = True logger.verbose("link (%s), password (%s)", self._link, self._password) return self._link, self._is_shared
class batch_file_viewer(QTableWidget): def __init__(self, nf_settings_path): super(batch_file_viewer,self).__init__(parent = None) self.nf_settings_parser = custom_config_parser() self.nf_settings_parser.load(nf_settings_path) self.setRowCount(20) self.setColumnCount(2) # Fill all places so there are no "None" types in the table for row in range(self.rowCount()): for column in range(self.columnCount()): item = QTableWidgetItem() item.setText('') self.setItem(row, column, item) self.original_background = item.background() self.clipboard = QGuiApplication.clipboard() self.cellChanged.connect(self.check_cell) # Needs to be after "filling for loop" above self.header = self.horizontalHeader() self.header.setSectionResizeMode(0, QHeaderView.Stretch) self.setHorizontalHeaderLabels(["MS files", "Label"]) self.header.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.header.customContextMenuRequested.connect( self.right_click_menu ) self.saved_text = '' self.store_re_text = '' def right_click_menu(self, point): column = self.header.logicalIndexAt(point.x()) # show menu about the column if column 1 if column == 1: menu = QMenu(self) menu.addAction('Auto label (experimental)', self.auto_label) menu.popup(self.header.mapToGlobal(point)) elif column == 0: menu = QMenu(self) menu.addAction('Remove empty rows', self.remove_empty_rows) menu.popup(self.header.mapToGlobal(point)) def keyPressEvent(self, event): """Add functionallity to keyboard""" # Mac OS specifics is_mac_os_delete = (event.key() == QtCore.Qt.Key_H and event.modifiers() == QtCore.Qt.ControlModifier) if event.key() == QtCore.Qt.Key_Delete or is_mac_os_delete: # 16777223 for item in self.selectedItems(): item.setText('') elif event.key() == 16777221 or event.key() == 16777220: # *.221 is right enter if len(self.selectedIndexes()) == 0: # Quick check if anything is selected pass else: index = self.selectedIndexes()[0] # Take last if index.row() + 1 > self.rowCount() - 1: self.addRow_with_items() self.setCurrentCell(index.row() + 1, index.column()) else: modifiers = QGuiApplication.keyboardModifiers() if modifiers == QtCore.Qt.ControlModifier and event.key() == 67: # Copy self.saved_text = '' new_row = False for index in self.selectedIndexes(): if index.column() == 0: if new_row: self.saved_text += '\n' new_row = True self.saved_text += self.item(index.row(), index.column()).text() self.saved_text += '\t' elif index.column() == 1: self.saved_text += self.item(index.row(), index.column()).text() self.saved_text += '\n' new_row = False self.clipboard.setText(self.saved_text) elif modifiers == QtCore.Qt.ControlModifier and event.key() == 86: # Paste clipboard_text = self.clipboard.text() clipboard_text = clipboard_text.split('\n') paste_index = self.selectedIndexes()[0] row = paste_index.row() for text, index in zip(clipboard_text, range(len(clipboard_text))): text = text.split('\t') column = paste_index.column() for input in text: if input == '': continue if column > self.columnCount() - 1: pass else: if self.item(row, column) is None: self.addRow_with_items() self.item(row, column).setText(input) column += 1 row += 1 else: super().keyPressEvent(event) # Propagate to built in methods # This interferes with copy and paste if it is not else def check_cell(self, row, column): """Triggered when cell is changed""" self.blockSignals(True) self.pick_color(row, column) self.blockSignals(False) def addRow_with_items(self): item = QTableWidgetItem() item.setText('') self.setRowCount(self.rowCount() + 1) self.setItem(self.rowCount() - 1, 0, item) # Note: new rowcount here label = QTableWidgetItem() label.setText('') self.setItem(self.rowCount() - 1, 1, label) def pick_color(self, row, column): """Triggered by check_cell""" msfile = self.item(row, 0) label = self.item(row, 1) if label is None or msfile is None: # NOTE: item == None will give NotImplementedError. Must use "is" return # This might remove some weird errors in the future # Fix for adding empty spaces if msfile.text() == ' ': msfile.setText('') # Ms file if not os.path.isfile(msfile.text()): msfile.setForeground(QColor('red')) elif msfile.text().split('.')[-1] == "mzML": msfile.setForeground(QColor(0,255,150)) elif msfile.text().split('.')[-1] != "mzML": msfile.setForeground(QColor(30,150,255)) workflow = self.nf_settings_parser.get('params.workflow') if msfile.text() == '': label.setBackground(self.original_background) label.setForeground(QColor('white')) elif label.text() == '' and os.path.isfile(msfile.text()) and workflow == "Full": label.setBackground(QColor('red')) elif os.path.isfile(msfile.text()) and label.text() != '': label.setBackground(self.original_background) label.setForeground(QColor(0,255,150)) else: label.setBackground(self.original_background) label.setForeground(QColor('white')) def update(self): for row in range(self.rowCount()): for column in range(self.columnCount()): self.pick_color(row, column) def auto_assign(self, file): """Triggered when using file chooser button""" for row in range(self.rowCount()): item = self.item(row, 0) if item.text() == '': self.item(row, 0).setText(file) return # If we get here, add more rows self.blockSignals(True) self.addRow_with_items() self.item(self.rowCount() - 1, 0).setText(file) self.pick_color(self.rowCount() - 1, 0) self.blockSignals(False) def auto_label(self): all_labels = [] # Get current labels, we want unique for row in range(self.rowCount()): label = self.item(row, 1).text() all_labels.append(label) self.dialog = QDialog() lay = QVBoxLayout() self.dialog.setLayout(lay) self.line = QLineEdit() self.line.setText(self.store_re_text) bbox = QDialogButtonBox() bbox.addButton("Help", QDialogButtonBox.HelpRole) bbox.addButton("Apply", QDialogButtonBox.AcceptRole) bbox.addButton("Cancel", QDialogButtonBox.RejectRole) bbox.accepted.connect(self.apply_auto) bbox.rejected.connect(self.cancel_auto) bbox.helpRequested.connect(self.help_auto) lay.addWidget(self.line) lay.addWidget(bbox) self.dialog.resize(300, 100) ans = self.dialog.exec_() # This will block until the dialog closes if ans != 1: return re_text = self.line.text() self.store_re_text = re_text # Assign labels c = 0 for row in range(self.rowCount()): label = self.item(row, 1).text() file = self.item(row, 0).text() if label == '' and file != '': file_name = os.path.basename(file) search = re.search(re_text, file_name) if search is not None: c += 1 # idk how to check how many captured groups, so lets do this a hacky way for i in range(10,-1,-1): try: added_label = search.group(i) break except Exception as e: pass else: added_label = '' # Do not add label if you don't know what to add self.item(row, 1).setText(added_label) if c == 0: ERROR("No files matched the regex pattern") self.auto_label() def apply_auto(self): re_text = self.line.text() test_string = "This is a string to check if you put in a correct regex code" try: match = re.search(re_text, test_string) except Exception as e: ERROR("This is not a valid regex string. Error is: \n" + str(e)) return self.dialog.accept() def cancel_auto(self): self.dialog.reject() def help_auto(self): help_dialog = QDialog() lay = QVBoxLayout() help_string = '''<html> <center> Auto labeler uses regular expressions to determine which files belong to a certain groupself. <br> Write the regular expression in the box and press apply. <br> The labeler will then label your file depending on the naming convention you applied. <br> Example: You have 100s of files named like this <br> patient_X_<date>.RAW <br> Solution can be found <a href=\"https://regex101.com/r/dpCBo9/1/\">here</a> <br> NOTE: The auto labeler will always take the LAST capturing group </html> ''' help_label = QLabel(help_string) help_label.setOpenExternalLinks(True) lay.addWidget(help_label) help_dialog.setLayout(lay) ans = help_dialog.exec_() # This will block until the dialog closes def remove_empty_rows(self): row = 0 for _ in range(5000): file = self.item(row, 0) label = self.item(row, 1) if file is None or label is None: self.removeRow(row) elif file.text() == '' and label.text() == '': self.removeRow(row) else: row += 1 if self.rowCount() == 0: item = QTableWidgetItem() self.setRowCount(self.rowCount() + 1) row = self.rowCount() - 1 self.setItem(row, 0, item) # Note: new rowcount here label = QTableWidgetItem() label.setText('') self.setItem(row, 1, label)
class Settings(object): class _MigrationFailed(ExpectedError): pass def __init__(self, cfg, main_cfg, start_service, exit_service, parent=None, size=None, migrate=False, dp=1, get_offline_dirs=lambda: None, set_offline_dirs=lambda o, no: None): super(Settings, self).__init__() self._cfg = cfg self._main_cfg = main_cfg self._start_service = start_service self._exit_service = exit_service self._parent = parent self._size = size self._dp = dp self._get_offline_dirs = get_offline_dirs self._set_offline_dirs = set_offline_dirs self._dialog = QDialog(parent) self._dialog.setWindowIcon(QIcon(':/images/icon.png')) self._dialog.setAttribute(Qt.WA_MacFrameworkScaled) self._ui = settings.Ui_Dialog() self._ui.setupUi(self._dialog) self._max_root_len = get_max_root_len(self._cfg) self._migrate = migrate self._migration = None self._migration_cancelled = False try: self._ui.account_type.setText( license_display_name_from_constant(self._cfg.license_type)) self._ui.account_type.setVisible(True) self._ui.account_type_header.setVisible(True) self._ui.account_upgrade.setVisible(True) except KeyError: pass upgrade_license_types = (FREE_LICENSE, FREE_TRIAL_LICENSE) if self._cfg.license_type in upgrade_license_types: self._ui.account_upgrade.setText('<a href="{}">{}</a>'.format( GET_PRO_URI.format(self._cfg.host), tr('Upgrade'))) self._ui.account_upgrade.setTextFormat(Qt.RichText) self._ui.account_upgrade.setTextInteractionFlags( Qt.TextBrowserInteraction) self._ui.account_upgrade.setOpenExternalLinks(True) self._ui.account_upgrade.setAlignment(Qt.AlignLeft) else: self._ui.account_upgrade.setText("") self._ui.centralWidget.setFrameShape(QFrame.NoFrame) self._ui.centralWidget.setLineWidth(1) self._ui.language_comboBox.addItem(tr('English')) self._ui.language_comboBox.setEnabled(False) self._connect_slots() self._set_fonts() self._ui.tabWidget.setCurrentIndex(0) self._smart_sync_dialog = None self.logged_out = Signal(bool) self.logging_disabled_changed = Signal(bool) # FIXMe: without line below app crashes on exit after settings opened self._dialog.mousePressEvent = self.on_mouse_press_event def on_mouse_press_event(self, ev): pass def _connect_slots(self): ui = self._ui ui.logout_button.clicked.connect(self._logout) ui.download_auto_radioButton.clicked.connect( lambda: ui.download_limit_edit.setEnabled( False) or ui.download_limit_edit.clear()) ui.download_limit_radioButton.clicked.connect( lambda: ui.download_limit_edit.setEnabled(True)) ui.upload_auto_radioButton.clicked.connect( lambda: ui.upload_limit_edit.setEnabled( False) or ui.upload_limit_edit.clear()) ui.upload_limit_radioButton.clicked.connect( lambda: ui.upload_limit_edit.setEnabled(True)) ui.buttonBox.accepted.connect(self._dialog.accept) ui.buttonBox.rejected.connect(self._dialog.reject) ui.smart_sync_button.clicked.connect( self._on_smart_sync_button_clicked) ui.location_button.clicked.connect( self._on_sync_folder_location_button_clicked) ui.location_button.enterEvent = lambda _: \ ui.location_button.setIcon(QIcon( ':/images/settings/pencil_hovered.svg')) ui.location_button.leaveEvent = lambda _: \ ui.location_button.setIcon(QIcon( ':/images/settings/pencil.svg')) ui.smart_sync_button.enterEvent = lambda _: \ ui.smart_sync_button.setIcon(QIcon( ':/images/settings/folder_sync_hovered.svg')) ui.smart_sync_button.leaveEvent = lambda _: \ ui.smart_sync_button.setIcon(QIcon( ':/images/settings/folder_sync.svg')) ui.logout_button.enterEvent = lambda _: \ ui.logout_button.setIcon(QIcon( ':/images/settings/logout_hovered.svg')) ui.logout_button.leaveEvent = lambda _: \ ui.logout_button.setIcon(QIcon( ':/images/settings/logout.svg')) def _set_fonts(self): ui = self._ui controls = [ui.tabWidget, ui.language_comboBox] controls.extend([c for c in ui.tabWidget.findChildren(QLabel)]) controls.extend([c for c in ui.tabWidget.findChildren(QLineEdit)]) controls.extend([c for c in ui.tabWidget.findChildren(QPushButton)]) controls.extend([c for c in ui.tabWidget.findChildren(QCheckBox)]) controls.extend([c for c in ui.tabWidget.findChildren(QRadioButton)]) for control in controls: font = control.font() font_size = control.font().pointSize() * self._dp if font_size > 0: control_font = QFont(font.family(), font_size) control_font.setBold(font.bold()) control.setFont(control_font) def _logout(self): userAnswer = msgbox(tr('Keep local files on device?'), buttons=[ (tr('Clear all'), 'Wipe'), (tr('Keep'), 'Keep'), ], parent=self._dialog, default_index=1, enable_close_button=True) if userAnswer == '': return wipe_all = userAnswer == 'Wipe' if not wipe_all: self._cfg.set_settings({'user_password_hash': ""}) self.logged_out.emit(wipe_all) self._dialog.reject() def show(self, on_finished): def finished(): if self._dialog.result() == QDialog.Accepted: self._apply_settings() self._dialog.finished.disconnect(finished) on_finished() self._setup_to_ui() if self._migrate: self._ui.tabWidget.setCurrentIndex(1) # Account page QTimer.singleShot(100, self._on_sync_folder_location_button_clicked) self._dialog.finished.connect(finished) self._dialog.raise_() self._dialog.setModal(True) self._dialog.show() def _setup_to_ui(self): ui = self._ui cfg = self._cfg portable = is_portable() if cfg.get_setting('lang', None) is None: self._ui.language_comboBox.setCurrentIndex(0) else: lang = cfg.lang if cfg.lang in get_available_languages() else 'en' assert lang in get_available_languages() for i in range(1, ui.language_comboBox.count()): if ui.language_comboBox.itemText(i) == lang: ui.language_comboBox.setCurrentIndex(i) break ui.location_edit.setText( FilePath(cfg.sync_directory) if cfg.sync_directory else '') ui.location_button.setEnabled(not portable) if portable: ui.location_button.setToolTip(tr("Disabled in portable version")) ui.email_label.setText(cfg.user_email if cfg.user_email else '') def set_limit(limit, auto_btn, manual_btn, edit): edit.setValidator(QRegExpValidator(QRegExp("\\d{1,9}"))) if limit: manual_btn.setChecked(True) edit.setText(str(limit)) else: auto_btn.setChecked(True) auto_btn.click() set_limit(limit=cfg.download_limit, auto_btn=ui.download_auto_radioButton, manual_btn=ui.download_limit_radioButton, edit=ui.download_limit_edit) set_limit(limit=cfg.upload_limit, auto_btn=ui.upload_auto_radioButton, manual_btn=ui.upload_limit_radioButton, edit=ui.upload_limit_edit) ui.autologin_checkbox.setChecked(self._main_cfg.autologin) ui.autologin_checkbox.setEnabled(not portable) if portable: ui.autologin_checkbox.setToolTip( tr("Disabled in portable version")) ui.tracking_checkbox.setChecked(cfg.send_statistics) ui.autoupdate_checkbox.setChecked(self._main_cfg.autoupdate) ui.download_backups_checkBox.setChecked(cfg.download_backups) ui.is_smart_sync_checkBox.setChecked(cfg.smart_sync) ui.disable_logging_checkBox.setChecked(self._main_cfg.logging_disabled) # Disable smart sync for free license if not cfg.license_type or cfg.license_type == FREE_LICENSE: ui.is_smart_sync_checkBox.setText( tr("SmartSync+ is not available for your license")) ui.is_smart_sync_checkBox.setChecked(False) ui.is_smart_sync_checkBox.setCheckable(False) ui.smart_sync_button.setEnabled(False) ui.startup_checkbox.setChecked(is_in_system_startup()) ui.startup_checkbox.setEnabled(not portable) if portable: ui.startup_checkbox.setToolTip(tr("Disabled in portable version")) def _apply_settings(self): service_settings, main_settings = self._get_configs_from_ui() if main_settings['logging_disabled'] != \ self._main_cfg.logging_disabled: self.logging_disabled_changed.emit( main_settings['logging_disabled']) self._cfg.set_settings(service_settings) self._main_cfg.set_settings(main_settings) if self._ui.startup_checkbox.isChecked(): if not is_in_system_startup(): add_to_system_startup() else: if is_in_system_startup(): remove_from_system_startup() def _config_is_changed(self): service_settings, main_settings = self._get_configs_from_ui() for param, value in service_settings.items(): if self._cfg.get_setting(param) != value: return True for param, value in main_settings.items(): if self._main_cfg.get_setting(param) != value: return True return False def _get_configs_from_ui(self): ui = self._ui return { 'lang': (str(ui.language_comboBox.currentText()) if ui.language_comboBox.currentIndex() > 0 else None), 'upload_limit': (0 if ui.upload_auto_radioButton.isChecked() or not ui.upload_limit_edit.text() else int( ui.upload_limit_edit.text())), 'download_limit': (0 if ui.download_auto_radioButton.isChecked() or not ui.download_limit_edit.text() else int( ui.download_limit_edit.text())), 'send_statistics': bool(ui.tracking_checkbox.isChecked()), 'download_backups': bool(ui.download_backups_checkBox.isChecked()), 'smart_sync': bool(ui.is_smart_sync_checkBox.isChecked()), 'autologin': bool(ui.autologin_checkbox.isChecked()), }, { 'autologin': bool(ui.autologin_checkbox.isChecked()), 'autoupdate': bool(ui.autoupdate_checkbox.isChecked()), 'logging_disabled': bool(ui.disable_logging_checkBox.isChecked()), 'download_backups': bool(ui.download_backups_checkBox.isChecked()), } def _on_smart_sync_button_clicked(self): self._get_offline_dirs() root = str(self._ui.location_edit.text()) self._smart_sync_dialog = SmartSyncDialog(self._dialog) offline, online = self._smart_sync_dialog.show(root_path=root, hide_dotted=True) if offline or online: logger.info("Directories set to be offline: (%s)", ", ".join(map(lambda s: u"'%s'" % s, offline))) self._set_offline_dirs(offline, online) def offline_dirs(self, offline_dirs): root = str(self._ui.location_edit.text()) pc = PathConverter(root) offline_dirs_abs_paths = set( map(lambda p: pc.create_abspath(p), offline_dirs)) if self._smart_sync_dialog: self._smart_sync_dialog.set_offline_paths(offline_dirs_abs_paths) def _on_sync_folder_location_button_clicked(self): selected_folder = QFileDialog.getExistingDirectory( self._dialog, tr('Choose Pvtbox folder location'), get_parent_dir(FilePath(self._cfg.sync_directory))) selected_folder = ensure_unicode(selected_folder) try: if not selected_folder: raise self._MigrationFailed("Folder is not selected") if len(selected_folder + "/Pvtbox") > self._max_root_len: if not self._migrate: msgbox(tr("Destination path too long. " "Please select shorter path."), tr("Path too long"), parent=self._dialog) raise self._MigrationFailed("Destination path too long") free_space = get_free_space(selected_folder) selected_folder = get_data_dir(dir_parent=selected_folder, create=False) if FilePath(selected_folder) == FilePath(self._cfg.sync_directory): raise self._MigrationFailed("Same path selected") if FilePath(selected_folder) in FilePath(self._cfg.sync_directory): msgbox(tr("Can't migrate into existing Pvtbox folder.\n" "Please choose other location"), tr("Invalid Pvtbox folder location"), parent=self._dialog) raise self._MigrationFailed( "Can't migrate into existing Pvtbox folder") if self._size and free_space < self._size: logger.debug( "No disk space in %s. Free space: %s. Needed: %s.", selected_folder, free_space, self._size) msgbox(tr( "Insufficient disk space for migration to\n{}.\n" "Please clean disk", selected_folder), tr("No disk space"), parent=self._dialog) raise self._MigrationFailed( "Insufficient disk space for migration") self._migration_cancelled = False dialog = QProgressDialog(self._dialog) dialog.setWindowTitle(tr('Migrating to new Pvtbox folder')) dialog.setWindowIcon(QIcon(':/images/icon.svg')) dialog.setModal(True) dialog.setMinimum(0) dialog.setMaximum(100) dialog.setMinimumSize(400, 80) dialog.setAutoClose(False) def progress(value): logger.debug("Migration dialog progress received: %s", value) dialog.setValue(value) def migration_failed(error): logger.warning("Migration failed with error: %s", error) msgbox(error, tr('Migration to new Pvtbox folder error'), parent=dialog) dialog.cancel() self._migration_cancelled = True done() def cancel(): logger.debug("Migration dialog cancelled") self._migration_cancelled = True self._migration.cancel() def done(): logger.debug("Migration done") try: self._migration.progress.disconnect(progress) self._migration.failed.disconnect(migration_failed) self._migration.done.disconnect(done) dialog.canceled.disconnect(cancel) except Exception as e: logger.warning("Can't disconnect signal %s", e) dialog.hide() dialog.done(QDialog.Accepted) dialog.close() self._migration = SyncDirMigration(self._cfg, parent=self._dialog) self._migration.progress.connect(progress, Qt.QueuedConnection) self._migration.failed.connect(migration_failed, Qt.QueuedConnection) self._migration.done.connect(done, Qt.QueuedConnection) dialog.canceled.connect(cancel) self._exit_service() old_dir = self._cfg.sync_directory self._migration.migrate(old_dir, selected_folder) def on_finished(): logger.info("Migration dialog closed") if not self._migration_cancelled: logger.debug("Setting new location") self._ui.location_edit.setText(FilePath(selected_folder)) disable_file_logging(logger) shutil.rmtree(op.join(old_dir, '.pvtbox'), ignore_errors=True) set_root_directory(FilePath(selected_folder)) enable_file_logging(logger) make_dir_hidden(get_patches_dir(selected_folder)) self._start_service() dialog.finished.connect(on_finished) dialog.show() except self._MigrationFailed as e: logger.warning("Sync dir migration failed. Reason: %s", e) finally: if self._migrate: self._dialog.accept()
def accept(self) -> None: """ When the user clicks "OK", the ports and name are set on the Action. :return: None :rtype: NoneType """ apim = sm.StateMachine.instance._project.getAPIModel() # get copies of input and output ports for validation. inputPorts = [] il = self.ui.inputLayout for i in range(il.count() - 1): pew = il.itemAt(i).widget() inputPorts.append(pew.previewPort()) outputPorts = [] il = self.ui.outputLayout for i in range(il.count() - 1): pew = il.itemAt(i).widget() outputPorts.append(pew.previewPort()) # clear error message self.ui.errorLabel.setText("") errors = [] ################################# # VALIDATE ACTION NAME AND PORTS ################################# name = self.ui.actionName.text().strip() # Make sure name of action pipeline is unique if name in [ap.getName() for ap in apim.getActionPipelines()]: errors.append( "An action pipeline with the name '%s' already exists." % name) # Make sure name is a valid identifier if not name.isidentifier(): errors.append( "The name of the action pipeline must be a valid Python identifier." ) # Name must start with a lower-case character if name[0].isupper(): errors.append( "The action name must start with a lower-case letter.") # Make sure all inputs have unique names. inputNames = set() for port in inputPorts: if port.getName() in inputNames: errors.append( "Duplicate name '{}' in input ports is not allowed".format( port.getName())) inputNames.add(port.getName()) # Make sure all outputs have unique names. outputNames = set() for port in outputPorts: if port.getName() in outputNames: errors.append( "Duplicate name '{}' in output ports is not allowed.". format(port.getName())) outputNames.add(port.getName()) # Make sure that optional inputs come after required inputs optionalFound = False for port in inputPorts: if port.isOptional(): optionalFound = True if optionalFound and not port.isOptional(): errors.append( "Optional inputs must come after required inputs.") break # Make sure that optional inputs have a default value for port in inputPorts: if port.isOptional(): if port.getDefaultValue() == "": errors.append( "All optional ports must have default values.") # Make sure the type of the port is not NoneType for port in inputPorts + outputPorts: if port.getDataType() == type(None): errors.append("Data type of port cannot be NoneType.") break # If type is simple, and port is optional, check the type of the default value. checkable_types = [int, float, str, bool] for port in inputPorts: if port.isOptional() and port.getDataType() != type(None): default = port.getDefaultValue() t = port.getDataType() bad = False try: result = t(default) except ValueError: bad = True else: if t == bool and result is False: bad = True if t == str: validEnds = default.startswith('"') and default.endswith( '"') or default.startswith("'") and default.endswith( "'") if not validEnds: errors.append( "String values must be enclosed by quotes.") else: if default[0] in default[1:-1]: errors.append( "Avoid using the same quote character in the default " "value as the one that encloses the default value." ) if bad: errors.append( "The default value is not the correct type for port '{}'." .format(port.getName())) if len(errors) != 0: errMsg = "Errors:\n" for err in errors: errMsg += "\t" + err + "\n" self.ui.errorLabel.setText(errMsg) self.ui.errorLabel.show() return else: self.ui.errorLabel.hide() ################################# # EDIT ACTION NAME AND PORTS ################################# self._action.setName(name) # add new input ports to the action il = self.ui.inputLayout newPorts = [] for i in range(il.count() - 1): pew = il.itemAt(i).widget() pew.updatePort() port = pew.getPort() newPorts.append(port) if port.getAction() is None: self._action.addInputPort(port) # remove old input ports from the action. for port in self._action.getInputPorts(): if port not in newPorts: self._action.removePort(port) # remove old input ports from the action. for port in self._action.getInputPorts(): if port not in newPorts: self._action.removePort(port) # add new output ports to the action. ol = self.ui.outputLayout newPorts = [] for i in range(ol.count() - 1): pew = ol.itemAt(i).widget() pew.updatePort() port = pew.getPort() newPorts.append(port) if port.getAction() is None: self._action.addOutputPort(port) # remove old output ports from the action. for port in self._action.getOutputPorts(): if port not in newPorts: self._action.removePort(port) return QDialog.accept(self)
def accept(self) -> None: """ This method is called when the user clicks the "OK" button. It will validate all of the user's input and show error messages if any information is invalid. :emits: projectCreated if a project was successfully created :return: None :rtype: NoneType """ oldPath = self.ui.oldPathEdit.text() oldName = self.ui.oldNameEdit.text() oldDescription = self.ui.oldDescriptionEdit.toPlainText() oldExe = self.ui.oldAppEdit.text() newPath = self.ui.newPathEdit.text() newName = self.ui.newNameEdit.text() newDescription = self.ui.newDescriptionEdit.toPlainText() newExe = self.ui.newAppEdit.text() # clear error messages self.ui.oldErrorLabel.setText("") self.ui.newErrorLabel.setText("") # detect any errors oldErrors = [] newErrors = [] # check existing project for errors (as much as we can) if not self._oldProject: oldErrors.append("must select an existing project") # check new project details for errors if not newName: newErrors.append("new project must have a name") if not newDescription: newErrors.append("new project must have a description") if newExe != oldExe: newErrors.append( "new project must use the same executable as the old project") if not newPath: newErrors.append("Must specify location of new project") else: isAlreadyProject = False for file in os.listdir(newPath): if file[-4:] == ".fcl": isAlreadyProject = True break if isAlreadyProject: newErrors.append( "The selected project directory already belongs to a different project. Please select another." ) # if there are any errors, show them, then return. if len(newErrors) != 0: errMsg = "Errors:\n" for err in newErrors: errMsg += "\t" + err + "\n" self.ui.newErrorLabel.setText(errMsg) if len(oldErrors) != 0: errMsg = "Errors:\n" for err in oldErrors: errMsg += "\t" + err + "\n" self.ui.oldErrorLabel.setText(errMsg) # if there are no errors, create a new project, emit the projectCreated signal, and # call the super-class's accept method to perform the default behavior. if len(newErrors) == 0 and len(oldErrors) == 0: self._newProject.setName(newName) self._newProject.setDescription(newDescription) self._newProject.setProjectDir(newPath) self.projectCreated.emit(self._newProject) return QDialog.accept(self)
def accept(self): self.accepted.emit(self.ui.volumeInput.value(), self.ui.pHInput.value()) QDialog.accept(self)
class TutorialDialog(object): def __init__(self, parent, dp=None): self._dialog = QDialog(parent) self._dp = dp self._dialog.setWindowIcon(QIcon(':/images/icon.png')) self._ui = Ui_Dialog() self._ui.setupUi(self._dialog) self._current_index = 0 self._ui.slides.setCurrentIndex(self._current_index) self._slides_count = self._ui.slides.count() self._ui.next_button.clicked.connect(self._on_next_button_clicked) self._ui.prev_button.clicked.connect(self._on_prev_button_clicked) self._point_enabled_style = "background-color:#f9af61; " \ "border: 2px solid; " \ "border-radius: 3px; " \ "border-color:#f9af61;" self._point_disabled_style = "background-color:#cccccc; " \ "border: 2px solid; " \ "border-radius: 3px; " \ "border-color:#cccccc;" self._points = [self._ui.point] self._init_points() self._setup_buttons() self._set_labels_fonts() self._set_controls_font([self._ui.next_button, self._ui.prev_button]) self._slide_show = SlideShow(self._dialog, self._ui.slides) self._slide_show.current_index_changed.connect( self._on_current_index_changed) self._slide_show.clicked.connect(self._on_next_button_clicked) self._slide_show.key_pressed.connect(self._on_key_pressed) self._dialog.keyPressEvent = self._on_key_pressed def _on_next_button_clicked(self): if self._current_index + 1 >= self._slides_count: self._close() return self._slide_show.setCurrentIndex(self._current_index + 1) def _on_prev_button_clicked(self): if self._current_index - 1 < 0: return self._slide_show.setCurrentIndex(self._current_index - 1) def _on_key_pressed(self, ev): if ev.key() == Qt.Key_Left: self._on_prev_button_clicked() elif ev.key() == Qt.Key_Right: self._on_next_button_clicked() def _on_current_index_changed(self, new_index): self._current_index = new_index self._setup_buttons() def _setup_buttons(self): if self._current_index == 0: self._ui.prev_button.setDisabled(True) self._ui.prev_button.setStyleSheet( "border: 0; color:#ffffff; text-align:left;") else: self._ui.prev_button.setDisabled(False) self._ui.prev_button.setStyleSheet( "border: 0; color:#222222; text-align:left;") if self._current_index + 1 == self._slides_count: self._ui.next_button.setText(tr("GOT IT")) else: self._ui.next_button.setText(tr("NEXT")) self._setup_points() def _init_points(self): self._points[0].setText(' ') self._points[0].setFont(QFont("Noto Sans", 2)) for i in range(1, self._slides_count): new_point = QLabel() new_point.setText(' ') new_point.setFont(QFont("Noto Sans", 2)) new_point.setStyleSheet(self._point_disabled_style) self._points.append(new_point) self._ui.points_layout.addSpacing(8) self._ui.points_layout.addWidget(new_point) def _setup_points(self): for i, point in enumerate(self._points): style = self._point_enabled_style if i == self._current_index \ else self._point_disabled_style point.setStyleSheet(style) def _set_labels_fonts(self): self._set_controls_font(self._ui.slides.findChildren(QLabel)) def _set_controls_font(self, controls): if not self._dp or self._dp == 1: return for control in controls: font = control.font() font_size = font.pointSize() * self._dp control_font = QFont(font.family(), font_size, italic=font.italic()) control_font.setBold(font.bold()) control.setFont(control_font) def _close(self): self._slide_show.current_index_changed.disconnect( self._on_current_index_changed) self._dialog.accept() self._dialog.close() def show(self): logger.debug("Opening tutorial dialog") # Execute dialog self._dialog.exec_()
def accept(self) -> None: """ This method is called when the user clicks the "OK" button. It will validate all of the user's input and show error messages if any information is invalid. :emits: projectCreated if a project was successfully created :return: None :rtype: NoneType """ name = self.ui.project_name_edit.text() description = self.ui.description_edit.toPlainText() projectDir = self.ui.project_folder_edit.text() appExe = self.ui.executable_file_edit.text() # clear error message self.ui.error_label.setText("") # detect any errors errors = [] if not self.ui.project_name_edit.text(): errors.append("Need project name") if not self.ui.description_edit.toPlainText(): errors.append("Need project description") # Check for valid project directory. if not projectDir: errors.append("Need to select project folder") else: isAlreadyProject = False for file in os.listdir(projectDir): if file[-4:] == ".fcl": isAlreadyProject = True break if isAlreadyProject: errors.append( "The selected project directory already belongs to a different project. Please select another." ) # Check for valid target application executable if not appExe: errors.append("Need to select target application executable") else: if not isExecutable(appExe): errors.append("Target application must be an executable file.") elif not appBitnessMatches(appExe): pyBit = getPythonBitness() appBit = getExeBitness(appExe) errors.append( "{} bit Python cannot control {} bit application".format( pyBit, appBit)) # Check for valid framework frameworkOption = self._radioBtnGroup.checkedButton() framework = frameworkOption.text() if frameworkOption == self.ui.option_Other: framework = self.ui.other_edit.text() if not framework: errors.append("Must specify which framework is being used") # check for valid backend backendWidget = frameworkOption.parentWidget() backend = "" if isinstance(backendWidget, QGroupBox): backend = backendWidget.title() else: # TODO: Get best backend for target application. (using function from TGUIIL) pass # if there are any errors, show them, then return. if len(errors) != 0: errMsg = "Errors:\n" for err in errors: errMsg += "\t" + err + "\n" self.ui.error_label.setText(errMsg) return # if there are no errors, create a new project, emit the projectCreated signal, and # call the super-class's accept method to perform the default behavior. else: newProject = Project(name, description, appExe, backend, projectDir=projectDir) self.projectCreated.emit(newProject) return QDialog.accept(self)