def processArguments(arguments): parser = QCommandLineParser() parser.addHelpOption() parser.addVersionOption() delayOption = QCommandLineOption(["d", "delay"], "Take a screenshot after NUM seconds", "NUM") fullscreenOption = QCommandLineOption(["f", "fullscreen"], "Take a screenshot of the whole screen") topWindowOption = QCommandLineOption(["w", "top-window"], "Take a screenshot of the most top window") savePathOption = QCommandLineOption(["s", "save-path"], "Specify a path to save the screenshot", "PATH") startFromDesktopOption = QCommandLineOption(["i", "icon"], "Indicate that this program's started by clicking desktop file.") parser.addOption(delayOption) parser.addOption(fullscreenOption) parser.addOption(topWindowOption) parser.addOption(savePathOption) parser.addOption(startFromDesktopOption) parser.process(arguments) delay = int(parser.value(delayOption) or 0) fullscreen = bool(parser.isSet(fullscreenOption) or False) topWindow = bool(parser.isSet(topWindowOption) or False) savePath = str(parser.value(savePathOption) or "") startFromDesktop = bool(parser.isSet(startFromDesktopOption) or False) return {"delay": delay, "fullscreen": fullscreen, "topWindow": topWindow, "savePath": savePath, "startFromDesktop": startFromDesktop}
def main(): global app # register representation factories baseRepresentationFactories.registerAllFactories() representationFactories.registerAllFactories() # initialize the app app = Application(sys.argv) app.setOrganizationName("TruFont") app.setOrganizationDomain("trufont.github.io") app.setApplicationName("TruFont") app.setApplicationVersion(__version__) app.setWindowIcon(QIcon(":app.png")) app.setAttribute(Qt.AA_UseHighDpiPixmaps, True) # Install stream redirection app.outputWindow = OutputWindow() # Exception handling sys.excepthook = exceptionCallback # Qt's translation for itself. May not be installed. qtTranslator = QTranslator() qtTranslator.load("qt_" + QLocale.system().name(), QLibraryInfo.location(QLibraryInfo.TranslationsPath)) app.installTranslator(qtTranslator) appTranslator = QTranslator() appTranslator.load("trufont_" + QLocale.system().name(), os.path.dirname(os.path.realpath(__file__)) + "/resources") app.installTranslator(appTranslator) # parse options and open fonts parser = QCommandLineParser() parser.setApplicationDescription(QApplication.translate( "Command-line parser", "The TruFont font editor.")) parser.addHelpOption() parser.addVersionOption() parser.addPositionalArgument(QApplication.translate( "Command-line parser", "files"), QApplication.translate( "Command-line parser", "The UFO files to open.")) parser.process(app) args = parser.positionalArguments() if not args: fontPath = None # maybe load recent file settings = QSettings() loadRecentFile = settings.value("misc/loadRecentFile", False, bool) if loadRecentFile: recentFiles = settings.value("core/recentFiles", [], type=str) if len(recentFiles) and os.path.exists(recentFiles[0]): fontPath = recentFiles[0] app.openFile(fontPath) # otherwise, create a new file if fontPath is None: app.newFile() else: for fontPath in args: app.openFile(fontPath) sys.exit(app.exec_())
def main(): app = QCoreApplication(sys.argv) # Set some application details. app.setApplicationName("MyApp") app.setApplicationVersion("0.1.0") app.setOrganizationName("My Organization") app.setOrganizationDomain("www.my-organization.org") # Create a verbosity command line option. verbose_option = QCommandLineOption("verbose", "Verbose mode. Print out debug messages.") # Setup the commandline parser. command_parser = QCommandLineParser() command_parser.addHelpOption() command_parser.addVersionOption() # Add the commandline options. command_parser.addOption(verbose_option) # Process the command line. command_parser.process(app) # Set the basic logger mnessage format and verbosity level. logger = logging.getLogger() # This dictates how the messages are formatted. formatter = logging.Formatter(fmt=MESSAGE_FORMAT, style="{") # This handler sends everything to stdout. handler = logging.StreamHandler() handler.setFormatter(formatter) # Add the handler to the logger. logger.addHandler(handler) # Check if the verbosity flag is set and set the log level to debug if it is. if command_parser.isSet(verbose_option): logger.setLevel(logging.DEBUG) logger.debug("Setting loglevel to debug.") else: logger.setLevel(logging.ERROR) # Start the event loop. sys.exit(app.exec())
def main(): # register representation factories representationFactories.registerAllFactories() # initialize the app app = Application(sys.argv) app.setOrganizationName("TruFont") app.setOrganizationDomain("trufont.github.io") app.setApplicationName("TruFont") app.setApplicationVersion(__version__) app.setWindowIcon(QIcon(":/resources/app.png")) settings = QSettings() glyphListPath = settings.value("settings/glyphListPath", "", type=str) if glyphListPath and os.path.exists(glyphListPath): from defconQt.util import glyphList try: glyphList = glyphList.parseGlyphList(glyphListPath) except Exception as e: print(e) else: app.GL2UV = glyphList # parse options and open fonts parser = QCommandLineParser() parser.setApplicationDescription("The TruFont font editor.") parser.addHelpOption() parser.addVersionOption() parser.addPositionalArgument("files", "The UFO files to open.") parser.process(app) args = parser.positionalArguments() if not len(args): fontPath = None # maybe load recent file settings = QSettings() loadRecentFile = settings.value("misc/loadRecentFile", False, bool) if loadRecentFile: recentFiles = settings.value("core/recentFiles", [], type=str) if len(recentFiles): fontPath = recentFiles[0] app.openFile(fontPath) # otherwise, create a new file if fontPath is None: app.newFile() else: for fontPath in args: app.openFile(fontPath) sys.exit(app.exec_())
def main(): multiprocessing.set_start_method('spawn') if markups.__version_tuple__ < (2, ): sys.exit('Error: ReText needs PyMarkups 2.0 or newer to run.') # If we're running on Windows without a console, then discard stdout # and save stderr to a file to facilitate debugging in case of crashes. if sys.executable.endswith('pythonw.exe'): sys.stdout = open(devnull, 'w') sys.stderr = open('stderr.log', 'w') try: # See https://github.com/retext-project/retext/issues/399 # and https://launchpad.net/bugs/941826 ctypes.CDLL('libGL.so.1', ctypes.RTLD_GLOBAL) except OSError: pass # Needed for Qt WebEngine on Windows QApplication.setAttribute(Qt.ApplicationAttribute.AA_ShareOpenGLContexts) QApplication.setAttribute(Qt.ApplicationAttribute.AA_UseHighDpiPixmaps) app = QApplication(sys.argv) app.setOrganizationName("ReText project") app.setApplicationName("ReText") app.setApplicationDisplayName("ReText") app.setApplicationVersion(app_version) app.setOrganizationDomain('mitya57.me') app.setDesktopFileName('me.mitya57.ReText.desktop') QNetworkProxyFactory.setUseSystemConfiguration(True) initializeDataDirs() RtTranslator = QTranslator() for path in datadirs: if RtTranslator.load('retext_' + globalSettings.uiLanguage, join(path, 'locale')): break QtTranslator = QTranslator() QtTranslator.load("qtbase_" + globalSettings.uiLanguage, QLibraryInfo.location(QLibraryInfo.LibraryLocation.TranslationsPath)) app.installTranslator(RtTranslator) app.installTranslator(QtTranslator) parser = QCommandLineParser() parser.addHelpOption() parser.addVersionOption() previewOption = QCommandLineOption('preview', QApplication.translate('main', 'Open the files in preview mode')) newWindowOption = QCommandLineOption('new-window', QApplication.translate('main', 'Create a new window even if there is an existing one')) parser.addOption(previewOption) parser.addOption(newWindowOption) parser.addPositionalArgument('files', QApplication.translate('main', 'List of files to open'), '[files...]') parser.process(app) filesToOpen = parser.positionalArguments() print('Using configuration file:', settings.fileName()) if globalSettings.appStyleSheet: sheetfile = QFile(globalSettings.appStyleSheet) sheetfile.open(QIODevice.OpenModeFlag.ReadOnly) app.setStyleSheet(QTextStream(sheetfile).readAll()) sheetfile.close() window = ReTextWindow() openInExistingWindow = (globalSettings.openFilesInExistingWindow and not parser.isSet(newWindowOption)) connection = QDBusConnection.sessionBus() if connection.isConnected() and openInExistingWindow: connection.registerObject('/', window, QDBusConnection.RegisterOption.ExportAllSlots) serviceName = 'me.mitya57.ReText' if not connection.registerService(serviceName) and filesToOpen: print('Opening the file(s) in the existing window of ReText.') iface = QDBusInterface(serviceName, '/', '', connection) for fileName in filesToOpen: iface.call('openFileWrapper', fileName) qWidgetIface = QDBusInterface(serviceName, '/', 'org.qtproject.Qt.QWidget', connection) qWidgetIface.call('raise') sys.exit(0) window.show() # ReText can change directory when loading files, so we # need to have a list of canonical names before loading fileNames = list(map(canonicalize, filesToOpen)) readStdIn = False if globalSettings.openLastFilesOnStartup: window.restoreLastOpenedFiles() for fileName in fileNames: if QFile.exists(fileName): window.openFileWrapper(fileName) if parser.isSet(previewOption): window.actionPreview.setChecked(True) window.preview(True) elif fileName == '-': readStdIn = True inputData = '' if readStdIn and sys.stdin is not None: if sys.stdin.isatty(): print('Reading stdin, press ^D to end...') inputData = sys.stdin.read() if inputData or not window.tabWidget.count(): window.createNew(inputData) signal.signal(signal.SIGINT, lambda sig, frame: window.close()) sys.exit(app.exec())
def main(): global app # register representation factories baseRepresentationFactories.registerAllFactories() representationFactories.registerAllFactories() if hasattr(Qt, "AA_EnableHighDpiScaling"): QApplication.setAttribute(Qt.AA_EnableHighDpiScaling) # initialize the app app = Application(sys.argv) app.setOrganizationName("TruFont") app.setOrganizationDomain("trufont.github.io") app.setApplicationName("TruFont") app.setApplicationVersion(__version__) app.setWindowIcon(QIcon(":app.png")) app.setAttribute(Qt.AA_UseHighDpiPixmaps, True) app.setStyleSheet(platformSpecific.appStyleSheet()) # Install stream redirection app.outputWindow = OutputWindow() # Exception handling sys.excepthook = errorReports.exceptionCallback # Qt's translation for itself. May not be installed. qtTranslator = QTranslator() qtTranslator.load("qt_" + QLocale.system().name(), QLibraryInfo.location(QLibraryInfo.TranslationsPath)) app.installTranslator(qtTranslator) appTranslator = QTranslator() appTranslator.load("trufont_" + QLocale.system().name(), os.path.dirname(os.path.realpath(__file__)) + "/resources") app.installTranslator(appTranslator) # parse options and open fonts parser = QCommandLineParser() parser.setApplicationDescription(QApplication.translate( "Command-line parser", "The TruFont font editor.")) parser.addHelpOption() parser.addVersionOption() parser.addPositionalArgument(QApplication.translate( "Command-line parser", "files"), QApplication.translate( "Command-line parser", "The UFO files to open.")) parser.process(app) # bootstrap extensions folder = app.getExtensionsDirectory() for file in os.listdir(folder): if not file.rstrip("\\/ ").endswith(".tfExt"): continue path = os.path.join(folder, file) try: extension = TExtension(path) if extension.launchAtStartup: extension.run() except Exception as e: msg = QApplication.translate( "Extensions", "The extension at {0} could not be run.".format( path)) errorReports.showWarningException(e, msg) continue app.registerExtension(extension) # load menu if platformSpecific.useGlobalMenuBar(): menuBar = app.fetchMenuBar() # noqa app.setQuitOnLastWindowClosed(False) # process files args = parser.positionalArguments() if not args: fontPath = None # maybe load recent file settings = QSettings() loadRecentFile = settings.value("misc/loadRecentFile", False, bool) if loadRecentFile: recentFiles = settings.value("core/recentFiles", [], type=str) if len(recentFiles) and os.path.exists(recentFiles[0]): fontPath = recentFiles[0] app.openFile(fontPath) # otherwise, create a new file if fontPath is None: app.newFile() else: for fontPath in args: app.openFile(fontPath) sys.exit(app.exec_())
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.edl, self.video = '', '' self.parse_cmdline() self.init_logger() self.init_cutter() self.setWindowTitle('%s' % qApp.applicationName()) self.setContentsMargins(0, 0, 0, 0) self.statusBar().showMessage('Ready') statuslogo = QLabel(pixmap=QPixmap(':/images/vidcutter-emboss.png'), objectName='logowidget') self.statusBar().addPermanentWidget(statuslogo) self.statusBar().setStyleSheet('border:none;') self.setAcceptDrops(True) self.setMinimumSize(900, 640) self.show() try: if len(self.video): self.cutter.loadMedia(self.video) if len(self.edl): self.cutter.openEDL(edlfile=self.edl) except (FileNotFoundError, PermissionError) as e: QMessageBox.critical(self, 'Error loading file', sys.exc_info()[0]) logging.exception('Error loading file') qApp.restoreOverrideCursor() self.cutter.startNew() if not self.cutter.ffmpeg_check(): self.close() sys.exit(1) def init_logger(self) -> None: try: log_path = QStandardPaths.writableLocation( QStandardPaths.AppConfigLocation).lower() except AttributeError: if sys.platform == 'win32': log_path = os.path.join(QDir.homePath(), 'AppData', 'Local', qApp.applicationName().lower()) elif sys.platform == 'darwin': log_path = os.path.join(QDir.homePath(), 'Library', 'Preferences', qApp.applicationName()).lower() else: log_path = os.path.join(QDir.homePath(), '.config', qApp.applicationName()).lower() os.makedirs(log_path, exist_ok=True) handlers = [ logging.handlers.RotatingFileHandler(os.path.join( log_path, '%s.log' % qApp.applicationName().lower()), maxBytes=1000000, backupCount=1) ] if os.getenv('DEBUG', False): handlers.append(logging.StreamHandler()) logging.basicConfig( handlers=handlers, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M', level=logging.INFO) logging.captureWarnings(capture=True) sys.excepthook = self.log_uncaught_exceptions @staticmethod def log_uncaught_exceptions(cls, exc, tb) -> None: logging.critical(''.join(traceback.format_tb(tb))) logging.critical('{0}: {1}'.format(cls, exc)) def parse_cmdline(self) -> None: self.parser = QCommandLineParser() self.parser.setApplicationDescription( 'The simply FAST & ACCURATE video cutter & joiner') self.parser.addPositionalArgument('video', 'Preloads the video file in app.', '[video]') self.edl_option = QCommandLineOption( 'edl', 'Preloads clip index from a previously saved EDL file.\n' + 'NOTE: You must also set the video argument for this to work.', 'edl file') self.debug_option = QCommandLineOption( ['d', 'debug'], 'Output all info, warnings and errors to the console. ' + 'This will basically output what is being logged to file to the ' + 'console stdout. Mainly useful for debugging problems with your ' + 'system video and/or audio stack and codec configuration.') self.parser.addOption(self.edl_option) self.parser.addOption(self.debug_option) self.parser.addVersionOption() self.parser.addHelpOption() self.parser.process(qApp) self.args = self.parser.positionalArguments() if self.parser.value('edl').strip() and not os.path.exists( self.parser.value('edl')): print('\n ERROR: EDL file not found.\n', file=sys.stderr) self.close() sys.exit(1) if self.parser.value('edl').strip() and len(self.args) == 0: print('\n ERROR: Video file argument is missing.\n', file=sys.stderr) self.close() sys.exit(1) if self.parser.value('edl').strip(): self.edl = self.parser.value('edl') if self.parser.isSet(self.debug_option): os.environ['DEBUG'] = '1' if len(self.args) > 0 and not os.path.exists(self.args[0]): print('\n ERROR: Video file not found.\n', file=sys.stderr) self.close() sys.exit(1) if len(self.args) > 0: self.video = self.args[0] def init_cutter(self) -> None: self.cutter = VideoCutter(self) qApp.setWindowIcon(self.cutter.appIcon) self.setCentralWidget(self.cutter) @staticmethod def get_bitness() -> int: from struct import calcsize return calcsize('P') * 8 def restart(self) -> None: self.cutter.deleteLater() self.init_cutter() @staticmethod def get_path(path: str = None, override: bool = False) -> str: if override: if getattr(sys, 'frozen', False): return os.path.join(sys._MEIPASS, path) return os.path.join(QFileInfo(__file__).absolutePath(), path) return ':%s' % path @staticmethod def load_stylesheet(qssfile: str) -> None: if QFileInfo(qssfile).exists(): qss = QFile(qssfile) qss.open(QFile.ReadOnly | QFile.Text) qApp.setStyleSheet(QTextStream(qss).readAll()) @staticmethod def get_version(filename: str = '__init__.py') -> str: with open(MainWindow.get_path(filename, override=True), 'r', encoding='utf-8') as initfile: for line in initfile.readlines(): m = re.match('__version__ *= *[\'](.*)[\']', line) if m: return m.group(1) def contextMenuEvent(self, event: QContextMenuEvent) -> None: if event.reason() == QContextMenuEvent.Mouse: self.cutter.appMenu.exec_(event.globalPos()) event.accept() super(MainWindow, self).contextMenuEvent(event) def mousePressEvent(self, event: QMouseEvent): if event.button() == Qt.LeftButton: self.cutter.cliplist.clearSelection() def dragEnterEvent(self, event: QDragEnterEvent) -> None: if event.mimeData().hasUrls(): event.accept() def dropEvent(self, event: QDropEvent) -> None: filename = event.mimeData().urls()[0].toLocalFile() self.cutter.loadMedia(filename) event.accept() def closeEvent(self, event: QCloseEvent) -> None: if hasattr(self, 'cutter'): if hasattr(self.cutter, 'mediaPlayer'): self.cutter.mediaPlayer.terminate() qApp.quit()
def main(): global app # register representation factories baseRepresentationFactories.registerAllFactories() representationFactories.registerAllFactories() if hasattr(Qt, "AA_EnableHighDpiScaling"): QApplication.setAttribute(Qt.AA_EnableHighDpiScaling) platformSpecific.setAppName() # initialize the app app = Application(sys.argv) app.setOrganizationName("TruFont") app.setOrganizationDomain("trufont.github.io") app.setApplicationName("TruFont") app.setApplicationVersion(__version__) app.setWindowIcon(QIcon(":app.png")) app.setAttribute(Qt.AA_UseHighDpiPixmaps, True) appFont = platformSpecific.UIFontOverride() if appFont is not None: app.setFont(appFont) app.setStyleSheet(platformSpecific.appStyleSheet()) # Install stream redirection app.outputWindow = OutputWindow() # Exception handling sys.excepthook = errorReports.exceptionCallback # Qt's translation for itself. May not be installed. qtTranslator = QTranslator() qtTranslator.load( "qt_" + QLocale.system().name(), QLibraryInfo.location(QLibraryInfo.TranslationsPath), ) app.installTranslator(qtTranslator) appTranslator = QTranslator() appTranslator.load( "trufont_" + QLocale.system().name(), os.path.dirname(os.path.realpath(__file__)) + "/resources", ) app.installTranslator(appTranslator) # parse options and open fonts parser = QCommandLineParser() parser.setApplicationDescription( QApplication.translate("Command-line parser", "The TruFont font editor.") ) parser.addHelpOption() parser.addVersionOption() parser.addPositionalArgument( QApplication.translate("Command-line parser", "files"), QApplication.translate("Command-line parser", "The UFO files to open."), ) parser.process(app) # load menu if platformSpecific.useGlobalMenuBar(): app.fetchMenuBar() app.setQuitOnLastWindowClosed(False) # bootstrap extensions folder = app.getExtensionsDirectory() for file in os.listdir(folder): if not file.rstrip("\\/ ").endswith(".tfExt"): continue path = os.path.join(folder, file) try: extension = TExtension(path) if extension.launchAtStartup: extension.run() except Exception as e: msg = QApplication.translate( "Extensions", f"The extension at {path} could not be run." ) errorReports.showWarningException(e, msg) continue app.registerExtension(extension) # process files args = parser.positionalArguments() if not args: # maybe load recent file loadRecentFile = settings.loadRecentFile() if loadRecentFile: recentFiles = settings.recentFiles() if len(recentFiles) and os.path.exists(recentFiles[0]): app.openFile(recentFiles[0]) else: for fontPath in args: app.openFile(fontPath) # if we did not open a font, spawn new font or go headless if not app.allFonts(): if platformSpecific.shouldSpawnDocument(): app.newFile() else: # HACK: on OSX we may want to trigger native QMenuBar display # without opening any window. Since Qt infers new menu bar on # focus change, fire the signal. app.focusWindowChanged.emit(None) sys.exit(app.exec_())
def runmain(): import sys app = QApplication(sys.argv) cmdParser = QCommandLineParser() cmdParser.setApplicationDescription( "Room file merger utility script for Basement Renovator. Takes a config file and feeds it to the cli roommerger script" ) cmdParser.addHelpOption() cmdParser.addPositionalArgument( "configFile", """json config file to grab configuration from; sets current working directory to its directory. Format: { files: [ { outputFile: path to file to output, paths: [ path to file/folder to replace, ... ], skipSTB: optional, true to skip generating the stb, noRecomputeIds: optional, true to skip recompute room ids, startingId: starting room id to recompute from }... ] } """, ) fileEditedOpt = QCommandLineOption( "fileEdited", "optional file to limit which rooms get merged from the config", "file", ) cmdParser.addOption(fileEditedOpt) cmdParser.process(app) configArg = cmdParser.positionalArguments()[0] configPath = Path(configArg).absolute().resolve() if not configArg or not configPath.is_file(): print("Invalid config path!") return fileEditedArg = cmdParser.value(fileEditedOpt) fileEditedPath = None if fileEditedArg: fileEditedPath = Path(fileEditedArg).absolute().resolve() if not fileEditedPath.is_file(): print("Invalid edited file path!") return scriptPath = Path(__file__ + "/../roommerger.py").absolute().resolve() with open(configPath) as configFile: config = json.load(configFile) mergeRooms( config["files"], str(scriptPath), configPath.parent, fileEdited=fileEditedPath, ) print("Success! Merged all.")
def runmain(): import sys app = QApplication(sys.argv) cmdParser = QCommandLineParser() cmdParser.setApplicationDescription( "Room file merger utility script for Basement Renovator. Takes a set of file paths" ) cmdParser.addHelpOption() cmdParser.addPositionalArgument("file", "xml files to merge") outputFileOpt = QCommandLineOption("output", "output filename, must be xml", "file") cmdParser.addOption(outputFileOpt) stbOpt = QCommandLineOption( "stb", "whether to save an stb version of the file next to it") cmdParser.addOption(stbOpt) noRecompIdsOpt = QCommandLineOption( "noRecomputeIds", "turn off recomputing room ids; useful for special room merging", ) cmdParser.addOption(noRecompIdsOpt) idOpt = QCommandLineOption( "startingId", "optional starting id to use when recomputing room ids", "id") cmdParser.addOption(idOpt) skipOpt = QCommandLineOption( "roommerge", "placeholder argument used to prevent recursive execution") cmdParser.addOption(skipOpt) cmdParser.process(app) if cmdParser.isSet(skipOpt): print("Recursive execution from save hook, skipping") return paths = cmdParser.positionalArguments() if not paths: print("Must specify at least one file to merge!") return outputFileArg = cmdParser.value(outputFileOpt) outputFilePath = Path(outputFileArg).absolute().resolve() if not outputFileArg or outputFilePath.suffix != ".xml": print("Must specify xml output file!") return lastModified = None if outputFilePath.exists(): lastModified = outputFilePath.stat().st_mtime idArg = cmdParser.value(idOpt) noRecompIdsArg = cmdParser.isSet(noRecompIdsOpt) stbArg = cmdParser.isSet(stbOpt) mergeRoomFile = None i = -1 while (i + 1) < len(paths): i += 1 file = paths[i] path = Path(file) if path.is_dir(): files = list(filter(lambda f: f.suffix == ".xml", path.iterdir())) print("Adding xml files to queue from: ", path) del paths[i] i -= 1 paths.extend(files) paths = list(filter(lambda f: Path(f).exists(), paths)) if lastModified: anyModified = (next( (file for file in paths if file.stat().st_mtime > lastModified), None) is not None) if not anyModified: print("----") print( "Skipping since no xmls in folder have been modified since last update" ) return for file in paths: print("----") print("Path:", file) path = Path(file) print("Merging file...") if path.suffix != ".xml": print("Must be xml! Skipping!") continue roomFile = cvt.xmlToCommon(path) if not mergeRoomFile: mergeRoomFile = roomFile else: mergeRoomFile.rooms.extend(roomFile.rooms) print("----") if not mergeRoomFile: print("No rooms files to merge") return if not noRecompIdsArg: recomputeRoomIDs(mergeRoomFile.rooms, idArg and int(idArg)) cvt.commonToXML(outputFilePath, mergeRoomFile.rooms, file=mergeRoomFile) if stbArg: cvt.commonToSTBAB(outputFileArg.replace(".xml", ".stb"), mergeRoomFile.rooms) settings = QSettings(__file__ + "/../../settings.ini", QSettings.IniFormat) saveHooks = settings.value("HooksSave") if saveHooks: fullPath = str(outputFilePath) for hook in saveHooks: hook = Path(hook).absolute().resolve() try: subprocess.run( [str(hook), fullPath, "--save", "--roommerge"], cwd=hook.parent, timeout=60, ) except Exception as e: print("Save hook failed! Reason:", e) print("Success! Merged to", outputFileArg)
class MainWindow(QMainWindow): EXIT_CODE_REBOOT = 666 def __init__(self): super(MainWindow, self).__init__() self.video, self.devmode = '', False self.parse_cmdline() self.init_logger() self.init_settings() self.init_scale() self.init_cutter() self.setWindowTitle('%s' % qApp.applicationName()) self.setContentsMargins(0, 0, 0, 0) self.statusBar().showMessage('Ready') self.statusBar().setStyleSheet('border: none; padding: 0; margin: 0;') self.setAcceptDrops(True) self.show() self.console.setGeometry(int(self.x() - (self.width() / 2)), self.y() + int(self.height() / 3), 750, 300) try: if len(self.video): if QFileInfo(self.video).suffix() == 'vcp': self.cutter.openProject(project_file=self.video) else: self.cutter.loadMedia(self.video) except (FileNotFoundError, PermissionError) as e: QMessageBox.critical(self, 'Error loading file', sys.exc_info()[0]) logging.exception('Error loading file') qApp.restoreOverrideCursor() self.restart() if not self.cutter.ffmpeg_check(): qApp.exit(1) def init_scale(self) -> None: screen_size = qApp.desktop().availableGeometry(-1) self.scale = 'LOW' if screen_size.width() <= 1024 else 'NORMAL' self.setMinimumSize(self.get_size(self.scale)) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) @staticmethod def get_size(mode: str = 'NORMAL') -> QSize: modes = { 'LOW': QSize(800, 425), 'NORMAL': QSize(915, 680), 'HIGH': QSize(1850, 1300) } return modes[mode] def init_logger(self) -> None: try: log_path = QStandardPaths.writableLocation(QStandardPaths.AppConfigLocation).lower() except AttributeError: if sys.platform == 'win32': log_path = os.path.join(QDir.homePath(), 'AppData', 'Local', qApp.applicationName().lower()) elif sys.platform == 'darwin': log_path = os.path.join(QDir.homePath(), 'Library', 'Preferences', qApp.applicationName()).lower() else: log_path = os.path.join(QDir.homePath(), '.config', qApp.applicationName()).lower() os.makedirs(log_path, exist_ok=True) self.console = ConsoleWidget(self) self.consoleLogger = ConsoleHandler(self.console) handlers = [logging.handlers.RotatingFileHandler(os.path.join(log_path, '%s.log' % qApp.applicationName().lower()), maxBytes=1000000, backupCount=1), self.consoleLogger] if self.parser.isSet(self.debug_option): handlers.append(logging.StreamHandler()) logging.basicConfig(handlers=handlers, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M', level=logging.INFO) logging.captureWarnings(capture=True) sys.excepthook = self.log_uncaught_exceptions def init_settings(self) -> None: if sys.platform == 'darwin': QSettings.setDefaultFormat(QSettings.IniFormat) self.settings = QSettings(self) else: try: settings_path = QStandardPaths.writableLocation(QStandardPaths.AppConfigLocation).lower() except AttributeError: if sys.platform == 'win32': settings_path = os.path.join(QDir.homePath(), 'AppData', 'Local', qApp.applicationName().lower()) elif sys.platform == 'darwin': settings_path = os.path.join(QDir.homePath(), 'Library', 'Preferences', qApp.applicationName()).lower() else: settings_path = os.path.join(QDir.homePath(), '.config', qApp.applicationName()).lower() os.makedirs(settings_path, exist_ok=True) settings_file = '%s.ini' % qApp.applicationName().lower() self.settings = QSettings(os.path.join(settings_path, settings_file), QSettings.IniFormat) if self.settings.value('geometry') is not None: self.restoreGeometry(self.settings.value('geometry')) if self.settings.value('windowState') is not None: self.restoreState(self.settings.value('windowState')) self.theme = self.settings.value('theme', 'light', type=str) self.startupvol = self.settings.value('volume', 100, type=int) @staticmethod def log_uncaught_exceptions(cls, exc, tb) -> None: logging.critical(''.join(traceback.format_tb(tb))) logging.critical('{0}: {1}'.format(cls, exc)) def parse_cmdline(self) -> None: self.parser = QCommandLineParser() self.parser.setApplicationDescription('\nVidCutter - the simplest + fastest video cutter & joiner') self.parser.addPositionalArgument('video', 'Preload video file', '[video]') self.parser.addPositionalArgument('project', 'Open VidCutter project file (.vcp)', '[project]') self.debug_option = QCommandLineOption(['debug'], 'debug mode; verbose console output & logging. ' + 'This will basically output what is being logged to file to the ' + 'console stdout. Mainly useful for debugging problems with your ' + 'system video and/or audio stack and codec configuration.') self.dev_option = QCommandLineOption(['dev'], 'developer mode; disables the use of compiled resource files ' + 'so that all app resources & assets are accessed directly from the file ' + 'system allowing you to see UI changes immediately. this typically ' + 'relates to changes made to Qt stylesheets (.qss), layout/templates, ' + 'content includes and images. basically all assets defined in .qrc ' + 'files throughout the codebase.') self.parser.addOption(self.debug_option) self.parser.addOption(self.dev_option) self.parser.addVersionOption() self.parser.addHelpOption() self.parser.process(qApp) self.args = self.parser.positionalArguments() if self.parser.isSet(self.debug_option): os.environ['DEBUG'] = '1' if self.parser.isSet(self.dev_option): self.devmode = True if len(self.args) > 0: file_path = QFileInfo(self.args[0]).absoluteFilePath() if not os.path.exists(file_path): sys.stderr.write('\nERROR: File not found: %s\n' % file_path) self.close() sys.exit(1) self.video = file_path def init_cutter(self) -> None: self.cutter = VideoCutter(self) self.cutter.errorOccurred.connect(self.errorHandler) # qApp.setWindowIcon(QIcon(':/images/vidcutter.png')) qApp.setWindowIcon(QIcon.fromTheme(qApp.applicationName().lower(), QIcon(':/images/vidcutter.png'))) self.setCentralWidget(self.cutter) @staticmethod def get_bitness() -> int: from struct import calcsize return calcsize('P') * 8 @pyqtSlot() def reboot(self) -> None: self.save_settings() qApp.exit(MainWindow.EXIT_CODE_REBOOT) def save_settings(self) -> None: self.settings.setValue('lastFolder', self.cutter.lastFolder) self.settings.setValue('geometry', self.saveGeometry()) self.settings.setValue('windowState', self.saveState()) self.settings.sync() @staticmethod def get_path(path: str = None, override: bool = False) -> str: if override: if getattr(sys, 'frozen', False): return os.path.join(sys._MEIPASS, path) return os.path.join(QFileInfo(__file__).absolutePath(), path) return ':%s' % path @staticmethod def get_version(filename: str = '__init__.py') -> str: with open(MainWindow.get_path(filename, override=True), 'r', encoding='utf-8') as initfile: for line in initfile.readlines(): m = re.match('__version__ *= *[\'](.*)[\']', line) if m: return m.group(1) @pyqtSlot(str) def errorHandler(self, msg: str) -> None: QMessageBox.critical(self, 'An error occurred', msg, QMessageBox.Ok) logging.error(msg) def contextMenuEvent(self, event: QContextMenuEvent) -> None: if event.reason() == QContextMenuEvent.Mouse: self.cutter.appMenu.exec_(event.globalPos()) event.accept() super(MainWindow, self).contextMenuEvent(event) def mousePressEvent(self, event: QMouseEvent) -> None: if event.button() == Qt.LeftButton and self.cutter.mediaAvailable: self.cutter.cliplist.clearSelection() self.cutter.timeCounter.clearFocus() self.cutter.frameCounter.clearFocus() def dragEnterEvent(self, event: QDragEnterEvent) -> None: if event.mimeData().hasUrls(): event.accept() def dropEvent(self, event: QDropEvent) -> None: filename = event.mimeData().urls()[0].toLocalFile() self.cutter.loadMedia(filename) event.accept() def resizeEvent(self, event: QResizeEvent) -> None: try: if self.cutter.mediaAvailable and self.cutter.thumbnailsButton.isChecked(): self.cutter.seekSlider.reloadThumbs() except AttributeError: pass def closeEvent(self, event: QCloseEvent) -> None: event.accept() self.console.deleteLater() if hasattr(self, 'cutter'): self.save_settings() if hasattr(self.cutter, 'mpvWidget'): self.cutter.mpvWidget.shutdown() qApp.quit()
class PyCirkuitParser(QObject): def _initStrings(self): self._appDescriptionStr = _translate( "CommandLine", "\n" "{productName} is a front-end for Circuit Macros by Dwight Aplevich,\n" "which are a set of macros for drawing high-quality line diagrams\n" "to be included in TeX, LaTeX, web or similar documents.", "Commandline application description. Don't translate '{productName}'." ) self._batchOptionStr = _translate( "CommandLine", "Activates batch (unattended) mode, and convert files specified by <path> to {formatID} format. Several output formats can be used together.", "Commandline option description. Don't translate the '{formatID}' variable." ) self._dpiOptionStr = _translate( "CommandLine", "Sets the resolution of output raster images (png, jpg), in dots per inch. Value <N> is mandatory. If option is not set, default is {defaultDPI}dpi (defined in 'settings' dialog).", "Commandline argument description. Don't translate the '{defaultDPI}' variable." ) self._qualityOptionStr = _translate( "CommandLine", "Sets the quality of output raster lossy images (jpg), in percent. Value <Q> is mandatory. If option is not set, default is {defaultQuality}% (defined in 'settings' dialog).", "Commandline option description. Don't translate the '{defaultQuality}' variable." ) self._overwriteOptionStr = _translate( "CommandLine", "Overwrite by default the converted files if they are present. If not set, user will be asked at runtime.", "Commandline option description.") self._followLinksOptionStr = _translate( "CommandLine", "Follow symbolic links.\n" "- If not set, destination file will be saved into the same directory where the source file is, whether it's a real file or a symbolic link.\n" "- If set, destination file will be saved into the directory where the real source file is located.", "Commandline option description.") self._destDirOptionStr = _translate( "CommandLine", "Save all converted files into the same destination directory <D> (value is mandatory).", "Commandline option description. Don't translate '<D>'.") self._recurseOptionStr = _translate( "CommandLine", "Using this option the pattern '**' will match any files and zero or more subdirs, so '**/*.ckt' will match all files with 'ckt' extension in the current directory and all its subdirectories.", "Commandline option description.") self._pathDescriptionStr = _translate( "CommandLine", "Path to source drawing file(s) to process. Wildcards accepted.\n" "- If no <path> is given, the GUI is opened.\n" "- If <path> points to only one file and no batch conversion options are present, this file is opened into the GUI for editing.\n" "- If <path>s point to more than one valid file and a combination of output formats options are present, these source files are processed sequentially in batch (unattended) mode and converted into the requested formats.\n" "- Specifying more than one file to process with no output format options present is not allowed.", "Commandline argument description. If you translate <path>, translate the name and path syntax accordingly." ) self._seeHelpStr = _translate( "CommandLine", 'Try "{appName} --help" to get more information.', "Command-line error message. Don't translate '{appName}'.") def __init__(self, args): super().__init__() self.args = args settings = QSettings() self.imageParam = { Option.DPI: settings.value("Export/exportDPI", 150, type=int), Option.QUAL: settings.value("Export/exportQuality", 80, type=int), } self.cli_mode = False self.requestedRecursive = False self.overwrite = Overwrite.UNSET self.dstDir = "" self._initStrings() self.parser = QCommandLineParser() #self.parser.setSingleDashWordOptionMode(QCommandLineself.parser.ParseAsLongOptions) self.parser.setApplicationDescription( self._appDescriptionStr.format(productName=__productname__)) # Adding the '-h, --help' option self.parser.addHelpOption() # Adding the '-v --version' option self.parser.addVersionOption() # Allowing positional arguments (the file/files to open or process) self.parser.addPositionalArgument( _translate( "CommandLine", "path", "Commandline argument name. If you translate this name, translate it accordingly into the path description and path syntax." ), self._pathDescriptionStr, _translate( "CommandLine", "[<path> [ <path2>...]]", "Commandline argument syntax. If you translate <path>, translate the name and path description accordingly." )) # Adding command line options self.options = { Option.TIKZ: QCommandLineOption( ["t", "tikz"], self._batchOptionStr.format(formatID='TIkZ'), ), Option.PDF: QCommandLineOption( ["f", "pdf"], self._batchOptionStr.format(formatID='PDF'), ), Option.PNG: QCommandLineOption( ["p", "png"], self._batchOptionStr.format(formatID='PNG'), ), Option.JPEG: QCommandLineOption( ["j", "jpeg"], self._batchOptionStr.format(formatID='JPEG'), ), Option.SVG: QCommandLineOption( ["s", "svg"], self._batchOptionStr.format(formatID='SVG'), ), Option.DPI: QCommandLineOption( ["dpi"], self._dpiOptionStr.format( defaultDPI=self.imageParam[Option.DPI]), "N", ), Option.QUAL: QCommandLineOption( ["quality"], self._qualityOptionStr.format( defaultQuality=self.imageParam[Option.QUAL]), "Q", ), Option.DEST: QCommandLineOption( ["destination"], self._destDirOptionStr, "D", ), Option.LINK: QCommandLineOption( ["links"], self._followLinksOptionStr, ), Option.OVER: QCommandLineOption( ["overwrite"], self._overwriteOptionStr, ), Option.REC: QCommandLineOption( ["r"], self._recurseOptionStr, ), } # Adding the options in the list for option in self.options.values(): self.parser.addOption(option) def _checkFiles(self): # Test for some path passed as parameters, or none paths = self.parser.positionalArguments() # User gave some filespec to process? pathPresent = (len(paths) > 0) # User may have entered more than one path, and these can contain wildcards # We have to expand them into files prior to process self.requestedFilesToProcess = list() for pathSpec in paths: for f in glob.iglob(pathSpec, recursive=self.requestedRecursive): if isfile(realpath(f)): f = realpath(f) if self.followSymlinks else abspath(f) self.requestedFilesToProcess.append(f) NumFiles = len(self.requestedFilesToProcess) if (NumFiles == 0) and pathPresent: print( QCoreApplication.applicationName() + ": " + _translate("CommandLine", "The given path does not match any existing file.", "Commandline error message")) print( self._seeHelpStr.format( appName=QCoreApplication.applicationName())) sys.exit(-1) return NumFiles def _checkFileOptions(self): self.followSymlinks = self.parser.isSet(self.options[Option.LINK]) self.overwrite = Overwrite.ALL if self.parser.isSet( self.options[Option.OVER]) else Overwrite.UNSET if self.parser.isSet(self.options[Option.DEST]): self.dstDir = abspath( self.parser.value((self.options[Option.DEST]))) if not isdir(self.dstDir): print(QCoreApplication.applicationName() + ": " + _translate( "CommandLine", "The given path does not match any existing file.", "Commandline error message")) print( self._seeHelpStr.format( appName=QCoreApplication.applicationName())) sys.exit(-1) else: self.dstDir = "" def _checkFormats(self): # Test for requested output formats. If any, cli_mode is set. validOutputFormats = { Option.TIKZ, Option.PNG, Option.PDF, Option.JPEG, Option.SVG } self.requestedOutputFormats = set() for outputFormat in validOutputFormats: if self.parser.isSet(self.options[outputFormat]): self.cli_mode = True self.requestedOutputFormats.add(outputFormat) NumFormats = len(self.requestedOutputFormats) return NumFormats def _checkRecursive(self): self.requestedRecursive = self.parser.isSet(self.options[Option.REC]) def _checkRasterOptions(self): # Set the "dpi" and "quality" parameters to the values provided by user, if any # process the "dpi" option if self.parser.isSet(self.options[Option.DPI]): try: self.imageParam[Option.DPI] = int( self.parser.value(self.options[Option.DPI])) if self.imageParam[Option.DPI] not in range(25, 3001): raise Exception() except: print(QCoreApplication.applicationName() + ": " + _translate( "CommandLine", "The --dpi parameter must be an integer between 25 and 3000.", "Error message")) print( self._seeHelpStr.format( appName=QCoreApplication.applicationName())) sys.exit(-1) # Process the "quality" option if self.parser.isSet(self.options[Option.QUAL]): try: self.imageParam[Option.QUAL] = int( self.parser.value(self.options[Option.QUAL])) if self.imageParam[Option.QUAL] not in range(0, 101): raise Exception() except: print(QCoreApplication.applicationName() + ": " + _translate( "CommandLine", "The --quality parameter must be an integer between 0 and 100.", "Error message")) print( self._seeHelpStr.format( appName=QCoreApplication.applicationName())) sys.exit(-1) def parseCmdLine(self): self.parser.process(self.args) ##### FETCH OPTIONS AND ARGUMENTS # Test if "recursive" flag is set self._checkRecursive() # Check if user set some image raster parameters self._checkRasterOptions() # Test how many output formats were requested. self._checkFormats() # Test for various file options self._checkFileOptions() # Find files to process NumFiles = self._checkFiles() ##### Process CLI mode if self.cli_mode: # Is an error to call pycirkuit with a batch option and no filenames if (NumFiles == 0): print(QCoreApplication.applicationName() + ": " + _translate( "CommandLine", "Batch processing requested with no files.", "Commandline error message")) print( self._seeHelpStr.format( appName=QCoreApplication.applicationName())) sys.exit(-1) # Instantiate a processor object for this CLI session try: processor = PyCirkuitProcessor() for fileName in self.requestedFilesToProcess: processed = False print( _translate( "CommandLine", "Processing file:", "Command line message. Will be followed by an absolute file path" ), fileName) while not processed: processor.beginProcessing(fileName) for format in self.requestedOutputFormats: try: processor.requestResult( format, dstDir=self.dstDir, overwrite=self.overwrite, dpi=self.imageParam[Option.DPI], quality=self.imageParam[Option.QUAL]) except PyCktToolExecutionError as err: answer = self._askOnError(err) if answer == Decision.ABORT: # Terminate program sys.exit(-1) elif answer == Decision.SKIP: # Consider file processed and jump to the next one processed = True continue elif answer == Decision.OPEN: # Open a IGU try: run(["pycirkuit", fileName], shell=False, check=False) # Breaking here puts us out of the "for" loop and source is re-read in "beginProcesing" break except: processed = True else: processed = True print("") except PyCirkuitError as err: print("\npycirkuit:", err) sys.exit(-1) print( _translate( "CommandLine", "Files processed: {N}.", "Command line message. {N} will be an integer, don't translate it." ).format(N=NumFiles)) sys.exit(0) ##### Process GUI mode. Perform some final checks and exit. if NumFiles == 0: return None elif NumFiles == 1: return abspath(self.requestedFilesToProcess[0]) else: print(QCoreApplication.applicationName() + ": " + _translate( "CommandLine", "More than one file to process with no batch option given.", "Commandline error message")) print( self._seeHelpStr.format( appName=QCoreApplication.applicationName())) sys.exit(-1) def _askOnError(self, err): # Test if we have GUI or not, and ask accordingly print("\npycirkuit:", err) question = _translate( "CommandLine-UserInput2", "Please choose what to do: [a]bort processing, [s]kip file, [o]pen in GUI for editing: ", "WARNING!! Critical translation. You should translate this message to your language, enclosing into brackets one single DIFFERENT character for each option, and translate accordingly the characters in the next message." ) answerAbort = _translate( "CommandLine-UserInput2", "a", "WARNING!! Critical translation. This char must match one of those of the message 'Please choose what to do:'" ) answerSkip = _translate( "CommandLine-UserInput2", "s", "WARNING!! Critical translation. This char must match one of those of the message 'Please choose what to do:'" ) answerOpen = _translate( "CommandLine-UserInput2", "o", "WARNING!! Critical translation. This char must match one of those of the message 'Please choose what to do:'" ) if pycirkuit.__haveGUI__: question = _translate( "CommandLine-UserInput2", "Please choose what to do: [a]bort processing, [s]kip file, [o]pen in GUI for editing: ", "WARNING!! Critical translation. You should translate this message to your language, enclosing into brackets one single DIFFERENT character for each option, and translate accordingly the characters in the next message." ) answers = { answerAbort: Decision.ABORT, answerSkip: Decision.SKIP, answerOpen: Decision.OPEN } else: question = _translate( "CommandLine-UserInput2", "Please choose what to do: [a]bort processing, [s]kip file: ", "WARNING!! Critical translation. You should translate this message to your language, enclosing into brackets one single DIFFERENT character for each option, and translate accordingly the characters in the next message." ) answers = { answerAbort: Decision.ABORT, answerSkip: Decision.SKIP, } # Ask for user decision, loop until answered while True: answer = input(question) if answer.lower() in answers: return answers[answer]
- create instance of application class (ui) - call setupUi to set dialog properties (calls retranslateUi) - call parseConfigFile - show the QDialog - the application will process messages until it is told to exit """ import sys, os from subprocess import Popen, PIPE from configparser import ConfigParser app = QApplication(sys.argv) app.setApplicationName("gitStatus.py") app.setApplicationVersion("1.0.0") clp = QCommandLineParser() # handle command line options clp.addHelpOption() clp.addVersionOption() verboseOption = QCommandLineOption("verbose", "Issue progress messages to console.") clp.addOption(verboseOption) clp.process(sys.argv) GitStatus = QtWidgets.QDialog() # create QDialog ui = Ui_GitStatus() # instantiate ui ui.setupUi(GitStatus) # configure all widgets ui.isVerbose = clp.isSet(verboseOption) if not ui.parseConfigFile(): # read the .ini file sys.exit(1) ui.populateDialog() # populate the dialog's widgets
class MainWindow(QMainWindow): EXIT_CODE_REBOOT = 666 TEMP_PROJECT_FILE = 'vidcutter_reboot.vcp' WORKING_FOLDER = os.path.join(QDir.tempPath(), 'vidcutter') def __init__(self): super(MainWindow, self).__init__() self.video, self.resizeTimer = '', 0 self.parse_cmdline() self.init_settings() self.init_logger() self.init_scale() self.init_cutter() self.setWindowTitle(qApp.applicationName()) self.setContentsMargins(0, 0, 0, 0) self.statusBar().showMessage('Ready') self.statusBar().setStyleSheet('border: none; padding: 0; margin: 0;') self.setAcceptDrops(True) self.show() if sys.platform == 'win32' and TaskbarProgress.isValidWinVer(): self.win_taskbar_button = QWinTaskbarButton(self) self.win_taskbar_button.setWindow(self.windowHandle()) self.win_taskbar_button.progress().setVisible(True) self.win_taskbar_button.progress().setValue(0) self.console.setGeometry(int(self.x() - (self.width() / 2)), self.y() + int(self.height() / 3), 750, 300) if not self.video and os.path.isfile(os.path.join(QDir.tempPath(), MainWindow.TEMP_PROJECT_FILE)): self.video = os.path.join(QDir.tempPath(), MainWindow.TEMP_PROJECT_FILE) if self.video: self.file_opener(self.video) def init_scale(self) -> None: screen_size = qApp.desktop().availableGeometry(-1) self.scale = 'LOW' if screen_size.width() <= 1024 else 'NORMAL' self.setMinimumSize(self.get_size(self.scale)) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) @pyqtSlot(str) def file_opener(self, filename: str) -> None: try: if QFileInfo(filename).suffix() == 'vcp': self.cutter.openProject(project_file=filename) if filename == os.path.join(QDir.tempPath(), MainWindow.TEMP_PROJECT_FILE): os.remove(os.path.join(QDir.tempPath(), MainWindow.TEMP_PROJECT_FILE)) else: self.cutter.loadMedia(filename) except (FileNotFoundError, PermissionError): QMessageBox.critical(self, 'Error loading file', sys.exc_info()[0]) logging.exception('Error loading file') qApp.restoreOverrideCursor() self.restart() @staticmethod def get_size(mode: str='NORMAL') -> QSize: modes = { 'LOW': QSize(800, 425), 'NORMAL': QSize(930, 680), 'HIGH': QSize(1850, 1300) } return modes[mode] def init_logger(self) -> None: try: log_path = QStandardPaths.writableLocation(QStandardPaths.AppConfigLocation).replace( qApp.applicationName(), qApp.applicationName().lower()) except AttributeError: if sys.platform == 'win32': log_path = os.path.join(QDir.homePath(), 'AppData', 'Local', qApp.applicationName().lower()) elif sys.platform == 'darwin': log_path = os.path.join(QDir.homePath(), 'Library', 'Preferences', qApp.applicationName().lower()) else: log_path = os.path.join(QDir.homePath(), '.config', qApp.applicationName().lower()) os.makedirs(log_path, exist_ok=True) self.console = ConsoleWidget(self) self.consoleLogger = ConsoleHandler(self.console) handlers = [logging.handlers.RotatingFileHandler(os.path.join(log_path, '%s.log' % qApp.applicationName().lower()), maxBytes=1000000, backupCount=1), self.consoleLogger] if self.parser.isSet(self.debug_option) or self.verboseLogs: # noinspection PyTypeChecker handlers.append(logging.StreamHandler()) logging.setLoggerClass(VideoLogger) logging.basicConfig(handlers=handlers, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M', level=logging.INFO) logging.captureWarnings(capture=True) sys.excepthook = MainWindow.log_uncaught_exceptions def init_settings(self) -> None: try: settings_path = QStandardPaths.writableLocation(QStandardPaths.AppConfigLocation).replace( qApp.applicationName(), qApp.applicationName().lower()) except AttributeError: if sys.platform == 'win32': settings_path = os.path.join(QDir.homePath(), 'AppData', 'Local', qApp.applicationName().lower()) elif sys.platform == 'darwin': settings_path = os.path.join(QDir.homePath(), 'Library', 'Preferences', qApp.applicationName().lower()) else: settings_path = os.path.join(QDir.homePath(), '.config', qApp.applicationName().lower()) os.makedirs(settings_path, exist_ok=True) settings_file = '%s.ini' % qApp.applicationName().lower() self.settings = QSettings(os.path.join(settings_path, settings_file), QSettings.IniFormat) if self.settings.value('geometry') is not None: self.restoreGeometry(self.settings.value('geometry')) if self.settings.value('windowState') is not None: self.restoreState(self.settings.value('windowState')) self.theme = self.settings.value('theme', 'light', type=str) self.startupvol = self.settings.value('volume', 100, type=int) self.verboseLogs = self.settings.value('verboseLogs', 'off', type=str) in {'on', 'true'} @staticmethod def log_uncaught_exceptions(cls, exc, tb) -> None: logging.critical(''.join(traceback.format_tb(tb))) logging.critical('{0}: {1}'.format(cls, exc)) def parse_cmdline(self) -> None: self.parser = QCommandLineParser() self.parser.setApplicationDescription('\nVidCutter - the simplest + fastest media cutter & joiner') self.parser.addPositionalArgument('video', 'Preload video file', '[video]') self.parser.addPositionalArgument('project', 'Open VidCutter project file (.vcp)', '[project]') self.debug_option = QCommandLineOption(['debug'], 'debug mode; verbose console output & logging. ' 'This will basically output what is being logged to file to the ' 'console stdout. Mainly useful for debugging problems with your ' 'system video and/or audio stack and codec configuration.') self.parser.addOption(self.debug_option) self.parser.addVersionOption() self.parser.addHelpOption() self.parser.process(qApp) self.args = self.parser.positionalArguments() if self.parser.isSet(self.debug_option): os.environ['DEBUG'] = '1' if len(self.args) > 0: file_path = QFileInfo(self.args[0]).absoluteFilePath() if not os.path.exists(file_path): sys.stderr.write('\nERROR: File not found: %s\n' % file_path) self.close() qApp.exit(1) self.video = file_path def init_cutter(self) -> None: self.cutter = VideoCutter(self) self.cutter.errorOccurred.connect(self.errorHandler) self.setCentralWidget(self.cutter) qApp.setWindowIcon(VideoCutter.getAppIcon(encoded=False)) @staticmethod def get_bitness() -> int: from struct import calcsize return calcsize('P') * 8 @pyqtSlot() def reboot(self) -> None: if self.cutter.mediaAvailable: self.cutter.saveProject(reboot=True) self.save_settings() qApp.exit(MainWindow.EXIT_CODE_REBOOT) def save_settings(self) -> None: self.settings.setValue('lastFolder', self.cutter.lastFolder) self.settings.setValue('geometry', self.saveGeometry()) self.settings.setValue('windowState', self.saveState()) self.settings.sync() @staticmethod def get_path(path: str=None, override: bool=False) -> str: if override: if getattr(sys, 'frozen', False) and getattr(sys, '_MEIPASS', False): # noinspection PyProtectedMember, PyUnresolvedReferences return os.path.join(sys._MEIPASS, path) return os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), path) return ':%s' % path @pyqtSlot(str) def errorHandler(self, msg: str, title: str=None) -> None: qApp.restoreOverrideCursor() QMessageBox.critical(self, 'An error occurred' if title is None else title, msg, QMessageBox.Ok) logging.error(msg) @staticmethod @pyqtSlot() def cleanup(): shutil.rmtree(MainWindow.WORKING_FOLDER, ignore_errors=True) def contextMenuEvent(self, event: QContextMenuEvent) -> None: if event.reason() == QContextMenuEvent.Mouse: self.cutter.appMenu.exec_(event.globalPos()) event.accept() super(MainWindow, self).contextMenuEvent(event) def mousePressEvent(self, event: QMouseEvent) -> None: if event.button() == Qt.LeftButton and self.cutter.mediaAvailable: self.cutter.cliplist.clearSelection() self.cutter.timeCounter.clearFocus() self.cutter.frameCounter.clearFocus() # noinspection PyBroadException try: if hasattr(self.cutter, 'notify'): self.cutter.notify.close() except BaseException: pass event.accept() def dragEnterEvent(self, event: QDragEnterEvent) -> None: if event.mimeData().hasUrls(): event.accept() def dropEvent(self, event: QDropEvent) -> None: filename = event.mimeData().urls()[0].toLocalFile() self.file_opener(filename) event.accept() def resizeEvent(self, event: QResizeEvent) -> None: try: if self.isEnabled() and self.cutter.mediaAvailable and self.cutter.thumbnailsButton.isChecked(): if self.cutter.seekSlider.thumbnailsOn: self.cutter.sliderWidget.setLoader(True) self.cutter.sliderWidget.hideThumbs() if self.resizeTimer: self.killTimer(self.resizeTimer) self.resizeTimer = self.startTimer(500) except AttributeError: pass def timerEvent(self, event: QTimerEvent) -> None: try: self.cutter.seekSlider.reloadThumbs() self.killTimer(self.resizeTimer) self.resizeTimer = 0 except AttributeError: pass def closeEvent(self, event: QCloseEvent) -> None: try: if not self.isEnabled(): warntext = ''' <style> h2 {{ color: {}; font-family: "Futura-Light", sans-serif; font-weight: 400; }} </style> <table border="0" cellpadding="6" cellspacing="0" width="350"> <tr> <td><h2>Video is currently being processed</h2></td> </tr> <tr> <td>Are you sure you wish to exit right now?</td> </tr> </table>'''.format('#C681D5' if self.theme == 'dark' else '#642C68') exitwarn = QMessageBox(QMessageBox.Warning, 'Warning', warntext, parent=self) exitwarn.setIconPixmap(QPixmap(':images/warning.png')) exitwarn.addButton('Yes', QMessageBox.NoRole) cancelbutton = exitwarn.addButton('No', QMessageBox.RejectRole) exitwarn.exec_() res = exitwarn.clickedButton() if res == cancelbutton: event.ignore() return elif self.cutter.mediaAvailable and self.cutter.projectDirty and not self.cutter.projectSaved: warntext = ''' <style> h2 {{ color: {}; font-family: "Futura-Light", sans-serif; font-weight: 400; }} </style> <table border="0" cellpadding="6" cellspacing="0" width="350"> <tr> <td><h2>There are unsaved changes in your project</h2></td> </tr> <tr> <td>Would you like to save the project now?</td> </tr> </table>'''.format('#C681D5' if self.theme == 'dark' else '#642C68') savewarn = QMessageBox(QMessageBox.Warning, 'Warning', warntext, parent=self) savewarn.setIconPixmap(QPixmap(':images/warning.png')) savebutton = savewarn.addButton('Save project', QMessageBox.YesRole) savewarn.addButton('Do not save', QMessageBox.NoRole) cancelbutton = savewarn.addButton('Cancel', QMessageBox.RejectRole) savewarn.exec_() res = savewarn.clickedButton() if res == savebutton: event.ignore() self.cutter.saveProject() return elif res == cancelbutton: event.ignore() return except AttributeError: pass event.accept() self.console.deleteLater() if hasattr(self, 'cutter'): self.save_settings() try: if hasattr(self.cutter.videoService, 'smartcut_jobs'): [ self.cutter.videoService.cleanup(job.files.values()) for job in self.cutter.videoService.smartcut_jobs ] if hasattr(self.cutter, 'mpvWidget'): self.cutter.mpvWidget.shutdown() except AttributeError: pass try: qApp.quit() except mpv.MPVError: pass
filename = "resources/Entities/questionmark.png" if img: filename = f"{os.path.splitext(anim.file)[0]}.png" img.save(filename, "PNG") if __name__ == "__main__": import sys app = QApplication(sys.argv) cmdParser = QCommandLineParser() cmdParser.setApplicationDescription( "Icon generator utility script for Basement Renovator. Takes an anm2 " ) cmdParser.addHelpOption() cmdParser.addPositionalArgument("file", "anm2 file to generate the icon from") frameOpt = QCommandLineOption( ["f", "frame"], "frame in the anm2 to use, defaults to 0", "f", "0" ) cmdParser.addOption(frameOpt) animOpt = QCommandLineOption( ["n", "anim"], "name of the animation in the anm2 to use, defaults to the default anim", "n", ) cmdParser.addOption(animOpt)
qml_context.setContextProperty("windowView", view) qml_context.setContextProperty("qApp", qApp) qml_context.setContextProperty("screenWidth", view.window_info.screen_width) qml_context.setContextProperty("screenHeight", view.window_info.screen_height) qml_context.setContextProperty("_menu_controller", menu_controller) view.setSource(QUrl.fromLocalFile(MAIN_QML)) view.disable_zone() view.showWindow() menu_controller.preMenuShow.connect(view.ungrabFocus) menu_controller.postMenuHide.connect(view.grabFocus) if __name__ == "__main__": parser = QCommandLineParser() parser.addHelpOption() parser.addVersionOption() delayOption = QCommandLineOption(["d", "delay"], "Take a screenshot after NUM seconds", "NUM") fullscreenOption = QCommandLineOption(["f", "fullscreen"], "Take a screenshot of the whole screen") topWindowOption = QCommandLineOption(["w", "top-window"], "Take a screenshot of the most top window") savePathOption = QCommandLineOption(["s", "save-path"], "Specify a path to save the screenshot", "PATH") startFromDesktopOption = QCommandLineOption(["i", "icon"], "Indicate that this program's started by clicking desktop file.") parser.addOption(delayOption) parser.addOption(fullscreenOption)
def main(): global app # Register representation factories baseRepresentationFactories.registerAllFactories() representationFactories.registerAllFactories() # initialize the app app = Application(sys.argv) app.setOrganizationName("SimpleFont") app.setOrganizationDomain("elih.blog/simplefont") app.setApplicationName("SimpleFont") app.setApplicationVersion(__version__) app.setWindowIcon(QIcon(":app.png")) app.setAttribute(Qt.AA_UseHighDpiPixmaps, True) appFont = platformSpecific.UIFontOverride() if appFont is not None: app.setFont(appFont) # app.setStyleSheet(platformSpecific.appStyleSheet()) app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5()) # Install stream redirection app.outputWindow = OutputWindow() # Exception handling sys.excepthook = errorReports.exceptionCallback # Qt's translation for itself. May not be installed. # qtTranslator = QTranslator() # qtTranslator.load("qt_" + QLocale.system().name(), # QLibraryInfo.location(QLibraryInfo.TranslationsPath)) # app.installTranslator(qtTranslator) # appTranslator = QTranslator() # appTranslator.load("simplefont_" + QLocale.system().name(), # os.path.dirname(os.path.realpath(__file__)) + # "/resources") # app.installTranslator(appTranslator) # parse options and open fonts parser = QCommandLineParser() parser.setApplicationDescription(QApplication.translate( "Command-line parser", "The SimpleFont font editor.")) parser.addHelpOption() parser.addVersionOption() parser.addPositionalArgument(QApplication.translate( "Command-line parser", "files"), QApplication.translate( "Command-line parser", "The UFO files to open.")) parser.process(app) # load menu if platformSpecific.useGlobalMenuBar(): app.fetchMenuBar() app.setQuitOnLastWindowClosed(False) # bootstrap extensions # process files args = parser.positionalArguments() if not args: # maybe load recent file loadRecentFile = settings.loadRecentFile() if loadRecentFile: recentFiles = settings.recentFiles() if len(recentFiles) and os.path.exists(recentFiles[0]): app.openFile(recentFiles[0]) else: for fontPath in args: app.openFile(fontPath) # if we did not open a font, spawn new font or go headless if not app.allFonts(): if platformSpecific.shouldSpawnDocument(): app.newFile() else: # HACK: on OSX we may want to trigger native QMenuBar display # without opening any window. Since Qt infers new menu bar on # focus change, fire the signal. app.focusWindowChanged.emit(None) sys.exit(app.exec_())