def run(self): result = str() for img_file in self.img_list: if self.output_dir == Path('.'): self.output_dir = img_file.parent if not path_exists(self.output_dir): try: self.output_dir.mkdir(parents=True) except Exception as e: result += _( 'Konnte Ausgabe Verzeichnis nicht erstellen: {}' ).format(f'{e}\n') break # Open and convert image try: img = OpenImageUtil.read_image(img_file) except Exception as e: result += _( 'Konnte Bilddatei {} nicht konvertieren: {}').format( img_file.name, f'{e}\n') continue # Write image to file try: img_out = self.output_dir / Path(img_file.stem).with_suffix( self.output_format) OpenImageUtil.write_image(img_out, img) result += _('Bilddatei erstellt: {}').format( f'{img_out.name}\n') except Exception as e: result += _('Konnte Bilddatei {} nicht erstellen: {}').format( img_file.name, f'{e}\n') continue # Move source files if not self.move_converted or img_file.suffix == self.output_format: continue # Create un-converted directory move_dir = self.output_dir.parent / self.unconverted_dir_name if not path_exists(move_dir): move_dir.mkdir(parents=True) # Move the file to un-converted directory try: img_file.replace(move_dir / img_file.name) LOGGER.debug('Moving un-converted image file: %s', img_file.name) except FileNotFoundError or FileExistsError: result += _( 'Konnte unkonvertierte Bilddatei nicht verschieben: {}' ).format(f'{img_file.name}') pass self.result_signal.emit(result)
def convert_file(self, img_file: Path, output_dir: Path = Path('.'), output_format: str = '.png', move_converted: bool = False) -> bool: if not path_exists(img_file) or not path_exists(output_dir): return False if not img_file.suffix.casefold() in self.supported_image_types: return False self._start_img_thread([ img_file, ], output_dir, output_format, move_converted) return True
def open_existing_file(cls, parent=None, directory: Union[Path, str] = None, file_key: str = 'xml') -> Union[str, None]: # Update path directory = cls._get_current_path(directory) # Update filter and title depending on file type if file_key not in cls.file_types.keys(): file_key = 'xml' title = cls.file_types[file_key]['title'] file_filter = cls.file_types[file_key]['filter'] file, file_ext = cls.__create_file_dialog(parent, title, directory, file_filter) if file and path_exists(file): if Path(file).suffix != f'.{file_key}': LOGGER.warning( f'User supposed to open: %s but opened: %s - returning None', f'.{file_key}', Path(file).suffix) return KnechtSettings.app['current_path'] = Path(file).parent.as_posix() if file_key in cls.valid_recent_file_types: KnechtSettings.add_recent_file(Path(file).as_posix(), file_key) return file
def restore(self) -> bool: """ Restore a user session asynchronous """ if not path_exists(self.session_zip): return False self.load_dir = CreateZip.create_tmp_dir() try: with ZipFile(self.session_zip, 'r') as zip_file: zip_file.extractall(self.load_dir) except Exception as e: LOGGER.error(e) return False # Restore original file save paths Settings.load(self.restore_files_storage, self.load_dir / self.files_list_name) # Restore in saved order for file in self.restore_files_storage.restore_file_order(self.load_dir): LOGGER.debug('Starting restore of document: %s @ %s', file.name, self.restore_files_storage.store.get(file.name)) self.load_queue.append(file) self._load_next() return True
def _await_rendered_image(self, img_path: Path): """ Wait until image was created """ start_time = time.time() while not path_exists(img_path): time.sleep(1) self.display_remaining_time() if self.abort_rendering: return if self._is_timed_out(start_time, self.render_timeout): break # Leave some time for DG to write the image time.sleep(3) # Verify a valid image file was created self.status.emit(_('Prüfe Bilddaten...')) self.btn_text.emit(_('Prüfe Bilddaten...')) self.verify_rendered_image(img_path) # Image created self.status.emit(_('Rendering erzeugt.')) self.btn_text.emit(_('Rendering erzeugt.')) time.sleep(0.5) # Wait 5 seconds for DeltaGen to recover for count in range(5, 0, -1): msg = _('Erzeuge nächstes Bild in {}...').format(str(count)) self.status.emit(msg + '\n') self.btn_text.emit(msg) time.sleep(1)
def read_image(self) -> bool: if path_exists(self.file): self.file_is_valid = True else: return False # Get image meta data with OpenImageIO try: img_meta = OpenImageUtil.read_img_metadata(self.file) except Exception as e: LOGGER.error(e) return False # Read through image info dict for required camera tags for k, v in img_meta.items(): for tag in self.rtt_camera_tags: if k.startswith(tag): self.camera_info[k] = v if not img_meta or not self.camera_info: return False else: # Test if all required camera command keys are inside camera info if self.camera_info.keys().isdisjoint(self.rtt_camera_cmds.keys()): return False self.info_is_valid = True # Convert Camera Orientation self._convert_orientation() 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 verify_paths(self): for p in (self.pos_path.path, self.xlsx_path.path): if p is None or not path_exists(p) or not p.is_file(): break else: return True return False
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)
def open_desktop_directory(self, directory: Path): """ Open directory with desktop explorer """ if path_exists(directory): q = QtCore.QUrl.fromLocalFile(directory.as_posix()) QDesktopServices.openUrl(q) else: self.ovr.display( _('Verzeichnis existiert nicht.<br>{}<br>').format( directory.as_posix()), 5000)
def convert_directory(self, img_dir: Path, output_dir: Path = Path('.'), output_format: str = '.png', move_converted: bool = False) -> bool: if not path_exists(img_dir) or not path_exists(output_dir): return False img_list = list() for file in img_dir.glob('*.*'): if file.suffix.casefold() in self.supported_image_types: img_list.append(file) if not img_list: return False self._start_img_thread(img_list, output_dir, output_format, move_converted) return True
def __init__(self, version, logging_queue): LOGGER.info('Sys argv: %s', sys.argv) super(KnechtApp, self).__init__(sys.argv) splash = show_splash_screen_movie(self) self.version = version self.logging_queue = logging_queue # History widget will set active Undo Stack on view change self.undo_grp = QtWidgets.QUndoGroup(self) # -- Main Window -- self.ui = KnechtWindow(self) self.ui.closeEvent = self.ui_close_event load_style(self) # -- Init DeltaGen thread -- self.send_dg = SendToDeltaGen(self.ui) # -- Init Rendering Controller spawning rendering threads -- self.render_dg = KnechtRender(self.ui) # -- Exception error box -- self.error_message_box = GenericErrorBox(self.ui) # Prepare exception handling KnechtExceptionHook.app = self KnechtExceptionHook.setup_signal_destination(self.report_exception) # -- Show main window -- self.ui.show() self.ready_to_quit = False self.aboutToQuit.connect(self.about_to_quit) splash.finish(self.ui) # Applying the style before showing the main window will not update # the menu font sizes self.setFont(FontRsc.regular) self.session_handler = None self.file_queue = list() if len(sys.argv) > 1: for a in sys.argv: if path_exists(a): self.file_queue.append(Path(a)) QTimer.singleShot(250, self._open_file_deferred) # Restore SessionData QTimer.singleShot(50, self.init_session)
def _get_current_path(d) -> Path: # Current settings path __c = Path(KnechtSettings.app['current_path']) # Fallback path USERPROFILE path or current directory '.' __fallback = Path(os.getenv('USERPROFILE', '.')) if not d or not path_exists(d): if KnechtSettings.app['current_path'] not in [ '', '.' ] and path_exists(__c): # Set to settings current_path and continue with file vs. dir check d = __c else: return __fallback if Path(d).is_file(): if path_exists(Path(d).parent): # Remove file and return directory return Path(d).parent else: return __fallback return Path(d)
def _get_plmxml_item(self, variants: KnechtVariantList) -> Optional[Path]: if variants.plm_xml_path: return Path(variants.plm_xml_path) index, src_model = self.view.editor.get_current_selection() current_item = src_model.get_item(index) if current_item.userType != Kg.plmxml_item: return else: plmxml_file = Path(current_item.data(Kg.VALUE)) if not path_exists(plmxml_file): return return plmxml_file
def __init__(self, ui, file: Union[Path, str] = None): """ Wizard assisting the user to create presets from Vplus + FaKom data :param modules.gui.main_ui.KnechtWindow ui: Main Window """ super(PresetWizard, self).__init__(parent=ui) self.ui = ui self.setWindowTitle(self.title) self.setWizardStyle(QWizard.ModernStyle) self._asked_for_close = False self.session = WizardSession(self) self.setButtonText(QWizard.BackButton, _('Zurück')) self.setButtonText(QWizard.NextButton, _('Weiter')) self.setButtonText(QWizard.FinishButton, _('Abschließen')) self.setButtonText(QWizard.CancelButton, _('Abbrechen')) self.automagic_clipboard = TreeClipboard() # --- Session Management --- session_btn = QPushButton(self) session_btn.setMinimumWidth(150) session_btn.setText(_('Sitzung')) session_btn.setMenu(WizardSessionMenu(self)) self.setButton(self.CustomButton1, session_btn) self.setOption(self.HaveCustomButton1, True) # --- Navigation Menu --- nav_btn = QPushButton(self) nav_btn.setMinimumWidth(150) self.nav_menu = WizardNavMenu(self, nav_btn) self.setButton(self.CustomButton2, nav_btn) self.setOption(self.HaveCustomButton2, True) self.page_welcome = WelcomeWizardPage(self) self.page_import = ImportWizardPage(self) self.page_fakom = FakomWizardPage(self) self.page_placeholder = PlaceholderPage(self) self.page_result = ResultWizardPage(self) self.addPage(self.page_welcome) self.addPage(self.page_import) self.addPage(self.page_fakom) self.addPage(self.page_placeholder) # Load session file if provided if file and path_exists(file): self.open_session_file(Path(file).as_posix())
def open_existing_directory( cls, parent=None, directory: Union[Path, str] = None, ) -> Union[str, None]: # Update path directory = cls._get_current_path(directory) title = cls.file_types['dir']['title'] directory = cls.__create_dir_dialog(parent, title, directory) if directory and path_exists(directory): KnechtSettings.app['current_path'] = Path(directory).as_posix() return directory
def excel_load_thread(signals: ThreadSignals, file: Path, pos_file: Path=None): """ The thread that loads the excel file """ LOGGER.debug('Excel file reader thread started: %s', file.name) signals.progress_msg.emit(_('Excel Datei wird gelesen...')) xl = ExcelReader() fakom_data, knecht_data = FakomData(), KnData() fakom_result, xl_result = True, False # -- Read Fakom data if pos file provided -- if pos_file and path_exists(pos_file): try: fakom_data = FakomReader.read_pos_file(pos_file) if fakom_data.empty(): xl.errors.append(_('POS Xml enthält keine bekannten Farbkombinationsmuster.')) fakom_result = False except Exception as e: LOGGER.error(e) xl.errors.append(_('Konnte POS Xml Daten nicht lesen oder verarbeiten.')) fakom_result = False # -- Read Excel file -- if fakom_result: try: # --- Create data from excel file --- xl_result = xl.read_file(file) signals.progress_msg.emit(_('Daten werden konvertiert...')) # --- Convert excel data to knecht data --- converter = ExcelDataToKnechtData(xl.data) knecht_data = converter.convert() knecht_data.fakom = fakom_data except Exception as e: LOGGER.error(e) xl_result = False # Transmit resulting data or report error if xl_result and fakom_result: signals.progress_msg.emit(_('Daten übertragen...')) LOGGER.debug('Excel read succeded. Converting ExcelData to KnData.') signals.finished.emit(knecht_data) else: LOGGER.debug('Excel read failed: %s', xl.errors) signals.error.emit(xl.errors)
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 drop_event(self, e: QDropEvent): mime: QMimeData = e.mimeData() src = e.source() # -- File drop -- if mime.hasUrls(): destination_index = self.view.indexAt(e.pos()) for url in mime.urls(): local_path = Path(url.toLocalFile()) if not path_exists(local_path): continue self.file_drop(local_path, destination_index) e.accept() return # --- Internal View Drops --- if not isinstance(src, self.view.__class__): e.ignore() return e.setDropAction(Qt.MoveAction) if src is not self.view: e.setDropAction(Qt.CopyAction) if e.keyboardModifiers() == Qt.ShiftModifier: e.setDropAction(Qt.CopyAction) # -- Copy drop -- if e.dropAction() is Qt.CopyAction: destination_index = self.view.indexAt(e.pos()) self.copy_drop(src, destination_index) e.accept() # -- Drag move -- if e.dropAction() is Qt.MoveAction: destination_index = self.view.indexAt(e.pos()) self.move_drop(destination_index) # Ignore default view behaviour e.ignore()
def open(self, file: Union[Path, str]): file = Path(file) if not path_exists(file): LOGGER.info( 'The provided Xml path does not seem to exist or is un-accessible.' ) self.load_aborted.emit( _('Kann nicht auf die gewählte Datei zugreifen.'), file) return self.load_start_time = time.time() self.xml_worker = XmlWorkThread(file, self.xml_worker_queue, open_xml=True) self.xml_worker.xml_items_loaded.connect(self.load_thread_finished) self.xml_worker.start()
def create_directory(self, render_dir): render_dir = Path(render_dir) / self.unique_out_dir_name if not path_exists(render_dir): try: render_dir.mkdir(parents=True) except Exception as e: LOGGER.critical( 'Could not create rendering directory! Rendering to executable path.\n%s', e) render_dir = Path('.') / self.unique_out_dir_name try: render_dir.mkdir(parents=True) except Exception as e: LOGGER.critical( 'Could not create fallback directory! ' 'Rendering will not be able to write images.\n%s', e) return render_dir
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()
def doc_action(self, action: QAction): file, tab_page = Path('.'), None if self.context_tab_index >= 0: tab_page = self.ui.view_mgr.tab.widget(self.context_tab_index) file = self.ui.view_mgr.file_mgr.get_file_from_widget( tab_page) or Path('.') if not path_exists(file) or not file.is_file(): self.ui.msg( _('Kein gültiger Pfad für das Dokument gesetzt. Das Dokument muss zuerst gespeichert werden.' ), 5000) return if action == self.copy_action: self.ui.app.clipboard().setText(file.as_posix()) self.ui.msg( _('Dokumenten Pfad wurde in die Zwischenablage kopiert.<br/><i>{}<i>' ).format(file.as_posix())) elif action == self.open_action: q = QUrl.fromLocalFile(file.parent.as_posix()) QDesktopServices.openUrl(q)
def manager_delete_render_file(self, item): job = self.get_job_from_item_index(item) if not job: return if job.status < 4: self.ovr.display( '<b>Nachricht von Kapitän Offensichtlich:</b><br>' '<i>Rendering Szenen laufender Jobs können nicht gelöscht werden!</i>', 7500) return # Path to scene file eg. C:/some_dir/some_file.csb scene_file = Path(job.remote_file) # Create render file name some_file_render.mb render_file = Path(scene_file.stem + '_render.mb') # Create the path to the render file C:/some_dir/some_file_render.mb render_file = scene_file.with_name(render_file.name) if path_exists(render_file): # Delete the file try: render_file.unlink() except Exception as e: LOGGER.error('Error deleting render file %s', e) self.ovr.display( _('Fehler: Datei {} konnte nicht entfernt werden.<br>{}<br>' ).format(render_file.name, e), 7500) return else: self.ovr.display( _('Datei {} <b>existiert nicht mehr oder kann nicht gefunden werden.</b><br>' ).format(render_file.name), 7500) return self.ovr.display( _('Datei {} wurde entfernt.').format(render_file.name), 7500)
def open_desktop_directory(self): """ Open directory with desktop explorer """ if path_exists(self.plmxml.file.parent): q = QUrl.fromLocalFile(self.plmxml.file.parent.as_posix()) QDesktopServices.openUrl(q)
def open_settings_dir(self): settings_dir = Path(get_settings_dir()) if path_exists(settings_dir): q = QUrl.fromLocalFile(settings_dir.as_posix()) QDesktopServices.openUrl(q)
def _is_update_ready(self) -> bool: if path_exists(self.installer_file): if self.remote_version > KnechtSettings.app['version']: return True return False
def start_app(app_path: Path): if path_exists(app_path) and app_path.is_file(): Popen(app_path.as_posix())
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)