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)
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))
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())
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())
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())
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
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)
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, ""])
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'))
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
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])
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())
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
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
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()
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
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()
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())
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()))
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)
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())
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))
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())
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
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("")
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()}")
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()
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))
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()