class LoginScreenTest(default_code.DefaultCode): def setUp(self) -> None: super().setUp() self.model = MainModel() self.env_settings = QSettings() self.env_settings.setValue("Credentials/password", None) self.env_settings.setValue("Credentials/user", None) self.login_controller = LoginController(self.model, None) self.login_test = self.login_controller.login_screen def tearDown(self) -> None: super().tearDown() def test_default(self): self.assertEqual(self.login_test.get_user(), self.login_test.model.get_username()) self.assertEqual(self.login_test.get_psw(), "") @patch('src.model.network_model.NetworkModel.login', return_value=True) def test_login(self, mock_login): self.login_test.login_button.click() mock_login.assert_called_once() def test_login_fail_slot_exists(self): self.login_test.Sl_login_fail() @patch('src.model.network_model.NetworkModel.is_logged', return_value=True) def test_model_changed(self, mock_is_logged): self.login_test.Sl_model_changed() mock_is_logged.assert_called_once()
class Settings(object): def __init__(self, setting_path: str): self.setting_path = setting_path self.settings = QSettings(setting_path, QSettings.IniFormat) self.settings.setFallbacksEnabled(False) self.set_value(index_filter, []) def int_value(self, item: setting_item): return int(self.value(item)) def float_value(self, item: setting_item): return float(self.value(item)) def boolean_value(self, item: setting_item): value = self.value(item) return value.lower() == 'true' if isinstance(value, str) else bool(value) def list_value(self, item: setting_item): value = self.value(item) return value if isinstance(value, list) else [value] def str_value(self, item: setting_item): return str(self.value(item)) def value(self, item: setting_item): return self.settings.value(f'{item.section}/{item.key}', item.default_value) def set_value(self, item: setting_item, value: Any): self.settings.setValue(f'{item.section}/{item.key}', value)
def sortByColumn(self, col: int, order: Qt.SortOrder, save: bool = True) -> None: # type: ignore if save and col is not None and order is not None: settings = QSettings() settings.setValue('modlistSortColumn', col) settings.setValue('modlistSortOrder', 0 if order == Qt.AscendingOrder else 1) super().sortByColumn(col, order)
class Settings(object): def __init__(self) -> None: self._settings = QSettings('Evelyn Reminder', 'Evelyn Desktop') @staticmethod def _key( section: str, option: str ) -> str: return f'{section}/{option}' def set( self, section: str, option: str, value: Any ) -> None: key = self._key(section, option) self._settings.setValue(key, value) def get( self, section: str, option: str, default: Any = None, type_: Optional[Type] = None ) -> Any: # make key for QSettings key = self._key(section, option) # check not present if not self._settings.contains(key): return default # get value value = self._settings.value(key) # parse special values if type_ is bool: return self._parse_bool(value) # check type if not isinstance(value, type_): return default # done return value @staticmethod def _parse_bool( value: str ) -> Optional[bool]: if value == 'true': return True if value == 'false': return False return None
def _select_models_path(self): print('Selecting models path... ', end='', flush=True) settings = QSettings() models_path = QFileDialog.getExistingDirectory( parent=self, caption='Select models directory', dir=QStandardPaths.standardLocations( QStandardPaths.AppDataLocation).pop(), ) if models_path != '': settings.setValue(self._models_path_key, str(models_path)) self._models_path = Path(models_path) print(models_path) else: print('canceled')
async def headerChangedEvent(self) -> None: settings = QSettings() state = self.horizontalHeader().saveState() # call later to work around pyqt5 StopIteration exception asyncio.get_running_loop().call_later( 25 / 1000.0, lambda: settings.setValue('modlistHorizontalHeaderState', state))
def writeSettings(self): settings = QSettings('Trolltech', 'MDI Example') settings.setValue('pos', self.pos()) settings.setValue('size', self.size())
class MainWindow(QMainWindow): def __init__(self): """ Constructor """ self.receive_attempts = 0 self.settings = QSettings("gui.ini", QSettings.IniFormat) self.blurrer = None super(MainWindow, self).__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.restore() self.load_weights_options() self.ui.button_source.clicked.connect(self.button_source_clicked) self.ui.button_start.clicked.connect(self.button_start_clicked) self.ui.button_target.clicked.connect(self.button_target_clicked) self.ui.button_abort.clicked.connect(self.button_abort_clicked) self.ui.combo_box_weights.currentIndexChanged.connect( self.setup_blurrer) def load_weights_options(self): self.ui.combo_box_weights.clear() for net_path in glob("./weights/*.pt"): clean_name = os.path.splitext(os.path.basename(net_path))[0] self.ui.combo_box_weights.addItem(clean_name) self.setup_blurrer() def setup_blurrer(self): """ Create and connect a blurrer thread """ weights_name = self.ui.combo_box_weights.currentText() self.blurrer = VideoBlurrer(weights_name) self.blurrer.setMaximum.connect(self.setMaximumValue) self.blurrer.updateProgress.connect(self.setProgress) self.blurrer.finished.connect(self.blurrer_finished) self.blurrer.alert.connect(self.blurrer_alert) msg_box = QMessageBox() msg_box.setText(f"Successfully loaded {weights_name}.pt") msg_box.exec_() def blurrer_alert(self, message: str): """ Display blurrer messages in the GUI :param message: Message to be displayed """ msg_box = QMessageBox() msg_box.setText(message) msg_box.exec_() def button_abort_clicked(self): """ Callback for button_abort """ self.force_blurrer_quit() self.ui.progress.setValue(0) self.ui.button_start.setEnabled(True) self.ui.button_abort.setEnabled(False) self.setup_blurrer() def setProgress(self, value: int): """ Set progress bar's current progress :param value: progress to be set """ self.ui.progress.setValue(value) def setMaximumValue(self, value: int): """ Set progress bar's maximum value :param value: value to be set """ self.ui.progress.setMaximum(value) def button_start_clicked(self): """ Callback for button_start """ self.ui.button_abort.setEnabled(True) self.ui.button_start.setEnabled(False) # read inference size inference_size = int( self.ui.combo_box_scale.currentText()[:-1]) * 16 / 9 # ouch again # set up parameters parameters = { "input_path": self.ui.line_source.text(), "output_path": self.ui.line_target.text(), "blur_size": self.ui.spin_blur.value(), "blur_memory": self.ui.spin_memory.value(), "threshold": self.ui.double_spin_threshold.value(), "roi_multi": self.ui.double_spin_roimulti.value(), "inference_size": inference_size, "quality": self.ui.spin_quality.value() } if self.blurrer: self.blurrer.parameters = parameters self.blurrer.start() else: print("No blurrer object!") print("Blurrer started!") def button_source_clicked(self): """ Callback for button_source """ source_path, _ = QFileDialog.getOpenFileName( self, "Open Video", "", "Video Files (*.mkv *.avi *.mov *.mp4)") self.ui.line_source.setText(source_path) def button_target_clicked(self): """ Callback for button_target """ target_path, _ = QFileDialog.getSaveFileName(self, "Save Video", "", "Video Files (*.mkv)") self.ui.line_target.setText(target_path) def force_blurrer_quit(self): """ Force blurrer thread to quit """ if self.blurrer.isRunning(): self.blurrer.terminate() self.blurrer.wait() def restore(self): """ Restores relevent UI settings from ini file """ for name, obj in inspect.getmembers(self.ui): if isinstance(obj, QSpinBox): name = obj.objectName() value = self.settings.value(name) if value: obj.setValue(int(value)) if isinstance(obj, QDoubleSpinBox): name = obj.objectName() value = self.settings.value(name) if value: obj.setValue(float(value)) if isinstance(obj, QLineEdit): name = obj.objectName() value = self.settings.value(name) if value: obj.setText(value) if isinstance(obj, QRadioButton): name = obj.objectName() value = self.settings.value(name) if value and value == "true": # ouch... obj.setChecked(True) if isinstance(obj, QComboBox): name = obj.objectName() value = self.settings.value(name) if value: index = obj.findText(value) if index == -1: obj.insertItems(0, [value]) index = obj.findText(value) obj.setCurrentIndex(index) else: obj.setCurrentIndex(index) def blurrer_finished(self): """ Create a new blurrer, setup UI and notify the user """ msg_box = QMessageBox() if self.blurrer and self.blurrer.result["success"]: minutes = int(self.blurrer.result["elapsed_time"] // 60) seconds = round(self.blurrer.result["elapsed_time"] % 60) msg_box.setText( f"Video blurred successfully in {minutes} minutes and {seconds} seconds." ) else: msg_box.setText("Blurring resulted in errors.") msg_box.exec_() if not self.blurrer: self.setup_blurrer() self.ui.button_start.setEnabled(True) self.ui.button_abort.setEnabled(False) self.ui.progress.setValue(0) def save(self): """ Save all relevant UI parameters """ for name, obj in inspect.getmembers(self.ui): if isinstance(obj, QSpinBox): name = obj.objectName() value = obj.value() self.settings.setValue(name, value) if isinstance(obj, QDoubleSpinBox): name = obj.objectName() value = obj.value() self.settings.setValue(name, value) if isinstance(obj, QLineEdit): name = obj.objectName() value = obj.text() self.settings.setValue(name, value) if isinstance(obj, QRadioButton): name = obj.objectName() value = obj.isChecked() self.settings.setValue(name, value) if isinstance(obj, QComboBox): index = obj.currentIndex() # get current index from combobox value = obj.itemText(index) self.settings.setValue(name, value) def closeEvent(self, event): """ Overload closeEvent to shut down blurrer and save UI settings :param event: """ self.force_blurrer_quit() self.save() print("saved settings") QMainWindow.closeEvent(self, event)
class Snippets(QDialog): def __init__(self, context, parent=None): super(Snippets, self).__init__(parent) # Create widgets self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) self.title = QLabel(self.tr("Snippet Editor")) self.saveButton = QPushButton(self.tr("&Save")) self.saveButton.setShortcut(QKeySequence(self.tr("Ctrl+S"))) self.runButton = QPushButton(self.tr("&Run")) self.runButton.setShortcut(QKeySequence(self.tr("Ctrl+R"))) self.closeButton = QPushButton(self.tr("Close")) self.clearHotkeyButton = QPushButton(self.tr("Clear Hotkey")) self.setWindowTitle(self.title.text()) #self.newFolderButton = QPushButton("New Folder") self.browseButton = QPushButton("Browse Snippets") self.browseButton.setIcon(QIcon.fromTheme("edit-undo")) self.deleteSnippetButton = QPushButton("Delete") self.newSnippetButton = QPushButton("New Snippet") indentation = Settings().get_string("snippets.indentation") if Settings().get_bool("snippets.syntaxHighlight"): self.edit = QCodeEditor(SyntaxHighlighter=Pylighter, delimeter=indentation) else: self.edit = QCodeEditor(SyntaxHighlighter=None, delimeter=indentation) self.edit.setPlaceholderText("python code") self.resetting = False self.columns = 3 self.context = context self.keySequenceEdit = QKeySequenceEdit(self) self.currentHotkey = QKeySequence() self.currentHotkeyLabel = QLabel("") self.currentFileLabel = QLabel() self.currentFile = "" self.snippetDescription = QLineEdit() self.snippetDescription.setPlaceholderText("optional description") #Set Editbox Size font = getMonospaceFont(self) self.edit.setFont(font) font = QFontMetrics(font) self.edit.setTabStopDistance( 4 * font.horizontalAdvance(' ')) #TODO, replace with settings API #Files self.files = QFileSystemModel() self.files.setRootPath(snippetPath) self.files.setNameFilters(["*.py"]) #Tree self.tree = QTreeView() self.tree.setModel(self.files) self.tree.setSortingEnabled(True) self.tree.hideColumn(2) self.tree.sortByColumn(0, Qt.AscendingOrder) self.tree.setRootIndex(self.files.index(snippetPath)) for x in range(self.columns): #self.tree.resizeColumnToContents(x) self.tree.header().setSectionResizeMode( x, QHeaderView.ResizeToContents) treeLayout = QVBoxLayout() treeLayout.addWidget(self.tree) treeButtons = QHBoxLayout() #treeButtons.addWidget(self.newFolderButton) treeButtons.addWidget(self.browseButton) treeButtons.addWidget(self.newSnippetButton) treeButtons.addWidget(self.deleteSnippetButton) treeLayout.addLayout(treeButtons) treeWidget = QWidget() treeWidget.setLayout(treeLayout) # Create layout and add widgets buttons = QHBoxLayout() buttons.addWidget(self.clearHotkeyButton) buttons.addWidget(self.keySequenceEdit) buttons.addWidget(self.currentHotkeyLabel) buttons.addWidget(self.closeButton) buttons.addWidget(self.runButton) buttons.addWidget(self.saveButton) description = QHBoxLayout() description.addWidget(QLabel(self.tr("Description: "))) description.addWidget(self.snippetDescription) vlayoutWidget = QWidget() vlayout = QVBoxLayout() vlayout.addLayout(description) vlayout.addWidget(self.edit) vlayout.addLayout(buttons) vlayoutWidget.setLayout(vlayout) hsplitter = QSplitter() hsplitter.addWidget(treeWidget) hsplitter.addWidget(vlayoutWidget) hlayout = QHBoxLayout() hlayout.addWidget(hsplitter) self.showNormal() #Fixes bug that maximized windows are "stuck" #Because you can't trust QT to do the right thing here if (sys.platform == "darwin"): self.settings = QSettings("Vector35", "Snippet Editor") else: self.settings = QSettings("Vector 35", "Snippet Editor") if self.settings.contains("ui/snippeteditor/geometry"): self.restoreGeometry( self.settings.value("ui/snippeteditor/geometry")) else: self.edit.setMinimumWidth(80 * font.averageCharWidth()) self.edit.setMinimumHeight(30 * font.lineSpacing()) # Set dialog layout self.setLayout(hlayout) # Add signals self.saveButton.clicked.connect(self.save) self.closeButton.clicked.connect(self.close) self.runButton.clicked.connect(self.run) self.clearHotkeyButton.clicked.connect(self.clearHotkey) self.tree.selectionModel().selectionChanged.connect(self.selectFile) self.newSnippetButton.clicked.connect(self.newFileDialog) self.deleteSnippetButton.clicked.connect(self.deleteSnippet) #self.newFolderButton.clicked.connect(self.newFolder) self.browseButton.clicked.connect(self.browseSnippets) if self.settings.contains("ui/snippeteditor/selected"): selectedName = self.settings.value("ui/snippeteditor/selected") self.tree.selectionModel().select( self.files.index(selectedName), QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows) if self.tree.selectionModel().hasSelection(): self.selectFile(self.tree.selectionModel().selection(), None) self.edit.setFocus() cursor = self.edit.textCursor() cursor.setPosition(self.edit.document().characterCount() - 1) self.edit.setTextCursor(cursor) else: self.readOnly(True) else: self.readOnly(True) @staticmethod def registerAllSnippets(): for action in list( filter(lambda x: x.startswith("Snippets\\"), UIAction.getAllRegisteredActions())): if action == "Snippets\\Snippet Editor...": continue UIActionHandler.globalActions().unbindAction(action) Menu.mainMenu("Tools").removeAction(action) UIAction.unregisterAction(action) for snippet in includeWalk(snippetPath, ".py"): snippetKeys = None (snippetDescription, snippetKeys, snippetCode) = loadSnippetFromFile(snippet) actionText = actionFromSnippet(snippet, snippetDescription) if snippetCode: if snippetKeys == None: UIAction.registerAction(actionText) else: UIAction.registerAction(actionText, snippetKeys) UIActionHandler.globalActions().bindAction( actionText, UIAction(makeSnippetFunction(snippetCode, actionText))) Menu.mainMenu("Tools").addAction(actionText, "Snippets") def clearSelection(self): self.keySequenceEdit.clear() self.currentHotkey = QKeySequence() self.currentHotkeyLabel.setText("") self.currentFileLabel.setText("") self.snippetDescription.setText("") self.edit.clear() self.tree.clearSelection() self.currentFile = "" def askSave(self): return QMessageBox.question( self, self.tr("Save?"), self.tr("Do you want to save changes to {}?").format( self.currentFileLabel.text()), QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel) def reject(self): self.settings.setValue("ui/snippeteditor/geometry", self.saveGeometry()) if self.snippetChanged(): save = self.askSave() if save == QMessageBox.Yes: self.save() elif save == QMessageBox.No: self.loadSnippet() elif save == QMessageBox.Cancel: return self.accept() def browseSnippets(self): url = QUrl.fromLocalFile(snippetPath) QDesktopServices.openUrl(url) def newFolder(self): (folderName, ok) = QInputDialog.getText(self, self.tr("Folder Name"), self.tr("Folder Name: ")) if ok and folderName: index = self.tree.selectionModel().currentIndex() selection = self.files.filePath(index) if QFileInfo(selection).isDir(): QDir(selection).mkdir(folderName) else: QDir(snippetPath).mkdir(folderName) def selectFile(self, new, old): if (self.resetting): self.resetting = False return if len(new.indexes()) == 0: self.clearSelection() self.currentFile = "" self.readOnly(True) return newSelection = self.files.filePath(new.indexes()[0]) self.settings.setValue("ui/snippeteditor/selected", newSelection) if QFileInfo(newSelection).isDir(): self.readOnly(True) self.clearSelection() self.currentFile = "" return if old and old.length() > 0: oldSelection = self.files.filePath(old.indexes()[0]) if not QFileInfo(oldSelection).isDir() and self.snippetChanged(): save = self.askSave() if save == QMessageBox.Yes: self.save() elif save == QMessageBox.No: pass elif save == QMessageBox.Cancel: self.resetting = True self.tree.selectionModel().select( old, QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows) return False self.currentFile = newSelection self.loadSnippet() def loadSnippet(self): self.currentFileLabel.setText(QFileInfo(self.currentFile).baseName()) (snippetDescription, snippetKeys, snippetCode) = loadSnippetFromFile(self.currentFile) self.snippetDescription.setText( snippetDescription ) if snippetDescription else self.snippetDescription.setText("") self.keySequenceEdit.setKeySequence( snippetKeys ) if snippetKeys else self.keySequenceEdit.setKeySequence( QKeySequence("")) self.edit.setPlainText( snippetCode) if snippetCode else self.edit.setPlainText("") self.readOnly(False) def newFileDialog(self): (snippetName, ok) = QInputDialog.getText(self, self.tr("Snippet Name"), self.tr("Snippet Name: "), flags=self.windowFlags()) if ok and snippetName: if not snippetName.endswith(".py"): snippetName += ".py" index = self.tree.selectionModel().currentIndex() selection = self.files.filePath(index) if QFileInfo(selection).isDir(): path = os.path.join(selection, snippetName) else: path = os.path.join(snippetPath, snippetName) self.readOnly(False) open(path, "w").close() self.tree.setCurrentIndex(self.files.index(path)) log_debug("Snippet %s created." % snippetName) def readOnly(self, flag): self.keySequenceEdit.setEnabled(not flag) self.snippetDescription.setReadOnly(flag) self.edit.setReadOnly(flag) if flag: self.snippetDescription.setDisabled(True) self.edit.setDisabled(True) else: self.snippetDescription.setEnabled(True) self.edit.setEnabled(True) def deleteSnippet(self): selection = self.tree.selectedIndexes()[::self.columns][ 0] #treeview returns each selected element in the row snippetName = self.files.fileName(selection) question = QMessageBox.question( self, self.tr("Confirm"), self.tr("Confirm deletion: ") + snippetName) if (question == QMessageBox.StandardButton.Yes): log_debug("Deleting snippet %s." % snippetName) self.clearSelection() self.files.remove(selection) self.registerAllSnippets() def snippetChanged(self): if (self.currentFile == "" or QFileInfo(self.currentFile).isDir()): return False (snippetDescription, snippetKeys, snippetCode) = loadSnippetFromFile(self.currentFile) if snippetKeys == None and not self.keySequenceEdit.keySequence( ).isEmpty(): return True if snippetKeys != None and snippetKeys != self.keySequenceEdit.keySequence( ).toString(): return True return self.edit.toPlainText() != snippetCode or \ self.snippetDescription.text() != snippetDescription def save(self): log_debug("Saving snippet %s" % self.currentFile) outputSnippet = codecs.open(self.currentFile, "w", "utf-8") outputSnippet.write("#" + self.snippetDescription.text() + "\n") outputSnippet.write("#" + self.keySequenceEdit.keySequence().toString() + "\n") outputSnippet.write(self.edit.toPlainText()) outputSnippet.close() self.registerAllSnippets() def run(self): if self.context == None: log_warn("Cannot run snippets outside of the UI at this time.") return if self.snippetChanged(): self.save() actionText = actionFromSnippet(self.currentFile, self.snippetDescription.text()) UIActionHandler.globalActions().executeAction(actionText, self.context) log_debug("Saving snippet %s" % self.currentFile) outputSnippet = codecs.open(self.currentFile, "w", "utf-8") outputSnippet.write("#" + self.snippetDescription.text() + "\n") outputSnippet.write("#" + self.keySequenceEdit.keySequence().toString() + "\n") outputSnippet.write(self.edit.toPlainText()) outputSnippet.close() self.registerAllSnippets() def clearHotkey(self): self.keySequenceEdit.clear()
def saveEvent(self) -> None: settings = QSettings() settings.setValue('settingsWindowGeometry', self.saveGeometry()) settings.setValue('gamePath', self.gamePath.text()) settings.setValue('configPath', self.configPath.text()) settings.setValue('scriptMergerPath', self.scriptMergerPath.text()) settings.setValue('nexusAPIKey', self.nexusAPIKey.text()) settings.setValue('nexusGetInfo', str(self.nexusGetInfo.isChecked())) settings.setValue('nexusCheckUpdates', str(self.nexusCheckUpdates.isChecked())) settings.setValue('nexusCheckClipboard', str(self.nexusCheckClipboard.isChecked())) settings.setValue('debugOutput', str(self.debugOutput.isChecked())) settings.setValue('unhideOutput', str(self.unhideOutput.isChecked())) self.close()
def setupMenu(self) -> None: self.setMenuBar(QMenuBar(self)) settings = QSettings() # mods menu menuMods: QMenu = self.menuBar().addMenu('&Mods') downIcon = QIcon(str(getRuntimePath('resources/icons/down.ico'))) gearIcon = QIcon(str(getRuntimePath('resources/icons/gear.ico'))) dirsIcon = QIcon(str( getRuntimePath('resources/icons/open-folder.ico'))) colrIcon = QIcon( str(getRuntimePath('resources/icons/color-circle.ico'))) smilIcon = QIcon(str(getRuntimePath('resources/icons/smile.ico'))) actionAddModFromFile = menuMods.addAction('&Add Mods') actionAddModFromFile.triggered.connect(self.showAddModFromFileDialog) actionAddModFromFolder = menuMods.addAction('Add u&npacked Mod') actionAddModFromFolder.triggered.connect( self.showAddModFromFolderDialog) actionDownloadMod = menuMods.addAction('&Download Mod') actionDownloadMod.setIcon(downIcon) actionDownloadMod.triggered.connect(self.showDownloadModDialog) menuMods.addSeparator() actionGetInfo = menuMods.addAction('Update Mod de&tails') actionGetInfo.setIcon(downIcon) actionGetInfo.triggered.connect(self.showGetInfoDialog) actionGetUpdates = menuMods.addAction('Check for Mod &updates') actionGetUpdates.setIcon(downIcon) actionGetUpdates.triggered.connect(self.showGetUpdatesDialog) menuMods.addSeparator() actionExport = menuMods.addAction('&Export Modlist') actionExport.triggered.connect(self.showExportDialog) menuMods.aboutToShow.connect(lambda: [ actionDownloadMod.setDisabled(not str(settings.value('nexusAPIKey'))), actionGetInfo.setDisabled( not str(settings.value('nexusAPIKey')) or \ not len(self.model) or \ not self.mainwidget.modlist.selectionModel().hasSelection()), actionGetUpdates.setDisabled( not str(settings.value('nexusAPIKey')) or \ not len(self.model) or \ not self.mainwidget.modlist.selectionModel().hasSelection()), actionExport.setDisabled(not len(self.model)) ]) # view menu menuView: QMenu = self.menuBar().addMenu('&View') showSummary = menuView.addAction('Show &Summary') showSummary.setCheckable(True) showSummary.setChecked(settings.value('showSummary', 'True') == 'True') showSummary.triggered.connect(lambda checked: [ settings.setValue('showSummary', str(checked)), self.mainwidget.summary.setVisible(checked) ]) menuView.addSeparator() toggleHighlightNewest = menuView.addAction('Highlight &Newest') toggleHighlightNewest.setCheckable(True) toggleHighlightNewest.setChecked( settings.value('highlightNewest', 'True') == 'True') toggleHighlightNewest.triggered.connect(lambda checked: [ settings.setValue('highlightNewest', str(checked)), self.model.updateCallbacks.fire(self.model) ]) iconHighlightNewest = QPixmap(256, 256) iconHighlightNewest.fill(Qt.transparent) painter = QPainter(iconHighlightNewest) painter.setBrush(QBrush(QColor(222, 255, 222))) painter.drawEllipse(10, 10, 236, 236) toggleHighlightNewest.setIcon(QIcon(iconHighlightNewest)) painter.end() toggleHighlightRecent = menuView.addAction('Highlight &Recent') toggleHighlightRecent.setCheckable(True) toggleHighlightRecent.setChecked( settings.value('highlightRecent', 'True') == 'True') toggleHighlightRecent.triggered.connect(lambda checked: [ settings.setValue('highlightRecent', str(checked)), self.model.updateCallbacks.fire(self.model) ]) iconHighlightRecent = QPixmap(256, 256) iconHighlightRecent.fill(Qt.transparent) painter = QPainter(iconHighlightRecent) painter.setBrush(QBrush(QColor(222, 226, 255))) painter.drawEllipse(10, 10, 236, 236) toggleHighlightRecent.setIcon(QIcon(iconHighlightRecent)) painter.end() toggleHighlightUnmanaged = menuView.addAction('Highlight &Unmanaged') toggleHighlightUnmanaged.setCheckable(True) toggleHighlightUnmanaged.setChecked( settings.value('highlightUnmanaged', 'True') == 'True') toggleHighlightUnmanaged.triggered.connect(lambda checked: [ settings.setValue('highlightUnmanaged', str(checked)), self.model.updateCallbacks.fire(self.model) ]) iconHighlightUnmanaged = QPixmap(256, 256) iconHighlightUnmanaged.fill(Qt.transparent) painter = QPainter(iconHighlightUnmanaged) painter.setBrush(QBrush(QColor(250, 220, 220))) painter.drawEllipse(10, 10, 236, 236) toggleHighlightUnmanaged.setIcon(QIcon(iconHighlightUnmanaged)) painter.end() toggleHighlightDisabled = menuView.addAction('Highlight &Disabled') toggleHighlightDisabled.setCheckable(True) toggleHighlightDisabled.setChecked( settings.value('highlightDisabled', 'True') == 'True') toggleHighlightDisabled.triggered.connect(lambda checked: [ settings.setValue('highlightDisabled', str(checked)), self.model.updateCallbacks.fire(self.model) ]) iconHighlightDisabled = QPixmap(256, 256) iconHighlightDisabled.fill(Qt.transparent) painter = QPainter(iconHighlightDisabled) painter.setBrush(QBrush(QColor(230, 230, 230))) painter.drawEllipse(10, 10, 236, 236) toggleHighlightDisabled.setIcon(QIcon(iconHighlightDisabled)) painter.end() menuView.addSeparator() toggleColors = menuView.addAction('&Colored Icons') toggleColors.setCheckable(True) toggleColors.setChecked(settings.value('iconColors', 'True') == 'True') toggleColors.triggered.connect(lambda checked: [ settings.setValue('iconColors', str(checked)), self.mainwidget.modlist.listmodel.setIcons(), self.model.updateCallbacks.fire(self.model) ]) toggleColors.setIcon(colrIcon) menuView.addSeparator() toggleCompact = menuView.addAction('Compact &Mode') toggleCompact.setCheckable(True) toggleCompact.setChecked( settings.value('compactMode', 'False') == 'True') toggleCompact.triggered.connect(lambda checked: [ settings.setValue('compactMode', str(checked)), self.mainwidget.modlist.setSectionSize(checked) ]) # settings menu menuSettings: QMenu = self.menuBar().addMenu('&Tools') actionSettings = menuSettings.addAction('&Settings') actionSettings.setIcon(gearIcon) actionSettings.triggered.connect(self.showSettingsDialog) menuSettings.addSeparator() actionOpenGameDirectory = menuSettings.addAction( 'Open &Game directory') actionOpenGameDirectory.setIcon(dirsIcon) actionOpenGameDirectory.triggered.connect( lambda: util.openDirectory(self.model.gamepath)) actionOpenConfigDirectory = menuSettings.addAction( 'Open &Config directory') actionOpenConfigDirectory.setIcon(dirsIcon) actionOpenConfigDirectory.triggered.connect( lambda: util.openDirectory(self.model.configpath)) # info menu menuInfo: QMenu = self.menuBar().addMenu('&Info') actionFeedback = menuInfo.addAction('Send &Feedback') actionFeedback.setIcon(smilIcon) actionFeedback.triggered.connect( lambda: QDesktopServices.openUrl(QUrl(w3modmanager.URL_ISSUES))) menuInfo.addSeparator() actionAbout = menuInfo.addAction('&About') actionAbout.setIcon(QIcon.fromTheme('document-open')) actionAbout.triggered.connect(self.showAboutDialog)
class SettingsModel(QObject): Sg_model_changed = Signal() Sg_model_path_changed = Signal() __model = None __create_key = object() @classmethod def get_instance(cls): if SettingsModel.__model is None: SettingsModel.__model = SettingsModel(cls.__create_key) return SettingsModel.__model def __init__(self, create_key): assert (create_key == SettingsModel.__create_key), \ "SettingsModel objects must be created using SettingsModel.get_instance()" super(SettingsModel, self).__init__(None) self.env_settings = QSettings() def get_policy(self) -> Policy: return Policy(settings.get_policy()) def set_policy(self, new_policy: Policy) -> None: settings.update_policy(new_policy.value) self.Sg_model_changed.emit() def get_path(self) -> Optional[str]: return self.env_settings.value("sync_path") def set_path(self, new_path: str) -> None: self.env_settings.setValue("sync_path", new_path) self.env_settings.sync() self.Sg_model_changed.emit() self.Sg_model_path_changed.emit() def set_sync_time(self, new_sync_time: int) -> None: settings.update_sync_time(new_sync_time) self.Sg_model_changed.emit() def get_sync_time(self) -> int: return settings.get_sync_time() def get_quota_disco_raw(self) -> float: """Ritorna il valore grezzo""" return settings.get_quota_disco() def get_quota_disco(self) -> str: """Ritorna il valore con la sua unità adatta""" return self.convert_size(settings.get_quota_disco()) def set_quota_disco(self, new_quota: bitmath.Byte) -> None: # TODO: Il controllo non dovremmo farlo nel controller? folder_size = bitmath.parse_string(self.convert_size(self.get_size())) free_disk = bitmath.parse_string( self.convert_size(self.get_free_disk())) # Controllo che la nuova quota sia minore dello spazio disponibile nell'hdd # e maggiore dello spazio utilizzato dalla cartella corrente if folder_size <= new_quota <= free_disk: settings.update_quota_disco(str(new_quota.value)) self.Sg_model_changed.emit() def get_free_disk(self) -> int: mem = psutil.disk_usage('/') return mem.free @staticmethod def convert_size(size_bytes: int) -> str: if size_bytes == 0: return "0 B" size_name = ("Byte", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB") i = int(math.floor(math.log(size_bytes, 1024))) p = math.pow(1024, i) s = round(size_bytes / p, 2) return "%s %s" % (s, size_name[i]) def get_quota_libera(self) -> float: return self.get_quota_disco_raw() - self.get_size() def get_size(self) -> int: total_size = 0 if not self.get_path(): return 0 for dirpath, dirnames, filenames in os.walk(self.get_path()): for f in filenames: fp = os.path.join(dirpath, f) # skip if it is symbolic link if not os.path.islink(fp): total_size += os.path.getsize(fp) return total_size def get_sync_list(self) -> list: return settings.get_sync_list() def is_id_in_sync_list(self, id: str) -> bool: return id in settings.get_sync_list() def add_id_to_sync_list(self, id: str) -> None: """Aggiungi id a whitelist""" id_list = settings.get_sync_list() if not self.is_id_in_sync_list(id): id_list.append(id) settings.update_sync_list(id_list) self.Sg_model_changed.emit() def remove_id_from_sync_list(self, id: str) -> None: """Rimuovi id da whitelist""" id_list = settings.get_sync_list() if self.is_id_in_sync_list(id): id_list.remove(id) settings.update_sync_list(id_list) self.Sg_model_changed.emit()
def closeEvent(self, event: QCloseEvent) -> None: settings = QSettings() settings.setValue('mainWindowGeometry', self.saveGeometry()) settings.setValue('mainWindowState', self.saveState())
class MainWindow(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setWindowIcon(QtGui.QIcon('icon.ico')) self.font_id = QFontDatabase.addApplicationFont( "Roboto/Roboto-Bold.ttf") if self.font_id == -1: QMessageBox.warning(self, "Внимание", "Пользовательский шрифт не был найден!") self.setupUi(self) self.curFile = '' self.setCurrentFile('') self.createStatusBar() self.textEdit.document().contentsChanged.connect( self.documentWasModified) self.setCurrentFile('') self.settings = QSettings('Matewriter', 'Matewriter') self.exit_action.triggered.connect(QApplication.quit) self.save_action.triggered.connect(self.save) self.open_action.triggered.connect(self.open) self.newfile_action.triggered.connect(self.newFile) self.saveas_action.triggered.connect(self.saveAs) self.open_action.setShortcut('Ctrl+O') self.newfile_action.setShortcut('Ctrl+N') self.save_action.setShortcut('Ctrl+S') # Конфиги окна windowScreenGeometry = self.settings.value("windowScreenGeometry") windowScreenState = self.settings.value("windowScreenState") if windowScreenGeometry: self.restoreGeometry(windowScreenGeometry) else: self.resize(600) if windowScreenState: self.restoreState(windowScreenState) def closeEvent(self, event): self.settings.setValue("windowScreenGeometry", self.saveGeometry()) self.settings.setValue("windowScreenState", self.saveState()) if self.maybeSave(): self.writeSettings() event.accept() else: event.ignore() def newFile(self): if self.maybeSave(): self.textEdit.clear() self.setCurrentFile('') def open(self): if self.maybeSave(): fileName, _ = QFileDialog.getOpenFileName(self) if fileName: self.loadFile(fileName) def save(self): if self.curFile: return self.saveFile(self.curFile) return self.saveAs() def saveAs(self): fileName, _ = QFileDialog.getSaveFileName(self) if fileName: return self.saveFile(fileName) return False def documentWasModified(self): self.setWindowModified(self.textEdit.document().isModified()) def createStatusBar(self): self.statusBar().showMessage("Ready") def readSettings(self): settings = QSettings("MateWriter") pos = settings.value("pos", QPoint(200, 200)) size = settings.value("size", QSize(400, 400)) self.resize(size) self.move(pos) def writeSettings(self): settings = QSettings("MateWriter") settings.setValue("pos", self.pos()) settings.setValue("size", self.size()) def maybeSave(self): if self.textEdit.document().isModified(): ret = QMessageBox.warning( self, "MateWriter", "The document has been modified.\nDo you want to save " "your changes?", QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel) if ret == QMessageBox.Save: return self.save() if ret == QMessageBox.Cancel: return False return True def loadFile(self, fileName): file = QFile(fileName) if not file.open(QFile.ReadOnly | QFile.Text): QMessageBox.warning( self, "MateWriter", "Cannot read file %s:\n%s." % (fileName, file.errorString())) return inf = QTextStream(file) QApplication.setOverrideCursor(Qt.WaitCursor) self.textEdit.setPlainText(inf.readAll()) QApplication.restoreOverrideCursor() self.setCurrentFile(fileName) self.statusBar().showMessage("File loaded", 2000) def saveFile(self, fileName): file = QFile(fileName) if not file.open(QFile.WriteOnly | QFile.Text): QMessageBox.warning( self, "MateWriter", "Cannot write file %s:\n%s." % (fileName, file.errorString())) return False outf = QTextStream(file) QApplication.setOverrideCursor(Qt.WaitCursor) outf << self.textEdit.toPlainText() QApplication.restoreOverrideCursor() self.setCurrentFile(fileName) self.statusBar().showMessage("File saved", 2000) return True def setCurrentFile(self, fileName): self.curFile = fileName self.textEdit.document().setModified(False) self.setWindowModified(False) if self.curFile: shownName = self.strippedName(self.curFile) else: shownName = 'untitled.txt' self.setWindowTitle(" %s[*] - MateWriter" % shownName) def strippedName(self, fullFileName): return QFileInfo(fullFileName).fileName()
def saveSettings(self): settings = QSettings() settings.setValue("delay", self.doubleSpinBoxDelay.value())
class QtSetting(QtWidgets.QDialog, Ui_Setting): def __init__(self, owner): super(self.__class__, self).__init__() Ui_Setting.__init__(self) self.setupUi(self) self.settings = QSettings('config.ini', QSettings.IniFormat) # self.setWindowModality(Qt.ApplicationModal) self.mainSize = QSize(1500, 1100) self.bookSize = QSize(900, 1020) self.readSize = QSize(1120, 1020) self.userId = "" self.passwd = "" self.gpuInfos = [] self.translate = QTranslator() def show(self): self.LoadSetting() super(self.__class__, self).show() def exec(self): self.LoadSetting() super(self.__class__, self).exec() def GetSettingV(self, key, defV=None): v = self.settings.value(key) try: if v: if isinstance(defV, int): if v == "true" or v == "True": return 1 elif v == "false" or v == "False": return 0 return int(v) elif isinstance(defV, float): return float(v) else: return v return defV except Exception as es: Log.Error(es) return v def LoadSetting(self): x = self.settings.value("MainSize_x") y = self.settings.value("MainSize_y") if x and y: self.mainSize = QSize(int(x), int(y)) v = self.settings.value("Waifu2x/Encode") if v: config.Encode = int(v) # v = self.settings.value("Waifu2x/LogIndex") # if v: # config.LogIndex = int(v) # self.logBox.setCurrentIndex(config.LogIndex) Log.UpdateLoggingLevel() v = self.settings.value("Waifu2x/Open") config.SelectEncodeGpu = self.GetSettingV("Waifu2x/SelectEncodeGpu", "") config.UseCpuNum = self.GetSettingV("Waifu2x/UseCpuNum", 0) config.Language = self.GetSettingV("Waifu2x/Language", 0) self.encodeSelect.setCurrentIndex(0) self.languageSelect.setCurrentIndex(config.Language) for index in range(self.encodeSelect.count()): if config.SelectEncodeGpu == self.encodeSelect.itemText(index): self.encodeSelect.setCurrentIndex(index) return def ExitSaveSetting(self, mainQsize): self.settings.setValue("MainSize_x", mainQsize.width()) self.settings.setValue("MainSize_y", mainQsize.height()) def SaveSetting(self): config.Encode = self.encodeSelect.currentIndex() config.UseCpuNum = int(self.threadSelect.currentIndex()) # config.LogIndex = int(self.logBox.currentIndex()) config.Language = int(self.languageSelect.currentIndex()) config.SelectEncodeGpu = self.encodeSelect.currentText() self.settings.setValue("Waifu2x/Encode", config.Encode) # self.settings.setValue("Waifu2x/Thread", config.Waifu2xThread) # self.settings.setValue("Waifu2x/Scale", config.Scale) # self.settings.setValue("Waifu2x/Model", config.Model) self.settings.setValue("Waifu2x/SelectEncodeGpu", config.SelectEncodeGpu) self.settings.setValue("Waifu2x/UseCpuNum", config.UseCpuNum) # self.settings.setValue("Waifu2x/LogIndex", config.LogIndex) self.settings.setValue("Waifu2x/Language", config.Language) Log.UpdateLoggingLevel() # QtWidgets.QMessageBox.information(self, '保存成功', "成功", QtWidgets.QMessageBox.Yes) QtBubbleLabel.ShowMsgEx(self, "Save Success") self.close() def SetGpuInfos(self, gpuInfo, cpuNum): self.gpuInfos = gpuInfo config.EncodeGpu = config.SelectEncodeGpu if not self.gpuInfos: config.EncodeGpu = "CPU" config.Encode = -1 self.encodeSelect.addItem(config.EncodeGpu) self.encodeSelect.setCurrentIndex(0) return if not config.EncodeGpu or (config.EncodeGpu != "CPU" and config.EncodeGpu not in self.gpuInfos): config.EncodeGpu = self.gpuInfos[0] config.Encode = 0 index = 0 for info in self.gpuInfos: self.encodeSelect.addItem(info) if info == config.EncodeGpu: self.encodeSelect.setCurrentIndex(index) config.Encode = index index += 1 self.encodeSelect.addItem("CPU") if config.EncodeGpu == "CPU": config.Encode = -1 self.encodeSelect.setCurrentIndex(index) if config.UseCpuNum > cpuNum: config.UseCpuNum = cpuNum for i in range(cpuNum): self.threadSelect.addItem(str(i + 1)) self.threadSelect.setCurrentIndex(config.UseCpuNum) Log.Info("waifu2x GPU: " + str(self.gpuInfos) + ",select: " + str(config.EncodeGpu) + ",use cpu num: " + str(config.UseCpuNum)) return def GetGpuName(self): return config.EncodeGpu # index = config.Encode # if index >= len(self.gpuInfos) or index < 0: # return "GPU" # return self.gpuInfos[index] def SetLanguage(self, app, owner): language = config.Language # Auto if language == 0: locale = QLocale.system().name() Log.Info("Init translate {}".format(locale)) if locale[:3].lower() == "zh_": if locale.lower() == "zh_cn": language = 1 else: language = 2 else: language = 3 if language == 1: app.removeTranslator(self.translate) elif language == 2: self.translate.load(":/tr_hk.qm") app.installTranslator(self.translate) else: self.translate.load(":/tr_en.qm") app.installTranslator(self.translate) owner.RetranslateUi()
class NetworkModel(QObject, Api, metaclass=NetworkMeta): logger = logging.getLogger("NetworkModel") __model = None status: Status = Status.Ok Sg_model_changed = Signal() Sg_logout = Signal() # error signals Sg_login_failed = Signal() Sg_connection_failed = Signal() Sg_server_failed = Signal() __create_key = object() @classmethod def get_instance(cls): if NetworkModel.__model is None: NetworkModel.__model = NetworkModel(cls.__create_key) return NetworkModel.__model def __init__(self, create_key): assert (create_key == NetworkModel.__create_key), \ "NetworkModel objects must be created using NetworkModel.get_instance()" super(NetworkModel, self).__init__(None) super(Api, self).__init__() self.api_implementation = ApiImplementation() self.env_settings = QSettings() self.lock = Lock() def raise_for_status(self): if self.status == Status.Error: raise APIException() @APIExceptionsHandler def login(self, user: str = "", password: str = "") -> None: NetworkModel.logger.info("try to login...") user = user if user else self.env_settings.value("Credentials/user") password = password if password else self.env_settings.value( "Credentials/password") self.api_implementation.login(user, password) NetworkModel.logger.info("login successful") # save to Qsettings NetworkModel.logger.info("saving credentials") self.env_settings.setValue("Credentials/user", user) self.env_settings.setValue("Credentials/password", password) self.env_settings.sync() self.Sg_model_changed.emit() @APIExceptionsHandler @RetryLogin def get_info_from_email(self) -> dict[str, str]: self.lock.acquire() try: return self.api_implementation.get_info_from_email() finally: self.lock.release() @APIExceptionsHandler @RetryLogin def get_user_id(self) -> str: self.lock.acquire() try: return self.api_implementation.get_user_id() finally: self.lock.release() @APIExceptionsHandler @RetryLogin def is_logged(self) -> bool: return self.api_implementation.is_logged() def get_username(self) -> str: user = self.env_settings.value("Credentials/user") return user if user else "" def get_password(self) -> str: password = self.env_settings.value("Credentials/password") return password if password else "" @APIExceptionsHandler @RetryLogin def logout(self) -> bool: self.lock.acquire() try: if self.api_implementation.logout(): self.message = "" self.env_settings.setValue("Credentials/user", None) self.env_settings.setValue("Credentials/password", None) return True return False finally: self.lock.release() @RetryLogin def download_node(self, node: TreeNode, path_folder: str, quota_libera: float) -> dict: remote_node = self.api_implementation.get_content_from_node( node.get_payload().id) file_size = remote_node["getNode"]["size"] # Se ho spazio procedo al download if quota_libera > file_size: result = self.api_implementation.download_node(node, path_folder) return { "node_name": node.get_name(), "result": result, "type": "network_error" if not result else "" } return { "node_name": node.get_name(), "result": False, "type": "space_error" } @RetryLogin def upload_node(self, node: TreeNode, parent_folder_id: str) -> None: self.api_implementation.upload_node(node, parent_folder_id) @RetryLogin def delete_node(self, node_id: str) -> None: self.lock.acquire() try: self.api_implementation.delete_node(node_id) finally: self.lock.release() @RetryLogin def get_content_from_node(self, node_id: str = "LOCAL_ROOT") -> str: self.lock.acquire() try: return self.api_implementation.get_content_from_node(node_id) finally: self.lock.release() @RetryLogin def create_folder(self, folder_name: str, parent_folder_id: str = "LOCAL_ROOT") -> str: self.lock.acquire() try: return self.api_implementation.create_folder( folder_name, parent_folder_id) finally: self.lock.release()
env_settings = QSettings() # env_settings.setValue("sync_path", None) # env_settings.setValue("Credentials/user", None) # env_settings.setValue("Credentials/password", None) # Controlliamo se l'utente ha già settato il PATH della cartella check_path = env_settings.value("sync_path") if not check_path or not os.path.isdir(check_path): dialog = QFileDialog() dialog.setFileMode(QFileDialog.Directory) dialog.setViewMode(QFileDialog.Detail) # provare anche .List dialog.setOption(QFileDialog.ShowDirsOnly) dialog.setOption(QFileDialog.DontResolveSymlinks) # L'utente non ha selezionato la cartella if not dialog.exec(): env_settings.setValue("sync_path", None) app.quit() sync_path = dialog.selectedFiles() if len(sync_path) == 1: env_settings.setValue("sync_path", sync_path[0]) env_settings.sync() print("Nuova directory: " + env_settings.value("sync_path")) model = MainModel() controller = MainController(app, model) login_controller = LoginController(model, controller) sys.exit(app.exec())
def write_settings(self): settings = QSettings() settings.beginGroup(SETTINGS_MAIN_SECTION) settings.setValue(SETTINGS_USE_CUSTOM_JAVA, self.ui.customJavaRadio.isChecked()) settings.setValue(SETTINGS_CUSTOM_JAVA_PATH, self.ui.customJavaPathEdit.text()) settings.setValue(SETTINGS_USE_CUSTOM_PLANTUML, self.ui.customPlantUmlRadio.isChecked()) settings.setValue(SETTINGS_CUSTOM_PLANTUML_PATH, self.ui.customPlantUmlEdit.text()) settings.setValue(SETTINGS_USE_CUSTOM_GRAPHVIZ, self.ui.customGraphvizRadio.isChecked()) settings.setValue(SETTINGS_CUSTOM_GRAPHVIZ_PATH, self.ui.customGraphvizEdit.text()) settings.endGroup()
def writeSettings(self): settings = QSettings("MateWriter") settings.setValue("pos", self.pos()) settings.setValue("size", self.size())
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.art_scene = QGraphicsScene(self) self.art_scene.addText('Open an image file.') self.ui.art_view.setScene(self.art_scene) self.symbols_scene = QGraphicsScene(self) self.ui.symbols_view.setScene(self.symbols_scene) self.ui.action_exit.triggered.connect(self.close) self.ui.action_open_art.triggered.connect(self.open_image) self.ui.action_open_words.triggered.connect(self.open_words) self.ui.action_save.triggered.connect(self.save_pdf) self.ui.action_save_png.triggered.connect(self.save_png) self.ui.action_shuffle.triggered.connect(self.shuffle) self.ui.action_sort.triggered.connect(self.sort) self.ui.rows.valueChanged.connect(self.on_options_changed) self.ui.columns.valueChanged.connect(self.on_options_changed) self.ui.word_clues_radio.toggled.connect(self.on_options_changed) self.ui.symbol_clues_radio.toggled.connect(self.on_options_changed) self.word_layout = QGridLayout(self.ui.word_content) self.ui.word_scroll.setWidgetResizable(True) self.word_labels: typing.Dict[str, QLabel] = {} self.word_shuffler = WordShuffler([]) self.clues = None self.pixmap = self.scaled_pixmap = self.mini_pixmap = None self.sliced_pixmap_item: typing.Optional[QGraphicsPixmapItem] = None self.sliced_image: typing.Optional[QImage] = None self.selection_grid: typing.Optional[SelectionGrid] = None self.cells = [] self.art_shuffler: typing.Optional[ArtShuffler] = None self.symbols_source_pixmap_item: typing.Optional[ QGraphicsPixmapItem] = None self.symbols_pixmap_item: typing.Optional[QGraphicsPixmapItem] = None self.symbols_image: typing.Optional[QImage] = None self.symbols_shuffler: typing.Optional[ArtShuffler] = None self.selected_row: typing.Optional[int] = None self.selected_column: typing.Optional[int] = None self.settings = QSettings() self.image_path: typing.Optional[str] = self.settings.value( 'image_path') self.words_path: typing.Optional[str] = self.settings.value( 'words_path') self.dirty_letters = set() self.timer = QTimer() self.timer.setInterval(500) self.timer.setSingleShot(True) # noinspection PyUnresolvedReferences self.timer.timeout.connect(self.on_dirty) self.row_count = self.column_count = 0 self.clue_type = ClueType.words self.ui.rows.setValue(self.settings.value('row_count', 6, int)) self.ui.columns.setValue(self.settings.value('column_count', 4, int)) clue_type_name = self.settings.value('clue_type', ClueType.words.name) try: clue_type = ClueType[clue_type_name] except KeyError: clue_type = ClueType.words if clue_type == ClueType.words: self.ui.word_clues_radio.setChecked(True) else: self.ui.symbol_clues_radio.setChecked(True) self.row_clues: typing.List[QPixmap] = [] self.column_clues: typing.List[QPixmap] = [] self.on_options_changed() def on_dirty(self): for letter in self.dirty_letters: self.word_labels[letter].setText( self.word_shuffler.make_display(letter)) self.settings.setValue(f'word_{letter}', self.word_shuffler[letter]) if self.dirty_letters: self.clues = self.word_shuffler.make_clues() self.art_shuffler.clues = dict(self.clues) self.dirty_letters.clear() self.on_selection_moved() if self.pixmap is not None: x, y, width, height = self.get_selected_fraction() self.settings.setValue('x', x) self.settings.setValue('y', y) self.settings.setValue('width', width) self.settings.setValue('height', height) new_rows = self.ui.rows.value() new_columns = self.ui.columns.value() if self.ui.word_clues_radio.isChecked(): new_clue_type = ClueType.words else: new_clue_type = ClueType.symbols if (new_rows, new_columns, new_clue_type) == (self.row_count, self.column_count, self.clue_type): return self.settings.setValue('row_count', new_rows) self.settings.setValue('column_count', new_columns) self.settings.setValue('clue_type', new_clue_type.name) self.row_count, self.column_count = new_rows, new_columns self.clue_type = new_clue_type word_count = (self.row_count * self.column_count) while self.word_layout.count(): layout_item = self.word_layout.takeAt(0) layout_item.widget().deleteLater() self.word_labels.clear() self.row_clues.clear() self.column_clues.clear() if self.image_path is not None: self.load_image(self.image_path) if self.words_path is not None: self.load_words(self.words_path) letters = [chr(65 + i) for i in range(word_count)] if self.word_shuffler.needs_blank: letters.insert(0, '') word_fields = {} for i, letter in enumerate(letters): word_field = QLineEdit() self.word_layout.addWidget(word_field, i, 0) # noinspection PyUnresolvedReferences word_field.textEdited.connect(partial(self.on_word_edited, letter)) word_label = QLabel() self.word_layout.addWidget(word_label, i, 1) self.word_labels[letter] = word_label word_fields[letter] = word_field for i, letter in enumerate(letters): word = self.settings.value(f'word_{letter}', '') self.word_shuffler[letter] = word self.dirty_letters.add(letter) word_fields[letter].setText(word) def on_options_changed(self, *_): self.timer.start() def shuffle(self): self.clues = self.word_shuffler.make_clues() if self.art_shuffler is not None: self.art_shuffler.shuffle() self.on_selection_moved() def sort(self): if self.art_shuffler is not None: self.art_shuffler.sort() self.on_selection_moved() def open_words(self): word_filter = 'Text files (*.txt)' if self.words_path is None: words_folder = None else: words_folder = str(Path(self.words_path).parent) file_name, _ = QFileDialog.getOpenFileName(self, "Open a words file.", dir=words_folder, filter=word_filter) if not file_name: return self.settings.setValue('words_path', file_name) self.load_words(file_name) def load_words(self, words_path): with open(words_path) as f: choice = 0 if choice == 0: self.word_shuffler = WordShuffler(f) else: self.word_shuffler = WordStripper(f) def open_image(self): formats = QImageReader.supportedImageFormats() patterns = (f'*.{fmt.data().decode()}' for fmt in formats) image_filter = f'Images ({" ".join(patterns)})' if self.image_path is None: image_folder = None else: image_folder = str(Path(self.image_path).parent) file_name, _ = QFileDialog.getOpenFileName(self, "Open an image file.", dir=image_folder, filter=image_filter) if not file_name: return self.settings.setValue('image_path', file_name) self.load_image(file_name) def load_image(self, image_path): self.pixmap = QPixmap(image_path) if self.pixmap.isNull(): self.pixmap = None self.image_path = image_path self.scale_image() def scale_image(self): if self.pixmap is None: return if self.selection_grid is None: x = self.settings.value('x', 0.0, float) y = self.settings.value('y', 0.0, float) width = self.settings.value('width', 1.0, float) height = self.settings.value('height', 1.0, float) else: x, y, width, height = self.get_selected_fraction() self.art_scene.clear() self.cells.clear() view_size = self.ui.art_view.maximumViewportSize() if view_size.width() == 0: return self.art_scene.setSceneRect(0, 0, view_size.width(), view_size.height()) display_size = QSize(view_size.width() * 0.99 / 2, view_size.height() * 0.99) self.scaled_pixmap = self.pixmap.scaled( display_size, aspectMode=Qt.AspectRatioMode.KeepAspectRatio) self.art_scene.addPixmap(self.scaled_pixmap) scaled_size = self.scaled_pixmap.size() self.selection_grid = SelectionGrid(scaled_size.width() * x, scaled_size.height() * y, scaled_size.width() * width, scaled_size.height() * height, row_count=self.row_count, column_count=self.column_count) self.selection_grid.on_moved = self.on_selection_moved self.art_scene.addItem(self.selection_grid) self.sliced_image = QImage(display_size, QImage.Format.Format_ARGB32_Premultiplied) self.check_clues() self.art_shuffler = ArtShuffler(self.selection_grid.row_count, self.selection_grid.column_count, self.sliced_image, QRect(0, 0, display_size.width(), display_size.height()), clues=self.clues, row_clues=self.row_clues, column_clues=self.column_clues) self.sliced_pixmap_item = self.art_scene.addPixmap( QPixmap.fromImage(self.sliced_image)) self.sliced_pixmap_item.setPos(display_size.width(), 0) self.symbols_scene.clear() self.symbols_source_pixmap_item = self.symbols_scene.addPixmap( self.scaled_pixmap) self.symbols_image = QImage(display_size, QImage.Format.Format_ARGB32_Premultiplied) if self.symbols_shuffler is not None: selected_row = self.symbols_shuffler.selected_row selected_column = self.symbols_shuffler.selected_column else: selected_row = 0 selected_column = None self.symbols_shuffler = ArtShuffler(self.selection_grid.row_count, self.selection_grid.column_count, self.symbols_image, QRect(0, 0, display_size.width(), display_size.height()), row_clues=self.row_clues, column_clues=self.column_clues) self.symbols_shuffler.selected_row = selected_row self.symbols_shuffler.selected_column = selected_column self.symbols_pixmap_item = ClickablePixmapItem( QPixmap.fromImage(self.symbols_image)) self.symbols_pixmap_item.on_click = self.on_symbols_clicked self.symbols_scene.addItem(self.symbols_pixmap_item) self.symbols_pixmap_item.setPos(display_size.width(), 0) self.on_selection_moved() def on_symbols_clicked(self, event: QGraphicsSceneMouseEvent): self.symbols_scene.clearSelection() self.symbols_shuffler.select_clue(event.pos().toPoint()) self.on_selection_moved() def on_word_edited(self, letter, word): self.word_shuffler[letter] = word self.dirty_letters.add(letter) self.timer.start() def get_selected_fraction(self): selection_rect = self.selection_grid.rect() selection_pos = self.selection_grid.pos() size = self.scaled_pixmap.size() x = (selection_pos.x() + selection_rect.x()) / size.width() width = selection_rect.width() / size.width() y = (selection_pos.y() + selection_rect.y()) / size.height() height = selection_rect.height() / size.height() return x, y, width, height def on_selection_moved(self): selected_pixmap = self.get_selected_pixmap() self.art_shuffler.draw(selected_pixmap) self.sliced_pixmap_item.setPixmap(QPixmap.fromImage(self.sliced_image)) selected_pixmap = self.get_selected_pixmap() cell_width = (selected_pixmap.width() / self.selection_grid.column_count) cell_height = (selected_pixmap.height() / self.selection_grid.row_count) self.row_clues.clear() self.column_clues.clear() for i in range(self.selection_grid.row_count): clue_image = selected_pixmap.copy(0, i * cell_height, cell_width, cell_height) self.row_clues.append(clue_image) for j in range(self.selection_grid.column_count): clue_image = selected_pixmap.copy(j * cell_width, 0, cell_width, cell_height) self.column_clues.append(clue_image) self.symbols_shuffler.row_clues = self.row_clues self.symbols_shuffler.column_clues = self.column_clues self.symbols_shuffler.draw_grid(selected_pixmap) self.symbols_pixmap_item.setPixmap( QPixmap.fromImage(self.symbols_image)) self.timer.start() def get_selected_pixmap(self) -> QPixmap: x, y, width, height = self.get_selected_fraction() original_size = self.pixmap.size() selected_pixmap = self.pixmap.copy(x * original_size.width(), y * original_size.height(), width * original_size.width(), height * original_size.height()) return selected_pixmap def resizeEvent(self, event: QResizeEvent): super().resizeEvent(event) self.scale_image() def save_pdf(self): pdf_folder = self.settings.value('pdf_folder') file_name, _ = QFileDialog.getSaveFileName(self, "Save a PDF file.", dir=pdf_folder, filter='Documents (*.pdf)') if not file_name: return self.settings.setValue('pdf_folder', os.path.dirname(file_name)) writer = QPdfWriter(file_name) writer.setPageSize(QPageSize(QPageSize.Letter)) writer.setTitle('Sliced Art Puzzle') writer.setCreator('Don Kirkby') self.paint_puzzle(writer) def save_png(self): pdf_folder = self.settings.value('pdf_folder') file_name, _ = QFileDialog.getSaveFileName(self, "Save an image file.", dir=pdf_folder, filter='Images (*.png)') if not file_name: return writer = QPixmap(1000, 2000) self.paint_puzzle(writer) writer.save(file_name) self.settings.setValue('pdf_folder', os.path.dirname(file_name)) def paint_puzzle(self, writer: QPaintDevice): self.check_clues() painter = QPainter(writer) try: print_shuffler = ArtShuffler(self.art_shuffler.rows, self.art_shuffler.cols, writer, QRect(0, 0, writer.width(), round(writer.height() / 2)), clues=self.clues, row_clues=self.row_clues, column_clues=self.column_clues) print_shuffler.cells = self.art_shuffler.cells[:] print_shuffler.is_shuffled = self.art_shuffler.is_shuffled selected_pixmap = self.get_selected_pixmap() print_shuffler.draw(selected_pixmap, painter) print_shuffler.rect.moveTop(writer.height() / 2) print_shuffler.draw_grid(selected_pixmap, painter) finally: painter.end() def check_clues(self): if self.clue_type == ClueType.words: if self.clues is None: self.clues = self.word_shuffler.make_clues() self.row_clues.clear() self.column_clues.clear() else: self.clues = None
def main(gamePath: Optional[str] = None, configPath: Optional[str] = None, startupMode: StartupMode = StartupMode.Main) -> NoReturn: from w3modmanager.util.util import getRuntimePath from w3modmanager.core.model import Model from w3modmanager.core.errors import OtherInstanceError, InvalidGamePath, InvalidConfigPath from w3modmanager.ui.graphical.mainwindow import MainWindow from w3modmanager.domain.web.nexus import closeSession from w3modmanager.domain.system.permissions import \ getWritePermissions, setWritePermissions from PySide6.QtCore import Qt, QSettings from PySide6.QtWidgets import QApplication, QMessageBox from PySide6.QtGui import QIcon, QPalette, QFont from qasync import QEventLoop QApplication.setOrganizationName(w3modmanager.ORG_NAME) QApplication.setOrganizationDomain(w3modmanager.ORG_URL) QApplication.setApplicationName(w3modmanager.TITLE) QApplication.setApplicationVersion(w3modmanager.VERSION) QApplication.setApplicationDisplayName('') QApplication.setAttribute(Qt.AA_NativeWindows) app = QApplication(sys.argv) app.setStyleSheet(''' Link { text-decoration: none; } ''') eventloop = QEventLoop(app) asyncio.set_event_loop(eventloop) palette = QPalette(QApplication.palette()) palette.setColor(QPalette.Link, Qt.red) palette.setColor(QPalette.LinkVisited, Qt.red) palette.setColor(QPalette.PlaceholderText, Qt.gray) app.setPalette(palette) font = QFont('Segoe UI') font.setStyleHint(QFont.System) font.setWeight(QFont.Normal) font.setStyleStrategy(QFont.PreferDevice) font.setPointSize(9) app.setFont(font) icon = QIcon() icon.addFile(str(getRuntimePath('resources/icons/w3b.ico'))) app.setWindowIcon(icon) pool = ThreadPoolExecutor() asyncio.get_running_loop().set_default_executor(pool) # configure startup overrides settings = QSettings() if gamePath: settings.setValue('gamePath', gamePath) if configPath: settings.setValue('configPath', configPath) if startupMode == StartupMode.About: MainWindow.showAboutDialog(None).exec_() sys.exit() if startupMode == StartupMode.Settings: MainWindow.showSettingsDialog(None).exec_() sys.exit() exception_hook_set = False def createModel(ignorelock: bool = False) -> Model: nonlocal settings return Model( Path(str(settings.value('gamePath'))), Path(str(settings.value('configPath'))), Path( appdirs.user_data_dir(w3modmanager.NAME, w3modmanager.ORG_NAME)), ignorelock) try: # try to initialize the mod management model try: model = createModel() # if another instance is already open, inform and ask to open anyway except OtherInstanceError as e: if MainWindow.showOtherInstanceDialog( None).exec_() == QMessageBox.Yes: model = createModel(True) else: raise e # if game path or config path is invalid or not set, # show a special settings dialog and retry except (InvalidGamePath, InvalidConfigPath): MainWindow.showSettingsDialog(None, True).exec_() model = createModel() # check for write access to the game and config directories for path in ( model.gamepath, model.configpath, model.cachepath, ): if not getWritePermissions(path): if MainWindow.showInvalidPermissionsDialog(None, path).exec_() != QMessageBox.Yes \ or not setWritePermissions(path): raise PermissionError(f'Not enough permissions for {path}') window = MainWindow(model) app.setActiveWindow(window) def show_exception_hook(exctype, value, tb) -> None: # noqa nonlocal window MainWindow.showCritcalErrorDialog( window, value, ''.join(traceback.format_exception(exctype, value, tb))).exec_() exception_hook(exctype, value, tb) sys.excepthook = show_exception_hook exception_hook_set = True with eventloop: status = eventloop.run_forever() eventloop.run_until_complete(closeSession()) sys.exit(status) except OtherInstanceError as e: sys.exit(f'error: {str(e)}') except (InvalidGamePath, InvalidConfigPath) as e: MainWindow.showInvalidConfigErrorDialog(None).exec_() sys.exit(f'error: {str(e)}') except PermissionError as e: MainWindow.showInvalidPermissionsErrorDialog(None).exec_() sys.exit(f'error: {str(e)}') except Exception as e: if not exception_hook_set: MainWindow.showCritcalErrorDialog(None, str(e)).exec_() raise e sys.exit()
# import persepolis_setting # persepolis is using QSettings for saving windows size and windows # position and program settings. persepolis_setting = QSettings('persepolis_download_manager', 'persepolis') persepolis_setting.beginGroup('settings') default_setting_dict = returnDefaultSettings() # this loop is checking values in persepolis_setting . if value is not # valid then value replaced by default_setting_dict value for key in default_setting_dict.keys(): setting_value = persepolis_setting.value(key, default_setting_dict[key]) persepolis_setting.setValue(key, setting_value) # download files is downloading in temporary folder(download_path_temp) and then they will be moved to user download folder(download_path) after completion. # Check that mount point is available of not! if not(os.path.exists(persepolis_setting.value('download_path_temp'))): persepolis_setting.setValue('download_path_temp', default_setting_dict['download_path_temp']) if not(os.path.exists(persepolis_setting.value('download_path'))): persepolis_setting.setValue('download_path', default_setting_dict['download_path']) persepolis_setting.sync() # this section creates temporary download folder and download folder and # download sub folders if they did not existed. download_path_temp = persepolis_setting.value('download_path_temp')