Exemple #1
0
 def testMenu(self):
     self._actionDestroyed = False
     w = QWidget()
     menu = QMenu(w)
     act = menu.addAction("MENU")
     _ref = weakref.ref(act, self.actionDestroyed)
     act = None
     self.assertFalse(self._actionDestroyed)
     menu.clear()
     self.assertTrue(self._actionDestroyed)
Exemple #2
0
 def contextMenuEvent(self, event):
     i=self.indexAt(event.pos())
     #print(self.indexAt(event.pos()))
     menu = QMenu(self)
     deleteAction = menu.addAction("删除")
     pasteAction = menu.addAction("粘贴")
     action = menu.exec_(self.mapToGlobal(event.pos()))
     if action == deleteAction:
         p=self.parent()
         while p!=None:
             oldp=p
             p=p.parent()
         oldp.treat_delete(self.model().filePath(i))
     elif action == pasteAction:
         p=self.parent()
         while p!=None:
             oldp=p
             p=p.parent()
         oldp.treat_paste(self.model().filePath(i))
Exemple #3
0
    def createHeaderMenus(self):
        for headInfo in self.headers:
            x = headInfo['x']
            x = x - self.position
            if self.currPosX > x and self.currPosX < x+self.w and self.currPosY > self.t and self.currPosY < self.h+self.t:
                if 0 == self.headers.index(headInfo):
                    break

                self.selectedHeader = headInfo
                menu = QMenu()
                if headInfo['flagCluster']:
                    menu.addAction(self.scatterAct)
                else:
                    menu.addAction(self.deleteAct)
                    menu.addAction(self.groupAct)
                menu.exec_(QtGui.QCursor.pos())
Exemple #4
0
 def contextMenuEvent(self, event: QContextMenuEvent):
     item = self.itemAt(event.pos())
     if item is not None:
         item.handle_context_menu_event(event)
     else:
         menu = QMenu()
         menu.addAction("Create new stash", self._create_new_stash)
         menu.exec_(QCursor.pos())
Exemple #5
0
    def contextMenuEvent(self, event: QContextMenuEvent) -> None:
        index = self.indexAt(event.pos())

        menu = QMenu("Menu")

        edit_action = QAction("Edit")
        edit_action.triggered.connect(lambda: self.edit_flight(index))
        menu.addAction(edit_action)

        delete_action = QAction(f"Delete")
        delete_action.triggered.connect(
            lambda: self.cancel_or_abort_flight(index))
        menu.addAction(delete_action)

        menu.exec_(event.globalPos())
Exemple #6
0
 def onOrderTreeRightClicked(self):
     order_tree = self.manual_create_order.findChild(QTreeWidget, "mtree")
     delete_order = self.manual_create_order.findChild(
         QAction, "delete_order")
     if order_tree.currentColumn() >= 0:
         menu = QMenu(order_tree)
         menu.addAction(delete_order)
         menu.popup(QtGui.QCursor.pos())
    def __init__(self, parent):
        """

        Args:
            parent (QWidget): Graph View Form's (QMainWindow) central widget (self.centralwidget)
        """
        super().__init__(
            parent=parent)  # Parent is passed to QWidget's constructor
        self._spine_db_editor = None
        self._menu = QMenu(self)
        self.pos_x_parameter = "x"
        self.pos_y_parameter = "y"
        self.selected_items = list()
        self.removed_items = list()
        self.hidden_items = list()
        self.prunned_entity_ids = dict()
        self.heat_map_items = list()
        self._point_value_tuples_per_parameter_name = dict(
        )  # Used in the heat map menu
        self._hovered_obj_item = None
        self.relationship_class = None
        self.cross_hairs_items = []
        self.auto_expand_objects = None
        self._auto_expand_objects_action = None
        self._save_pos_action = None
        self._clear_pos_action = None
        self._hide_action = None
        self._show_hidden_action = None
        self._prune_entities_action = None
        self._prune_classes_action = None
        self._restore_all_pruned_action = None
        self._rebuild_action = None
        self._export_as_pdf_action = None
        self._zoom_action = None
        self._rotate_action = None
        self._arc_length_action = None
        self._restore_pruned_menu = None
        self._parameter_heat_map_menu = None
Exemple #8
0
    def setup_ui(self):
        window = self.window

        # Progress
        self.background_processor.background_tasks_button_lock_signal.connect(
            self.enable_buttons_with_background_tasks)

        for preset in self._window_manager.preset_manager.all_presets:
            self._create_button_for_preset(preset)

        # Menu
        self._tool_button_menu = QMenu(window.preset_tool_button)
        window.preset_tool_button.setMenu(self._tool_button_menu)

        self._action_delete = QAction(window)
        self._action_delete.setText("Delete")
        self._tool_button_menu.addAction(self._action_delete)

        action_export_preset = QAction(window)
        action_export_preset.setText("Export")
        self._tool_button_menu.addAction(action_export_preset)

        action_import_preset = QAction(window)
        action_import_preset.setText("Import")
        self._tool_button_menu.addAction(action_import_preset)

        # Signals
        window.create_customize_button.clicked.connect(
            self._on_customize_button)
        window.create_preset_combo.activated.connect(self._on_select_preset)
        window.create_generate_button.clicked.connect(
            partial(self._generate_new_seed, True))
        window.create_generate_race_button.clicked.connect(
            partial(self._generate_new_seed, False))

        self._action_delete.triggered.connect(self._on_delete_preset)
        action_export_preset.triggered.connect(self._on_export_preset)
        action_import_preset.triggered.connect(self._on_import_preset)
Exemple #9
0
class AccountButton(QPushButton):
    changed = Signal(int)

    def __init__(self, parent):
        QPushButton.__init__(self, parent)
        self.p_account_id = 0

        self.Menu = QMenu(self)
        self.Menu.addAction(g_tr('AccountButton', "Choose account"),
                            self.ChooseAccount)
        self.Menu.addAction(g_tr('AccountButton', "Any account"),
                            self.ClearAccount)
        self.setMenu(self.Menu)

        self.dialog = AccountListDialog()
        self.setText(self.dialog.SelectedName)

    def getId(self):
        return self.p_account_id

    def setId(self, account_id):
        self.p_account_id = account_id
        self.setText(self.dialog.SelectedName)
        self.changed.emit(self.p_account_id)

    account_id = Property(int, getId, setId, notify=changed)

    def ChooseAccount(self):
        ref_point = self.mapToGlobal(self.geometry().bottomLeft())
        self.dialog.setGeometry(ref_point.x(), ref_point.y(),
                                self.dialog.width(), self.dialog.height())
        self.dialog.setFilter()
        res = self.dialog.exec_(enable_selection=True)
        if res:
            self.account_id = self.dialog.selected_id

    def ClearAccount(self):
        self.account_id = 0
 def __init__(self, file_path, ds_form):
     super().__init__()
     self.ds_form = ds_form
     self.file_path = file_path
     self.dir_name, self.file_name = os.path.split(file_path)
     self.setText(self.file_name)
     self.setPopupMode(QToolButton.MenuButtonPopup)
     self.setStyleSheet("""
         QToolButton {
             padding-left: 12px; padding-right: 32px; padding-top: 6px; padding-bottom: 6px;
             background-color: #ffffff;
             border: 1px solid #cccccc;
             border-style: outset;
             border-radius: 6px;
         }
         QToolButton:hover {
             background-color: #eeeeee;
         }
         QToolButton:pressed {
             background-color: #dddddd;
         }
         QToolButton::menu-button {
             border: 1px solid #cccccc;
             border-style: outset;
             border-top-right-radius: 6px;
             border-bottom-right-radius: 6px;
             width: 20px;
         }
         """)
     menu = QMenu(ds_form)
     self.setMenu(menu)
     open_file_action = menu.addAction("Open")
     open_containing_folder_action = menu.addAction(
         "Open containing folder")
     open_file_action.triggered.connect(self.open_file)
     open_containing_folder_action.triggered.connect(
         self.open_containing_folder)
     self.clicked.connect(open_file_action.triggered)
class ProjectItemButton(ProjectItemButtonBase):
    def __init__(self, toolbox, icon, item_type, parent=None):
        super().__init__(toolbox, icon, item_type, parent=parent)
        self.setToolTip(
            f"<p>Drag-and-drop this onto the Design View to create a new <b>{item_type}</b> item.</p>"
        )
        if not toolbox.supports_specification(item_type):
            self._list_view = None
            self._menu = None
            return
        self.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self._list_view = ProjectItemDragListView()
        self._list_view.doubleClicked.connect(toolbox.edit_specification)
        self._list_view.context_menu_requested.connect(
            toolbox.show_specification_context_menu)
        self._list_widget = _CreateNewSpecListWidget(item_type)
        self._list_widget.itemClicked.connect(
            lambda _, item_type=item_type: toolbox.show_specification_form(
                item_type))
        self._menu = QMenu(self)  # Drop-down menu
        widget_action = CustomWidgetAction(self._menu)
        widget_action.setDefaultWidget(self._list_view)
        self._menu.addAction(widget_action)
        widget_action = CustomWidgetAction(self._menu)
        widget_action.setDefaultWidget(self._list_widget)
        self._menu.addAction(widget_action)
        self.setMenu(self._menu)
        self.setPopupMode(QToolButton.MenuButtonPopup)
        self._resize()
        model = toolbox.filtered_spec_factory_models.get(self.item_type)
        self._list_view.setModel(model)
        model.rowsInserted.connect(lambda *args: self._resize())
        model.rowsRemoved.connect(lambda *args: self._resize())
        model.modelReset.connect(lambda *args: self._resize())
        self._list_view.drag_about_to_start.connect(self._menu.hide)

    def set_menu_color(self, color):
        if self._menu:
            self._menu.setStyleSheet(
                f"QMenu{{background: {make_icon_background(color)};}}")

    def setIconSize(self, size):
        super().setIconSize(size)
        if self._list_view:
            self._list_view.setIconSize(size)

    def _resize(self):
        self._list_view._set_preferred_height()
        self._list_widget._set_preferred_height()
        width = max(self._list_view._get_preferred_width(),
                    self._list_widget._get_preferred_width())
        self._list_view.setFixedWidth(width)
        self._list_widget.setFixedWidth(width)
        event = QResizeEvent(QSize(), self.menu().size())
        QApplication.sendEvent(self.menu(), event)

    def _make_mime_data_text(self):
        return ",".join([self.item_type, ""])
Exemple #12
0
class QMenuAddActionWithIcon(UsesQApplication):
    def setUp(self):
        super(QMenuAddActionWithIcon, self).setUp()
        self.menu = QMenu()
        self.icon = QIcon()

    def tearDown(self):
        del self.menu
        del self.icon
        super(QMenuAddActionWithIcon, self).tearDown()

    def testAddActionWithoutKeySequenceCallable(self):
        # bug #280
        action = self.menu.addAction(self.icon, self.app.tr('aaa'), lambda: 1)

    def testAddActionKeySequenceCallable(self):
        # bug #228
        action = self.menu.addAction(self.icon, self.app.tr('aaa'), lambda: 1,
                                     QKeySequence(self.app.tr('Ctrl+O')))

    def testAddActionKeySequenceSlot(self):
        action = self.menu.addAction(self.icon, 'Quit', self.app,
                                     SLOT('quit()'), QKeySequence('Ctrl+O'))
Exemple #13
0
    def addBtn_clicked(self) -> QPushButton:
        index = self.layUp.count()  # 添加的按钮在布局中的索引位置,起始0
        button = QPushButton('btn{}'.format(index))
        button.clicked.connect(lambda: self.button_clicked(button))

        button.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)

        def on_context_menu(point):
            # 弹出菜单
            menu.exec_(button.mapToGlobal(point))  # 把相对于按钮的位置转为相对于全局的位置

        button.setContextMenuPolicy(Qt.CustomContextMenu)  # 菜单策略,自定义
        button.customContextMenuRequested.connect(on_context_menu)  # 触发信号

        # 设置右击删除菜单
        menu = QMenu(button)
        delQAction = QAction("删除", button)
        delQAction.triggered.connect(lambda: self.deleteButton(button))
        menu.addAction(delQAction)

        self.layUp.insertWidget(index, button)  # 添加按钮到布局中
        self.signalBtnAdded.emit(button)  # 发送添加信号
        return button
Exemple #14
0
    def contextMenuEvent(self, pos):
        menu = QMenu()
        if self.deletable is True:
            delete_action = menu.addAction("Delete")
        else:
            delete_action = None

        if self.infectionStateEditable is True:
            edit_infection_state_action = menu.addAction(
                "Toggle Infection State")
        else:
            edit_infection_state_action = None

        global_position = self.mapToGlobal(pos)
        selected_item = menu.exec_(global_position)

        if selected_item == delete_action and self.deletable:
            action_row = self.itemAt(pos).row()
            self.removeRow(action_row)
            self.delItem.emit([self.objectName(), action_row])
        if selected_item == edit_infection_state_action:
            action_row = self.itemAt(pos).row()
            self.editIS.emit([self.objectName(), action_row])
Exemple #15
0
    def contextMenuEvent(self, event):
        menu: QMenu = QMenu(self)

        delete_action = QAction('delete')
        delete_action.triggered.connect(self.action_delete_triggered)

        edit_value_action = QAction('edit value')
        edit_value_action.triggered.connect(self.action_edit_val_triggered)

        actions = [delete_action, edit_value_action]
        for a in actions:
            menu.addAction(a)

        menu.exec_(event.globalPos())
Exemple #16
0
    def qmenu(self, extra_entries=None):
        if extra_entries is None:
            extra_entries = []
        else:
            extra_entries = [MenuSeparator() if entry is None else MenuEntry(*entry) for entry in extra_entries]

        if not extra_entries and self._qmenu is not None:
            # in order to use the cached result, must not have extra entries
            return self._qmenu

        if self.parent is not None:
            menu = QMenu(self.caption, self.parent)
        else:
            menu = QMenu(self.caption)

        for entry in self.entries + extra_entries:
            self._translate_element(menu, entry)

        # in order to cache the result, must not have extra entries
        if not extra_entries:
            self._qmenu = menu

        return menu
Exemple #17
0
    def get_actions(self, actions_dict, menu):
        actions = []

        for k in actions_dict:
            v_dict = actions_dict[k]
            try:
                method = v_dict['method']
                data = None
                try:
                    data = v_dict['data']
                except KeyError:
                    pass
                action = NodeInstanceAction(k, menu, data)
                action.custom_triggered.connect(method)
                actions.append(action)
            except KeyError:
                action_menu = QMenu(k, menu)
                sub_actions = self.get_actions(v_dict, action_menu)
                for a in sub_actions:
                    action_menu.addAction(a)
                actions.append(action_menu)

        return actions
Exemple #18
0
    def contextMenuEvent(self, event):
        """Context Menu"""

        row = self.rowAt(event.pos().y())
        totalRows = self.proxyModel.rowCount()

        if 0 <= row < totalRows:

            menu = QMenu()
            menu.setFont(self.parent.font())
            menu.addAction(_("Copy to command"))
            # menu.addAction(_("Remove"))
            menu.addAction(_("Delete"))

            if action := menu.exec_(event.globalPos()):
                result = action.text()

                if result == _("Copy to command"):
                    self.copyCommand()
                if result == _("Delete"):
                    self.deleteSelectedRows()
                elif result == _("Remove"):
                    self.removeSelection()
Exemple #19
0
 def rightClickMenu(self, event):
     """
     The right click menu of the move list
     :param event: The event (here right click) that makes the menu come up
     :return: No return
     """
     menu = QMenu()
     # Add a button in the menu that when clicked, it puts a move in modifying state
     menu.addAction(
         "Modify Move", lambda: self.modifyMove(self.__listOfMoveLabels.
                                                selectedItems()[0]))
     # Add a button in the menu that when clicked, it deletes a move in the list
     menu.addAction(
         "Delete Move", lambda: self.deleteMove(self.__listOfMoveLabels.
                                                selectedItems()[0]))
     menu.exec_(self.__listOfMoveLabels.mapToGlobal(event))
    def createHelpMenu(self):
        helpViewAction = QAction("Help", self)
        aboutViewAction = QAction("About", self)

        helpMenu = QMenu("Help")
        helpMenu.addAction(helpViewAction)
        helpMenu.addAction(aboutViewAction)

        return helpMenu
Exemple #21
0
class TrayIcon(QSystemTrayIcon):
    on_settings = Signal()

    host: "Host"

    def __init__(self, host: "Host"):
        global _tray_icon
        super().__init__(QIcon(":/runekit/ui/trayicon.png"))

        _tray_icon = self

        self.host = host
        self._setup_menu()
        self.setContextMenu(self.menu)

    def _setup_menu(self):
        if not hasattr(self, "menu"):
            self.menu = QMenu("RuneKit")

        self.menu.clear()

        self._setup_app_menu("", self.menu)

        self.menu.addSeparator()
        self.menu_settings = self.menu.addAction("Settings")
        self.menu_settings.triggered.connect(self.on_settings)
        self.menu.addAction(
            QIcon.fromTheme("application-exit"),
            "Exit",
            lambda: QCoreApplication.instance().quit(),
        )

    def _setup_app_menu(self, path: str, menu: QMenu):
        for app_id, manifest in self.host.app_store.list_app(path):
            if manifest is None:
                # Folder
                submenu = menu.addMenu(QIcon.fromTheme("folder"), app_id)
                self._setup_app_menu(app_id, submenu)
                continue

            app_menu = menu.addAction(manifest["appName"])
            app_menu.triggered.connect(
                lambda _=None, app_id=app_id: self.host.launch_app_id(app_id)
            )

            icon = self.host.app_store.icon(app_id)
            if icon:
                app_menu.setIcon(icon)

    @Slot()
    def update_menu(self):
        self._setup_menu()
Exemple #22
0
 def __open_menu(self, point):
     """ Initializes and shows context menu """
     menu = QMenu()
     selected_item = self.itemAt(point)
     if selected_item:
         edit_question = QAction('Редактировать список стоп-слов', menu)
         edit_question.triggered.connect(self.__open_stop_word_edit_dialog)
         menu.addAction(edit_question)
     menu.exec_(self.mapToGlobal(point))
    def contextMenuEvent(self, event:QContextMenuEvent):
        menu = QMenu("", self)
        menu.addAction('Add POI', self.POIView.menu_add_empty_poi)

        remove = menu.addAction('Remove', self.POIView.menu_remove_poi)
        if len(self.POIView.multiPOIList.selectedItems()) == 0:
            remove.setDisabled(True)

        # remove = menu.addAction('Remove both locally and remotely...', self.POIView.menu_remove_poi_remotely)
        # if len(self.POIView.multiPOIList.selectedItems()) == 0:
        #     remove.setDisabled(True)

        menu.exec_(event.globalPos())
Exemple #24
0
    def contextMenuEvent(self, event: QGraphicsSceneContextMenuEvent) -> None:
        menu = QMenu("Menu", self.parent)

        object_details_action = QAction(self.object_dialog_text)
        object_details_action.triggered.connect(self.on_click)
        menu.addAction(object_details_action)

        # Not all locations have valid objectives. Off-map spawns, for example,
        # have no mission types.
        if list(self.mission_target.mission_types(for_player=True)):
            new_package_action = QAction(f"New package")
            new_package_action.triggered.connect(self.open_new_package_dialog)
            menu.addAction(new_package_action)

        self.add_context_menu_actions(menu)

        menu.exec_(event.screenPos())
    def contextMenuEvent(self, event: QContextMenuEvent):
        """This event handler, for event event, can be reimplemented in a
        subclass to receive widget context menu events.

        The handler is called when the widget's contextMenuPolicy
        is Qt::DefaultContextMenu.

        The default implementation ignores the context event.
        See the QContextMenuEvent documentation for more details.

        Arguments:
            event (QContextMenuEvent): The event
        """
        self._event = event  # debug

        # TODO: Should we work based on slection or what we have clicked at the moment?
        self.menu = QMenu(self)
        self.menu._d = self.menu.addAction("Delete")
        self.menu._r = self.menu.addAction("Rename")

        self.menu._d.triggered.connect(lambda: self.do_menu_delete(event))
        self.menu._r.triggered.connect(lambda: self.do_menu_rename(event))

        self.menu._action = self.menu.exec_(self.mapToGlobal(event.pos()))
Exemple #26
0
    def __init__(self, model, parent, main_window):

        self.figure = Figure(dpi=main_window.logicalDpiX())
        super().__init__(self.figure)

        FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding,
                                   QSizePolicy.Expanding)

        FigureCanvas.updateGeometry(self)
        self.model = model
        self.main_window = main_window
        self.parent = parent

        self.rubber_band = QRubberBand(QRubberBand.Rectangle, self)
        self.band_origin = QtCore.QPoint()
        self.x_plot_origin = None
        self.y_plot_origin = None

        self.colorbar = None
        self.data_indicator = None
        self.tally_data_indicator = None
        self.image = None

        self.menu = QMenu(self)
Exemple #27
0
    def contextMenuEvent(self, event):
        contextMenu = QMenu(self)

        newAction = contextMenu.addAction("New")
        openAction = contextMenu.addAction("Open")
        quitAction = contextMenu.addAction("Quit")

        action = contextMenu.exec_(self.mapToGlobal(event.pos()))

        if action == quitAction:
            self.close()

        if action == openAction:
            # model = self.sti
            # indices = self.table.selectionModel().selectedRows()
            # for index in sorted(indices):
            #     model.removeRow(index.row())
            index_list = []
            for model_index in self.table.selectionModel().selectedRows():
                index = QtCore.QPersistentModelIndex(model_index)
                index_list.append(index)

            for index in index_list:
                self.sti.removeRow(index.row())
Exemple #28
0
    def setModel(self, model):
        # Assign model to view by calling the parent method
        super().setModel(model)

        # Additional: Create a context menu for showing/hiding the table headers
        # (columns)
        self.__header_context_menu = QMenu(self)
        header = self.horizontalHeader()

        # Iterate through each column
        for i in range(header.count()):
            column_label = model.headerData(section=i,
                                            orientation=Qt.Horizontal,
                                            role=Qt.DisplayRole)

            # Add a checkable action corresponding to each column
            action = self.__header_context_menu.addAction(column_label)
            action.setCheckable(True)
            action.setChecked(True)

            # Each action will show/hide the corresponding column referenced by its
            # index depending on if the action is checked or not (toggled)
            action.toggled.connect(lambda toggled, index=i: header.showSection(
                index) if toggled else header.hideSection(index))
Exemple #29
0
class MyTableView(QTableView):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.contextMenu = QMenu()
        self.contextMenu.addAction("copy").triggered.connect(
            self.copySelectionToClipboard)
        headerView: QHeaderView = self.horizontalHeader()
        headerView.setSectionResizeMode(QHeaderView.ResizeToContents)

    def copySelectionToClipboard(self):
        indexes = self.selectedIndexes()
        indexes.sort(key=lambda i: (i.row(), i.column()))
        model = self.model()
        stringIO = io.StringIO()
        last = indexes[0].row()
        for index in indexes:
            if index.row() != last:
                last = index.row()
                stringIO.write('\n')
            info = model.data(index, Qt.DisplayRole)
            if info is None:
                info = ''
            stringIO.write(info)
            stringIO.write('\t')
        clipboard = QApplication.clipboard()
        clipboard.setText(stringIO.getvalue())

    def keyPressEvent(self, event):
        if event.matches(QKeySequence.Copy):
            self.copySelectionToClipboard()
            event.accept()
        else:
            super().keyPressEvent(event)

    def contextMenuEvent(self, event: QContextMenuEvent):
        self.contextMenu.popup(event.globalPos())
Exemple #30
0
    def setupTopBar(self):
        tb = QWidget()
        tbl = QHBoxLayout()
        tb.setLayout(tbl)
        tb.setStyleSheet("border: 3px solid black; background-color: #7289da;")

        tbl.setAlignment(Qt.AlignLeft)

        homeBtn = QPushButton()
        homeBtn.setIcon(self.client.ico)

        saTB = QToolBar()
        self.ServerActions = QMenu()
        self.ServerActions.setTitle("⠀           Home             ⠀")

        saTB.addAction(self.ServerActions.menuAction())

        tbl.addWidget(homeBtn)
        tbl.addWidget(saTB)
        saTB.setStyleSheet("border: 1px solid black;")
        homeBtn.setStyleSheet("border: none;")
        self.ServerActions.setStyleSheet("border: none;")

        return tb
Exemple #31
0
    def __init__(self):
        # Create a Qt application
        self.app = QApplication(sys.argv)
        self.main = BT('main.ui')

        self.splash = QSplashScreen(QPixmap('../images/boot.jpg'))
        self.splash.show()

        menu = QMenu()
        showAction = menu.addAction("显示")
        hideAction = menu.addAction("隐藏")
        closeAction = menu.addAction("退出")

        showAction.triggered.connect(
            lambda event: self.show(showAction, hideAction))
        hideAction.triggered.connect(
            lambda event: self.hide(showAction, hideAction))
        closeAction.triggered.connect(self.exit)

        self.tray = QSystemTrayIcon()
        self.tray.setIcon(QIcon("../icon/icon.ico"))
        self.tray.setContextMenu(menu)
        self.tray.show()
        self.tray.setToolTip("")
Exemple #32
0
class CustomLineEdit(QTextEdit):
    def __init__(self, parent=None):
        super(CustomLineEdit, self).__init__()
        self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.__contextMenu)

    def __contextMenu(self):
        # self._normalMenu = self.createStandardContextMenu() # Remove this for standard menu
        self._normalMenu = QMenu()
        self._addCustomMenuItems(self._normalMenu)
        self._normalMenu.exec_(QCursor.pos())

    def _addCustomMenuItems(self, menu):
        # menu.addSeparator() # add a seperator
        menu.addAction("Change Colour", self.colourchange)
        menu.addAction("Change Font", self.changefont)
        menu.addAction("Edit Title", self.changetitle)

    def changetitle(self):
        popup = ExamplePopup(self)
        popup.setGeometry(100, 200, 100, 100)
        popup.exec_()

    def changefont(self):
        dialog = QFontDialog()
        dialog.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
        dialog.exec()
        font = dialog.selectedFont()
        self.setFont(font)

    def colourchange(self):
        dialog = QColorDialog()
        dialog.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
        dialog.exec()
        color = dialog.selectedColor()
        self.setStyleSheet(f"background-color: {color.name()}")
Exemple #33
0
class TextInput():

    def __init__(self, suggestion='', input_valid_callback = None):

        self.input_valid_callback = input_valid_callback

        self.menu = QMenu()

        self.lb = QWidgetAction(None)

        self.widget = QWidget(None)
        self.layout = QHBoxLayout()
        self.button = QPushButton()
        self.button.setText("Ok")
        self.le = QLineEdit()

        self.layout.addWidget(self.le)
        self.layout.addWidget(self.button)
        self.widget.setLayout(self.layout)

        self.button.pressed.connect(self.done)

        self.le.textEdited.connect(self.check_input)
        self.eventFilter = EnterKeyPressFilter()
        self.eventFilter.callback = self.done
        self.le.installEventFilter(self.eventFilter)

        self.lb.setDefaultWidget(self.widget)

        self.menu.addAction(self.lb)

        self.le.setText(suggestion)
        self.le.setFocus()
        self.le.selectAll()

        self.result = None

    def show(self, pos):
        self.menu.exec_(pos)
        return self.result

    def done(self):
        self.result = self.le.text()
        self.menu.close()

    def check_input(self):
        if self.input_valid_callback is not None:
            result = self.input_valid_callback(self.le.text())
            if result:
                self.le.setStyleSheet('')
            else:
                self.le.setStyleSheet('background: pink')



        return None
    def context_menu_event(self, event):
        state = self.state()
        context_menu = QMenu()
        launch_action = context_menu.addAction("Launch")
        launch_action.setEnabled(state == QWebEngineDownloadItem.DownloadCompleted)
        show_in_folder_action = context_menu.addAction("Show in Folder")
        show_in_folder_action.setEnabled(state == QWebEngineDownloadItem.DownloadCompleted)
        cancel_action = context_menu.addAction("Cancel")
        cancel_action.setEnabled(state == QWebEngineDownloadItem.DownloadInProgress)
        remove_action = context_menu.addAction("Remove")
        remove_action.setEnabled(state != QWebEngineDownloadItem.DownloadInProgress)

        chosen_action = context_menu.exec_(event.globalPos())
        if chosen_action == launch_action:
            self._launch()
        elif chosen_action == show_in_folder_action:
            DownloadWidget.open_file(QFileInfo(self._download_item.path()).absolutePath())
        elif chosen_action == cancel_action:
            self._download_item.cancel()
        elif chosen_action == remove_action:
            self.remove_requested.emit()
Exemple #35
0
class MainWindow(Ui_Form):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.appname = "poliBeePsync"
        self.settings_fname = 'pbs-settings.ini'
        self.data_fname = 'pbs.data'
        self.setupUi(self)
        self.w = QWidget()

        self.status_signal = MySignal()
        self.status_signal.sig.connect(self.update_status_bar)

        self.logging_signal = MySignal()
        self.logging_signal.sig.connect(self.myStream_message)
        logging_console_hdl = SignalLoggingHandler(self.logging_signal)
        logger.addHandler(logging_console_hdl)
        commonlogger.addHandler(logging_console_hdl)

        self.about_text()
        self.timer = QTimer(self)

        # settings_path is a string containing the path to settings
        self.settings_path = None
        # settings is a dictionary of settings
        self.settings = None
        # load_settings() sets settings_path and settings
        self.load_settings()
        self.load_data()

        self.timer.timeout.connect(self.syncfiles)
        self.timer.start(1000 * 60 * int(self.settings['UpdateEvery']))

        self.loginthread = LoginThread(self.user, self)
        self.loginthread.signal_error.sig.connect(self.update_status_bar)
        self.loginthread.signal_ok.sig.connect(self.update_status_bar)

        self.refreshcoursesthread = RefreshCoursesThread(self.user, self)
        self.refreshcoursesthread.dumpuser.sig.connect(self.dumpUser)
        self.refreshcoursesthread.newcourses.sig.connect(self.addtocoursesview)
        self.refreshcoursesthread.newcourses.sig.connect(self.syncnewcourses)
        self.refreshcoursesthread.removable.sig.connect(self.rmfromcoursesview)

        self.downloadthread = DownloadThread(self.user,
                                             self.settings['RootFolder'],
                                             self)
        self.downloadthread.dumpuser.sig.connect(self.dumpUser)
        self.downloadthread.download_signal.connect(
            self.update_course_download)
        self.downloadthread.initial_sizes.connect(self.setinizialsizes)
        self.downloadthread.date_signal.connect(self.update_file_localtime)

        self._window.userCode.setText(str(self.user.username))
        self._window.userCode.editingFinished.connect(self.setusercode)
        self._window.password.setText(self.user.password)
        self._window.password.editingFinished.connect(self.setpassword)
        self._window.trylogin.clicked.connect(self.testlogin)

        self._window.courses_model = CoursesListModel(self.user.
                                                      available_courses)
        self._window.coursesView.setModel(self._window.courses_model)
        self._resizeview()
        self._window.refreshCourses.clicked.connect(self.refreshcourses)

        self._window.syncNow.clicked.connect(self.syncfiles)

        if self.settings['SyncNewCourses'] == str(True):
            self._window.sync_new = Qt.Checked
        else:
            self._window.sync_new = Qt.Unchecked

        self._window.rootfolder.setText(self.settings['RootFolder'])
        self._window.rootfolder.textChanged.connect(self.rootfolderslot)

        self._window.addSyncNewCourses.setCheckState(self._window.sync_new)
        self._window.addSyncNewCourses.stateChanged.connect(self.syncnewslot)

        self._window.timerMinutes.setValue(int(self.settings['UpdateEvery']))
        self._window.timerMinutes.valueChanged.connect(self.updateminuteslot)

        self._window.changeRootFolder.clicked.connect(self.chooserootdir)
        self._window.version_label.setText("Current version: {}."
                                           .format(__version__))
        self._window.check_version.clicked.connect(self.checknewversion)

        self.trayIconMenu = QMenu()
        self.trayIcon = QSystemTrayIcon(self.icon, self.w)
        self.trayIcon.activated.connect(self._activate_traymenu)
        self.createTray()

    @Slot()
    def _resizeview(self, **kwargs):
        self._window.coursesView.setColumnWidth(3, 160)
        self._window.coursesView.resizeColumnToContents(1)
        self._window.coursesView.setColumnWidth(0, 320)

    def checknewversion(self):
        rawdata = requests.get('https://pypi.python.org/pypi/'
                               'poliBeePsync/json')
        latest = json.loads(rawdata.text)['info']['version']
        self._window.version_label.setTextFormat(Qt.RichText)
        self._window.version_label.setOpenExternalLinks(True)
        self._window.version_label.setLocale(QLocale(QLocale.English,
                                                     QLocale.UnitedStates))
        self._window.version_label.setScaledContents(True)
        self._window.version_label.setWordWrap(True)
        if latest != __version__:
            newtext = """<p>Current version: {}.<br>
Latest version: {}. </p>
<p>Visit <a
href='https://jacotsu.github.io/polibeepsync/dirhtml/index.html\
        #how-to-install-upgrade-remove'>here</a> to find out how to upgrade.
""".format(__version__, latest)
        else:
            newtext = "Current version: {} up-to-date.".format(__version__)
        self._window.version_label.setText(newtext)

    def _update_time(self, folder, file, path_list):
        logger.debug(f'inside {folder.name}')
        for path in path_list:
            logger.debug(f'namegoto: {path}')
            folder_dict = {'name': path}
            fakefolder = Folder(folder_dict)
            logger.debug(f'contained folders:  {folder.folders}')
            ind = folder.folders.index(fakefolder)
            goto = folder.folders[ind]
            self._update_time(goto, file, path_list)

        if file in folder.files:
            ind = folder.files.index(file)
            thisfile = folder.files[ind]
            thisfile.local_creation_time = file.local_creation_time

    @Slot(tuple)
    def update_file_localtime(self, data, **kwargs):
        course, coursefile, path = data
        rootpath = os.path.join(self.settings['RootFolder'],
                                course.save_folder_name)
        if path.startswith(rootpath):
            partial = path[len(rootpath):]
        path_list = filter(None, partial.split(os.path.sep))
        self._update_time(course.documents, coursefile, path_list)

    @Slot(Course)
    def update_course_download(self, course, **kwargs):
        if course in self.user.available_courses:
            updating = self.user.available_courses[course.name]
            updating.downloaded_size = course.downloaded_size
            row = self._window.courses_model.courses.index(updating)
            where = self._window.courses_model.index(row, 3)
            self._window.courses_model.dataChanged.emit(where, where)

    @Slot(Course)
    def setinizialsizes(self, course, **kwargs):
        if course in self.user.available_courses:
            updating = self.user.available_courses[course.name]
            updating.downloaded_size = course.downloaded_size
            updating.total_file_size = course.total_file_size
            row = self._window.courses_model.courses.index(updating)
            where = self._window.courses_model.index(row, 3)
            self._window.courses_model.dataChanged.emit(where, where)
            self.dumpUser()

    @Slot(list)
    def syncnewcourses(self, newlist):
        if self.settings['SyncNewCourses'] == 'True':
            for elem in newlist:
                elem.sync = True

    def load_settings(self):
        for path in [user_config_dir(self.appname),
                     user_data_dir(self.appname)]:
            try:
                os.makedirs(path, exist_ok=True)
            except OSError:
                logger.critical('OSError while calling os.makedirs.',
                                exc_info=True)
                logger.critical(f"I couldn't create {path}.\nStart"
                                " poliBeePsync with --debug "
                                "error to get more details.")
        self.settings_path = os.path.join(user_config_dir(self.appname),
                                          self.settings_fname)
        defaults = {
            'UpdateEvery': '60',
            'RootFolder': os.path.join(os.path.expanduser('~'), self.appname),
            'SyncNewCourses': 'False'
        }
        self.settings = filesettings.settingsFromFile(self.settings_path,
                                                      defaults)

    def load_data(self):
        try:
            with open(os.path.join(user_data_dir(self.appname),
                                   self.data_fname), 'rb') as f:
                self.user = pickle.load(f)
                self.user.password = keyring\
                        .get_password('beep.metid.polimi.it',
                                      self.user.username)
                logger.info("Data has been loaded successfully.")
        except (EOFError, pickle.PickleError):
            logger.error('Settings corrupted', exc_info=True)
            self.user = User('', '')

        except FileNotFoundError:
            logger.error('Settings file not found.')
            self.user = User('', '')
            logger.error("I couldn't find data in the"
                         " predefined directory. Ignore this"
                         "message if you're using poliBeePsync"
                         " for the first time.")

    @Slot(str)
    def update_status_bar(self, status):
        self._window.statusbar.showMessage(status)

    @Slot(int)
    def syncnewslot(self, state):
        if state == 2:
            self.settings['SyncNewCourses'] = 'True'
        else:
            self.settings['SyncNewCourses'] = 'False'
        filesettings.settingsToFile(self.settings, self.settings_path)

    @Slot(int)
    def updateminuteslot(self, minutes):
        self.settings['UpdateEvery'] = str(minutes)
        filesettings.settingsToFile(self.settings, self.settings_path)
        self.timer.start(1000 * 60 * int(self.settings['UpdateEvery']))

    @Slot(str)
    def rootfolderslot(self, path):
        self.settings['RootFolder'] = path
        filesettings.settingsToFile(self.settings, self.settings_path)

    @Slot()
    def chooserootdir(self):
        currentdir = self.settings['RootFolder']
        flags = QFileDialog.DontResolveSymlinks | QFileDialog.ShowDirsOnly
        newroot = QFileDialog.getExistingDirectory(None,
                                                   "Open Directory",
                                                   currentdir, flags)
        if newroot != "" and str(newroot) != currentdir:
            self.settings['RootFolder'] = str(newroot)
            filesettings.settingsToFile(self.settings, self.settings_path)
            self._window.rootfolder.setText(newroot)
            # we delete the already present downloadthread and recreate it
            # because otherwise it uses the old download folder. I don't know
            # if there's a cleaner approach
            del self.downloadthread
            self.downloadthread = DownloadThread(self.user,
                                                 self.settings['RootFolder'],
                                                 self)
            self.downloadthread.dumpuser.sig.connect(self.dumpUser)
            self.dumpUser()

    @Slot()
    def setusercode(self):
        newcode = self._window.userCode.text()
        try:
            if len(newcode) == 8:
                self.user.username = newcode
                logger.info(f'User code changed to {newcode}.')
                keyring.set_password('beep.metid.polimi.it',
                                     self.user.username,
                                     self.user.password)
        except OSError:
            logger.critical("I couldn't save data to disk. Run"
                            " poliBeePsync with option --debug"
                            " error to get more details.")
            logger.error('OSError raised while trying to write the User'
                         'instance to disk.', exc_info=True)

    @Slot()
    def setpassword(self):
        newpass = self._window.password.text()
        self.user.password = newpass
        try:
            keyring.set_password('beep.metid.polimi.it',
                                 self.user.username,
                                 self.user.password)
            logger.info("Password changed.")
        except OSError:
            logger.critical("I couldn't save data to disk. Run"
                            " poliBeePsync with option --debug"
                            " error to get more details.")
            logger.error('OSError raised while trying to write the User'
                         'instance to disk.', exc_info=True)

    @Slot()
    def testlogin(self):
        if not self.loginthread.isRunning():
            self.loginthread.exiting = False
            self.loginthread.start()
            self.status_signal.sig.emit("Logging in, please wait.")

    @Slot(list)
    def addtocoursesview(self, addlist):
        for elem in addlist:
            self._window.courses_model.insertRows(0, 1, elem)

    @Slot(list)
    def rmfromcoursesview(self, removelist):
        for elem in removelist:
            index = self._window.courses_model.courses.index(elem)
            self._window.courses_model.removeRows(index, 1)

    @Slot()
    def dumpUser(self):
        # we don't use the message...
        with open(os.path.join(user_data_dir(self.appname),
                               self.data_fname), 'wb') as f:
            tmp_pw = self.user.password
            self.user.password = ''
            pickle.dump(self.user, f)
            self.user.password = tmp_pw

    @Slot()
    def refreshcourses(self):
        self.status_signal.sig.emit('Searching for online updates...'
                                'this may take a while.')
        if not self.loginthread.isRunning():
            self.loginthread.exiting = False
            self.loginthread.signal_ok.sig.connect(self.do_refreshcourses)
            self.loginthread.start()

    def do_refreshcourses(self):
        self.loginthread.signal_ok.sig.disconnect(self.do_refreshcourses)
        if not self.refreshcoursesthread.isRunning():
            self.refreshcoursesthread.start()

    @Slot()
    def syncfiles(self):
        # we delete the already present downloadthread and recreate it
        # because otherwise it uses the old download folder. I don't know
        # if there's a cleaner approach
        del self.downloadthread
        self.downloadthread = DownloadThread(self.user,
                                             self.settings['RootFolder'],
                                             self)
        self.downloadthread.dumpuser.sig.connect(self.dumpUser)

        self.refreshcoursesthread.finished.connect(self.do_syncfiles)
        self.refreshcourses()

    @Slot()
    def do_syncfiles(self):
        self.refreshcoursesthread.finished.disconnect(self.do_syncfiles)
        self.status_signal.sig.emit('Started syncing.')
        self.downloadthread.start()

    @Slot(str)
    def myStream_message(self, message):
        self._window.status.moveCursor(QTextCursor.End)
        self._window.status.insertPlainText(message + "\n")

    def restore_window(self):
        self._window.setWindowState(self.windowState() & ~Qt.WindowMinimized |
                                Qt.WindowActive)
        self._window.show()

    def createTray(self):
        restoreAction = QAction("&Restore", self, triggered=self.restore_window)
        quitAction = QAction("&Quit", self, triggered=qApp.quit)
        self.trayIconMenu.addAction(restoreAction)
        self.trayIconMenu.addAction(quitAction)
        self.trayIcon.setContextMenu(self.trayIconMenu)
        self.trayIcon.show()

    @Slot(str)
    def _activate_traymenu(self, reason):
        if reason == QSystemTrayIcon.ActivationReason.DoubleClick:
            self.restore_window()
        else:
            self.trayIconMenu.activateWindow()
            self.trayIconMenu.popup(QCursor.pos())

    def closeEvent(self, event):
        self._window.hide()
        event.ignore()

    def about_text(self):
        self._window.label_3 = QLabel()
        self._window.label_3.setTextFormat(Qt.RichText)
        self._window.label_3.setOpenExternalLinks(True)
        self._window.label_3.setLocale(QLocale(QLocale.English,
                                               QLocale.UnitedStates))
        self._window.label_3.setScaledContents(True)
        self._window.label_3.setWordWrap(True)
        text = """
<html>
<head/>
<body>
  <p>poliBeePsync is a program written by Davide Olianas,
released under GNU GPLv3+.</p>
  <p>Feel free to contact me at <a
  href=\"mailto:[email protected]\">[email protected]</a> for
  suggestions and bug reports.</p>
  <p>More information is available on the
  <a href=\"http://www.davideolianas.com/polibeepsync\">
  <span style=\" text-decoration: underline; color:#0000ff;\">
  official website</span></a>.
  </p>
</body>
</html>
"""

        self._window.label_3.setText(QApplication.translate("Form", text,
                                                            None))
Exemple #36
0
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.appname = "poliBeePsync"
        self.settings_fname = 'pbs-settings.ini'
        self.data_fname = 'pbs.data'
        self.setupUi(self)
        self.w = QWidget()

        self.status_signal = MySignal()
        self.status_signal.sig.connect(self.update_status_bar)

        self.logging_signal = MySignal()
        self.logging_signal.sig.connect(self.myStream_message)
        logging_console_hdl = SignalLoggingHandler(self.logging_signal)
        logger.addHandler(logging_console_hdl)
        commonlogger.addHandler(logging_console_hdl)

        self.about_text()
        self.timer = QTimer(self)

        # settings_path is a string containing the path to settings
        self.settings_path = None
        # settings is a dictionary of settings
        self.settings = None
        # load_settings() sets settings_path and settings
        self.load_settings()
        self.load_data()

        self.timer.timeout.connect(self.syncfiles)
        self.timer.start(1000 * 60 * int(self.settings['UpdateEvery']))

        self.loginthread = LoginThread(self.user, self)
        self.loginthread.signal_error.sig.connect(self.update_status_bar)
        self.loginthread.signal_ok.sig.connect(self.update_status_bar)

        self.refreshcoursesthread = RefreshCoursesThread(self.user, self)
        self.refreshcoursesthread.dumpuser.sig.connect(self.dumpUser)
        self.refreshcoursesthread.newcourses.sig.connect(self.addtocoursesview)
        self.refreshcoursesthread.newcourses.sig.connect(self.syncnewcourses)
        self.refreshcoursesthread.removable.sig.connect(self.rmfromcoursesview)

        self.downloadthread = DownloadThread(self.user,
                                             self.settings['RootFolder'],
                                             self)
        self.downloadthread.dumpuser.sig.connect(self.dumpUser)
        self.downloadthread.download_signal.connect(
            self.update_course_download)
        self.downloadthread.initial_sizes.connect(self.setinizialsizes)
        self.downloadthread.date_signal.connect(self.update_file_localtime)

        self._window.userCode.setText(str(self.user.username))
        self._window.userCode.editingFinished.connect(self.setusercode)
        self._window.password.setText(self.user.password)
        self._window.password.editingFinished.connect(self.setpassword)
        self._window.trylogin.clicked.connect(self.testlogin)

        self._window.courses_model = CoursesListModel(self.user.
                                                      available_courses)
        self._window.coursesView.setModel(self._window.courses_model)
        self._resizeview()
        self._window.refreshCourses.clicked.connect(self.refreshcourses)

        self._window.syncNow.clicked.connect(self.syncfiles)

        if self.settings['SyncNewCourses'] == str(True):
            self._window.sync_new = Qt.Checked
        else:
            self._window.sync_new = Qt.Unchecked

        self._window.rootfolder.setText(self.settings['RootFolder'])
        self._window.rootfolder.textChanged.connect(self.rootfolderslot)

        self._window.addSyncNewCourses.setCheckState(self._window.sync_new)
        self._window.addSyncNewCourses.stateChanged.connect(self.syncnewslot)

        self._window.timerMinutes.setValue(int(self.settings['UpdateEvery']))
        self._window.timerMinutes.valueChanged.connect(self.updateminuteslot)

        self._window.changeRootFolder.clicked.connect(self.chooserootdir)
        self._window.version_label.setText("Current version: {}."
                                           .format(__version__))
        self._window.check_version.clicked.connect(self.checknewversion)

        self.trayIconMenu = QMenu()
        self.trayIcon = QSystemTrayIcon(self.icon, self.w)
        self.trayIcon.activated.connect(self._activate_traymenu)
        self.createTray()