class ServicesQWidget(QWidget): """ Class wo create services QWidget """ def __init__(self, parent=None): super(ServicesQWidget, self).__init__(parent) # Fields self.services = None self.services_tree_widget = QTreeWidget() self.services_list_widget = QListWidget() self.service_data_widget = ServiceDataQWidget() self.services_dashboard = ServicesDashboardQWidget() def initialize(self): """ Initialize QWidget """ layout = QGridLayout() self.setLayout(layout) layout.setContentsMargins(0, 0, 0, 0) # Services dashboard self.services_dashboard.initialize() for state in self.services_dashboard.states_btns: self.services_dashboard.states_btns[state].clicked.connect( lambda _, s=state: self.filter_services(state=s) ) layout.addWidget(self.services_dashboard, 0, 0, 1, 2) layout.addWidget(get_frame_separator(), 1, 0, 1, 2) # Services QTreeWidget self.services_tree_widget.setIconSize(QSize(32, 32)) self.services_tree_widget.setAlternatingRowColors(True) self.services_tree_widget.header().close() layout.addWidget(self.services_tree_widget, 2, 0, 1, 1) # Services QListWidget self.services_list_widget.clicked.connect(self.update_service_data) self.services_list_widget.hide() layout.addWidget(self.services_list_widget, 2, 0, 1, 1) # Service DataWidget self.service_data_widget.initialize() layout.addWidget(self.service_data_widget, 2, 1, 1, 1) def filter_services(self, state): """ Filter services with the wanted state :param state: state of service: OK, WARNING, NOT_MONITORED, DOWNTIME :return: """ # Clear QListWidget and update filter buttons of services dashboard self.services_list_widget.clear() for btn_state in self.services_dashboard.states_btns: if btn_state != state: self.services_dashboard.states_btns[btn_state].setChecked(False) # Update QWidgets if self.sender().isChecked(): self.set_filter_items(state) self.services_tree_widget.hide() self.services_list_widget.show() else: self.services_tree_widget.show() self.services_list_widget.hide() def set_filter_items(self, state): """ Add filter items to QListWidget corresponding to "state" :param state: state of service to filter :type state: str """ services_added = False if state in 'NOT_MONITORED': for service in self.services: if not service.data['active_checks_enabled'] and \ not service.data['passive_checks_enabled']and \ not service.data['ls_downtimed'] and \ not service.data['ls_acknowledged']: self.add_filter_item(service) services_added = True elif state in 'DOWNTIME': for service in self.services: if service.data['ls_downtimed']: self.add_filter_item(service) services_added = True elif state in 'ACKNOWLEDGE': for service in self.services: if service.data['ls_acknowledged']: self.add_filter_item(service) services_added = True else: for service in self.services: if service.data['ls_state'] in state: self.add_filter_item(service) services_added = True if not services_added: not_added_item = QListWidgetItem() not_added_item.setData(Qt.DecorationRole, QIcon(settings.get_image('services_ok'))) not_added_item.setData(Qt.DisplayRole, _('No such services to display...')) self.services_list_widget.addItem(not_added_item) def add_filter_item(self, filter_item): """ Add filter item to QListWidget :param filter_item: filter item (service) :type filter_item: alignak_app.items.service.Service """ item = QListWidgetItem() monitored = \ filter_item.data['passive_checks_enabled'] + filter_item.data['active_checks_enabled'] icon_name = get_icon_name( filter_item.item_type, filter_item.data['ls_state'], filter_item.data['ls_acknowledged'], filter_item.data['ls_downtimed'], monitored ) item.setData(Qt.DecorationRole, QIcon(settings.get_image(icon_name))) item.setData(Qt.DisplayRole, filter_item.get_display_name()) item.setData(Qt.UserRole, filter_item.item_id) item.setToolTip(filter_item.get_tooltip()) self.services_list_widget.addItem(item) def update_widget(self, services): """ Update the QTreeWidget and its items :param services: list of :class:`Services <alignak_app.items.service.Service>` items :type services: list """ self.services = services # Update services dashboard self.services_dashboard.update_widget(self.services) # Clear QTreeWidget self.services_tree_widget.clear() self.services_tree_widget.setIconSize(QSize(16, 16)) if self.services: # Set as "Global" aggregation who are empty for service in self.services: if not service.data['aggregation']: service.data['aggregation'] = 'Global' # First sort list by state then by aggregation newlist = sorted( self.services, key=lambda s: itemgetter('ls_state', 'ls_acknowledged', 'aggregation')(s.data) ) self.services = newlist # Get list of aggregations aggregations = [] for service in self.services: if service.data['aggregation'] not in aggregations: aggregations.append(service.data['aggregation']) # Add QTreeWidgetItems for aggregation in aggregations: main_tree = QTreeWidgetItem() main_tree.setText(0, aggregation) main_tree.setIcon(0, QIcon(settings.get_image('tree'))) main_tree.setToolTip(0, aggregation) for service in self.services: if service.data['aggregation'] == aggregation: service_tree = ServiceTreeItem() service_tree.initialize(service) service_tree.setToolTip(0, service.get_tooltip()) self.services_tree_widget.clicked.connect(self.update_service_data) main_tree.addChild(service_tree) self.services_tree_widget.addTopLevelItem(main_tree) self.service_data_widget.hide() else: # If no services, reset service item to None and hide data widget self.service_data_widget.service_item = None self.service_data_widget.hide() def update_service_data(self): # pragma: no cover """ Update ServiceDataqWidget """ service_item = self.sender().currentItem() if isinstance(service_item, (ServiceTreeItem, QListWidgetItem)): service = None # Get service if isinstance(service_item, ServiceTreeItem): service = data_manager.get_item('service', '_id', service_item.service_id) elif isinstance(service_item, QListWidgetItem): service = data_manager.get_item('service', '_id', service_item.data(Qt.UserRole)) if not service: service = self.service_data_widget.service_item # Update QWidgets self.services_tree_widget.setMaximumWidth(self.width() * 0.5) self.services_list_widget.setMaximumWidth(self.width() * 0.5) self.service_data_widget.setMaximumWidth(self.width() * 0.5) self.service_data_widget.update_widget(service) self.services_dashboard.update_widget(self.services) self.service_data_widget.show() # Update Service Items (ServiceTreeItem, QListWidgetItem) if isinstance(service_item, ServiceTreeItem): service_item.update_item() else: monitored = \ service.data['passive_checks_enabled'] + service.data['active_checks_enabled'] icon_name = get_icon_name( 'service', service.data['ls_state'], service.data['ls_acknowledged'], service.data['ls_downtimed'], monitored ) service_item.setData(Qt.DecorationRole, QIcon(settings.get_image(icon_name))) service_item.setData(Qt.DisplayRole, service.get_display_name()) service_item.setToolTip(service.get_tooltip())
class CollapsibleDialog(QDialog): """a dialog to which collapsible sections can be added; reimplement define_sections() to define sections and add them as (title, widget) tuples to self.sections reimplemented from http://www.fancyaddress.com/blog/qt-2/create-something-like-the-widget-box-as-in-the-qt-designer/ """ def __init__(self, parent = None): super().__init__(parent) self.tree = QTreeWidget() self.tree.setHeaderHidden(True) layout = QVBoxLayout() layout.addWidget(self.tree) self.setLayout(layout) self.tree.setIndentation(0) self.sections = [] self.section_dic = {} self.define_sections() self.add_sections() def add_sections(self): """adds a collapsible sections for every (title, widget) tuple in self.sections """ for (i, (title, widget)) in enumerate(self.sections): button = self.add_button(title) section = self.add_widget(button, widget) button.addChild(section) if i == 0: button.setExpanded(True) self.section_dic[i] = (button, section) def define_sections(self): """reimplement this to define all your sections and add them as (title, widget) tuples to self.sections """ widget = QFrame(self.tree) layout = QHBoxLayout(widget) layout.addWidget(QLabel("Bla")) layout.addWidget(QLabel("Blubb")) title = "Section 1" self.sections.append((title, widget)) def add_button(self, title): """creates a QTreeWidgetItem containing a button to expand or collapse its section """ item = QTreeWidgetItem() self.tree.addTopLevelItem(item) self.tree.setItemWidget(item, 0, SectionExpandButton(item, text = title)) return item def add_widget(self, button, widget): """creates a QWidgetItem containing the widget, as child of the button-QWidgetItem """ section = QTreeWidgetItem(button) section.setDisabled(True) self.tree.setItemWidget(section, 0, widget) return section @pyqtSlot(int, int) def proceed_sections(self, old_section, new_section): """collapses old section and expands next section """ (button_new, _) = self.section_dic[new_section] (button_old, _) = self.section_dic[old_section] button_new.setExpanded(True) button_old.setExpanded(False) try: self.sender().setChecked(False) # if sent from a button, un-press it except: pass
class ServicesQWidget(QWidget): """ Class wo create services QWidget """ def __init__(self, parent=None): super(ServicesQWidget, self).__init__(parent) # Fields self.services = None self.services_tree_widget = QTreeWidget() self.services_list_widget = QListWidget() self.service_data_widget = ServiceDataQWidget() self.services_dashboard = ServicesDashboardQWidget() def initialize(self): """ Initialize QWidget """ layout = QGridLayout() self.setLayout(layout) layout.setContentsMargins(0, 0, 0, 0) # Services dashboard self.services_dashboard.initialize() for state in self.services_dashboard.states_btns: self.services_dashboard.states_btns[state].clicked.connect( lambda _, s=state: self.filter_services(state=s)) layout.addWidget(self.services_dashboard, 0, 0, 1, 2) layout.addWidget(get_frame_separator(), 1, 0, 1, 2) # Services QTreeWidget self.services_tree_widget.setIconSize(QSize(32, 32)) self.services_tree_widget.setAlternatingRowColors(True) self.services_tree_widget.header().close() layout.addWidget(self.services_tree_widget, 2, 0, 1, 1) # Services QListWidget self.services_list_widget.clicked.connect(self.update_service_data) self.services_list_widget.hide() layout.addWidget(self.services_list_widget, 2, 0, 1, 1) # Service DataWidget self.service_data_widget.initialize() layout.addWidget(self.service_data_widget, 2, 1, 1, 1) def filter_services(self, state): """ Filter services with the wanted state :param state: state of service: OK, WARNING, NOT_MONITORED, DOWNTIME :return: """ # Clear QListWidget and update filter buttons of services dashboard self.services_list_widget.clear() for btn_state in self.services_dashboard.states_btns: if btn_state != state: self.services_dashboard.states_btns[btn_state].setChecked( False) # Update QWidgets if self.sender().isChecked(): self.set_filter_items(state) self.services_tree_widget.hide() self.services_list_widget.show() else: self.services_tree_widget.show() self.services_list_widget.hide() def set_filter_items(self, state): """ Add filter items to QListWidget corresponding to "state" :param state: state of service to filter :type state: str """ services_added = False if state in 'NOT_MONITORED': for service in self.services: if not service.data['active_checks_enabled'] and \ not service.data['passive_checks_enabled']and \ not service.data['ls_downtimed'] and \ not service.data['ls_acknowledged']: self.add_filter_item(service) services_added = True elif state in 'DOWNTIME': for service in self.services: if service.data['ls_downtimed']: self.add_filter_item(service) services_added = True elif state in 'ACKNOWLEDGE': for service in self.services: if service.data['ls_acknowledged']: self.add_filter_item(service) services_added = True else: for service in self.services: if service.data['ls_state'] in state: self.add_filter_item(service) services_added = True if not services_added: not_added_item = QListWidgetItem() not_added_item.setData(Qt.DecorationRole, QIcon(settings.get_image('services_ok'))) not_added_item.setData(Qt.DisplayRole, _('No such services to display...')) self.services_list_widget.addItem(not_added_item) def add_filter_item(self, filter_item): """ Add filter item to QListWidget :param filter_item: filter item (service) :type filter_item: alignak_app.items.service.Service """ item = QListWidgetItem() monitored = \ filter_item.data['passive_checks_enabled'] + filter_item.data['active_checks_enabled'] icon_name = get_icon_name(filter_item.item_type, filter_item.data['ls_state'], filter_item.data['ls_acknowledged'], filter_item.data['ls_downtimed'], monitored) item.setData(Qt.DecorationRole, QIcon(settings.get_image(icon_name))) item.setData(Qt.DisplayRole, filter_item.get_display_name()) item.setData(Qt.UserRole, filter_item.item_id) item.setToolTip(filter_item.get_tooltip()) self.services_list_widget.addItem(item) def update_widget(self, services): """ Update the QTreeWidget and its items :param services: list of :class:`Services <alignak_app.items.service.Service>` items :type services: list """ self.services = services # Update services dashboard self.services_dashboard.update_widget(self.services) # Clear QTreeWidget self.services_tree_widget.clear() self.services_tree_widget.setIconSize(QSize(16, 16)) if self.services: # Set as "Global" aggregation who are empty for service in self.services: if not service.data['aggregation']: service.data['aggregation'] = 'Global' # First sort list by state then by aggregation newlist = sorted(self.services, key=lambda s: itemgetter( 'ls_state', 'ls_acknowledged', 'aggregation') (s.data)) self.services = newlist # Get list of aggregations aggregations = [] for service in self.services: if service.data['aggregation'] not in aggregations: aggregations.append(service.data['aggregation']) # Add QTreeWidgetItems for aggregation in aggregations: main_tree = QTreeWidgetItem() main_tree.setText(0, aggregation) main_tree.setIcon(0, QIcon(settings.get_image('tree'))) main_tree.setToolTip(0, aggregation) for service in self.services: if service.data['aggregation'] == aggregation: service_tree = ServiceTreeItem() service_tree.initialize(service) service_tree.setToolTip(0, service.get_tooltip()) self.services_tree_widget.clicked.connect( self.update_service_data) main_tree.addChild(service_tree) self.services_tree_widget.addTopLevelItem(main_tree) self.service_data_widget.hide() else: # If no services, reset service item to None and hide data widget self.service_data_widget.service_item = None self.service_data_widget.hide() def update_service_data(self): # pragma: no cover """ Update ServiceDataqWidget """ service_item = self.sender().currentItem() if isinstance(service_item, (ServiceTreeItem, QListWidgetItem)): service = None # Get service if isinstance(service_item, ServiceTreeItem): service = data_manager.get_item('service', '_id', service_item.service_id) elif isinstance(service_item, QListWidgetItem): service = data_manager.get_item('service', '_id', service_item.data(Qt.UserRole)) if not service: service = self.service_data_widget.service_item # Update QWidgets self.services_tree_widget.setMaximumWidth(self.width() * 0.5) self.services_list_widget.setMaximumWidth(self.width() * 0.5) self.service_data_widget.setMaximumWidth(self.width() * 0.5) self.service_data_widget.update_widget(service) self.services_dashboard.update_widget(self.services) self.service_data_widget.show() # Update Service Items (ServiceTreeItem, QListWidgetItem) if isinstance(service_item, ServiceTreeItem): service_item.update_item() else: monitored = \ service.data['passive_checks_enabled'] + service.data['active_checks_enabled'] icon_name = get_icon_name('service', service.data['ls_state'], service.data['ls_acknowledged'], service.data['ls_downtimed'], monitored) service_item.setData(Qt.DecorationRole, QIcon(settings.get_image(icon_name))) service_item.setData(Qt.DisplayRole, service.get_display_name()) service_item.setToolTip(service.get_tooltip())
class Database_maint_frame(QMainWindow): FROM, SUBJECT, DATE = range(3) def __init__(self, database_driver=None): # create application object app = QApplication(sys.argv) super().__init__() self.__title='Database maintain' self.__posx=200 self.__posy=200 self.__width=1080 self.__height=720 # Validation for database driver self.__database_driver = None if database_driver and isinstance(database_driver, IDatabase_driver): # set database driver self.__database_driver = database_driver # opened tables self.__opened_tables = [] # set style sheet self.set_stylesheet() # initialize method self.initUI() sys.exit(app.exec_()) def initUI(self): ''' UI initialize ''' # set the window position(x,y) and size self.setGeometry(self.__posx, self.__posy, self.__width, self.__height) # set the window title self.setWindowTitle(self.__title) # update window status self.update_status('Loading...') # add menu bar self.__mainMenu = self.menuBar() self.__fileMenu = self.__mainMenu.addMenu('File') self.__editMenu = self.__mainMenu.addMenu('Edit') self.__viewMenu = self.__mainMenu.addMenu('View') self.__searchMenu = self.__mainMenu.addMenu('Search') self.__toolsMenu = self.__mainMenu.addMenu('Tools') self.__helpMenu = self.__mainMenu.addMenu('Help') # add frame self.__lefttop_square = QFrame(self) self.__lefttop_square.setGeometry(10, 30, 230, 150) self.__leftbtm_square = QFrame(self) self.__leftbtm_square.setGeometry(10, 190, 230, 510) self.__right_square = QFrame(self) self.__right_square.setGeometry(250, 30, 820, 670) # add database combobox and add items self.__db_comboBox = QComboBox(self.__lefttop_square) self.__db_comboBox.setGeometry(QRect(15, 30, 200, 30)) self.__db_comboBox.setObjectName(("comboBox")) # load data self.on_load_combolist(self.__db_comboBox) # load event # add datatable treeview and add items self.__tb_treeview = QTreeWidget(self.__leftbtm_square) self.__tb_treeview.setGeometry(15, 30, 200, 440) self.__tb_treeview_root = QTreeWidgetItem(self.__tb_treeview) self.__tb_treeview_root.setText(0, "Tables") self.__tb_treeview_root.setText(1, "root") self.__tb_treeview.addTopLevelItem(self.__tb_treeview_root) self.__tb_treeview.expandAll() self.__tb_treeview.setHeaderHidden(True) # add tab self.__tab = QTabWidget(self.__right_square) self.__tab.setGeometry(10, 10, 800, 620) # add datagrid buttons self.__new_rec_btn = QPushButton('New',self) self.__new_rec_btn.setToolTip('Add a new record') self.__new_rec_btn.resize(60, 30) self.__new_rec_btn.move(400,665) self.__new_rec_btn.clicked.connect(self.click_new_rec_btn) # button click event self.__del_rec_btn = QPushButton('Delete',self) self.__del_rec_btn.setToolTip('Delete a new record') self.__del_rec_btn.resize(60, 30) self.__del_rec_btn.move(470,665) # event self.__del_rec_btn.clicked.connect(self.click_del_rec_btn) # button click event self.__db_comboBox.currentIndexChanged.connect(self.on_combox_selection_change) # selection change event self.__tb_treeview.doubleClicked.connect(self.on_treeview_doubleClick) # selection change event # show the window self.show() def set_stylesheet(self): ''' set the style sheet from qss and icons ''' # get the relative project path fileconstant = File_constant() root_path = os.path.dirname(os.path.abspath(__file__)) proj_path = root_path[:root_path.index(fileconstant.MY_PROJECT_PACKAGE)] # set the qss qss_path = proj_path + "\\src\\main\\pydev\\com\\ftd\\resource\\style\\StyleSheet.qss" self.setStyleSheet(open(qss_path, "r").read()) # set the window icon icon_path = proj_path + "\\src\\main\\pydev\\com\\ftd\\resource\\icons\\title_icon.jpg" self.setWindowIcon(QIcon(icon_path)) def update_status(self, status): ''' update the window status ''' self.statusBar().showMessage(status) def closeEvent(self, event): ''' window close event ''' reply = QMessageBox.question(self, 'Message', 'Do you want to quit?', QMessageBox.Yes | QMessageBox.No,QMessageBox.Yes) if reply == QMessageBox.Yes: event.accept() else: event.ignore() def click_new_rec_btn(self): ''' new button click ''' print('NEW BUTTON') def click_del_rec_btn(self): ''' delete button click ''' print('DELETE BUTTON') def on_load_combolist(self, parent): ''' combobox load event ''' self.load_databases(parent) def load_databases(self, parent): ''' load the database name list and append into combolist ''' if not self.__database_driver: QMessageBox.warning(self, 'Warning', "Invalid database driver, please check.", QMessageBox.Ok) return result, database_list, message = self.__database_driver.get_database_list() if not result: QMessageBox.critical(self, 'Error', message, QMessageBox.Ok) else: if len(database_list) > 0: parent.addItem("") for name in database_list: parent.addItem(name) else: QMessageBox.warning(self, 'Warning', "Database is empty.", QMessageBox.Ok) def on_combox_selection_change(self): ''' combobox selection change event ''' if not self.__database_driver: return self.clear_treeview_nodes() if not self.__db_comboBox.currentText(): return table_list = self.__database_driver.get_table_list(self.__db_comboBox.currentText()) self.create_treeview_nodes(table_list) def clear_treeview_nodes(self): ''' clear nodes from datatable treeview ''' if self.__tb_treeview_root: while self.__tb_treeview_root.childCount() > 0: self.__tb_treeview_root.removeChild(self.__tb_treeview_root.takeChild(0)) def create_treeview_nodes(self, nodelist=None): ''' append nodes into datatable treeview ''' if nodelist: for table in nodelist: child = QTreeWidgetItem(self.__tb_treeview_root) child.setText(0,table) child.setText(1,'child') def on_treeview_doubleClick(self): ''' treeview selection double click event ''' if self.__tb_treeview.currentItem(): hititem = self.__tb_treeview.currentItem() if hititem.text(1) == 'root': return if hititem.text(0) in self.__opened_tables: return columns = [] column_types = [] records = [] try: # load the datatable record columns, column_types, records = self.__database_driver.get_records(self.__db_comboBox.currentText(), hititem.text(0)) except Exception as e: QMessageBox.warning(self, 'Warning', "Table load failed, please retry.", QMessageBox.Ok) print('expect:', e) return # record the selected table self.__opened_tables.append(hititem.text(0)) # render grid self.render_table_grid(hititem.text(0), columns, column_types, records) def render_table_grid(self, datatablename, columns, column_types, table_records): ''' render the grid ''' # Create table self.__datatable = QTableWidget() # render the columns self.__datatable.setRowCount(len(table_records)) self.__datatable.setColumnCount(len(columns)) self.__datatable.setHorizontalHeaderLabels(columns) # render the grid cells if table_records and len(table_records) > 0: rows_count = len(table_records) column_count = len(columns) for i in range(0, rows_count): # Rows for j in range(0, column_count): # Columns self.__datatable.setItem(i , j, QTableWidgetItem(str(table_records[i][j]))) # render grid style self.__datatable.setAlternatingRowColors(True) self.__datatable.horizontalHeader().setObjectName("dt_hheader") self.__datatable.verticalHeader().setObjectName("dt_vheader") self.__datatable.verticalHeader().setSectionResizeMode(QHeaderView.Fixed) self.__datatable.doubleClicked.connect(self.on_gridcell_click) # double click event # Create tab self.__tab.addTab(self.__datatable, datatablename) def on_gridcell_click(self): for currentQTableWidgetItem in self.__datatable.selectedItems(): print(currentQTableWidgetItem.row(), currentQTableWidgetItem.column(), currentQTableWidgetItem.text())
class ConfigWidget(QWidget): def __init__(self, plugin_action): QWidget.__init__(self) self.plugin_action = plugin_action self.gui = plugin_action.gui self._initialise_layout() self.blank_icon = QIcon(I('blank.png')) fav_menus = plugin_prefs[STORE_MENUS] # Rebuild this into a map for comparison purposes lookup_menu_map = self._build_lookup_menu_map(fav_menus) self._populate_actions_tree(lookup_menu_map) self.items_list.populate_list(fav_menus) # Hook up our events self.tv.itemChanged.connect(self._tree_item_changed) self.items_list.currentRowChanged.connect(self._update_button_states) self._update_button_states() def _initialise_layout(self): layout = QHBoxLayout(self) self.setLayout(layout) self.tv = QTreeWidget(self.gui) self.tv.setIconSize(QSize(ICON_SIZE, ICON_SIZE)) self.tv.header().hide() layout.addWidget(self.tv, 1) self.items_list = FavMenusListWidget(self.gui) self.items_list.setIconSize(QSize(ICON_SIZE, ICON_SIZE)) layout.addWidget(self.items_list, 1) button_layout = QVBoxLayout() layout.addLayout(button_layout) self.up_btn = QToolButton(self.gui) self.up_btn.setIcon(get_icon('arrow-up.png')) self.up_btn.setToolTip('Move the selected menu item up') self.up_btn.clicked.connect(self._move_item_up) self.down_btn = QToolButton(self.gui) self.down_btn.setIcon(get_icon('arrow-down.png')) self.down_btn.setToolTip('Move the selected menu item down') self.down_btn.clicked.connect(self._move_item_down) self.remove_btn = QToolButton(self.gui) self.remove_btn.setIcon(get_icon('trash.png')) self.remove_btn.setToolTip('Remove the selected item from the menu') self.remove_btn.clicked.connect(self._remove_item) self.sep_btn = QToolButton(self.gui) self.sep_btn.setIcon(get_icon('plus.png')) self.sep_btn.setToolTip('Add a separator to the menu following the selected item') self.sep_btn.clicked.connect(self._add_separator) self.rename_btn = QToolButton(self.gui) self.rename_btn.setIcon(get_icon('edit-undo.png')) self.rename_btn.setToolTip('Rename the menu item for when it appears on your Favourites menu') self.rename_btn.clicked.connect(self._rename_item) button_layout.addWidget(self.up_btn) button_layout.addStretch(1) button_layout.addWidget(self.rename_btn) button_layout.addStretch(1) button_layout.addWidget(self.sep_btn) button_layout.addStretch(1) button_layout.addWidget(self.remove_btn) button_layout.addStretch(1) button_layout.addWidget(self.down_btn) def _move_item_up(self): idx = self.items_list.currentRow() if idx > 0: self.items_list.swap_list_widgets(idx-1) self.items_list.setCurrentRow(idx-1) self._update_button_states() def _move_item_down(self): idx = self.items_list.currentRow() if idx < self.items_list.count() - 1: self.items_list.swap_list_widgets(idx) self.items_list.setCurrentRow(idx+1) self._update_button_states() def _add_separator(self): idx = self.items_list.currentRow() self.items_list.populate_list_item(None, idx) self.items_list.setCurrentRow(idx+1) def _remove_item(self): def find_child(twi, paths): for i in range(0, twi.childCount()): c = twi.child(i) text = unicode(c.text(0)) if text == paths[0]: if len(paths) == 1: return c else: return find_child(c, paths[1:]) idx = self.items_list.currentRow() if idx < 0: return item = self.items_list.currentItem() data = convert_qvariant(item.data(Qt.UserRole)) if data is not None: # Not removing a separator fav_menu = data[0] # Lookup the item to uncheck it. self.tv.blockSignals(True) paths = fav_menu['path'] plugin = paths[0] # Find the top-level item for the plugin tree_item = None if plugin in self.top_level_items_map: tree_item = self.top_level_items_map[plugin] if len(paths) > 1: tree_item = find_child(tree_item, paths[1:]) if tree_item is not None: tree_item.setCheckState(0, Qt.Unchecked) self.tv.blockSignals(False) self.items_list.takeItem(idx) self._update_button_states() def _rename_item(self): idx = self.items_list.currentRow() if idx < 0: return item = self.items_list.currentItem() data = convert_qvariant(item.data(Qt.UserRole)) if data is not None: self.items_list.editItem(item) def _update_button_states(self): idx = self.items_list.currentRow() self.up_btn.setEnabled(idx > 0) self.down_btn.setEnabled(idx < self.items_list.count() - 1) self.remove_btn.setEnabled(self.items_list.count() > 0) self.sep_btn.setEnabled(self.items_list.count() > 0) data = None if idx >= 0: item = self.items_list.currentItem() data = convert_qvariant(item.data(Qt.UserRole)) self.rename_btn.setEnabled(data is not None) def _build_lookup_menu_map(self, fav_menus): m = {} for fav_menu in fav_menus: if fav_menu is None: continue path = fav_menu['path'] plugin = path[0] if plugin not in m: m[plugin] = [] fav_menu['paths_text'] = '|'.join(path[1:]) m[plugin].append(fav_menu) return m def _get_scaled_icon(self, icon): if icon.isNull(): return self.blank_icon # We need the icon scaled to 16x16 src = icon.pixmap(ICON_SIZE, ICON_SIZE) if src.width() == ICON_SIZE and src.height() == ICON_SIZE: return icon # Need a new version of the icon pm = QPixmap(ICON_SIZE, ICON_SIZE) pm.fill(Qt.transparent) p = QPainter(pm) p.drawPixmap(QPoint((ICON_SIZE - src.width()) / 2, (ICON_SIZE - src.height()) / 2), src) p.end() return QIcon(pm) def _populate_actions_tree(self, lookup_menu_map): # Lets re-sort the keys so that items will appear on screen sorted # by their display name (not by their key) skeys_map = {} for plugin_name, iaction in six.iteritems(self.gui.iactions): if plugin_name == self.plugin_action.name: continue if 'toolbar' in iaction.dont_add_to and 'toolbar-device' in iaction.dont_add_to: print(('Not adding:', plugin_name)) continue display_name = unicode(iaction.qaction.text()) if plugin_name == 'Choose Library': display_name = 'Library' skeys_map[display_name] = (plugin_name, iaction.qaction) # Add a special case item for the location manager skeys_map['Location Manager'] = ('Location Manager', None) self.top_level_items_map = {} for display_name in sorted(skeys_map.keys()): plugin_name, qaction = skeys_map[display_name] possible_menus = lookup_menu_map.get(plugin_name, []) # Create a node for our top level plugin name tl = Item() tl.setText(0, display_name) tl.setData(0, Qt.UserRole, plugin_name) if plugin_name == 'Location Manager': # Special case handling tl.setFlags(Qt.ItemIsEnabled | Qt.ItemIsUserCheckable) tl.setCheckState(0, Qt.PartiallyChecked) tl.setIcon(0, self._get_scaled_icon(get_icon('reader.png'))) # Put all actions except library within this node. actions = self.gui.location_manager.all_actions[1:] self._populate_action_children(actions, tl, possible_menus, [], plugin_name, is_location_mgr_child=True) else: # Normal top-level checkable plugin iaction handling tl.setFlags(Qt.ItemIsEnabled | Qt.ItemIsUserCheckable) tl.setCheckState(0, Qt.Unchecked) tl.setIcon(0, self._get_scaled_icon(qaction.icon())) # Lookup to see if we have a menu item for this top-level plugin if possible_menus: fav_menu = self._is_in_menu(possible_menus) if fav_menu is not None: fav_menu['icon'] = tl.icon(0) tl.setCheckState(0, Qt.Checked) m = qaction.menu() if m: # Iterate through all the children of this node self._populate_action_children(QMenu.actions(m), tl, possible_menus, [], plugin_name) self.tv.addTopLevelItem(tl) self.top_level_items_map[plugin_name] = tl def _populate_action_children(self, children, parent, possible_menus, paths, plugin_name, is_location_mgr_child=False): for ac in children: if ac.isSeparator(): continue if not ac.isVisible() and not is_location_mgr_child: # That is special case of location mgr visibility, since it has child # actions that will not be visible if device not plugged in at the # moment but we want to always be able to configure them. continue text = get_safe_title(ac) it = Item(parent) it.setText(0, text) it.setFlags(Qt.ItemIsEnabled | Qt.ItemIsUserCheckable) it.setCheckState(0, Qt.Unchecked) it.setIcon(0, self._get_scaled_icon(ac.icon())) new_paths = list(paths) new_paths.append(text) if possible_menus: fav_menu = self._is_in_menu(possible_menus, new_paths) if fav_menu is not None: fav_menu['icon'] = it.icon(0) it.setCheckState(0, Qt.Checked) if ac.menu(): self._populate_action_children(QMenu.actions(ac.menu()), it, possible_menus, new_paths, plugin_name) def _is_in_menu(self, possible_menus, paths=[]): path_text = '|'.join(paths) for x in range(0, len(possible_menus)): fav_menu = possible_menus[x] if fav_menu['paths_text'] == path_text: del possible_menus[x] return fav_menu return None def _tree_item_changed(self, item, column): # Checkstate has been changed - are we adding or removing this item? if unicode(item.text(column)) == 'Location Manager': # Special case of not allowing this since it is not a "real" plugin, # just a special placeholder used for configuring menus that resolves # down to a collection of underlying actions. self.tv.blockSignals(True) item.setCheckState(column, Qt.PartiallyChecked) self.tv.blockSignals(False) return is_checked = item.checkState(column) == Qt.Checked paths = [] fav_menu = {'icon': item.icon(column), 'display': unicode(item.text(column)), 'path': paths} while True: parent = item.parent() if parent is None: paths.insert(0, convert_qvariant(item.data(column, Qt.UserRole))) break else: paths.insert(0, unicode(item.text(column))) item = parent if is_checked: # We want to add this item to the list self.items_list.populate_list_item(fav_menu) self.items_list.setCurrentRow(self.items_list.count() -1) else: # We want to remove the matching item from the list self.items_list.remove_matching_item(fav_menu) self._update_button_states() def save_settings(self): plugin_prefs[STORE_MENUS] = self.items_list.get_fav_menus()