def update_mru_menu_items(mru_file_list: List[str], mru_menu: QMenu, file_open_action: Callable[[str], None], current_file_name: str, clear_all_actions: Callable[[None], None] = None): # look for a separator below the item list act_separator = None act_clear = None for act in mru_menu.actions(): if act.isSeparator(): act_separator = act elif act.data() == 'clearall': act_clear = act if act_clear and act_separator: break if not act_separator: act_separator = mru_menu.addSeparator() if not act_clear: if clear_all_actions: act_clear = mru_menu.addAction('Clear all') act_clear.setData('clearall') act_clear.triggered.connect(clear_all_actions) act_clear.setVisible(len(mru_file_list) > 0) else: act_clear.setVisible(clear_all_actions is not None and len(mru_file_list) > 0) action_idx = -1 home_dir = os.path.expanduser('~') for idx, file_name in enumerate(mru_file_list): if file_name.find(home_dir) == 0: short_file_name = '~' + file_name[len(home_dir):] else: short_file_name = file_name action_idx += 1 if action_idx < len(mru_menu.actions()) and not mru_menu.actions()[action_idx].isSeparator(): act = mru_menu.actions()[action_idx] act.setText(short_file_name) else: act = QAction(short_file_name, mru_menu) mru_menu.insertAction(act_separator, act) act.triggered.disconnect() act.triggered.connect(partial(file_open_action, file_name)) act.setVisible(True) act.setCheckable(True) if file_name == current_file_name: act.setChecked(True) else: act.setChecked(False) # hide all unused actions action_idx += 1 for idx in range(action_idx, len(mru_menu.actions())): act = mru_menu.actions()[idx] if not (act.isSeparator() or act.data() == 'clearall'): act.setVisible(False) mru_menu.update()
def trv_models_action_click_slot(self, action: QAction): model = self.treeview_models.model() if action.text() == self.treeview_models.CTX_MENU_ADD_REPOSITORY_ACTION: form = NewRepoForm() if form.exec_() == QDialog.Accepted: repository = form.result self.add_repository(repository) elif action.text() == self.treeview_models.CTX_MENU_UPDATE_REPO_ACTION: index: QModelIndex = action.data() node: CustomNode = index.internalPointer() hub: HubVO = node.tag if hub and hub.id: model.removeChild(index) self.update_repository(hub) elif action.text() == self.treeview_models.CTX_MENU_AUTO_LABEL_ACTION: index: QModelIndex = action.data() node: CustomNode = index.internalPointer() parent_node = node.parent # repo repo, model_name = parent_node.get_data(0), node.get_data(0) self.predict_annotations_using_pytorch_thub_model(repo, model_name) if action.text() == self.treeview_models.CTX_MENU_DELETE_REPO_ACTION: reply = QMessageBox.question(self, 'Delete Repository', "Are you sure?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.No: return index: QModelIndex = action.data() node: CustomNode = index.internalPointer() hub: HubVO = node.tag if hub: self._hub_dao.delete(hub.id) # TODO: this method should be call from other thread model.removeChild(index)
def _file_menu(self, action: QAction): if action.data()['action'] == 'download': remote_path, name = action.data()['path'], action.data()['name'] local_path = QFileDialog.getSaveFileName(caption='Save File', directory=name)[0] if local_path: self._conn.file_from_remote(remote_path, local_path) elif action.data()['action'] == 'delete': remote_path, remote_name, item = action.data( )['path'], action.data()['name'], action.data()['item'] dialog = QMessageBox() dialog.setText( "Are you sure you want to delete '{}'? This cannot be undone". format(remote_name)) dialog.setStandardButtons(QMessageBox.Cancel | QMessageBox.Yes) dialog.setDefaultButton(QMessageBox.Cancel) res = dialog.exec() if res == QMessageBox.Cancel: return self._conn.delete_file(remote_path) item.parent().takeRow(item.row()) elif action.data()['action'] == 'rename': item = action.data()['item'] if item.index() == self.rootIndex(): self.parent_dir() self.edit(item.index())
def fnProcesaSeleccionRats(self, action: QAction): def llenarTabla(msg): self.fillTableWidget(self.pandasUtils.tempDf) self.overlay.killAndHide() self.ratsSeleccionados[str(action.data())] = action.isChecked() print(f"Fn procesa seleccion Rat {action} {self.ratsSeleccionados}") if (sum([1 for rat, v in self.ratsSeleccionados.items() if v is True]) == 0): action.setChecked(True) self.ratsSeleccionados[str(action.data())] = action.isChecked() self.fnMuestraCantidadEnRats() self.fnAplicaFiltrosDfOk(llenarTabla)
def _process_image_adjust_oper(self, action: QAction): curr_action = action.data() k = self._number_of_clusters_spin.value() @work_exception def do_work(): if curr_action == "reset": self._reset_sliders() self.image_viewer.reset_viewer() elif curr_action == "equalize_histo": self.image_viewer.equalize_histogram() elif curr_action == "correct_l": self.image_viewer.correct_lightness() elif curr_action == "clustering": self.image_viewer.clusterize(k=k) return None, None @gui_exception def done_work(result): out, err = result if err: return self._loading_dialog.hide() self.image_viewer.update_viewer() self._loading_dialog.show() worker = Worker(do_work) worker.signals.result.connect(done_work) self._thread_pool.start(worker)
class ToolBar(QToolBar): back_button_clicked = pyqtSignal(name="backClicked") forward_button_clicked = pyqtSignal(name="forwardClicked") stop_reload_button_clicked = pyqtSignal(int, name="stopReloadClicked") address_changed = pyqtSignal(QUrl, name="addressChanged") dom_tree_viewer_clicked = pyqtSignal(name="domTreeViewerClicked") def __init__(self): QToolBar.__init__(self) self.setMovable(False) self.toggleViewAction().setEnabled(False) self.le = QLineEdit() self.init_ui() def init_ui(self): back_action = QAction(self) back_action.setShortcut(QKeySequence(Qt.Key_Back)) back_action.setIcon(QIcon("images/go-previous.png")) self.addAction(back_action) back_action.triggered.connect(self.back_button_clicked) forward_action = QAction(self) forward_action.setShortcut(QKeySequence(Qt.Key_Forward)) forward_action.setIcon(QIcon("images/go-next.png")) self.addAction(forward_action) forward_action.triggered.connect(self.forward_button_clicked) self.stop_reload_action = QAction(self) self.stop_reload_action.setShortcut(QKeySequence(Qt.Key_F5)) self.stop_reload_action.setIcon(QIcon("images/view-refresh.png")) self.stop_reload_action.setData(QWebEnginePage.Reload) self.addAction(self.stop_reload_action) self.stop_reload_action.triggered.connect( lambda: self.stop_reload_button_clicked.emit( QWebEnginePage.WebAction(self.stop_reload_action.data()))) fav_action = QAction(self) self.le.addAction(fav_action, QLineEdit.LeadingPosition) self.le.setClearButtonEnabled(True) self.addWidget(self.le) self.le.editingFinished.connect( lambda: self.address_changed.emit(QUrl(self.le.text()))) self.addSeparator() self.dom_tree_viewer = QAction(self) self.dom_tree_viewer.setIcon(QIcon("images/view-dom_tree.png")) self.dom_tree_viewer.triggered.connect(self.dom_tree_viewer_clicked) self.addAction(self.dom_tree_viewer) @pyqtSlot(bool, name="changeStopReload") def change_stop_reload(self, state): if state: self.stop_reload_action.setShortcut(QKeySequence(Qt.Key_F5)) self.stop_reload_action.setIcon(QIcon("images/view-refresh.png")) self.stop_reload_action.setData(QWebEnginePage.Reload) else: self.stop_reload_action.setShortcut(QKeySequence(Qt.Key_Escape)) self.stop_reload_action.setIcon(QIcon("images/process-stop.png")) self.stop_reload_action.setData(QWebEnginePage.Stop)
def trv_models_action_click_slot(self, action: QAction): if action.text() == self.treeview_models.CTX_MENU_NEW_DATASET_ACTION: self.add_repository() elif action.text() == self.treeview_models.CTX_MENU_AUTO_LABEL_ACTION: current_node = action.data() # model name parent_node = current_node.parent # repo repo, model = parent_node.get_data(0), current_node.get_data(0) self.autolabel(repo, model)
class Toolbar(QToolBar): back_button_clicked = pyqtSignal(name="backButtonClicked") forward_button_clicked = pyqtSignal(name="forwardButtonClicked") stop_reload_button_clicked = pyqtSignal(int, name="stopReloadButtonClicked") address_changed = pyqtSignal(str, name="addressChanged") def __init__(self): QToolBar.__init__(self) self.setMovable(False) self.toggleViewAction().setEnabled(False) self.setIconSize(QSize(24, 24)) # 뒤로가기 버튼 self.back_action = QAction(self) self.back_action.setShortcut(QKeySequence(Qt.Key_Back)) self.back_action.setIcon(QIcon("assets/svg/left.svg")) self.addAction(self.back_action) self.back_action.triggered.connect(self.back_button_clicked) # 앞으로가기 버튼 self.forward_action = QAction(self) self.forward_action.setShortcut(QKeySequence(Qt.Key_Forward)) self.forward_action.setIcon(QIcon("assets/svg/right.svg")) self.addAction(self.forward_action) self.forward_action.triggered.connect(self.forward_button_clicked) # 새로고침 취소 액션 self.stop_reload_action = QAction(self) self.stop_reload_action.setShortcut(QKeySequence(Qt.Key_F5)) self.stop_reload_action.setIcon(QIcon("assets/svg/reload.svg")) self.stop_reload_action.setData(QWebEnginePage.Reload) self.addAction(self.stop_reload_action) self.stop_reload_action.triggered.connect( lambda: self.stop_reload_button_clicked.emit( QWebEnginePage.WebAction(self.stop_reload_action.data()))) # 주소창 self.le = QLineEdit() fav_action = QAction(self) self.le.addAction(fav_action, QLineEdit.LeadingPosition) self.le.setClearButtonEnabled(True) self.le.setContentsMargins(8, 8, 8, 8) self.addWidget(self.le) self.le.editingFinished.connect( lambda: self.address_changed.emit(self.le.text())) @pyqtSlot(bool, name="changeStopReload") def change_stop_reload(self, state): if state: self.stop_reload_action.setShortcut(QKeySequence(Qt.Key_F5)) self.stop_reload_action.setIcon(QIcon("assets/svg/reload.svg")) self.stop_reload_action.setData(QWebEnginePage.Reload) else: self.stop_reload_action.setShortcut(QKeySequence(Qt.Key_Escape)) self.stop_reload_action.setIcon(QIcon("assets/svg/close.svg")) self.stop_reload_action.setData(QWebEnginePage.Stop)
def change_gadget(self, tool: QAction): if isinstance(tool, QAction): tool = tool.data() self.workbench_view.set_gadget(tool) if tool == ToolsToolBar.BrowserImageTool: self.browser_result() self.browser_result_signal.emit(True) else: if self._current_tool == ToolsToolBar.BrowserImageTool: self.end_browser() self.browser_result_signal.emit(False) self._current_tool = tool
def on_men_connections_triggered(self, action: QtWidgets.QAction): """A connection is selected in the men_connections menu.""" if not helper.cm.pyload_connect(action.data()): QtWidgets.QMessageBox.critical( self, self.tr("Error"), self.tr( "Can not connect to RevPi XML-RPC Service! \n\n" "This could have the following reasons: The RevPi is not " "online, the XML-RPC service is not running / bind to " "localhost or the ACL permission is not set for your " "IP!!!\n\nRun 'sudo revpipyload_secure_installation' on " "Revolution Pi to setup this function!" ) )
def trv_labels_action_click_slot(self, action: QAction): model = self.treeview_labels.model() if action.text() == self.treeview_labels.CTX_MENU_ADD_LABEL: form = NewLabelForm() if form.exec_() == QDialog.Accepted: label_vo: LabelVO = form.result label_vo.dataset = self.source.dataset label_vo = self._labels_dao.save(label_vo) self.treeview_labels.add_row(label_vo) elif action.text() == self.treeview_labels.CTX_MENU_DELETE_LABEL: index: QModelIndex = action.data() if index: label_vo = model.index(index.row(), 2).data() self._labels_dao.delete(label_vo.id) self.viewer.remove_annotations_by_label(label_vo.name) model.removeRow(index.row())
def trv_labels_action_click_slot(self, action: QAction): model = self.treeview_labels.model() if action.text() == self.treeview_labels.CTX_MENU_ADD_LABEL: form = NewLabelForm() if form.exec_() == QDialog.Accepted: label_vo: LabelVO = form.result label_vo.dataset = self.tag.dataset label_vo = self._labels_dao.save(label_vo) self.treeview_labels.add_row(label_vo) elif action.text() == self.treeview_labels.CTX_MENU_DELETE_LABEL: reply = QMessageBox.question(self, 'Delete Label', "Are you sure?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.No: return index: QModelIndex = action.data() if index: label_vo = model.index(index.row(), 2).data() self._labels_dao.delete(label_vo.id) # TODO: this method should be call from other thread self.image_viewer.remove_annotations_by_label(label_vo.name) model.removeRow(index.row())
class ContentPresenter(object): """ UI Logic for main window :param Controller ramsis_core: Ramsis core """ def __init__(self, ramsis_core, ui): self.ramsis_core = ramsis_core self.ui = ui self.fc_tree_model = None self.context_menu = QMenu(self.ui.forecastTreeView) self.run_action = QAction('Run now', self.context_menu) self.run_action.triggered.connect(self.action_run_now) self.context_menu.addAction(self.run_action) self.ui.forecastTreeView.setContextMenuPolicy(Qt.CustomContextMenu) self.ui.forecastTreeView.customContextMenuRequested.connect( self.on_context_menu_requested ) self.current_scenario = None # Presenters for the main window components tab_classes = [ModelTabPresenter, HazardTabPresenter, GeneralTabPresenter, SettingsTabPresenter] self.tab_presenters = [Klass(self.ui) for Klass in tab_classes] self.time_line_presenter = TimeLinePresenter(self.ui, ramsis_core) # Essential signals from the core self.ramsis_core.engine.job_status_update.\ connect(self.on_job_status_update) # Display update methods for individual window components with # increasing granularity (i.e. top level methods at the top) def present_current_project(self): project = self.ramsis_core.project self._observe_project_changes(project) self.fc_tree_model = ForecastTreeModel(project.forecast_set) self.ui.forecastTreeView.setModel(self.fc_tree_model) # observe selection changes fc_selection = self.ui.forecastTreeView.selectionModel() fc_selection.selectionChanged.connect(self.on_fc_selection_change) def _observe_project_changes(self, project): # Make sure we get updated on project changes project.will_close.connect(self.on_project_will_close) project.project_time_changed.connect(self.on_project_time_change) project.forecast_set.forecasts_changed.connect( self.on_forecasts_change) def _refresh_forecast_list(self): """ Refresh the list of forecasts """ self.fc_tree_model.refresh() def _clear_all(self): for tab_presenter in self.tab_presenters: tab_presenter.present_scenario(None) def _refresh_scenario_status(self): """ Show the overall status of the currently selected forecast """ scenario = self.current_scenario if scenario is None: msg = 'No scenario selected' color = STATUS_COLOR_OTHER errors = False else: errors = scenario.has_errors() status = scenario.summary_status fc = scenario.forecast_input.forecast dt = fc.forecast_time - self.ramsis_core.project.project_time if status == Scenario.PENDING: h = int(dt.total_seconds() / 3600) m = int((dt.total_seconds() % 3600) / 60) if dt.total_seconds() > 0: pre = 'Scenario scheduled to run in ' color = STATUS_COLOR_PENDING else: pre = 'Scenario overdue for ' color = STATUS_COLOR_OTHER if h > 24: msg = pre + '{} days'.format(h / 24) elif h > 0: msg = pre + '{} hours {} minutes'.format(h, m) else: msg = pre + '{} minutes'.format(m) elif status == Scenario.RUNNING: color = STATUS_COLOR_RUNNING msg = 'Scenario is currently being computed' elif status == Scenario.COMPLETE: color = STATUS_COLOR_COMPLETE msg = 'Scenario computation complete' else: color = STATUS_COLOR_OTHER msg = 'Scenario computation partially complete' if errors: msg += ' (with errors)' color = STATUS_COLOR_ERROR text_color = 'black' if color == STATUS_COLOR_OTHER else 'white' self.ui.fcStatusLabel.setText(msg) self.ui.statusAreaWidget.setStyleSheet('background-color: {};' 'color: {};' .format(color, text_color)) # Context menu actions def action_run_now(self, checked): self.ramsis_core.engine.run(datetime.utcnow(), self.run_action.data()) # Handlers for signals from the UI def on_project_will_close(self, _): self._clear_all() fc_selection = self.ui.forecastTreeView.selectionModel() fc_selection.selectionChanged.disconnect(self.on_fc_selection_change) self.ui.forecastTreeView.setModel(None) self.fc_tree_model = None def on_project_time_change(self, t): pass def on_forecasts_change(self, _): self._refresh_forecast_list() def on_fc_selection_change(self, selection): idx = selection.indexes()[0] if idx.parent().isValid(): forecast_idx = idx.parent().row() scenario_idx = idx.row() else: forecast_idx = idx.row() scenario_idx = 0 try: forecast_set = self.fc_tree_model.forecast_set forecast = forecast_set.forecasts[forecast_idx] self.current_scenario = forecast.input.scenarios[scenario_idx] except IndexError: self.current_scenario = None for tab_presenter in self.tab_presenters: tab_presenter.present_scenario(self.current_scenario) self._refresh_scenario_status() def on_context_menu_requested(self, pos): if self.fc_tree_model is None: return idx = self.ui.forecastTreeView.indexAt(pos) node = idx.internalPointer() if isinstance(node, ForecastNode): forecast = node.item self.run_action.setData(forecast) self.context_menu.exec_(self.ui.forecastTreeView.mapToGlobal(pos)) # Signals from the core def on_job_status_update(self, status): general_tab = next(t for t in self.tab_presenters if isinstance(t, GeneralTabPresenter)) general_tab.refresh_status() self._refresh_scenario_status()
def __on_pen_width_action_checked(self, action: QAction) -> None: selected_pen_width = int(action.data()) self.__image_widget.set_pen_width(selected_pen_width) if self.__image_widget.is_paint_enabled(): self.__image_widget.setCursor(self.__get_pen_cursor()) self.pen_width_changed.emit(selected_pen_width)
def init_menu_bar(self): """ Initializes menu bar, creates actions and submenus within menu bar, connects actions to menu items KNOWN PROBLEMS -> ["M3201A", "M3300A", "M4i", "ZIUHFLI"] list of instruments that produce bugs :return: NoneType """ # Create action and bind it to a function that exits the application and closes all of its windows exit_action = QAction("&Exit", self) exit_action.setShortcut("Ctrl+Q") exit_action.setStatusTip("Exit the application") exit_action.triggered.connect(self.exit) # Action for adding a new instrument start_new_measurement_menu = QMenu("Add instrument", self) start_new_measurement_action = QAction("New", self) start_new_measurement_action.setShortcut("Ctrl+M") start_new_measurement_action.setStatusTip( "Open 'Add New Instrument' window") start_new_measurement_action.triggered.connect( lambda checked, name="DummyInstrument": self.add_new_instrument( name)) start_new_measurement_menu.addAction(start_new_measurement_action) start_new_measurement_menu.addSeparator() # fetch all instruments defined in qcodes and add then to the Add Instrument menu. Clicking any of these will # open AddInstrumentWidget with data for this instrument already filled in that window path = os.path.dirname(inspect.getfile(qc)) + "\\instrument_drivers" brands = get_subfolders(path, True) for brand in brands: current_brand_menu = QMenu(brand, self) start_new_measurement_menu.addMenu(current_brand_menu) models = get_files_in_folder(path + "\\" + brand, True) for model in models: if model[0:-3] not in [ "M3201A", "M3300A", "M4i", "Keithley_2600_channels", "AWGFileParser", "Keysight_33500B_channels", "Infiniium", "KeysightAgilent_33XXX", "Model_336", "Base_SPDT", "RC_SP4T", "RC_SPDT", "USB_SPDT", "QDac_channels", "RTO1000", "ZNB", "SR860", "SR86x", "AWG5208", "AWG70000A", "AWG70002A", "Keithley_2600_channels" ]: # above is the list of instruments that produce error when attempting to create them current_model_action = QAction(model[0:-3], self) current_model_action.setData(model[0:-3]) current_brand_menu.addAction(current_model_action) current_model_action.triggered.connect( lambda checked, name=current_model_action.data( ): self.add_new_instrument(name)) else: current_model_action = QAction(model[0:-3], self) current_model_action.setEnabled(False) current_model_action.setIcon( QtGui.QIcon("img/disabled.png")) current_brand_menu.addAction(current_model_action) current_model_action.triggered.connect( lambda checked, name=current_model_action.data( ): self.add_new_instrument(name)) reopen_plot_window = QAction("Reopen plot", self) reopen_plot_window.triggered.connect(self.reopen_plot_windows) multi_param_measurement = QAction("Multi sweep", self) multi_param_measurement.triggered.connect( self.open_multi_sweep_measurement) file_menu = self.menuBar().addMenu("&File") file_menu.addAction(exit_action) file_menu.addMenu(start_new_measurement_menu) tools_menu = self.menuBar().addMenu("&Tools") tools_menu.addAction(reopen_plot_window) measurement_menu = self.menuBar().addMenu("&Measurement") measurement_menu.addAction(multi_param_measurement)
class Minecraft: def __init__(self,parent=None): self.ui = uic.loadUi('UI/main.ui') self.ui.setWindowIcon(QIcon('MCPEManager.ico')) ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("myappid") # 白名单管理 self.Whitelist_QThread = Whitelist() self.Whitelist_Add_QThread = WhitelistAdd() self.Whitelist_Del_QThread = WhitelistDel() self.ui.whitelist_list.setColumnCount(3) self.ui.whitelist_list.setRowCount(100) self.ui.whitelist_list.setHorizontalHeaderLabels(['ID','xuid','忽略玩家计数']) self.ui.whitelist_list.setSelectionMode(QAbstractItemView.SingleSelection) self.ui.whitelist_list.setEditTriggers(QAbstractItemView.NoEditTriggers) self.ui.whitelist_list.setSelectionBehavior(QAbstractItemView.SelectRows) self.ui.whitelist_list.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) #self.ui.whitelist_add_edit.setEnabled(False) #self.ui.whitelist_add_button.setEnabled(False) #self.ui.whitelist_del_button.setEnabled(False) self.ui.whitelist_list.itemClicked.connect(self.Whitelist_Click) self.ui.whitelist_add_button.clicked.connect(self.Whitelist_Add) self.ui.whitelist_del_button.clicked.connect(self.Whitelist_Del) self.Whitelist_QThread.OutWhitelist.connect(self.Whitelist_Show) self.Whitelist_Add_QThread.OutWhitelist.connect(self.SSH_Whitelist) self.Whitelist_Del_QThread.OutWhitelist.connect(self.SSH_Whitelist) # 设置标签页 self.ui.setting_save_button.clicked.connect(self.Setting_Save) # 关于标签页 self.ui.about_vcheck_button.clicked.connect(self.CheckVersion) # 一键开服标签页 self.Build_QThread = Build() self.Build_Check_QThread = Build_Check() self.ui.build_build_button.clicked.connect(self.Build_Start) self.Build_QThread.consoleOutPut_All.connect(self.Build_Check) self.Build_QThread.consoleOutPut.connect(self.Build_Console_Show) self.Build_QThread.OutProgress.connect(self.ProgressBar) self.Build_QThread.stopcheck.connect(self.Build_Check_Stop) self.Build_Check_QThread.consoleOutPut.connect(self.Build_Console_All_Show) # 日志监控标签页 self.Log_QThread = Log() self.Log_Check_QThread = Log_Check() self.Log_Start_Server_QThread = LogStartServer() self.Log_Stop_Server_QThread = LogStopServer() self.Log_Start_Server_Quit_QThread = LogStartServerQuit() self.ui.log_startlog_button.clicked.connect(self.Log_Start) self.ui.log_startserver_button.clicked.connect(self.Server_Start) self.ui.log_stopserver_button.clicked.connect(self.Server_Stop) self.Log_QThread.consoleOutPut.connect(self.Log_Check) self.Log_Check_QThread.consoleOutPut.connect(self.Log_Show) self.Log_Start_Server_QThread.OutPut.connect(self.Server_Start_Quit) self.Log_Start_Server_Quit_QThread.OutPut.connect(self.Log_Start) # SSH连接 self.SSH_QThread = SSH() self.ui.Connect_button.clicked.connect(self.SSH_Start) self.SSH_QThread.OutPut.connect(self.SSH_Show) self.SSH_QThread.OutProgress.connect(self.ProgressBar) self.SSH_QThread.OutConsole.connect(self.Console) self.SSH_QThread.OutWhitelist.connect(self.SSH_Whitelist) self.SSH_QThread.OutPlugin.connect(self.SSH_Plugin) # SSH保存 menu = QMenu() self.SSH_Open_QThread = SSHOpen() self.action_save = QAction("保存SSH配置",menu) self.action_open = QAction("打开SSH配置",menu) menu.addActions([self.action_save,self.action_open]) #action_open.setData(QFileDialog.getOpenFileName(self,"选择BSM文件","C:\Users\Administrator\Desktop","BSM文件(*.bsm)")) self.ui.ssh_save_button.triggered.connect(self.SSH_Open) self.ui.ssh_save_button.setMenu(menu) self.SSH_Open_QThread.OutPut.connect(self.SSH_Open_Show) # 服务器控制 self.Control_QThread = Control() self.ui.control_save.clicked.connect(self.Control_Start) self.Control_QThread.OutProgress.connect(self.ProgressBar) self.Control_QThread.OutPut.connect(self.Control_button_Show) # 插件管理 #self.Plugin_JS_QThread = PluginJs() self.ui.plugin_dll_list.setColumnCount(3) self.ui.plugin_dll_list.setHorizontalHeaderLabels(['插件','简介','是否启用']) self.ui.plugin_dll_list.setSelectionMode(QAbstractItemView.SingleSelection) self.ui.plugin_dll_list.setEditTriggers(QAbstractItemView.NoEditTriggers) self.ui.plugin_dll_list.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) self.ui.plugin_dll_list.setRowCount(100) self.ui.plugin_script_list.setColumnCount(3) self.ui.plugin_script_list.setHorizontalHeaderLabels(['插件','简介','是否启用']) self.ui.plugin_script_list.setSelectionMode(QAbstractItemView.SingleSelection) self.ui.plugin_script_list.setEditTriggers(QAbstractItemView.NoEditTriggers) self.ui.plugin_script_list.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) self.ui.plugin_script_list.setRowCount(100) #self.Plugin_JS_QThread.OutPluginJs.connect(self.Plugin_Js_Show) # 插件仓库 self.Plugin_Repo_QThread = Plugin_Depository() self.ui.pluginstore_pstore_list.setRowCount(100) self.ui.pluginstore_pstore_list.setColumnCount(5) self.ui.pluginstore_pstore_list.setHorizontalHeaderLabels(['插件名称','简介','类型','版本','更新日期']) self.ui.pluginstore_pstore_list.setSelectionMode(QAbstractItemView.SingleSelection) self.ui.pluginstore_pstore_list.setSelectionBehavior(QAbstractItemView.SelectRows) self.ui.pluginstore_pstore_list.setEditTriggers(QAbstractItemView.NoEditTriggers) self.Plugin_Repo_QThread.OutPluginlist.connect(self.Plugin_Repo_Show) self.ui.pluginstore_install_button.clicked.connect(self.Plugin_Click) #self.ui.plugin_dll_list.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) # 关于页面相关控件 def CheckVersion(self): webbrowser.open("https://github.com/Sakitami/MinecraftBDS-Manager/releases", new=0, autoraise=True) # 设置页面相关控件 def Setting_Save(self): self.ui.setting_save_button.setEnabled(False) self.ui.setting_save_button.setText('保存中') server_locations = self.ui.server_location_edit.text() if not server_locations.endswith('/'): server_locations = server_locations + '/' config.set("Server", "server_location", server_locations) config.write(open("config.cfg", "w")) self.ui.setting_save_button.setEnabled(True) self.ui.setting_save_button.setText('保存成功') # SSH连接信号与界面逻辑 def SSH_Start(self): self.ui.Connect_button.setEnabled(False) self.ui.Connect_button.setEnabled(False) self.ui.IP_edit.setEnabled(False) self.ui.Port_edit.setEnabled(False) self.ui.User_edit.setEnabled(False) self.ui.Password_edit.setEnabled(False) self.ui.progressBar.setRange(0,100) self.ui.Connect_button.setText('连接中') self.ui.progressBar.setValue(10) SSH_IP = self.ui.IP_edit.text() SSH_Port = self.ui.Port_edit.text() SSH_Port = str(SSH_Port) SSH_User = self.ui.User_edit.text() SSH_Password = self.ui.Password_edit.text() config.set("SSH", "server_ip", SSH_IP) config.set("SSH", "server_port", SSH_Port) config.set("SSH", "server_user", SSH_User) config.set("SSH", "server_pass", SSH_Password) config.write(open("config.cfg", "w")) self.SSH_QThread.start() def SSH_Show(self, button_show): self.ui.Connect_button.setText(button_show) if button_show == '正在处理...': self.ui.progressBar.setValue(80) elif button_show == '连接成功': self.ui.progressBar.setValue(100) config.set("SSH", "connected", '1') config.write(open("config.cfg", "w")) self.ui.log_startlog_button.setEnabled(True) self.ui.pluginstore_install_button.setEnabled(True) self.ui.log_startserver_button.setEnabled(True) self.ui.log_stopserver_button.setEnabled(True) return else: self.ui.progressBar.reset() self.ui.Connect_button.setEnabled(True) self.ui.IP_edit.setEnabled(True) self.ui.Port_edit.setEnabled(True) self.ui.User_edit.setEnabled(True) self.ui.Password_edit.setEnabled(True) def SSH_Open(self): self.action_open.setData(QFileDialog.getOpenFileName(self.ui,"选择BSM文件",r"C:\Users\Administrator\Desktop","BSM文件(*.bsm)")) self.opend_ssh=self.action_open.data()[0] config.set("SETTING", "opend_ssh", self.opend_ssh) config.write(open("config.cfg", "w")) print(self.opend_ssh) self.SSH_Open_QThread.start() def SSH_Open_Show(self,check): if check == True: self.ui.IP_edit.setText(config.get("SSH", "server_ip")) self.ui.Port_edit.setText(config.get("SSH", "server_port")) self.ui.User_edit.setText(config.get("SSH", "server_user")) self.ui.Password_edit.setText(config.get("SSH", "server_pass")) def SSH_Whitelist(self,start): if start == 'True': self.ui.whitelist_add_edit.setEnabled(True) self.ui.whitelist_add_button.setEnabled(True) self.ui.whitelist_del_button.setEnabled(True) self.Whitelist_QThread.start() def SSH_Plugin(self,start): if start == 'True': self.Plugin_Repo_QThread.start() # 日志监控信号与界面逻辑 def Log_Start(self): self.ui.log_startlog_button.setEnabled(False) self.Log_QThread.start() def Log_Check(self,check): if check == True: self.ui.log_startlog_button.setText('已开启') self.Log_Check_QThread.start() def Log_Show(self,check): self.ui.log_log_text.clear() with open('Snap/log.txt','r')as f: f = f.read() self.ui.log_log_text.append(f) def Server_Start(self): self.ui.log_startserver_button.setEnabled(False) self.ui.log_stopserver_button.setEnabled(False) self.Log_Start_Server_QThread.start() def Server_Start_Quit(self,check): if check == True: self.Log_Start_Server_Quit_QThread.start() self.ui.log_stopserver_button.setEnabled(True) def Server_Stop(self): self.ui.log_stopserver_button.setEnabled(False) self.ui.log_startlog_button.setEnabled(True) self.Log_Stop_Server_QThread.start() self.ui.log_log_text.clear() # 一键开服信号与界面逻辑 def Build_Start(self): self.ui.build_build_button.setText('执行中') self.ui.build_build_button.setEnabled(False) self.ui.progressBar.setRange(0,100) self.ui.build_log_text.clear() self.ui.build_log_text.append('开始构建...') self.ui.progressBar.setValue(10) download_user = self.ui.log_save_edit_2.text() config.set("Server", "local", download_user) config.write(open("config.cfg", "w")) self.Build_QThread.start() def Build_Check(self,check): if check == True: self.Build_Check_QThread.start() def Build_Check_Stop(self,check): shutil.copy('Snap/build_log.txt', 'Log/build_log.txt') os.remove('Snap/build_log.txt') self.Build_Check_QThread.quit() self.ui.build_build_button.setText('开服') self.ui.build_build_button.setEnabled(True) def Build_Console_Show(self, console_txt): if console_txt == 'SSH连接失败!': self.ui.build_build_button.setText('开服') self.ui.progressBar.reset() self.ui.build_build_button.setEnabled(True) elif console_txt == '上传失败!': self.ui.build_build_button.setText('开服') self.ui.progressBar.reset() self.ui.build_build_button.setEnabled(True) self.ui.build_log_text.append(console_txt) def Build_Console_All_Show(self,check): if check == True: self.ui.build_log_text.clear() with open('Snap/build_log.txt','r')as f: f = f.read() self.ui.build_log_text.append(f) # 服务器控制信号与界面逻辑 def Control_Start(self): if config.getint('SSH', 'connected') == 0: self.ui.control_save.setText('SSH未连接') else: self.ui.control_save.setEnabled(False) self.ui.control_save.setText('保存中') self.ui.control_servername_edit.setEnabled(False) self.ui.control_gamemode_combo.setEnabled(False) self.ui.control_chest_combo.setEnabled(False) self.ui.control_maxplayer_spin.setEnabled(False) self.ui.control_xbox_combo.setEnabled(False) self.ui.control_whitelist_combo.setEnabled(False) self.ui.control_view_spin.setEnabled(False) self.ui.control_tkdistance_spin.setEnabled(False) self.ui.control_ktime_spin.setEnabled(False) self.ui.control_maxthread_spin.setEnabled(False) self.ui.control_playerchara_combo.setEnabled(False) self.ui.control_texture_combo.setEnabled(False) self.ui.control_log_combo.setEnabled(False) self.ui.control_zip_spin.setEnabled(False) self.ui.control_v4_spin.setEnabled(False) self.ui.control_v6_spin.setEnabled(False) config.set("CONTROL", 'server-name', str(self.ui.control_servername_edit.text())) config.set("CONTROL", 'gamemode', self.ui.control_gamemode_combo.currentText()) config.set("CONTROL", 'allow-cheats', self.ui.control_chest_combo.currentText()) config.set("CONTROL", 'max-players', str(self.ui.control_maxplayer_spin.value())) config.set("CONTROL", 'online-mode', self.ui.control_xbox_combo.currentText()) config.set("CONTROL", 'white-list', self.ui.control_whitelist_combo.currentText()) config.set("CONTROL", 'view-distance', str(self.ui.control_view_spin.value())) config.set("CONTROL", 'tick-distance', str(self.ui.control_tkdistance_spin.value())) config.set("CONTROL", 'player-idle-timeout', str(self.ui.control_ktime_spin.value())) config.set("CONTROL", 'max-threads', str(self.ui.control_maxthread_spin.value())) config.set("CONTROL", 'default-player-permission-level', self.ui.control_playerchara_combo.currentText()) config.set("CONTROL", 'texturepack-required', self.ui.control_texture_combo.currentText()) config.set("CONTROL", 'content-log-file-enabled', self.ui.control_log_combo.currentText()) config.set("CONTROL", 'compression-threshold', str(self.ui.control_zip_spin.value())) config.set("CONTROL", 'server-port', str(self.ui.control_v4_spin.value())) config.set("CONTROL", 'server-portv6', str(self.ui.control_v6_spin.value())) config.write(open("config.cfg", "w")) self.ui.progressBar.setValue(10) self.Control_QThread.start() def Control_button_Show(self, text): self.ui.control_save.setText(text) self.ui.control_servername_edit.setEnabled(True) self.ui.control_save.setEnabled(True) self.ui.control_gamemode_combo.setEnabled(True) self.ui.control_chest_combo.setEnabled(True) self.ui.control_maxplayer_spin.setEnabled(True) self.ui.control_xbox_combo.setEnabled(True) self.ui.control_whitelist_combo.setEnabled(True) self.ui.control_view_spin.setEnabled(True) self.ui.control_tkdistance_spin.setEnabled(True) self.ui.control_ktime_spin.setEnabled(True) self.ui.control_maxthread_spin.setEnabled(True) self.ui.control_playerchara_combo.setEnabled(True) self.ui.control_texture_combo.setEnabled(True) self.ui.control_log_combo.setEnabled(True) self.ui.control_zip_spin.setEnabled(True) self.ui.control_v4_spin.setEnabled(True) self.ui.control_v6_spin.setEnabled(True) # 白名单管理信号与界面逻辑 def Whitelist_Add(self): self.ui.whitelist_add_edit.setEnabled(False) self.ui.whitelist_add_button.setEnabled(False) self.ui.whitelist_del_button.setEnabled(False) if str(self.ui.whitelist_add_edit.text()) == '': self.ui.whitelist_add_button.setText('未输入!') self.ui.whitelist_add_edit.setEnabled(True) self.ui.whitelist_add_button.setEnabled(True) self.ui.whitelist_del_button.setEnabled(True) return config.set("Server", "add_user", str(self.ui.whitelist_add_edit.text())) self.ui.whitelist_add_edit.setEnabled(True) self.ui.whitelist_add_button.setEnabled(True) self.ui.whitelist_del_button.setEnabled(True) self.Whitelist_Add_QThread.start() def Whitelist_Del(self): self.ui.whitelist_add_edit.setEnabled(False) self.ui.whitelist_add_button.setEnabled(False) self.ui.whitelist_del_button.setEnabled(False) if str(self.ui.whitelist_add_edit.text()) == '': self.ui.whitelist_add_button.setText('未输入!') self.ui.whitelist_add_edit.setEnabled(True) self.ui.whitelist_add_button.setEnabled(True) self.ui.whitelist_del_button.setEnabled(True) return config.set("Server", "del_user", str(self.ui.whitelist_add_edit.text())) self.ui.whitelist_add_edit.setEnabled(True) self.ui.whitelist_add_button.setEnabled(True) self.ui.whitelist_del_button.setEnabled(True) self.Whitelist_Del_QThread.start() def Whitelist_Show(self, whitelist): self.ui.whitelist_list.clearContents() self.column_number = 0 for i in range(0,len(whitelist)): self.white_user = [] self.white_user.append(whitelist[i][0]) self.white_user.append(whitelist[i][1]) self.white_user.append(whitelist[i][2]) self.line_number = 0 for j in self.white_user: newItem = QTableWidgetItem(str(j)) self.ui.whitelist_list.setItem(self.line_number, self.column_number,newItem) self.column_number += 1 self.line_number += 1 #self.ui.whitelist_list.append(whitelist[i]) # write_whitelist() def Whitelist_Click(self,Item=None): if Item==None: return self.ui.whitelist_add_edit.setText(Item.text()) # 插件仓库信号与界面逻辑 def Plugin_Repo_Show(self, pluginlist): self.ui.pluginstore_pstore_list.clearContents() self.column_number = 0 for i in range(0,len(pluginlist)): self.plugin = [] self.plugin.append(pluginlist[i][1]) self.plugin.append(pluginlist[i][2]) self.plugin.append(pluginlist[i][3]) self.plugin.append(pluginlist[i][4]) self.plugin.append(pluginlist[i][5]) self.line_number = 0 for j in self.plugin: newItem = QTableWidgetItem(str(j)) self.ui.pluginstore_pstore_list.setItem(self.line_number, self.column_number,newItem) self.column_number += 1 self.line_number += 1 def Plugin_Click(self): try: id = self.ui.pluginstore_pstore_list.currentRow() print(id) except: self.ui.pluginstore_install_button.setText('请选择') # 插件管理信号与界面逻辑 #def Plugin_Js_Add(self): # pass #def Plugin_Js_Show(self, plugin_js_list): # self.ui.plugin_js_list.clearContents() # self.column_number = 0 # for i in range(0,len(plugin_js_list)): # self.white_user = [] # self.white_user.append(plugin_js_list[i][0]) # self.white_user.append(plugin_js_list[i][1]) # self.white_user.append(plugin_js_list[i][2]) # self.line_number = 0 # for j in self.white_user: # newItem = QTableWidgetItem(str(j)) # self.ui.plugin_js_list.setItem(self.line_number, self.column_number,newItem) # self.column_number += 1 # self.line_number += 1 # 进度条显示 def ProgressBar(self, progress_int): self.ui.progressBar.setValue(progress_int) # 控制台显示 def Console(self, text): self.ui.log_log_text.append(text) def Console_Clear(self,check): if check == True: self.ui.log_log_text.clear()
def change_eraser_option(self, option_action: QAction): self._eraser_option = option_action.data()
def toggle_column(self, action: QtWidgets.QAction) -> None: column: AssEventsModelColumn = action.data() self.horizontalHeader().setSectionHidden( column.value, not action.isChecked() )
def __menu_click(self, action: QAction): if action.data(): self.setUrl(action.data())
def change_toolbar_gadget(self, toolbar_gadget: QAction): self._selection_option = toolbar_gadget.data()
class StackedWidget(QStackedWidget): treeViewDataChanged = QtCore.pyqtSignal(str, str, UUID) playlistAdded = QtCore.pyqtSignal(str) playlistRemoved = QtCore.pyqtSignal(UUID) widgetDoubleClicked = QtCore.pyqtSignal(UUID, int) songRemoved = QtCore.pyqtSignal(UUID, int) def __init__(self, parent=None): super(StackedWidget, self).__init__(parent) self.playlistMappings = {} self.__setContextMenuActions() def createCustomPlaylistView(self, uuid): playlistModel = PlaylistModel(uuid) playlistView = QTableView(self) playlistView.setModel(playlistModel) playlistView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) playlistView.setSortingEnabled(True) playlistView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) playlistView.setSelectionBehavior(QAbstractItemView.SelectRows) playlistView.setShowGrid(False) playlistView.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) playlistView.doubleClicked.connect(self._doubleCLickedWidget) playlistView.customContextMenuRequested.connect( self.customMenuRequested) self.playlistMappings[uuid] = playlistView self.insertWidget(DEFAULT_VIEWS_COUNT, playlistView) def _doubleCLickedWidget(self, index): uuid = index.model().getUuid() row = index.row() self.widgetDoubleClicked.emit(uuid, row) def removePlaylistView(self, uuid): if uuid in self.playlistMappings: widget = self.playlistMappings[uuid] self.removeWidget(widget) self.setCurrentIndex(0) del self.playlistMappings[uuid] def createLibraryPlaylisView(self, uuid): playlistModel = PlaylistModel(uuid) playlistView = QTableView(self) playlistView.setModel(playlistModel) playlistView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) playlistView.setSortingEnabled(True) playlistView.setSelectionBehavior(QAbstractItemView.SelectRows) playlistView.setShowGrid(False) playlistView.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) playlistView.doubleClicked.connect(self._doubleCLickedWidget) playlistView.customContextMenuRequested.connect( self.customMenuRequested) self.playlistMappings[uuid] = playlistView self.insertWidget(0, playlistView) self.setCurrentWidget(self.playlistMappings[uuid]) def __setContextMenuActions(self): self.editAct = QAction("Edit", self) self.editAct.setStatusTip("Edit this file's metadata") self.editAct.triggered.connect(self.editData) self.removeAct = QAction("Remove From Playlist", self) self.removeAct.setStatusTip("Remove file from this Playlist") self.removeAct.triggered.connect(self.removeEntry) @QtCore.pyqtSlot(UUID, list) def updatePlaylist(self, uuid, mediaFiles): widget = self.playlistMappings[uuid] model = widget.model() model.insertMedia(model.rowCount(), mediaFiles) model.reset() model.insertMedia(model.rowCount(), mediaFiles) @QtCore.pyqtSlot(UUID, list) def appendToPlaylist(self, uuid, mediaFiles): widget = self.playlistMappings[uuid] model = widget.model() model.insertMedia(model.rowCount(), mediaFiles) @QtCore.pyqtSlot(UUID, int) def setWidgetIndex(self, uuid, row): widget = self.playlistMappings[uuid] index = widget.model().index(row, 0) widget.setCurrentIndex(index) @QtCore.pyqtSlot(QtCore.QPoint) def customMenuRequested(self, pos): menu = QMenu(self) row = self.currentWidget().indexAt(pos).row() song = self.currentWidget().model().getDataAtRow(row) self.editAct.setData(song) self.removeAct.setData((self.currentWidget().model().getUuid(), row)) menu.addAction(self.editAct) menu.addAction(self.removeAct) menu.popup(self.mapToGlobal(pos)) def editData(self): song = self.editAct.data() available_metadata = song.get_values(MetadataDialog.METADATA_INFO) dialog = MetadataDialog(available_metadata) dialogCode = dialog.exec_() if dialogCode == QDialog.Accepted: result = dialog.getResultDict() for k, v in result.items(): song.set_tag(k, v) song.save() if dialogCode == QDialog.Rejected: return def removeEntry(self): uuid, row = self.removeAct.data() widget = self.playlistMappings[uuid] model = widget.model() model.removeMedia(row, 1) self.songRemoved.emit(uuid, row)
class BrowserWindow(QMainWindow): def __init__(self, parent: QWidget = None, flags: Qt.WindowFlags = Qt.Widget): super().__init__(parent, flags) self.m_tabWidget = TabWidget(self) self.m_progressBar = QProgressBar(self) self.m_historyBackAction = None self.m_historyForwardAction = None self.m_stopAction = None self.m_reloadAction = None self.m_stopReloadAction = None self.m_urlLineEdit = UrlLineEdit(self) self.setToolButtonStyle(Qt.ToolButtonFollowStyle) self.setAttribute(Qt.WA_DeleteOnClose, True) toolbar = self.createToolBar() self.addToolBar(toolbar) # self.menuBar().addMenu(self.createFileMenu(self.m_tabWidget)) # TODO: menu not created if done like this? self.createFileMenu(self.m_tabWidget) # self.menuBar().addMenu(self.createViewMenu(toolbar)) self.createViewMenu(toolbar) # self.menuBar().addMenu(self.createWindowMenu(self.m_tabWidget)) self.createWindowMenu(self.m_tabWidget) # self.menuBar().addMenu(self.createHelpMenu()) self.createHelpMenu() centralWidget = QWidget(self) layout = QVBoxLayout() layout.setSpacing(0) # layout.setMargin(0) self.addToolBarBreak() self.m_progressBar.setMaximumHeight(1) self.m_progressBar.setTextVisible(False) self.m_progressBar.setStyleSheet( "QProgressBar {border: 0px } QProgressBar.chunk { background-color: red }" ) layout.addWidget(self.m_progressBar) layout.addWidget(self.m_tabWidget) centralWidget.setLayout(layout) self.setCentralWidget(centralWidget) self.m_tabWidget.titleChanged.connect(self.handleWebViewTitleChanged) self.m_tabWidget.linkHovered.connect(self._link_hovered) self.m_tabWidget.loadProgress.connect(self.handleWebViewLoadProgress) self.m_tabWidget.urlChanged.connect(self.handleWebViewUrlChanged) self.m_tabWidget.iconChanged.connect(self.handleWebViewIconChanged) self.m_tabWidget.webActionEnabledChanged.connect( self.handleWebActionEnabledChanged) self.m_urlLineEdit.returnPressed.connect(self._return_pressed) self.m_urlLineEdit.setFavIcon(QIcon(":defaulticon.png")) self.handleWebViewTitleChanged(self.tr("Qt Simple Browser")) self.m_tabWidget.createTab() def _link_hovered(self, url: str): self.statusBar().showMessage(url) def _return_pressed(self): self.m_urlLineEdit.setFavIcon(QIcon(":defaulticon.png")) self.loadPageUrl(self.m_urlLineEdit.url()) def sizeHint(self) -> QSize: desktopRect = QApplication.desktop().screenGeometry() size = desktopRect.size() return QSize(int(size.width() * 0.9), int(size.height() * 0.9)) def createFileMenu(self, tabWidget: TabWidget) -> QMenu: fileMenu = self.menuBar().addMenu(self.tr("&File")) # fileMenu = QMenu(self.tr("&File")) # TODO: menu not created if done like this?...menu goes out of scope and is destroyed beore being added in caller? # self.file_menu = QMenu(self.tr("&File")) # Saving as a member fixes the above issue # fileMenu = self.file_menu # fileMenu = QMenu(self.tr("&File"), self) # TODO: crashes if done like this? fileMenu.addAction(self.tr("&New Window"), self.handleNewWindowTriggered, QKeySequence.New) newTabAction = QAction(QIcon(":addtab.png"), self.tr("New &Tab"), self) newTabAction.setShortcuts(QKeySequence.AddTab) newTabAction.setIconVisibleInMenu(False) newTabAction.triggered.connect(tabWidget.createTab) fileMenu.addAction(newTabAction) fileMenu.addAction(self.tr("&Open File..."), self.handleFileOpenTriggered, QKeySequence.Open) fileMenu.addSeparator() closeTabAction = QAction(QIcon(":closetab.png"), self.tr("&Close Tab"), self) closeTabAction.setShortcuts(QKeySequence.Close) closeTabAction.setIconVisibleInMenu(False) closeTabAction.triggered.connect( lambda: tabWidget.closeTab(tabWidget.currentIndex())) fileMenu.addAction(closeTabAction) closeAction = QAction(self.tr("&Quit"), self) closeAction.setShortcut(QKeySequence(Qt.CTRL | Qt.Key_Q)) closeAction.triggered.connect(self.close) fileMenu.addAction(closeAction) fileMenu.aboutToShow.connect(lambda: self._about_to_show(closeAction)) return fileMenu def _about_to_show(self, closeAction): from browser import Browser if len(Browser.instance().windows()) == 1: closeAction.setText(self.tr("&Quit")) else: closeAction.setText(self.tr("&Close Window")) def createViewMenu(self, toolbar: QToolBar) -> QMenu: # viewMenu = QMenu(self.tr("&View")) viewMenu = self.menuBar().addMenu(self.tr("&View")) self.m_stopAction = viewMenu.addAction(self.tr("&Stop")) shortcuts = [QKeySequence(Qt.CTRL | Qt.Key_Period), Qt.Key_Escape] self.m_stopAction.setShortcuts(shortcuts) self.m_stopAction.triggered.connect( lambda: self.m_tabWidget.triggerWebPageAction(QWebEnginePage.Stop)) self.m_reloadAction = viewMenu.addAction(self.tr("Reload Page")) self.m_reloadAction.setShortcuts(QKeySequence.Refresh) self.m_reloadAction.triggered.connect( lambda: self.m_tabWidget.triggerWebPageAction(QWebEnginePage.Reload )) zoomIn = viewMenu.addAction(self.tr("Zoom &In")) zoomIn.setShortcut(QKeySequence(Qt.CTRL | Qt.Key_Plus)) zoomIn.triggered.connect(self._zoom_in) zoomOut = viewMenu.addAction(self.tr("Zoom &Out")) zoomOut.setShortcut(QKeySequence(Qt.CTRL | Qt.Key_Minus)) zoomOut.triggered.connect(self._zoom_out) resetZoom = viewMenu.addAction(self.tr("Reset &Zoom")) resetZoom.setShortcut(QKeySequence(Qt.CTRL | Qt.Key_0)) resetZoom.triggered.connect(self._zoom_reset) viewMenu.addSeparator() viewToolbarAction = QAction(self.tr("Hide Toolbar"), self) viewToolbarAction.setShortcut(self.tr("Ctrl+|")) viewToolbarAction.triggered.connect( lambda: self._view_toolbar(toolbar, viewToolbarAction)) viewMenu.addAction(viewToolbarAction) viewStatusbarAction = QAction(self.tr("Hide Status Bar"), self) viewStatusbarAction.setShortcut(self.tr("Ctrl+/")) viewStatusbarAction.triggered.connect( lambda: self._view_statusbar(viewStatusbarAction)) viewMenu.addAction(viewStatusbarAction) return viewMenu def _zoom_in(self): if self.currentTab(): self.currentTab().setZoomFactor(self.currentTab().zoomFactor() + 0.1) def _zoom_out(self): if self.currentTab(): self.currentTab().setZoomFactor(self.currentTab().zoomFactor() - 0.1) def _zoom_reset(self): if self.currentTab(): self.currentTab().setZoomFactor(1.0) def _view_toolbar(self, toolbar: QToolBar, viewToolbarAction: QAction): if toolbar.isVisible(): viewToolbarAction.setText(self.tr("Show Toolbar")) toolbar.close() else: viewToolbarAction.setText(self.tr("Hide Toolbar")) toolbar.show() def _view_statusbar(self, viewStatusbarAction: QAction): if self.statusBar().isVisible(): viewStatusbarAction.setText(self.tr("Show Status Bar")) self.statusBar().close() else: viewStatusbarAction.setText(self.tr("Hide Status Bar")) self.statusBar().show() def createWindowMenu(self, tabWidget: TabWidget) -> QMenu: # menu = QMenu(self.tr("&Window")) menu = self.menuBar().addMenu(self.tr("&Window")) nextTabAction = QAction(self.tr("Show Next Tab"), self) shortcuts = [ QKeySequence(Qt.CTRL | Qt.Key_BraceRight), QKeySequence(Qt.CTRL | Qt.Key_PageDown), QKeySequence(Qt.CTRL | Qt.Key_BracketRight), QKeySequence(Qt.CTRL | Qt.Key_Less) ] nextTabAction.setShortcuts(shortcuts) nextTabAction.triggered.connect(tabWidget.nextTab) previousTabAction = QAction(self.tr("Show Previous Tab"), self) shortcuts.clear() shortcuts.append(QKeySequence(Qt.CTRL | Qt.Key_BraceLeft)) shortcuts.append(QKeySequence(Qt.CTRL | Qt.Key_PageUp)) shortcuts.append(QKeySequence(Qt.CTRL | Qt.Key_BracketLeft)) shortcuts.append(QKeySequence(Qt.CTRL | Qt.Key_Greater)) previousTabAction.setShortcuts(shortcuts) previousTabAction.triggered.connect(tabWidget.previousTab) menu.aboutToShow.connect(lambda: self._about_to_show_window_menu( menu, nextTabAction, previousTabAction)) return menu def _about_to_show_window_menu(self, menu, nextTabAction, previousTabAction): menu.clear() menu.addAction(nextTabAction) menu.addAction(previousTabAction) menu.addSeparator() from browser import Browser windows = Browser.instance().windows() for index, window in enumerate(windows): action = menu.addAction(window.windowTitle(), self.handleShowWindowTriggered) action.setData(index) action.setCheckable(True) if window == self: action.setChecked(True) def createHelpMenu(self) -> QMenu: # helpMenu = QMenu(self.tr("&Help")) helpMenu = self.menuBar().addMenu(self.tr("&Help")) helpMenu.addAction(self.tr("About &Qt"), QApplication.aboutQt) return helpMenu def createToolBar(self) -> QToolBar: navigationBar = QToolBar(self.tr("Navigation")) navigationBar.setAllowedAreas(Qt.TopToolBarArea | Qt.BottomToolBarArea) navigationBar.toggleViewAction().setEnabled(False) self.m_historyBackAction = QAction(self) backShortcuts = QKeySequence.keyBindings(QKeySequence.Back) for i, x in enumerate(reversed(backShortcuts)): if x[0] == Qt.Key_Backspace: # Chromium already handles navigate on backspace when appropriate. backShortcuts.pop(i) # For some reason Qt doesn't bind the dedicated Back key to Back. backShortcuts.append(QKeySequence(Qt.Key_Back)) self.m_historyBackAction.setShortcuts(backShortcuts) self.m_historyBackAction.setIconVisibleInMenu(False) self.m_historyBackAction.setIcon(QIcon(":go-previous.png")) self.m_historyBackAction.triggered.connect( lambda: self.m_tabWidget.triggerWebPageAction(QWebEnginePage.Back)) navigationBar.addAction(self.m_historyBackAction) self.m_historyForwardAction = QAction(self) fwdShortcuts = QKeySequence.keyBindings(QKeySequence.Forward) for i, x in enumerate(reversed(fwdShortcuts)): if x[0] & Qt.Key_unknown == Qt.Key_Backspace: fwdShortcuts.pop(i) fwdShortcuts.append(QKeySequence(Qt.Key_Forward)) self.m_historyForwardAction.setShortcuts(fwdShortcuts) self.m_historyForwardAction.setIconVisibleInMenu(False) self.m_historyForwardAction.setIcon(QIcon(":go-next.png")) self.m_historyForwardAction.triggered.connect( lambda: self.m_tabWidget.triggerWebPageAction(QWebEnginePage. Forward)) navigationBar.addAction(self.m_historyForwardAction) self.m_stopReloadAction = QAction(self) self.m_stopReloadAction.triggered.connect( lambda: self.m_tabWidget.triggerWebPageAction( QWebEnginePage.WebAction(self.m_stopReloadAction.data()))) navigationBar.addAction(self.m_stopReloadAction) navigationBar.addWidget(self.m_urlLineEdit) size = self.m_urlLineEdit.sizeHint().height() navigationBar.setIconSize(QSize(size, size)) return navigationBar def handleWebViewIconChanged(self, icon: QIcon): self.m_urlLineEdit.setFavIcon(icon) def handleWebViewUrlChanged(self, url: QUrl): self.m_urlLineEdit.setUrl(url) if url.isEmpty(): self.m_urlLineEdit.setFocus() def handleWebActionEnabledChanged(self, action: QWebEnginePage.WebAction, enabled: bool): if action == QWebEnginePage.Back: self.m_historyBackAction.setEnabled(enabled) return if action == QWebEnginePage.Forward: self.m_historyForwardAction.setEnabled(enabled) return if action == QWebEnginePage.Reload: self.m_reloadAction.setEnabled(enabled) return if action == QWebEnginePage.Stop: self.m_stopAction.setEnabled(enabled) return # qWarning print("Unhandled webActionChanged signal", action, flush=True) def handleWebViewTitleChanged(self, title: str): if not title: self.setWindowTitle(self.tr("Qt Simple Browser")) else: self.setWindowTitle( self.tr("{} - Qt Simple Browser").format(title)) def handleNewWindowTriggered(self): window = BrowserWindow() from browser import Browser Browser.instance().addWindow(window) window.loadHomePage() def handleFileOpenTriggered(self): file, success = QFileDialog.getOpenFileName( self, self.tr("Open Web Resource"), '', self. tr("Web Resources (*.html *.htm *.svg *.png *.gif *.svgz)All files (*.*)" )) if not file: return self.loadPage(file) def closeEvent(self, event: QCloseEvent): if self.m_tabWidget.count() > 1: ret = QMessageBox.warning( self, self.tr("Confirm close"), self.tr("Are you sure you want to close the window ?\n" "There are {} tabs open.").format( self.m_tabWidget.count()), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if ret == QMessageBox.No: event.ignore() return event.accept() # deleteLater() def loadHomePage(self): self.loadPage("http://www.qt.io") def loadPage(self, page: str): self.loadPageUrl(QUrl.fromUserInput(page)) def loadPageUrl(self, url: QUrl): if url.isValid(): self.m_urlLineEdit.setUrl(url) self.m_tabWidget.setUrl(url) def tabWidget(self) -> TabWidget: return self.m_tabWidget def currentTab(self) -> WebView: return self.m_tabWidget.currentWebView() def handleWebViewLoadProgress(self, progress: int): stopIcon = QIcon(":process-stop.png") reloadIcon = QIcon(":view-refresh.png") if progress < 100 and progress > 0: self.m_stopReloadAction.setData(QWebEnginePage.Stop) self.m_stopReloadAction.setIcon(stopIcon) self.m_stopReloadAction.setToolTip( self.tr("Stop loading the current page")) else: self.m_stopReloadAction.setData(QWebEnginePage.Reload) self.m_stopReloadAction.setIcon(reloadIcon) self.m_stopReloadAction.setToolTip( self.tr("Reload the current page")) self.m_progressBar.setValue(progress if progress < 100 else 0) def handleShowWindowTriggered(self): action = self.sender() if isinstance(action, QAction): offset = action.data() from browser import Browser windows = Browser.instance().windows() activate = windows[offset] activate.activateWindow() if isinstance( windows[offset], BrowserWindow): # WebPopupWindow instances have no tabs windows[offset].currentTab().setFocus()