diff options
Diffstat (limited to 'src/gui/tags/panel/table')
-rw-r--r-- | src/gui/tags/panel/table/menu.py | 25 | ||||
-rw-r--r-- | src/gui/tags/panel/table/model.py | 103 | ||||
-rw-r--r-- | src/gui/tags/panel/table/widget.py | 70 |
3 files changed, 198 insertions, 0 deletions
diff --git a/src/gui/tags/panel/table/menu.py b/src/gui/tags/panel/table/menu.py new file mode 100644 index 0000000..f95c097 --- /dev/null +++ b/src/gui/tags/panel/table/menu.py @@ -0,0 +1,25 @@ +from PyQt5 import QtWidgets + +import db.tags +import gui.tags.panel.dialog +from model.tag import Tag, ValidTagForm + +def open(table, update_tag_signal, position): + rows = set([index.row() for index in table.selectedIndexes()]) + + menu = QtWidgets.QMenu(table) + + if len(rows) == 1: + modify_action = menu.addAction(gui.icon.dialog_open(menu.style()), 'modify') + else: + modify_action = QtWidgets.QAction(menu) + + delete_action = menu.addAction(gui.icon.trash(menu.style()), 'delete') + + action = menu.exec_(table.mapToGlobal(position)) + if action == modify_action and len(rows) == 1: + row = list(rows)[0] + tag = table.model().get_at(row) + gui.tags.panel.dialog.update(table, update_tag_signal, row, tag).exec_() + elif action == delete_action: + gui.tags.panel.dialog.show_delete(table, rows) diff --git a/src/gui/tags/panel/table/model.py b/src/gui/tags/panel/table/model.py new file mode 100644 index 0000000..7c66b5d --- /dev/null +++ b/src/gui/tags/panel/table/model.py @@ -0,0 +1,103 @@ +from PyQt5 import QtCore, QtWidgets, QtGui +from PyQt5.QtCore import Qt + +from model.tag import Tag +import time +import math +import util.array +import util.range +import gui.color + +columns = 1 + +headers = ['Name', 'Color'] + +default_sort = (0, Qt.AscendingOrder) + +class TableModel(QtCore.QAbstractTableModel): + def __init__(self, tags): + super(TableModel, self).__init__() + self._tags = tags + + def headerData(self, section, orientation, role): + if role == Qt.DisplayRole and orientation == Qt.Horizontal: + return headers[section] + elif role == Qt.DisplayRole and orientation == Qt.Vertical: + return section + 1 + else: + return QtCore.QVariant() + + def data(self, index, role): + tag = self._tags[index.row()] + + if role == Qt.DisplayRole: + if index.column() == 0: + return tag.name + elif index.column() == 1: + return tag.color + elif role == Qt.BackgroundRole: + return QtGui.QBrush(QtGui.QColor(tag.color)) + else: + return QtCore.QVariant() + + def rowCount(self, index): + return len(self._tags) + + def columnCount(self, index): + return columns + + def get_at(self, row): + if row >= 0 and row < len(self._tags): + return self._tags[row] + + def insert_tag(self, header: QtWidgets.QHeaderView, tag: Tag) -> int: + at = self.insert_position(header, tag) + self.beginInsertRows(QtCore.QModelIndex(), at, at) + self._tags.insert(at, tag) + self.endInsertRows() + return at + + def insert_position(self, header: QtWidgets.QHeaderView, tag: Tag) -> int: + row = header.sortIndicatorSection() + order = header.sortIndicatorOrder() + is_rev = is_reversed(row, order) + return util.array.insert_position( + sort_key(tag, row, is_rev), + [sort_key(t, row, is_rev) for t in self._tags], + is_rev) + + def update_tag(self, header: QtWidgets.QHeaderView, row, tag: Tag) -> int: + self.delete_tag_range(row, 1) + return self.insert_tag(header, tag) + + def delete_tags(self, indexes): + for range in reversed(util.range.from_indexes(indexes)): + self.delete_tag_range(range.start, range.length) + return True + + def delete_tag_range(self, row, rows): + self.beginRemoveRows(QtCore.QModelIndex(), row, row + rows - 1) + self._tags = self._tags[:row] + self._tags[row + rows:] + self.endRemoveRows() + return True + + def row_ids(self, rows): + return [tag.id for i, tag in enumerate(self._tags) if i in rows] + + def sort(self, row: int, order: Qt.SortOrder): + self.layoutAboutToBeChanged.emit() + is_rev = is_reversed(row, order) + self._tags = sorted( + self._tags, + key = lambda tag: sort_key(tag, row, is_rev), + reverse = is_rev) + self.layoutChanged.emit() + +def sort_key(tag: Tag, row: int, is_reversed: bool): + if row == 0: + return tag.name.lower() + elif row == 1: + return tag.color + +def is_reversed(row: int, order: Qt.SortOrder) -> bool: + return order == Qt.DescendingOrder diff --git a/src/gui/tags/panel/table/widget.py b/src/gui/tags/panel/table/widget.py new file mode 100644 index 0000000..f0bf82c --- /dev/null +++ b/src/gui/tags/panel/table/widget.py @@ -0,0 +1,70 @@ +from PyQt5 import QtWidgets +from PyQt5.QtCore import Qt + +import db.tags +import gui.tags.panel.signal +import gui.tags.panel.table.menu +import gui.tags.panel.table.model +import gui.tags.panel.dialog +from model.tag import Tag, ValidTagForm +import database + +class Widget(QtWidgets.QTableView): + + def __init__(self, parent, add_tag_signal): + super().__init__(parent) + + self._update_tag_signal = gui.tags.panel.signal.UpdateTag() + + tags = db.tags.get(database.cursor()) + table_model = gui.tags.panel.table.model.TableModel(tags) + + self.setModel(table_model) + self.sortByColumn( + gui.tags.panel.table.model.default_sort[0], + gui.tags.panel.table.model.default_sort[1]) + self.setSortingEnabled(True) + self.setSelectionBehavior(QtWidgets.QTableView.SelectRows) + self.horizontalHeader().setStretchLastSection(True) + self.resizeColumns() + + self.doubleClicked.connect(lambda index: self.on_double_click(index.row())) + + # # Menu + self.setContextMenuPolicy(Qt.CustomContextMenu) + self.customContextMenuRequested.connect(lambda position: gui.tags.panel.table.menu.open(self, self._update_tag_signal, position)) + + add_tag_signal.connect(lambda tag: self.insert(tag)) + self._update_tag_signal.connect(lambda row, tag: self.update(row, tag)) + + def insert(self, tag): + self.model().insert_tag(self.horizontalHeader(), tag) + self.resizeColumns() + + def update(self, row, tag): + row = self.model().update_tag(self.horizontalHeader(), row, tag) + self.selectRow(row) + self.resizeColumns() + + def resizeColumns(self): + for column in range(gui.tags.panel.table.model.columns): + self.resizeColumnToContents(column) + + def keyPressEvent(self, event): + super().keyPressEvent(event) + if event.key() in (Qt.Key_Return, Qt.Key_Enter): + rows = self.get_selected_rows() + if len(rows) == 1: + row = rows[0] + tag = self.model().get_at(row) + gui.tags.panel.dialog.update(self, self._update_tag_signal, row, tag).exec_() + elif event.key() == Qt.Key_Delete: + rows = self.get_selected_rows() + gui.tags.panel.dialog.show_delete(self, rows) + + def get_selected_rows(self): + return list(set([index.row() for index in self.selectedIndexes()])) + + def on_double_click(self, row: int): + tag = self.model().get_at(row) + gui.tags.panel.dialog.update(self, self._update_tag_signal, row, tag).exec_() |