void
Application::initiateLogin( bool forceWizard ) throw( StubbornUserException )
{
    closeAllWindows();

    if( forceWizard || !unicorn::Settings().value( SETTING_FIRST_RUN_WIZARD_COMPLETED, false ).toBool() )
    {
        setWizardRunning( true );

        FirstRunWizard w;
        if( w.exec() != QDialog::Accepted )
        {
            setWizardRunning( false );
            throw StubbornUserException();
        }

        setWizardRunning( false );
    }

    //this covers the case where the last user was removed
    //and the main window was closed.
    if ( m_mw )
        m_mw->show();

    if ( m_tray )
    {
        //HACK: turns out when all the windows are closed, the tray stops working
        //unless you call the following methods.
        m_tray->hide();
        m_tray->show();
    }
}
Esempio n. 2
0
void App::firstRunWizard()
{
    ///show firstRunWizard

    FirstRunWizard wizard;
    setTopWidget( &wizard );
    KConfigDialogManager* config = new KConfigDialogManager(&wizard, AmarokConfig::self(), "wizardconfig");
    config->updateWidgets();
   // connect(config, SIGNAL(settingsChanged()), SLOT(updateSettings()));
    wizard.setCaption( makeStdCaption( i18n( "First-Run Wizard" ) ) );

    if( wizard.exec() != QDialog::Rejected )
    {
        switch( wizard.interface() )
        {
        case FirstRunWizard::XMMS:
            amaroK::config()->writeEntry( "XMLFile", "amarokui_xmms.rc" );
            AmarokConfig::setShowPlayerWindow( true );
            //FIXME the statusbar is now quite essential and also without it
            // the popup messages break. Fix in 1.2.1
            AmarokConfig::setShowStatusBar( /*false*/ true );
            break;

        case FirstRunWizard::Compact:
            amaroK::config()->writeEntry( "XMLFile", "amarokui.rc" );
            AmarokConfig::setShowPlayerWindow( false );
            AmarokConfig::setShowStatusBar( true );
            break;
        }

        const QStringList oldCollectionFolders = AmarokConfig::collectionFolders();
        wizard.writeCollectionConfig();

        // If wizard is invoked at runtime, rescan collection if folder setup has changed
        if ( !amaroK::config()->readBoolEntry( "First Run", true ) &&
             oldCollectionFolders != AmarokConfig::collectionFolders() )
            CollectionDB::instance()->startScan();

        config->updateSettings();
    }
}
Esempio n. 3
0
int main(int argc, char *argv[]) {
    QDir clamDir;
    QFile dbFile, confFile;

    QApplication app(argc, argv);
    QTranslator myappTranslator;

    QString locale = QLocale::system().name();
    QString defaultLanguage = QString(APP_NAME) + "_" + locale + ".qm";

    // Falls die Sprache manuell gesetzt wurde.
    QSettings clamui_conf(QSettings::NativeFormat, QSettings::UserScope,
                             APP_TITLE, APP_NAME);
    clamui_conf.beginGroup("ClamUI");
    bool languageSet = clamui_conf.value("Language_Manually", false).toBool();
    QString currLanguage = clamui_conf.value(
                     "languageFileName", defaultLanguage).toString();
    bool hideWindow =clamui_conf.value("Hide_Window", false).toBool();
    clamui_conf.endGroup();

    // Systemsprache aus der Umgebungsvariable des Systems lesen.
    // Read the system language from the system environment.
    QTranslator qtTranslator;
    qtTranslator.load("qt_" + QLocale::system().name(),
                      QLibraryInfo::location(QLibraryInfo::TranslationsPath));
    app.installTranslator(&qtTranslator);

    if (languageSet == false) {
        // Langauge from system settings
        myappTranslator.load(LANG_PATH
                             + APP_NAME + "_"
                             + locale + ".qm");
        app.installTranslator(&myappTranslator);
      } else {
        // Language manually.
        myappTranslator.load(LANG_PATH + currLanguage);
        app.installTranslator(&myappTranslator);
      }

    /*
     * Check if there is a ClamAV directory.
     * In this directory are the config files stored.
     */
    if (!clamDir.exists(CLAMAV_PATH))
        clamDir.mkdir(CLAMAV_PATH);

    /*
     * The default quarantine folder.
     */
    if (!clamDir.exists(CLAMAV_PATH + "quarantine"))
        clamDir.mkdir(CLAMAV_PATH + "quarantine");

    /*
     * The directory for the virus definition stored.
     */
    if (!clamDir.exists(CLAMAV_VDB_PATH))
        clamDir.mkdir(CLAMAV_VDB_PATH);

    /*
     * Check for an existing SQLite3 database.
     */
    if (!dbFile.exists(APP_CONFIG_PATH + SQLITE_DB_NAME)){

        SQLite_DB sqliteDB;
        sqliteDB.connectDB();
    }

    /*
     * Check for an existing config file.
     *
     * If not run the wizard.
     */
    if (!confFile.exists(APP_CONFIG_PATH + APP_NAME + ".conf")){

        FirstRunWizard startWizard;
        startWizard.show();
        return app.exec();

    }

    /*
     * If exists run clamui.
     */
    if (confFile.exists(APP_CONFIG_PATH + APP_NAME + ".conf")){

        ClamUI startClamUI;
        if (hideWindow){

            startClamUI.hide();
            return app.exec();

        } else {

            startClamUI.show();
            return app.exec();
        }
    }

} // main end
Esempio n. 4
0
int main(int argc, char *argv[])
{
    qRegisterMetaType<JoyButtonSlot*>();
    qRegisterMetaType<InputDevice*>();
    qRegisterMetaType<AutoProfileInfo*>();

    QTextStream outstream(stdout);
    QTextStream errorstream(stderr);

    // If running Win version, check if an explicit style
    // was defined on the command-line. If so, make a note
    // of it.
#ifdef Q_OS_WIN
    bool styleChangeFound = false;
    for (int i=0; i < argc && !styleChangeFound; i++)
    {
        char *tempchrstr = argv[i];
        QString temp = QString::fromUtf8(tempchrstr);
        if (temp == "-style")
        {
            styleChangeFound = true;
        }
    }
#endif

    CommandLineUtility cmdutility;
    QStringList cmdarguments = PadderCommon::arguments(argc, argv);
    cmdarguments.removeFirst();
    cmdutility.parseArguments(cmdarguments);

    Logger appLogger(&outstream, &errorstream);

    if (cmdutility.hasError())
    {
        appLogger.LogError(cmdutility.getErrorText());
        return 1;
    }
    else if (cmdutility.isHelpRequested())
    {
        appLogger.LogInfo(cmdutility.generateHelpString(), false);
        //cmdutility.printHelp();
        return 0;
    }
    else if (cmdutility.isVersionRequested())
    {
        appLogger.LogInfo(cmdutility.generateVersionString());
        //cmdutility.printVersionString();
        return 0;
    }

    if (cmdutility.getCurrentLogLevel() != appLogger.getCurrentLogLevel())
    {
        appLogger.setLogLevel(cmdutility.getCurrentLogLevel());
    }

    Q_INIT_RESOURCE(resources);

    QDir configDir(PadderCommon::configPath);
    if (!configDir.exists())
    {
        configDir.mkpath(PadderCommon::configPath);
    }

    QMap<SDL_JoystickID, InputDevice*> *joysticks = new QMap<SDL_JoystickID, InputDevice*>();

    // Cross-platform way of performing IPC. Currently,
    // only establish a connection and then disconnect.
    // In the future, there might be a reason to actually send
    // messages to the QLocalServer.
    QLocalSocket socket;
    socket.connectToServer(PadderCommon::localSocketKey);
    socket.waitForConnected(1000);
    if (socket.state() == QLocalSocket::ConnectedState)
    {
        // An instance of this program is already running.
        // Save app config and exit.
        QApplication a(argc, argv);
        AntiMicroSettings settings(PadderCommon::configFilePath, QSettings::IniFormat);
        InputDaemon *joypad_worker = new InputDaemon(joysticks, &settings, false);
        MainWindow w(joysticks, &cmdutility, &settings, false);

        if (!cmdutility.hasError() && cmdutility.hasProfile())
        {
            w.saveAppConfig();
        }

        joypad_worker->quit();
        w.removeJoyTabs();

        settings.sync();
        socket.disconnectFromServer();

        deleteInputDevices(joysticks);
        delete joysticks;
        joysticks = 0;

        delete joypad_worker;
        joypad_worker = 0;

        return 0;
    }

    LocalAntiMicroServer *localServer = 0;
    QApplication *a = 0;

#ifndef Q_OS_WIN
    if (cmdutility.launchAsDaemon())
    {
        pid_t pid, sid;

        //Fork the Parent Process
        pid = fork();

        if (pid == 0)
        {
            appLogger.LogInfo(QObject::tr("Daemon launched"));
            //outstream << QObject::tr("Daemon launched") << endl;

            a = new QApplication(argc, argv);
            localServer = new LocalAntiMicroServer();
            localServer->startLocalServer();
        }
        else if (pid < 0)
        {
            appLogger.LogError(QObject::tr("Failed to launch daemon"));
            //errorstream << QObject::tr("Failed to launch daemon") << endl;

            deleteInputDevices(joysticks);
            delete joysticks;
            joysticks = 0;

            exit(EXIT_FAILURE);
        }
        //We got a good pid, Close the Parent Process
        else if (pid > 0)
        {
            appLogger.LogInfo(QObject::tr("Launching daemon"));
            //outstream << QObject::tr("Launching daemon") << endl;

            deleteInputDevices(joysticks);
            delete joysticks;
            joysticks = 0;

            exit(EXIT_SUCCESS);
        }


    #ifdef WITH_X11
        #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))

        if (QApplication::platformName() == QStringLiteral("xcb"))
        {
        #endif

        if (cmdutility.getDisplayString().isEmpty())
        {
            X11Extras::getInstance()->syncDisplay();
        }
        else
        {
            X11Extras::getInstance()->syncDisplay(cmdutility.getDisplayString());
            if (X11Extras::getInstance()->display() == NULL)
            {
                appLogger.LogError(QObject::tr("Display string \"%1\" is not valid.").arg(cmdutility.getDisplayString()));
                //errorstream << QObject::tr("Display string \"%1\" is not valid.").arg(cmdutility.getDisplayString()) << endl;

                deleteInputDevices(joysticks);
                delete joysticks;
                joysticks = 0;

                delete localServer;
                localServer = 0;

                X11Extras::deleteInstance();

                exit(EXIT_FAILURE);
            }
        }

        #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
        }
        #endif

    #endif

        //Change File Mask
        umask(0);

        //Create a new Signature Id for our child
        sid = setsid();
        if (sid < 0)
        {
            appLogger.LogError(QObject::tr("Failed to set a signature id for the daemon"));
            //errorstream << QObject::tr("Failed to set a signature id for the daemon") << endl;

            deleteInputDevices(joysticks);
            delete joysticks;
            joysticks = 0;

            delete localServer;
            localServer = 0;

    #ifdef WITH_X11
        #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
            if (QApplication::platformName() == QStringLiteral("xcb"))
            {
        #endif
            X11Extras::deleteInstance();

        #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
            }
        #endif
    #endif

            exit(EXIT_FAILURE);
        }

        if ((chdir("/")) < 0)
        {
            appLogger.LogError(QObject::tr("Failed to change working directory to /"));
            //errorstream << QObject::tr("Failed to change working directory to /")
            //            << endl;

            deleteInputDevices(joysticks);
            delete joysticks;
            joysticks = 0;

            delete localServer;
            localServer = 0;

    #ifdef WITH_X11
        #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))

            if (QApplication::platformName() == QStringLiteral("xcb"))
            {
        #endif
            X11Extras::deleteInstance();
        #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
            }
        #endif
    #endif

            exit(EXIT_FAILURE);
        }

        //Close Standard File Descriptors
        close(STDIN_FILENO);
        close(STDOUT_FILENO);
        close(STDERR_FILENO);
    }
    else
    {
        a = new QApplication(argc, argv);
        localServer = new LocalAntiMicroServer();
        localServer->startLocalServer();

    #ifdef WITH_X11
        #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))

        if (QApplication::platformName() == QStringLiteral("xcb"))
        {
        #endif
        if (!cmdutility.getDisplayString().isEmpty())
        {
            X11Extras::getInstance()->syncDisplay(cmdutility.getDisplayString());
            if (X11Extras::getInstance()->display() == NULL)
            {
                appLogger.LogError(QObject::tr("Display string \"%1\" is not valid.").arg(cmdutility.getDisplayString()));
                //errorstream << QObject::tr("Display string \"%1\" is not valid.").arg(cmdutility.getDisplayString()) << endl;

                deleteInputDevices(joysticks);
                delete joysticks;
                joysticks = 0;

                delete localServer;
                localServer = 0;

                X11Extras::deleteInstance();

                exit(EXIT_FAILURE);
            }
        }

        #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
        }
        #endif
    #endif
    }

#else
    a = new QApplication (argc, argv);
    localServer = new LocalAntiMicroServer();
    localServer->startLocalServer();
#endif

    a->setQuitOnLastWindowClosed(false);

    //QString defaultStyleName = qApp->style()->objectName();

    // If running Win version and no explicit style was
    // defined, use the style Fusion by default. I find the
    // windowsvista style a tad ugly
#ifdef Q_OS_WIN
    if (!styleChangeFound)
    {
        qApp->setStyle(QStyleFactory::create("Fusion"));
    }

    QIcon::setThemeName("/");
#endif

    AntiMicroSettings settings(PadderCommon::configFilePath, QSettings::IniFormat);
    settings.importFromCommandLine(cmdutility);

    QString targetLang = QLocale::system().name();
    if (settings.contains("Language"))
    {
        targetLang = settings.value("Language").toString();
    }

    QTranslator qtTranslator;
    qtTranslator.load(QString("qt_").append(targetLang), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
    a->installTranslator(&qtTranslator);

    QTranslator myappTranslator;
#if defined(Q_OS_UNIX)
    myappTranslator.load(QString("antimicro_").append(targetLang), QApplication::applicationDirPath().append("/../share/antimicro/translations"));
#elif defined(Q_OS_WIN)
    myappTranslator.load(QString("antimicro_").append(targetLang), QApplication::applicationDirPath().append("\\share\\antimicro\\translations"));
#endif
    a->installTranslator(&myappTranslator);

    InputDaemon *joypad_worker = new InputDaemon(joysticks, &settings);

#ifndef Q_OS_WIN
    // Have program handle SIGTERM
    struct sigaction termaction;
    termaction.sa_handler = &termSignalTermHandler;
    sigemptyset(&termaction.sa_mask);
    termaction.sa_flags = 0;

    sigaction(SIGTERM, &termaction, 0);

    // Have program handle SIGINT
    struct sigaction termint;
    termint.sa_handler = &termSignalIntHandler;
    sigemptyset(&termint.sa_mask);
    termint.sa_flags = 0;

    sigaction(SIGINT, &termint, 0);

#endif

    if (cmdutility.shouldListControllers())
    {
        AppLaunchHelper mainAppHelper(&settings, false);
        mainAppHelper.printControllerList(joysticks);

        joypad_worker->quit();

        deleteInputDevices(joysticks);
        delete joysticks;
        joysticks = 0;

        delete joypad_worker;
        joypad_worker = 0;

        delete localServer;
        localServer = 0;

    #ifdef WITH_X11
        #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
        if (QApplication::platformName() == QStringLiteral("xcb"))
        {
        #endif
        X11Extras::deleteInstance();
        #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
        }
        #endif
    #endif

        delete a;
        a = 0;

        return 0;
    }

#ifdef USE_SDL_2
    else if (cmdutility.shouldMapController())
    {
        MainWindow *w = new MainWindow(joysticks, &cmdutility, &settings);

        QObject::connect(a, SIGNAL(aboutToQuit()), w, SLOT(removeJoyTabs()));
        QObject::connect(a, SIGNAL(aboutToQuit()), joypad_worker, SLOT(quit()));

        int app_result = a->exec();

        deleteInputDevices(joysticks);
        delete joysticks;
        joysticks = 0;

        delete joypad_worker;
        joypad_worker = 0;

        delete localServer;
        localServer = 0;

#ifdef WITH_X11
    #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
        if (QApplication::platformName() == QStringLiteral("xcb"))
        {
    #endif
        X11Extras::deleteInstance();
    #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
        }
    #endif
#endif

        delete w;
        w = 0;

        delete a;
        a = 0;

        return app_result;
    }
#endif

#ifdef Q_OS_UNIX
    bool status = true;
    EventHandlerFactory *factory = EventHandlerFactory::getInstance(cmdutility.getEventGenerator());
    if (!factory)
    {
        status = false;
    }
    else
    {
        status = factory->handler()->init();
    }

#if defined(WITH_UINPUT) && defined(WITH_XTEST)
    // Use xtest as a fallback.
    if (!status && cmdutility.getEventGenerator() != EventHandlerFactory::fallBackIdentifier())
    {
        QString eventDisplayName = EventHandlerFactory::handlerDisplayName(
                    EventHandlerFactory::fallBackIdentifier());
        appLogger.LogInfo(QObject::tr("Attempting to use fallback option %1 for event generation.")
                                     .arg(eventDisplayName));
        //outstream << QObject::tr("Attempting to use fallback option %1 for event generation.")
        //             .arg(eventDisplayName) << endl;

        factory->deleteInstance();
        factory = EventHandlerFactory::getInstance(EventHandlerFactory::fallBackIdentifier());
        if (!factory)
        {
            status = false;
        }
        else
        {
            status = factory->handler()->init();
        }
    }
#endif

    if (!status)
    {
        appLogger.LogError(QObject::tr("Failed to open event generator. Exiting."));
        //errorstream << QObject::tr("Failed to open event generator. Exiting.") << endl;

        joypad_worker->quit();

        deleteInputDevices(joysticks);
        delete joysticks;
        joysticks = 0;

        delete joypad_worker;
        joypad_worker = 0;

        delete localServer;
        localServer = 0;

    #ifdef WITH_X11
        #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))

        if (QApplication::platformName() == QStringLiteral("xcb"))
        {
        #endif
        X11Extras::deleteInstance();
        #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
        }
        #endif
    #endif

        delete a;
        a = 0;

        return EXIT_FAILURE;
    }
    else
    {
        appLogger.LogInfo(QObject::tr("Using %1 as the event generator.").arg(factory->handler()->getName()));
        //outstream << QObject::tr("Using %1 as the event generator.").arg(factory->handler()->getName())
        //          << endl;
        factory->handler()->printPostMessages();
    }
#endif

    AntKeyMapper::getInstance(cmdutility.getEventGenerator());

    MainWindow *w = new MainWindow(joysticks, &cmdutility, &settings);

    FirstRunWizard *runWillard = 0;

    if (w->getGraphicalStatus() && FirstRunWizard::shouldDisplay(&settings))
    {
        runWillard = new FirstRunWizard(&settings, &qtTranslator, &myappTranslator);
        QObject::connect(runWillard, SIGNAL(finished(int)), w, SLOT(changeWindowStatus()));
        runWillard->show();
    }
    else
    {
        w->changeWindowStatus();
    }

    w->setAppTranslator(&qtTranslator);
    w->setTranslator(&myappTranslator);

    AppLaunchHelper mainAppHelper(&settings, w->getGraphicalStatus());
    mainAppHelper.initRunMethods();

    QObject::connect(joypad_worker,
                     SIGNAL(joysticksRefreshed(QMap<SDL_JoystickID, InputDevice*>*)),
                     w, SLOT(fillButtons(QMap<SDL_JoystickID, InputDevice*>*)));

    QObject::connect(w, SIGNAL(joystickRefreshRequested()), joypad_worker, SLOT(refresh()));
    QObject::connect(joypad_worker, SIGNAL(joystickRefreshed(InputDevice*)),
                     w, SLOT(fillButtons(InputDevice*)));

    QObject::connect(a, SIGNAL(aboutToQuit()), localServer, SLOT(close()));
    QObject::connect(a, SIGNAL(aboutToQuit()), w, SLOT(saveAppConfig()));
    QObject::connect(a, SIGNAL(aboutToQuit()), w, SLOT(removeJoyTabs()));
    QObject::connect(a, SIGNAL(aboutToQuit()), joypad_worker, SLOT(quit()));

#ifdef Q_OS_WIN
    QObject::connect(a, SIGNAL(aboutToQuit()), &mainAppHelper, SLOT(appQuitPointerPrecision()));
#endif
    QObject::connect(localServer, SIGNAL(clientdisconnect()), w, SLOT(handleInstanceDisconnect()));

#ifdef USE_SDL_2
    QObject::connect(w, SIGNAL(mappingUpdated(QString,InputDevice*)), joypad_worker, SLOT(refreshMapping(QString,InputDevice*)));
    QObject::connect(joypad_worker, SIGNAL(deviceUpdated(int,InputDevice*)), w, SLOT(testMappingUpdateNow(int,InputDevice*)));
    QObject::connect(joypad_worker, SIGNAL(deviceRemoved(SDL_JoystickID)), w, SLOT(removeJoyTab(SDL_JoystickID)));
    QObject::connect(joypad_worker, SIGNAL(deviceAdded(InputDevice*)), w, SLOT(addJoyTab(InputDevice*)));
#endif

#ifdef Q_OS_WIN
    // Raise process priority. Helps reduce timer delays caused by
    // the running of other processes.
    bool raisedPriority = WinExtras::raiseProcessPriority();
    if (!raisedPriority)
    {
        appLogger.LogInfo(QObject::tr("Could not raise process priority."));
        //outstream << QObject::tr("Could not raise process priority.") << endl;
    }
#else
    // Raise main thread prority. Helps reduce timer delays caused by
    // the running of other processes.
    QThread::currentThread()->setPriority(QThread::HighPriority);
#endif

    int app_result = a->exec();

    appLogger.LogInfo(QObject::tr("Quitting Program"));

    deleteInputDevices(joysticks);
    delete joysticks;
    joysticks = 0;

    delete joypad_worker;
    joypad_worker = 0;

    delete localServer;
    localServer = 0;

    AntKeyMapper::getInstance()->deleteInstance();

#ifdef Q_OS_UNIX
    #ifdef WITH_X11
        #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))

    if (QApplication::platformName() == QStringLiteral("xcb"))
    {
        #endif
    X11Extras::deleteInstance();
        #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
    }
        #endif
    #endif

    EventHandlerFactory::getInstance()->handler()->cleanup();
    EventHandlerFactory::getInstance()->deleteInstance();
#endif

    delete w;
    w = 0;

    delete a;
    a = 0;

    return app_result;
}
Esempio n. 5
0
int main(int argc, char* argv[])
{
    Application app(argc, argv);

    // Set the organization / application names must be done very early because some other
    // classes will use these values (for example QSettings, Debug (for the file logging path))!
    Application::setOrganizationName("LibrePCB");
    Application::setOrganizationDomain("librepcb.org");
#ifdef GIT_BRANCH
    Application::setApplicationName(QString("LibrePCB_git-%1").arg(GIT_BRANCH));
#else
    Application::setApplicationName("LibrePCB");
#endif
    Application::setApplicationVersion(Version(QString("%1.%2.%3").arg(APP_VERSION_MAJOR).arg(APP_VERSION_MINOR).arg(APP_VERSION_PATCH)));


    Debug::instance(); // this creates the Debug object and installs the message handler.


    // Install Qt translations
    QTranslator qtTranslator;
    qtTranslator.load("qt_" % QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
    app.installTranslator(&qtTranslator);

    // Install system language translations (all system languages defined in the system settings, in the defined order)
    QTranslator systemTranslator;
    systemTranslator.load(QLocale::system(), "librepcb", "_", ":/i18n/");
    app.installTranslator(&systemTranslator);

    // Install language translations (like "de" for German)
    QTranslator appTranslator1;
    appTranslator1.load("librepcb_" % QLocale::system().name().split("_").at(0), ":/i18n");
    app.installTranslator(&appTranslator1);

    // Install language/country translations (like "de_ch" for German/Switzerland)
    QTranslator appTranslator2;
    appTranslator2.load("librepcb_" % QLocale::system().name(), ":/i18n");
    app.installTranslator(&appTranslator2);


    Application::setQuitOnLastWindowClosed(false);


    // this is to remove the ugly frames around widgets in all status bars...
    // (from http://www.qtcentre.org/threads/1904)
    app.setStyleSheet("QStatusBar::item { border: 0px solid black; }");



    // Initialization finished, open the workspace (or show the first run wizard)...
    FilePath wsPath(Workspace::getMostRecentlyUsedWorkspacePath());
    if (!Workspace::isValidWorkspacePath(wsPath))
    {
        FirstRunWizard wizard;
        if (wizard.exec() != QDialog::Accepted) return 0;
        wsPath = wizard.getWorkspaceFilePath();
        if (wizard.getCreateNewWorkspace())
        {
            if (!Workspace::createNewWorkspace(wsPath))
            {
                QMessageBox::critical(0, Application::translate("Workspace",
                    "Error"), Application::translate("Workspace", "Could not "
                    "create the workspace directory. Check file permissions."));
                return 0; // TODO: Show the wizard again instead of closing the application
            }
        }
        Workspace::setMostRecentlyUsedWorkspacePath(wsPath);
    }

    try
    {
        Workspace ws(wsPath);   // The Workspace constructor can throw an exception.
        ControlPanel p(ws);
        p.show();

        return appExec();
    }
    catch (UserCanceled& e)
    {
        return 0; // quit the application
    }
    catch (Exception& e)
    {
        QMessageBox::critical(0, Application::translate("Workspace",
            "Cannot open the workspace"), QString(Application::translate(
            "Workspace", "The workspace \"%1\" cannot be opened: %2"))
            .arg(wsPath.toNative(), e.getUserMsg()));
        return 0; // quit the application
    }

    return 0;
}