diff --git a/src/MainWidgets.py b/src/MainWidgets.py index 6fa12e9..aca65fb 100644 --- a/src/MainWidgets.py +++ b/src/MainWidgets.py @@ -91,9 +91,9 @@ def __delete_filter(self, index): def delete_question_group(self, index_tabwidget: int): msgBox = QMessageBox() - msgBox.setWindowTitle("Regelgruppe löschen.") - msgBox.setText("Regelgruppe löschen.
" - "Möchtest du wirklich diese Fragengruppe löschen? Dies lässt sich nicht umkehren!") + msgBox.setWindowTitle("Fragengruppe löschen.") + msgBox.setText("Möchtest du diese Fragengruppe wirklich löschen?
" + "Dies lässt sich nicht umkehren!") msgBox.setStandardButtons(QMessageBox.Yes | QMessageBox.Cancel) msgBox.setDefaultButton(QMessageBox.Cancel) ret = msgBox.exec() @@ -125,7 +125,7 @@ def _question_group_editor(self, question_group: Union[QuestionGroup, None], # ID was not changed -> update of title return EditorResult.Success if db.get_question_group(editor.id): - QMessageBox(QMessageBox.Icon.Critical, "Fehler", "Regelgruppennummer existiert bereits!", + QMessageBox(QMessageBox.Icon.Critical, "Fehler", "Fragengruppennummer existiert bereits!", parent=self, ).exec() return EditorResult.Invalid return EditorResult.Success diff --git a/src/datatypes.py b/src/datatypes.py index 9a1011c..ce0e0aa 100644 --- a/src/datatypes.py +++ b/src/datatypes.py @@ -120,7 +120,7 @@ class Question(Base): signature = Column(String, default=(lambda: uuid.uuid4().hex), primary_key=True) parameters = { - 'group_id': QuestionParameters(table_header="Regelgruppe", filter_options=None, datatype=int), + 'group_id': QuestionParameters(table_header="Fragengruppe", filter_options=None, datatype=int), 'question_id': QuestionParameters(table_header="Regelnummer", filter_options=(FilterOption.equal,), datatype=int), 'question': QuestionParameters(table_header="Frage", diff --git a/src/main_application.py b/src/main_application.py index 1704851..7255cff 100644 --- a/src/main_application.py +++ b/src/main_application.py @@ -1,28 +1,19 @@ -import os -import shutil -import stat -import subprocess -import sys import webbrowser from enum import Enum, auto, IntEnum -from typing import Union -import markdown2 -import requests from PIL import Image -from PySide6.QtCore import QCoreApplication, Qt, Signal, QThread +from PySide6.QtCore import QCoreApplication, Qt from PySide6.QtWidgets import QMainWindow, QWidget, QFileDialog, QApplication, QMessageBox, QDialog from bs4 import BeautifulSoup from src import document_builder from src.MainWidgets import FirstSetupWidget, QuestionOverviewWidget -from src.basic_config import app_version, check_for_update, display_name, is_bundled, app_dirs, base_path, \ - current_platform +from src.basic_config import app_version, check_for_update, display_name, is_bundled from src.database import db from src.datatypes import create_question_groups, create_questions_and_mchoice, Regeltest from src.regeltestcreator import RegeltestSaveDialog, RegeltestSetup from src.ui_mainwindow import Ui_MainWindow -from src.ui_update_checker import Ui_UpdateChecker +from src.updater import UpdateChecker class FilterMode(Enum): @@ -124,7 +115,7 @@ def __init__(self, parent=None): self.ui.actionRegeltest_l_schen.setEnabled(False) self.ui.regeltest_list.setAcceptDrops(True) - self.ui.actionAnsicht_zur_cksetzen.triggered.connect(lambda: self.ui.regeltest_creator.show()) + self.ui.actionAnsicht_zur_cksetzen.triggered.connect(self.reset_ui) self.ui.actionRegeldatensatz_exportieren.triggered.connect(lambda: save_dataset(self)) self.ui.actionNeue_Kategorie_erstellen.triggered.connect(self.add_question_group) @@ -152,18 +143,9 @@ def initialize(self): if dataset: for question_group in dataset: self.question_overview.create_question_group_tab(question_group) - self.set_mode(ApplicationMode.question_overview) + self.set_mode(ApplicationMode.question_overview, reset=True) else: - self.set_mode(ApplicationMode.initial_setup) - - def clear_questionlist(self): - self.ui.regeltest_list.clear() - self.ui.regeltest_list.questions.clear() - self.regeltest_list_updated() - - def regeltest_list_updated(self): - self.ui.regeltest_stats.setText( - f"{self.ui.regeltest_list.count()} Fragen selektiert ({self.ui.regeltest_list.count() * 2} Punkte)") + self.set_mode(ApplicationMode.initial_setup, reset=True) def load_dataset(self): load_dataset(self, reset_cursor=False) @@ -174,16 +156,34 @@ def add_question_group(self): self.question_overview.add_question_group() self.set_mode(ApplicationMode.question_overview) - def set_mode(self, mode: ApplicationMode): - if self.ui.stackedWidget.currentIndex() == int(mode): + def reset_ui(self): + self.set_mode(ApplicationMode(self.ui.stackedWidget.currentIndex()), reset=True) + + def set_mode(self, mode: ApplicationMode, reset=False): + if self.ui.stackedWidget.currentIndex() == int(mode) and not reset: return self.ui.stackedWidget.setCurrentIndex(int(mode)) + + if mode == ApplicationMode.initial_setup: + self.ui.actionAnsicht_zur_cksetzen.setDisabled(True) + else: + self.ui.actionAnsicht_zur_cksetzen.setDisabled(False) + if mode == ApplicationMode.question_overview: self.ui.regeltest_creator.show() else: self.ui.regeltest_creator.close() + def clear_questionlist(self): + self.ui.regeltest_list.clear() + self.ui.regeltest_list.questions.clear() + self.regeltest_list_updated() + + def regeltest_list_updated(self): + self.ui.regeltest_stats.setText( + f"{self.ui.regeltest_list.count()} Fragen selektiert ({self.ui.regeltest_list.count() * 2} Punkte)") + def setup_regeltest(self): regeltest_setup = RegeltestSetup(self) if regeltest_setup.exec(): @@ -210,139 +210,3 @@ def create_regeltest(self): icon=icon) QApplication.restoreOverrideCursor() webbrowser.open_new(output_path) - - -class UpdateChecker(QDialog, Ui_UpdateChecker): - def __init__(self, parent, versions, display_dev=False): - super(UpdateChecker, self).__init__(parent) - self.ui = Ui_UpdateChecker() - self.ui.setupUi(self) - self.setWindowTitle("Update-Check") - self.versions = versions - - self.ui.comboBox.currentIndexChanged.connect(self.display) - - if display_dev: - self.ui.comboBox.setCurrentIndex(1) - - self.ui.text.setTextFormat(Qt.RichText) - self.ui.text.setTextInteractionFlags(Qt.TextBrowserInteraction) - self.ui.text.setOpenExternalLinks(True) - - self.download_link = None # type: Union[str, None] - self.ui.install_update_button.clicked.connect(self.update) - self.ui.install_update_button.setDisabled(True) - self.ui.download_progress.setVisible(False) - if not is_bundled: - self.ui.install_update_button.setText("Auto-Update ist nur mit der kompilierten Version möglich!") - if current_platform == 'Darwin': - self.ui.install_update_button.setVisible(False) - - self.display() - - def display(self): - release = self.versions[self.ui.comboBox.currentIndex()] - if not release: - self.ui.text.setText("

Kein Update verfügbar!

Die aktuellste Version ist bereits installiert.") - self.download_link = None - if is_bundled: - self.ui.install_update_button.setDisabled(True) - return - if release[3]: - download_link = f'Neueste Version jetzt herunterladen' - self.download_link = release[3] - if is_bundled: - self.ui.install_update_button.setDisabled(False) - else: - download_link = 'Noch kein Download für die aktuelle Plattform verfügbar.
' \ - 'Bitte versuche es später erneut.' - self.download_link = None - if is_bundled: - self.ui.install_update_button.setDisabled(True) - release_notes = markdown2.markdown(release[1]).replace("h3>", "h4>").replace("h2>", "h3>").replace("h1>", "h2>") - self.ui.text.setText(f'

Update {release[0]} verfügbar!

' - f'{release_notes}{download_link}') - - def update(self) -> None: - def progressbar_tracking(value): - self.ui.download_progress.setValue(value) - if value != 100: - return - - updater_script_win = "updater.ps1" - os.rename(os.path.join(base_path, updater_script_win), - os.path.join(app_dirs.user_cache_dir, updater_script_win)) - - updater_script_unix = "updater.sh" - os.rename(os.path.join(base_path, updater_script_unix), - os.path.join(app_dirs.user_cache_dir, updater_script_unix)) - if current_platform == 'Darwin' or current_platform == 'Linux': - os.chmod(os.path.join(app_dirs.user_cache_dir, updater_script_unix), - stat.S_IXUSR | stat.S_IRUSR) - os.chmod(os.path.join(app_dirs.user_cache_dir, executable_name), - stat.S_IXUSR | stat.S_IRUSR) - - if current_platform == 'Windows': - subprocess.Popen(["powershell.exe", os.path.join(app_dirs.user_cache_dir, updater_script_win), - sys.executable, str(os.getpid()), download_path], - creationflags=subprocess.CREATE_NEW_CONSOLE) - elif current_platform == 'Darwin' or current_platform == 'Linux': - subprocess.Popen(" ".join([os.path.join(app_dirs.user_cache_dir, updater_script_unix), - sys.executable, str(os.getpid()), download_path]), shell=True) - sys.exit(0) - - if not self.download_link: - return - - self.ui.download_progress.setVisible(True) - - if os.path.isdir(app_dirs.user_cache_dir): - shutil.rmtree(app_dirs.user_cache_dir, ignore_errors=True) - if not os.path.isdir(app_dirs.user_cache_dir): - os.makedirs(app_dirs.user_cache_dir) - - path, executable_name = os.path.split(sys.executable) - - download_path = os.path.join(app_dirs.user_cache_dir, executable_name) - - request = requests.get(self.download_link, stream=True) - filesize = request.headers['Content-Length'] - file_handle = open(download_path, 'wb+') - downloadThread = DownloadThread(request, filesize, file_handle, buffer=10240) - downloadThread.download_progress.connect(progressbar_tracking) - downloadThread.run() - - # r = requests.get(self.download_link) - # with open(download_path, 'wb+') as file: - # file.write(r.content) - - -class DownloadThread(QThread): - download_progress = Signal(int) - - def __init__(self, request, filesize, fileobj, buffer): - super(DownloadThread, self).__init__() - self.request = request - self.filesize = filesize - self.fileobj = fileobj - self.buffer = buffer - - def run(self): - try: - offset = 0 - for chunk in self.request.iter_content(chunk_size=self.buffer): - if not chunk: - break - self.fileobj.seek(offset) - self.fileobj.write(chunk) - offset = offset + len(chunk) - download_progress = offset / int(self.filesize) * 100 - if download_progress != 100: - self.download_progress.emit(int(download_progress)) - - self.fileobj.close() - self.download_progress.emit(100) - self.exit(0) - - except Exception as e: - print(e) diff --git a/src/updater.py b/src/updater.py new file mode 100644 index 0000000..9a89684 --- /dev/null +++ b/src/updater.py @@ -0,0 +1,149 @@ +import os +import shutil +import stat +import subprocess +import sys + +import markdown2 +import requests +from PySide6.QtCore import Signal, QThread, Qt +from PySide6.QtWidgets import QDialog + +from src.basic_config import app_dirs, current_platform, base_path, is_bundled +from src.ui_update_checker import Ui_UpdateChecker + + +class UpdateChecker(QDialog, Ui_UpdateChecker): + def __init__(self, parent, versions, display_dev=False): + super(UpdateChecker, self).__init__(parent) + self.ui = Ui_UpdateChecker() + self.ui.setupUi(self) + self.setWindowTitle("Update-Check") + self.versions = versions + + self.ui.comboBox.currentIndexChanged.connect(self.display) + + if display_dev: + self.ui.comboBox.setCurrentIndex(1) + + self.ui.text.setTextFormat(Qt.RichText) + self.ui.text.setTextInteractionFlags(Qt.TextBrowserInteraction) + self.ui.text.setOpenExternalLinks(True) + + self.download_link = None # type: Union[str, None] + self.ui.install_update_button.clicked.connect(self.update) + self.ui.install_update_button.setDisabled(True) + self.ui.download_progress.setVisible(False) + if not is_bundled: + self.ui.install_update_button.setText("Auto-Update ist nur mit der kompilierten Version möglich!") + if current_platform == 'Darwin': + self.ui.install_update_button.setVisible(False) + + self.display() + + def display(self): + release = self.versions[self.ui.comboBox.currentIndex()] + if not release: + self.ui.text.setText("

Kein Update verfügbar!

Die aktuellste Version ist bereits installiert.") + self.download_link = None + if is_bundled: + self.ui.install_update_button.setDisabled(True) + return + if release[3]: + download_link = f'Neueste Version jetzt herunterladen' + self.download_link = release[3] + if is_bundled: + self.ui.install_update_button.setDisabled(False) + else: + download_link = 'Noch kein Download für die aktuelle Plattform verfügbar.
' \ + 'Bitte versuche es später erneut.' + self.download_link = None + if is_bundled: + self.ui.install_update_button.setDisabled(True) + release_notes = markdown2.markdown(release[1]).replace("h3>", "h4>").replace("h2>", "h3>").replace("h1>", "h2>") + self.ui.text.setText(f'

Update {release[0]} verfügbar!

' + f'{release_notes}{download_link}') + + def update(self) -> None: + def progressbar_tracking(value): + self.ui.download_progress.setValue(value) + if value != 100: + return + + updater_script_win = "updater.ps1" + os.rename(os.path.join(base_path, updater_script_win), + os.path.join(app_dirs.user_cache_dir, updater_script_win)) + + updater_script_unix = "updater.sh" + os.rename(os.path.join(base_path, updater_script_unix), + os.path.join(app_dirs.user_cache_dir, updater_script_unix)) + if current_platform == 'Darwin' or current_platform == 'Linux': + os.chmod(os.path.join(app_dirs.user_cache_dir, updater_script_unix), + stat.S_IXUSR | stat.S_IRUSR) + os.chmod(os.path.join(app_dirs.user_cache_dir, executable_name), + stat.S_IXUSR | stat.S_IRUSR) + + if current_platform == 'Windows': + subprocess.Popen(["powershell.exe", os.path.join(app_dirs.user_cache_dir, updater_script_win), + sys.executable, str(os.getpid()), download_path], + creationflags=subprocess.CREATE_NEW_CONSOLE) + elif current_platform == 'Darwin' or current_platform == 'Linux': + subprocess.Popen(" ".join([os.path.join(app_dirs.user_cache_dir, updater_script_unix), + sys.executable, str(os.getpid()), download_path]), shell=True) + sys.exit(0) + + if not self.download_link: + return + + self.ui.download_progress.setVisible(True) + + if os.path.isdir(app_dirs.user_cache_dir): + shutil.rmtree(app_dirs.user_cache_dir, ignore_errors=True) + if not os.path.isdir(app_dirs.user_cache_dir): + os.makedirs(app_dirs.user_cache_dir) + + path, executable_name = os.path.split(sys.executable) + + download_path = os.path.join(app_dirs.user_cache_dir, executable_name) + + request = requests.get(self.download_link, stream=True) + filesize = request.headers['Content-Length'] + file_handle = open(download_path, 'wb+') + downloadThread = DownloadThread(request, filesize, file_handle, buffer=10240) + downloadThread.download_progress.connect(progressbar_tracking) + downloadThread.run() + + # r = requests.get(self.download_link) + # with open(download_path, 'wb+') as file: + # file.write(r.content) + + +class DownloadThread(QThread): + download_progress = Signal(int) + + def __init__(self, request, filesize, fileobj, buffer): + super(DownloadThread, self).__init__() + self.request = request + self.filesize = filesize + self.fileobj = fileobj + self.buffer = buffer + + def run(self): + try: + offset = 0 + for chunk in self.request.iter_content(chunk_size=self.buffer): + if not chunk: + break + self.fileobj.seek(offset) + self.fileobj.write(chunk) + offset = offset + len(chunk) + download_progress = offset / int(self.filesize) * 100 + if download_progress != 100: + self.download_progress.emit(int(download_progress)) + + self.fileobj.close() + self.download_progress.emit(100) + self.exit(0) + + except Exception as e: + print(e)