diff --git a/kontor-gui/.gitignore b/kontor-gui/.gitignore deleted file mode 100644 index e877d19..0000000 --- a/kontor-gui/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -deployment/ -venv/ -kontor.bin -bin/ -include/ -lib/ -lib64/ -lib64 -env/ diff --git a/kontor-gui/Makefile b/kontor-gui/Makefile deleted file mode 100644 index 5bb3fcd..0000000 --- a/kontor-gui/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -.PHONY: clean virtualenv test docker dist dist-upload - -clean: - find . -name '*.py[co]' -delete - -virtualenv: - virtualenv --prompt '|> kontor <| ' env - env/bin/pip install -r requirements.txt - env/bin/python setup.py develop - @echo - @echo "VirtualENV Setup Complete. Now run: source env/bin/activate" - @echo - -test: - python -m pytest \ - -v \ - --cov=kontor \ - --cov-report=term \ - --cov-report=html:coverage-report \ - tests/ - -docker: clean - docker build -t kontor-api:latest . - -dist: clean - rm -rf dist/* - python setup.py sdist - python setup.py bdist_wheel - -dist-upload: - twine upload dist/* diff --git a/kontor-gui/README.md b/kontor-gui/README.md deleted file mode 100644 index c2c7bec..0000000 --- a/kontor-gui/README.md +++ /dev/null @@ -1 +0,0 @@ -# kontor-gui diff --git a/kontor-gui/gui/__init__.py b/kontor-gui/gui/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/kontor-gui/gui/comic_window.py b/kontor-gui/gui/comic_window.py deleted file mode 100644 index d032998..0000000 --- a/kontor-gui/gui/comic_window.py +++ /dev/null @@ -1,66 +0,0 @@ -from PySide6.QtCore import Signal, QSortFilterProxyModel -from PySide6.QtWidgets import QWidget, QVBoxLayout, QTabWidget, QTableView, QMdiSubWindow, \ - QHeaderView - -from gui.model_config import KontorModelConfig -from gui.table_model import KontorTableModel - - -class ComicWindow(QMdiSubWindow): - closed = Signal() - - def __init__(self, main_window): - super().__init__() - self.data_views = list() - 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.setWindowTitle("Comics") - self.setWidget(QWidget()) - layout = QVBoxLayout() - 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) - layout.addWidget(self.tabs) - self.setLayout(layout) - self.setWidget(self.tabs) - - 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() - - table_config = KontorModelConfig(self._main_window.kontor_db, self, table_name) - model = KontorTableModel(table_config) - layout = QVBoxLayout() - self.data_views.append(model) - data_tab.setLayout(layout) - table_view = QTableView() - header = table_view.horizontalHeader() - header.setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents) - proxy_model = QSortFilterProxyModel() - proxy_model.setSourceModel(model) - table_view.setSortingEnabled(True) - table_view.setModel(proxy_model) - layout.addLayout(table_config.get_filter_layout()) - layout.addWidget(table_view) - model.refresh() - return data_tab diff --git a/kontor-gui/gui/data_view.py b/kontor-gui/gui/data_view.py deleted file mode 100644 index 91c66d2..0000000 --- a/kontor-gui/gui/data_view.py +++ /dev/null @@ -1,12 +0,0 @@ -from abc import ABC, abstractmethod - - -class DataViewMeta(ABC): - @abstractmethod - def get_header(self): - pass - - -class ComicView(DataViewMeta): - def get_header(self): - pass diff --git a/kontor-gui/gui/data_view_model.py b/kontor-gui/gui/data_view_model.py deleted file mode 100644 index 4ffdc8c..0000000 --- a/kontor-gui/gui/data_view_model.py +++ /dev/null @@ -1,32 +0,0 @@ -from typing import List - -from PySide6.QtCore import QModelIndex, QAbstractTableModel -from PySide6.QtGui import Qt - -from gui.data_view import DataViewMeta - - -class DataViewModel(QAbstractTableModel): - def __init__(self): - super().__init__() - self.main_window = None - self._config = None - self._data = List[DataViewMeta] - - def rowCount(self, parent=QModelIndex()): - return len(self._data) - - def columnCount(self, parent=QModelIndex()): - return 0 - - def headerData(self, section, orientation, role=Qt.ItemDataRole.DisplayRole): - return None - - def data(self, index, role=Qt.ItemDataRole.DisplayRole): - return None - - def setData(self, index, value, role=Qt.ItemDataRole.EditRole): - return False - - def flags(self, index): - return None diff --git a/kontor-gui/gui/dialogs.py b/kontor-gui/gui/dialogs.py deleted file mode 100644 index 21dbe92..0000000 --- a/kontor-gui/gui/dialogs.py +++ /dev/null @@ -1,106 +0,0 @@ -from pathlib import Path - -from PySide6.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout, QLabel, QHBoxLayout, QPushButton, QFileDialog, \ - QCheckBox, QComboBox - - -class ExportKontorDialog(QDialog): - def __init__(self, parent=None, kontor_db=None): - super().__init__(parent) - - self.parent = parent - self.kontor_db = kontor_db - self.file_name = "data.json" - self.tables = [] - self._table_options = {} - - self.export_options = {"JSON": {"ext": ".json"}, "YAML": {"ext": ".yaml"}, "SQLite": {"ext": ".db"}} - self.current_export_type = "JSON" - - buttons = (QDialogButtonBox.Ok | QDialogButtonBox.Cancel) - - self.buttonBox = QDialogButtonBox(buttons) - self.buttonBox.accepted.connect(self.accept) - self.buttonBox.rejected.connect(self.reject) - - layout = QVBoxLayout() - - self.label = QLabel() - self.label.setText("Export DB to data.json") - - self.combo_box = QComboBox() - self.combo_box.addItems(["JSON", "YAML", "SQLite"]) - self.combo_box.currentTextChanged.connect(self.change_export_type) - file_layout = QHBoxLayout() - file_layout.addWidget(self.label) - file_layout.addWidget(self.combo_box) - file_button = QPushButton("Select file") - file_button.clicked.connect(self.select_file) - file_layout.addWidget(file_button) - layout.addLayout(file_layout) - - for table_name in self.kontor_db.get_table_names(): - check_box = QCheckBox(table_name) - check_box.setChecked(True) - self.tables.append(table_name) - self._table_options[table_name] = check_box - check_box.stateChanged.connect(self.change_selection) - layout.addWidget(check_box) - layout.addWidget(self.buttonBox) - self.setLayout(layout) - - def change_selection(self): - self.tables.clear() - for (name, box) in self._table_options.items(): - if box.isChecked(): - self.tables.append(name) - - def change_export_type(self, text): - self.current_export_type = text - self.label.setText(f'Export DB to data.{self.export_options[text]["ext"]}') - - def select_file(self): - file_dialog = QFileDialog() - file_dialog.setFileMode(QFileDialog.FileMode.AnyFile) - file_dialog.setDefaultSuffix(self.export_options[self.current_export_type]["ext"]) - file_dialog.setNameFilter(f'*{self.export_options[self.current_export_type]["ext"]}') - if file_dialog.exec(): - self.file_name = file_dialog.selectedFiles()[0] - export_file = Path(self.file_name) - self.file_name = export_file.with_suffix(self.export_options[self.current_export_type]["ext"]) - self.label.setText(f"Export DB to {self.file_name}") - - def get_tables_to_export(self) -> list: - return self.tables - - -class ImportKontorDialog(QDialog): - def __init__(self, parent=None): - super().__init__(parent) - - self.file_name = None - - QBtn = (QDialogButtonBox.Ok | QDialogButtonBox.Cancel) - - self.buttonBox = QDialogButtonBox(QBtn) - self.buttonBox.accepted.connect(self.accept) - self.buttonBox.rejected.connect(self.reject) - - self.label = QLabel() - self.label.setText("Import DB from data.json") - layout = QVBoxLayout() - file_layout = QHBoxLayout() - file_layout.addWidget(self.label) - file_button = QPushButton("Select file") - file_button.clicked.connect(self.select_file) - file_layout.addWidget(file_button) - layout.addLayout(file_layout) - layout.addWidget(self.buttonBox) - self.setLayout(layout) - - def select_file(self): - file_dialog = QFileDialog() - file_dialog.setFileMode(QFileDialog.FileMode.ExistingFile) - if file_dialog.exec(): - self.file_name = file_dialog.selectedFiles()[0] - self.label.setText(f"Import DB from {self.file_name}") diff --git a/kontor-gui/gui/main_window.py b/kontor-gui/gui/main_window.py deleted file mode 100644 index 336e2be..0000000 --- a/kontor-gui/gui/main_window.py +++ /dev/null @@ -1,237 +0,0 @@ -from PySide6.QtCore import Qt -from PySide6.QtGui import QAction, QIcon, QGuiApplication -from PySide6.QtWidgets import QMenu, QMessageBox, QProgressBar, QMdiArea -from PySide6.QtWidgets import QLabel, QMainWindow -from sqlalchemy import Engine -from kontor_schema import KontorDB - -from .comic_window import ComicWindow -from .media_window import MediaWindow -from .meta_data_window import MetaDataWindow -from .progress import ProgressUpdate -from .dialogs import ExportKontorDialog, ImportKontorDialog -from .worker import VideoDownloader - - -class MainWindow(QMainWindow): - - def __init__(self, engine: Engine, log): - super().__init__() - - self.downloader = None - self.tick = QIcon('res/tick.png') - self.cross = QIcon('res/cross.png') - self.import_icon = QIcon("res/application-import.png") - 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.media_dir = "/data/media" - self.dl_tool = "yt-dlp" - - self._setup_ui() - - def _setup_ui(self): - self.setWindowTitle("Kontor") - self.setMinimumSize(1200, 800) - self._create_actions() - self.mdi_area = QMdiArea() - self.setCentralWidget(self.mdi_area) - self.mdi_area.setObjectName('mdi_area') - self.mdi_area.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded) - self.mdi_area.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded) - self._create_menubar() - self._create_toolbars() - self.status_progress = QProgressBar() - self.progress_update = ProgressUpdate(self.status_progress) - self._create_statusbar() - center_point = QGuiApplication.screens()[0].geometry().center() - self.move(center_point - self.frameGeometry().center()) - - def _create_actions(self): - self.newAction = QAction("&New", self) - self.aboutAction = QAction("&Über...", self) - self.aboutAction.triggered.connect(self.about) - self.showComicWindow = QAction("&Comic Window", self) - self.showComicWindow.triggered.connect(self.show_comic_window) - self.showTyscWindow = QAction("TYSC Window", self) - self.showMediaWindow = QAction("&Media Window", self) - self.showMediaWindow.triggered.connect(self.show_media_window) - self.showMetaDataWindow = QAction("Meta Data Window", self) - self.showMetaDataWindow.triggered.connect(self.show_meta_data_window) - self.importAction = QAction(self.import_icon, "&Import", self) - self.importAction.triggered.connect(self.import_from_file) - self.exportAction = QAction(self.export_icon, "&Export", self) - self.exportAction.triggered.connect(self.export_to_file) - self.refreshAction = QAction(self.circle_icon, "&Refresh", self) - self.refreshAction.triggered.connect(self.refresh) - self.updateTitleAction = QAction("&Update Titles", self) - self.updateTitleAction.triggered.connect(self.update_title) - self.downloadAction = QAction("&Download Videos", self) - self.downloadAction.triggered.connect(self.start_download) - self.checkFileAction = QAction("&Check files", self) - self.checkFileAction.triggered.connect(self.check_files) - self.exitAction = QAction("&Beenden", self) - self.exitAction.setShortcut("Alt+F4") - self.exitAction.triggered.connect(self.close) - - def _create_menubar(self): - menu_bar = self.menuBar() - # File menu - file_menu = QMenu("&Datei") - menu_bar.addMenu(file_menu) - file_menu.addAction(self.exitAction) - # Kontor menu - kontor_menu = QMenu("&Kontor") - menu_bar.addMenu(kontor_menu) - kontor_menu.addAction(self.importAction) - kontor_menu.addAction(self.exportAction) - comic_menu = QMenu("&Comic") - comic_menu.addAction(self.showComicWindow) - tysc_menu = QMenu("&TradeYourSportCards") - media_file_menu = QMenu("&MediaFile") - media_file_menu.addAction(self.updateTitleAction) - media_file_menu.addAction(self.downloadAction) - media_file_menu.addAction(self.checkFileAction) - kontor_menu.addMenu(comic_menu) - kontor_menu.addMenu(tysc_menu) - kontor_menu.addMenu(media_file_menu) - window_menu = QMenu("&Window") - layouts_menu = QMenu("&Layouts") - window_menu.addMenu(layouts_menu) - window_menu.addAction(self.showComicWindow) - window_menu.addAction(self.showMediaWindow) - window_menu.addAction(self.showMetaDataWindow) - menu_bar.addMenu(window_menu) - # Help menu - help_menu = QMenu("&Hilfe") - menu_bar.addMenu(help_menu) - help_menu.addAction(self.aboutAction) - - def _create_toolbars(self): - # Kontor toolbar - kontor_tool_bar = self.addToolBar("Kontor") - kontor_tool_bar.addAction(self.importAction) - kontor_tool_bar.addAction(self.exportAction) - kontor_tool_bar.addAction(self.refreshAction) - - def _create_statusbar(self): - self.statusBar = self.statusBar() - self.statusBar.showMessage("Kontor ready", 6000) - self.status_label = QLabel("") - self.status_progress.setEnabled(False) - self.statusBar.addPermanentWidget(self.status_progress) - - def about(self): - QMessageBox.about(self, "Über Kontor", "Python: 3.11\nKontor: 0.1.0") - - def show_comic_window(self): - 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: - comic = self._subwindows.pop('comic') - comic.close() - self.mdi_area.removeSubWindow(comic) - - def show_media_window(self): - if 'media' not in self._subwindows: - media = MediaWindow(self) - media.closed.connect(self.sub_window_closed) - self._subwindows['media'] = media - self.mdi_area.addSubWindow(media) - media.show() - else: - media = self._subwindows.pop('media') - media.close() - self.mdi_area.removeSubWindow(media) - - def show_meta_data_window(self): - if 'meta_data' not in self._subwindows: - meta_data = MetaDataWindow(self) - meta_data.closed.connect(self.sub_window_closed) - self._subwindows['meta_data'] = meta_data - self.mdi_area.addSubWindow(meta_data) - meta_data.show() - else: - meta_data = self._subwindows.pop('meta_data') - meta_data.close() - self.mdi_area.removeSubWindow(meta_data) - - 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) - if import_dlg.exec(): - print(f"import DB from file {import_dlg.file_name}") - self.kontor_db.import_db(import_dlg.file_name) - else: - print("do nothing for import") - - def export_to_file(self): - export_dlg = ExportKontorDialog(self, self.kontor_db) - if export_dlg.exec(): - self.log.info(export_dlg.get_tables_to_export()) - self.log.info(f"export DB to {export_dlg.file_name}") - self.statusBar.showMessage(f"export DB to {export_dlg.file_name}", 3000) - self.kontor_db.export_db(export_dlg.current_export_type, export_dlg.file_name) - else: - self.statusBar.showMessage("Export cancelled", 3000) - - def update_title(self): - self.log.info("update title for table MediaFile") - self.statusBar.showMessage("update title for table MediaFile", 3000) - self.status_progress.setEnabled(True) - self.kontor_db.update_titles() - self.status_progress.setEnabled(False) - self.refresh() - - def start_download(self): - self.status_progress.setEnabled(True) - self.statusBar.showMessage("download videos for table MediaFile", 3000) - self.downloader = VideoDownloader(self.kontor_db, self.log) - self.downloader.setTotalProgress.connect(self.status_progress.setMaximum) - self.downloader.setCurrentProgress.connect(self.downloadProgress) - self.downloader.succeeded.connect(self.downloadSucceeded) - self.downloader.finished.connect(self.downloadFinished) - self.downloader.start() - - def downloadProgress(self, value: int): - self.status_progress.setValue(value) - self.refresh() - - def downloadSucceeded(self): - self.status_progress.setValue(self.status_progress.maximum()) - self.statusBar.showMessage("Download succeeded", 3000) - - def downloadFinished(self): - self.status_progress.setEnabled(False) - del self.downloader - - def check_files(self): - self.log.info("check files") - self.statusBar.showMessage("check files for table MediaFile", 3000) - self.kontor_db.check_files() - - def refresh(self): - self.log.info("refresh") - for (_, window) in self._subwindows.items(): - window.refresh() - - def update_status(self, message, timeout=3000): - self.statusBar.showMessage(message, timeout=timeout) diff --git a/kontor-gui/gui/media_window.py b/kontor-gui/gui/media_window.py deleted file mode 100644 index f084c76..0000000 --- a/kontor-gui/gui/media_window.py +++ /dev/null @@ -1,77 +0,0 @@ -from PySide6.QtCore import Signal, QSortFilterProxyModel -from PySide6.QtWidgets import QMdiSubWindow, QWidget, QVBoxLayout, QTabWidget, QTableView - -from .model_config import KontorModelConfig -from .table_details import KontorTableDetailsView -from .table_model import KontorTableModel - - -class MediaWindow(QMdiSubWindow): - closed = Signal() - - def __init__(self, main_window): - super().__init__() - self.data_views = list() - 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.setWindowTitle("Media") - self.setWidget(QWidget()) - layout = QVBoxLayout() - self.tabs = QTabWidget() - self.tabs.addTab(self.generate_data_tab("media_file"), "Media File") - self.tabs.addTab(self.generate_data_tab("media_video"), "Media Video") - self.tabs.addTab(self.generate_data_tab("media_article"), "Media Article") - self.tabs.addTab(self.generate_data_tab_with_details("media_actor"), "Media Actor") - self.tabs.currentChanged.connect(self._tab_changed) - layout.addWidget(self.tabs) - self.setLayout(layout) - self.setWidget(self.tabs) - - def closeEvent(self, event): - self.closed.emit() - super().closeEvent(event) - self._main_window.remove_sub_window('media') - - def refresh(self): - self.log.info("MediaWindow.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() - - table_config = KontorModelConfig(self._main_window.kontor_db, self, table_name) - model = KontorTableModel(table_config) - layout = QVBoxLayout() - self.data_views.append(model) - data_tab.setLayout(layout) - table_view = QTableView() - proxy_model = QSortFilterProxyModel() - proxy_model.setSourceModel(model) - table_view.setSortingEnabled(True) - table_view.setModel(proxy_model) - layout.addLayout(table_config.get_filter_layout()) - layout.addWidget(table_view) - model.refresh() - table_view.resizeColumnToContents(0) - return data_tab - - def generate_data_tab_with_details(self, table_name): - table_config = KontorModelConfig(self._main_window.kontor_db, self, table_name) - model = KontorTableModel(table_config) - self.data_views.append(model) - details_view = KontorTableDetailsView(model) - return details_view.data_view - - def cell_selected(self, item): - self.log.info(f"Cell {item.row()}:{item.column()} clicked") diff --git a/kontor-gui/gui/meta_data_window.py b/kontor-gui/gui/meta_data_window.py deleted file mode 100644 index 567abeb..0000000 --- a/kontor-gui/gui/meta_data_window.py +++ /dev/null @@ -1,66 +0,0 @@ -from PySide6.QtCore import Signal, QSortFilterProxyModel -from PySide6.QtWidgets import QWidget, QVBoxLayout, QTabWidget, QTableView, QMdiSubWindow - -from gui.model_config import KontorModelConfig -from gui.table_model import KontorTableModel - - -class MetaDataWindow(QMdiSubWindow): - closed = Signal() - - def __init__(self, main_window): - super().__init__() - self.data_views = list() - 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.setWindowTitle("Meta Data") - self.setWidget(QWidget()) - layout = QVBoxLayout() - self.tabs = QTabWidget() - self.tabs.addTab(self.generate_data_tab("module_data"), "Module") - self.tabs.addTab(self.generate_data_tab("meta_data_table"), "Tables") - self.tabs.addTab(self.generate_data_tab("meta_data_column"), "Columns") - self.tabs.currentChanged.connect(self._tab_changed) - layout.addWidget(self.tabs) - self.setLayout(layout) - self.setWidget(self.tabs) - - def closeEvent(self, event): - self.closed.emit() - super().closeEvent(event) - self._main_window.remove_sub_window('meta_data') - - 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() - table_config = KontorModelConfig(self._main_window.kontor_db, self, table_name) - model = KontorTableModel(table_config) - layout = QVBoxLayout() - self.data_views.append(model) - data_tab.setLayout(layout) - table_view = QTableView() - # header = table_view.horizontalHeader() - # header.setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents) - proxy_model = QSortFilterProxyModel() - proxy_model.setSourceModel(model) - table_view.setSortingEnabled(True) - table_view.setModel(proxy_model) - layout.addLayout(table_config.get_filter_layout()) - layout.addWidget(table_view) - model.refresh() - table_view.resizeColumnToContents(0) - return data_tab diff --git a/kontor-gui/gui/model_config.py b/kontor-gui/gui/model_config.py deleted file mode 100644 index 6a4e00b..0000000 --- a/kontor-gui/gui/model_config.py +++ /dev/null @@ -1,55 +0,0 @@ -from PySide6.QtWidgets import QHBoxLayout, QCheckBox -from kontor_schema import KontorDB, ColumnEntry - - -class KontorModelConfig: - - def __init__(self, kontor_db: KontorDB, main_window, table_name: str): - 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(): - # print(column, filter_info) - if filter_info[ColumnEntry.COLUMN_WIDGET].isChecked(): - _filters[column] = True - # print(f"{filter_rule=}") - # self.log.info("filters -> %s", _filters) - return _filters - - def get_data(self) -> list: - # self.log.info("get_data") - data = self.kontor_db.data(self._table_name, self.header, self.filters()) - # 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() - filter_checkbox.setText(filter_info[ColumnEntry.COLUMN_LABEL]) - filter_checkbox.checkStateChanged.connect(self.main_window.refresh) - self.filter[column][ColumnEntry.COLUMN_WIDGET] = filter_checkbox - filter_layout.addWidget(filter_checkbox) - filter_layout.addStretch() - # self.log.info("get_filter_layout: %s", self.filter) - return filter_layout diff --git a/kontor-gui/gui/progress.py b/kontor-gui/gui/progress.py deleted file mode 100644 index 1b44c26..0000000 --- a/kontor-gui/gui/progress.py +++ /dev/null @@ -1,18 +0,0 @@ -from PySide6.QtWidgets import QProgressBar - - -class ProgressUpdate: - def __init__(self, progress: QProgressBar): - self.start = 0 - self.end = 0 - self.current = 0 - self.progress = progress - - def start(self, start_value, end_value): - self.start = start_value - self.end = end_value - self.current = start_value - self.progress.update() - - def update(self, current): - self.progress.update() diff --git a/kontor-gui/gui/table_details.py b/kontor-gui/gui/table_details.py deleted file mode 100644 index 07760f0..0000000 --- a/kontor-gui/gui/table_details.py +++ /dev/null @@ -1,60 +0,0 @@ -from PySide6.QtCore import QSortFilterProxyModel -from PySide6.QtWidgets import QHBoxLayout, QWidget, QTableView, QVBoxLayout, QFormLayout, QLineEdit, QLabel - -from .table_model import KontorTableModel - - -class KontorTableDetailsView: - def __init__(self, table_model: KontorTableModel): - self._data_view: QWidget = QWidget() - self._model = table_model - self.log = table_model.log - self._table_view = QTableView() - self._label = QLabel() - self.init_gui() - - def init_gui(self): - self.log.info("KontorTableDetailsView.init_gui()") - layout = QVBoxLayout() - self._data_view.setLayout(layout) - details_layout = QHBoxLayout() - table_with_details = QWidget() - table_with_details.setLayout(details_layout) - - self._table_view.setSelectionBehavior(QTableView.SelectionBehavior.SelectRows) - proxy_model = QSortFilterProxyModel() - proxy_model.setSourceModel(self._model) - self._table_view.setSortingEnabled(True) - self._table_view.setModel(proxy_model) - self._table_view.clicked.connect(self.update_details) - self._table_view.activated.connect(self.refresh_details) - - layout.addLayout(self._model.config.get_filter_layout()) - details_layout.addWidget(self._table_view) - - form = QWidget() - form_layout = QFormLayout(form) - form.setLayout(form_layout) - - title = QLineEdit(form) - form_layout.addRow("ID", self._label) - form_layout.addRow("Title", title) - # layout.addWidget(table_view) - details_layout.addWidget(form) - layout.addWidget(table_with_details) - self._model.refresh() - self._table_view.resizeColumnToContents(0) - - @property - def data_view(self): - return self._data_view - - def update_details(self, item): - print(f"Cell {item.row()}-{item.column()} selected") - self.log.info(f"Cell {item.row()}-{item.column()} selected") - self._label.setText(self._model.raw_data()[item.row()][0]) - - def refresh_details(self): - indexes = self._table_view.selectedIndexes() - for index in indexes: - self.log.info(f"refresh_details: Cell {index.row()}-{index.column()} selected") diff --git a/kontor-gui/gui/table_model.py b/kontor-gui/gui/table_model.py deleted file mode 100644 index fb32802..0000000 --- a/kontor-gui/gui/table_model.py +++ /dev/null @@ -1,128 +0,0 @@ -from datetime import datetime -from typing import Any - -from PySide6.QtCore import QAbstractTableModel, QModelIndex -from PySide6.QtGui import Qt, QColor -from kontor_schema.database import ColumnEntry - -from .model_config import KontorModelConfig - - -def get_display_value(value: Any, column_config: dict, window) -> str: - if isinstance(value, datetime): - return value.strftime("%Y-%m-%d %M:%M:%S") - if column_config[ColumnEntry.COLUMN_TYPE] == 'BOOLEAN': - if value == 1: - return window.tick - else: - return window.cross - if value is None: - return "" - # window.log.info(f"unknown type: {column_config[ColumnEntry.COLUMN_TYPE]} - {type(value)}") - return str(value) - - -def get_edit_value(value, column_config, window): - # window.log.info(f"edit value {value}") - return str(value) - - -def get_decoration_value(value: Any, column_config: dict, window): - if column_config[ColumnEntry.COLUMN_TYPE] == 'BOOLEAN': - if value == 1: - return window.tick - else: - return window.cross - - -def get_background_value(value: Any, column_config: dict, window): - if value is None: - return QColor('lightgrey') - - -class KontorTableModel(QAbstractTableModel): - - def __init__(self, model_config: KontorModelConfig): - super().__init__() - 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})" - - @property - def config(self): - return self._config - - @property - def raw_data(self): - return self._data - - def refresh(self): - # self.log.info("refresh") - data = self._config.get_data() - count = 0 - # print(data) - if data is not None: - self.beginResetModel() - self._data.clear() - self._data = data - self.endResetModel() - count = len(data) - # print(data) - # print(self._data) - self.layoutChanged.emit() - 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 - return len(self._data) - - def headerData(self, col, orientation, role=Qt.ItemDataRole.DisplayRole): - # self.log.info(f"{self._config.header[col]}") - if orientation == Qt.Orientation.Horizontal and role == Qt.ItemDataRole.DisplayRole: - return self._config.header[col][ColumnEntry.COLUMN_LABEL] - if orientation == Qt.Orientation.Vertical and role == Qt.ItemDataRole.DisplayRole: - return str(col + 1) - - def data(self, index, role=Qt.ItemDataRole.DisplayRole): - if self._data is None: - return None - value = self._data[index.row()][index.column()] - # print('{}:: {}:: {}:: {}: {}'.format(index, role, self._config.header[index.column()][ColumnEntry.COLUMN_TYPE], value, type(value))) - match role: - case Qt.ItemDataRole.DisplayRole: - return get_display_value(value, self._config.header[index.column()], self._config.main_window) - case Qt.ItemDataRole.EditRole: - return get_edit_value(value, self._config.header[index.column()], self._config.main_window) - case Qt.ItemDataRole.DecorationRole: - return get_decoration_value(value, self._config.header[index.column()], self._config.main_window) - case Qt.ItemDataRole.BackgroundRole: - return get_background_value(value, self._config.header[index.column()], self._config.main_window) - - def columnCount(self, index=QModelIndex()): - # self.log.info("rowCount %s: %d", self, len(self._config.header)) - return len(self._config.header) - - def setData(self, index, value, role=Qt.ItemDataRole.EditRole) -> bool: - # self._config.log.info(f"{index}: {role}") - if role == Qt.ItemDataRole.EditRole: - self._data[index.row()][index.column()] = value - # self._config.log.info(f"{index.row()}-{index.column()}: {self._data[index.row()][index.column()]}") - self.dataChanged.emit(index, index) - return True - if role == Qt.ItemDataRole.CheckStateRole: - print("role == Qt.ItemDataRole.CheckStateRole") - checked = value == Qt.CheckState.Checked - self._data[index.row()][index.column()] = checked - return False - - def flags(self, index): - if self._config.header[index.column()][ColumnEntry.COLUMN_NAME] == 'id': - return Qt.ItemFlag.ItemIsEnabled - return Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsEditable | Qt.ItemFlag.ItemIsUserTristate diff --git a/kontor-gui/gui/worker.py b/kontor-gui/gui/worker.py deleted file mode 100644 index 5f0d4d6..0000000 --- a/kontor-gui/gui/worker.py +++ /dev/null @@ -1,27 +0,0 @@ - -from PySide6.QtCore import Signal, QThread - - -class VideoDownloader(QThread): - # Signal for the window to establish the maximum value - # of the progress bar. - setTotalProgress = Signal(int) - # Signal to increase the progress. - setCurrentProgress = Signal(int) - # Signal to be emitted when the file has been downloaded successfully. - succeeded = Signal() - - def __init__(self, kontor_db, log): - super().__init__() - self.kontor_db = kontor_db - self.log = log - - def run(self): - self.log.info("download videos for table MediaFile") - download_entries = self.kontor_db.get_download_list() - self.setTotalProgress.emit(len(download_entries)) - for index, entry in enumerate(download_entries): - self.kontor_db.download_file(entry) - self.setCurrentProgress.emit(index) - self.succeeded.emit() - diff --git a/kontor-gui/main.py b/kontor-gui/main.py deleted file mode 100644 index 9ec73f1..0000000 --- a/kontor-gui/main.py +++ /dev/null @@ -1,48 +0,0 @@ -""" -PySide6 GUI for Kontor -""" -import sys -import logging.config -from pathlib import Path -from platformdirs import PlatformDirs -from PySide6.QtWidgets import QApplication -import yaml -from sqlalchemy import create_engine -from sqlalchemy.orm import sessionmaker -from kontor_schema.base import Base - -from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter -from gui.main_window import MainWindow - -parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter) -parser.add_argument('--verbose', '-v', action='count', default=0) -parser.add_argument('--config', '-c', default='kontor-docker') -args = parser.parse_args() - - -if __name__ == '__main__': - app = QApplication(sys.argv) - dirs = PlatformDirs(args.config) - database_config = Path(dirs.user_config_dir, 'database-config.yaml') - with open(database_config, 'rt') as f: - db_config = yaml.safe_load(f.read()) - connect_string = ('mariadb+mariadbconnector://{}:{}@{}:{}/{}'.format( - db_config['mariadb']['user'], - db_config['mariadb']['password'], - db_config['mariadb']['host'], - db_config['mariadb']['port'], - db_config['mariadb']['database'] - )) - logging_config = Path(dirs.user_config_dir, 'logging-config.yaml') - with open(logging_config, 'rt') as f: - config = yaml.safe_load(f.read()) - logging.config.dictConfig(config) - logger = logging.getLogger('development') - # engine = create_engine(connect_string, echo=True) - engine = create_engine(connect_string) - Base.metadata.create_all(bind=engine, checkfirst=True) - __session__ = sessionmaker(bind=engine) - - window = MainWindow(engine, logger) - window.show() - app.exec() diff --git a/kontor-gui/pyproject.toml b/kontor-gui/pyproject.toml deleted file mode 100644 index db3be97..0000000 --- a/kontor-gui/pyproject.toml +++ /dev/null @@ -1,26 +0,0 @@ -[project] -name = "kontor-gui" -version = "0.1.0" -description = "Kontor GUI" -authors = [ - {name = "Thomas Peetz", email = "thomas.peetz@thpeetz.de"}, -] -dependencies = [ - "platformdirs", - "pyyaml", - "PySide6", -] -requires-python = ">=3.11" -readme = "README.md" -license = {text = "MIT"} - -[build-system] -requires = ["pdm-backend"] -build-backend = "pdm.backend" - - -[tool.pdm] -distribution = true - -[dependency-groups] -dev = ["-e file:///${PROJECT_ROOT}/../kontor-schema#egg=kontor-schema"] diff --git a/kontor-gui/pysidedeploy.spec b/kontor-gui/pysidedeploy.spec deleted file mode 100644 index 6fb865d..0000000 --- a/kontor-gui/pysidedeploy.spec +++ /dev/null @@ -1,98 +0,0 @@ -[app] - -# title of your application -title = kontor - -# project directory. the general assumption is that project_dir is the parent directory -# of input_file -project_dir = /home/tpeetz/projects/kontor/python/kontor-gui - -# source file path -input_file = /home/tpeetz/projects/kontor/python/kontor-gui/main.py - -# directory where exec is stored -exec_directory = . - -# path to .pyproject project file -project_file = - -# application icon -icon = /usr/local/lib/python3.11/dist-packages/PySide6/scripts/deploy_lib/pyside_icon.jpg - -[python] - -# python path -python_path = /home/tpeetz/projects/kontor/python/kontor-gui/env/bin/python - -# python packages to install -packages = Nuitka==2.4.8 - -# buildozer = for deploying Android application -android_packages = buildozer==1.5.0,cython==0.29.33 - -[qt] - -# comma separated path to qml files required -# normally all the qml files required by the project are added automatically -qml_files = - -# excluded qml plugin binaries -excluded_qml_plugins = - -# qt modules used. comma separated -modules = Widgets,DBus,Core,Gui - -# qt plugins used by the application -plugins = platformthemes,imageformats,platforms,generic,iconengines,egldeviceintegrations,styles,xcbglintegrations,platforms/darwin,platforminputcontexts,accessiblebridge - -[android] - -# path to pyside wheel -wheel_pyside = - -# path to shiboken wheel -wheel_shiboken = - -# plugins to be copied to libs folder of the packaged application. comma separated -plugins = - -[nuitka] - -# usage description for permissions requested by the app as found in the info.plist file -# of the app bundle -# eg = extra_args = --show-modules --follow-stdlib -macos.permissions = - -# mode of using nuitka. accepts standalone or onefile. default is onefile. -mode = onefile - -# (str) specify any extra nuitka arguments -extra_args = --quiet --noinclude-qt-translations - -[buildozer] - -# build mode -# possible options = [release, debug] -# release creates an aab, while debug creates an apk -mode = debug - -# contrains path to pyside6 and shiboken6 recipe dir -recipe_dir = - -# path to extra qt android jars to be loaded by the application -jars_dir = - -# if empty uses default ndk path downloaded by buildozer -ndk_path = - -# if empty uses default sdk path downloaded by buildozer -sdk_path = - -# other libraries to be loaded. comma separated. -# loaded at app startup -local_libs = - -# architecture of deployed platform -# possible values = ["aarch64", "armv7a", "i686", "x86_64"] -arch = - diff --git a/kontor-gui/pyvenv.cfg b/kontor-gui/pyvenv.cfg deleted file mode 100644 index e6324f5..0000000 --- a/kontor-gui/pyvenv.cfg +++ /dev/null @@ -1,5 +0,0 @@ -home = /usr/bin -include-system-site-packages = false -version = 3.11.2 -executable = /usr/bin/python3.11 -command = /usr/bin/python -m venv /home/tpeetz/projects/kontor/python/kontor-gui diff --git a/kontor-gui/requirements.txt b/kontor-gui/requirements.txt deleted file mode 100644 index a6e9a93..0000000 --- a/kontor-gui/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ --e ../kontor-schema - -platformdirs -pyyaml -PySide6 - diff --git a/kontor-gui/res/application-export.png b/kontor-gui/res/application-export.png deleted file mode 100644 index 555887a..0000000 Binary files a/kontor-gui/res/application-export.png and /dev/null differ diff --git a/kontor-gui/res/application-import.png b/kontor-gui/res/application-import.png deleted file mode 100644 index 922cb07..0000000 Binary files a/kontor-gui/res/application-import.png and /dev/null differ diff --git a/kontor-gui/res/arrow-circle-double.png b/kontor-gui/res/arrow-circle-double.png deleted file mode 100644 index ba5ebd1..0000000 Binary files a/kontor-gui/res/arrow-circle-double.png and /dev/null differ diff --git a/kontor-gui/res/cross.png b/kontor-gui/res/cross.png deleted file mode 100644 index 6b9fa6d..0000000 Binary files a/kontor-gui/res/cross.png and /dev/null differ diff --git a/kontor-gui/res/tick.png b/kontor-gui/res/tick.png deleted file mode 100644 index 2414885..0000000 Binary files a/kontor-gui/res/tick.png and /dev/null differ diff --git a/kontor-gui/src/kontor_gui/__init__.py b/kontor-gui/src/kontor_gui/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/kontor-gui/tests/__init__.py b/kontor-gui/tests/__init__.py deleted file mode 100644 index e69de29..0000000