Example #1
0
    def load_db_config() -> dict:
        file = Path(get_current_modules_dir()) / Path(DB_CONFIG_FILE)

        if not file.exists():
            LOGGER.error('Could not locate db_config file: %s',
                         file.absolute().as_posix())
            return dict()

        config: dict
        config = Settings.pickle_load(file, True)

        key_file = Path(config.get('key_location') or '.')
        key = None

        if key_file.exists() and key_file.is_file():
            with open(key_file, 'rb') as f:
                key = f.read()

        if not key:
            LOGGER.error('Could not read key file %s', key_file)
            return dict()

        decrypted_config = dict()
        for k, v in config.items():
            if type(v) is not bytes:
                continue
            decrypted_config[k] = decrypt(key, v)

        LOGGER.debug('Loaded db_config for %s', decrypted_config.get('host'))
        return decrypted_config
Example #2
0
    def load_docs(self):
        doc_file = Path(get_current_modules_dir()) / DOCS_HTML_FILEPATH

        if path_exists(doc_file):
            q = QUrl.fromLocalFile(doc_file.as_posix())
            LOGGER.info('Loading Documentation file: %s', q.toDisplayString())

            self.load(q)
Example #3
0
def get_translation():
    # Set OS language if not already set
    lang = os.environ.get('LANGUAGE')

    if not lang:
        print('Setting language from OS.')
        os.environ.setdefault('LANGUAGE', get_ms_windows_language())
        print('Local Language detected: ' + os.environ.get('LANGUAGE'))

    locale_dir = os.path.join(get_current_modules_dir(), 'locale')
    return translation('knecht', localedir=locale_dir, codeset='UTF-8')
Example #4
0
    def from_ui_file(widget_cls, ui_file, custom_widgets=dict()):
        """ Load a Qt .ui file to setup the provided widget """
        # Store current log level and set it to ERROR for Ui load
        current_log_level = logging.root.getEffectiveLevel()
        logging.root.setLevel(logging.ERROR)

        # Load the Ui file
        ui_file = Path(get_current_modules_dir()) / UI_PATH / ui_file
        file = QFile(ui_file.as_posix())
        file.open(QFile.ReadOnly)
        loadUi(file, widget_cls, custom_widgets)
        file.close()

        # Restore previous log level
        logging.root.setLevel(current_log_level)
Example #5
0
    def load_ui_resources(cls) -> bool:
        """ update app globals with GUI resource paths """
        ui_paths_file = Path(
            get_current_modules_dir()) / Path(UI_PATH) / Path(UI_PATHS_FILE)

        if not ui_paths_file.exists():
            print(
                'Could not locate gui resource file: %s. Aborting application.',
                ui_paths_file.absolute().as_posix())
            return False

        try:
            Settings.load(Resource, ui_paths_file)
        except Exception as e:
            print(
                'Could not load GUI resources from file %s. Aborting application. Error:\n%s',
                ui_paths_file.absolute().as_posix(), e)
            return False
        return True
Example #6
0
class FileMenu(QObject):
    recent_files_changed = Signal()
    new_document_count = 0
    current_progress_obj = ShowTreeViewProgressMessage(None)
    load_save_mgr = None
    supported_file_types = ('.xml', '.rksession', '.xlsx')

    viewer_app = Path(get_current_modules_dir()) / KNECHT_VIEWER_BIN
    schnuffi_app = Path(get_current_modules_dir()) / POS_SCHNUFFI_BIN

    def __init__(self, ui, menu: QMenu = None):
        """ The File menu

        :param modules.gui.main_ui.KnechtWindow ui:
        :param menu: Menu created setup in ui file
        """
        super(FileMenu, self).__init__(parent=ui)
        self.ui = ui
        self.view_mgr: UiViewManager = None

        self.menu = menu or ui.menuDatei
        self.menu.setEnabled(False)
        self.recent_menu = QMenu(_('Zuletzt geöffnet'), self.menu)
        self.import_menu = ImportMenu(self.ui)
        self.import_menu.new_model_ready.connect(self.model_loaded)

        self.xml_message_box = XmlFailedMsgBox(self.ui)

        self.setup_file_menu()
        QTimer.singleShot(1, self.delayed_setup)

    @Slot()
    def delayed_setup(self):
        """ Setup attributes that require a fully initialized ui"""
        self.view_mgr: UiViewManager = self.ui.view_mgr
        self.menu.setEnabled(True)

        self.load_save_mgr = SaveLoadController(self)
        self.load_save_mgr.model_loaded.connect(self.model_loaded)
        self.load_save_mgr.load_aborted.connect(self._load_aborted)

    @Slot(Path)
    def guess_open_file(self, local_file_path: Path) -> bool:
        if local_file_path.suffix.casefold() == '.xml':
            self.open_xml(local_file_path.as_posix())
            return True
        elif local_file_path.suffix.casefold() == '.rksession':
            self.import_menu.open_wizard(local_file_path)
            return True
        elif local_file_path.suffix.casefold() == '.xlsx':
            self.import_menu.open_xlsx(local_file_path)
            return True

        return False

    def setup_file_menu(self):
        insert_before = 0
        if self.ui.actionBeenden in self.menu.actions():
            insert_before = self.ui.actionBeenden
            self.ui.actionBeenden.setIcon(IconRsc.get_icon('sad'))
            self.ui.actionBeenden.setShortcut(QKeySequence('Ctrl+Q'))

        # ---- New file ----
        new_action = QAction(IconRsc.get_icon('document'), _('Neu\tStrg+N'),
                             self.menu)
        new_action.setShortcut(QKeySequence('Ctrl+N'))
        new_action.triggered.connect(self.new_document)
        self.menu.insertAction(insert_before, new_action)

        # ---- Open ----
        open_xml_action = QAction(_('Öffnen\tStrg+O'), self.menu)
        open_xml_action.setShortcut(QKeySequence('Ctrl+O'))
        open_xml_action.triggered.connect(self.open_xml)
        open_xml_action.setIcon(IconRsc.get_icon('folder'))
        self.menu.insertAction(insert_before, open_xml_action)

        # ---- Import Menu ----
        self.menu.insertMenu(insert_before, self.import_menu)

        # ---- Save ----
        save_xml_action = QAction(_('Speichern\tStrg+S'), self.menu)
        save_xml_action.setShortcut(QKeySequence('Ctrl+S'))
        save_xml_action.triggered.connect(self.save_xml)
        save_xml_action.setIcon(IconRsc.get_icon('disk'))
        self.menu.insertAction(insert_before, save_xml_action)

        save_as_action = QAction(_('Speichern unter ...\tStrg+Shift+S'),
                                 self.menu)
        save_as_action.setShortcut(QKeySequence('Ctrl+Shift+S'))
        save_as_action.triggered.connect(self.save_as_xml)
        save_as_action.setIcon(IconRsc.get_icon('save_alt'))
        self.menu.insertAction(insert_before, save_as_action)

        self.menu.insertSeparator(insert_before)

        # ---- Apps ----
        start_knecht_viewer = QAction(_('KnechtViewer starten'), self.menu)
        start_knecht_viewer.triggered.connect(self.start_knecht_viewer)
        start_knecht_viewer.setIcon(IconRsc.get_icon('img'))
        self.menu.insertAction(insert_before, start_knecht_viewer)
        if not path_exists(self.viewer_app):
            LOGGER.info('KnechtViewer executable could not be found: %s',
                        self.viewer_app.as_posix())
            start_knecht_viewer.setEnabled(False)

        start_schnuffi_app = QAction(_('POS Schnuffi starten'), self.menu)
        start_schnuffi_app.triggered.connect(self.start_schnuffi_app)
        start_schnuffi_app.setIcon(IconRsc.get_icon('dog'))
        self.menu.insertAction(insert_before, start_schnuffi_app)
        if not path_exists(self.schnuffi_app):
            LOGGER.info('KnechtViewer executable could not be found: %s',
                        self.schnuffi_app.as_posix())
            start_schnuffi_app.setEnabled(False)

        img_conv = QAction(_('Bilddaten konvertieren ...'))
        img_conv.triggered.connect(self.convert_image_directory)
        img_conv.setIcon(IconRsc.get_icon('render'))
        self.menu.insertAction(insert_before, img_conv)

        material_merger = QAction('AViT Material Merger')
        material_merger.triggered.connect(self.start_material_merger)
        material_merger.setIcon(IconRsc.get_icon('options'))
        self.menu.insertAction(insert_before, material_merger)

        self.menu.insertSeparator(insert_before)

        # ---- Recent files menu ----
        self.recent_menu.aboutToShow.connect(self.update_recent_files_menu)
        self.menu.insertMenu(insert_before, self.recent_menu)

        self.menu.insertSeparator(insert_before)

    def new_document(self):
        new_file = Path(
            _('Neues_Dokument_{:02d}.xml').format(self.new_document_count))
        self.view_mgr.create_view(None, new_file)

        self.new_document_count += 1

    def start_knecht_viewer(self):
        start_app(self.viewer_app)

    def start_schnuffi_app(self):
        start_app(self.schnuffi_app)

    def start_material_merger(self):
        material_merger = MaterialMerger(self.ui)
        GenericTabWidget(self.ui, material_merger)

    def save_xml(self):
        if not self.view_mgr.current_tab_is_document_tab():
            return

        self.enable_menus(False)

        file = self.view_mgr.current_file()

        if not file or not path_exists(file):
            if self._ask_save_as_file(file):
                # User agreed to set new save file
                self.save_as_xml()
                return
            # User aborted
            self.enable_menus(True)
            return

        self.save_as_xml(file)

    def save_as_xml(self, file: Path = None):
        if not self.view_mgr.current_tab_is_document_tab():
            return

        self.enable_menus(False)

        if not file:
            current_dir = Path(KnechtSettings.app['current_path'])
            file, file_type = FileDialog.save(self.ui,
                                              current_dir,
                                              file_key='xml')

        if not file:
            LOGGER.info('Save Xml File dialog canceled.')
            self.enable_menus(True)
            return

        file = Path(file)
        view = self.view_mgr.current_view()

        result, error = self.load_save_mgr.save(file, view)

        if result:
            LOGGER.debug('File saved: %s', file.as_posix())
            self.view_mgr.tab_view_saved(file)
            self.ui.msg(
                _('Datei gespeichert:{0}{1:.3}s').format(
                    f'\n{file.name}\n', self.load_save_mgr.last_progress_time))
        else:
            self._save_aborted(error, file)

        self.enable_menus(True)

    def open_xml(self, file: str = None) -> None:
        self.enable_menus(False)

        if not file:
            file = FileDialog.open(self.ui, None, 'xml')

        if not file:
            LOGGER.info('Open Xml File dialog canceled.')
            self.enable_menus(True)
            return

        # Check if the file is already opened
        file = Path(file)
        if self.view_mgr.file_mgr.already_open(file):
            LOGGER.info('File already open.')
            self.enable_menus(True)
            return

        # Update treeview progress
        view = self.view_mgr.current_view()
        view.progress_msg.msg(_('Daten werden gelesen'))
        view.progress_msg.show_progress()

        self.load_save_mgr.open(file)
        self.enable_menus(True)

    @Slot(KnechtModel, Path)
    @Slot(KnechtModel, Path, bool)
    def model_loaded(self,
                     model: KnechtModel,
                     file: Path,
                     reset_clean: bool = False):
        # Update progress
        view = self.view_mgr.current_view()
        view.progress_msg.hide_progress()

        # Create a new view inside a new tab or load into current view if view model is empty
        new_view = self.view_mgr.create_view(model, file)

        # Refresh model data
        if reset_clean:
            new_view.undo_stack.resetClean()

        self.ui.statusBar().showMessage(
            _('{0} in {1:.3}s geladen.').format(
                file.name, self.load_save_mgr.last_progress_time))

    @Slot(str, Path)
    def _load_aborted(self, error_msg: str, file: Path):
        # Update progress
        view = self.view_mgr.current_view()
        view.progress_msg.hide_progress()

        self.xml_message_box.set_error_msg(error_msg, Path(file))

        self.ui.play_warning_sound()
        self.xml_message_box.exec_()

    def _save_aborted(self, error_msg: str, file: Path):
        self.xml_message_box.set_error_msg(error_msg, Path(file))

        self.ui.play_warning_sound()
        self.xml_message_box.exec_()

    def enable_menus(self, enabled: bool = True):
        for a in self.menu.actions():
            a.setEnabled(enabled)

        self.recent_menu.setEnabled(enabled)

    def _open_recent_xml_file(self):
        recent_action = self.sender()
        self.open_xml(recent_action.file)

    def _open_recent_xlsx_file(self):
        recent_action = self.sender()
        self.import_menu.open_xlsx(recent_action.file)

    def _open_recent_rksession(self):
        recent_action = self.sender()
        self.import_menu.open_wizard(recent_action.file)

    def _ask_save_as_file(self, file: Path):
        """ User hits save but file to save does not exist yet """
        msg_box = AskToContinue(self.ui)

        if not msg_box.ask(
                _('Zieldatei zum Speichern festlegen?'),
                _('Die Datei: <i>{}</i><br>'
                  'Pfad: <i>{}</i><br>'
                  'wurde entfernt oder existiert nicht mehr.<br><br>'
                  'Neue Zieldatei zum Speichern festlegen?'
                  '').format(file.name, file.parent.as_posix()),
                _('Speichern unter..')):
            # User wants to abort save as
            return False
        return True

    def convert_image_directory(self):
        img_dir = FileDialog.open_dir(self.ui, None)

        if not img_dir or not path_exists(img_dir):
            self.ui.msg(
                _('Zu konvertierendes Verzeichnis ist nicht erreichbar.'),
                8000)
            return

        img_dir = Path(img_dir)
        out_dir = img_dir / 'converted'

        try:
            out_dir.mkdir(exist_ok=True)
        except Exception as e:
            self.ui.msg(
                _('Konnte Bild Konvertierung Ausgabeverzeichnis nicht erstellen.'
                  ), 8000)
            LOGGER.warning(e)

        img_converter = KnechtImage(self)
        img_converter.conversion_result.connect(self._conversion_result)

        if img_converter.convert_directory(img_dir, out_dir):
            self.ui.msg(
                _('Bildkonvertierung gestartet.<br /><i>{}</i>').format(
                    img_dir), 5000)
        else:
            self.ui.msg(
                _('Bildkonvertierung konnte nicht gestartet werden. Keine konvertierbaren Dateien gefunden.'
                  ), 10000)

    def _conversion_result(self, result: str):
        result = result.replace('\n', '<br />')
        title = _("Ergebnis der Bildkonvertierung:")
        self.ui.overlay.display_confirm(f'<b>{title}</b><br />{result}',
                                        (('[X]', None), ))

    def update_recent_files_menu(self):
        self.recent_menu.clear()

        if not len(KnechtSettings.app['recent_files']):
            no_entries_dummy = QAction(_("Keine Einträge vorhanden"),
                                       self.recent_menu)
            no_entries_dummy.setEnabled(False)
            self.recent_menu.addAction(no_entries_dummy)

        for idx, entry in enumerate(KnechtSettings.app['recent_files']):
            if idx >= 20:
                break

            file, file_type = entry
            file_name = Path(file).stem

            if not path_exists(file):
                # Skip and remove non existing files
                KnechtSettings.app['recent_files'].pop(idx)
                continue

            recent_action = QAction(f'{file_name} - {file_type}',
                                    self.recent_menu)
            recent_action.file = Path(file)

            if file_type == 'xml':
                recent_action.setText(f'{file_name} - Xml Presets')
                recent_action.setIcon(IconRsc.get_icon('document'))
                recent_action.triggered.connect(self._open_recent_xml_file)
            elif file_type == 'xlsx':
                recent_action.setText(f'{file_name} - Excel Import')
                recent_action.setIcon(IconRsc.get_icon('excel'))
                recent_action.triggered.connect(self._open_recent_xlsx_file)
            elif file_type == 'rksession':
                recent_action.setText(f'{file_name} - Preset Wizard Session')
                recent_action.setIcon(IconRsc.get_icon('qub_button'))
                recent_action.triggered.connect(self._open_recent_rksession)

            self.recent_menu.addAction(recent_action)

        self.recent_files_changed.emit()
Example #7
0
def _start_knecht_app():
    app_path = Path(os.path.join(get_current_modules_dir(),
                                 'RenderKnecht.exe'))
    time.sleep(2)
    start_app(app_path)