Refactor GUI to use Multi Document Interface

This commit is contained in:
Thomas Peetz
2025-01-21 20:12:50 +01:00
parent 4e884fdbe5
commit e8660faa06
5 changed files with 122 additions and 68 deletions
+20 -13
View File
@@ -1,42 +1,49 @@
from PySide6.QtWidgets import QMainWindow, QWidget, QVBoxLayout, QTabWidget, QMenu, QTableView
from PySide6.QtCore import Signal
from PySide6.QtWidgets import QMainWindow, QWidget, QVBoxLayout, QTabWidget, QMenu, QTableView, QMdiSubWindow
from gui.model_config import KontorModelConfig
from gui.table_model import KontorTableModel
class ComicWindow(QWidget):
class ComicWindow(QMdiSubWindow):
closed = Signal()
def __init__(self, main_window):
super().__init__()
self.statusBar = main_window.statusBar
self._main_window = main_window
self.data_views = list()
# self._create_menubar()
self._main_window = main_window
self.log = main_window.log
self._init_gui()
self.tick = main_window.tick
self.cross = main_window.cross
def _init_gui(self):
self.central_widget = QWidget()
self.setWindowTitle("Comics")
self.setWidget(QWidget())
layout = QVBoxLayout()
#self.central_widget.setLayout(parent_layout)
self.tabs = QTabWidget()
self.tabs.addTab(self.generate_data_tab("comic"), "Comics")
self.tabs.addTab(self.generate_data_tab("publisher"), "Publisher")
self.tabs.currentChanged.connect(self._tab_changed)
# label.setAlignment(Qt.AlignmentFlag.AlignCenter)
layout.addWidget(self.tabs)
self.setLayout(layout)
# self.setCentralWidget(self.central_widget)
self.setWidget(self.tabs)
# def _create_menubar(self):
# menu_bar = self.menuBar()
# comic_menu = QMenu("Comic")
# menu_bar.addMenu(comic_menu)
def closeEvent(self, event):
self.closed.emit()
super().closeEvent(event)
self._main_window.remove_sub_window('comic')
def refresh(self):
# self.log.info("refresh")
self.data_views[self.tabs.currentIndex()].refresh()
def _tab_changed(self, tab_index):
self.data_views[tab_index].refresh()
def update_status(self, message):
self._main_window.update_status(message)
def generate_data_tab(self, table_name):
data_tab = QWidget()
+57 -26
View File
@@ -1,5 +1,5 @@
from PySide6.QtGui import QAction, QIcon, QGuiApplication
from PySide6.QtWidgets import QWidget, QVBoxLayout, QMenu, QMessageBox, QTabWidget, QTableView, QProgressBar
from PySide6.QtWidgets import QWidget, QVBoxLayout, QMenu, QMessageBox, QTabWidget, QTableView, QProgressBar, QMdiArea
from PySide6.QtWidgets import QLabel, QMainWindow
from sqlalchemy import Engine
from kontor_schema import KontorDB
@@ -22,32 +22,39 @@ class MainWindow(QMainWindow):
self.export_icon = QIcon("res/application-export.png")
self.circle_icon = QIcon("res/arrow-circle-double.png")
self.data = []
self.filter = {}
self.kontor_db = KontorDB(engine, log)
self.log = log
self._subwindows = {}
self._setup_ui()
#self.tabs = QTabWidget()
#self.tabs.addTab(self.generate_data_tab("comic"), "Comics")
#self.tabs.addTab(self.generate_data_tab("media_file"), "MediaFile")
#self.tabs.currentChanged.connect(self._tab_changed)
#label.setAlignment(Qt.AlignmentFlag.AlignCenter)
#parent_layout.addWidget(self.tabs)
self.setCentralWidget(self.central_widget)
def _setup_ui(self):
self.setWindowTitle("Kontor")
self.setMinimumSize(800, 500)
self.setMinimumSize(1200, 800)
self._create_actions()
self.central_widget = QWidget()
# parent_layout = QVBoxLayout()
# self.central_widget.setLayout(parent_layout)
self.mdi_area = QMdiArea(self.central_widget)
self.mdi_area.setObjectName('mdi_area')
self.setCentralWidget(self.central_widget)
self._create_menubar()
self._create_toolbars()
self.status_progress = QProgressBar()
self.progress_update = ProgressUpdate(self.status_progress)
self._create_statusbar()
self.data = []
self.filter = {}
self.kontor_db = KontorDB(engine, log)
self.log = log
self.comic_window = ComicWindow(self)
self.central_widget = QWidget()
parent_layout = QVBoxLayout()
self.central_widget.setLayout(parent_layout)
self.tabs = QTabWidget()
self.tabs.addTab(self.generate_data_tab("comic"), "Comics")
self.tabs.addTab(self.generate_data_tab("media_file"), "MediaFile")
self.tabs.currentChanged.connect(self._tab_changed)
#label.setAlignment(Qt.AlignmentFlag.AlignCenter)
parent_layout.addWidget(self.tabs)
self.setCentralWidget(self.central_widget)
centerPoint = QGuiApplication.screens()[0].geometry().center()
self.move(centerPoint - self.frameGeometry().center())
@@ -117,10 +124,26 @@ class MainWindow(QMainWindow):
QMessageBox.about(self.central_widget, "Über Kontor", f"Python: 3.11\nKontor: 0.1.0")
def show_comic_window(self):
if self.comic_window.isHidden():
self.comic_window.show()
if 'comic' not in self._subwindows:
comic = ComicWindow(self)
comic.closed.connect(self.sub_window_closed)
self._subwindows['comic'] = comic
self.mdi_area.addSubWindow(comic)
comic.show()
else:
self.comic_window.hide()
comic = self._subwindows.pop('comic')
comic.close()
self.mdi_area.removeSubWindow(comic)
def remove_sub_window(self, name: str):
# self.log.info("remove subwindow %s", name)
if name in self._subwindows:
window = self._subwindows.pop(name)
window.close()
self.mdi_area.removeSubWindow(window)
def sub_window_closed(self):
self.log.info("close subwindow")
def import_from_file(self):
import_dlg = ImportKontorDialog(self)
@@ -162,10 +185,17 @@ class MainWindow(QMainWindow):
self.kontor_db.check_files()
def refresh(self):
self.data[self.tabs.currentIndex()].refresh()
self.log.info("refresh")
for (_, window) in self._subwindows.items():
window.refresh()
# def refresh(self):
# self.data[self.tabs.currentIndex()].refresh()
def _tab_changed(self, tab_index):
self.data[tab_index].refresh()
# def _tab_changed(self, tab_index):
# self.data[tab_index].refresh()
def update_status(self, message, timeout=3000):
self.statusBar.showMessage(message, timeout=timeout)
def generate_data_tab(self, table_name):
data_tab = QWidget()
@@ -181,3 +211,4 @@ class MainWindow(QMainWindow):
layout.addWidget(table_view)
model.refresh()
return data_tab
+14 -6
View File
@@ -1,4 +1,4 @@
from PySide6.QtWidgets import QHBoxLayout, QCheckBox
from PySide6.QtWidgets import QHBoxLayout, QCheckBox, QMdiSubWindow
from kontor_schema import KontorDB
@@ -8,15 +8,23 @@ class KontorModelConfig:
self.header = {}
self.filter = {}
self.main_window = main_window
self.log = main_window.log
self._table_name = table_name
self.kontor_db = kontor_db
self.get_table_config()
def __str__(self):
return f"KontorModelConfig({self._table_name})"
def get_table_config(self):
# self.log.info("get_table_config %s", self)
self.header = self.kontor_db.get_column_meta_data(self._table_name)
self.filter = self.kontor_db.get_filters(self._table_name)
# self.log.info("headers: %s", self.header)
# self.log.info("%s filters: %s", self, self.filter)
def filters(self) -> dict:
# self.log.info("%s filters: %s", self, self.filter)
_filters = {}
# print(self.filter["download"].isChecked())
for column, filter_info in self.filter.items():
@@ -24,18 +32,17 @@ class KontorModelConfig:
if filter_info['widget'].isChecked():
_filters[column] = True
# print(f"{filter_rule=}")
# self.log.info("filters -> %s", _filters)
return _filters
def get_data(self) -> list:
# data = self.kontor_db.get_data(self._table_name, self.header, self.get_filter())
# data.clear()
# self.log.info("get_data")
data = self.kontor_db.data(self._table_name, self.header, self.filters())
# print(f"KontorModelConfig.get_data: {len(data)}")
# comics = self.kontor_db.session.query(Comic).all()
# print(f'{len(comics)} Comics loaded')
# self.log.info("get_data: %d %s", len(data), data)
return data
def get_filter_layout(self) -> QHBoxLayout:
# self.log.info("get_filter_layout: %s", self.filter)
filter_layout = QHBoxLayout()
for column, filter_info in self.filter.items():
filter_checkbox = QCheckBox()
@@ -44,4 +51,5 @@ class KontorModelConfig:
self.filter[column]['widget'] = filter_checkbox
filter_layout.addWidget(filter_checkbox)
filter_layout.addStretch()
# self.log.info("get_filter_layout: %s", self.filter)
return filter_layout
+23 -19
View File
@@ -13,8 +13,13 @@ class KontorTableModel(QAbstractTableModel):
self._main_window = model_config.main_window
self._config = model_config
self._data = []
self.log = model_config.log
def __str__(self):
return f"KontorTableModel({self._config})"
def refresh(self):
# self.log.info("refresh")
data = self._config.get_data()
count = 0
# print(data)
@@ -27,9 +32,10 @@ class KontorTableModel(QAbstractTableModel):
# print(data)
# print(self._data)
self.layoutChanged.emit()
self._main_window.statusBar.showMessage(f"{count} Einträge geladen", 3000)
self._main_window.update_status(f"{count} Einträge geladen")
def rowCount(self, parent=QModelIndex()):
# self.log.info("rowCount %s: %d", self, len(self._data))
# The length of the outer list.
if self._data is None:
return 0
@@ -53,53 +59,51 @@ class KontorTableModel(QAbstractTableModel):
return value
if isinstance(value, bytes):
if value == b'\x01':
return self._main_window.tick
return self._config.main_window.tick
else:
return self._main_window.cross
return self._config.main_window.cross
if isinstance(value, int):
# print('{}:: {}: {}'.format(index, value, type(value)))
if value == 1:
return self._main_window.tick
return self._config.main_window.tick
else:
return self._main_window.cross
return self._config.main_window.cross
if isinstance(value, bool):
if value:
return self._main_window.tick
return self._config.main_window.tick
else:
return self._main_window.cross
return self._config.main_window.cross
return str(value)
if role == Qt.ItemDataRole.DecorationRole:
if isinstance(value, bytes):
if value == b'\x01':
return self._main_window.tick
return self._config.main_window.tick
else:
return self._main_window.cross
return self._config.main_window.cross
if isinstance(value, int):
if value == 1:
return self._main_window.tick
return self._config.main_window.tick
else:
return self._main_window.cross
return self._config.main_window.cross
if isinstance(value, bool):
if value:
return self._main_window.tick
return self._config.main_window.tick
else:
return self._main_window.cross
return self._config.main_window.cross
def columnCount(self, index=QModelIndex()):
# The following takes the first sub-list, and returns
# the length (only works if all rows are an equal length)
# print(f"Header count: {len(self._config.get_header())}")
# self.log.info("rowCount %s: %d", self, len(self._config.header))
return len(self._config.header)
def setData(self, index, value, role: int) -> bool:
print(index, role)
# print(index, role)
if role == Qt.ItemDataRole.EditRole:
self._data[index.row()][index.column()] = value
print(self._data[index.row()][index.column()])
# print(self._data[index.row()][index.column()])
self.dataChanged.emit(index, index)
return True
if role == Qt.ItemDataRole.CheckStateRole:
print("role == Qt.ItemDataRole.CheckStateRole")
# print("role == Qt.ItemDataRole.CheckStateRole")
checked = value == Qt.CheckState.Checked
self._data[index.row()][index.column()] = checked
return False
@@ -83,6 +83,7 @@ class KontorDB:
filter(MetaDataTable.id == MetaDataColumn.table_id).
filter(MetaDataTable.table_name == table_name).
filter(MetaDataColumn.is_shown == 1).all()):
# self.log.info("get_column_meta_data: %s %s %d", column.column_name, column.column_label, column.column_order)
meta_data[order] = {'column': column.column_name, 'label': column.column_label,
'order': column.column_order, 'ref_column': column.ref_column}
order += 1
@@ -96,7 +97,8 @@ class KontorDB:
'ref_column': column.ref_column
}
order += 1
return meta_data
# self.log.info("get_column_meta_data: %s", meta_data)
return meta_data
def get_columns(self, table_name: str) -> dict:
columns = {}
@@ -131,6 +133,7 @@ class KontorDB:
else:
entries = session.scalars(select(table).filter_by(**filters)).all()
for entry in entries:
# self.log.info("data: %s", entry)
row = []
for order in columns.keys():
column_name = columns[order]['column']
@@ -142,6 +145,7 @@ class KontorDB:
else:
row.append(getattr(entry, column_name))
data.append(row)
# self.log.info("data: %s", data)
return data
def export_db(self, export_type: str, export_file_name: str) -> dict:
@@ -259,7 +263,7 @@ class KontorDB:
return existing_ids
def add_entry(self, table_name: str, update_item: dict):
self.log.info("add entry to table %s with %s", table_name, update_item)
# self.log.info("add entry to table %s with %s", table_name, update_item)
__session__ = sessionmaker(self.engine)
with __session__() as session:
add_item = self.registry[table_name]()
@@ -270,7 +274,7 @@ class KontorDB:
session.commit()
def update_entry(self, table_name, current_id, update_item: dict) -> bool:
self.log.info("update entry to table %s", table_name)
# self.log.info("update entry to table %s", table_name)
__session__ = sessionmaker(self.engine)
with __session__() as session:
existing_item = session.query(self.registry[table_name]).get(current_id)
@@ -335,7 +339,7 @@ class KontorDB:
def delete_entries(self):
for (table_name, table) in self.registry.items():
self.log.info("delete entries from table %s", table_name)
# self.log.info("delete entries from table %s", table_name)
__session__ = sessionmaker(self.engine)
with __session__() as session:
items = session.query(table).all()