Example #1
0
def new_qt_application(app_config: dict,
                       logger: Logger,
                       quit_on_last_closed: bool = False,
                       name: str = None) -> QApplication:
    app = QApplication(sys.argv)
    app.setQuitOnLastWindowClosed(
        quit_on_last_closed
    )  # otherwise windows opened through the tray icon kill the application when closed
    app.setApplicationName(name if name else __app_name__)
    app.setApplicationVersion(__version__)
    app.setWindowIcon(util.get_default_icon()[1])

    if app_config['ui']['qt_style']:
        app.setStyle(str(app_config['ui']['qt_style']))
    else:
        app.setStyle('fusion')

    app.setProperty('qt_style', app.style().objectName().lower())

    theme_key = app_config['ui']['theme'].strip(
    ) if app_config['ui']['theme'] else None
    set_theme(theme_key=theme_key, app=app, logger=logger)

    if not app_config['ui']['system_theme']:
        app.setPalette(app.style().standardPalette())

    return app
Example #2
0
def main():
    try:
        create_tables()
        app = QApplication(sys.argv)
        app_theme = "cvstudio"
        app.setProperty("theme", app_theme)
        if app_theme == "light":
            light_theme(app)
        elif app_theme == "dark":
            dark_theme(app)
        elif app_theme == "gray":
            gray_theme(app)
        elif app_theme == "cvstudio":
            cvstudio_theme(app)
        mainWindow = MainWindow()
        mainWindow.setWindowIcon(GUIUtilities.get_icon("polygon.png"))
        mainWindow.show()
        sys.exit(app.exec_())
    except Exception as ex:
        print(ex)
Example #3
0
class Application:
    _app = None  # type: QApplication

    @property
    def app(self) -> QApplication:
        if self._app is None:
            self.setup()
        return self._app

    def setup(self) -> None:
        # Imports .qrc resources even if it is "unused"
        from genial.resources import icons_rc
        from genial.resources import locale_rc
        from genial.resources import plugins_rc

        # Initializes the app variable
        self._app = QApplication(sys.argv)
        self._app.setApplicationName("Génial")
        self._app.setApplicationDisplayName("Génial")
        self._app.setProperty("AA_EnableHighDpiScaling", True)

        # Qt translation
        qt_translator = QTranslator()
        if qt_translator.load(QLocale(), "qt", "_", ":/locale"):
            # noinspection PyArgumentList,PyCallByClass,PyTypeChecker
            QCoreApplication.installTranslator(qt_translator)

        # App translation
        genial_translator = QTranslator()
        if genial_translator.load(QLocale(), "genial", "_", ":/locale"):
            # noinspection PyArgumentList,PyCallByClass,PyTypeChecker
            QCoreApplication.installTranslator(genial_translator)

    def run(self) -> int:
        # Importing here makes available PyQt5.QtWidgets.QApplication.instance()
        # for each of these modules (and for their imports too.)
        from genial.controllers.maincontroller import MainController
        main_controller = MainController(self.app)
        main_controller.start()
        return self.app.exec()
Example #4
0
    dark_palette.setColor(QPalette.Disabled, QPalette.Base,
                          QColor(68, 68, 68, 255))
    dark_palette.setColor(QPalette.Disabled, QPalette.Shadow,
                          QColor(0, 0, 0, 255))
    app.setPalette(dark_palette)
    app.setStyleSheet(
        "QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }"
    )


if __name__ == "__main__":
    try:
        create_tables()
        app = QApplication(sys.argv)
        app_theme = "cvstudio"
        app.setProperty("theme", app_theme)
        if app_theme == "light":
            light_theme(app)
        elif app_theme == "dark":
            dark_theme(app)
        elif app_theme == "gray":
            gray_theme(app)
        elif app_theme == "cvstudio":
            cvstudio_theme(app)
        mainWindow = MainWindow()
        mainWindow.setWindowIcon(GUIUtilities.get_icon("polygon.png"))
        mainWindow.show()
        sys.exit(app.exec_())
    except Exception as ex:
        print(ex)
Example #5
0
class Main(QObject):

    def __init__(self, parent = None):
        """Create a wizard or the mainwindow"""
        self._parent = parent

        super().__init__(self._parent)

        print("runner/Main parent: ", self._parent, " -> self: ", self) if oPB.PRINTHIER else None

        self.logger = None
        self.args = self.get_args()
        self._log_level = None
        self._log_file = None
        self.translator = None

        # make it really quiet, part 1
        if self.args.quiet:
            self.args.nogui = True

        # instantiate configuration class
        confighandler.ConfigHandler(oPB.CONFIG_INI)

        # redirect system exception hook
        if not self.args.noexcepthook:
            sys.excepthook = self.excepthook

        # pre-instantiating the application, avoid some nasty OpenGL messages
        QApplication.setAttribute(QtCore.Qt.AA_UseOpenGLES)
        # create new application and install stylesheet
        self.app = QApplication(sys.argv)
        self.install_stylesheet()

        # Create and display the splash screen, if in ui mode
        if not self.args.nogui:
            splash_pix = QPixmap(':/images/splash.png')
            self.splash = QSplashScreen(splash_pix, QtCore.Qt.WindowStaysOnTopHint)
            self.splash.setMask(splash_pix.mask())
            # splash.showMessage("opsi Package Builder " + oPB.PROGRAM_VERSION + " " + translate("Main", "is loading..."), QtCore.Qt.AlignCenter, QtCore.Qt.white)
            self.splash.show()
            self.app.processEvents()

        # Application name
        self.app.setOrganizationName("opsi Package Builder")
        self.app.setApplicationName("opsi Package Builder " + oPB.PROGRAM_VERSION)

        # save ourselves in main instance property to be easily accessd via qApp
        # i.e.
        # from PyQt5.QtWidgets import qApp
        # main = qApp.property("main")
        self.app.setProperty("main", self)

        if confighandler.ConfigHandler.cfg.log_always == "True":
            if self.args.log_file is not None:
                self._log_file = self.args.log_file
            else:
                self._log_file = confighandler.ConfigHandler.cfg.log_file

            if self.args.log_level.upper() != "NOTSET":
                self._log_level = self.args.log_level.upper()
            else:
                self._log_level = confighandler.ConfigHandler.cfg.log_level
        else:
            self._log_file = self.args.log_file
            if self.args.log_level.upper() == "NOTSET":
                self._log_level = "CRITICAL"
            else:
                self._log_level = self.args.log_level.upper()

        if self._log_file is not None:
            if not pathlib.Path(self._log_file).is_absolute():
                if platform.system() == "Windows":
                    self._log_file = str(pathlib.PurePath(oPB.WIN_TMP_PATH, self._log_file))
                if platform.system() in ["Darwin", "Linux"]:
                    self._log_file = str(pathlib.PurePath(oPB.UNIX_TMP_PATH, self._log_file))

        # overwrite development directory from config with command line arg
        if self.args.dev_dir is not None:
                confighandler.ConfigHandler.cfg.dev_dir = self.args.dev_dir

        # Initialize the logger and reroute QtCore messages to it
        self.logWindow =  oPB.gui.logging.LogDialog(None, self, self._log_level)
        self.instantiate_logger(False)
        QtCore.qInstallMessageHandler(self.qt_message_handler)

        # log program version and user
        self.logger.info(80 * "-")
        self.logger.info("opsi PackageBuilder (MIT licensed) " + oPB.PROGRAM_VERSION)
        self.logger.info("Current user: "******"Command line arguments given:")
        for key, val in vars(self.args).items():
            self.logger.info("  " + key + ": " + str(val))
        if self._log_level not in ["DEBUG", "INFO", "SSHINFO", "WARNING", "ERROR", "CRITICAL", "SSH"]:
            self.logger.error("  Undefined log level: " + self._log_level)
            self.logger.error("  Log level has been set to ERROR")

        for elem in self.app.libraryPaths():
            self.logger.debug("QT5 library path: " + elem)

        # write config to log, if necessary
        confighandler.ConfigHandler.cfg.log_config()


        self.check_online_status()

        # -----------------------------------------------------------------------------------------
        # main ui dispatching

        # startup gui variant
        if not self.args.nogui:

            # hide console window, but only under Windows and only if app is frozen
            if sys.platform.lower().startswith('win'):
                if getattr(sys, 'frozen', False):
                    hideConsole()

            # installing translators
            self.translator = Translator(self.app, "opsipackagebuilder")
            self.translator.install_translations(confighandler.ConfigHandler.cfg.language)

            # retranslate logWindow, as it is loaded before the translations
            self.logWindow.retranslateUi(self.logWindow)

            # create app icon
            app_icon = QtGui.QIcon()
            app_icon.addFile(':images/prog_icons/opb/package_16x16.png', QtCore.QSize(16, 16))
            app_icon.addFile(':images/prog_icons/opb/package_24x24.png', QtCore.QSize(24, 24))
            app_icon.addFile(':images/prog_icons/opb/package_32x32.png', QtCore.QSize(32, 32))
            app_icon.addFile(':images/prog_icons/opb/package_48x48.png', QtCore.QSize(48, 48))
            app_icon.addFile(':images/prog_icons/opb/package_64x64.png', QtCore.QSize(64, 64))
            app_icon.addFile(':images/prog_icons/opb/package_92x92.png', QtCore.QSize(92, 92))
            app_icon.addFile(':images/prog_icons/opb/package_128x128.png', QtCore.QSize(128, 128))
            app_icon.addFile(':images/prog_icons/opb/package_256x256.png', QtCore.QSize(256, 256))
            self.app.setProperty("prog_icon",app_icon)

            # startup program window
            self.mainWindow = main.MainWindowController(self.args)
            self.mainWindow.ui.showLogRequested.connect(self.logWindow.show)
            self.mainWindow.closeAppRequested.connect(self.logWindow.close)

            self.splash.finish(self.mainWindow.ui)

            # check for updates if configured
            if confighandler.ConfigHandler.cfg.updatecheck == "True":
                self.mainWindow.update_check()

            # run main app loop
            self.app.exec_()

        # only process commandline
        else:
            self.logger.info("No-GUI parameter set")

            # startup program window
            self.console = console.ConsoleController(self.args)

        # -----------------------------------------------------------------------------------------

        # unmount drive (if exist) after end of program
        if (oPB.NETDRV is not None) and oPB.NETDRV != "offline":
            ret = MapDrive.unMapDrive(oPB.NETDRV)
            if ret[0] != 0:
                self.logger.error("Error unmounting path: " + str(ret))
            else:
                self.logger.info("Network drive successfully unmounted")

        # exit and set return code
        self.logger.info("Exit code: " + str(oPB.EXITCODE))

        # show console window
        if not self.args.nogui:
            if sys.platform.lower().startswith('win'):
                if getattr(sys, 'frozen', False):
                    showConsole()

        sys.exit(oPB.EXITCODE)

    def qt_message_handler(self, mode, context, message):
        if mode == QtCore.QtInfoMsg:
            mode = 'INFO'
            fun = self.logger.info
        elif mode == QtCore.QtWarningMsg:
            mode = 'WARNING'
            fun = self.logger.warning
        elif mode == QtCore.QtCriticalMsg:
            mode = 'CRITICAL'
            fun = self.logger.critical
        elif mode == QtCore.QtFatalMsg:
            mode = 'FATAL'
            fun = self.logger.error
        else:
            mode = 'DEBUG'
            fun = self.logger.debug
        fun('Qt framework message handler: line: %d, func: %s(), file: %s' % (
            context.line, context.function, context.file))
        fun('Qt framework message handler:   %s: %s' % (mode, message))

    def install_stylesheet(self):
        if platform.system() == "Darwin":
            css = os.environ['OPB_BASE'] + "/ui/stylesheet-mac.qss"
        else:
            css = os.environ['OPB_BASE'] + "/ui/stylesheet.qss"

        try:
            with open(css, "r", encoding="utf-8", newline="\n") as file:
                style = file.readlines()
                file.close()
        except:
            self.logger.debug("Stylesheet could not be opened.")
        else:
            self.app.setStyleSheet(("\n").join(style))

    def check_online_status(self):
        self.logger.debug("Check online status")
        # check if server is generally available
        # use SSH port for connection test
        ret = Helper.test_port(confighandler.ConfigHandler.cfg.opsi_server, confighandler.ConfigHandler.cfg.sshport, 0.5)
        if ret is True:
            # check network access and mount network drive if on linux
            if sys.platform == 'win32':
                self.logger.info("System platform: "+ sys.platform)
                if self.args.nonetdrive is False:
                    if confighandler.ConfigHandler.cfg.usenetdrive == "False":

                        drives = Helper.get_available_drive_letters()
                        if not drives:
                            self.logger.error("No free drive letter found")
                        else:
                            self.logger.info("Free drive letter found: " + repr(drives))
                            self.logger.info("Using drive letter: " + drives[::-1][0])
                            path = "\\\\" + confighandler.ConfigHandler.cfg.opsi_server + "\\" + "opsi_workbench"
                            self.logger.info("Trying to mount path: " + path)
                            ret = MapDrive.mapDrive(drives[::-1][0] + ":", path, confighandler.ConfigHandler.cfg.opsi_user, confighandler.ConfigHandler.cfg.opsi_pass)
                            if ret[0] != 0:
                                self.logger.error("Error mounting path: " + str(ret))
                            else:
                                self.logger.info("Network drive successfully mounted")
                                oPB.NETDRV = drives[::-1][0] + ":"
                    else:
                        self.logger.info("Using existing network drive")
                else:
                    self.logger.info("Mounting of network drive via command line disabled")
            else:
                self.logger.info("System platform: "+ sys.platform)
                self.logger.warning("This is not a windows based system. No network drive will be associated")
                self.logger.warning("Please take care, that the specified development base path is correct.")
        else:
            self.logger.warning("opsi server not available. Offline mode activated.")
            self.logger.warning("Return value from connection test: " + str(ret))
            oPB.NETMODE = "offline"

    def get_args(self):
        # get cmdline args
        cmd_params = CommandLine()
        return cmd_params.getArgs()

    def set_log_level(self, level, handler):
        # set log level
        if level == "DEBUG":
            handler.setLevel(logging.DEBUG)
        elif level == "INFO":
            handler.setLevel(logging.INFO)
        elif level == "WARNING":
            handler.setLevel(logging.WARNING)
        elif level == "ERROR":
            handler.setLevel(logging.ERROR)
        elif level == "CRITICAL":
            handler.setLevel(logging.WARNING)
        elif level == "SSH":
            handler.setLevel(oPB.core.logging.SSH)
        elif level == "SSHINFO":
            handler.setLevel(oPB.core.logging.SSHINFO)
        else:
            handler.setLevel(logging.ERROR)

    def instantiate_logger(self, long):
        # for additional log facilities, see
        # http://stackoverflow.com/questions/2183233/how-to-add-a-custom-loglevel-to-pythons-logging-facility

        # Create logger
        logger = logging.getLogger('oPB')

        # to add a further logging facility, we have to subclass current logger class
        # and set this new one to be the default logger class
        setLoggerClass(oPB.core.logging.SSHLogger)

        # log level for logger(!) - we filter on handler-based log level later
        self.set_log_level("DEBUG", logger)

        # make it really quiet, part 2
        if self.args.quiet:
            self.noop = logging.NullHandler()
            logger.addHandler(self.noop)
        else:
            if long:
                format = logging.Formatter(oPB.LOG_LONG, oPB.LOG_DATETIME)
            else:
                format = logging.Formatter(oPB.LOG_SHORT, oPB.LOG_DATETIME)

            # redirect stdout / stdin if gui
            if not self.args.nogui:
                # Output forwarding
                sys.stdout = oPB.core.logging.LogOutput(self.logWindow.editOutput,  sys.__stdout__,  self.logWindow.editOutput.textColor())
                sys.stderr = oPB.core.logging.LogOutput(self.logWindow.editOutput,  sys.__stderr__,  QtGui.QColor(QtCore.Qt.red))

            # Create standart output handler
            self.stdout = logging.StreamHandler(sys.__stderr__)
            self.set_log_level(self._log_level, self.stdout)
            self.stdout.setFormatter(format)

            # Add handlers to logger
            logger.addHandler(self.stdout)

            # Create different log window handler
            if not self.args.nogui:
                # output standard msg into dialog tab "Logging"
                self.dialogHandler = oPB.core.logging.LogStreamHandler(self.logWindow.editLog, self)
                self.dialogHandler.colors = oPB.OPB_LOG_COLORS
                self.dialogHandler.colorize = True
                self.set_log_level(self._log_level, self.dialogHandler)
                self.dialogHandler.setFormatter(format)

                logger.addHandler(self.dialogHandler)

                # Create special SSH output log facility, put this into tab "SSH Output"
                self.sshHandler = oPB.core.logging.LogStreamHandler(self.logWindow.editSSH, self)
                self.set_log_level("SSHINFO", self.sshHandler)
                sshformat = logging.Formatter(oPB.LOG_SSH, oPB.LOG_DATETIME)
                self.sshHandler.setFormatter(sshformat)

                logger.addHandler(self.sshHandler)

            # Create log file handler, possible
            try:
                if self._log_file is not None:
                    self.fileHandler = logging.FileHandler(self._log_file)
                    self.set_log_level(self._log_level, self.fileHandler)
                    self.fileHandler.setFormatter(format)

                    logger.addHandler(self.fileHandler)
            except IOError as error:
                logger.error("Log file could not be opened: " + self._log_file)
                logger.error(error)

        self.logger = logger

    def excepthook(self, excType, excValue, tracebackobj):
        """
        Global function to catch unhandled exceptions. Writes
        traceback to temporary file.

        Adopted to Python 3 from here:
        http://www.riverbankcomputing.com/pipermail/pyqt/2009-May/022961.html

        :param excType: exception type
        :param excValue: exception value
        :param tracebackobj: traceback object
        """

        try:
            self.splash.close()
        except:
            pass

        self.logger.debug("Entering excepthook")

        separator = '-' * 80
        logFile = tempfile.NamedTemporaryFile(mode = "w+", suffix = ".log", prefix = "opb-error-", delete = False)

        # """If you have any additional, confidential information you can\n""" \
        # """use this mail address: <%s>\n\n""" \

        notice = \
            """An unhandled exception occurred. Please report the problem\n"""\
            """via the official opsi PackageBuilder forum:\n\n"""\
            """https://forum.opsi.org/viewforum.php?f=22\n\n"""\
            """Thank you!\n\n"""\
            """A log has been written to "%s".\n\nError information:\n""" % \
            (logFile.name)

        versionInfo="0.0.1"
        timeString = datetime.datetime.now().strftime("%Y-%m-%d, %H:%M:%S")


        tbinfofile = StringIO()
        traceback.print_tb(tracebackobj, None, tbinfofile)
        tbinfofile.seek(0)
        tbinfo = tbinfofile.read()
        errmsg = '%s: \n%s' % (str(excType), str(excValue))
        sections = [separator, timeString, separator, errmsg, separator, tbinfo]
        msg = '\n'.join(sections)
        try:
            logFile.file.write(msg)
            logFile.file.write(versionInfo)
            logFile.close()
        except IOError:
            pass

        if not self.args.nogui:
            errorbox = QtWidgets.QMessageBox()
            errorbox.setText(str(notice) + str(msg) + str(versionInfo))
            errorbox.exec_()
        else:
            print(str(notice) + str(msg) + str(versionInfo))
Example #6
0
class Main(QObject):

    def __init__(self, parent = None):
        """Create a wizard or the mainwindow"""
        super().__init__(parent)

        self.logger = None
        self.args = self.get_args()

        # redirect system exception hook
        sys.excepthook = self.excepthook

        # create new application
        self.app = QApplication(sys.argv)

        # Application name
        self.app.setOrganizationName("opsi Package Builder")
        self.app.setApplicationName("opsi Package Builder " + oPB.PROGRAM_VERSION)

        # save ourselves in main instance property to be easily accessd via qApp
        # i.e.
        # from PyQt5.QtWidgets import qApp
        # main = qApp.property("main")
        self.app.setProperty("main", self)

        # Initialize the logger
        self.logWindow =  oPB.gui.logging.LogDialog(None, self, self.args.log_level.upper())
        self.instantiate_logger(False)

        #self.instantiate_logger_old()

        # instantiate configuration class
        confighandler.ConfigHandler(oPB.CONFIG_INI)

        # log program version and user
        self.logger.info("opsi PackageBuilder (MIT licensed) " + oPB.PROGRAM_VERSION)
        self.logger.info("Current user: "******"Command line arguments given:")
        for key, val in vars(self.args).items():
            self.logger.info("  " + key + ": " + str(val))
        if self.args.log_level.upper() not in ["DEBUG", "INFO", "SSHINFO", "WARNING", "ERROR", "CRITICAL", "SSH"]:
            self.logger.error("  Undefined log level: " + self.args.log_file.upper())
            self.logger.error("  Log level has been set to ERROR")

        for elem in self.app.libraryPaths():
            self.logger.debug("QT5 library path: " + elem)

        self.install_translations()

        self.check_online_status()

        # -----------------------------------------------------------------------------------------
        # main ui dispatching

        # startup gui variant
        if not self.args.nogui:

            # startup program window
            self.mainWindow = main.MainWindowController(self.args)
            self.mainWindow.ui.showLogRequested.connect(self.logWindow.show)
            self.mainWindow.closeAppRequested.connect(self.logWindow.close)

            # run main app loop
            self.app.exec_()

        # only process commandline
        else:
            self.logger.info("No-GUI parameter set")

            # startup program window
            self.console = console.ConsoleController(self.args)

        # -----------------------------------------------------------------------------------------

        # unmount drive after end of program
        if oPB.NETDRV is not None:
            ret = MapDrive.unMapDrive(oPB.NETDRV)
            if ret[0] != 0:
                self.logger.error("Error unmounting path: " + str(ret))
            else:
                self.logger.info("Network drive successfully unmounted")

        # exit and set return code
        self.logger.debug("Exit code: " + str(oPB.EXITCODE))

        sys.exit(oPB.EXITCODE)


    def install_translations(self):
        # get current system language and load translation
        # we need two translators: one for the individual appplication strings
        # and one for the standard qt message texts
        # qm = 'opsiPackageBuilder_en_EN.qm'
        # get files
        qm_app = ':locale/opsiPackageBuilder_%s.qm' % QtCore.QLocale().system().name()
        self.logger.debug("Load application translation: " + qm_app)
        qm_qt = ':locale/qtbase_%s.qm' % QtCore.QLocale().system().name()
        self.logger.debug("Load Qt standard translation: " + qm_qt)

        # create translators
        translator_app = QtCore.QTranslator(self.app)
        translator_app.load(qm_app)
        translator_qt = QtCore.QTranslator(self.app)
        translator_qt.load(qm_qt)

        # install translators to use it later
        self.app.installTranslator(translator_app)
        self.app.installTranslator(translator_qt)

    def check_online_status(self):
        # check if server is generally available
        # use SSH port for connection test
        ret = Helper.test_port(confighandler.ConfigHandler.cfg.opsi_server, confighandler.ConfigHandler.cfg.sshport, 0.5)
        if type(ret) != tuple:
            # check network access and mount network drive if on linux
            if sys.platform == 'win32':
                self.logger.info("System platform: "+ sys.platform)
                if confighandler.ConfigHandler.cfg.usenetdrive == "False":

                    drives = Helper.get_available_drive_letters()
                    if not drives:
                        self.logger.error("No free drive letter found")
                    else:
                        self.logger.info("Free drive letter found: " + repr(drives))
                        self.logger.info("Using drive letter: " + drives[::-1][0])
                        path = "\\\\" + confighandler.ConfigHandler.cfg.opsi_server + "\\" + "opsi_workbench"
                        self.logger.info("Trying to mount path: " + path)
                        ret = MapDrive.mapDrive(drives[::-1][0] + ":", path, confighandler.ConfigHandler.cfg.opsi_user, confighandler.ConfigHandler.cfg.opsi_pass)
                        if ret[0] != 0:
                            self.logger.error("Error mounting path: " + str(ret))
                        else:
                            self.logger.info("Network drive successfully mounted")
                            oPB.NETDRV = drives[::-1][0] + ":"
            else:
                self.logger.info("System platform: "+ sys.platform)
                self.logger.warning("This is not a windows based system. No network drive will be associated")
                self.logger.warning("Please take care, if the specified development base path is correct.")
        else:
            self.logger.warning("opsi server not available. Offline mode activated.")
            self.logger.warning("Return value from connection test: " + str(ret))
            oPB.NETMODE = "offline"

    def get_args(self):
        # get cmdline args
        cmd_params = CommandLine()
        return cmd_params.getArgs()

    def set_log_level(self, level, handler):
        # set log level
        if level == "DEBUG":
            handler.setLevel(logging.DEBUG)
        elif level == "INFO":
            handler.setLevel(logging.INFO)
        elif level == "WARNING":
            handler.setLevel(logging.WARNING)
        elif level == "ERROR":
            handler.setLevel(logging.ERROR)
        elif level == "CRITICAL":
            handler.setLevel(logging.WARNING)
        elif level == "SSH":
            handler.setLevel(oPB.core.logging.SSH)
        elif level == "SSHINFO":
            handler.setLevel(oPB.core.logging.SSHINFO)
        else:
            handler.setLevel(logging.ERROR)

    def instantiate_logger(self, long):
        # for additional log facilities, see
        # http://stackoverflow.com/questions/2183233/how-to-add-a-custom-loglevel-to-pythons-logging-facility

        # Create logger
        logger = logging.getLogger('oPB')

        # to add a further logging facility, we have to subclass current logger class
        # and set this new one to be the default logger class
        setLoggerClass(oPB.core.logging.SSHLogger)

        # log level from command line or standard
        self.set_log_level(self.args.log_level.upper(), logger)

        if long:
            format = logging.Formatter(oPB.LOG_LONG, oPB.LOG_DATETIME)
        else:
            format = logging.Formatter(oPB.LOG_SHORT, oPB.LOG_DATETIME)

        # redirect stdout / stdin if gui
        if not self.args.nogui:
            # Output forwarding
            sys.stdout = oPB.core.logging.LogOutput(self.logWindow.editOutput,  sys.__stdout__,  self.logWindow.editOutput.textColor())
            sys.stderr = oPB.core.logging.LogOutput(self.logWindow.editOutput,  sys.__stderr__,  QtGui.QColor(QtCore.Qt.red))

        # Create standart output handler
        self.stdout = logging.StreamHandler(sys.__stderr__)
        self.set_log_level(self.args.log_level.upper(), self.stdout)
        self.stdout.setFormatter(format)

        # Add handlers to logger
        logger.addHandler(self.stdout)

        # Create different log window handler
        if not self.args.nogui:
            # output standard msg into dialog tab "Logging"
            self.dialogHandler = oPB.core.logging.LogStreamHandler(self.logWindow.editLog, self)
            self.set_log_level(self.args.log_level.upper(), self.dialogHandler)
            self.dialogHandler.setFormatter(format)

            logger.addHandler(self.dialogHandler)

            # Create special SSH output log facility, put this into tab "SSH Output"
            self.sshHandler = oPB.core.logging.LogStreamHandler(self.logWindow.editSSH, self)
            self.set_log_level(oPB.core.logging.SSH, self.sshHandler)
            sshformat = logging.Formatter(oPB.LOG_SSH, oPB.LOG_DATETIME)
            self.sshHandler.setFormatter(sshformat)

            logger.addHandler(self.sshHandler)

        # Create log file handler, possible
        try:
            if self.args.log_file is not None:
                self.fileHandler = logging.FileHandler(self.args.log_file)
                self.fileHandler.setFormatter(format)

                logger.addHandler(self.fileHandler)
        except IOError as error:
            logger.error("Log file could not be opened: " + self.args.log_file)
            logger.error(error)

        self.logger = logger

    def excepthook(self, excType, excValue, tracebackobj):
        """
        Global function to catch unhandled exceptions. Writes
        traceback to temporary file.

        Adopted to Python 3 from here:
        http://www.riverbankcomputing.com/pipermail/pyqt/2009-May/022961.html

        :param excType exception type
        :param excValue exception value
        :param tracebackobj traceback object
        """
        self.logger.debug("Entering excepthook")

        separator = '-' * 80
        logFile = tempfile.NamedTemporaryFile(mode = "w+", suffix = ".log", prefix = "opb-error-", delete = False)

        notice = \
            """An unhandled exception occurred. Please report the problem\n"""\
            """using an error reporting email to <%s>.\n\n"""\
            """A log has been written to "%s".\n\nError information:\n""" % \
            (oPB.__email__, logFile.name)

        versionInfo="0.0.1"
        timeString = datetime.datetime.now().strftime("%Y-%m-%d, %H:%M:%S")


        tbinfofile = StringIO()
        traceback.print_tb(tracebackobj, None, tbinfofile)
        tbinfofile.seek(0)
        tbinfo = tbinfofile.read()
        errmsg = '%s: \n%s' % (str(excType), str(excValue))
        sections = [separator, timeString, separator, errmsg, separator, tbinfo]
        msg = '\n'.join(sections)
        try:
            logFile.file.write(msg)
            logFile.file.write(versionInfo)
            logFile.close()
        except IOError:
            pass

        if not self.args.nogui:
            errorbox = QtWidgets.QMessageBox()
            errorbox.setText(str(notice) + str(msg) + str(versionInfo))
            errorbox.exec_()
        else:
            print(str(notice) + str(msg) + str(versionInfo))