def main(): # Try to close any existing dialogs so there aren't # duplicates open. global pyAssetTrackerDialog try: pyAssetTrackerDialog.ui.close() except: pass # Instantiate the main dialog pyAssetTrackerDialog = AssetTrackerDialog() ui = pyAssetTrackerDialog.ui # Create the source model, but map it to a proxy model to enable # sorting, filtering, etc. sourceModel = model.Model() proxyModel = QSortFilterProxyModel() proxyModel.setSourceModel(sourceModel) # Assign the proxy model to the tree view ui.treeView.setModel(proxyModel) # Show the UI ui.show() ui.setWindowTitle("Better Asset Tracker")
def setupTabs(self): """ Setup the various tabs in the AddressWidget. """ groups = ["ABC", "DEF", "GHI", "JKL", "MNO", "PQR", "STU", "VW", "XYZ"] for group in groups: proxyModel = QSortFilterProxyModel(self) proxyModel.setSourceModel(self.tableModel) proxyModel.setDynamicSortFilter(True) tableView = QTableView() tableView.setModel(proxyModel) tableView.setSortingEnabled(True) tableView.setSelectionBehavior(QAbstractItemView.SelectRows) tableView.horizontalHeader().setStretchLastSection(True) tableView.verticalHeader().hide() tableView.setEditTriggers(QAbstractItemView.NoEditTriggers) tableView.setSelectionMode(QAbstractItemView.SingleSelection) # This here be the magic: we use the group name (e.g. "ABC") to # build the regex for the QSortFilterProxyModel for the group's # tab. The regex will end up looking like "^[ABC].*", only # allowing this tab to display items where the name starts with # "A", "B", or "C". Notice that we set it to be case-insensitive. reFilter = "^[%s].*" % group proxyModel.setFilterRegExp(QRegExp(reFilter, Qt.CaseInsensitive)) proxyModel.setFilterKeyColumn(0) # Filter on the "name" column proxyModel.sort(0, Qt.AscendingOrder) # This prevents an application crash (see: http://www.qtcentre.org/threads/58874-QListView-SelectionModel-selectionChanged-Crash) viewselectionmodel = tableView.selectionModel() tableView.selectionModel().selectionChanged.connect(self.selectionChanged) self.addTab(tableView, group)
def __init__(self, parent: QObject, manager: Manager): super().__init__(parent) self._manager = manager self.setWindowTitle("Tasks") # Build widget self.search_field = QLineEdit(self) self.table = _base.ExcelLikeTableView(self) self.table.setSelectionBehavior(QAbstractItemView.SelectRows) self.table.horizontalHeader().setSectionResizeMode( QHeaderView.ResizeToContents) self.table.horizontalHeader().setStretchLastSection(True) self.table.verticalHeader().setVisible(False) self.button_add = QPushButton("Add", self) self.button_remove = QPushButton("Remove", self) self.button_import = QPushButton("Import", self) self.button_export = QPushButton("Export", self) # Build layout layout_footer = QHBoxLayout() layout_footer.addWidget(self.search_field) layout_footer.addWidget(self.button_add) layout_footer.addWidget(self.button_remove) layout_footer.addWidget(self.button_import) layout_footer.addWidget(self.button_export) layout_content = QVBoxLayout() layout_content.addLayout(layout_footer) layout_content.addWidget(self.table) main_widget = QWidget() main_widget.setLayout(layout_content) self.setWidget(main_widget) # Configure model self.model = TasksListModel(self, self._manager.context) model_table = TasksListToTableProxyModel(self) model_table.setSourceModel(self.model) model_table_proxy = QSortFilterProxyModel(self) model_table_proxy.setSourceModel(model_table) # Configure view self.table.setModel(model_table_proxy) self.artist_delegate = ArtistDelegate(self, self._manager) self.table.setItemDelegateForColumn(2, self.artist_delegate) self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) # Connect signals for signal, callback in ( (self.model.dataChanged, self._on_data_changed), (self.button_add.pressed, self.add_task), (self.button_remove.pressed, self.remove_tasks), (self.button_export.pressed, self.export_tasks), (self.button_import.pressed, self.import_tasks), ( self.search_field.textChanged, model_table_proxy.setFilterWildcard, ), ): signal.connect(callback)
def setupTabs(self): """ Setup the various tabs in the AddressWidget. """ groups = ["ABC", "DEF", "GHI", "JKL", "MNO", "PQR", "STU", "VW", "XYZ"] for group in groups: proxyModel = QSortFilterProxyModel(self) proxyModel.setSourceModel(self.tableModel) proxyModel.setDynamicSortFilter(True) tableView = QTableView() tableView.setModel(proxyModel) tableView.setSortingEnabled(True) tableView.setSelectionBehavior(QAbstractItemView.SelectRows) tableView.horizontalHeader().setStretchLastSection(True) tableView.verticalHeader().hide() tableView.setEditTriggers(QAbstractItemView.NoEditTriggers) tableView.setSelectionMode(QAbstractItemView.SingleSelection) # This here be the magic: we use the group name (e.g. "ABC") to # build the regex for the QSortFilterProxyModel for the group's # tab. The regex will end up looking like "^[ABC].*", only # allowing this tab to display items where the name starts with # "A", "B", or "C". Notice that we set it to be case-insensitive. reFilter = "^[%s].*" % group proxyModel.setFilterRegExp(QRegExp(reFilter, Qt.CaseInsensitive)) proxyModel.setFilterKeyColumn(0) # Filter on the "name" column proxyModel.sort(0, Qt.AscendingOrder) # This prevents an application crash (see: http://www.qtcentre.org/threads/58874-QListView-SelectionModel-selectionChanged-Crash) viewselectionmodel = tableView.selectionModel() tableView.selectionModel().selectionChanged.connect( self.selectionChanged) self.addTab(tableView, group)
class QFilteredComboBox(QComboBox): def __init__( self, parent=None, include_targets=True, include_airbases=True, include_frontlines=True, include_units=True, include_enemy=True, include_friendly=True, ): super(QFilteredComboBox, self).__init__(parent) self.setFocusPolicy(Qt.StrongFocus) self.setEditable(True) self.completer = QCompleter(self) self.include_targets = include_targets self.include_airbases = include_airbases self.include_frontlines = include_frontlines self.include_units = include_units self.include_enemy = include_enemy self.include_friendly = include_friendly # always show all completions self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion) self.pFilterModel = QSortFilterProxyModel(self) self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive) self.completer.setPopup(self.view()) self.setCompleter(self.completer) self.lineEdit().textEdited.connect(self.pFilterModel.setFilterFixedString) self.completer.activated.connect(self.setTextIfCompleterIsClicked) def setModel(self, model): super(QFilteredComboBox, self).setModel(model) self.pFilterModel.setSourceModel(model) self.completer.setModel(self.pFilterModel) self.model().sort(0) def setModelColumn(self, column): self.completer.setCompletionColumn(column) self.pFilterModel.setFilterKeyColumn(column) super(QFilteredComboBox, self).setModelColumn(column) def view(self): return self.completer.popup() def index(self): return self.currentIndex() def setTextIfCompleterIsClicked(self, text): if text: index = self.findText(text) self.setCurrentIndex(index)
def __init__(self, data_list, header, *args): QWidget.__init__(self, *args) # setGeometry(x_pos, y_pos, width, height) self.setGeometry(300, 200, 570, 450) self.setWindowTitle('Click on column title to sort') # Setup the model and view '''tmodel = MyTableModel(self, data_list, header) tview = QTableView() tview.setModel(tmodel) delegate = MyDelegate() tview.setItemDelegate(delegate)''' # Setup the proxy model for sorting and filtering tmodel = MyTableModel(self, data_list, header) pmodel = QSortFilterProxyModel() pmodel.setSourceModel(tmodel) tview = QTableView() tview.setModel(pmodel) delegate = MyDelegate() tview.setItemDelegate(delegate) # TableView properties tview.resizeColumnsToContents() # set column width to fit contents tview.setShowGrid(False) # hide gridlines #tview.verticalHeader().hide() # row labels #tview.horizontalHeader().hide() # column labels # Select a single row at a time tview.setSelectionBehavior(QTableView.SelectRows) tview.setSelectionMode(QTableView.SingleSelection) # Enable sorting tview.setSortingEnabled(True) # Drag and drop reordering using header labels '''tview.verticalHeader().setSectionsMovable(True) tview.verticalHeader().setDragEnabled(True) tview.verticalHeader().setDragDropMode(QAbstractItemView.InternalMove) tview.horizontalHeader().setSectionsMovable(True) tview.horizontalHeader().setDragEnabled(True) tview.horizontalHeader().setDragDropMode(QAbstractItemView.InternalMove)''' # Drag and drop reordering using rows tview.setDragEnabled(True) tview.setAcceptDrops(True) tview.setDragDropMode(QTableView.InternalMove) tview.setDragDropOverwriteMode(False) layout = QVBoxLayout(self) layout.addWidget(tview) self.setLayout(layout)
def __init__(self, blocksModel, filename, parent): super().__init__() self.setupUi(self) self._blocksModel = blocksModel if len(filename) > 33: windowTitle = filename[:15] + ' ... ' + filename[-15:] else: windowTitle = filename self.setWindowTitle(windowTitle) sortModel = QSortFilterProxyModel() sortModel.setSourceModel(blocksModel) self.blocksTableView.setModel(sortModel) self.blocksTableView.resizeColumnsToContents() self.blocksTableView.addAction( CopySelectedCellsAction(self.blocksTableView)) self.setParent(parent) self.setWindowFlags(Qt.Window | Qt.WindowCloseButtonHint)
def setupTable(self): proxyModel = QSortFilterProxyModel(self) proxyModel.setSourceModel(self.tableModel) proxyModel.setDynamicSortFilter(True) self.tableView.setModel(proxyModel) self.tableView.setSortingEnabled(True) self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows) self.tableView.horizontalHeader().setStretchLastSection(True) self.tableView.verticalHeader().hide() self.tableView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.tableView.setSelectionMode(QAbstractItemView.SingleSelection) proxyModel.setFilterKeyColumn(0) # Filter on the "name" column proxyModel.sort(0, Qt.AscendingOrder) viewselectionmodel = self.tableView.selectionModel() self.tableView.selectionModel().selectionChanged.connect(self.selectionChanged)
def setupTable(self): proxyModel = QSortFilterProxyModel(self) proxyModel.setSourceModel(self.tableModel) proxyModel.setDynamicSortFilter(True) self.tableView.setModel(proxyModel) self.tableView.setSortingEnabled(True) self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows) self.tableView.horizontalHeader().setStretchLastSection(True) self.tableView.verticalHeader().hide() self.tableView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.tableView.setSelectionMode(QAbstractItemView.SingleSelection) proxyModel.setFilterKeyColumn(0) # Filter on the "name" column proxyModel.sort(0, Qt.AscendingOrder) viewselectionmodel = self.tableView.selectionModel() self.tableView.selectionModel().selectionChanged.connect( self.selectionChanged)
def _update_document_view(self) -> KnechtTreeView: """ Update current view to search in and update search tree view accordingly """ view = self.ui.tree_with_focus() self.last_view = view self.last_view.destroyed.connect(self._last_view_deleted) if view.model().sourceModel() != self.search_view.model().sourceModel( ): proxy_model = QSortFilterProxyModel() proxy_model.setFilterCaseSensitivity( self.view_filter_case_sensitivity) proxy_model.setSourceModel(view.model().sourceModel()) proxy_model.setRecursiveFilteringEnabled(True) self.search_view.setModel(proxy_model) for c in (Kg.REF, Kg.ID): self.search_view.hideColumn(c) LOGGER.debug('Search Dialog Document View updated.') return view
def __init__(self): QWidget.__init__(self) layout = QVBoxLayout(self) self.splitter = QSplitter(self) self.cats = QTreeView(self) self.cats.setSortingEnabled(True) self.cat_model = RssCategoryModel() proxy = QSortFilterProxyModel() proxy.setSourceModel(self.cat_model) self.cats.setModel(proxy) self.splitter.addWidget(self.cats) self.t = QTableWidget(0, 4, self) self.splitter.addWidget(self.t) self.stats = [QLabel('{}'.format(datetime.now())) for _ in range(8)] stat: QLabel for stat in self.stats: stat.setFont(QFont(pointSize=14)) layout.addWidget(stat, 0, Qt.AlignTop) layout.addWidget(self.splitter, 0, Qt.AlignTop) self.ds = DataSource() self.f_model = ForumsModel(self.ds.get_forums()) self.forums = QTableView(self) self.forums.setModel(self.f_model) self.forums.resizeColumnsToContents() layout.addWidget(self.forums, 10, Qt.AlignTop) self.setLayout(layout) self.worker = RssWorker() self.worker_thread = QThread() self.worker_thread.started.connect(self.worker.run) self.worker.finished.connect(self.worker_thread.quit) self.worker.moveToThread(self.worker_thread) self.worker_thread.start() self.worker.processed.connect(self.processed) self.worker.current.connect(self.current)
def __init__(self): QWidget.__init__(self) layout = QVBoxLayout(self) self.splitter = QSplitter(self) self.list = QTreeView(self) self.list.setSortingEnabled(True) self.model = NewTorrentModel() proxy = QSortFilterProxyModel() proxy.setSourceModel(self.model) self.list.setModel(proxy) self.splitter.addWidget(self.list) self.t = QTableWidget(0, 4, self) self.splitter.addWidget(self.t) layout.addWidget(self.splitter) self.setLayout(layout) self.ds = DataSource() self.worker = UpdateTorrentWorker() self.worker_thread = QThread() self.worker_thread.started.connect(self.worker.run) self.worker.finished.connect(self.worker_thread.quit) self.worker.moveToThread(self.worker_thread) self.worker_thread.start() self.worker.processed.connect(self.processed)
class AdvComboBox(QComboBox): """ Combo with autocomplete Found in Internet by Sergei """ def __init__(self, parent=None): super(AdvComboBox, self).__init__(parent) self.setFocusPolicy(QtCore.Qt.StrongFocus) self.setEditable(True) # add a filter model to filter matching items self.pFilterModel = QSortFilterProxyModel(self) self.pFilterModel.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive) self.pFilterModel.setSourceModel(self.model()) # add a completer, which uses the filter model self.completer = QCompleter(self.pFilterModel, self) # always show all (filtered) completions self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion) self.setCompleter(self.completer) # connect signals def filter_function(text): self.pFilterModel.setFilterFixedString(str(text)) self.lineEdit().textEdited.connect(filter_function) self.completer.activated.connect(self.on_completer_activated) # on selection of an item from the completer, select the corresponding item from combobox def on_completer_activated(self, text): if text: index = self.findText(str(text)) self.setCurrentIndex(index)
class IconColorEditor(QDialog): """An editor to let the user select an icon and a color for an object_class. """ def __init__(self, parent): """Init class.""" super().__init__(parent) # , Qt.Popup) icon_size = QSize(32, 32) self.icon_mngr = IconListManager(icon_size) self.setWindowTitle("Select icon and color") self.icon_widget = QWidget(self) self.icon_list = QListView(self.icon_widget) self.icon_list.setViewMode(QListView.IconMode) self.icon_list.setIconSize(icon_size) self.icon_list.setResizeMode(QListView.Adjust) self.icon_list.setItemDelegate(_IconPainterDelegate(self)) self.icon_list.setMovement(QListView.Static) self.icon_list.setMinimumHeight(400) icon_widget_layout = QVBoxLayout(self.icon_widget) icon_widget_layout.addWidget(QLabel("Font Awesome icons")) self.line_edit = QLineEdit() self.line_edit.setPlaceholderText("Search icons for...") icon_widget_layout.addWidget(self.line_edit) icon_widget_layout.addWidget(self.icon_list) self.color_dialog = QColorDialog(self) self.color_dialog.setWindowFlags(Qt.Widget) self.color_dialog.setOption(QColorDialog.NoButtons, True) self.color_dialog.setOption(QColorDialog.DontUseNativeDialog, True) self.button_box = QDialogButtonBox(self) self.button_box.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) top_widget = QWidget(self) top_layout = QHBoxLayout(top_widget) top_layout.addWidget(self.icon_widget) top_layout.addWidget(self.color_dialog) layout = QVBoxLayout(self) layout.addWidget(top_widget) layout.addWidget(self.button_box) self.proxy_model = QSortFilterProxyModel(self) self.proxy_model.setSourceModel(self.icon_mngr.model) self.proxy_model.filterAcceptsRow = self._proxy_model_filter_accepts_row self.icon_list.setModel(self.proxy_model) self.setAttribute(Qt.WA_DeleteOnClose) self.connect_signals() def _proxy_model_filter_accepts_row(self, source_row, source_parent): """Overridden method to filter icons according to search terms. """ text = self.line_edit.text() if not text: return QSortFilterProxyModel.filterAcceptsRow( self.proxy_model, source_row, source_parent) searchterms = self.icon_mngr.model.index( source_row, 0, source_parent).data(Qt.UserRole + 1) return any([text in term for term in searchterms]) def connect_signals(self): """Connect signals to slots.""" self.line_edit.textEdited.connect(self.proxy_model.invalidateFilter) self.button_box.accepted.connect(self.accept) self.button_box.rejected.connect(self.reject) def set_data(self, data): icon_code, color_code = interpret_icon_id(data) self.icon_mngr.init_model() for i in range(self.proxy_model.rowCount()): index = self.proxy_model.index(i, 0) if index.data(Qt.UserRole) == icon_code: self.icon_list.setCurrentIndex(index) break self.color_dialog.setCurrentColor(QColor(color_code)) def data(self): icon_code = self.icon_list.currentIndex().data(Qt.UserRole) color_code = self.color_dialog.currentColor().rgb() return make_icon_id(icon_code, color_code)
class SearchBarEditor(QTableView): """A Google-like search bar, implemented as a QTableView with a _CustomLineEditDelegate in the first row. """ data_committed = Signal() def __init__(self, parent, tutor=None): """Initializes instance. Args: parent (QWidget): parent widget tutor (QWidget, NoneType): another widget used for positioning. """ super().__init__(parent) self._tutor = tutor self._base_size = QSize() self._base_offset = QPoint() self._original_text = None self._orig_pos = None self.first_index = QModelIndex() self.model = QStandardItemModel(self) self.proxy_model = QSortFilterProxyModel(self) self.proxy_model.setSourceModel(self.model) self.proxy_model.filterAcceptsRow = self._proxy_model_filter_accepts_row self.setModel(self.proxy_model) self.verticalHeader().hide() self.horizontalHeader().hide() self.setShowGrid(False) self.setMouseTracking(True) self.setTabKeyNavigation(False) delegate = _CustomLineEditDelegate(self) delegate.text_edited.connect(self._handle_delegate_text_edited) self.setItemDelegateForRow(0, delegate) def set_data(self, current, items): """Populates model. Args: current (str) items (Sequence(str)) """ item_list = [QStandardItem(current)] for item in items: qitem = QStandardItem(item) item_list.append(qitem) qitem.setFlags(~Qt.ItemIsEditable) self.model.invisibleRootItem().appendRows(item_list) self.first_index = self.proxy_model.mapFromSource( self.model.index(0, 0)) def set_base_size(self, size): self._base_size = size def set_base_offset(self, offset): self._base_offset = offset def update_geometry(self): """Updates geometry. """ self.horizontalHeader().setDefaultSectionSize(self._base_size.width()) self.verticalHeader().setDefaultSectionSize(self._base_size.height()) self._orig_pos = self.pos() + self._base_offset if self._tutor: self._orig_pos += self._tutor.mapTo(self.parent(), self._tutor.rect().topLeft()) self.refit() def refit(self): self.move(self._orig_pos) table_height = self.verticalHeader().length() size = QSize(self._base_size.width(), table_height + 2).boundedTo(self.parent().size()) self.resize(size) # Adjust position if widget is outside parent's limits bottom_right = self.mapToGlobal(self.rect().bottomRight()) parent_bottom_right = self.parent().mapToGlobal( self.parent().rect().bottomRight()) x_offset = max(0, bottom_right.x() - parent_bottom_right.x()) y_offset = max(0, bottom_right.y() - parent_bottom_right.y()) self.move(self.pos() - QPoint(x_offset, y_offset)) def data(self): return self.first_index.data(Qt.EditRole) @Slot("QString") def _handle_delegate_text_edited(self, text): """Filters model as the first row is being edited.""" self._original_text = text self.proxy_model.setFilterRegExp("^" + text) self.proxy_model.setData(self.first_index, text) self.refit() def _proxy_model_filter_accepts_row(self, source_row, source_parent): """Always accept first row. """ if source_row == 0: return True return QSortFilterProxyModel.filterAcceptsRow(self.proxy_model, source_row, source_parent) def keyPressEvent(self, event): """Sets data from current index into first index as the user navigates through the table using the up and down keys. """ super().keyPressEvent(event) event.accept( ) # Important to avoid unhandled behavior when trying to navigate outside view limits # Initialize original text. TODO: Is there a better place for this? if self._original_text is None: self.proxy_model.setData(self.first_index, event.text()) self._handle_delegate_text_edited(event.text()) # Set data from current index in model if event.key() in (Qt.Key_Up, Qt.Key_Down): current = self.currentIndex() if current.row() == 0: self.proxy_model.setData(self.first_index, self._original_text) else: self.proxy_model.setData(self.first_index, current.data()) def currentChanged(self, current, previous): super().currentChanged(current, previous) self.edit_first_index() def edit_first_index(self): """Edits first index if valid and not already being edited. """ if not self.first_index.isValid(): return if self.isPersistentEditorOpen(self.first_index): return self.edit(self.first_index) def mouseMoveEvent(self, event): """Sets the current index to the one hovered by the mouse.""" if not self.currentIndex().isValid(): return index = self.indexAt(event.pos()) if index.row() == 0: return self.setCurrentIndex(index) def mousePressEvent(self, event): """Commits data.""" index = self.indexAt(event.pos()) if index.row() == 0: return self.proxy_model.setData(self.first_index, index.data(Qt.EditRole)) self.data_committed.emit()
class ABDataFrameView(QTableView): """ Base class for showing pandas dataframe objects as tables. """ ALL_FILTER = "All Files (*.*)" CSV_FILTER = "CSV (*.csv);; All Files (*.*)" TSV_FILTER = "TSV (*.tsv);; All Files (*.*)" EXCEL_FILTER = "Excel (*.xlsx);; All Files (*.*)" def __init__(self, parent=None): super().__init__(parent) self.setVerticalScrollMode(QTableView.ScrollPerPixel) self.setHorizontalScrollMode(QTableView.ScrollPerPixel) self.setWordWrap(True) self.setAlternatingRowColors(True) self.setSortingEnabled(True) self.verticalHeader().setDefaultSectionSize(22) # row height self.verticalHeader().setVisible(True) # Use a custom ViewOnly delegate by default. # Can be overridden table-wide or per column in child classes. self.setItemDelegate(ViewOnlyDelegate(self)) self.table_name = 'LCA results' # Initialize attributes which are set during the `sync` step. # Creating (and typing) them here allows PyCharm to see them as # valid attributes. self.model: Optional[PandasModel] = None self.proxy_model: Optional[QSortFilterProxyModel] = None def get_max_height(self) -> int: return (self.verticalHeader().count())*self.verticalHeader().defaultSectionSize() + \ self.horizontalHeader().height() + self.horizontalScrollBar().height() + 5 def sizeHint(self) -> QSize: return QSize(self.width(), self.get_max_height()) def rowCount(self) -> int: return 0 if self.model is None else self.model.rowCount() @Slot(name="updateProxyModel") def update_proxy_model(self) -> None: self.proxy_model = QSortFilterProxyModel(self) self.proxy_model.setSourceModel(self.model) self.proxy_model.setSortCaseSensitivity(Qt.CaseInsensitive) self.setModel(self.proxy_model) @Slot(name="resizeView") def custom_view_sizing(self) -> None: """ Custom table resizing to perform after setting new (proxy) model. """ self.setMaximumHeight(self.get_max_height()) @Slot(name="exportToClipboard") def to_clipboard(self): """ Copy dataframe to clipboard """ rows = list(range(self.model.rowCount())) cols = list(range(self.model.columnCount())) self.model.to_clipboard(rows, cols, include_header=True) def savefilepath(self, default_file_name: str, caption: str = None, file_filter: str = None): """ Construct and return default path where data is stored Uses the application directory for AB """ safe_name = safe_filename(default_file_name, add_hash=False) caption = caption or "Choose location to save lca results" filepath, _ = QFileDialog.getSaveFileName( parent=self, caption=caption, dir=os.path.join(ab_settings.data_dir, safe_name), filter=file_filter or self.ALL_FILTER, ) # getSaveFileName can now weirdly return Path objects. return str(filepath) if filepath else filepath @Slot(name="exportToCsv") def to_csv(self): """ Save the dataframe data to a CSV file. """ filepath = self.savefilepath(self.table_name, file_filter=self.CSV_FILTER) if filepath: if not filepath.endswith('.csv'): filepath += '.csv' self.model.to_csv(filepath) @Slot(name="exportToExcel") def to_excel(self, caption: str = None): """ Save the dataframe data to an excel file. """ filepath = self.savefilepath(self.table_name, caption, file_filter=self.EXCEL_FILTER) if filepath: if not filepath.endswith('.xlsx'): filepath += '.xlsx' self.model.to_excel(filepath) @Slot(QKeyEvent, name="copyEvent") def keyPressEvent(self, e): """ Allow user to copy selected data from the table NOTE: by default, the table headers (column names) are also copied. """ if e.modifiers() & Qt.ControlModifier: # Should we include headers? headers = e.modifiers() & Qt.ShiftModifier if e.key() == Qt.Key_C: # copy selection = [ self.model.proxy_to_source(p) for p in self.selectedIndexes() ] rows = [index.row() for index in selection] columns = [index.column() for index in selection] rows = sorted(set(rows), key=rows.index) columns = sorted(set(columns), key=columns.index) self.model.to_clipboard(rows, columns, headers)
class MainWindow(QMainWindow, Ui_MainWindow): def __init__(self, close_handler, driver: Driver): super().__init__() self.setupUi(self) self.driver = driver self.open_editors = {} self.close_handler = close_handler self.setWindowTitle("Paragon") self.setWindowIcon(QIcon("paragon.ico")) self.proxy_model = QSortFilterProxyModel() self.proxy_model.setSourceModel(self.driver.module_model) self.module_list_view.setModel(self.proxy_model) self.editors_list_view.setModel(self.driver.services_model) self.open_file_model = OpenFilesModel() self.file_list_view.setModel(self.open_file_model) self.search_field.textChanged.connect(self.proxy_model.setFilterRegExp) self.module_list_view.activated.connect(self._on_module_activated) self.editors_list_view.activated.connect(self._on_editor_activated) self.file_list_view.selectionModel().currentRowChanged.connect( self._on_file_list_selection_change) self.close_button.clicked.connect(self._on_close_file_pressed) self.action_save.triggered.connect(self.save) self.action_close.triggered.connect(self.close) self.action_quit.triggered.connect(self.quit_application) logging.info("Opened main window.") def save(self): self.driver.save() def close(self): self.hide() self.close_handler() @staticmethod def quit_application(): exit(0) def _on_file_list_selection_change(self, index): self.close_button.setEnabled( self.open_file_model.can_close(index.row())) def _on_close_file_pressed(self): self.open_file_model.close(self.file_list_view.currentIndex().row()) def _on_module_activated(self, index): logging.info("Module " + str(index.row()) + " activated.") # First, see if the module is already open. module: Module = self.proxy_model.data(index, QtCore.Qt.UserRole) if module in self.open_editors: logging.info(module.name + " is cached. Reopening editor...") self.driver.set_module_used(module) self.open_editors[module].show() return # Next, handle common modules. if not module.unique: logging.info(module.name + " is a common module. Prompting for a file...") target_file = QFileDialog.getOpenFileName(self) if not target_file[0]: logging.info("No file selected - operation aborted.") return logging.info("File selected. Opening common module...") module = self.driver.handle_open_for_common_module( module, target_file[0]) # Hack to keep the display for the open file model consistent. self.open_file_model.beginResetModel() self.open_file_model.endResetModel() if module.type == "table": logging.info("Opening " + module.name + " as a TableModule.") editor = SimpleEditor(self.driver, cast(TableModule, module)) elif module.type == "object": logging.info("Opening " + module.name + " as an ObjectModule.") editor = ObjectEditor(self.driver, module) else: logging.error("Attempted to open an unsupported module type.") raise NotImplementedError self.driver.set_module_used(module) self.open_editors[module] = editor editor.show() def _on_editor_activated(self, index): model = self.driver.services_model service = model.data(index, QtCore.Qt.UserRole) service.editor.show()
class TreeCard(QDialog): def __init__(self, db=0, mode=0): super().__init__() layout = QGridLayout() #self.central_widget.setLayout(layout) self.resize(800, self.height()) self.lb_find = QInvisibleButton('Поиск') self.lb_find.setFont(mainfont) self.te_find = QLineEdit() self.te_find.setFont(mainfont) self.pid = 0 layout.addWidget(self.te_find, 0, 0, 1, 1) layout.addWidget(self.lb_find, 0, 0, 1, 1) #if mode: # te.setReadOnly(False) self.lb_find.clicked.connect(self.button_pressed) self.te_find.returnPressed.connect(self.line_edit_return_pressed) self.database = db self.table = QTableView() # Создаём таблицу self.table.doubleClicked.connect(self.viewPerson) #self.table = table self.model = TableModel(self.database.get_peoples()) self.table.setModel(self.model) self.table.resizeRowsToContents() self.table.setSelectionBehavior(QAbstractItemView.SelectRows) #self.table.setSelectionMode(QAbstractItemView.SingleSelection); self.model.dataChanged.connect(self.table.update) layout.addWidget(self.table) self.setLayout(layout) def viewPerson(self): select = self.table.selectionModel() pid_list = [ index.data() for index in self.table.selectionModel().selection().indexes() if index.column() == 0 ] if len(pid_list) == 1: self.pid = int(pid_list[0]) print(int(pid_list[0])) self.accept() return 0 def button_pressed(self): #sender = self.sender() self.lb_find.stackUnder(self.te_find) self.te_find.setFocus() def line_edit_return_pressed(self): print(self.te_find.text()) self.model = TableModel(self.database.get_peoples()) self.proxy_model = QSortFilterProxyModel(self.model) self.proxy_model.setSourceModel(self.model) self.proxy_model.setFilterFixedString(self.te_find.text()) self.proxy_model.setFilterKeyColumn(-1) #print(self.proxy_model.filterKeyColumn()) self.table.setModel(self.proxy_model) self.table.update() self.table.resizeRowsToContents() #sender = self.sender() self.te_find.stackUnder(self.lb_find) self.lb_find.setFocus()
class QStringTable(QTableView): def __init__(self, parent, selection_callback=None): super(QStringTable, self).__init__(parent) self._selected = selection_callback self._filter = None self.setSelectionBehavior(QAbstractItemView.SelectRows) self.setShowGrid(False) self.verticalHeader().setVisible(False) self.verticalHeader().setDefaultSectionSize(24) self.setHorizontalScrollMode(self.ScrollPerPixel) self._model = QStringModel(None) self._proxy = QSortFilterProxyModel(self) self._proxy.setSourceModel(self._model) self._proxy.setFilterCaseSensitivity(Qt.CaseInsensitive) self.setModel(self._proxy) self.setSortingEnabled(True) self.setSelectionMode(QAbstractItemView.SingleSelection) # let the last column (string) fill table width self.horizontalHeader().setSectionResizeMode(QHeaderView.Fixed) self.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch) self.doubleClicked.connect(self._on_string_selected) # # Properties # @property def cfg(self): return self._model.cfg @cfg.setter def cfg(self, v): self._model.cfg = v self.fast_resize() @property def xrefs(self): return self._model.xrefs @xrefs.setter def xrefs(self, v): self._model.xrefs = v @property def function(self): return self._model.function @function.setter def function(self, v): self._model.function = v self.fast_resize() @property def filter_string(self): return self._filter @filter_string.setter def filter_string(self, v): self._filter = v if isinstance(v, re.Pattern): self._proxy.setFilterRegExp(self._filter.pattern) else: self._proxy.setFilterWildcard(self._filter) self._proxy.setFilterKeyColumn(2) # # Public methods # def fast_resize(self): self.setVisible(False) self.resizeColumnsToContents() self.setVisible(True) # # Event handlers # def _on_string_selected(self, model_index): model_index = self._proxy.mapToSource(model_index) selected_index = model_index.row() if self._model is None: return if 0 <= selected_index < len(self._model.values): selected_item = self._model.values[selected_index] else: selected_item = None if self._selected is not None: self._selected(selected_item)
class PlaylistView(QTableView): current_index_changed = Signal(QModelIndex) playlist_double_clicked = Signal() filtering = Signal(str) unfiltered = Signal(str) next = Slot(int) previous = Slot(int) @property def mime_Index(self): return 'application/x-original_index' @property def mime_URLS(self): return 'application/x-file-urls' @property def mime_url_count(self): return 'application/x-urls-count' @property def url_delimiter(self): return '\n' @property def open_file_filter(self): return '*.mp4 *.m4v *.mov *.mpg *.mpeg *. mp3 *.m4a *.wmv *.aiff *.wav' def __init__(self, parent=None): super(PlaylistView, self).__init__(parent) self.setSelectionMode(QAbstractItemView.ExtendedSelection) self.setDragEnabled(True) self.setAcceptDrops(True) self.setDragDropMode(QAbstractItemView.DragDrop) self.setDropIndicatorShown(True) self.proxy_model = QSortFilterProxyModel(self) self.proxy_model.setSourceModel(PlaylistModel(self)) self.setModel(self.proxy_model) # self.setModel(PlaylistModel()) self.setShowGrid(False) self.setSelectionBehavior(QAbstractItemView.SelectRows) self.verticalHeader().setDefaultSectionSize(16) self.verticalHeader().hide() self.horizontalHeader().setMinimumSectionSize(30) self.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive) self.current_index = QModelIndex() self.previousIndex = QModelIndex() self.rubberBand: QRubberBand = QRubberBand(QRubberBand.Rectangle, self) self.isDragging = False self.wasSelected = False self.context_menu = QMenu(self) self.create_context_menu() # self.current_index_changed.connect(self.proxy_model.sourceModel().set_current_index) self.current_index_changed.connect( self.proxy_model.sourceModel().set_current_index) def create_context_menu(self): add_file = createAction(self, 'Add File(s)', self.open) delete_selected = createAction(self, 'Delete selected', self.delete_items) sort_action = createAction(self, 'Sort', self.proxy_model.sourceModel().sort) pickup_dup_action = createAction(self, 'Filter by same title', self.filter_same_title) stop_filtering_action = createAction(self, 'Stop Filtering', self.unfilter) self.context_menu.addActions([ add_file, delete_selected, sort_action, pickup_dup_action, stop_filtering_action ]) def contextMenuEvent(self, event): self.context_menu.exec_(event.globalPos()) def count(self): return self.proxy_model.sourceModel().rowCount() def open(self): list, _ = QFileDialog.getOpenFileNames(self, 'Open File', QDir.homePath()) for path in list: if path[-3:] == 'm3u': self.load(path) else: self.add_item(path) def open_directory(self): directory_url = QFileDialog.getExistingDirectory( self, '0Open directory', QDir.homePath()) dir = QDir(directory_url) filters = [ '*.mp4', '*.m4v', '*.mov', '*.mpg', '*.mpeg', '*.mp3', '*.m4a', '*.wmv', '*.wav', '*.aiff' ] dir.setNameFilters(filters) file_list = dir.entryList() path = dir.absolutePath() + '/' for file in file_list: self.add_item(path + file) def save(self, path=None): """プレイリストを保存する。 :param file :QFile 出力するようのファイル fileが指定されていれば、fileに内容を書き込み、 指定がなければ、ダイアログで名前を指定してそこにファイルを保存。 """ if path is None: return with open(path, 'wt') as fout: for i in range(self.proxy_model.sourceModel().rowCount()): index = self.proxy_model.sourceModel().index(i, 0) print(self.url(index).toLocalFile(), file=fout) return True def load(self, path=None): """プレイリストを読み込む pathが与えられた場合は、そこから読み込み、 ない場合は、何も読み込まない。""" with open(path, 'rt') as fin: for line in fin: self.add_item(line[:-1]) # 最後の改行文字を取り除く def add_item(self, path): if is_media(path): self.proxy_model.sourceModel().add(QUrl.fromLocalFile(path)) return True return False def current_url(self): return self.url(self.current_index) def current_title(self): return self.title(self.current_index) def next(self, step=1): if self.current_row() + step < self.count(): self.set_current_index_from_row(self.current_row() + step) return self.url(self.current_index) else: return None def previous(self, step=1): if self.current_row() - step >= 0: self.set_current_index_from_row(self.current_row() - step) return self.url(self.current_index) else: return None def selected(self): selected_indexes = self.selectedIndexes() if len(selected_indexes) > 0: return selected_indexes[0] else: return None def current_row(self): return self.current_index.row() def url(self, index): if isinstance(index, int): row = index if 0 <= row < self.count(): index = self.proxy_model.sourceModel().index(row, 0) if isinstance(index, QModelIndex): return self.proxy_model.sourceModel().data(index) else: return None def title(self, index): if isinstance(index, int): row = index if 0 <= row < self.count(): index = self.proxy_model.sourceModel().index(row, 0) if isinstance(index, QModelIndex): return self.proxy_model.sourceModel().data(index, Qt.DisplayRole) else: return None def set_current_index_from_row(self, row): new_index = self.proxy_model.sourceModel().index(row, 0) return self.set_current_index(new_index) def set_current_index(self, new_index: QModelIndex): self.current_index = new_index self.current_index_changed.emit(new_index) def deactivate(self): self.set_current_index(QModelIndex()) def auto_resize_header(self): """auto resize Header width on table view. """ width = self.viewport().width() duration_width = 120 self.horizontalHeader().resizeSection(0, width - duration_width) self.horizontalHeader().resizeSection(1, duration_width) def mousePressEvent(self, event): """左クリックされたらカーソル下にある要素を選択し、ドラッグを認識するために現在の位置を保存する。 :param event: QMousePressEvent :return: nothing """ self.isDragging = False if Qt.LeftButton == event.button(): self.dragStartPosition = event.pos() index = self.indexAt(self.dragStartPosition) if index in self.selectedIndexes(): self.isDragging = True self.wasSelected = True return self.rubberBand.setGeometry(QRect(self.dragStartPosition, QSize())) self.rubberBand.show() super(PlaylistView, self).mousePressEvent(event) def mouseMoveEvent(self, event): """start Drag and prepare for Drop. :type event: QMoveEvent マウスを動かした嶺がQApplication.startDragDistance()を超えると、Drag開始されたと認識し、 そのための準備を行う。QMimeDataを使って、データをやりとりする。 """ if not (event.buttons() & Qt.LeftButton): return if (event.pos() - self.dragStartPosition).manhattanLength() \ < QApplication.startDragDistance(): return if self.isDragging: indexes = self.selectedIndexes() urls = self.url_list(indexes) mimeData = QMimeData() # mimeData.setData(self.mime_URLS, convert_to_bytearray(urls)) mimeData.setUrls(urls) file_icon = self.style().standardIcon(QStyle.SP_FileIcon) pixmap = file_icon.pixmap(32, 32) drag = QDrag(self) drag.setMimeData(mimeData) drag.setPixmap(pixmap) drag.setHotSpot(QPoint(0, 0)) dropAction = drag.exec_(Qt.CopyAction | Qt.MoveAction, Qt.CopyAction) if dropAction == Qt.MoveAction: pass else: self.rubberBand.setGeometry( QRect(self.dragStartPosition, event.pos()).normalized()) super(PlaylistView, self).mouseMoveEvent(event) def mouseReleaseEvent(self, event): '''マウスを離したときにQRubberBandを隠す。 左クリックをpress と release がだいたい同じ位置であれば、その要素を1つだけ選択する。 :param event: ''' self.rubberBand.hide() if Qt.LeftButton == event.button( ) and Qt.NoModifier == event.modifiers(): if self.indexAt(event.pos()).row() == -1 and \ self.indexAt(self.dragStartPosition).row() == -1: self.clearSelection() elif len(self.selectedIndexes() ) / 2 == 1 and self.wasSelected == True: self.clearSelection() elif (event.pos() - self.dragStartPosition).manhattanLength() \ < QApplication.startDragDistance(): self.setCurrentIndex(self.indexAt(event.pos())) self.wasSelected = False super(PlaylistView, self).mouseReleaseEvent(event) def dragEnterEvent(self, event): """ドラッグした状態でWidgetに入った縁で呼ばれる関数。 :param event: QDragEvent :return: nothing イベントが発生元と発生しているWidgetが同一の場合はMoveActionにする。それ以外はCopyAction。 その二つの場合は受け入れられるように、accept()もしくはacceptProposedAction()を呼ぶ。 """ if event.mimeData().hasUrls() or event.mimeData().hasFormat( self.mime_URLS): if event.source() is self: event.setDropAction(Qt.MoveAction) event.accept() else: event.acceptProposedAction() else: event.ignore() def dragMoveEvent(self, event): """ドラッグした状態でWidget内を移動したときに呼ばれる。 :param event: QDragMoveEvent :return: nothing ドラッグしている要素の背景の色を変えて、どこにファイルがDropされるかをグラデーションした背景で 表現する。 """ if event.mimeData().hasUrls() or event.mimeData().hasFormat( self.mime_URLS): self.rubberBand.setGeometry( self.rectForDropIndicator( self.index_for_dropping_pos(event.pos()))) self.rubberBand.show() self.previousIndex = self.indexAt(event.pos()) if event.source() is self: event.setDropAction(Qt.MoveAction) event.accept() else: event.acceptProposedAction() else: event.ignore() def dragLeaveEvent(self, event): """ドラッグしたままWidget内を出たときにドラッグ下にあった要素の背景色の色を元に戻す。 :param event: QDragLeaveEvent :return: nothing """ self.rubberBand.hide() def dropEvent(self, event): """Dropされたらデータを取り出して、新たに登録する。 :param event: QDropEvent :return: nothing ファイルへのパスと移動前に登録してあった要素のindexを取り出す。 """ self.rubberBand.hide() if event.mimeData().hasUrls() or event.mimeData().hasFormat( self.mime_URLS): if event.mimeData().hasUrls(): urls = event.mimeData().urls() else: urls = convert_from_bytearray(event.mimeData().data( self.mime_URLS)) index = self.index_for_dropping_pos(event.pos()) if event.source() is self: self.move_items(self.selectedIndexes(), index) event.setDropAction(Qt.MoveAction) event.accept() else: self.add_items(urls) event.acceptProposedAction() else: event.ignore() def mouseDoubleClickEvent(self, event): if event.button() == Qt.LeftButton: new_index = self.indexAt(event.pos()) if not new_index.isValid(): return self.selectRow(new_index.row()) self.playlist_double_clicked.emit() def add_items(self, items: [QUrl], start: int = -1): """渡された要素をmodelに追加する。 :param items: 追加する項目 :param start: 追加するindexを表す。初期値は-1 start に −1を渡すと一番後ろに追加する。 """ if isinstance(items, QUrl): self.proxy_model.sourceModel().add(items) elif start == -1: for item in items: self.proxy_model.sourceModel().add(item) else: for item, i in items, range(start, len(items)): self.proxy_model.sourceModel().add(item, i) def delete_items(self): """渡されたインデックスを順番に消していく。 :param indexes: 消すためのインデックス """ indexes = self.selectedIndexes() if indexes: self.proxy_model.sourceModel().remove_items(indexes) else: return def move_items(self, indexes: [QModelIndex], dest: QModelIndex): self.proxy_model.sourceModel().move(indexes, dest.row()) def filter_same_title(self): dup = self.proxy_model.sourceModel().pickup_same_title() re = QRegularExpression('|'.join(dup)) self.proxy_model.setFilterRegularExpression(re) self.filtering.emit(' - filtered') def unfilter(self): self.proxy_model.setFilterWildcard('*') self.unfiltered.emit('') def index_for_dropping_pos(self, pos: QPoint) -> QModelIndex: """dropした場所のindexを返す。ただし、要素の高さ半分より下にある場合は、下の要素を返す。 :param pos: :return: posから導き出されたindex 挿入や移動のために、要素の間を意識している。 """ index = self.indexAt(pos) if index.row() < 0: new_index = self.proxy_model.sourceModel().index( self.proxy_model.sourceModel().rowCount(), 0) return new_index item_rect = self.visualRect(index) pos_in_rect = pos.y() - item_rect.top() if pos_in_rect < (item_rect.height() / 2): return index else: return self.proxy_model.sourceModel().index(index.row() + 1, 0) def rectForDropIndicator(self, index: QModelIndex) -> QRect: """QRubberBand を DropIndicatorとして表示するためのQRectを返す。 Geometryに渡されるので、表示位置となるようにQRectを作成する。 幅が表示領域、縦1pixelの棒で表示する。 """ item_rect = self.visualRect(index) top_left = item_rect.topLeft() size = QSize(item_rect.width(), 3) return QRect(top_left, size) def url_list(self, indexes): urls = [] for index in indexes: urls.append(self.proxy_model.sourceModel().data(index)) return sorted(set(urls), key=urls.index)
class FE14CharacterEditor(Ui_FE14CharacterEditor): def __init__(self, is_person=False, parent=None): super().__init__(parent) self.is_person = is_person self.module: TableModule = locator.get_scoped( "ModuleService").get_module("Characters") self.proxy_model = QSortFilterProxyModel() self.proxy_model.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive) self.proxy_model.setSourceModel(self.module.entries_model) self.characters_list_view.setModel(self.proxy_model) self.selection: Optional[PropertyContainer] = None self.character_details_form_1 = PropertyForm( self.module.element_template, category="character_description_1") self.character_details_form_contents_1.setLayout( self.character_details_form_1) self.character_details_form_2 = PropertyForm( self.module.element_template, category="character_description_2") self.character_details_form_contents_2.setLayout( self.character_details_form_2) self.character_details_form_2.fix_editor_width(100) self.stats_editor = MergedStatsEditor( ["Bases", "Growths", "Modifiers", "Penalties", "Bonuses"]) self.stats_form = PropertyForm(self.module.element_template, category="stats") self.stats_layout.addWidget(self.stats_editor) self.stats_layout.addLayout(self.stats_form) self.skills_form = PropertyForm(self.module.element_template, category="skills", sort_editors=True) self.skills_contents.setLayout(self.skills_form) self.flags_editor = MergedFlagsEditor( ["Bitflags (1)", "Bitflags (2)", "Bitflags (3)", "Bitflags (4)"], self.module.element_template) self.flags_editor_2 = MergedFlagsEditor( ["Bitflags (5)", "Bitflags (6)", "Bitflags (7)", "Bitflags (8)"], self.module.element_template) self.misc_form = PropertyForm(self.module.element_template, category="misc") self.misc_layout.addWidget(self.flags_editor) self.misc_layout.addWidget(self.flags_editor_2) self.misc_layout.addLayout(self.misc_form) self.ids_form = PropertyForm(self.module.element_template, category="ids") self.ids_tab.setLayout(self.ids_form) self.classes_form = PropertyForm(self.module.element_template, category="classes", sort_editors=True) self.classes_tab.setLayout(self.classes_form) if not self.is_person: self.dialogue_tab = DialogueEditor() self.supports_tab = QWidget() self.supports_layout = QHBoxLayout() self.supports_widget = FE14SupportWidget() self.supports_scroll = QScrollArea() self.supports_scroll_contents = QWidget() self.supports_scroll.setWidget(self.supports_scroll_contents) self.supports_scroll.setWidgetResizable(True) self.supports_layout.addWidget(self.supports_widget) self.supports_layout.addWidget(self.supports_scroll) self.supports_tab.setLayout(self.supports_layout) self.supports_form = PropertyForm(self.module.element_template, category="supports") self.supports_scroll_contents.setLayout(self.supports_form) self.tab_widget.addTab(self.supports_tab, "Supports") self.tab_widget.addTab(self.dialogue_tab, "Dialogue") self.context_menu = QMenu(self) self.context_menu.addActions( [self.action_add, self.action_remove, self.action_copy_to]) self.clear_selection_shortcut = QShortcut(QKeySequence.Cancel, self) self._install_signals() self._clear() def set_module(self, module: TableModule): self.module = module if self.module: self.proxy_model.setSourceModel(self.module.entries_model) else: self.proxy_model.setSourceModel(None) self.setEnabled(self.module is not None) self._clear() def _on_context_menu_requested(self, point: QPoint): self.context_menu.exec_(self.characters_list_view.mapToGlobal(point)) def _install_signals(self): self.characters_list_view.selectionModel().currentRowChanged.connect( self._update_selection) self.characters_list_view.customContextMenuRequested.connect( self._on_context_menu_requested) self.search_bar.textChanged.connect(self._update_filter) self.action_add.triggered.connect(self._on_add_character_triggered) self.action_remove.triggered.connect( self._on_remove_character_triggered) self.action_copy_to.triggered.connect(self._on_copy_to_triggered) self.clear_selection_shortcut.activated.connect(self._clear) if self.character_details_form_1.editors['Name'] != None: self.character_details_form_1.editors[ 'Name'].value_editor.editingFinished.connect( self._update_conversation_widget) def _clear(self): self.characters_list_view.clearSelection() self.characters_list_view.selectionModel().clearCurrentIndex() def _update_selection(self, index: QModelIndex): self.selection = self.proxy_model.data(index, QtCore.Qt.UserRole) self.portraits_tab.update_target(self.selection) self.character_details_form_1.update_target(self.selection) self.character_details_form_2.update_target(self.selection) self.stats_editor.update_target(self.selection) self.ids_form.update_target(self.selection) self.classes_form.update_target(self.selection) self.stats_form.update_target(self.selection) self.skills_form.update_target(self.selection) self.flags_editor.update_target(self.selection) self.flags_editor_2.update_target(self.selection) self.misc_form.update_target(self.selection) if not self.is_person: self.dialogue_tab.update_target(self.selection) self.supports_widget.update_target(self.selection) self.supports_form.update_target(self.selection) if self.selection: locator.get_scoped("SpriteService").get_sprite_for_character( self.selection, 0) self.action_remove.setEnabled(self.selection is not None) self.action_copy_to.setEnabled(self.selection is not None) self._update_portrait_box() def _update_portrait_box(self): portrait_service = locator.get_scoped("PortraitService") mini_portraits = portrait_service.get_sorted_portraits_for_character( self.selection, "bu") if mini_portraits: _, texture = mini_portraits[0] scene = QGraphicsScene() scene.addPixmap(QPixmap.fromImage(texture.image())) self.portrait_display.setScene(scene) else: self.portrait_display.setScene(None) def _update_filter(self): self.proxy_model.setFilterRegExp(self.search_bar.text()) def _on_add_character_triggered(self): model = self.module.entries_model model.insertRow(model.rowCount()) source = self.module.entries[0] destination = self.module.entries[-1] source.copy_to(destination) # Update any present conversation widget with the new obj list self._update_conversation_widget() def _on_remove_character_triggered(self): if self.characters_list_view.currentIndex().isValid(): model = self.module.entries_model model.removeRow(self.characters_list_view.currentIndex().row()) model.beginResetModel() model.endResetModel() # Update any present conversation widget with the new obj list self._update_conversation_widget() def _update_conversation_widget(self): for editor in self.supports_widget.service._conversation_editors: editor: FE14ConversationEditor character_list = list() [ character_list.append(child[1]) for child in self.module.children() ] editor.text_area._character_list = character_list def _on_copy_to_triggered(self): if not self.selection: return logging.info("Beginning copy to for " + self.module.name) choices = [] for i in range(0, len(self.module.entries)): choices.append( str(i + 1) + ". " + self.module.entries[i].get_display_name()) choice = QInputDialog.getItem(self, "Select Destination", "Destination", choices) if choice[1]: for i in range(0, len(choices)): if choice[0] == choices[i]: self.selection.copy_to(self.module.entries[i]) # Update any present conversation widget with the new obj list self._update_conversation_widget() else: logging.info("No choice selected for " + self.module.name + " copy to. Aborting.")
class ArtistsWidget(QDockWidget): """Widget displaying a list of artists.""" artistDeleted = Signal() def __init__(self, parent: QObject, manager: Manager): super().__init__(parent) self.setWindowTitle("Artists") self._manager = manager # Build widgets self.search_field = QLineEdit(self) self.table = _base.ExcelLikeTableView(self) self.table.setSelectionBehavior(QAbstractItemView.SelectRows) self.table.horizontalHeader().setSectionResizeMode( QHeaderView.ResizeToContents) self.table.horizontalHeader().setStretchLastSection(True) self.table.verticalHeader().setVisible(False) self.button_add = QPushButton("Add", self) self.button_remove = QPushButton("Remove", self) self.button_import = QPushButton("Import", self) self.button_export = QPushButton("Export", self) # Build layout layout_main = QVBoxLayout() layout_footer = QHBoxLayout() layout_footer.addWidget(self.search_field) layout_footer.addWidget(self.button_add) layout_footer.addWidget(self.button_remove) layout_footer.addWidget(self.button_import) layout_footer.addWidget(self.button_export) layout_main.addLayout(layout_footer) layout_main.addWidget(self.table) main_widget = QWidget(self) main_widget.setLayout(layout_main) self.setWidget(main_widget) # Configure model self.model = ArtistsListModel(self, self._manager.context) self._model_table = ArtistListToTableProxyModel(self) self._model_table.setSourceModel(self.model) self._model_table_proxy = QSortFilterProxyModel(self) self._model_table_proxy.setSourceModel(self._model_table) # Configure view self.table.setModel(self._model_table_proxy) # Connect signals for signal, callback in ( (self.model.dataChanged, self._on_data_changed), (self.button_add.pressed, self._on_add), (self.button_remove.pressed, self._on_remove), (self.button_export.pressed, self._on_export), (self.button_import.pressed, self._on_import), ( self.search_field.textChanged, self._model_table_proxy.setFilterWildcard, ), ): signal.connect(callback) def _on_add(self): """Add an artist to the list.""" with context_reset_model(self.model): self._manager.add_artist() def _on_remove(self): """Remove selected artists from the list.""" artists = tuple(self._iter_selected()) if not artists: return with context_reset_model(self.model): self._manager.remove_artists(artists) self.artistDeleted.emit() def _on_export(self): """Export the list of artists to a .csv file.""" path = show_save_dialog(self, "Export Artist", "CSV (*.csv)") if not path: return self._manager.export_artists(path) def _on_import(self): """Import the list of artists from a .csv file.""" path = show_open_dialog(self, "Import Artists", "CSV (*.csv)") if not path: return with context_reset_model(self.model): self._manager.import_artists(path) def _on_data_changed(self, top_left, bottom_right, roles): # pylint: disable=unused-argument """Called when the internal data changed. Notify if the change affect the solve.""" if {RoleArtistAvailability, RoleArtistTags} & set(roles): self._manager.set_dirty() def _iter_selected(self): return iter_selected_rows_data(self.table)
class TdisMainForm(QMainWindow): def __init__(self, parent=None): super().__init__() self.setWindowTitle("Родословная") self.resize(800, self.height()) self.distance = 1000 self.central_widget = QWidget() self.setCentralWidget(self.central_widget) layout = QGridLayout() self.central_widget.setLayout(layout) self.lb_find = QInvisibleButton('Поиск') self.lb_find.setFont(mainfont) self.te_find = QLineEdit() self.te_find.setFont(mainfont) layout.addWidget(self.te_find, 0, 0, 1, 1) layout.addWidget(self.lb_find, 0, 0, 1, 1) #if mode: # te.setReadOnly(False) self.lb_find.clicked.connect(self.button_pressed) self.te_find.returnPressed.connect(self.line_edit_return_pressed) self.table = QTableView() # Создаём таблицу self.table.doubleClicked.connect(self.viewPerson) layout.addWidget(self.table) self.table.setFocus() timer = QTimer(self) timer.singleShot(0, self.async_init) def async_init(self): self.database = AllTables('database/objects') self.model = TableModel(self.database.get_peoples()) self.table.setModel(self.model) self.table.resizeRowsToContents() self.table.setSelectionBehavior(QAbstractItemView.SelectRows) self.model.dataChanged.connect(self.table.update) # Работаем с выпадающим меню def openMenu(position): menu = QMenu() relAction = menu.addAction('Связи') menu.addSeparator() albAction = menu.addAction('Альбомы') menu.addSeparator() miniatureAction = menu.addAction('Миниатюра') menu.addSeparator() viewAction = menu.addAction('Просмотреть') addAction = menu.addAction('Добавить') editAction = menu.addAction('Редактировать') delAction = menu.addAction('Удалить') menu.addSeparator() drawGraphAction = menu.addAction('Построить дерево') menu.addSeparator() quitAction = menu.addAction('Выход') action = menu.exec_(self.table.mapToGlobal(position)) if action == viewAction: self.viewPerson() if action == miniatureAction: p = self.get_selected_people() print('p = ' + str(p)) if p is not None: photo_ids = self.database.get_all_photo_ids(p['pid']) path = 0 if photo_ids and type(photo_ids) == type( []) and len(photo_ids) > 0: path = self.database.get_photo_path( p['pid'], photo_ids[0]) gm = GalleryMiniature(p['pid'], path) gm.exec() if action == albAction: p = self.get_selected_people() if p is not None: self.albuns = AlbumViewer(p['pid'], self.database, 1) self.albuns.show() if action == addAction: self.personal_card = PersonalCard( self.database.get_people(self.database.add_people({})), self.database, 1) self.personal_card.exec_() self.line_edit_return_pressed() if action == editAction: p = self.get_selected_people() if p is not None: self.personal_card = PersonalCard(p, self.database, 1) self.personal_card.exec_() self.line_edit_return_pressed() if action == delAction: res = QMessageBox.question( self, 'ВНИМАНИЕ!!!', "Вы действительно хотите выполнить удаление?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if res == QMessageBox.Yes: select = self.table.selectionModel() if select.hasSelection(): id_list = [ index.data() for index in self.table.selectionModel().selection().indexes() if index.column() == 0 ] print(id_list) self.database.del_people(id_list) self.database.peoples.save() for pid in id_list: print('remove = ' + str(self.model.removeRow(pid))) self.line_edit_return_pressed() if action == relAction: pid = self.get_selected_pid() backup_relations = copy.deepcopy(self.database.relations) self.relation_card = RelationCard(pid, self.database, 2) if not self.relation_card.exec_(): self.database.relations = backup_relations if action == drawGraphAction: print('draw graph') #dialog = MyDialog() #dialog.exec_() #engine = dialog.engine engine = 'dot' self.gd = GraphDrawer(self.database, engine) if action == quitAction: qApp.quit() self.table.setContextMenuPolicy(Qt.CustomContextMenu) self.table.customContextMenuRequested.connect(openMenu) def get_selected_pid(self): pid_list = [ index.data() for index in self.table.selectionModel().selection().indexes() if index.column() == 0 ] if len(pid_list) == 1: return int(pid_list[0]) return None def get_selected_people(self): pid_list = [ index.data() for index in self.table.selectionModel().selection().indexes() if index.column() == 0 ] if len(pid_list) == 1: return self.database.get_people(int(pid_list[0])) return None def viewPerson(self): p = self.get_selected_people() if p is not None: self.personal_card = PersonalCard(p, self.database, 0) self.personal_card.show() def button_pressed(self): self.lb_find.stackUnder(self.te_find) self.te_find.setFocus() def line_edit_return_pressed(self): print(self.te_find.text()) self.model = TableModel(self.database.get_peoples()) self.proxy_model = QSortFilterProxyModel(self.model) self.proxy_model.setSourceModel(self.model) self.proxy_model.setFilterFixedString(self.te_find.text()) self.proxy_model.setFilterKeyColumn(-1) self.table.setModel(self.proxy_model) self.table.update() self.table.resizeRowsToContents() #sender = self.sender() self.te_find.stackUnder(self.lb_find) self.lb_find.setFocus()
class LayersList(QWidget): ''' LayerList class which acts as collapsable list. ''' def __init__(self, name, layers, filter, expand=True): super().__init__() self.setWindowModality(QtCore.Qt.WindowModal) self.currently_expanded = True self.main_layout = QVBoxLayout() self.main_layout.setMargin(0) self.main_layout.setSpacing(0) self.main_layout.setContentsMargins(0, 0, 0, 0) self.expand_button = QPushButton(name) self.expand_button.setToolTip(f"List of {name} Layers") self.expand_button.setIcon( QIcon(os.path.join(PATH, 'LayersList_Down.png'))) self.layer_list = QListView() self.layer_list.setDragEnabled(True) self.layer_list.setEditTriggers(QAbstractItemView.NoEditTriggers) self.layer_list.setWrapping(False) self.layer_list.setViewMode(self.layer_list.ListMode) self.container_model = QStandardItemModel() self.model = QSortFilterProxyModel() self.model.setSourceModel(self.container_model) self.model.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive) #self.model.cas filter.textChanged.connect(self.filter_model) for l in layers: self.container_model.appendRow( QStandardItem( QIcon(os.path.join(PATH, 'LayersList_Layer_Icon.png')), l)) self.layer_list.setModel(self.model) self.main_layout.addWidget(self.expand_button, 0, Qt.AlignTop) self.main_layout.addWidget(self.layer_list, 0, Qt.AlignTop) self.expand_button.clicked.connect(self.expand) self.setLayout(self.main_layout) self.resized_size = len(layers) * (self.layer_list.sizeHintForRow(0) + self.layer_list.frameWidth()) self.layer_list.setMaximumHeight(self.resized_size) self.layer_list.setMinimumHeight(self.resized_size) self.setMinimumWidth(self.layer_list.frameWidth()) self.set_styling() if not expand: self.expand() @QtCore.Slot() def expand(self): if self.currently_expanded: self.layer_list.setMinimumHeight(0) self.currently_expanded = False self.expand_button.setIcon( QIcon(os.path.join(PATH, 'LayersList_Up2.png'))) self.layer_list.setMaximumHeight(0) else: self.layer_list.setMinimumHeight(self.resized_size) self.currently_expanded = True self.expand_button.setIcon( QIcon(os.path.join(PATH, 'LayersList_Down.png'))) self.layer_list.setMaximumHeight(self.resized_size) def set_styling(self): self.setStyleSheet(''' background-color:white; ''') self.expand_button.setStyleSheet(''' background-color:#d6d2d2; text-align:left; ''') @QtCore.Slot() def filter_model(self, text): self.show() self.model.setFilterRegExp(QRegExp(text, QtCore.Qt.CaseInsensitive)) if not self.currently_expanded: self.expand() if self.model.rowCount() == 0: self.hide()
class MainWindow(QMainWindow): def __init__(self): super().__init__() hlayout = QHBoxLayout() layout = QVBoxLayout() self.filtert = QLineEdit() self.filtert.setPlaceholderText("Search...") self.table = QTableView() vlayout = QVBoxLayout() vlayout.addWidget(self.filtert) vlayout.addWidget(self.table) # Left/right pane. hlayout.addLayout(vlayout) hlayout.addLayout(layout) form = QFormLayout() self.track_id = QSpinBox() self.track_id.setDisabled(True) self.track_id.setRange(0, 2147483647) self.name = QLineEdit() self.album = QComboBox() self.media_type = QComboBox() self.genre = QComboBox() self.composer = QLineEdit() self.milliseconds = QSpinBox() self.milliseconds.setRange(0, 2147483647) self.milliseconds.setSingleStep(1) self.bytes = QSpinBox() self.bytes.setRange(0, 2147483647) self.bytes.setSingleStep(1) self.unit_price = QDoubleSpinBox() self.unit_price.setRange(0, 999) self.unit_price.setSingleStep(0.01) self.unit_price.setPrefix("$") form.addRow(QLabel("Track ID"), self.track_id) form.addRow(QLabel("Track name"), self.name) form.addRow(QLabel("Composer"), self.composer) form.addRow(QLabel("Milliseconds"), self.milliseconds) form.addRow(QLabel("Bytes"), self.bytes) form.addRow(QLabel("Unit Price"), self.unit_price) self.model = QSqlTableModel(db=db) self.proxy_model = QSortFilterProxyModel() self.proxy_model.setSourceModel(self.model) self.proxy_model.sort(1, Qt.AscendingOrder) self.proxy_model.setFilterKeyColumn(-1) # all columns self.table.setModel(self.proxy_model) # Update search when filter changes. self.filtert.textChanged.connect(self.proxy_model.setFilterFixedString) self.mapper = QDataWidgetMapper() self.mapper.setModel(self.proxy_model) self.mapper.addMapping(self.track_id, 0) self.mapper.addMapping(self.name, 1) self.mapper.addMapping(self.composer, 5) self.mapper.addMapping(self.milliseconds, 6) self.mapper.addMapping(self.bytes, 7) self.mapper.addMapping(self.unit_price, 8) self.model.setTable("Track") self.model.select() # Change the mapper selection using the table. self.table.selectionModel().currentRowChanged.connect( self.mapper.setCurrentModelIndex) self.mapper.toFirst() # tag::controls[] self.setMinimumSize(QSize(800, 400)) controls = QHBoxLayout() prev_rec = QPushButton("Previous") prev_rec.clicked.connect(self.mapper.toPrevious) next_rec = QPushButton("Next") next_rec.clicked.connect(self.mapper.toNext) save_rec = QPushButton("Save Changes") save_rec.clicked.connect(self.mapper.submit) controls.addWidget(prev_rec) controls.addWidget(next_rec) controls.addWidget(save_rec) layout.addLayout(form) layout.addLayout(controls) widget = QWidget() widget.setLayout(hlayout) self.setCentralWidget(widget)
def setup_p_view(self) -> None: """inits stacked widget page widget Returns: None""" self.p_view = QtWidgets.QWidget() self.stacked_widget.addWidget(self.p_view) self.model = QStandardItemModel(self.p_view) self.model.setHorizontalHeaderLabels(labels) self.filters = [] source_model = self.model for filter_num in range(7): filter = QSortFilterProxyModel() filter.setSourceModel(source_model) filter.setFilterKeyColumn(filter_num) source_model = filter self.filters.append(filter) delegate = ComboDelegate() self.table = QtWidgets.QTableView(self.p_view) self.table.setModel(self.filters[-1]) self.table.setItemDelegateForColumn(2, delegate) self.table.horizontalHeader().setStretchLastSection(True) self.table.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.header = FilterHeader(self.table) self.header.set_filter_boxes() self.header.setMaximumHeight(50) self.table.setHorizontalHeader(self.header) self.bt_burger = QPushButton(self.p_view) self.bt_burger.setIcon(QIcon("./data/menu2.svg")) self.bt_burger.setIconSize(QSize(30, 30)) self.bt_burger.setToolTip('slide out description') l_burger = QLabel("menu", self.p_view) self.bt_register_new = QPushButton(self.p_view) self.bt_register_new.setIcon(QIcon("./data/add.ico")) self.bt_register_new.setIconSize(QSize(30, 30)) self.bt_register_new.setToolTip("register new") l_register_new = QLabel("register new", self.p_view) self.bt_delete_column = QPushButton(self.p_view) self.bt_delete_column.setIcon(QIcon("./data/remove.ico")) self.bt_delete_column.setIconSize(QSize(30, 30)) self.bt_delete_column.setToolTip( "delete columns with min 1 cell selected") l_delete = QLabel("delete column", self.p_view) self.bt_hide_show_filter = QPushButton(self.p_view) self.bt_hide_show_filter.setIcon(QIcon("./data/show_hide.ico")) self.bt_hide_show_filter.setIconSize(QSize(30, 30)) self.bt_hide_show_filter.setToolTip("hide/show filter input") l_hide_show = QLabel("hide/show", self.p_view) self.left_btn_frame = QFrame(self.p_view) self.left_btn_frame.setMaximumWidth(40) self.left_btn_frame.setContentsMargins(0, 0, 0, 0) self.left_menu_frame = QFrame(self.p_view) self.left_menu_frame.setMaximumWidth(0) self.left_menu_frame.setContentsMargins(0, 0, 0, 0) p_view_layout2 = QtWidgets.QVBoxLayout(self.left_btn_frame) p_view_layout2.addWidget(self.bt_burger) p_view_layout2.addWidget(self.bt_register_new) p_view_layout2.addWidget(self.bt_delete_column) p_view_layout2.addWidget(self.bt_hide_show_filter) p_view_layout2.setAlignment(Qt.AlignTop) p_view_layout2.setContentsMargins(0, 0, 0, 0) self.p_view_layout3 = QtWidgets.QVBoxLayout(self.left_menu_frame) self.p_view_layout3.addWidget(l_burger) self.p_view_layout3.addWidget(l_register_new) self.p_view_layout3.addWidget(l_delete) self.p_view_layout3.addWidget(l_hide_show) self.p_view_layout3.setAlignment(Qt.AlignTop | Qt.AlignCenter) self.p_view_layout3.setContentsMargins(0, 0, 0, 0) self.p_view_layout3.setSpacing(25) p_view_layout = QHBoxLayout(self.p_view) p_view_layout.setContentsMargins(0, 0, 0, 0) p_view_layout.addWidget(self.left_btn_frame) p_view_layout.addWidget(self.left_menu_frame) p_view_layout.addWidget(self.table) self.p_view.setLayout(p_view_layout) self.p_view.addAction(self.action_open) self.p_view.addAction(self.action_save) self.p_view.addAction(self.action_new) self.p_view.addAction(self.action_print) self.p_view.addAction(self.action_register) self.p_view.addAction(self.action_hide_menu_bar)
class Window(QWidget): def __init__(self): super(Window, self).__init__() self.proxyModel = QSortFilterProxyModel() self.proxyModel.setDynamicSortFilter(True) self.sourceGroupBox = QGroupBox("Original Model") self.proxyGroupBox = QGroupBox("Sorted/Filtered Model") self.sourceView = QTreeView() self.sourceView.setRootIsDecorated(False) self.sourceView.setAlternatingRowColors(True) self.proxyView = QTreeView() self.proxyView.setRootIsDecorated(False) self.proxyView.setAlternatingRowColors(True) self.proxyView.setModel(self.proxyModel) self.proxyView.setSortingEnabled(True) self.sortCaseSensitivityCheckBox = QCheckBox("Case sensitive sorting") self.filterCaseSensitivityCheckBox = QCheckBox("Case sensitive filter") self.filterPatternLineEdit = QLineEdit() self.filterPatternLineEdit.setClearButtonEnabled(True) self.filterPatternLabel = QLabel("&Filter pattern:") self.filterPatternLabel.setBuddy(self.filterPatternLineEdit) self.filterSyntaxComboBox = QComboBox() self.filterSyntaxComboBox.addItem("Regular expression", REGULAR_EXPRESSION) self.filterSyntaxComboBox.addItem("Wildcard", WILDCARD) self.filterSyntaxComboBox.addItem("Fixed string", FIXED_STRING) self.filterSyntaxLabel = QLabel("Filter &syntax:") self.filterSyntaxLabel.setBuddy(self.filterSyntaxComboBox) self.filterColumnComboBox = QComboBox() self.filterColumnComboBox.addItem("Subject") self.filterColumnComboBox.addItem("Sender") self.filterColumnComboBox.addItem("Date") self.filterColumnLabel = QLabel("Filter &column:") self.filterColumnLabel.setBuddy(self.filterColumnComboBox) self.filterPatternLineEdit.textChanged.connect(self.filterRegExpChanged) self.filterSyntaxComboBox.currentIndexChanged.connect(self.filterRegExpChanged) self.filterColumnComboBox.currentIndexChanged.connect(self.filterColumnChanged) self.filterCaseSensitivityCheckBox.toggled.connect(self.filterRegExpChanged) self.sortCaseSensitivityCheckBox.toggled.connect(self.sortChanged) sourceLayout = QHBoxLayout() sourceLayout.addWidget(self.sourceView) self.sourceGroupBox.setLayout(sourceLayout) proxyLayout = QGridLayout() proxyLayout.addWidget(self.proxyView, 0, 0, 1, 3) proxyLayout.addWidget(self.filterPatternLabel, 1, 0) proxyLayout.addWidget(self.filterPatternLineEdit, 1, 1, 1, 2) proxyLayout.addWidget(self.filterSyntaxLabel, 2, 0) proxyLayout.addWidget(self.filterSyntaxComboBox, 2, 1, 1, 2) proxyLayout.addWidget(self.filterColumnLabel, 3, 0) proxyLayout.addWidget(self.filterColumnComboBox, 3, 1, 1, 2) proxyLayout.addWidget(self.filterCaseSensitivityCheckBox, 4, 0, 1, 2) proxyLayout.addWidget(self.sortCaseSensitivityCheckBox, 4, 2) self.proxyGroupBox.setLayout(proxyLayout) mainLayout = QVBoxLayout() mainLayout.addWidget(self.sourceGroupBox) mainLayout.addWidget(self.proxyGroupBox) self.setLayout(mainLayout) self.setWindowTitle("Basic Sort/Filter Model") self.resize(500, 450) self.proxyView.sortByColumn(1, Qt.AscendingOrder) self.filterColumnComboBox.setCurrentIndex(1) self.filterPatternLineEdit.setText("Andy|Grace") self.filterCaseSensitivityCheckBox.setChecked(True) self.sortCaseSensitivityCheckBox.setChecked(True) def setSourceModel(self, model): self.proxyModel.setSourceModel(model) self.sourceView.setModel(model) def filterRegExpChanged(self): syntax_nr = self.filterSyntaxComboBox.currentData() pattern = self.filterPatternLineEdit.text() if syntax_nr == WILDCARD: pattern = QRegularExpression.wildcardToRegularExpression(pattern) elif syntax_nr == FIXED_STRING: pattern = QRegularExpression.escape(pattern) regExp = QRegularExpression(pattern) if not self.filterCaseSensitivityCheckBox.isChecked(): options = regExp.patternOptions() options |= QRegularExpression.CaseInsensitiveOption regExp.setPatternOptions(options) self.proxyModel.setFilterRegularExpression(regExp) def filterColumnChanged(self): self.proxyModel.setFilterKeyColumn(self.filterColumnComboBox.currentIndex()) def sortChanged(self): if self.sortCaseSensitivityCheckBox.isChecked(): caseSensitivity = Qt.CaseSensitive else: caseSensitivity = Qt.CaseInsensitive self.proxyModel.setSortCaseSensitivity(caseSensitivity)
class DictWidget(QWidget): def __init__(self, parent=None): super().__init__() self.view = QTableView() self.model = DictModel() self.proxy_model = QSortFilterProxyModel() self.search_bar = QLineEdit() self._show_loading = False self.proxy_model.setSourceModel(self.model) self.view.setModel(self.proxy_model) self.view.setAlternatingRowColors(True) self.view.horizontalHeader().setStretchLastSection(True) self.view.setSelectionMode(QAbstractItemView.SingleSelection) self.view.setSelectionBehavior(QAbstractItemView.SelectRows) self.view.setSortingEnabled(True) self.view.verticalHeader().hide() self.search_bar.textChanged.connect( self.proxy_model.setFilterRegularExpression) self.search_bar.setVisible(False) self._show_search_action = QAction("show search bar") self._show_search_action.setCheckable(True) self._show_search_action.setShortcutContext(Qt.WidgetShortcut) self._show_search_action.setShortcut(QKeySequence.Find) self._show_search_action.triggered.connect(self._on_show_search) self._close_search_action = QAction() self._close_search_action.setShortcut(QKeySequence(Qt.Key_Escape)) self._close_search_action.setShortcutContext(Qt.WidgetShortcut) self._close_search_action.triggered.connect(self._on_close_search) self.view.addAction(self._show_search_action) self.search_bar.addAction(self._close_search_action) _layout = QVBoxLayout() _layout.addWidget(self.view) _layout.addWidget(self.search_bar) _layout.setContentsMargins(0, 0, 0, 0) self.setLayout(_layout) print("init") def set_dict(self, data: dict): self.model.set_dict(data) def _on_show_search(self): self.search_bar.setVisible(True) self.search_bar.setFocus(Qt.ShortcutFocusReason) def _on_close_search(self): self.search_bar.hide() self.search_bar.clear() self.view.setFocus(Qt.ShortcutFocusReason) def set_header_visible(self, visible=True): self.view.horizontalHeader().setVisible(visible) def clear(self): self.model.clear() def paintEvent(self, event: QPaintEvent): if self._show_loading: painter = QPainter(self) painter.drawText(self.rect(), Qt.AlignCenter, self.tr("Loading ...")) else: super().paintEvent(event) def set_loading(self, show=True): self._show_loading = True self.view.setVisible(not show) self.update()
class Ui_Main(object): def setupUi(self, Main): if not Main.objectName(): Main.setObjectName(u"Main") Main.resize(718, 453) Main.setMinimumSize(QSize(2018, 1053)) Main.setStyleSheet(u"") self.centralwidget = QWidget(Main) self.centralwidget.setObjectName(u"centralwidget") self.centralwidget.setMinimumSize(QSize(2018, 1053)) self.verticalLayout = QVBoxLayout(self.centralwidget) self.verticalLayout.setSpacing(0) self.verticalLayout.setObjectName(u"verticalLayout") self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.topbar_menu = QFrame(self.centralwidget) self.topbar_menu.setObjectName(u"topbar_menu") self.topbar_menu.setMinimumSize(QSize(20, 148)) self.topbar_menu.setMaximumSize(QSize(16777215, 148)) self.topbar_menu.setCursor(QCursor(Qt.ArrowCursor)) self.topbar_menu.setStyleSheet(u"background-color: black;") self.topbar_menu.setFrameShape(QFrame.WinPanel) self.topbar_menu.setFrameShadow(QFrame.Raised) self.horizontalLayout_2 = QHBoxLayout(self.topbar_menu) self.horizontalLayout_2.setSpacing(0) self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0) self.slideMenuFrame = QFrame(self.topbar_menu) self.slideMenuFrame.setObjectName(u"slideMenuFrame") self.slideMenuFrame.setMinimumSize(QSize(156, 160)) self.slideMenuFrame.setMaximumSize(QSize(1999, 1999)) self.slideMenuFrame.setStyleSheet(u"background-color: black;") self.slideMenuFrame.setFrameShape(QFrame.StyledPanel) self.slideMenuFrame.setFrameShadow(QFrame.Raised) self.horizontalLayout_3 = QHBoxLayout(self.slideMenuFrame) self.horizontalLayout_3.setSpacing(5) self.horizontalLayout_3.setObjectName(u"horizontalLayout_3") self.horizontalLayout_3.setContentsMargins(9, 6, 6, 6) self.slideMenuButton = QPushButton(self.slideMenuFrame) self.slideMenuButton.setObjectName(u"slideMenuButton") self.slideMenuButton.setMinimumSize(QSize(153, 100)) self.slideMenuButton.setMaximumSize(QSize(400, 500)) self.slideMenuButton.setCursor(QCursor(Qt.PointingHandCursor)) self.slideMenuButton.setStyleSheet( u"QPushButton{\n" " border-radius: 16px;\n" "}\n" "QPushButton:hover{\n" " background-color: rgb(208, 116, 53);\n" "}\n" "\n" "") icon = QIcon() icon.addFile(u":/Icons/Icons/Menu.svg", QSize(), QIcon.Normal, QIcon.Off) self.slideMenuButton.setIcon(icon) self.slideMenuButton.setIconSize(QSize(70, 70)) self.horizontalLayout_3.addWidget(self.slideMenuButton) self.horizontalLayout_2.addWidget(self.slideMenuFrame, 0, Qt.AlignLeft) self.titlleFrame = QFrame(self.topbar_menu) self.titlleFrame.setObjectName(u"titlleFrame") self.titlleFrame.setStyleSheet(u"margin-left: 20%;") self.titlleFrame.setFrameShape(QFrame.StyledPanel) self.titlleFrame.setFrameShadow(QFrame.Raised) self.verticalLayout_4 = QVBoxLayout(self.titlleFrame) self.verticalLayout_4.setObjectName(u"verticalLayout_4") self.verticalLayout_4.setContentsMargins(0, 6, 0, -1) self.titleLabel = QLabel(self.titlleFrame) self.titleLabel.setObjectName(u"titleLabel") font = QFont() font.setFamily(u"Bahnschrift") font.setPointSize(24) font.setBold(True) font.setItalic(True) font.setWeight(75) self.titleLabel.setFont(font) self.titleLabel.setStyleSheet(u"color: #bd6e38;\n" "") self.titleLabel.setAlignment(Qt.AlignCenter) self.verticalLayout_4.addWidget(self.titleLabel) self.horizontalLayout_2.addWidget(self.titlleFrame) self.window_buttons = QFrame(self.topbar_menu) self.window_buttons.setObjectName(u"window_buttons") self.window_buttons.setStyleSheet(u"border: none;\n" "margin-right: 5%;\n" "") self.window_buttons.setFrameShape(QFrame.WinPanel) self.window_buttons.setFrameShadow(QFrame.Raised) self.horizontalLayout = QHBoxLayout(self.window_buttons) self.horizontalLayout.setSpacing(2) self.horizontalLayout.setObjectName(u"horizontalLayout") self.horizontalLayout.setContentsMargins(0, 0, 0, 9) self.minimazeButton = QPushButton(self.window_buttons) self.minimazeButton.setObjectName(u"minimazeButton") self.minimazeButton.setMinimumSize(QSize(90, 90)) self.minimazeButton.setCursor(QCursor(Qt.PointingHandCursor)) self.minimazeButton.setStyleSheet( u"QPushButton:hover{\n" " background-color: rgb(154, 154, 154);\n" "}") icon1 = QIcon() icon1.addFile(u":/Icons/Icons/Minimaze-Icon.svg", QSize(), QIcon.Normal, QIcon.Off) self.minimazeButton.setIcon(icon1) self.minimazeButton.setIconSize(QSize(41, 41)) self.horizontalLayout.addWidget(self.minimazeButton) self.maximazeButton = QPushButton(self.window_buttons) self.maximazeButton.setObjectName(u"maximazeButton") self.maximazeButton.setMinimumSize(QSize(95, 95)) self.maximazeButton.setCursor(QCursor(Qt.PointingHandCursor)) self.maximazeButton.setStyleSheet( u"QPushButton:hover{\n" " background-color: rgb(154, 154, 154);\n" "}") icon2 = QIcon() icon2.addFile(u":/Icons/Icons/MaximazeButton_2.svg", QSize(), QIcon.Normal, QIcon.Off) self.maximazeButton.setIcon(icon2) self.maximazeButton.setIconSize(QSize(56, 56)) self.horizontalLayout.addWidget(self.maximazeButton) self.closeButton = QPushButton(self.window_buttons) self.closeButton.setObjectName(u"closeButton") self.closeButton.setMinimumSize(QSize(100, 100)) self.closeButton.setCursor(QCursor(Qt.PointingHandCursor)) self.closeButton.setStyleSheet(u"QPushButton:hover{\n" " background-color: rgb(170, 0, 0);\n" "}") icon3 = QIcon() icon3.addFile(u":/Icons/Icons/WindowCloseButton.svg", QSize(), QIcon.Normal, QIcon.Off) self.closeButton.setIcon(icon3) self.closeButton.setIconSize(QSize(52, 52)) self.horizontalLayout.addWidget(self.closeButton) self.horizontalLayout_2.addWidget(self.window_buttons, 0, Qt.AlignRight | Qt.AlignVCenter) self.verticalLayout.addWidget(self.topbar_menu) self.gridLayout = QGridLayout() self.gridLayout.setSpacing(0) self.gridLayout.setObjectName(u"gridLayout") self.left_side_menu = QFrame(self.centralwidget) self.left_side_menu.setObjectName(u"left_side_menu") self.left_side_menu.setMinimumSize(QSize(170, 0)) self.left_side_menu.setMaximumSize(QSize(170, 16777215)) self.left_side_menu.setStyleSheet(u"QFrame{\n" " background-color: black;\n" "}\n" "QPushButton{\n" " background: transparent;\n" " color: white;\n" "}") self.left_side_menu.setFrameShape(QFrame.WinPanel) self.left_side_menu.setFrameShadow(QFrame.Raised) self.verticalLayout_3 = QVBoxLayout(self.left_side_menu) self.verticalLayout_3.setSpacing(0) self.verticalLayout_3.setObjectName(u"verticalLayout_3") self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) self.left_menu_buttons = QFrame(self.left_side_menu) self.left_menu_buttons.setObjectName(u"left_menu_buttons") self.left_menu_buttons.setStyleSheet(u"margin-top: 10%;\n") self.left_menu_buttons.setFrameShape(QFrame.StyledPanel) self.left_menu_buttons.setFrameShadow(QFrame.Raised) self.verticalLayout_2 = QVBoxLayout(self.left_menu_buttons) self.verticalLayout_2.setSpacing(55) self.verticalLayout_2.setObjectName(u"verticalLayout_2") self.verticalLayout_2.setContentsMargins(0, 28, 0, 20) self.homeButton = QPushButton(self.left_menu_buttons) self.homeButton.setObjectName(u"homeButton") self.homeButton.setCursor(QCursor(Qt.PointingHandCursor)) self.homeButton.setStyleSheet(u"margin-left: 0%;") icon4 = QIcon() icon4.addFile(u":/Icons/Icons/New-Home-Icon.svg", QSize(), QIcon.Normal, QIcon.Off) self.homeButton.setIcon(icon4) self.homeButton.setIconSize(QSize(88, 88)) self.verticalLayout_2.addWidget(self.homeButton) self.listButton = QPushButton(self.left_menu_buttons) self.listButton.setObjectName(u"listButton") self.listButton.setCursor(QCursor(Qt.PointingHandCursor)) self.listButton.setStyleSheet(u"margin-left: 0%;") icon5 = QIcon() icon5.addFile(u":/Icons/Icons/New-Search-Icon.svg", QSize(), QIcon.Normal, QIcon.Off) self.listButton.setIcon(icon5) self.listButton.setIconSize(QSize(85, 85)) self.verticalLayout_2.addWidget(self.listButton) self.addButton = QPushButton(self.left_menu_buttons) self.addButton.setObjectName(u"addButton") self.addButton.setCursor(QCursor(Qt.PointingHandCursor)) self.addButton.setStyleSheet(u"margin-left: 0%;") icon6 = QIcon() icon6.addFile(u":/Icons/Icons/New_Add.svg", QSize(), QIcon.Normal, QIcon.Off) self.addButton.setIcon(icon6) self.addButton.setIconSize(QSize(85, 85)) self.verticalLayout_2.addWidget(self.addButton) self.removeButton = QPushButton(self.left_menu_buttons) self.removeButton.setObjectName(u"removeButton") self.removeButton.setCursor(QCursor(Qt.PointingHandCursor)) self.removeButton.setStyleSheet(u"margin-left: 0%;") icon7 = QIcon() icon7.addFile(u":/Icons/Icons/New_Delete.svg", QSize(), QIcon.Normal, QIcon.Off) self.removeButton.setIcon(icon7) self.removeButton.setIconSize(QSize(85, 85)) self.verticalLayout_2.addWidget(self.removeButton) self.verticalLayout_3.addWidget(self.left_menu_buttons, 0, Qt.AlignHCenter | Qt.AlignTop) self.versionLabel = QLabel(self.left_side_menu) self.versionLabel.setMinimumSize(QSize(100, 100)) self.versionLabel.setObjectName(u"versionLabel") self.versionLabel.setStyleSheet(u"color: white;\n" "margin-left: 10%;\n" "font-size: 30px;\n") self.verticalLayout_3.addWidget(self.versionLabel, 0, Qt.AlignHCenter | Qt.AlignBottom) self.gridLayout.addWidget(self.left_side_menu, 0, 0, 2, 1) self.footer = QFrame(self.centralwidget) self.footer.setObjectName(u"footer") self.footer.setMinimumSize(QSize(0, 40)) self.footer.setMaximumSize(QSize(16777215, 40)) self.footer.setStyleSheet(u"background-color: black;\n" "") self.footer.setFrameShape(QFrame.WinPanel) self.footer.setFrameShadow(QFrame.Raised) self.verticalLayout_10 = QVBoxLayout(self.footer) self.verticalLayout_10.setObjectName(u"verticalLayout_10") self.verticalLayout_10.setContentsMargins(0, 0, 0, 0) self.size_grip = QFrame(self.footer) self.size_grip.setObjectName(u"size_grip") self.size_grip.setMinimumSize(QSize(40, 30)) self.size_grip.setFrameShape(QFrame.StyledPanel) self.size_grip.setFrameShadow(QFrame.Raised) self.verticalLayout_10.addWidget(self.size_grip, 0, Qt.AlignRight | Qt.AlignBottom) self.gridLayout.addWidget(self.footer, 1, 1, 1, 1) self.content_menu = QFrame(self.centralwidget) self.content_menu.setObjectName(u"content_menu") self.content_menu.setMinimumSize(QSize(30, 60)) self.content_menu.setStyleSheet(u"background-color: #333;") self.content_menu.setFrameShape(QFrame.WinPanel) self.content_menu.setFrameShadow(QFrame.Raised) self.horizontalLayout_4 = QHBoxLayout(self.content_menu) self.horizontalLayout_4.setSpacing(0) self.horizontalLayout_4.setObjectName(u"horizontalLayout_4") self.horizontalLayout_4.setContentsMargins(0, 0, 0, 0) self.containerPages = QStackedWidget(self.content_menu) self.containerPages.setObjectName(u"containerPages") font1 = QFont() font1.setFamily(u"Bahnschrift") font1.setPointSize(30) self.containerPages.setFont(font1) self.containerPages.setStyleSheet(u"background: #333;\n" "QcheckBox{\n" " font: 12pt \"Bahnschript\";\n" " font-style: italic;\n" " color: white;\n" "}") self.HomeWWidget = QWidget() self.HomeWWidget.setObjectName(u"HomeWWidget") self.HomeWWidget.setStyleSheet( u"border-image: url(:/Icons/Icons/new_background.svg)") self.verticalLayout_11 = QVBoxLayout(self.HomeWWidget) self.verticalLayout_11.setObjectName(u"verticalLayout_11") self.verticalLayout_11.setContentsMargins(0, 0, 0, 0) self.homeTitleLabel = QLabel(self.HomeWWidget) self.homeTitleLabel.setObjectName(u"homeTitleLabel") font2 = QFont() font2.setFamily(u"Bahnschrift") font2.setPointSize(60) font2.setBold(True) font2.setWeight(75) self.homeTitleLabel.setFont(font2) self.homeTitleLabel.setStyleSheet(u"border-image: none;\n" "background: transparent;\n" "color: white;") self.homeTitleLabel.setAlignment(Qt.AlignCenter) self.verticalLayout_11.addWidget(self.homeTitleLabel) self.homeintroLabel = QLabel(self.HomeWWidget) self.homeintroLabel.setObjectName(u"homeintroLabel") font3 = QFont() font3.setFamily(u"Bahnschrift") font3.setPointSize(12) self.homeintroLabel.setFont(font3) self.homeintroLabel.setStyleSheet(u"border-image: none;\n" "background: transparent;\n" "color: white;\n") self.homeintroLabel.setAlignment(Qt.AlignCenter) self.verticalLayout_11.addWidget(self.homeintroLabel, 0, Qt.AlignHCenter | Qt.AlignTop) self.containerPages.addWidget(self.HomeWWidget) self.SearchWidget = QWidget() self.SearchWidget.setObjectName(u"SearchWidget") self.verticalLayout_9 = QVBoxLayout(self.SearchWidget) self.verticalLayout_9.setSpacing(7) self.verticalLayout_9.setObjectName(u"verticalLayout_9") self.verticalLayout_9.setContentsMargins(5, 0, 5, 5) self.searchbarFrame = QFrame(self.SearchWidget) self.searchbarFrame.setObjectName(u"searchbarFrame") self.searchbarFrame.setFrameShape(QFrame.StyledPanel) self.searchbarFrame.setFrameShadow(QFrame.Raised) self.horizontalLayout_8 = QHBoxLayout(self.searchbarFrame) self.horizontalLayout_8.setObjectName(u"horizontalLayout_8") self.searchbarLineEdit = QLineEdit(self.searchbarFrame) self.searchbarLineEdit.setObjectName(u"searchbarLineEdit") self.searchbarLineEdit.setStyleSheet(u"color: white;\n" "border: 1px solid white;\n" "border-radius: 30%;\n" "font-size: 45px;\n") self.searchbarLineEdit.setMinimumHeight(70) self.searchbarLineEdit.setPlaceholderText("Căutați aici...") self.searchbarLineEdit.setAlignment(Qt.AlignCenter) self.horizontalLayout_8.addWidget(self.searchbarLineEdit) self.verticalLayout_9.addWidget(self.searchbarFrame) self.FilterCheckBoxFrame = QFrame(self.SearchWidget) self.FilterCheckBoxFrame.setObjectName(u"FilterCheckBoxFrame") self.FilterCheckBoxFrame.setStyleSheet(u"QRadioButton{\n" " font: 9pt \"Bahnschript\";\n" " font-style: italic;\n" " color: white;\n" "}") self.FilterCheckBoxFrame.setFrameShape(QFrame.StyledPanel) self.FilterCheckBoxFrame.setFrameShadow(QFrame.Raised) self.horizontalLayout_9 = QHBoxLayout(self.FilterCheckBoxFrame) self.horizontalLayout_9.setObjectName(u"horizontalLayout_9") self.recentDateOrderRadioButton = QRadioButton( self.FilterCheckBoxFrame) self.recentDateOrderRadioButton.setObjectName( u"recentDateOrderRadioButton") self.horizontalLayout_9.addWidget(self.recentDateOrderRadioButton, 0, Qt.AlignHCenter) self.oldDateOrderRadioButton = QRadioButton(self.FilterCheckBoxFrame) self.oldDateOrderRadioButton.setObjectName(u"oldDateOrderRadioButton") self.horizontalLayout_9.addWidget(self.oldDateOrderRadioButton, 0, Qt.AlignHCenter) self.alphabeticalOrderRadioButton = QRadioButton( self.FilterCheckBoxFrame) self.alphabeticalOrderRadioButton.setObjectName( u"alphabeticalOrderRadioButton") self.horizontalLayout_9.addWidget(self.alphabeticalOrderRadioButton, 0, Qt.AlignHCenter) self.verticalLayout_9.addWidget(self.FilterCheckBoxFrame) self.tableFrame = QFrame(self.SearchWidget) self.tableFrame.setObjectName(u"tableFrame") self.tableFrame.setStyleSheet(u"border: 1px solid white;\n" "border-radius: 4px;\n" "margin-right:20%;\n" "margin-left:20%;\n") self.tableFrame.setFrameShape(QFrame.StyledPanel) self.tableFrame.setFrameShadow(QFrame.Raised) self.verticalLayout_12 = QVBoxLayout(self.tableFrame) self.verticalLayout_12.setSpacing(0) self.verticalLayout_12.setObjectName(u"verticalLayout_12") self.verticalLayout_12.setContentsMargins(0, 0, 0, 0) self.clientsDataTableView = QTableView(self.SearchWidget) data = pd.DataFrame(service.repository, columns=['Nume', 'ID', 'Creat la', 'Expiră la']) self.model = TableModel(data) # filter proxy model self.filter_proxy_model = QSortFilterProxyModel() self.filter_proxy_model.setSourceModel(self.model) self.filter_proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive) self.filter_proxy_model.setFilterKeyColumn( -1) # -1 is for searching in all columns self.clientsDataTableView.setModel(self.filter_proxy_model) self.clientsDataTableView.verticalHeader().hide( ) # REMOVE VERTICAL HEADER self.clientsDataTableView.horizontalHeader().setSectionResizeMode( QHeaderView.Interactive) self.clientsDataTableView.setHorizontalScrollBarPolicy( Qt.ScrollBarAlwaysOff) self.clientsDataTableView.horizontalHeader().setStretchLastSection( True) self.clientsDataTableView.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) self.clientsDataTableView.setSelectionBehavior(QTableView.SelectRows) self.clientsDataTableView.setObjectName(u"clientsDataTableView") self.clientsDataTableView.setStyleSheet(u"border: none;\n" "margin-right:0%;\n" "margin-left:0%;\n" "font: 9pt 'Bahnschript';\n" "font-style: bold italic;\n") self.verticalLayout_12.addWidget(self.clientsDataTableView) self.verticalLayout_9.addWidget(self.tableFrame) self.ViewClientButton = QPushButton(self.SearchWidget) self.ViewClientButton.setObjectName(u"ViewClientButton") self.ViewClientButton.setMinimumSize(QSize(100, 50)) self.ViewClientButton.setCursor(QCursor(Qt.PointingHandCursor)) font4 = QFont() font4.setPointSize(15) self.ViewClientButton.setFont(font4) self.ViewClientButton.setStyleSheet(u"QPushButton{\n" " background-color: #bd6e38;\n" " color: white;\n" " border: 4px solid white;\n" " border-radius: 15px;\n" " margin-bottom: 5%;\n" "}\n" "QPushButton:hover{\n" " background-color: black;\n" " border-color: #bd6e38;\n" "}\n") self.verticalLayout_9.addWidget(self.ViewClientButton, 0, Qt.AlignHCenter) self.containerPages.addWidget(self.SearchWidget) self.ViewClientWidget = QWidget() self.ViewClientWidget.setObjectName(u"ViewClientWidget") self.verticalLayout_13 = QVBoxLayout(self.ViewClientWidget) self.verticalLayout_13.setObjectName(u"verticalLayout_13") self.ClientViewFrame = QFrame(self.ViewClientWidget) self.ClientViewFrame.setObjectName(u"ClientViewFrame") self.ClientViewFrame.setStyleSheet(u"QLabel{\n" " font: 12pt \"Bahnschript\";\n" " font-style: italic;\n" " color: white;\n" "}\n" "\n" "QLineEdit{\n" " border-right: none;\n" " border-top: none;\n" " border-left: none;\n" " border-bottom: 1px solid white;\n" "}") self.ClientViewFrame.setFrameShape(QFrame.StyledPanel) self.ClientViewFrame.setFrameShadow(QFrame.Raised) self.verticalLayout_14 = QVBoxLayout(self.ClientViewFrame) self.verticalLayout_14.setObjectName(u"verticalLayout_14") self.verticalLayout_14.setContentsMargins(-1, 15, 0, 0) self.gridLayout_4 = QGridLayout() self.gridLayout_4.setObjectName(u"gridLayout_4") self.gridLayout_4.setHorizontalSpacing(35) self.gridLayout_4.setVerticalSpacing(20) self.gridLayout_4.setContentsMargins(20, -1, 20, -1) self.NameLabel = QLabel(self.ClientViewFrame) self.NameLabel.setObjectName(u"NameLabel") self.gridLayout_4.addWidget(self.NameLabel, 0, 0, 1, 1) self.nameLineEdit = QLineEdit(self.ClientViewFrame) self.nameLineEdit.setObjectName(u"nameLineEdit") self.nameLineEdit.setStyleSheet(u" font: 12pt \"Bahnschript\";\n" " font-style: italic;\n" " color: white;") self.nameLineEdit.setAlignment(Qt.AlignCenter) self.gridLayout_4.addWidget(self.nameLineEdit, 0, 1, 1, 1) self.CreationDateLabel = QLabel(self.ClientViewFrame) self.CreationDateLabel.setObjectName(u"CreationDateLabel") self.gridLayout_4.addWidget(self.CreationDateLabel, 0, 2, 1, 1) self.crationDateLineEdit = QLineEdit(self.ClientViewFrame) self.crationDateLineEdit.setObjectName(u"creationDateLineEdit") self.crationDateLineEdit.setStyleSheet( u" font: 12pt \"Bahnschript\";\n" " font-style: italic;\n" " color: white;") self.crationDateLineEdit.setAlignment(Qt.AlignCenter) self.gridLayout_4.addWidget(self.crationDateLineEdit, 0, 3, 1, 1) self.IdLabel = QLabel(self.ClientViewFrame) self.IdLabel.setObjectName(u"IdLabel") self.gridLayout_4.addWidget(self.IdLabel, 1, 0, 1, 1) self.IdLineEdit = QLineEdit(self.ClientViewFrame) self.IdLineEdit.setObjectName(u"IdLineEdit") self.IdLineEdit.setStyleSheet(u" font: 12pt \"Bahnschript\";\n" " font-style: italic;\n" " color: white;") self.IdLineEdit.setAlignment(Qt.AlignCenter) self.gridLayout_4.addWidget(self.IdLineEdit, 1, 1, 1, 1) self.ExpirationDateLabel = QLabel(self.ClientViewFrame) self.ExpirationDateLabel.setObjectName(u"ExpirationDateLabel") self.gridLayout_4.addWidget(self.ExpirationDateLabel, 1, 2, 1, 1) self.expirationDateLineEdit = QLineEdit(self.ClientViewFrame) self.expirationDateLineEdit.setObjectName(u"expirationDateLineEdit") self.expirationDateLineEdit.setStyleSheet( u" font: 12pt \"Bahnschript\";\n" " font-style: italic;\n" " color: white;") self.expirationDateLineEdit.setAlignment(Qt.AlignCenter) self.gridLayout_4.addWidget(self.expirationDateLineEdit, 1, 3, 1, 1) self.verticalLayout_14.addLayout(self.gridLayout_4) self.Valid_InvalidLabel = QLabel(self.ClientViewFrame) self.Valid_InvalidLabel.setObjectName(u"Valid_InvalidLabel") font5 = QFont() font5.setFamily(u"Bahnschript") font5.setPointSize(25) font5.setBold(False) font5.setItalic(True) font5.setWeight(50) self.Valid_InvalidLabel.setFont(font5) self.Valid_InvalidLabel.setStyleSheet(u"font: 25pt \"Bahnschript\";\n" "font-style: italic;\n" "color: white;") self.Valid_InvalidLabel.setAlignment(Qt.AlignCenter) self.verticalLayout_14.addWidget(self.Valid_InvalidLabel) self.PrintButton = QPushButton(self.ClientViewFrame) self.PrintButton.setObjectName(u"PrintButton") self.PrintButton.setMinimumSize(QSize(180, 130)) self.PrintButton.setCursor(QCursor(Qt.PointingHandCursor)) font6 = QFont() font6.setPointSize(11) font6.setBold(True) font6.setWeight(75) self.PrintButton.setFont(font6) self.PrintButton.setStyleSheet(u"QPushButton{\n" "background-color: #bd6e38;\n" "color: white;\n" "border: 4px solid white;\n" "border-radius: 30%;\n" "margin-bottom: 40%;\n" "}\n" "QPushButton:hover{\n" " background-color: black;\n" " border-color: #bd6e38;\n" "}\n") self.verticalLayout_14.addWidget(self.PrintButton, 0, Qt.AlignHCenter) self.verticalLayout_13.addWidget(self.ClientViewFrame) self.containerPages.addWidget(self.ViewClientWidget) self.AddWidget = QWidget() self.AddWidget.setObjectName(u"AddWidget") self.verticalLayout_6 = QVBoxLayout(self.AddWidget) self.verticalLayout_6.setObjectName(u"verticalLayout_6") self.addTextFrame = QFrame(self.AddWidget) self.addTextFrame.setObjectName(u"addTextFrame") self.addTextFrame.setStyleSheet(u"border-bottom: 1px solid #bd6e38;\n" "border-top: 2px solid #bd6e38;") self.addTextFrame.setFrameShape(QFrame.StyledPanel) self.addTextFrame.setFrameShadow(QFrame.Raised) self.verticalLayout_5 = QVBoxLayout(self.addTextFrame) self.verticalLayout_5.setObjectName(u"verticalLayout_5") self.verticalLayout_5.setContentsMargins(0, -1, 0, -1) self.addTextLabel = QLabel(self.addTextFrame) self.addTextLabel.setObjectName(u"addTextLabel") font7 = QFont() font7.setFamily(u"Bahnschrift") font7.setPointSize(15) font7.setItalic(True) self.addTextLabel.setFont(font7) self.addTextLabel.setStyleSheet(u"color: white;\n" "border: none;") self.addTextLabel.setAlignment(Qt.AlignCenter) self.verticalLayout_5.addWidget(self.addTextLabel) self.verticalLayout_6.addWidget(self.addTextFrame) self.InsertNameFrame = QFrame(self.AddWidget) self.InsertNameFrame.setObjectName(u"InsertNameFrame") self.InsertNameFrame.setFrameShape(QFrame.StyledPanel) self.InsertNameFrame.setFrameShadow(QFrame.Raised) self.horizontalLayout_5 = QHBoxLayout(self.InsertNameFrame) self.horizontalLayout_5.setSpacing(13) self.horizontalLayout_5.setObjectName(u"horizontalLayout_5") self.horizontalLayout_5.setContentsMargins(0, 0, 0, 0) self.addNameLabel = QLabel(self.InsertNameFrame) self.addNameLabel.setObjectName(u"addNameLabel") font8 = QFont() font8.setFamily(u"Bahnschrift") font8.setPointSize(17) font8.setItalic(True) self.addNameLabel.setFont(font8) self.addNameLabel.setStyleSheet(u"color: white;\n" "margin-left: 70%;\n" "margin-bottom: 10%;\n" "") self.addNameLabel.setAlignment(Qt.AlignCenter) self.addNameLabel.setMargin(0) self.horizontalLayout_5.addWidget(self.addNameLabel) self.addLineEdit = QLineEdit(self.InsertNameFrame) self.addLineEdit.setObjectName(u"addLineEdit") self.addLineEdit.setMinimumSize(QSize(50, 0)) font9 = QFont() font9.setFamily(u"Bahnschrift") font9.setPointSize(17) self.addLineEdit.setFont(font9) self.addLineEdit.setStyleSheet(u"margin-right: 70%;\n" "color: white;\n" "border-top: none;\n" "border-left: none;\n" "border-right: none;\n" "border-bottom: 1px solid white;\n" "\n" "") self.addLineEdit.setAlignment(Qt.AlignCenter) self.addLineEdit.setDragEnabled(False) self.horizontalLayout_5.addWidget(self.addLineEdit) self.verticalLayout_6.addWidget(self.InsertNameFrame) self.addButtonsFrame = QFrame(self.AddWidget) self.addButtonsFrame.setObjectName(u"addButtonsFrame") self.addButtonsFrame.setFrameShape(QFrame.StyledPanel) self.addButtonsFrame.setFrameShadow(QFrame.Raised) self.horizontalLayout_6 = QHBoxLayout(self.addButtonsFrame) self.horizontalLayout_6.setSpacing(40) self.horizontalLayout_6.setObjectName(u"horizontalLayout_6") self.horizontalLayout_6.setContentsMargins(0, 0, 0, 0) self.addPushBUtton = QPushButton(self.addButtonsFrame) self.addPushBUtton.setObjectName(u"addPushBUtton") self.addPushBUtton.setCursor(QCursor(Qt.PointingHandCursor)) self.addPushBUtton.setMinimumSize(QSize(0, 30)) font10 = QFont() font10.setFamily(u"Bahnschrift") font10.setPointSize(14) self.addPushBUtton.setFont(font10) self.addPushBUtton.setStyleSheet(u"QPushButton{\n" " background-color: #bd6e38;\n" " color: white;\n" " border: 4px solid white;\n" " border-radius: 15px;\n" " margin-left: 70%;\n" " margin-right: 50%;\n" "}\n" "QPushButton:hover{\n" " background-color: black;\n" " border-color: #bd6e38;\n " "}\n") self.horizontalLayout_6.addWidget(self.addPushBUtton) self.quitPushButton = QPushButton(self.addButtonsFrame) self.quitPushButton.setObjectName(u"quitPushButton") self.quitPushButton.setCursor(QCursor(Qt.PointingHandCursor)) self.quitPushButton.setMinimumSize(QSize(0, 34)) self.quitPushButton.setFont(font10) self.quitPushButton.setStyleSheet(u"QPushButton{\n" " background-color: #bd6e38;\n" " color: white;\n" " border: 4px solid white;\n" " border-radius: 15px;\n" " margin-left: 70%;\n" " margin-right: 50%;\n" "}\n" "QPushButton:hover{\n" " background-color: black;\n" " border-color: #bd6e38;\n " "}\n") self.horizontalLayout_6.addWidget(self.quitPushButton) self.verticalLayout_6.addWidget(self.addButtonsFrame) self.containerPages.addWidget(self.AddWidget) self.RemoveWidget = QWidget() self.RemoveWidget.setObjectName(u"RemoveWidget") self.horizontalLayout_11 = QHBoxLayout(self.RemoveWidget) self.horizontalLayout_11.setSpacing(2) self.horizontalLayout_11.setObjectName(u"horizontalLayout_11") self.horizontalLayout_11.setContentsMargins(0, 2, 2, 3) self.removeElementsFrame = QFrame(self.RemoveWidget) self.removeElementsFrame.setObjectName(u"removeElementsFrame") self.verticalLayout_16 = QVBoxLayout(self.removeElementsFrame) self.verticalLayout_16.setSpacing(0) self.verticalLayout_16.setObjectName(u"verticalLayout_16") self.verticalLayout_16.setContentsMargins(0, -1, -1, -1) self.verticalLayout_15 = QVBoxLayout() self.verticalLayout_15.setObjectName(u"verticalLayout_15") self.removeTextFrame = QFrame(self.removeElementsFrame) self.removeTextFrame.setObjectName(u"removeTextFrame") self.removeTextFrame.setStyleSheet( u"border-right: 4px solid #bd6e38;\n" "border-bottom: 4px solid #bd6e38;\n" "border: 4px solid #bd6e38;\n" "border-top-right-radius: 5%;\n" "border-bottom-right-radius: 5%;\n" "border-left: none;\n") self.removeTextFrame.setFrameShape(QFrame.StyledPanel) self.removeTextFrame.setFrameShadow(QFrame.Raised) self.verticalLayout_7 = QVBoxLayout(self.removeTextFrame) self.verticalLayout_7.setObjectName(u"verticalLayout_7") self.verticalLayout_7.setContentsMargins(0, -1, 0, -1) self.removeLabel = QLabel(self.removeTextFrame) self.removeLabel.setObjectName(u"removeLabel") self.removeLabel.setFont(font7) self.removeLabel.setStyleSheet(u"color: white;\n" "border: none;") self.removeLabel.setAlignment(Qt.AlignCenter) self.verticalLayout_7.addWidget(self.removeLabel) self.verticalLayout_15.addWidget(self.removeTextFrame, 0, Qt.AlignLeft | Qt.AlignTop) self.removeSearchbarFrame = QFrame(self.removeElementsFrame) self.removeSearchbarFrame.setObjectName(u"removeSearchbarFrame") self.removeSearchbarFrame.setStyleSheet(u"") self.removeSearchbarFrame.setFrameShape(QFrame.StyledPanel) self.removeSearchbarFrame.setFrameShadow(QFrame.Raised) self.horizontalLayout_10 = QHBoxLayout(self.removeSearchbarFrame) self.horizontalLayout_10.setObjectName(u"horizontalLayout_10") self.removeSearchbarLineEdit = QLineEdit(self.removeSearchbarFrame) self.removeSearchbarLineEdit.setObjectName(u"removeSearchbarLineEdit") self.removeSearchbarLineEdit.setStyleSheet( u"color: white;\n" "border: 1px solid white;\n" "border-radius: 30%;\n" "font: 15pt 'BahnSchrift'\n") self.removeSearchbarLineEdit.setPlaceholderText("Căutați aici...") self.removeSearchbarLineEdit.setAlignment(Qt.AlignCenter) self.horizontalLayout_10.addWidget(self.removeSearchbarLineEdit) self.verticalLayout_15.addWidget(self.removeSearchbarFrame, 0, Qt.AlignTop) self.verticalLayout_16.addLayout(self.verticalLayout_15) self.removeButtonsFrame = QFrame(self.removeElementsFrame) self.removeButtonsFrame.setObjectName(u"removeButtonsFrame") self.removeButtonsFrame.setFrameShape(QFrame.StyledPanel) self.removeButtonsFrame.setFrameShadow(QFrame.Raised) self.horizontalLayout_7 = QHBoxLayout(self.removeButtonsFrame) self.horizontalLayout_7.setSpacing(40) self.horizontalLayout_7.setObjectName(u"horizontalLayout_7") self.horizontalLayout_7.setContentsMargins(0, 0, 0, 0) self.removePushButton = QPushButton(self.removeButtonsFrame) self.removePushButton.setObjectName(u"removePushButton") self.removePushButton.setCursor(QCursor(Qt.PointingHandCursor)) self.removePushButton.setMinimumSize(QSize(0, 34)) self.removePushButton.setFont(font10) self.removePushButton.setStyleSheet(u"QPushButton{\n" " background-color: #bd6e38;\n" " color: white;\n" " border: 4px solid white;\n" " border-radius: 15px;\n" " margin-right: 20%;\n" " margin-left:40%;\n" "}\n" "QPushButton:hover{\n" " background-color: black;\n" " border-color: #bd6e38;\n" "}\n") self.horizontalLayout_7.addWidget(self.removePushButton) self.quitPushButton_2 = QPushButton(self.removeButtonsFrame) self.quitPushButton_2.setObjectName(u"quitPushButton_2") self.quitPushButton_2.setCursor(QCursor(Qt.PointingHandCursor)) self.quitPushButton_2.setMinimumSize(QSize(0, 34)) self.quitPushButton_2.setFont(font10) self.quitPushButton_2.setStyleSheet(u"QPushButton{\n" " background-color: #bd6e38;\n" " color: white;\n" " border: 4px solid white;\n" " border-radius: 15px;\n" " margin-right: 20%;\n" " margin-left: 20%;\n" "}\n" "QPushButton:hover{\n" " background-color: black;\n" " border-color: #bd6e38;\n" "}\n") self.horizontalLayout_7.addWidget(self.quitPushButton_2) self.verticalLayout_16.addWidget(self.removeButtonsFrame, 0, Qt.AlignBottom) self.horizontalLayout_11.addWidget(self.removeElementsFrame, 0, Qt.AlignLeft) self.removeTableFrame = QFrame(self.RemoveWidget) self.removeTableFrame.setObjectName(u"removeTableFrame") self.removeTableFrame.setStyleSheet(u"border: 1px solid white;\n" "border-radius: 4px;\n") self.removeTableFrame.setFrameShape(QFrame.StyledPanel) self.removeTableFrame.setFrameShadow(QFrame.Raised) self.verticalLayout_8 = QVBoxLayout(self.removeTableFrame) self.verticalLayout_8.setObjectName(u"verticalLayout_8") self.verticalLayout_8.setContentsMargins(0, 0, 0, 0) self.removetableView = QTableView(self.removeTableFrame) self.remove_model = TableModel(data) self.remove_filter_proxy_model = QSortFilterProxyModel() self.remove_filter_proxy_model.setSourceModel(self.remove_model) self.remove_filter_proxy_model.setFilterCaseSensitivity( Qt.CaseInsensitive) self.remove_filter_proxy_model.setFilterKeyColumn(-1) self.removetableView.setModel(self.remove_filter_proxy_model) self.removetableView.verticalHeader().hide() # REMOVE VERTICAL HEADER self.removetableView.horizontalHeader().setSectionResizeMode( QHeaderView.Interactive) self.removetableView.setHorizontalScrollBarPolicy( Qt.ScrollBarAlwaysOff) self.removetableView.horizontalHeader().setStretchLastSection(True) self.removetableView.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) self.removetableView.setSelectionBehavior(QTableView.SelectRows) self.removetableView.setObjectName(u"removetableView") self.removetableView.setStyleSheet(u"border: none;\n" "margin-right:0%;\n" "margin-left:0%;\n" "font: 9pt 'Bahnschript';\n" "font-style: bold italic;\n") self.verticalLayout_8.addWidget(self.removetableView) self.horizontalLayout_11.addWidget(self.removeTableFrame) self.containerPages.addWidget(self.RemoveWidget) self.horizontalLayout_4.addWidget(self.containerPages) self.gridLayout.addWidget(self.content_menu, 0, 1, 1, 1) self.verticalLayout.addLayout(self.gridLayout) Main.setCentralWidget(self.centralwidget) self.retranslateUi(Main) self.containerPages.setCurrentIndex(0) QMetaObject.connectSlotsByName(Main) # setupUi def retranslateUi(self, Main): Main.setWindowTitle( QCoreApplication.translate("Main", u"MainWindow", None)) self.slideMenuButton.setText("") self.titleLabel.setText( QCoreApplication.translate( "Main", u"<html><head/><body><p>STIHL SERVER</p></body></html>", None)) self.minimazeButton.setText("") self.maximazeButton.setText("") self.closeButton.setText("") self.versionLabel.setText( QCoreApplication.translate("Main", u"v 1.2", None)) self.homeTitleLabel.setText( QCoreApplication.translate("Main", u"HOME", None)) self.homeintroLabel.setText( QCoreApplication.translate( "Main", u"<html><head/><body><p><span style=\"background-color:#333;\">Aceasta este aplica\u021bia pentru gestionarea clien\u021bilor.</span></p><p><span style=\"background-color:#333;\">Pentru a vizuliza un client da-\u021bi click pe iconi\u021ba cu lup\u0103.</span></p><p><span style=\"background-color:#333;\">Pentru a filtra datele bifa\u021bi, \u00een func\u021bie de preferin\u021b\u0103, c\u0103su\u021bele de sub bara de c\u0103utare.</span></p><p><span style=\"background-color:#333;\">Pentru a genera un pdf voucher selecta\u021bi clientul dorit, da\u021bi click pe butonul "Vizualizeaz\u0103"</span></p><p><span style=\"background-color:#333;\">dup\u0103 care, ap\u0103sa\u021bi "Printare client".</span></p><p><span style=\"background-color:#333;\">Pentru a ad\u0103uga/\u0219terge un client ap\u0103sa\u021bi pe iconi\u021ba cu plus, respectiv "x".</span></p></body></html>", None)) self.recentDateOrderRadioButton.setText( QCoreApplication.translate("Main", u"Dat\u0103 recent\u0103", None)) self.oldDateOrderRadioButton.setText( QCoreApplication.translate("Main", u"Dat\u0103 vehce", None)) self.alphabeticalOrderRadioButton.setText( QCoreApplication.translate("Main", u"Ordonare alfabetic\u0103", None)) self.ViewClientButton.setText( QCoreApplication.translate("Main", u" Vizualizeaz\u0103 ", None)) self.NameLabel.setText( QCoreApplication.translate("Main", u"Nume:", None)) self.CreationDateLabel.setText( QCoreApplication.translate("Main", u"Dat\u0103 creare: ", None)) self.IdLabel.setText(QCoreApplication.translate("Main", u"ID:", None)) self.ExpirationDateLabel.setText( QCoreApplication.translate("Main", u"Dat\u0103 expirare: ", None)) self.Valid_InvalidLabel.setText( QCoreApplication.translate("Main", u"Client valid", None)) self.PrintButton.setText( QCoreApplication.translate("Main", u" Genereaz\u0103 PDF ", None)) self.addTextLabel.setText( QCoreApplication.translate( "Main", u"<html><head/><body><p align=\"center\">Pentru a ad\u0103uga un client nou trebuie </p><p align=\"center\">s\u0103 introduce\u021bi numele:</p></body></html>", None)) self.addNameLabel.setText( QCoreApplication.translate("Main", u"Nume: ", None)) self.addPushBUtton.setText( QCoreApplication.translate("Main", u"Adaug\u0103", None)) self.quitPushButton.setText( QCoreApplication.translate("Main", u"Renun\u021b\u0103", None)) self.removeLabel.setText( QCoreApplication.translate( "Main", u"<html><head/><body><p align=\"center\">Pentru a \u0219terge un client trebuie s\u0103 </p><p align=\"center\">selecta\u021bi r\u00e2ndul corespunz\u0103tor</p></body></html>", None)) self.removePushButton.setText( QCoreApplication.translate("Main", u"\u0218terge", None)) self.quitPushButton_2.setText( QCoreApplication.translate("Main", u"Renun\u021b\u0103", None))
class FE14SupportEditor(QWidget, Ui_support_editor): def __init__(self): super().__init__() self.setupUi(self) self.pushButton_2.setEnabled(False) self.pushButton_3.setEnabled(False) self.comboBox.setEnabled(False) self.setWindowTitle("Support Editor") self.setWindowIcon(QIcon("paragon.ico")) self.error_dialog = None module_service = locator.get_scoped("ModuleService") self.service = None self.current_character = None self.current_supports = None self.current_support = None self.model = module_service.get_module("Characters").entries_model self.proxy_model = QSortFilterProxyModel(self) self.proxy_model.setSourceModel(self.model) self.proxy_model.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive) self.characters_list_view.setModel(self.proxy_model) self.characters_list_view.selectionModel().currentRowChanged.connect(self._update_selection) self.listWidget.selectionModel().currentRowChanged.connect(self._on_target_character_changed) self.listWidget_2.selectionModel().currentRowChanged.connect(self._update_support_selection) self.lineEdit.textChanged.connect(self._update_filter) self.pushButton_2.clicked.connect(self._on_add_support_pressed) self.pushButton_3.clicked.connect(self._on_remove_support_pressed) self.comboBox.currentIndexChanged.connect(self._on_support_type_changed) def show(self): super().show() self.service = locator.get_scoped("SupportsService") self.service.set_in_use() success = True try: self.service.check_support_id_validity() except: logging.exception("Support IDs are invalid.") self.error_dialog = ErrorDialog("Support IDs are invalid. This could mean an ID was out of bounds or not " "unique. See the log for details.") self.error_dialog.show() success = False self.setDisabled(not success) def _update_filter(self): self.proxy_model.setFilterRegExp(self.lineEdit.text()) def _update_selection(self, index: QtCore.QModelIndex): if index.isValid(): character = self.proxy_model.data(index, QtCore.Qt.UserRole) self._refresh_lists(character) self.current_character = character def _refresh_lists(self, character): self._update_supports_list(character) self._update_add_list(character) self.current_support = None self.comboBox.setEnabled(False) self.pushButton_2.setEnabled(False) self.pushButton_3.setEnabled(False) def _update_add_list(self, character): supported_characters = self._create_supported_characters_set(character) module_service = locator.get_scoped("ModuleService") self.listWidget.clear() characters = module_service.get_module("Characters").entries for target_character in characters: if target_character["PID"] not in supported_characters: model_index = self._get_model_index_of_character(target_character) display_name = self.model.data(model_index, QtCore.Qt.DisplayRole) item = QListWidgetItem(display_name) item.setData(QtCore.Qt.UserRole, target_character) self.listWidget.addItem(item) # Dict is not hashable. PIDs should be unique, so we'll use those instead. # Might be able to use IDs instead. def _create_supported_characters_set(self, character): supports = self.service.get_supports_for_character(character) result = set() for support in supports: result.add(support.character["PID"]) return result def _update_supports_list(self, character): supports = self.service.get_supports_for_character(character) self.listWidget_2.clear() for support in supports: model_index = self._get_model_index_of_character(support.character) display_name = self.model.data(model_index, QtCore.Qt.DisplayRole) item = QListWidgetItem(display_name) item.setData(QtCore.Qt.UserRole, support) self.listWidget_2.addItem(item) self.current_supports = supports def _get_model_index_of_character(self, character): module_service = locator.get_scoped("ModuleService") entries = module_service.get_module("Characters").entries for i in range(0, len(entries)): if entries[i] == character: return self.model.index(i) return QModelIndex() def _update_support_selection(self, index): if not index.isValid() or not self.current_supports: return self.current_support = self.current_supports[index.row()] index = SUPPORT_TYPE_TO_INDEX[self.current_support.support_type] self.comboBox.setCurrentIndex(index) self.comboBox.setEnabled(True) self.pushButton_3.setEnabled(True) def _on_support_type_changed(self, index): if not self.current_character or not self.current_support: return support_type = INDEX_TO_SUPPORT_TYPE[index] self.service.set_support_type(self.current_character, self.current_support, support_type) def _on_target_character_changed(self): self.pushButton_2.setEnabled(self.listWidget.currentIndex().isValid()) def _on_add_support_pressed(self): if not self.current_character or not self.listWidget.currentIndex().isValid(): return other_character = self.listWidget.currentItem().data(QtCore.Qt.UserRole) support_type = INDEX_TO_SUPPORT_TYPE[0] # Default to romantic. self.service.add_support_between_characters(self.current_character, other_character, support_type) self._refresh_lists(self.current_character) def _on_remove_support_pressed(self): if not self.current_character or not self.current_support: return self.service.remove_support(self.current_character, self.current_support) self._refresh_lists(self.current_character)
class ObjListWindow(PBDialog): """Create a window managing a list (of bibtexs or of experiments)""" def __init__(self, parent=None, gridLayout=False): """Init using parent class and create common definitions Parameters: parent: the parent object gridLayout (boolean, default False): if True, use a QGridLayout, otherwise a QVBoxLayout """ super(ObjListWindow, self).__init__(parent) self.tableWidth = None self.proxyModel = None self.gridLayout = gridLayout self.filterInput = None self.proxyModel = None self.tableview = None if gridLayout: self.currLayout = QGridLayout() else: self.currLayout = QVBoxLayout() self.setLayout(self.currLayout) def triggeredContextMenuEvent(self, row, col, event): """Not implemented: requires a subclass""" raise NotImplementedError() def handleItemEntered(self, index): """Not implemented: requires a subclass""" raise NotImplementedError() def cellClick(self, index): """Not implemented: requires a subclass""" raise NotImplementedError() def cellDoubleClick(self, index): """Not implemented: requires a subclass""" raise NotImplementedError() def createTable(self, *args, **kwargs): """Not implemented: requires a subclass""" raise NotImplementedError() def changeFilter(self, string): """Change the filter of the current view. Parameter: string: the filter string to be matched """ self.proxyModel.setFilterRegExp(str(string)) def addFilterInput(self, placeholderText, gridPos=(1, 0)): """Add a `QLineEdit` to change the filter of the list. Parameter: placeholderText: the text to be shown when no filter is present gridPos (tuple): if gridLayout is active, the position of the `QLineEdit` in the `QGridLayout` """ self.filterInput = QLineEdit("", self) self.filterInput.setPlaceholderText(placeholderText) self.filterInput.textChanged.connect(self.changeFilter) if self.gridLayout: self.currLayout.addWidget(self.filterInput, *gridPos) else: self.currLayout.addWidget(self.filterInput) self.filterInput.setFocus() def setProxyStuff(self, sortColumn, sortOrder): """Prepare the proxy model to filter and sort the view. Parameter: sortColumn: the index of the column to use for sorting at the beginning sortOrder: the order for sorting (`Qt.AscendingOrder` or `Qt.DescendingOrder`) """ self.proxyModel = QSortFilterProxyModel(self) self.proxyModel.setSourceModel(self.tableModel) self.proxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive) self.proxyModel.setSortCaseSensitivity(Qt.CaseInsensitive) self.proxyModel.setFilterKeyColumn(-1) self.tableview = PBTableView(self) self.tableview.setModel(self.proxyModel) self.tableview.setSortingEnabled(True) self.tableview.setMouseTracking(True) self.tableview.setSelectionBehavior(QAbstractItemView.SelectRows) try: self.tableview.sortByColumn(self.tableModel.header.index("bibkey"), Qt.AscendingOrder) except (IndexError, ValueError): pass self.tableview.sortByColumn(sortColumn, sortOrder) try: self.proxyModel.sort(self.tableModel.header.index("bibkey"), Qt.AscendingOrder) except (IndexError, ValueError): pass self.proxyModel.sort(sortColumn, sortOrder) self.currLayout.addWidget(self.tableview) def finalizeTable(self, gridPos=(1, 0)): """Resize the table to fit the contents, connect functions, add to layout Parameter: gridPos (tuple): if gridLayout is active, the position of the `QLineEdit` in the `QGridLayout` """ self.tableview.resizeColumnsToContents() maxh = QDesktopWidget().availableGeometry().height() maxw = QDesktopWidget().availableGeometry().width() self.setMaximumHeight(maxh) self.setMaximumWidth(maxw) hwidth = self.tableview.horizontalHeader().length() swidth = self.tableview.style().pixelMetric(QStyle.PM_ScrollBarExtent) fwidth = self.tableview.frameWidth() * 2 if self.tableWidth is None: if hwidth > maxw - (swidth + fwidth): self.tableWidth = maxw - (swidth + fwidth) else: self.tableWidth = hwidth + swidth + fwidth self.tableview.setFixedWidth(self.tableWidth) self.setMinimumHeight(600) self.tableview.resizeColumnsToContents() self.tableview.resizeRowsToContents() self.tableview.entered.connect(self.handleItemEntered) self.tableview.clicked.connect(self.cellClick) self.tableview.doubleClicked.connect(self.cellDoubleClick) if self.gridLayout: self.currLayout.addWidget(self.tableview, *gridPos) else: self.currLayout.addWidget(self.tableview) def recreateTable(self): """Delete the previous table widget and other layout items, then create new ones """ self.cleanLayout() self.createTable()
class BaseList(BasePage): """ Generic table viewer widget. Subclasses should set the model_class attribute to a subclass of BaseListModel. If a subclass defines an open_item method that accepts one argument, when an item in the table is clicked on, that method will be called with the ID of the clicked item. Alternatively, if the details_class attribute is set to a tab page widget class, that will be used to open the item. """ def __init__(self, *args, **kwargs): self._model = self.model_class() self.proxy_model = QSortFilterProxyModel() self.proxy_model.setSourceModel(self._model) layout = QVBoxLayout() self.table_view = QTableView() self.table_view.setModel(self.proxy_model) self.table_view.setSortingEnabled(True) self.table_view.setSelectionBehavior(QAbstractItemView.SelectRows) self.table_view.doubleClicked.connect(self.table_double_clicked) layout.addWidget(self.table_view) self.extra_data = dict() super().__init__(*args, **kwargs) self.setLayout(layout) def table_double_clicked(self, index): """ Called when the QTableView is double clicked. If the open_item() method is defined, call it and pass the ID of the item that was clicked on. Args: The QModelIndex passed by the table_view.doubleClicked signal. """ if hasattr(self, "open_item"): # TODO: Figure out a better way to get the ID besides assuming that # it's in the first (or any) column id_index = index.siblingAtColumn(0) try: data_id = int(index.model().itemData(id_index)[0]) self.open_item(data_id) except ValueError: pass def open_item(self, data_id): """ If the details_class attribute is defined, use it to open a Details tab for the specified item. """ if hasattr(self, "details_class"): self.details_class.create_or_focus(self.gui, data_id) @property def data(self): """The page's current data set (a 2-dimensional sequence).""" return self._model.dataset @data.setter def data(self, data): self._model.populate(data) self.proxy_model.invalidate() @property def tab_name(self): """ The name of the tab page. Determined by the tab_name_fmt attribute and the widget's current supplemental data set. """ return self.tab_name_fmt.format(**self.extra_data)