Example #1
1
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()
Example #2
0
 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)
Example #3
0
 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())
Example #4
0
    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)
Example #6
0
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)
Example #7
0
 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)
Example #8
0
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)
Example #9
0
    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
Example #10
0
 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!"
             )
         )
Example #11
0
 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())
Example #12
0
 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)
Example #15
0
    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()
Example #17
0
 def change_eraser_option(self, option_action: QAction):
     self._eraser_option = option_action.data()
Example #18
0
 def toggle_column(self, action: QtWidgets.QAction) -> None:
     column: AssEventsModelColumn = action.data()
     self.horizontalHeader().setSectionHidden(
         column.value, not action.isChecked()
     )
Example #19
0
 def __menu_click(self, action: QAction):
     if action.data():
         self.setUrl(action.data())
Example #20
0
 def change_toolbar_gadget(self, toolbar_gadget: QAction):
     self._selection_option = toolbar_gadget.data()
Example #21
0
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)
Example #22
0
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()