#include <QPixmapCache>
#include <QTranslator>
#include <QFileInfo>
#include <QFileDialog>
#include <QFontDialog>
#include <QMessageBox>
#include <QTimer>
#include <QMap>
#include <QStyleFactory>
#include <QHeaderView>
#include <QBitArray>
#include <QAction>
#include <QPair>
#include <QLocale>

#include "options.h"
#include "emuopt.h"
#include "preview.h"
#include "flyer.h"
#include "qmc2main.h"
#include "gamelist.h"
#include "macros.h"
#include "unzip.h"
#include "keyseqscan.h"
#include "romalyzer.h"
#include "romstatusexport.h"
#if QMC2_JOYSTICK == 1
#include "joystick.h"
#include "joyfuncscan.h"
#endif
#if defined(QMC2_SDLMESS)
#include "messdevcfg.h"
#endif

// external global variables
extern MainWindow *qmc2MainWindow;
extern Options *qmc2Options;
extern bool qmc2GuiReady;
extern bool qmc2CleaningUp;
extern bool qmc2StartingUp;
extern bool qmc2EarlyStartup;
extern bool qmc2ReloadActive;
extern bool qmc2ScaledPreview;
extern bool qmc2ScaledFlyer;
extern bool qmc2SmoothScaling;
extern bool qmc2RetryLoadingImages;
extern bool qmc2ParentImageFallback;
extern bool qmc2VerifyActive;
extern bool qmc2ImageCheckActive;
extern bool qmc2SampleCheckActive;
extern bool qmc2UsePreviewFile;
extern bool qmc2UseFlyerFile;
extern bool qmc2UseIconFile;
extern bool qmc2AutomaticReload;
extern bool qmc2SuppressQtMessages;
extern bool qmc2ShowGameName;
extern bool qmc2ShowGameNameOnlyWhenRequired;
extern bool qmc2StatesTogglesEnabled;
extern bool qmc2VariantSwitchReady;
extern int qmc2GamelistResponsiveness;
extern int qmc2UpdateDelay;
extern QTranslator *qmc2Translator;
extern QTranslator *qmc2QtTranslator;
extern EmulatorOptions *qmc2GlobalEmulatorOptions;
extern EmulatorOptions *qmc2EmulatorOptions;
extern Preview *qmc2Preview;
extern Flyer *qmc2Flyer;
extern Gamelist *qmc2Gamelist;
extern ROMAlyzer *qmc2ROMAlyzer;
extern ROMStatusExporter *qmc2ROMStatusExporter;
extern int qmc2SortCriteria;
extern Qt::SortOrder qmc2SortOrder;
extern QMap<QString, QString> qmc2GamelistNameMap;
extern QSettings *qmc2Config;
extern QBitArray qmc2Filter;
extern unzFile qmc2IconFile;
extern QMap<QString, QPair<QString, QAction *> > qmc2ShortcutMap;
extern QMap<QString, QString> qmc2CustomShortcutMap;
extern QMap<QString, QString> qmc2JoystickFunctionMap;
extern KeyPressFilter *qmc2KeyPressFilter;
extern QMap<QString, int> qmc2QtKeyMap;
extern QMap<QString, QByteArray *> qmc2GameInfoDB;
#if defined(QMC2_SDLMAME)
extern QMap<QString, QByteArray *> qmc2EmuInfoDB;
#endif
#if QMC2_JOYSTICK == 1
extern Joystick *qmc2Joystick;
#endif
#if defined(QMC2_SDLMESS)
extern MESSDeviceConfigurator *qmc2MESSDeviceConfigurator;
#endif

Options::Options(QWidget *parent)
  : QDialog(parent, Qt::Dialog | Qt::SubWindow)
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::Options(QWidget *parent = 0x" + QString::number((ulong)parent, 16) + ")");
#endif

  qmc2Filter.resize(QMC2_ROMSTATE_COUNT);
  QSettings::setPath(QSettings::IniFormat, QSettings::SystemScope, QMC2_SYSCONF_PATH);
  QString userScopePath = QMC2_DOT_PATH;
  QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, userScopePath);
  QDir userScopeDir(userScopePath);
  if ( !userScopeDir.exists() )
    userScopeDir.mkdir(userScopePath);
  config = new QSettings(QSettings::IniFormat, QSettings::UserScope, "qmc2");

  setupUi(this);

#if defined(QMC2_SDLMESS)
  toolButtonBrowseEmuInfoDB->setVisible(FALSE);
  checkBoxProcessEmuInfoDB->setVisible(FALSE);
  checkBoxCompressEmuInfoDB->setVisible(FALSE);
  lineEditEmuInfoDB->setVisible(FALSE);
  labelEmuInfoDB->setVisible(FALSE);
  labelEmuInfoDBPic->setVisible(FALSE);
  labelGameInfoDB->setText(tr("Machine info DB"));
  lineEditGameInfoDB->setToolTip(tr("Machine information database - MESS sysinfo.dat (read)"));
  toolButtonBrowseGameInfoDB->setToolTip(tr("Browse machine information database (MESS sysinfo.dat)"));
  tabWidgetFrontendSettings->setTabText(QMC2_OPTIONS_FE_MACHINELIST_INDEX, tr("Machine &list"));
  comboBoxSortCriteria->setItemText(QMC2_SORTCRITERIA_DESCRIPTION, tr("Machine description"));
  comboBoxSortCriteria->setItemText(QMC2_SORTCRITERIA_MACHINENAME, tr("Machine name"));
  spinBoxResponsiveness->setToolTip(tr("Number of item insertions between machine list updates during reload (higher means faster, but makes the GUI less responsive)"));
  spinBoxUpdateDelay->setToolTip(tr("Delay update of any machine details (preview, flyer, info, configuration, ...) by how many milliseconds?"));
  checkBoxSortOnline->setToolTip(tr("Sort machine list while reloading (slower)"));
#endif

  // shortcuts
  qmc2ShortcutMap["Ctrl+1"] = QPair<QString, QAction *>(tr("Check all ROM states"), NULL);
  qmc2ShortcutMap["Ctrl+2"] = QPair<QString, QAction *>(tr("Check all sample sets"), NULL);
  qmc2ShortcutMap["Ctrl+3"] = QPair<QString, QAction *>(tr("Check preview images"), NULL);
  qmc2ShortcutMap["Ctrl+4"] = QPair<QString, QAction *>(tr("Check flyer images"), NULL);
  qmc2ShortcutMap["Ctrl+5"] = QPair<QString, QAction *>(tr("Check icon images"), NULL);
  qmc2ShortcutMap["Ctrl+A"] = QPair<QString, QAction *>(tr("About QMC2"), NULL);
  qmc2ShortcutMap["Ctrl+D"] = QPair<QString, QAction *>(tr("Analyze current game"), NULL);
  qmc2ShortcutMap["Ctrl+E"] = QPair<QString, QAction *>(tr("Export ROM Status"), NULL);
  qmc2ShortcutMap["Ctrl+F"] = QPair<QString, QAction *>(tr("Copy game to favorites"), NULL);
  qmc2ShortcutMap["Ctrl+H"] = QPair<QString, QAction *>(tr("Online documentation"), NULL);
  qmc2ShortcutMap["Ctrl+I"] = QPair<QString, QAction *>(tr("Clear image cache"), NULL);
  qmc2ShortcutMap["Ctrl+Shift+A"] = QPair<QString, QAction *>(tr("Setup arcade mode"), NULL);
  qmc2ShortcutMap["Ctrl+N"] = QPair<QString, QAction *>(tr("Clear icon cache"), NULL);
  qmc2ShortcutMap["Ctrl+O"] = QPair<QString, QAction *>(tr("Open options dialog"), NULL);
  qmc2ShortcutMap["Ctrl+P"] = QPair<QString, QAction *>(tr("Play selected game"), NULL);
  qmc2ShortcutMap["Ctrl+Q"] = QPair<QString, QAction *>(tr("About Qt"), NULL);
  qmc2ShortcutMap["Ctrl+R"] = QPair<QString, QAction *>(tr("Reload gamelist"), NULL);
  qmc2ShortcutMap["Ctrl+S"] = QPair<QString, QAction *>(tr("Check game's ROM state"), NULL);
  qmc2ShortcutMap["Ctrl+T"] = QPair<QString, QAction *>(tr("Recreate template map"), NULL);
  qmc2ShortcutMap["Ctrl+X"] = QPair<QString, QAction *>(tr("Stop processing / exit QMC2"), NULL);
  qmc2ShortcutMap["Ctrl+Z"] = QPair<QString, QAction *>(tr("Open ROMAlyzer dialog"), NULL);
  qmc2ShortcutMap["Ctrl+Alt+C"] = QPair<QString, QAction *>(tr("Toggle ROM state C"), NULL);
  qmc2ShortcutMap["Ctrl+Alt+M"] = QPair<QString, QAction *>(tr("Toggle ROM state M"), NULL);
  qmc2ShortcutMap["Ctrl+Alt+I"] = QPair<QString, QAction *>(tr("Toggle ROM state I"), NULL);
  qmc2ShortcutMap["Ctrl+Alt+N"] = QPair<QString, QAction *>(tr("Toggle ROM state N"), NULL);
  qmc2ShortcutMap["Ctrl+Alt+U"] = QPair<QString, QAction *>(tr("Toggle ROM state U"), NULL);
  qmc2ShortcutMap["Ctrl+Alt+1"] = QPair<QString, QAction *>(tr("Launch QMC2 for SDLMAME"), NULL);
  qmc2ShortcutMap["Ctrl+Alt+2"] = QPair<QString, QAction *>(tr("Launch QMC2 for SDLMESS"), NULL);
  qmc2ShortcutMap["F5"] = QPair<QString, QAction *>(tr("Gamelist with full detail"), NULL);
  qmc2ShortcutMap["F6"] = QPair<QString, QAction *>(tr("Parent / clone hierarchy"), NULL);
  qmc2ShortcutMap["F11"] = QPair<QString, QAction *>(tr("Toggle fullscreen"), NULL);
  qmc2ShortcutMap["F12"] = QPair<QString, QAction *>(tr("Toggle arcade mode"), NULL);
  qmc2ShortcutMap["Meta+F"] = QPair<QString, QAction *>(tr("Show FPS (arcade mode)"), NULL);
  qmc2ShortcutMap["Meta+F12"] = QPair<QString, QAction *>(tr("Take snapshot (arcade mode)"), NULL);
#if QMC2_USE_PHONON_API
  qmc2ShortcutMap["Ctrl+Alt+-"] = QPair<QString, QAction *>(tr("Previous track (audio player)"), NULL);
  qmc2ShortcutMap["Ctrl+Alt++"] = QPair<QString, QAction *>(tr("Next track (audio player)"), NULL);
  qmc2ShortcutMap["Ctrl+Alt+B"] = QPair<QString, QAction *>(tr("Fast backward (audio player)"), NULL);
  qmc2ShortcutMap["Ctrl+Alt+F"] = QPair<QString, QAction *>(tr("Fast forward (audio player)"), NULL);
  qmc2ShortcutMap["Ctrl+Alt+S"] = QPair<QString, QAction *>(tr("Stop track (audio player)"), NULL);
  qmc2ShortcutMap["Ctrl+Alt+#"] = QPair<QString, QAction *>(tr("Pause track (audio player)"), NULL);
  qmc2ShortcutMap["Ctrl+Alt+P"] = QPair<QString, QAction *>(tr("Play track (audio player)"), NULL);
  qmc2ShortcutMap["Ctrl+Alt+PgUp"] = QPair<QString, QAction *>(tr("Raise volume (audio player)"), NULL);
  qmc2ShortcutMap["Ctrl+Alt+PgDown"] = QPair<QString, QAction *>(tr("Lower volume (audio player)"), NULL);
#endif

  // special keys
  qmc2ShortcutMap["+"] = QPair<QString, QAction *>(tr("Plus (+)"), NULL);
  qmc2ShortcutMap["-"] = QPair<QString, QAction *>(tr("Minus (-)"), NULL);
  qmc2ShortcutMap["Down"] = QPair<QString, QAction *>(tr("Cursor down"), NULL);
  qmc2ShortcutMap["End"] = QPair<QString, QAction *>(tr("End"), NULL);
  qmc2ShortcutMap["Esc"] = QPair<QString, QAction *>(tr("Escape"), NULL);
  qmc2ShortcutMap["Left"] = QPair<QString, QAction *>(tr("Cursor left"), NULL);
  qmc2ShortcutMap["Home"] = QPair<QString, QAction *>(tr("Home"), NULL);
  qmc2ShortcutMap["PgDown"] = QPair<QString, QAction *>(tr("Page down"), NULL);
  qmc2ShortcutMap["PgUp"] = QPair<QString, QAction *>(tr("Page up"), NULL);
  qmc2ShortcutMap["Return"] = QPair<QString, QAction *>(tr("Enter key"), NULL);
  qmc2ShortcutMap["Right"] = QPair<QString, QAction *>(tr("Cursor right"), NULL);
  qmc2ShortcutMap["Tab"] = QPair<QString, QAction *>(tr("Tabulator"), NULL);
  qmc2ShortcutMap["Up"] = QPair<QString, QAction *>(tr("Cursor up"), NULL);

  if ( !config->isWritable() ) {
    qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: configuration is not writeable, please check access permissions for ") + config->fileName());
  }

#if QMC2_JOYSTICK != 1
  tabWidgetFrontendSettings->removeTab(tabWidgetFrontendSettings->indexOf(tabFrontendJoystick));
#else
  joystick = NULL;
  joystickCalibrationWidget = NULL;
  joystickTestWidget = NULL;
  scrollArea = new QScrollArea(groupBoxCalibrationAndTest);
  scrollArea->hide();
  scrollArea->setWidgetResizable(TRUE);
#endif

  restoreCurrentConfig();
}

Options::~Options()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::~Options()");
#endif

  if ( config->value(QMC2_FRONTEND_PREFIX + "GUI/SaveLayout").toBool() ) {
    config->setValue(QMC2_FRONTEND_PREFIX + "Layout/OptionsWidget/FrontendTab", tabWidgetFrontendSettings->currentIndex());
    config->setValue(QMC2_FRONTEND_PREFIX + "Layout/OptionsWidget/MAMETab", tabWidgetGlobalMAMESetup->currentIndex());
    config->setValue(QMC2_FRONTEND_PREFIX + "Layout/OptionsWidget/OptionsTab", tabWidgetOptions->currentIndex());
    config->setValue(QMC2_FRONTEND_PREFIX + "Layout/OptionsWidget/ShortcutsHeaderState", treeWidgetShortcuts->header()->saveState());
#if QMC2_JOYSTICK == 1
    config->setValue(QMC2_FRONTEND_PREFIX + "Layout/OptionsWidget/JoyMapHeaderState", treeWidgetJoystickMappings->header()->saveState());
#endif
  }

  delete config;
  close();
}

void Options::apply()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::apply()");
#endif

  qmc2MainWindow->statusBar()->setVisible(config->value(QMC2_FRONTEND_PREFIX + "GUI/Statusbar", TRUE).toBool());
  qmc2MainWindow->toolbar->setVisible(config->value(QMC2_FRONTEND_PREFIX + "GUI/Toolbar", TRUE).toBool());

  // adjust icon sizes of buttons
  QFont f;
  f.fromString(config->value(QMC2_FRONTEND_PREFIX + "GUI/Font").toString());
  qApp->setFont(f);
  QFontMetrics fm(f);
  QSize iconSize(fm.height() - 3, fm.height() - 3);
  qmc2MainWindow->treeWidgetGamelist->setIconSize(iconSize);
  qmc2MainWindow->treeWidgetHierarchy->setIconSize(iconSize);
  qmc2MainWindow->treeWidgetEmulators->setIconSize(iconSize);
  pushButtonApply->setIconSize(iconSize);
  pushButtonRestore->setIconSize(iconSize);
  pushButtonDefault->setIconSize(iconSize);
  toolButtonBrowseFont->setIconSize(iconSize);
  toolButtonBrowseTemporaryFile->setIconSize(iconSize);
  toolButtonBrowseFrontendLogFile->setIconSize(iconSize);
  toolButtonBrowseFavoritesFile->setIconSize(iconSize);
  toolButtonBrowseHistoryFile->setIconSize(iconSize);
  toolButtonBrowseGamelistCacheFile->setIconSize(iconSize);
  toolButtonBrowseROMStateCacheFile->setIconSize(iconSize);
  toolButtonBrowseDataDirectory->setIconSize(iconSize);
  toolButtonBrowseGameInfoDB->setIconSize(iconSize);
#if defined(QMC2_SDLMAME)
  toolButtonBrowseEmuInfoDB->setIconSize(iconSize);
#endif
  toolButtonBrowsePreviewDirectory->setIconSize(iconSize);
  toolButtonBrowsePreviewFile->setIconSize(iconSize);
  toolButtonBrowseFlyerDirectory->setIconSize(iconSize);
  toolButtonBrowseFlyerFile->setIconSize(iconSize);
  toolButtonBrowseIconDirectory->setIconSize(iconSize);
  toolButtonBrowseIconFile->setIconSize(iconSize);
  toolButtonShowC->setIconSize(iconSize);
  toolButtonShowM->setIconSize(iconSize);
  toolButtonShowI->setIconSize(iconSize);
  toolButtonShowN->setIconSize(iconSize);
  toolButtonShowU->setIconSize(iconSize);
  comboBoxSortOrder->setIconSize(iconSize);
  toolButtonBrowseExecutableFile->setIconSize(iconSize);
  toolButtonBrowseEmulatorLogFile->setIconSize(iconSize);
  toolButtonBrowseOptionsTemplateFile->setIconSize(iconSize);
  toolButtonBrowseListXMLCache->setIconSize(iconSize);
  toolButtonBrowseZipTool->setIconSize(iconSize);
  toolButtonBrowseFileRemovalTool->setIconSize(iconSize);
  pushButtonRedefineKeySequence->setIconSize(iconSize);
  pushButtonResetShortcut->setIconSize(iconSize);
#if QMC2_JOYSTICK == 1
  pushButtonRescanJoysticks->setIconSize(iconSize);
  pushButtonRemapJoystickFunction->setIconSize(iconSize);
  pushButtonRemoveJoystickMapping->setIconSize(iconSize);
#endif
  if ( qmc2ROMAlyzer ) {
    qmc2ROMAlyzer->pushButtonAnalyze->setIconSize(iconSize);
    qmc2ROMAlyzer->pushButtonPause->setIconSize(iconSize);
    qmc2ROMAlyzer->pushButtonClose->setIconSize(iconSize);
    qmc2ROMAlyzer->treeWidgetChecksums->setIconSize(iconSize);
    qmc2ROMAlyzer->pushButtonSearchForward->setIconSize(iconSize);
    qmc2ROMAlyzer->pushButtonSearchBackward->setIconSize(iconSize);
  }
  checkBoxProcessGameInfoDB->setIconSize(iconSize);
  checkBoxCompressGameInfoDB->setIconSize(iconSize);
#if defined(QMC2_SDLMAME)
  checkBoxProcessEmuInfoDB->setIconSize(iconSize);
  checkBoxCompressEmuInfoDB->setIconSize(iconSize);
#endif
#if QMC2_USE_PHONON_API
  qmc2MainWindow->toolButtonAudioPreviousTrack->setIconSize(iconSize);
  qmc2MainWindow->toolButtonAudioNextTrack->setIconSize(iconSize);
  qmc2MainWindow->toolButtonAudioFastBackward->setIconSize(iconSize);
  qmc2MainWindow->toolButtonAudioFastForward->setIconSize(iconSize);
  qmc2MainWindow->toolButtonAudioStopTrack->setIconSize(iconSize);
  qmc2MainWindow->toolButtonAudioPauseTrack->setIconSize(iconSize);
  qmc2MainWindow->toolButtonAudioPlayTrack->setIconSize(iconSize);
  qmc2MainWindow->toolButtonAudioAddTracks->setIconSize(iconSize);
  qmc2MainWindow->toolButtonAudioRemoveTracks->setIconSize(iconSize);
#endif
  if ( qmc2ROMStatusExporter ) {
    qmc2ROMStatusExporter->toolButtonBrowseASCIIFile->setIconSize(iconSize);
    qmc2ROMStatusExporter->toolButtonBrowseCSVFile->setIconSize(iconSize);
    qmc2ROMStatusExporter->toolButtonExportC->setIconSize(iconSize);
    qmc2ROMStatusExporter->toolButtonExportM->setIconSize(iconSize);
    qmc2ROMStatusExporter->toolButtonExportI->setIconSize(iconSize);
    qmc2ROMStatusExporter->toolButtonExportN->setIconSize(iconSize);
    qmc2ROMStatusExporter->toolButtonExportU->setIconSize(iconSize);
    qmc2ROMStatusExporter->pushButtonClose->setIconSize(iconSize);
    qmc2ROMStatusExporter->pushButtonExport->setIconSize(iconSize);
  }
#if defined(QMC2_SDLMESS)
  if ( qmc2MESSDeviceConfigurator ) {
    qmc2MESSDeviceConfigurator->pushButtonConfiguration->setIconSize(iconSize);
    qmc2MESSDeviceConfigurator->pushButtonNewConfiguration->setIconSize(iconSize);
    qmc2MESSDeviceConfigurator->pushButtonCloneConfiguration->setIconSize(iconSize);
    qmc2MESSDeviceConfigurator->pushButtonSaveConfiguration->setIconSize(iconSize);
    qmc2MESSDeviceConfigurator->pushButtonRemoveConfiguration->setIconSize(iconSize);
  }
#endif
  qmc2MainWindow->pushButtonSelectRomFilter->setIconSize(iconSize);
}

void Options::on_pushButtonOk_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_pushButtonOk_clicked()");
#endif

  on_pushButtonApply_clicked();
}

void Options::on_pushButtonCancel_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_pushButtonCancel_clicked()");
#endif

  restoreCurrentConfig();
}

void Options::on_pushButtonRestore_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_pushButtonRestore_clicked()");
#endif

  restoreCurrentConfig();
}

void Options::on_pushButtonApply_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_pushButtonApply_clicked()");
#endif

  static int oldCacheSize = 0;
  QString s;
  int i;
  bool needRestart = FALSE,
       needResort = FALSE,
       needRecreateTemplateMap = FALSE,
       needFilter = FALSE,
       needReopenPreviewFile = FALSE,
       needReopenFlyerFile = FALSE,
       needReopenIconFile = FALSE,
       needReload = FALSE,
       needManualReload = FALSE;

  // General
#ifdef BETA
  config->setValue("Version", QString::number(MAJOR) + "." + QString::number(MINOR) + ".b" + QString::number(BETA));
#else 
  config->setValue("Version", QString::number(MAJOR) + "." + QString::number(MINOR));
#endif

  // Frontend

  // GUI
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/Toolbar", checkBoxToolbar->isChecked());
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/SaveLayout", checkBoxSaveLayout->isChecked());
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/RestoreLayout", checkBoxRestoreLayout->isChecked());
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/SaveGameSelection", checkBoxSaveGameSelection->isChecked());
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/RestoreGameSelection", checkBoxRestoreGameSelection->isChecked());
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/Statusbar", checkBoxStatusbar->isChecked());
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/StandardColorPalette", checkBoxStandardColorPalette->isChecked());
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/ProgressTexts", checkBoxProgressTexts->isChecked());
  bool b = checkBoxProcessGameInfoDB->isChecked();
  needManualReload |= (config->value(QMC2_FRONTEND_PREFIX + "GUI/ProcessGameInfoDB").toBool() != b);
  bool invalidateGameInfoDB = (config->value(QMC2_FRONTEND_PREFIX + "GUI/ProcessGameInfoDB").toBool() != b);
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/ProcessGameInfoDB", checkBoxProcessGameInfoDB->isChecked());
  b = checkBoxCompressGameInfoDB->isChecked();
  needManualReload |= (config->value(QMC2_FRONTEND_PREFIX + "GUI/CompressGameInfoDB").toBool() != b);
  invalidateGameInfoDB |= (config->value(QMC2_FRONTEND_PREFIX + "GUI/CompressGameInfoDB").toBool() != b);
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/CompressGameInfoDB", checkBoxCompressGameInfoDB->isChecked());
#if defined(QMC2_SDLMAME)
  b = checkBoxProcessEmuInfoDB->isChecked();
  needManualReload |= (config->value(QMC2_FRONTEND_PREFIX + "GUI/ProcessEmuInfoDB").toBool() != b);
  bool invalidateEmuInfoDB = (config->value(QMC2_FRONTEND_PREFIX + "GUI/ProcessEmuInfoDB").toBool() != b);
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/ProcessEmuInfoDB", checkBoxProcessEmuInfoDB->isChecked());
  b = checkBoxCompressEmuInfoDB->isChecked();
  needManualReload |= (config->value(QMC2_FRONTEND_PREFIX + "GUI/CompressEmuInfoDB").toBool() != b);
  invalidateEmuInfoDB |= (config->value(QMC2_FRONTEND_PREFIX + "GUI/CompressEmuInfoDB").toBool() != b);
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/CompressEmuInfoDB", checkBoxCompressEmuInfoDB->isChecked());
#endif
  qmc2ScaledPreview = checkBoxScaledPreview->isChecked();
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/ScaledPreview", qmc2ScaledPreview);
  qmc2ScaledFlyer = checkBoxScaledFlyer->isChecked();
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/ScaledFlyer", qmc2ScaledFlyer);
  qmc2SmoothScaling = checkBoxSmoothScaling->isChecked();
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/SmoothScaling", qmc2SmoothScaling);
  qmc2RetryLoadingImages = checkBoxRetryLoadingImages->isChecked();
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/RetryLoadingImages", qmc2RetryLoadingImages);
  qmc2ParentImageFallback = checkBoxParentImageFallback->isChecked();
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/ParentImageFallback", qmc2ParentImageFallback);
  s = comboBoxLanguage->currentText().left(2).toLower();
  needRestart |= (config->value(QMC2_FRONTEND_PREFIX + "GUI/Language").toString() != s);
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/Language", s);
  if ( !qmc2EarlyStartup ) {
    s = comboBoxStyle->currentText();
    if ( s == QObject::tr("Default") ) 
      s = "Default";
    config->setValue(QMC2_FRONTEND_PREFIX + "GUI/Style", s);
    qmc2MainWindow->setupStyle(s);
  }
#if QMC2_JOYSTICK == 1
  if ( joystickTestWidget )
    joystickTestWidget->cleanupPalette();
#endif
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/Font", lineEditFont->text());
  if ( spinBoxPixmapCacheSize->value() != oldCacheSize ) {
    oldCacheSize = spinBoxPixmapCacheSize->value();
    qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("image cache size set to %1 MB").arg(oldCacheSize));
  }
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/PixmapCacheSize", oldCacheSize);
  QPixmapCache::setCacheLimit(oldCacheSize * 1024);
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/KillEmulatorsOnExit", checkBoxKillEmulatorsOnExit->isChecked());
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/ShowMenuBar", checkBoxShowMenuBar->isChecked());
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/CheckSingleInstance", checkBoxCheckSingleInstance->isChecked());
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/GameStatusIndicator", checkBoxGameStatusIndicator->isChecked());
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/GameStatusIndicatorOnlyWhenRequired", checkBoxGameStatusIndicatorOnlyWhenRequired->isChecked());
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/ShowGameName", checkBoxShowGameName->isChecked());
  qmc2ShowGameName = checkBoxShowGameName->isChecked();
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/ShowGameNameOnlyWhenRequired", checkBoxShowGameNameOnlyWhenRequired->isChecked());
  qmc2ShowGameNameOnlyWhenRequired = checkBoxShowGameNameOnlyWhenRequired->isChecked();
  // show / hide game status indicator
  if ( config->value(QMC2_FRONTEND_PREFIX + "GUI/GameStatusIndicator").toBool() ) {
    if ( config->value(QMC2_FRONTEND_PREFIX + "GUI/GameStatusIndicatorOnlyWhenRequired").toBool() ) {
      if ( qmc2MainWindow->hSplitter->sizes()[0] == 0 || qmc2MainWindow->tabWidgetGamelist->currentIndex() != QMC2_GAMELIST_INDEX ) {
        qmc2MainWindow->labelGameStatus->setVisible(TRUE);
      } else {
        qmc2MainWindow->labelGameStatus->setVisible(FALSE);
      }
    } else {
      qmc2MainWindow->labelGameStatus->setVisible(TRUE);
    }
  } else
    qmc2MainWindow->labelGameStatus->setVisible(FALSE);
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/FrontendLogSize", spinBoxFrontendLogSize->value());
  qmc2MainWindow->textBrowserFrontendLog->document()->setMaximumBlockCount(spinBoxFrontendLogSize->value());
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/EmulatorLogSize", spinBoxEmulatorLogSize->value());
  qmc2MainWindow->textBrowserEmulatorLog->document()->setMaximumBlockCount(spinBoxEmulatorLogSize->value());
  config->setValue(QMC2_FRONTEND_PREFIX + "GUI/MinimizeOnVariantLaunch", checkBoxMinimizeOnVariantLaunch->isChecked());

  // Files and directories
  config->setValue(QMC2_FRONTEND_PREFIX + "FilesAndDirectories/TemporaryFile", lineEditTemporaryFile->text());
  config->setValue(QMC2_FRONTEND_PREFIX + "FilesAndDirectories/LogFile", lineEditFrontendLogFile->text());
  config->setValue(QMC2_FRONTEND_PREFIX + "FilesAndDirectories/DataDirectory", lineEditDataDirectory->text());

#if defined(QMC2_SDLMAME)
  needReopenPreviewFile = (qmc2UsePreviewFile != (stackedWidgetPreview->currentIndex() == 1));
  needReopenPreviewFile |= (config->value("MAME/FilesAndDirectories/PreviewFile").toString() != lineEditPreviewFile->text());
  qmc2UsePreviewFile = (stackedWidgetPreview->currentIndex() == 1);
  config->setValue("MAME/FilesAndDirectories/UsePreviewFile", qmc2UsePreviewFile);
  config->setValue("MAME/FilesAndDirectories/PreviewDirectory", lineEditPreviewDirectory->text());
  config->setValue("MAME/FilesAndDirectories/PreviewFile", lineEditPreviewFile->text());
  needReopenFlyerFile = (qmc2UseFlyerFile != (stackedWidgetFlyer->currentIndex() == 1));
  needReopenFlyerFile |= (config->value("MAME/FilesAndDirectories/FlyerFile").toString() != lineEditFlyerFile->text());
  qmc2UseFlyerFile = (stackedWidgetFlyer->currentIndex() == 1);
  config->setValue("MAME/FilesAndDirectories/UseFlyerFile", qmc2UseFlyerFile);
  config->setValue("MAME/FilesAndDirectories/FlyerDirectory", lineEditFlyerDirectory->text());
  config->setValue("MAME/FilesAndDirectories/FlyerFile", lineEditFlyerFile->text());
  needReopenIconFile = (qmc2UseIconFile != (stackedWidgetIcon->currentIndex() == 1));
  needReopenIconFile |= (config->value("MAME/FilesAndDirectories/IconFile").toString() != lineEditIconFile->text());
  qmc2UseIconFile = (stackedWidgetIcon->currentIndex() == 1);
  config->setValue("MAME/FilesAndDirectories/UseIconFile", qmc2UseIconFile);
  config->setValue("MAME/FilesAndDirectories/IconDirectory", lineEditIconDirectory->text());
  config->setValue("MAME/FilesAndDirectories/IconFile", lineEditIconFile->text());
  s = lineEditGameInfoDB->text();
  needManualReload |= (config->value("MAME/FilesAndDirectories/GameInfoDB").toString() != s);
  invalidateGameInfoDB |= (config->value("MAME/FilesAndDirectories/GameInfoDB").toString() != s);
  config->setValue("MAME/FilesAndDirectories/GameInfoDB", lineEditGameInfoDB->text());
  s = lineEditEmuInfoDB->text();
  needManualReload |= (config->value("MAME/FilesAndDirectories/EmuInfoDB").toString() != s);
  invalidateEmuInfoDB |= (config->value("MAME/FilesAndDirectories/EmuInfoDB").toString() != s);
  config->setValue("MAME/FilesAndDirectories/EmuInfoDB", lineEditEmuInfoDB->text());
#elif defined(QMC2_SDLMESS)
  needReopenPreviewFile = (qmc2UsePreviewFile != (stackedWidgetPreview->currentIndex() == 1));
  needReopenPreviewFile |= (config->value("MESS/FilesAndDirectories/PreviewFile").toString() != lineEditPreviewFile->text());
  qmc2UsePreviewFile = (stackedWidgetPreview->currentIndex() == 1);
  config->setValue("MESS/FilesAndDirectories/UsePreviewFile", qmc2UsePreviewFile);
  config->setValue("MESS/FilesAndDirectories/PreviewDirectory", lineEditPreviewDirectory->text());
  config->setValue("MESS/FilesAndDirectories/PreviewFile", lineEditPreviewFile->text());
  needReopenFlyerFile = (qmc2UseFlyerFile != (stackedWidgetFlyer->currentIndex() == 1));
  needReopenFlyerFile |= (config->value("MESS/FilesAndDirectories/FlyerFile").toString() != lineEditFlyerFile->text());
  qmc2UseFlyerFile = (stackedWidgetFlyer->currentIndex() == 1);
  config->setValue("MESS/FilesAndDirectories/UseFlyerFile", qmc2UseFlyerFile);
  config->setValue("MESS/FilesAndDirectories/FlyerDirectory", lineEditFlyerDirectory->text());
  config->setValue("MESS/FilesAndDirectories/FlyerFile", lineEditFlyerFile->text());
  needReopenIconFile = (qmc2UseIconFile != (stackedWidgetIcon->currentIndex() == 1));
  needReopenIconFile |= (config->value("MESS/FilesAndDirectories/IconFile").toString() != lineEditIconFile->text());
  qmc2UseIconFile = (stackedWidgetIcon->currentIndex() == 1);
  config->setValue("MESS/FilesAndDirectories/UseIconFile", qmc2UseIconFile);
  config->setValue("MESS/FilesAndDirectories/IconDirectory", lineEditIconDirectory->text());
  config->setValue("MESS/FilesAndDirectories/IconFile", lineEditIconFile->text());
  s = lineEditGameInfoDB->text();
  needManualReload |= (config->value("MESS/FilesAndDirectories/GameInfoDB").toString() != s);
  invalidateGameInfoDB |= (config->value("MESS/FilesAndDirectories/GameInfoDB").toString() != s);
  config->setValue("MESS/FilesAndDirectories/GameInfoDB", lineEditGameInfoDB->text());
#endif

  // Gamelist
  config->setValue(QMC2_FRONTEND_PREFIX + "Gamelist/SortOnline", checkBoxSortOnline->isChecked());
  config->setValue(QMC2_FRONTEND_PREFIX + "Gamelist/AutoTriggerROMCheck", checkBoxAutoTriggerROMCheck->isChecked());
  qmc2GamelistResponsiveness = spinBoxResponsiveness->value();
  config->setValue(QMC2_FRONTEND_PREFIX + "Gamelist/Responsiveness", qmc2GamelistResponsiveness);
  qmc2UpdateDelay = spinBoxUpdateDelay->value();
  config->setValue(QMC2_FRONTEND_PREFIX + "Gamelist/UpdateDelay", qmc2UpdateDelay);
  i = comboBoxSortCriteria->currentIndex();
  needResort = (i != qmc2SortCriteria);
  int oldSortCriteria = qmc2SortCriteria;
  qmc2SortCriteria = i;
  config->setValue(QMC2_FRONTEND_PREFIX + "Gamelist/SortCriteria", qmc2SortCriteria);
  i = comboBoxSortOrder->currentIndex();
  needResort = needResort || (i == 0 ? qmc2SortOrder != Qt::AscendingOrder : qmc2SortOrder != Qt::DescendingOrder);
  Qt::SortOrder oldSortOrder = qmc2SortOrder; 
  qmc2SortOrder = (i == 0 ? Qt::AscendingOrder : Qt::DescendingOrder);
  config->setValue(QMC2_FRONTEND_PREFIX + "Gamelist/SortOrder", qmc2SortOrder);
  QBitArray newFilter(QMC2_ROMSTATE_COUNT);
  config->setValue(QMC2_FRONTEND_PREFIX + "Gamelist/ShowC", toolButtonShowC->isChecked());
  newFilter.setBit(QMC2_ROMSTATE_INT_C, toolButtonShowC->isChecked());
  config->setValue(QMC2_FRONTEND_PREFIX + "Gamelist/ShowM", toolButtonShowM->isChecked());
  newFilter.setBit(QMC2_ROMSTATE_INT_M, toolButtonShowM->isChecked());
  config->setValue(QMC2_FRONTEND_PREFIX + "Gamelist/ShowI", toolButtonShowI->isChecked());
  newFilter.setBit(QMC2_ROMSTATE_INT_I, toolButtonShowI->isChecked());
  config->setValue(QMC2_FRONTEND_PREFIX + "Gamelist/ShowN", toolButtonShowN->isChecked());
  newFilter.setBit(QMC2_ROMSTATE_INT_N, toolButtonShowN->isChecked());
  config->setValue(QMC2_FRONTEND_PREFIX + "Gamelist/ShowU", toolButtonShowU->isChecked());
  newFilter.setBit(QMC2_ROMSTATE_INT_U, toolButtonShowU->isChecked());
  needFilter = (qmc2Filter != newFilter);
  qmc2Filter = newFilter;

  // Shortcuts / Keys
  QMapIterator<QString, QPair<QString, QAction *> > it(qmc2ShortcutMap);
  while ( it.hasNext() ) {
    it.next();
    QString itShortcut = it.key();
    config->setValue(QString(QMC2_FRONTEND_PREFIX + "Shortcuts/%1").arg(itShortcut), qmc2CustomShortcutMap[itShortcut]);
  }
  setupShortcutActions();

  // Joystick
#if QMC2_JOYSTICK == 1
  config->setValue(QMC2_FRONTEND_PREFIX + "Joystick/EnableJoystickControl", checkBoxEnableJoystickControl->isChecked());
  config->setValue(QMC2_FRONTEND_PREFIX + "Joystick/Index", comboBoxSelectJoysticks->currentIndex());
  config->setValue(QMC2_FRONTEND_PREFIX + "Joystick/AutoRepeat", checkBoxJoystickAutoRepeat->isChecked());
  config->setValue(QMC2_FRONTEND_PREFIX + "Joystick/AutoRepeatTimeout", spinBoxJoystickAutoRepeatTimeout->value());
  config->setValue(QMC2_FRONTEND_PREFIX + "Joystick/EventTimeout", spinBoxJoystickEventTimeout->value());

  // Joystick function map
  it.toFront();
  while ( it.hasNext() ) {
    it.next();
    QString itShortcut = it.key();
    QString myKey = qmc2JoystickFunctionMap.key(itShortcut);
    if ( myKey.isEmpty() )
      config->remove(QString(QMC2_FRONTEND_PREFIX + "Joystick/Map/%1").arg(itShortcut));
    else
      config->setValue(QString(QMC2_FRONTEND_PREFIX + "Joystick/Map/%1").arg(itShortcut), myKey);
  }
  if ( joystick ) {
    if ( joystick->isOpen() )
      joystick->close();
    // reconnect joystick callbacks to main widget if applicable
    joystick->disconnect(qmc2MainWindow);
    if ( config->value(QMC2_FRONTEND_PREFIX + "Joystick/EnableJoystickControl").toBool() ) {
      if ( !joystick->open(config->value(QMC2_FRONTEND_PREFIX + "Joystick/Index").toInt()) ) {
        qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: can't initialize joystick"));
      } else {
        // (re)connect joystick callbacks to main widget
        connect(joystick, SIGNAL(axisValueChanged(int, int)), qmc2MainWindow, SLOT(on_joystickAxisValueChanged(int, int)));
        connect(joystick, SIGNAL(buttonValueChanged(int, bool)), qmc2MainWindow, SLOT(on_joystickButtonValueChanged(int, bool)));
        connect(joystick, SIGNAL(hatValueChanged(int, int)), qmc2MainWindow, SLOT(on_joystickHatValueChanged(int, int)));
        connect(joystick, SIGNAL(trackballValueChanged(int, int, int)), qmc2MainWindow, SLOT(on_joystickTrackballValueChanged(int, int, int)));
        qmc2MainWindow->joyIndex = config->value(QMC2_FRONTEND_PREFIX + "Joystick/Index").toInt();
      }
    }
  }
#endif

  // Tools
  config->setValue(QMC2_FRONTEND_PREFIX + "Tools/ZipTool", lineEditZipTool->text());
  config->setValue(QMC2_FRONTEND_PREFIX + "Tools/ZipToolRemovalArguments", lineEditZipToolRemovalArguments->text());
  config->setValue(QMC2_FRONTEND_PREFIX + "Tools/FileRemovalTool", lineEditFileRemovalTool->text());
  config->setValue(QMC2_FRONTEND_PREFIX + "Tools/FileRemovalToolArguments", lineEditFileRemovalToolArguments->text());

  // Emulator

  // Configuration
  if ( qmc2GuiReady ) {
    if ( qmc2GlobalEmulatorOptions->changed ) {
      if ( qmc2EmulatorOptions ) {
        switch ( QMessageBox::question(this, tr("Confirm"), tr("An open game-specific emulator configuration has been detected.\nUse local game-setting, overwrite with global setup or don't apply?"), tr("&Local"), tr("&Overwrite"), tr("Do&n't apply"), 0, 2) ) {
           case 0:
             qmc2EmulatorOptions->save();
             qmc2GlobalEmulatorOptions->save();
             qmc2GlobalEmulatorOptions->load();
             qmc2EmulatorOptions->load();
             break;

           case 1:
             qmc2GlobalEmulatorOptions->save();
             qmc2GlobalEmulatorOptions->load();
             qmc2EmulatorOptions->load(TRUE);
             qmc2EmulatorOptions->save();
             break;

           case 2: 
           default:
             break;
        }
      } else {
        qmc2GlobalEmulatorOptions->save();
        qmc2GlobalEmulatorOptions->load();
      }
    }
  }

  // Files and directories
#if defined(QMC2_SDLMAME)
  needReload = config->value("MAME/FilesAndDirectories/ExecutableFile").toString() != lineEditExecutableFile->text();
  config->setValue("MAME/FilesAndDirectories/ExecutableFile", lineEditExecutableFile->text());
  config->setValue("MAME/FilesAndDirectories/LogFile", lineEditEmulatorLogFile->text());
  config->setValue("MAME/FilesAndDirectories/ListXMLCache", lineEditListXMLCache->text());
  config->setValue("MAME/FilesAndDirectories/GamelistCacheFile", lineEditGamelistCacheFile->text());
  config->setValue("MAME/FilesAndDirectories/ROMStateCacheFile", lineEditROMStateCacheFile->text());
  s = lineEditOptionsTemplateFile->text();
  needRecreateTemplateMap = needRecreateTemplateMap || (config->value("MAME/FilesAndDirectories/OptionsTemplateFile").toString() != s );
  config->setValue("MAME/FilesAndDirectories/OptionsTemplateFile", s);
  config->setValue("MAME/FilesAndDirectories/FavoritesFile", lineEditFavoritesFile->text());
  config->setValue("MAME/FilesAndDirectories/HistoryFile", lineEditHistoryFile->text());
#elif defined(QMC2_SDLMESS)
  needReload = config->value("MESS/FilesAndDirectories/ExecutableFile").toString() != lineEditExecutableFile->text();
  config->setValue("MESS/FilesAndDirectories/ExecutableFile", lineEditExecutableFile->text());
  config->setValue("MESS/FilesAndDirectories/LogFile", lineEditEmulatorLogFile->text());
  config->setValue("MESS/FilesAndDirectories/ListXMLCache", lineEditListXMLCache->text());
  config->setValue("MESS/FilesAndDirectories/GamelistCacheFile", lineEditGamelistCacheFile->text());
  config->setValue("MESS/FilesAndDirectories/ROMStateCacheFile", lineEditROMStateCacheFile->text());
  s = lineEditOptionsTemplateFile->text();
  needRecreateTemplateMap = needRecreateTemplateMap || (config->value("MESS/FilesAndDirectories/OptionsTemplateFile").toString() != s );
  config->setValue("MESS/FilesAndDirectories/OptionsTemplateFile", s);
  config->setValue("MESS/FilesAndDirectories/FavoritesFile", lineEditFavoritesFile->text());
  config->setValue("MESS/FilesAndDirectories/HistoryFile", lineEditHistoryFile->text());
#endif

  // sync settings (write settings to disk) and apply
  config->sync();
  applied = TRUE;
  if ( qmc2GuiReady )
    apply();

  if ( invalidateGameInfoDB ) {
    qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("invalidating game info DB"));
    QMapIterator<QString, QByteArray *> it(qmc2GameInfoDB);
    QList<QByteArray *> deletedRecords;
    while ( it.hasNext() ) {
      it.next();
      if ( !deletedRecords.contains(it.value()) ) {
        if ( it.value() )
          delete it.value();
        deletedRecords.append(it.value());
      }
    }
    deletedRecords.clear();
    qmc2GameInfoDB.clear();
  }

#if defined(QMC2_SDLMAME)
  if ( invalidateEmuInfoDB ) {
    qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("invalidating emulator info DB"));
    QMapIterator<QString, QByteArray *> it(qmc2EmuInfoDB);
    QList<QByteArray *> deletedRecords;
    while ( it.hasNext() ) {
      it.next();
      if ( !deletedRecords.contains(it.value()) ) {
        if ( it.value() )
          delete it.value();
        deletedRecords.append(it.value());
      }
    }
    deletedRecords.clear();
    qmc2EmuInfoDB.clear();
  }
#endif

  if ( needManualReload )
    qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("please reload gamelist for some changes to take effect"));

  if ( needRestart )
    qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("please restart QMC2 for some changes to take effect"));

  if ( needRecreateTemplateMap )
    qmc2MainWindow->on_actionRecreateTemplateMap_activated();

  if ( needResort && !needReload ) {
    bool doResort = TRUE;

    if ( qmc2VerifyActive ) {
      qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("re-sort of gamelist impossible at this time"));
      qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("please wait for ROM verification to finish and try again"));
      qmc2SortCriteria = oldSortCriteria;
      qmc2SortOrder = oldSortOrder;
      doResort = FALSE;
    }

    if ( doResort ) {
      QString sortCirtieria = "?";
      switch ( qmc2SortCriteria ) {
        case QMC2_SORT_BY_DESCRIPTION:
          sortCirtieria = QObject::tr("game description");
          break;
        case QMC2_SORT_BY_ROM_STATE:
          sortCirtieria = QObject::tr("ROM state");
          break;
        case QMC2_SORT_BY_YEAR:
          sortCirtieria = QObject::tr("year");
          break;
        case QMC2_SORT_BY_MANUFACTURER:
          sortCirtieria = QObject::tr("manufacturer");
          break;
        case QMC2_SORT_BY_NAME:
          sortCirtieria = QObject::tr("game name");
          break;
      }
      qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("sorting gamelist by %1 in %2 order").arg(sortCirtieria).arg(qmc2SortOrder == Qt::AscendingOrder ? tr("ascending") : tr("descending")));
      qApp->processEvents();
      QList<QTreeWidgetItem *> itemList = qmc2MainWindow->treeWidgetGamelist->findItems("*", Qt::MatchContains | Qt::MatchWildcard);
      for (i = 0; i < itemList.count(); i++) {
        if ( itemList[i]->childCount() > 1 ) {
          qmc2MainWindow->treeWidgetGamelist->collapseItem(itemList[i]);
          QList<QTreeWidgetItem *> childrenList = itemList[i]->takeChildren();
          int j;
          for (j = 0; j < childrenList.count(); j++)
            delete childrenList[j];
          QTreeWidgetItem *nameItem = new QTreeWidgetItem(itemList[i]);
          nameItem->setText(QMC2_GAMELIST_COLUMN_GAME, tr("Waiting for data..."));
          nameItem->setText(QMC2_GAMELIST_COLUMN_ICON, qmc2GamelistNameMap[itemList[i]->text(QMC2_GAMELIST_COLUMN_GAME)]);
          qApp->processEvents();
        }
      }
      qApp->processEvents();
      qmc2MainWindow->treeWidgetGamelist->sortItems(0, qmc2SortOrder);
      qmc2MainWindow->treeWidgetHierarchy->sortItems(0, qmc2SortOrder);
      QTimer::singleShot(0, qmc2MainWindow, SLOT(scrollToCurrentItem()));
    }
  }

  if ( needFilter && !needReload )
    qmc2Gamelist->filter();

  if ( qmc2Preview ) {
    if ( needReopenPreviewFile ) {
      if ( qmc2UsePreviewFile ) {
#if defined(QMC2_SDLMAME)
        qmc2Preview->previewFile = unzOpen((const char *)config->value("MAME/FilesAndDirectories/PreviewFile").toString().toAscii());
        if ( qmc2Preview->previewFile == NULL )
          qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: can't open preview file, please check access permissions for %1").arg(config->value("MAME/FilesAndDirectories/PreviewFile").toString()));
#elif defined(QMC2_SDLMESS)
        qmc2Preview->previewFile = unzOpen((const char *)config->value("MESS/FilesAndDirectories/PreviewFile").toString().toAscii());
        if ( qmc2Preview->previewFile == NULL )
          qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: can't open preview file, please check access permissions for %1").arg(config->value("MESS/FilesAndDirectories/PreviewFile").toString()));
#endif
      } else
        unzClose(qmc2Preview->previewFile);
    }
    qmc2Preview->repaint();
  }

  if ( qmc2Flyer ) {
    if ( needReopenFlyerFile ) {
      if ( qmc2UseFlyerFile ) {
#if defined(QMC2_SDLMAME)
        qmc2Flyer->flyerFile = unzOpen((const char *)config->value("MAME/FilesAndDirectories/FlyerFile").toString().toAscii());
        if ( qmc2Flyer->flyerFile == NULL )
          qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: can't open flyer file, please check access permissions for %1").arg(config->value("MAME/FilesAndDirectories/FlyerFile").toString()));
#elif defined(QMC2_SDLMESS)
        qmc2Flyer->flyerFile = unzOpen((const char *)config->value("MESS/FilesAndDirectories/FlyerFile").toString().toAscii());
        if ( qmc2Flyer->flyerFile == NULL )
          qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: can't open flyer file, please check access permissions for %1").arg(config->value("MESS/FilesAndDirectories/FlyerFile").toString()));
#endif
      } else
        unzClose(qmc2Flyer->flyerFile);
    }
    qmc2Flyer->repaint();
  }

  if ( needReopenIconFile ) {
    if ( qmc2UseIconFile ) {
#if defined(QMC2_SDLMAME)
      qmc2IconFile = unzOpen((const char *)config->value("MAME/FilesAndDirectories/IconFile").toString().toAscii());
      if ( qmc2IconFile == NULL )
        qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: can't open icon file, please check access permissions for %1").arg(config->value("MAME/FilesAndDirectories/IconFile").toString()));
#elif defined(QMC2_SDLMESS)
      qmc2IconFile = unzOpen((const char *)config->value("MESS/FilesAndDirectories/IconFile").toString().toAscii());
      if ( qmc2IconFile == NULL )
        qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: can't open icon file, please check access permissions for %1").arg(config->value("MESS/FilesAndDirectories/IconFile").toString()));
#endif
    } else
      unzClose(qmc2IconFile);
  }

  if ( needReload ) {
    qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("triggering automatic reload of gamelist"));
    qmc2AutomaticReload = TRUE;
    QTimer::singleShot(0, qmc2MainWindow->actionReload, SLOT(trigger()));
  }

  QTimer::singleShot(0, this, SLOT(applyDelayed()));
}

void Options::on_pushButtonDefault_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_pushButtonDefault_clicked()");
#endif

  restoreCurrentConfig(TRUE);
}

void Options::restoreCurrentConfig(bool useDefaultSettings)
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::restoreCurrentConfig()");
#endif

  treeWidgetShortcuts->clear();
  treeWidgetJoystickMappings->clear();

  if ( useDefaultSettings ) {
    QString fn = config->fileName();
    delete config;
    QFile f(fn);
    f.copy(fn + ".bak");
    f.remove();
    config = new QSettings(QSettings::IniFormat, QSettings::UserScope, "qmc2");
    qmc2Config = config;
  }

  QString userScopePath = QMC2_DOT_PATH;

  // Frontend

  // GUI
  checkBoxToolbar->setChecked(config->value(QMC2_FRONTEND_PREFIX + "GUI/Toolbar", TRUE).toBool());
  checkBoxSaveLayout->setChecked(config->value(QMC2_FRONTEND_PREFIX + "GUI/SaveLayout", TRUE).toBool());
  checkBoxRestoreLayout->setChecked(config->value(QMC2_FRONTEND_PREFIX + "GUI/RestoreLayout", TRUE).toBool());
  checkBoxSaveGameSelection->setChecked(config->value(QMC2_FRONTEND_PREFIX + "GUI/SaveGameSelection", TRUE).toBool());
  checkBoxRestoreGameSelection->setChecked(config->value(QMC2_FRONTEND_PREFIX + "GUI/RestoreGameSelection", TRUE).toBool());
  checkBoxStatusbar->setChecked(config->value(QMC2_FRONTEND_PREFIX + "GUI/Statusbar", TRUE).toBool());
  checkBoxStandardColorPalette->setChecked(config->value(QMC2_FRONTEND_PREFIX + "GUI/StandardColorPalette", TRUE).toBool());
  checkBoxProgressTexts->setChecked(config->value(QMC2_FRONTEND_PREFIX + "GUI/ProgressTexts", FALSE).toBool());
  checkBoxProcessGameInfoDB->setChecked(config->value(QMC2_FRONTEND_PREFIX + "GUI/ProcessGameInfoDB", TRUE).toBool());
  checkBoxCompressGameInfoDB->setChecked(config->value(QMC2_FRONTEND_PREFIX + "GUI/CompressGameInfoDB", FALSE).toBool());
#if defined(QMC2_SDLMAME)
  checkBoxProcessEmuInfoDB->setChecked(config->value(QMC2_FRONTEND_PREFIX + "GUI/ProcessEmuInfoDB", TRUE).toBool());
  checkBoxCompressEmuInfoDB->setChecked(config->value(QMC2_FRONTEND_PREFIX + "GUI/CompressGameInfoDB", FALSE).toBool());
#endif
  qmc2ScaledPreview = config->value(QMC2_FRONTEND_PREFIX + "GUI/ScaledPreview", TRUE).toBool();
  checkBoxScaledPreview->setChecked(qmc2ScaledPreview);
  qmc2ScaledFlyer = config->value(QMC2_FRONTEND_PREFIX + "GUI/ScaledFlyer", TRUE).toBool();
  checkBoxScaledFlyer->setChecked(qmc2ScaledFlyer);
  qmc2SmoothScaling = config->value(QMC2_FRONTEND_PREFIX + "GUI/SmoothScaling", FALSE).toBool();
  checkBoxSmoothScaling->setChecked(qmc2SmoothScaling);
  qmc2RetryLoadingImages = config->value(QMC2_FRONTEND_PREFIX + "GUI/RetryLoadingImages", TRUE).toBool();
  checkBoxRetryLoadingImages->setChecked(qmc2RetryLoadingImages);
  qmc2ParentImageFallback = config->value(QMC2_FRONTEND_PREFIX + "GUI/ParentImageFallback", FALSE).toBool();
  checkBoxParentImageFallback->setChecked(qmc2ParentImageFallback);
  comboBoxLanguage->setCurrentIndex(comboBoxLanguage->findText(config->value(QMC2_FRONTEND_PREFIX + "GUI/Language", "us").toString().toUpper(), Qt::MatchContains | Qt::MatchCaseSensitive));
  comboBoxStyle->clear();
  comboBoxStyle->addItem(QObject::tr("Default"));
  comboBoxStyle->addItems(QStyleFactory::keys());
  QString myStyle = QObject::tr((const char *)config->value(QMC2_FRONTEND_PREFIX + "GUI/Style", "Default").toString().toUtf8());
  comboBoxStyle->setCurrentIndex(comboBoxStyle->findText(myStyle, Qt::MatchFixedString));
  lineEditFont->setText(config->value(QMC2_FRONTEND_PREFIX + "GUI/Font").toString());
  QFont f;
  f.fromString(lineEditFont->text());
  lineEditFont->setFont(f);
  int pixmapCacheSize = config->value(QMC2_FRONTEND_PREFIX + "GUI/PixmapCacheSize", 64).toInt();
  spinBoxPixmapCacheSize->setValue(pixmapCacheSize);
  checkBoxKillEmulatorsOnExit->setChecked(config->value(QMC2_FRONTEND_PREFIX + "GUI/KillEmulatorsOnExit", TRUE).toBool());
  checkBoxShowMenuBar->setChecked(config->value(QMC2_FRONTEND_PREFIX + "GUI/ShowMenuBar", TRUE).toBool());
  checkBoxCheckSingleInstance->setChecked(config->value(QMC2_FRONTEND_PREFIX + "GUI/CheckSingleInstance", TRUE).toBool());
  checkBoxGameStatusIndicator->setChecked(config->value(QMC2_FRONTEND_PREFIX + "GUI/GameStatusIndicator", FALSE).toBool());
  checkBoxGameStatusIndicatorOnlyWhenRequired->setChecked(config->value(QMC2_FRONTEND_PREFIX + "GUI/GameStatusIndicatorOnlyWhenRequired", TRUE).toBool());
  checkBoxShowGameName->setChecked(config->value(QMC2_FRONTEND_PREFIX + "GUI/ShowGameName", FALSE).toBool());
  qmc2ShowGameName = checkBoxShowGameName->isChecked();
  checkBoxShowGameNameOnlyWhenRequired->setChecked(config->value(QMC2_FRONTEND_PREFIX + "GUI/ShowGameNameOnlyWhenRequired", TRUE).toBool());
  qmc2ShowGameNameOnlyWhenRequired = checkBoxShowGameNameOnlyWhenRequired->isChecked();
  spinBoxFrontendLogSize->setValue(config->value(QMC2_FRONTEND_PREFIX + "GUI/FrontendLogSize", 0).toInt());
  spinBoxEmulatorLogSize->setValue(config->value(QMC2_FRONTEND_PREFIX + "GUI/EmulatorLogSize", 0).toInt());
  checkBoxMinimizeOnVariantLaunch->setChecked(config->value(QMC2_FRONTEND_PREFIX + "GUI/MinimizeOnVariantLaunch", FALSE).toBool());
  
  // Files / Directories
  lineEditDataDirectory->setText(config->value(QMC2_FRONTEND_PREFIX + "FilesAndDirectories/DataDirectory", QMC2_DEFAULT_DATA_PATH + "/").toString());
#if defined(QMC2_SDLMAME)
  lineEditTemporaryFile->setText(config->value(QMC2_FRONTEND_PREFIX + "FilesAndDirectories/TemporaryFile", userScopePath + "/qmc2-sdlmame.tmp").toString());
  lineEditFrontendLogFile->setText(config->value(QMC2_FRONTEND_PREFIX + "FilesAndDirectories/LogFile", userScopePath + "/qmc2-sdlmame.log").toString());
  lineEditPreviewDirectory->setText(config->value("MAME/FilesAndDirectories/PreviewDirectory", QMC2_DEFAULT_DATA_PATH + "/prv/").toString());
  lineEditPreviewFile->setText(config->value("MAME/FilesAndDirectories/PreviewFile", QMC2_DEFAULT_DATA_PATH + "/prv/previews.zip").toString());
  qmc2UsePreviewFile = config->value("MAME/FilesAndDirectories/UsePreviewFile", FALSE).toBool();
  stackedWidgetPreview->setCurrentIndex(qmc2UsePreviewFile ? 1 : 0);
  radioButtonPreviewSelect->setText(qmc2UsePreviewFile ? tr("Preview file") : tr("Preview directory"));
  lineEditFlyerDirectory->setText(config->value("MAME/FilesAndDirectories/FlyerDirectory", QMC2_DEFAULT_DATA_PATH + "/fly/").toString());
  lineEditFlyerFile->setText(config->value("MAME/FilesAndDirectories/FlyerFile", QMC2_DEFAULT_DATA_PATH + "/fly/flyers.zip").toString());
  qmc2UseFlyerFile = config->value("MAME/FilesAndDirectories/UseFlyerFile", FALSE).toBool();
  stackedWidgetFlyer->setCurrentIndex(qmc2UseFlyerFile ? 1 : 0);
  radioButtonFlyerSelect->setText(qmc2UseFlyerFile ? tr("Flyer file") : tr("Flyer directory"));
  lineEditIconDirectory->setText(config->value("MAME/FilesAndDirectories/IconDirectory", QMC2_DEFAULT_DATA_PATH + "/ico/").toString());
  lineEditIconFile->setText(config->value("MAME/FilesAndDirectories/IconFile", QMC2_DEFAULT_DATA_PATH + "/ico/icons.zip").toString());
  qmc2UseIconFile = config->value("MAME/FilesAndDirectories/UseIconFile", FALSE).toBool();
  stackedWidgetIcon->setCurrentIndex(qmc2UseIconFile ? 1 : 0);
  radioButtonIconSelect->setText(qmc2UseIconFile ? tr("Icon file") : tr("Icon directory"));
  lineEditGameInfoDB->setText(config->value("MAME/FilesAndDirectories/GameInfoDB", QMC2_DEFAULT_DATA_PATH + "/cat/history.dat").toString());
  lineEditEmuInfoDB->setText(config->value("MAME/FilesAndDirectories/EmuInfoDB", QMC2_DEFAULT_DATA_PATH + "/cat/mameinfo.dat").toString());
#elif defined(QMC2_SDLMESS)
  lineEditTemporaryFile->setText(config->value(QMC2_FRONTEND_PREFIX + "FilesAndDirectories/TemporaryFile", userScopePath + "/qmc2-sdlmess.tmp").toString());
  lineEditFrontendLogFile->setText(config->value(QMC2_FRONTEND_PREFIX + "FilesAndDirectories/LogFile", userScopePath + "/qmc2-sdlmess.log").toString());
  lineEditPreviewDirectory->setText(config->value("MESS/FilesAndDirectories/PreviewDirectory", QMC2_DEFAULT_DATA_PATH + "/prv/").toString());
  lineEditPreviewFile->setText(config->value("MESS/FilesAndDirectories/PreviewFile", QMC2_DEFAULT_DATA_PATH + "/prv/previews.zip").toString());
  qmc2UsePreviewFile = config->value("MESS/FilesAndDirectories/UsePreviewFile", FALSE).toBool();
  stackedWidgetPreview->setCurrentIndex(qmc2UsePreviewFile ? 1 : 0);
  radioButtonPreviewSelect->setText(qmc2UsePreviewFile ? tr("Preview file") : tr("Preview directory"));
  lineEditFlyerDirectory->setText(config->value("MESS/FilesAndDirectories/FlyerDirectory", QMC2_DEFAULT_DATA_PATH + "/fly/").toString());
  lineEditFlyerFile->setText(config->value("MESS/FilesAndDirectories/FlyerFile", QMC2_DEFAULT_DATA_PATH + "/fly/flyers.zip").toString());
  qmc2UseFlyerFile = config->value("MESS/FilesAndDirectories/UseFlyerFile", FALSE).toBool();
  stackedWidgetFlyer->setCurrentIndex(qmc2UseFlyerFile ? 1 : 0);
  radioButtonFlyerSelect->setText(qmc2UseFlyerFile ? tr("Flyer file") : tr("Flyer directory"));
  lineEditIconDirectory->setText(config->value("MESS/FilesAndDirectories/IconDirectory", QMC2_DEFAULT_DATA_PATH + "/ico/").toString());
  lineEditIconFile->setText(config->value("MESS/FilesAndDirectories/IconFile", QMC2_DEFAULT_DATA_PATH + "/ico/icons.zip").toString());
  qmc2UseIconFile = config->value("MESS/FilesAndDirectories/UseIconFile", FALSE).toBool();
  stackedWidgetIcon->setCurrentIndex(qmc2UseIconFile ? 1 : 0);
  radioButtonIconSelect->setText(qmc2UseIconFile ? tr("Icon file") : tr("Icon directory"));
  lineEditGameInfoDB->setText(config->value("MESS/FilesAndDirectories/GameInfoDB", QMC2_DEFAULT_DATA_PATH + "/cat/sysinfo.dat").toString());
#endif

  // Gamelist
  checkBoxSortOnline->setChecked(config->value(QMC2_FRONTEND_PREFIX + "Gamelist/SortOnline", FALSE).toBool());
  checkBoxAutoTriggerROMCheck->setChecked(config->value(QMC2_FRONTEND_PREFIX + "Gamelist/AutoTriggerROMCheck", FALSE).toBool());
  spinBoxResponsiveness->setValue(config->value(QMC2_FRONTEND_PREFIX + "Gamelist/Responsiveness", 100).toInt());
  qmc2GamelistResponsiveness = spinBoxResponsiveness->value();
  spinBoxUpdateDelay->setValue(config->value(QMC2_FRONTEND_PREFIX + "Gamelist/UpdateDelay", 10).toInt());
  qmc2UpdateDelay = spinBoxUpdateDelay->value();
  comboBoxSortCriteria->setCurrentIndex(config->value(QMC2_FRONTEND_PREFIX + "Gamelist/SortCriteria", 0).toInt());
  qmc2SortCriteria = comboBoxSortCriteria->currentIndex();
  comboBoxSortOrder->setCurrentIndex(config->value(QMC2_FRONTEND_PREFIX + "Gamelist/SortOrder", 0).toInt());
  qmc2SortOrder = comboBoxSortOrder->currentIndex() == 0 ? Qt::AscendingOrder : Qt::DescendingOrder;
  qmc2Filter.setBit(QMC2_ROMSTATE_INT_C, config->value(QMC2_FRONTEND_PREFIX + "Gamelist/ShowC", TRUE).toBool());
  toolButtonShowC->setChecked(qmc2Filter[QMC2_ROMSTATE_INT_C]);
  qmc2Filter.setBit(QMC2_ROMSTATE_INT_M, config->value(QMC2_FRONTEND_PREFIX + "Gamelist/ShowM", TRUE).toBool());
  toolButtonShowM->setChecked(qmc2Filter[QMC2_ROMSTATE_INT_M]);
  qmc2Filter.setBit(QMC2_ROMSTATE_INT_I, config->value(QMC2_FRONTEND_PREFIX + "Gamelist/ShowI", TRUE).toBool());
  toolButtonShowI->setChecked(qmc2Filter[QMC2_ROMSTATE_INT_I]);
  qmc2Filter.setBit(QMC2_ROMSTATE_INT_N, config->value(QMC2_FRONTEND_PREFIX + "Gamelist/ShowN", TRUE).toBool());
  toolButtonShowN->setChecked(qmc2Filter[QMC2_ROMSTATE_INT_N]);
  qmc2Filter.setBit(QMC2_ROMSTATE_INT_U, config->value(QMC2_FRONTEND_PREFIX + "Gamelist/ShowU", TRUE).toBool());
  toolButtonShowU->setChecked(qmc2Filter[QMC2_ROMSTATE_INT_U]);

  if ( qmc2MainWindow ) {
    qmc2StatesTogglesEnabled = FALSE;
    qmc2MainWindow->actionRomStatusFilterC->setChecked(qmc2Filter[QMC2_ROMSTATE_INT_C]);
    qmc2MainWindow->actionRomStatusFilterM->setChecked(qmc2Filter[QMC2_ROMSTATE_INT_M]);
    qmc2MainWindow->actionRomStatusFilterI->setChecked(qmc2Filter[QMC2_ROMSTATE_INT_I]);
    qmc2MainWindow->actionRomStatusFilterN->setChecked(qmc2Filter[QMC2_ROMSTATE_INT_N]);
    qmc2MainWindow->actionRomStatusFilterU->setChecked(qmc2Filter[QMC2_ROMSTATE_INT_U]);
  }

  // Shortcuts / Keys
  QMapIterator<QString, QPair<QString, QAction *> > it(qmc2ShortcutMap);
  while ( it.hasNext() ) {
    it.next();
    QString itShortcut = it.key();
    QString itFunction = it.value().first;
    QTreeWidgetItem *item = new QTreeWidgetItem(treeWidgetShortcuts);
    item->setText(0, itFunction);
    QStringList words = itShortcut.split("+");
    QString itemText;
    int i;
    for (i = 0; i < words.count(); i++) {
      if ( i > 0 ) itemText += "+";
      itemText += QObject::tr(words[i].toAscii());
    }
    item->setText(1, itemText);
    QString customSC = config->value(QString(QMC2_FRONTEND_PREFIX + "Shortcuts/%1").arg(itShortcut), itShortcut).toString();
    qmc2CustomShortcutMap[itShortcut] = customSC;
    if ( customSC != itShortcut ) {
      words = customSC.split("+");
      customSC = "";
      for (i = 0; i < words.count(); i++) {
        if ( i > 0 ) customSC += "+";
        customSC += QObject::tr(words[i].toAscii());
      }
      item->setText(2, customSC);
    }
  }

  // Joystick
#if QMC2_JOYSTICK == 1
  checkBoxEnableJoystickControl->setChecked(config->value(QMC2_FRONTEND_PREFIX + "Joystick/EnableJoystickControl", FALSE).toBool());
  checkBoxJoystickAutoRepeat->setChecked(config->value(QMC2_FRONTEND_PREFIX + "Joystick/AutoRepeat", TRUE).toBool());
  spinBoxJoystickAutoRepeatTimeout->setValue(config->value(QMC2_FRONTEND_PREFIX + "Joystick/AutoRepeatTimeout", 250).toInt());
  spinBoxJoystickEventTimeout->setValue(config->value(QMC2_FRONTEND_PREFIX + "Joystick/EventTimeout", 25).toInt());
  on_pushButtonRescanJoysticks_clicked();

  // Joystick function map
  it.toFront();
  while ( it.hasNext() ) {
    it.next();
    QString itShortcut = it.key();
    QString itFunction = it.value().first;
    QTreeWidgetItem *item = new QTreeWidgetItem(treeWidgetJoystickMappings);
    item->setText(0, itFunction);
    item->setWhatsThis(0, itShortcut);
    QString joyMapFunction = config->value(QString(QMC2_FRONTEND_PREFIX + "Joystick/Map/%1").arg(itShortcut), "").toString();
    if ( !joyMapFunction.isEmpty() ) {
      qmc2JoystickFunctionMap.insertMulti(joyMapFunction, itShortcut);
      item->setText(1, joyMapFunction);
    }
  }
#endif

  // Tools
  lineEditZipTool->setText(config->value(QMC2_FRONTEND_PREFIX + "Tools/ZipTool", "zip").toString());
  lineEditZipToolRemovalArguments->setText(config->value(QMC2_FRONTEND_PREFIX + "Tools/ZipToolRemovalArguments", "$ARCHIVE$ -d $FILELIST$").toString());
  lineEditFileRemovalTool->setText(config->value(QMC2_FRONTEND_PREFIX + "Tools/FileRemovalTool", "rm").toString());
  lineEditFileRemovalToolArguments->setText(config->value(QMC2_FRONTEND_PREFIX + "Tools/FileRemovalToolArguments", "-f -v $FILELIST$").toString());

  // Emulator

  // Configuration
  if ( qmc2GuiReady )
    qmc2GlobalEmulatorOptions->load();

  // Files and directories
#if defined(QMC2_SDLMAME)
  lineEditExecutableFile->setText(config->value("MAME/FilesAndDirectories/ExecutableFile", "").toString());
  lineEditEmulatorLogFile->setText(config->value("MAME/FilesAndDirectories/LogFile", userScopePath + "/mame.log").toString());
  lineEditListXMLCache->setText(config->value("MAME/FilesAndDirectories/ListXMLCache", userScopePath + "/mame.lxc").toString());
  lineEditGamelistCacheFile->setText(config->value("MAME/FilesAndDirectories/GamelistCacheFile", userScopePath + "/mame.glc").toString());
  lineEditROMStateCacheFile->setText(config->value("MAME/FilesAndDirectories/ROMStateCacheFile", userScopePath + "/mame.rsc").toString());
  lineEditOptionsTemplateFile->setText(config->value("MAME/FilesAndDirectories/OptionsTemplateFile", QMC2_DEFAULT_DATA_PATH + "/opt/template.xml").toString());
  lineEditFavoritesFile->setText(config->value("MAME/FilesAndDirectories/FavoritesFile", userScopePath + "/mame.fav").toString());
  lineEditHistoryFile->setText(config->value("MAME/FilesAndDirectories/HistoryFile", userScopePath + "/mame.hst").toString());
#elif defined(QMC2_SDLMESS)
  lineEditExecutableFile->setText(config->value("MESS/FilesAndDirectories/ExecutableFile", "").toString());
  lineEditEmulatorLogFile->setText(config->value("MESS/FilesAndDirectories/LogFile", userScopePath + "/mess.log").toString());
  lineEditListXMLCache->setText(config->value("MESS/FilesAndDirectories/ListXMLCache", userScopePath + "/mess.lxc").toString());
  lineEditGamelistCacheFile->setText(config->value("MESS/FilesAndDirectories/GamelistCacheFile", userScopePath + "/mess.glc").toString());
  lineEditROMStateCacheFile->setText(config->value("MESS/FilesAndDirectories/ROMStateCacheFile", userScopePath + "/mess.rsc").toString());
  lineEditOptionsTemplateFile->setText(config->value("MESS/FilesAndDirectories/OptionsTemplateFile", QMC2_DEFAULT_DATA_PATH + "/opt/template.xml").toString());
  lineEditFavoritesFile->setText(config->value("MESS/FilesAndDirectories/FavoritesFile", userScopePath + "/mess.fav").toString());
  lineEditHistoryFile->setText(config->value("MESS/FilesAndDirectories/HistoryFile", userScopePath + "/mess.hst").toString());
#endif

  if ( useDefaultSettings ) {
    QString fn = config->fileName();
    delete config;
    QFile f0(fn);
    f0.remove();
    QFile f(fn + ".bak");
    f.copy(fn);
    f.remove();
    config = new QSettings(QSettings::IniFormat, QSettings::UserScope, "qmc2");
    qmc2Config = config;
  }

  QTimer::singleShot(0, this, SLOT(applyDelayed()));
}

void Options::applyDelayed()
{
  // just for safety :)...
  if ( qmc2MainWindow == NULL ) {
    QTimer::singleShot(0, this, SLOT(applyDelayed()));
    return;
  }

  static bool firstTime = TRUE;

  if ( firstTime ) {
    setParent(qmc2MainWindow, Qt::Dialog | Qt::SubWindow);
    // restore layout
    if ( config->value(QMC2_FRONTEND_PREFIX + "GUI/RestoreLayout").toBool() ) {
      tabWidgetFrontendSettings->setCurrentIndex(config->value(QMC2_FRONTEND_PREFIX + "Layout/OptionsWidget/FrontendTab", 0).toInt());
      tabWidgetGlobalMAMESetup->setCurrentIndex(config->value(QMC2_FRONTEND_PREFIX + "Layout/OptionsWidget/MAMETab", 0).toInt());
      tabWidgetOptions->setCurrentIndex(config->value(QMC2_FRONTEND_PREFIX + "Layout/OptionsWidget/OptionsTab", 0).toInt());
      QStringList cl = config->allKeys();
      if ( cl.contains(QMC2_FRONTEND_PREFIX + "Layout/OptionsWidget/Size") )
        resize(config->value(QMC2_FRONTEND_PREFIX + "Layout/OptionsWidget/Size").toSize());
      if ( cl.contains(QMC2_FRONTEND_PREFIX + "Layout/OptionsWidget/Position") )
        move(config->value(QMC2_FRONTEND_PREFIX + "Layout/OptionsWidget/Position").toPoint());
      if ( cl.contains(QMC2_FRONTEND_PREFIX + "Layout/OptionsWidget/Visible") )
        if ( config->value(QMC2_FRONTEND_PREFIX + "Layout/OptionsWidget/Visible").toBool() )
          show();
      treeWidgetShortcuts->header()->restoreState(config->value(QMC2_FRONTEND_PREFIX + "Layout/OptionsWidget/ShortcutsHeaderState").toByteArray());
#if QMC2_JOYSTICK == 1
      treeWidgetJoystickMappings->header()->restoreState(config->value(QMC2_FRONTEND_PREFIX + "Layout/OptionsWidget/JoyMapHeaderState").toByteArray());
#endif
    }
    firstTime = FALSE;
  }

  // hide / show the menu bar
  qmc2MainWindow->menuBar()->setVisible(checkBoxShowMenuBar->isChecked());
  qApp->processEvents();
  qmc2VariantSwitchReady = TRUE;
}

void Options::on_toolButtonBrowseTemporaryFile_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_toolButtonBrowseTemporaryFile_clicked()");
#endif

  QString s = QFileDialog::getOpenFileName(this, tr("Choose temporary work file"), lineEditTemporaryFile->text(), tr("All files (*)"));
  if ( !s.isNull() )
    lineEditTemporaryFile->setText(s);
  raise();
}

void Options::on_toolButtonBrowsePreviewDirectory_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_toolButtonBrowsePreviewDirectory_clicked()");
#endif

  QString s = QFileDialog::getExistingDirectory(this, tr("Choose preview directory"), lineEditPreviewDirectory->text(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
  if ( !s.isNull() ) {
    if ( !s.endsWith("/") ) s += "/";
    lineEditPreviewDirectory->setText(s);
  }
  raise();
}

void Options::on_toolButtonBrowseFlyerDirectory_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_toolButtonBrowseFlyerDirectory_clicked()");
#endif

  QString s = QFileDialog::getExistingDirectory(this, tr("Choose flyer directory"), lineEditFlyerDirectory->text(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
  if ( !s.isNull() ) {
    if ( !s.endsWith("/") ) s += "/";
    lineEditFlyerDirectory->setText(s);
  }
  raise();
}

void Options::on_toolButtonBrowseIconDirectory_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_toolButtonBrowseIconDirectory_clicked()");
#endif

  QString s = QFileDialog::getExistingDirectory(this, tr("Choose icon directory"), lineEditIconDirectory->text(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
  if ( !s.isNull() ) {
    if ( !s.endsWith("/") ) s += "/";
    lineEditIconDirectory->setText(s);
  }
  raise();
}

void Options::on_toolButtonBrowseOptionsTemplateFile_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_toolButtonBrowseOptionsTemplateFile_clicked()");
#endif

  QString s = QFileDialog::getOpenFileName(this, tr("Choose options template file"), lineEditOptionsTemplateFile->text(), tr("All files (*)"));
  if ( !s.isNull() )
    lineEditOptionsTemplateFile->setText(s);
  raise();
}

void Options::on_toolButtonBrowseExecutableFile_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_toolButtonBrowseExecutableFile_clicked()");
#endif

  QString s = QFileDialog::getOpenFileName(this, tr("Choose emulator executable file"), lineEditExecutableFile->text(), tr("All files (*)"));
  if ( !s.isNull() )
    lineEditExecutableFile->setText(s);
  raise();
}

void Options::on_toolButtonBrowseEmulatorLogFile_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_toolButtonBrowseEmulatorLogFile_clicked()");
#endif

  QString s = QFileDialog::getOpenFileName(this, tr("Choose emulator log file"), lineEditEmulatorLogFile->text(), tr("All files (*)"));
  if ( !s.isNull() )
    lineEditEmulatorLogFile->setText(s);
  raise();
}

void Options::on_toolButtonBrowseListXMLCache_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_toolButtonListXMLCache_clicked()");
#endif

  QString s = QFileDialog::getOpenFileName(this, tr("Choose XML gamelist cache file"), lineEditListXMLCache->text(), tr("All files (*)"));
  if ( !s.isNull() )
    lineEditListXMLCache->setText(s);
  raise();
}

void Options::on_toolButtonBrowseZipTool_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_toolButtonZipTool_clicked()");
#endif

  QString s = QFileDialog::getOpenFileName(this, tr("Choose zip tool"), lineEditZipTool->text(), tr("All files (*)"));
  if ( !s.isNull() )
    lineEditZipTool->setText(s);
  raise();
}

void Options::on_toolButtonBrowseFileRemovalTool_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_toolButtonFileRemovalTool_clicked()");
#endif

  QString s = QFileDialog::getOpenFileName(this, tr("Choose file removal tool"), lineEditFileRemovalTool->text(), tr("All files (*)"));
  if ( !s.isNull() )
    lineEditFileRemovalTool->setText(s);
  raise();
}

void Options::on_toolButtonBrowseFavoritesFile_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_toolButtonBrowseFavoritesFile_clicked()");
#endif

  QString s = QFileDialog::getOpenFileName(this, tr("Choose game favorites file"), lineEditFavoritesFile->text(), tr("All files (*)"));
  if ( !s.isNull() )
    lineEditFavoritesFile->setText(s);
  raise();
}

void Options::on_toolButtonBrowseHistoryFile_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_toolButtonBrowseHistoryFile_clicked()");
#endif

  QString s = QFileDialog::getOpenFileName(this, tr("Choose play history file"), lineEditHistoryFile->text(), tr("All files (*)"));
  if ( !s.isNull() )
    lineEditHistoryFile->setText(s);
  raise();
}

void Options::on_toolButtonBrowseGamelistCacheFile_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_toolButtonBrowseGamelistCacheFile_clicked()");
#endif

  QString s = QFileDialog::getOpenFileName(this, tr("Choose gamelist cache file"), lineEditGamelistCacheFile->text(), tr("All files (*)"));
  if ( !s.isNull() )
    lineEditGamelistCacheFile->setText(s);
  raise();
}

void Options::on_toolButtonBrowseROMStateCacheFile_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_toolButtonBrowseROMStateCacheFile_clicked()");
#endif

  QString s = QFileDialog::getOpenFileName(this, tr("Choose ROM state cache file"), lineEditROMStateCacheFile->text(), tr("All files (*)"));
  if ( !s.isNull() )
    lineEditROMStateCacheFile->setText(s);
  raise();
}

void Options::on_toolButtonBrowseFrontendLogFile_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_toolButtonBrowseFrontendLogFile_clicked()");
#endif

  QString s = QFileDialog::getOpenFileName(this, tr("Choose frontend log file"), lineEditFrontendLogFile->text(), tr("All files (*)"));
  if ( !s.isNull() )
    lineEditFrontendLogFile->setText(s);
  raise();
}

void Options::on_toolButtonBrowseDataDirectory_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_toolButtonBrowseDataDirectory_clicked()");
#endif

  QString s = QFileDialog::getExistingDirectory(this, tr("Choose data directory"), lineEditDataDirectory->text(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
  if ( !s.isNull() )
    lineEditDataDirectory->setText(s);
  raise();
}

void Options::on_toolButtonBrowseGameInfoDB_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_toolButtonBrowseGameInfoDB_clicked()");
#endif

  QString s = QFileDialog::getOpenFileName(this, tr("Choose game info DB"), lineEditGameInfoDB->text(), tr("All files (*)"));
  if ( !s.isNull() )
    lineEditGameInfoDB->setText(s);
  raise();
}

#if defined(QMC2_SDLMAME)
void Options::on_toolButtonBrowseEmuInfoDB_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_toolButtonBrowseEmuInfoDB_clicked()");
#endif

  QString s = QFileDialog::getOpenFileName(this, tr("Choose emulator info DB"), lineEditEmuInfoDB->text(), tr("All files (*)"));
  if ( !s.isNull() )
    lineEditEmuInfoDB->setText(s);
  raise();
}
#endif

void Options::on_toolButtonBrowseFont_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_toolButtonBrowseFont_clicked()");
#endif

  bool ok;
  QFont currentFont;
  currentFont.fromString(lineEditFont->text());
  QFont f = QFontDialog::getFont(&ok, currentFont, 0);
  if ( ok ) {
    lineEditFont->setFont(f);
    lineEditFont->setText(f.toString());
  }
  raise();
}

void Options::closeEvent(QCloseEvent *e)
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::closeEvent(QCloseEvent *e = 0x" + QString::number((ulong)e, 16) + ")");
#endif

  e->accept();
}

void Options::showEvent(QShowEvent *e)
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::showEvent(QShowEvent *e = 0x" + QString::number((ulong)e, 16) + ")");
#endif

  if ( !qmc2CleaningUp && !qmc2EarlyStartup )
    if ( config->value(QMC2_FRONTEND_PREFIX + "GUI/SaveLayout").toBool() )
      config->setValue(QMC2_FRONTEND_PREFIX + "Layout/OptionsWidget/Visible", TRUE);

  e->accept();
}

void Options::hideEvent(QHideEvent *e)
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::hideEvent(QHideEvent *e = 0x" + QString::number((ulong)e, 16) + ")");
#endif

  if ( !qmc2CleaningUp && !qmc2EarlyStartup )
    if ( config->value(QMC2_FRONTEND_PREFIX + "GUI/SaveLayout").toBool() )
      config->setValue(QMC2_FRONTEND_PREFIX + "Layout/OptionsWidget/Visible", FALSE);

  e->accept();
}

void Options::moveEvent(QMoveEvent *e)
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::moveEvent(QMoveEvent *e = 0x" + QString::number((ulong)e, 16) + ")");
#endif

  if ( !qmc2CleaningUp && !qmc2EarlyStartup )
    if ( config->value(QMC2_FRONTEND_PREFIX + "GUI/SaveLayout").toBool() )
      config->setValue(QMC2_FRONTEND_PREFIX + "Layout/OptionsWidget/Position", pos());

  e->accept();
}

void Options::resizeEvent(QResizeEvent *e)
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::resizeEvent(QResizeEvent *e = 0x" + QString::number((ulong)e, 16) + ")");
#endif

  if ( !qmc2CleaningUp && !qmc2EarlyStartup )
    if ( config->value(QMC2_FRONTEND_PREFIX + "GUI/SaveLayout").toBool() )
      config->setValue(QMC2_FRONTEND_PREFIX + "Layout/OptionsWidget/Size", size());

  e->accept();
}

void Options::on_radioButtonPreviewSelect_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_radioButtonPreviewSelect_clicked()");
#endif

  bool currentUsePreviewFile = (stackedWidgetPreview->currentIndex() == 1);
  stackedWidgetPreview->setCurrentIndex(!currentUsePreviewFile);
  radioButtonPreviewSelect->setText(!currentUsePreviewFile ? tr("Preview file") : tr("Preview directory"));
}

void Options::on_radioButtonFlyerSelect_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_radioButtonFlyerSelect_clicked()");
#endif

  bool currentUseFlyerFile = (stackedWidgetFlyer->currentIndex() == 1);
  stackedWidgetFlyer->setCurrentIndex(!currentUseFlyerFile);
  radioButtonFlyerSelect->setText(!currentUseFlyerFile ? tr("Flyer file") : tr("Flyer directory"));
}

void Options::on_radioButtonIconSelect_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_radioButtonIconSelect_clicked()");
#endif

  bool currentUseIconFile = (stackedWidgetIcon->currentIndex() == 1);
  stackedWidgetIcon->setCurrentIndex(!currentUseIconFile);
  radioButtonIconSelect->setText(!currentUseIconFile ? tr("Icon file") : tr("Icon directory"));
}

void Options::on_toolButtonBrowsePreviewFile_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_toolButtonBrowsePreviewFile_clicked()");
#endif

  QString s = QFileDialog::getOpenFileName(this, tr("Choose ZIP-compressed preview file"), lineEditPreviewFile->text(), tr("All files (*)"));
  if ( !s.isNull() )
    lineEditPreviewFile->setText(s);
  raise();
}

void Options::on_toolButtonBrowseFlyerFile_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_toolButtonBrowseFlyerFile_clicked()");
#endif

  QString s = QFileDialog::getOpenFileName(this, tr("Choose ZIP-compressed flyer file"), lineEditFlyerFile->text(), tr("All files (*)"));
  if ( !s.isNull() )
    lineEditFlyerFile->setText(s);
  raise();
}

void Options::on_toolButtonBrowseIconFile_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_toolButtonBrowseIconFile_clicked()");
#endif

  QString s = QFileDialog::getOpenFileName(this, tr("Choose ZIP-compressed icon file"), lineEditIconFile->text(), tr("All files (*)"));
  if ( !s.isNull() )
    lineEditIconFile->setText(s);
  raise();
}

void Options::on_treeWidgetShortcuts_itemActivated(QTreeWidgetItem *item)
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_treeWidgetShortcuts_itemActivated(QTreeWidgetItem *item = 0x"+ QString::number((ulong)item, 16) + ")");
#endif

  if ( !item )
    return;

  qApp->removeEventFilter(qmc2KeyPressFilter);

  KeySequenceScanner keySeqScanner(this, qmc2QtKeyMap.contains(item->text(1)));
  if ( keySeqScanner.exec() == QDialog::Accepted ) {
    QStringList words = item->text(1).split("+");
    QString nativeShortcut = "";
    int i;
    for (i = 0; i < words.count(); i++) {
      if ( i > 0 ) nativeShortcut += "+";
      nativeShortcut += QObject::tr(words[i].toAscii());
    }

    bool found = FALSE;
    QMapIterator<QString, QPair<QString, QAction *> > it(qmc2ShortcutMap);
    while ( it.hasNext() && !found ) {
      it.next();
      words = it.key().split("+");
      QString itShortcut = "";
      for (i = 0; i < words.count(); i++) {
        if ( i > 0 ) itShortcut += "+";
        itShortcut += QObject::tr(words[i].toAscii());
      }

      if ( itShortcut == nativeShortcut ) {
        found = TRUE;
        nativeShortcut = it.key();
      }
    }

    if ( found ) {
      qmc2CustomShortcutMap[nativeShortcut] = keySeqScanner.currentKeySequence;
      item->setText(2, keySeqScanner.labelKeySequence->text());
      QTimer::singleShot(0, this, SLOT(checkShortcuts()));
    }

    pushButtonResetShortcut->setEnabled(TRUE);
  }

  qApp->installEventFilter(qmc2KeyPressFilter);
}

void Options::on_treeWidgetShortcuts_itemSelectionChanged()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_treeWidgetShortcuts_itemSelectionChanged()");
#endif

  QList<QTreeWidgetItem *> selItems = treeWidgetShortcuts->selectedItems();
  if ( selItems.count() > 0 ) {
    pushButtonRedefineKeySequence->setEnabled(TRUE);
    pushButtonResetShortcut->setEnabled(selItems[0]->text(2).length() > 0);
  } else {
    pushButtonRedefineKeySequence->setEnabled(FALSE);
    pushButtonResetShortcut->setEnabled(FALSE);
  }
}

void Options::on_pushButtonRedefineKeySequence_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_pushButtonRedefineKeySequence_clicked()");
#endif

  QList<QTreeWidgetItem *> selItems = treeWidgetShortcuts->selectedItems();
  if ( selItems.count() > 0 )
    on_treeWidgetShortcuts_itemActivated(selItems[0]);
}

void Options::on_pushButtonResetShortcut_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_pushButtonResetShortcut_clicked()");
#endif

  QList<QTreeWidgetItem *> selItems = treeWidgetShortcuts->selectedItems();
  if ( selItems.count() > 0 ) {
    QStringList words = selItems[0]->text(1).split("+");
    QString nativeShortcut = "";
    int i;
    for (i = 0; i < words.count(); i++) {
      if ( i > 0 ) nativeShortcut += "+";
      nativeShortcut += QObject::tr(words[i].toAscii());
    }

    bool found = FALSE;
    QMapIterator<QString, QPair<QString, QAction *> > it(qmc2ShortcutMap);
    while ( it.hasNext() && !found ) {
      it.next();
      words = it.key().split("+");
      QString itShortcut = "";
      for (i = 0; i < words.count(); i++) {
        if ( i > 0 ) itShortcut += "+";
        itShortcut += QObject::tr(words[i].toAscii());
      }

      if ( itShortcut == nativeShortcut ) {
        found = TRUE;
        nativeShortcut = it.key();
      }
    }

    if ( found ) {
      qmc2CustomShortcutMap[nativeShortcut] = nativeShortcut;
      selItems[0]->setText(2, "");
      QTimer::singleShot(0, this, SLOT(checkShortcuts()));
    }

    pushButtonResetShortcut->setEnabled(FALSE);
  }
}

void Options::checkShortcuts()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::checkShortcuts()");
#endif

  static QBrush redBrush(QColor(255, 0, 0));
  static QBrush greenBrush(QColor(0, 255, 0));
  static QBrush greyBrush(QColor(128, 128, 128));
  static char lastShortcutsState = -1;

  char shortcutsState = 1;
  int itemCount = treeWidgetShortcuts->topLevelItemCount();
  int i, j;
  for (i = 0; i < itemCount; i++) {
    QTreeWidgetItem *iItem = treeWidgetShortcuts->topLevelItem(i);
    if ( iItem->text(2).isEmpty() )
      iItem->setForeground(1, greenBrush);
    else
      iItem->setForeground(1, greyBrush);
    iItem->setForeground(2, greenBrush);
  }
  for (i = 0; i < itemCount; i++) {
    QTreeWidgetItem *iItem = treeWidgetShortcuts->topLevelItem(i);
    QString iShortcut;
    int iColumn = 1;
    if ( !iItem->text(2).isEmpty() )
      iColumn = 2;
    iShortcut = iItem->text(iColumn);
    for (j = i + 1; j < itemCount; j++) {
      QTreeWidgetItem *jItem = treeWidgetShortcuts->topLevelItem(j);
      QString jShortcut;
      int jColumn = 1;
      if ( !jItem->text(2).isEmpty() )
        jColumn = 2;
      jShortcut = jItem->text(jColumn);
      if ( iShortcut == jShortcut ) {
        iItem->setForeground(iColumn, redBrush);
        jItem->setForeground(jColumn, redBrush);
        shortcutsState = 0;
      }
    }
  }

  if ( shortcutsState != lastShortcutsState || lastShortcutsState == -1 ) {
    if ( shortcutsState == 1 )
      qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("shortcut map is clean"));
    else
      qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: shortcut map contains duplicates"));
  }
  lastShortcutsState = shortcutsState;
}

void Options::setupShortcutActions()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::setupShortcutActions()");
#endif

  QMapIterator<QString, QPair<QString, QAction *> > it(qmc2ShortcutMap);
  while ( it.hasNext() ) {
    it.next();
    QAction *action = it.value().second;
    if ( action ) {
      action->setShortcut(QKeySequence(qmc2CustomShortcutMap[it.key()]));
      action->setShortcutContext(Qt::ApplicationShortcut);
    }
  }
}

#if QMC2_JOYSTICK == 1
void Options::on_pushButtonRescanJoysticks_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_pushButtonRescanJoysticks_clicked()");
#endif

  toolButtonMapJoystick->setChecked(TRUE);
  on_toolButtonMapJoystick_clicked();

  QStringList joystickNames;
  joystickNames << tr("No joysticks found");

  if ( joystick )
    delete joystick;
  joystick = new Joystick(0, 
                          spinBoxJoystickEventTimeout->value(),
                          checkBoxJoystickAutoRepeat->isChecked(),
                          spinBoxJoystickAutoRepeatTimeout->value());
  if ( joystick )
    if ( joystick->joystickNames.count() > 0 )
      joystickNames = joystick->joystickNames;

  comboBoxSelectJoysticks->clear();
  comboBoxSelectJoysticks->insertItems(0, joystickNames);
  comboBoxSelectJoysticks->setCurrentIndex(config->value(QMC2_FRONTEND_PREFIX + "Joystick/Index", 0).toInt());
}

void Options::on_toolButtonCalibrateAxes_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_toolButtonCalibrateAxes_clicked()");
#endif

  if ( comboBoxSelectJoysticks->currentText() == tr("No joysticks found") || index < 0 ) {
    toolButtonMapJoystick->setChecked(TRUE);
    on_toolButtonMapJoystick_clicked();
    return;
  }

  if ( joystick ) {
    if ( joystick->isOpen() )
      joystick->close();
    if ( joystick->open(comboBoxSelectJoysticks->currentIndex()) ) {
      // create joystick calibration widget
      QGridLayout *myLayout = (QGridLayout *)qmc2Options->groupBoxCalibrationAndTest->layout();
      if ( joystickTestWidget ) {
        myLayout->removeWidget(scrollArea);
        scrollArea->takeWidget();
        scrollArea->hide();
        delete joystickTestWidget;
        joystickTestWidget = NULL;
      } else if ( joystickCalibrationWidget ) {
        myLayout->removeWidget(scrollArea);
        scrollArea->takeWidget();
        scrollArea->hide();
        delete joystickCalibrationWidget;
        joystickCalibrationWidget = NULL;
      } else {
        myLayout->removeWidget(pushButtonRemapJoystickFunction);
        myLayout->removeWidget(pushButtonRemoveJoystickMapping);
        myLayout->removeWidget(treeWidgetJoystickMappings);
        pushButtonRemapJoystickFunction->hide();
        pushButtonRemoveJoystickMapping->hide();
        treeWidgetJoystickMappings->hide();
      }
      joystickCalibrationWidget = new JoystickCalibrationWidget(joystick, groupBoxCalibrationAndTest);
      myLayout->addWidget(scrollArea);
      scrollArea->setWidget(joystickCalibrationWidget);
      scrollArea->show();
      joystickCalibrationWidget->show();
    } else {
      toolButtonMapJoystick->setChecked(TRUE);
      on_toolButtonMapJoystick_clicked();
    }
  } else {
    toolButtonMapJoystick->setChecked(TRUE);
    on_toolButtonMapJoystick_clicked();
  }
}

void Options::on_toolButtonTestJoystick_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_toolButtonTestJoystick_clicked()");
#endif

  if ( comboBoxSelectJoysticks->currentText() == tr("No joysticks found") || index < 0 ) {
    toolButtonMapJoystick->setChecked(TRUE);
    on_toolButtonMapJoystick_clicked();
    return;
  }

  if ( joystick ) {
    if ( joystick->isOpen() )
      joystick->close();
    if ( joystick->open(comboBoxSelectJoysticks->currentIndex()) ) {
      // create joystick test widget
      QGridLayout *myLayout = (QGridLayout *)qmc2Options->groupBoxCalibrationAndTest->layout();
      if ( joystickTestWidget ) {
        myLayout->removeWidget(scrollArea);
        scrollArea->takeWidget();
        scrollArea->hide();
        delete joystickTestWidget;
        joystickTestWidget = NULL;
      } else if ( joystickCalibrationWidget ) {
        myLayout->removeWidget(scrollArea);
        scrollArea->takeWidget();
        scrollArea->hide();
        delete joystickCalibrationWidget;
        joystickCalibrationWidget = NULL;
      } else {
        myLayout->removeWidget(pushButtonRemapJoystickFunction);
        myLayout->removeWidget(pushButtonRemoveJoystickMapping);
        myLayout->removeWidget(treeWidgetJoystickMappings);
        pushButtonRemapJoystickFunction->hide();
        pushButtonRemoveJoystickMapping->hide();
        treeWidgetJoystickMappings->hide();
      }
      joystickTestWidget = new JoystickTestWidget(joystick, groupBoxCalibrationAndTest);
      myLayout->addWidget(scrollArea);
      scrollArea->setWidget(joystickTestWidget);
      scrollArea->show();
      joystickTestWidget->show();
    } else {
      toolButtonMapJoystick->setChecked(TRUE);
      on_toolButtonMapJoystick_clicked();
    }
  } else {
    toolButtonMapJoystick->setChecked(TRUE);
    on_toolButtonMapJoystick_clicked();
  }
}

void Options::on_toolButtonMapJoystick_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_toolButtonMapJoystick_clicked()");
#endif

  bool relayout = ( joystickCalibrationWidget || joystickTestWidget );
  
  if ( joystickCalibrationWidget ) {
    groupBoxCalibrationAndTest->layout()->removeWidget(scrollArea);
    scrollArea->takeWidget();
    scrollArea->hide();
    delete joystickCalibrationWidget;
    joystickCalibrationWidget = NULL;
  }
  if ( joystickTestWidget ) {
    groupBoxCalibrationAndTest->layout()->removeWidget(scrollArea);
    scrollArea->takeWidget();
    scrollArea->hide();
    delete joystickTestWidget;
    joystickTestWidget = NULL;
  }

  if ( relayout ) {
    QGridLayout *myLayout = (QGridLayout *)qmc2Options->groupBoxCalibrationAndTest->layout();
    myLayout->addWidget(pushButtonRemapJoystickFunction, 0, 0);
    myLayout->addWidget(pushButtonRemoveJoystickMapping, 0, 1);
    myLayout->addWidget(treeWidgetJoystickMappings, 1, 0, 1, 2);
    pushButtonRemapJoystickFunction->show();
    pushButtonRemoveJoystickMapping->show();
    treeWidgetJoystickMappings->show();
  }
}

void Options::on_comboBoxSelectJoysticks_currentIndexChanged(int index)
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, QString("DEBUG: Options::on_comboBoxSelectJoysticks_currentIndexChanged(int index = %1)").arg(index));
#endif

  if ( comboBoxSelectJoysticks->currentText() == tr("No joysticks found") || index < 0 ) {
    labelJoystickAxesNum->setText("0");
    labelJoystickButtonsNum->setText("0");
    labelJoystickHatsNum->setText("0");
    labelJoystickTrackballsNum->setText("0");
    return;
  }

  if ( joystick )
    if ( joystick->open(index) ) {
      labelJoystickAxesNum->setText(QString::number(joystick->numAxes));
      labelJoystickButtonsNum->setText(QString::number(joystick->numButtons));
      labelJoystickHatsNum->setText(QString::number(joystick->numHats));
      labelJoystickTrackballsNum->setText(QString::number(joystick->numTrackballs));
      joystick->close();
    }
}

void Options::on_checkBoxEnableJoystickControl_toggled(bool enable)
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, QString("DEBUG: Options::on_checkBoxEnableJoystickControl_toggled(bool enable = %1)").arg(enable));
#endif

  toolButtonMapJoystick->setChecked(TRUE);
  on_toolButtonMapJoystick_clicked();
}

void Options::on_checkBoxJoystickAutoRepeat_toggled(bool repeat)
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, QString("DEBUG: Options::on_checkBoxJoystickAutoRepeat_toggled(bool repeat = %1)").arg(repeat));
#endif

  if ( joystick )
    joystick->autoRepeat = repeat;
}

void Options::on_spinBoxJoystickAutoRepeatTimeout_valueChanged(int value)
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, QString("DEBUG: Options::on_spinBoxJoystickAutoRepeatTimeout_valueChanged(int value = %1)").arg(value));
#endif

  if ( joystick )
    joystick->autoRepeatDelay = value;
}

void Options::on_spinBoxJoystickEventTimeout_valueChanged(int value)
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, QString("DEBUG: Options::on_spinBoxJoystickEventTimeout_valueChanged(int value = %1)").arg(value));
#endif

  if ( joystick ) {
    joystick->eventTimeout = value;
    if ( joystick->isOpen() )
      joystick->joystickTimer.start(joystick->eventTimeout);
  }
}

void Options::on_treeWidgetJoystickMappings_itemActivated(QTreeWidgetItem *item)
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, QString("DEBUG: Options::on_treeWidgetJoystickMappings_itemActivated(QTreeWidgetItem *item = %1)").arg((qulonglong)item));
#endif

  if ( !item )
    return;

  if ( joystick ) {
    if ( joystick->isOpen() )
      joystick->close();
    if ( joystick->open(comboBoxSelectJoysticks->currentIndex()) ) {
      // suppress strange Qt warning messages (this works - basta! :)
      qmc2SuppressQtMessages = TRUE;
      JoystickFunctionScanner joyFuncScanner(joystick, this);
      if ( joyFuncScanner.exec() == QDialog::Accepted ) {
        item->setText(1, joyFuncScanner.labelJoystickFunction->text());
        qmc2JoystickFunctionMap.insertMulti(joyFuncScanner.labelJoystickFunction->text(), item->whatsThis(0));
        pushButtonRemoveJoystickMapping->setEnabled(item->text(1).length() > 0);
        QTimer::singleShot(0, this, SLOT(checkJoystickMappings()));
      }
      qmc2SuppressQtMessages = FALSE;
    }
  }
}

void Options::on_treeWidgetJoystickMappings_itemSelectionChanged()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_treeWidgetJoystickMappings_itemSelectionChanged()");
#endif

  QList<QTreeWidgetItem *> selItems = treeWidgetJoystickMappings->selectedItems();
  if ( selItems.count() > 0 ) {
    pushButtonRemapJoystickFunction->setEnabled(TRUE);
    pushButtonRemoveJoystickMapping->setEnabled(selItems[0]->text(1).length() > 0);
  } else {
    pushButtonRemapJoystickFunction->setEnabled(FALSE);
    pushButtonRemoveJoystickMapping->setEnabled(FALSE);
  }
}

void Options::on_pushButtonRemapJoystickFunction_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_pushButtonRemapJoystickFunction_clicked()");
#endif

  QList<QTreeWidgetItem *> selItems = treeWidgetJoystickMappings->selectedItems();
  if ( selItems.count() > 0 )
    on_treeWidgetJoystickMappings_itemActivated(selItems[0]);
}

void Options::on_pushButtonRemoveJoystickMapping_clicked()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::on_pushButtonRemapJoystickFunction_clicked()");
#endif

  QList<QTreeWidgetItem *> selItems = treeWidgetJoystickMappings->selectedItems();
  if ( selItems.count() > 0 ) {
    QList<QString> valueList = qmc2JoystickFunctionMap.values(selItems[0]->text(1));
    qmc2JoystickFunctionMap.remove(selItems[0]->text(1));
    if ( valueList.count() > 1 ) {
      int i;
      QString valueToRemove = selItems[0]->whatsThis(0);
      for (i = 0; i < valueList.count(); i++)
        if ( valueList[i] != valueToRemove )
          qmc2JoystickFunctionMap.insertMulti(selItems[0]->text(1), valueList[i]);
    }
    selItems[0]->setText(1, "");
    pushButtonRemoveJoystickMapping->setEnabled(FALSE);
    QTimer::singleShot(0, this, SLOT(checkJoystickMappings()));
  }
}

void Options::checkJoystickMappings()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: Options::checkJoystickMappings()");
#endif

  static QBrush redBrush(QColor(255, 0, 0));
  static QBrush greenBrush(QColor(0, 255, 0));
  static QBrush greyBrush(QColor(128, 128, 128));
  static char lastJoystickMappingsState = -1;

  char joystickMappingsState = 1;
  int itemCount = treeWidgetJoystickMappings->topLevelItemCount();
  int i, j;
  for (i = 0; i < itemCount; i++) {
    QTreeWidgetItem *iItem = treeWidgetJoystickMappings->topLevelItem(i);
    if ( !iItem->text(1).isEmpty() )
      iItem->setForeground(1, greenBrush);
  }
  for (i = 0; i < itemCount; i++) {
    QTreeWidgetItem *iItem = treeWidgetJoystickMappings->topLevelItem(i);
    QString iMapping = iItem->text(1);
    for (j = i + 1; j < itemCount; j++) {
      QTreeWidgetItem *jItem = treeWidgetJoystickMappings->topLevelItem(j);
      QString jMapping = jItem->text(1);
      if ( iMapping == jMapping && !jMapping.isEmpty() ) {
        iItem->setForeground(1, redBrush);
        jItem->setForeground(1, redBrush);
        joystickMappingsState = 0;
      }
    }
  }

  if ( joystickMappingsState != lastJoystickMappingsState || lastJoystickMappingsState == -1 ) {
    if ( joystickMappingsState == 1 )
      qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("joystick map is clean"));
    else
      qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: joystick map contains duplicates"));
  }
  lastJoystickMappingsState = joystickMappingsState;
}

JoystickCalibrationWidget::JoystickCalibrationWidget(Joystick *joystick, QWidget *parent)
  : QWidget(parent)
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, QString("DEBUG: JoystickCalibrationWidget::JoystickCalibrationWidget(Joystick *joystick = %1, QWidget *parent = %2)").arg((qulonglong)joystick).arg((qulonglong)parent));
#endif

  myJoystick = joystick;

  int i;
  int joyIndex = qmc2Options->comboBoxSelectJoysticks->currentIndex();

  myLayout = new QGridLayout(this);

  int minButtonWidth = 0;
  for (i = 0; i < myJoystick->numAxes; i++) {
    QHBoxLayout *hLayout = new QHBoxLayout();

    bool enabled = qmc2Config->value(QString(QMC2_FRONTEND_PREFIX + "Joystick/%1/Axis%2Enabled").arg(joyIndex).arg(i), TRUE).toBool();
    int minValue = qmc2Config->value(QString(QMC2_FRONTEND_PREFIX + "Joystick/%1/Axis%2Minimum").arg(joyIndex).arg(i), 0).toInt();
    axesMinimums[i] = minValue;
    int maxValue = qmc2Config->value(QString(QMC2_FRONTEND_PREFIX + "Joystick/%1/Axis%2Maximum").arg(joyIndex).arg(i), 0).toInt();
    axesMaximums[i] = maxValue;
    int dzValue = qmc2Config->value(QString(QMC2_FRONTEND_PREFIX + "Joystick/%1/Axis%2Deadzone").arg(joyIndex).arg(i), 0).toInt();
    int sValue = qmc2Config->value(QString(QMC2_FRONTEND_PREFIX + "Joystick/%1/Axis%2Sensitivity").arg(joyIndex).arg(i), 0).toInt();

    axesEnablers[i] = new QCheckBox(this);
    axesEnablers[i]->setChecked(enabled);
    axesEnablers[i]->setToolTip(tr("Enable/disable axis %1").arg(i));
    axesEnablers[i]->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
    connect(axesEnablers[i], SIGNAL(stateChanged(int)), this, SLOT(on_axisEnablerStateChanged(int)));
    axesButtons[i] = new QToolButton(this);
    axesButtons[i]->setText(tr("Axis %1:").arg(i));
    axesButtons[i]->setToolTip(tr("Reset calibration of axis %1").arg(i));
    axesButtons[i]->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
    axesButtons[i]->setEnabled(enabled);
    connect(axesButtons[i], SIGNAL(clicked()), this, SLOT(on_resetAxisCalibration()));
    if ( minButtonWidth < axesButtons[i]->sizeHint().width() )
      minButtonWidth = axesButtons[i]->sizeHint().width();
    axesRanges[i] = new QProgressBar(this);
    axesRanges[i]->setFormat("%v");
    axesRanges[i]->setToolTip(tr("Current value of axis %1").arg(i));
    axesRanges[i]->setRange(minValue, maxValue);
    axesRanges[i]->setValue(myJoystick->getAxisValue(i));
    axesRanges[i]->setEnabled(enabled);
    deadzoneLabels[i] = new QLabel(tr("DZ:"), this);
    axesDeadzones[i] = new QSpinBox(this);
    axesDeadzones[i]->setToolTip(tr("Deadzone of axis %1").arg(i));
    axesDeadzones[i]->setRange(0, 32767);
    axesDeadzones[i]->setSingleStep(1000);
    axesDeadzones[i]->setValue(dzValue);
    axesDeadzones[i]->setEnabled(enabled);
    connect(axesDeadzones[i], SIGNAL(valueChanged(int)), this, SLOT(on_deadzoneValueChanged(int)));
    sensitivityLabels[i] = new QLabel(tr("S:"), this);
    axesSensitivities[i] = new QSpinBox(this);
    axesSensitivities[i]->setToolTip(tr("Sensitivity of axis %1").arg(i));
    axesSensitivities[i]->setRange(0, 32767);
    axesSensitivities[i]->setSingleStep(100);
    axesSensitivities[i]->setValue(sValue);
    axesSensitivities[i]->setEnabled(enabled);
    connect(axesSensitivities[i], SIGNAL(valueChanged(int)), this, SLOT(on_sensitivityValueChanged(int)));
    
    hLayout->addWidget(axesEnablers[i]);
    hLayout->addWidget(axesButtons[i]);
    hLayout->addWidget(axesRanges[i]);
    hLayout->addWidget(deadzoneLabels[i]);
    hLayout->addWidget(axesDeadzones[i]);
    hLayout->addWidget(sensitivityLabels[i]);
    hLayout->addWidget(axesSensitivities[i]);

    myLayout->addLayout(hLayout, i, 0);
  }
  for (i = 0; i < myJoystick->numAxes; i++)
    axesButtons[i]->setMinimumWidth(minButtonWidth);
  // add spacer
  myLayout->addItem(new QSpacerItem(10, 10, QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding), i, 0);

  // connect joystick callbacks
  connect(myJoystick, SIGNAL(axisValueChanged(int, int)), this, SLOT(on_joystickAxisValueChanged(int, int)));
  connect(myJoystick, SIGNAL(buttonValueChanged(int, bool)), this, SLOT(on_joystickButtonValueChanged(int, bool)));
  connect(myJoystick, SIGNAL(hatValueChanged(int, int)), this, SLOT(on_joystickHatValueChanged(int, int)));
  connect(myJoystick, SIGNAL(trackballValueChanged(int, int, int)), this, SLOT(on_joystickTrackballValueChanged(int, int, int)));
}

JoystickCalibrationWidget::~JoystickCalibrationWidget()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: JoystickCalibrationWidget::~JoystickCalibrationWidget()");
#endif

  // ignore destruction when we are already cleaning up the application...
  if ( !qmc2Options->groupBoxCalibrationAndTest->layout() )
    return;

  int i;
  // remove spacer item first
  QLayoutItem *layoutItem = (QLayoutItem *)myLayout->takeAt(myJoystick->numAxes);
  delete layoutItem;
  for (i = myJoystick->numAxes - 1; i >= 0; i--) {
    QLayout *hLayout = (QLayout *)myLayout->takeAt(i);

    hLayout->removeWidget(axesSensitivities[i]);
    delete axesSensitivities[i];
    hLayout->removeWidget(sensitivityLabels[i]);
    delete sensitivityLabels[i];
    hLayout->removeWidget(axesDeadzones[i]);
    delete axesDeadzones[i];
    hLayout->removeWidget(deadzoneLabels[i]);
    delete deadzoneLabels[i];
    hLayout->removeWidget(axesRanges[i]);
    delete axesRanges[i];
    hLayout->removeWidget(axesButtons[i]);
    delete axesButtons[i];
    hLayout->removeWidget(axesEnablers[i]);
    delete axesEnablers[i];

    delete hLayout;
  }
}

void JoystickCalibrationWidget::on_joystickAxisValueChanged(int axis, int value)
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, QString("DEBUG: JoystickCalibrationWidget::on_joystickAxisValueChanged(int axis = %1, int value = %2)").arg(axis).arg(value));
#endif

  int joyIndex = qmc2Options->comboBoxSelectJoysticks->currentIndex();

  if ( value > axesMaximums[axis] ) {
    axesMaximums[axis] = value;
    qmc2Config->setValue(QString(QMC2_FRONTEND_PREFIX + "Joystick/%1/Axis%2Maximum").arg(joyIndex).arg(axis), value);
  }

  if ( value < axesMinimums[axis] ) {
    axesMinimums[axis] = value;
    qmc2Config->setValue(QString(QMC2_FRONTEND_PREFIX + "Joystick/%1/Axis%2Minimum").arg(joyIndex).arg(axis), value);
  }

  axesRanges[axis]->setRange(axesMinimums[axis], axesMaximums[axis]);
  axesRanges[axis]->setValue(value);
}

void JoystickCalibrationWidget::on_joystickButtonValueChanged(int button, bool value)
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, QString("DEBUG: JoystickCalibrationWidget::on_joystickButtonValueChanged(int button = %1, bool value = %2)").arg(button).arg(value));
#endif

}

void JoystickCalibrationWidget::on_joystickHatValueChanged(int hat, int value)
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, QString("DEBUG: JoystickCalibrationWidget::on_joystickHatValueChanged(int hat = %1, int value = %2)").arg(hat).arg(value));
#endif

}

void JoystickCalibrationWidget::on_joystickTrackballValueChanged(int trackball, int deltaX, int deltaY)
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, QString("DEBUG: JoystickCalibrationWidget::on_joystickTrackballValueChanged(int trackball = %1, int deltaX = %2, int deltaY = %3)").arg(trackball).arg(deltaX).arg(deltaY));
#endif

}

void JoystickCalibrationWidget::on_resetAxisCalibration()
{
  QToolButton *pressedButton = (QToolButton *)sender();

#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: JoystickCalibrationWidget::on_resetAxisCalibration()");
#endif

  QList<QToolButton *> buttonList = axesButtons.values();
  int i;
  for (i = 0; i < buttonList.count() && buttonList[i] != pressedButton; i++) ;
  if ( pressedButton == buttonList[i] ) {
    int joyIndex = qmc2Options->comboBoxSelectJoysticks->currentIndex();
    axesMinimums[i] = 0;
    qmc2Config->setValue(QString(QMC2_FRONTEND_PREFIX + "Joystick/%1/Axis%2Minimum").arg(joyIndex).arg(i), 0);
    axesMaximums[i] = 0;
    qmc2Config->setValue(QString(QMC2_FRONTEND_PREFIX + "Joystick/%1/Axis%2Maximum").arg(joyIndex).arg(i), 0);
    axesRanges[i]->setRange(0, 0);
    axesRanges[i]->setValue(0);
    axesDeadzones[i]->setValue(0);
    qmc2Config->setValue(QString(QMC2_FRONTEND_PREFIX + "Joystick/%1/Axis%2Deadzone").arg(joyIndex).arg(i), 0);
    axesSensitivities[i]->setValue(0);
    qmc2Config->setValue(QString(QMC2_FRONTEND_PREFIX + "Joystick/%1/Axis%2Sensitivity").arg(joyIndex).arg(i), 0);
  }
}

void JoystickCalibrationWidget::on_deadzoneValueChanged(int value)
{
  QSpinBox *spinBox = (QSpinBox *)sender();

#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, QString("DEBUG: JoystickCalibrationWidget::on_deadzoneValueChanged(int value = %1)").arg(value));
#endif

  QList<QSpinBox *> spinBoxList = axesDeadzones.values();
  int i;
  for (i = 0; i < spinBoxList.count() && spinBoxList[i] != spinBox; i++) ;
  if ( spinBox == spinBoxList[i] ) {
    int joyIndex = qmc2Options->comboBoxSelectJoysticks->currentIndex();
    qmc2Config->setValue(QString(QMC2_FRONTEND_PREFIX + "Joystick/%1/Axis%2Deadzone").arg(joyIndex).arg(i), value);
    myJoystick->deadzones[i] = value;
  }
}

void JoystickCalibrationWidget::on_sensitivityValueChanged(int value)
{
  QSpinBox *spinBox = (QSpinBox *)sender();

#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, QString("DEBUG: JoystickCalibrationWidget::on_sensitivityValueChanged(int value = %1)").arg(value));
#endif

  QList<QSpinBox *> spinBoxList = axesSensitivities.values();
  int i;
  for (i = 0; i < spinBoxList.count() && spinBoxList[i] != spinBox; i++) ;
  if ( spinBox == spinBoxList[i] ) {
    int joyIndex = qmc2Options->comboBoxSelectJoysticks->currentIndex();
    qmc2Config->setValue(QString(QMC2_FRONTEND_PREFIX + "Joystick/%1/Axis%2Sensitivity").arg(joyIndex).arg(i), value);
    myJoystick->sensitivities[i] = value;
  }
}

void JoystickCalibrationWidget::on_axisEnablerStateChanged(int state)
{
  QCheckBox *checkBox = (QCheckBox *)sender();

#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, QString("DEBUG: JoystickCalibrationWidget::on_axisEnablerStateChanged(int state = %1)").arg(state));
#endif

  QList<QCheckBox *> checkBoxList = axesEnablers.values();
  int i;
  for (i = 0; i < checkBoxList.count() && checkBoxList[i] != checkBox; i++) ;
  if ( checkBox == checkBoxList[i] ) {
    bool enabled = (state == 0 ? FALSE : TRUE);
    int joyIndex = qmc2Options->comboBoxSelectJoysticks->currentIndex();
    qmc2Config->setValue(QString(QMC2_FRONTEND_PREFIX + "Joystick/%1/Axis%2Enabled").arg(joyIndex).arg(i), enabled);
    
    axesButtons[i]->setEnabled(enabled);
    axesRanges[i]->setEnabled(enabled);
    axesDeadzones[i]->setEnabled(enabled);
    axesSensitivities[i]->setEnabled(enabled);
  }
}

JoystickTestWidget::JoystickTestWidget(Joystick *joystick, QWidget *parent)
  : QWidget(parent)
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, QString("DEBUG: JoystickTestWidget::JoystickTestWidget(Joystick *joystick = %1, QWidget *parent = %2)").arg((qulonglong)joystick).arg((qulonglong)parent));
#endif

  myJoystick = joystick;

  int i;
  int joyIndex = qmc2Options->comboBoxSelectJoysticks->currentIndex();
  int maxRows = MAX(MAX(MAX(myJoystick->numAxes, myJoystick->numButtons), myJoystick->numHats), myJoystick->numTrackballs);

  myLayout = new QGridLayout(this);

  for (i = 0; i < myJoystick->numAxes; i++) {
    int minValue = qmc2Config->value(QString(QMC2_FRONTEND_PREFIX + "Joystick/%1/Axis%2Minimum").arg(joyIndex).arg(i), 0).toInt();
    int maxValue = qmc2Config->value(QString(QMC2_FRONTEND_PREFIX + "Joystick/%1/Axis%2Maximum").arg(joyIndex).arg(i), 0).toInt();
    int dzValue = qmc2Config->value(QString(QMC2_FRONTEND_PREFIX + "Joystick/%1/Axis%2Deadzone").arg(joyIndex).arg(i), 0).toInt();
    myJoystick->deadzones[i] = dzValue;
    int sValue = qmc2Config->value(QString(QMC2_FRONTEND_PREFIX + "Joystick/%1/Axis%2Sensitivity").arg(joyIndex).arg(i), 0).toInt();
    myJoystick->sensitivities[i] = sValue;
    bool enabled = qmc2Config->value(QString(QMC2_FRONTEND_PREFIX + "Joystick/%1/Axis%2Enabled").arg(joyIndex).arg(i), TRUE).toBool();

    axesRanges[i] = new QProgressBar(this);
    axesRanges[i]->setFormat(tr("A%1: %v").arg(i));
    axesRanges[i]->setToolTip(tr("Current value of axis %1").arg(i));
    axesRanges[i]->setRange(minValue, maxValue);
    axesRanges[i]->setValue(myJoystick->getAxisValue(i));
    axesRanges[i]->setSizePolicy(QSizePolicy::Expanding, myJoystick->numAxes < maxRows ? QSizePolicy::Ignored : QSizePolicy::Minimum);
    axesRanges[i]->setEnabled(enabled);
    
    myLayout->addWidget(axesRanges[i], i, 0);
  }

  for (i = 0; i < myJoystick->numButtons; i++) {
    buttonLabels[i] = new QLabel(tr("B%1").arg(i), this);
    buttonLabels[i]->setToolTip(tr("Current state of button %1").arg(i));
    buttonLabels[i]->setAlignment(Qt::AlignCenter);
    buttonLabels[i]->setAutoFillBackground(TRUE);
    buttonLabels[i]->setFrameShape(QFrame::Box);
    buttonLabels[i]->setSizePolicy(QSizePolicy::Expanding, myJoystick->numButtons < maxRows ? QSizePolicy::Ignored : QSizePolicy::Minimum);

    myLayout->addWidget(buttonLabels[i], i, 1);
  }

  for (i = 0; i < myJoystick->numHats; i++) {
    hatValueLabels[i] = new QLabel(tr("H%1: 0").arg(i), this);
    hatValueLabels[i]->setToolTip(tr("Current value of hat %1").arg(i));
    hatValueLabels[i]->setAlignment(Qt::AlignCenter);
    hatValueLabels[i]->setAutoFillBackground(TRUE);
    hatValueLabels[i]->setFrameShape(QFrame::Box);
    hatValueLabels[i]->setSizePolicy(QSizePolicy::Expanding, myJoystick->numHats < maxRows ? QSizePolicy::Ignored : QSizePolicy::Minimum);

    myLayout->addWidget(hatValueLabels[i], i, 2);
  }

  for (i = 0; i < myJoystick->numTrackballs; i++) {
    trackballDeltaXLabels[i] = new QLabel(tr("T%1 DX: 0").arg(i), this);
    trackballDeltaXLabels[i]->setToolTip(tr("Current X-delta of trackball %1").arg(i));
    trackballDeltaXLabels[i]->setAlignment(Qt::AlignCenter);
    trackballDeltaXLabels[i]->setAutoFillBackground(TRUE);
    trackballDeltaXLabels[i]->setFrameShape(QFrame::Box);
    trackballDeltaXLabels[i]->setSizePolicy(QSizePolicy::Expanding, myJoystick->numTrackballs < maxRows ? QSizePolicy::Ignored : QSizePolicy::Minimum);

    myLayout->addWidget(trackballDeltaXLabels[i], i, 3);
  }

  for (i = 0; i < myJoystick->numTrackballs; i++) {
    trackballDeltaYLabels[i] = new QLabel(tr("T%1 DY: 0").arg(i), this);
    trackballDeltaYLabels[i]->setToolTip(tr("Current Y-delta of trackball %1").arg(i));
    trackballDeltaYLabels[i]->setAlignment(Qt::AlignCenter);
    trackballDeltaYLabels[i]->setAutoFillBackground(TRUE);
    trackballDeltaYLabels[i]->setFrameShape(QFrame::Box);
    trackballDeltaYLabels[i]->setSizePolicy(QSizePolicy::Expanding, myJoystick->numTrackballs < maxRows ? QSizePolicy::Ignored : QSizePolicy::Minimum);
    
    myLayout->addWidget(trackballDeltaYLabels[i], i, 4);
  }

  // add spacer
  myLayout->addItem(new QSpacerItem(10, 10, QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding), maxRows, 1);

  // connect joystick callbacks
  connect(myJoystick, SIGNAL(axisValueChanged(int, int)), this, SLOT(on_joystickAxisValueChanged(int, int)));
  connect(myJoystick, SIGNAL(buttonValueChanged(int, bool)), this, SLOT(on_joystickButtonValueChanged(int, bool)));
  connect(myJoystick, SIGNAL(hatValueChanged(int, int)), this, SLOT(on_joystickHatValueChanged(int, int)));
  connect(myJoystick, SIGNAL(trackballValueChanged(int, int, int)), this, SLOT(on_joystickTrackballValueChanged(int, int, int)));
}

JoystickTestWidget::~JoystickTestWidget()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: JoystickTestWidget::~JoystickTestWidget()");
#endif

  // ignore destruction when we are already cleaning up the application...
  if ( !qmc2Options->groupBoxCalibrationAndTest->layout() )
    return;

  QLayoutItem *childItem;
  while ((childItem = myLayout->takeAt(0)) != 0) {
    delete childItem->widget();
    delete childItem;
  }
}

void JoystickTestWidget::on_joystickAxisValueChanged(int axis, int value)
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, QString("DEBUG: JoystickTestWidget::on_joystickAxisValueChanged(int axis = %1, int value = %2)").arg(axis).arg(value));
#endif

  axesRanges[axis]->setValue(value);
}

void JoystickTestWidget::on_joystickButtonValueChanged(int button, bool value)
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, QString("DEBUG: JoystickTestWidget::on_joystickButtonValueChanged(int button = %1, bool value = %2)").arg(button).arg(value));
#endif

  QPalette greenPalette(QApplication::palette());
  greenPalette.setBrush(QPalette::Window, QColor(0, 255, 0));

  if ( value )
    buttonLabels[button]->setPalette(greenPalette);
  else
    buttonLabels[button]->setPalette(QApplication::palette());
}

void JoystickTestWidget::on_joystickHatValueChanged(int hat, int value)
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, QString("DEBUG: JoystickTestWidget::on_joystickHatValueChanged(int hat = %1, int value = %2)").arg(hat).arg(value));
#endif

  QPalette greenPalette(QApplication::palette());
  greenPalette.setBrush(QPalette::Window, QColor(0, 255, 0));

  if ( value != 0 )
    hatValueLabels[hat]->setPalette(greenPalette);
  else
    hatValueLabels[hat]->setPalette(QApplication::palette());

  hatValueLabels[hat]->setText(tr("H%1: %2").arg(hat).arg(value));
}

void JoystickTestWidget::on_joystickTrackballValueChanged(int trackball, int deltaX, int deltaY)
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, QString("DEBUG: JoystickTestWidget::on_joystickTrackballValueChanged(int trackball = %1, int deltaX = %2, int deltaY = %3)").arg(trackball).arg(deltaX).arg(deltaY));
#endif

  QPalette greenPalette(QApplication::palette());
  greenPalette.setBrush(QPalette::Window, QColor(0, 255, 0));

  if ( deltaX != 0 )
    trackballDeltaXLabels[trackball]->setPalette(greenPalette);
  else
    trackballDeltaXLabels[trackball]->setPalette(QApplication::palette());

  if ( deltaY != 0 )
    trackballDeltaYLabels[trackball]->setPalette(greenPalette);
  else
    trackballDeltaYLabels[trackball]->setPalette(QApplication::palette());

  trackballDeltaXLabels[trackball]->setText(tr("T%1 DX: %2").arg(trackball).arg(deltaX));
  trackballDeltaYLabels[trackball]->setText(tr("T%1 DY: %2").arg(trackball).arg(deltaY));
}

void JoystickTestWidget::cleanupPalette()
{
#ifdef QMC2_DEBUG
  qmc2MainWindow->log(QMC2_LOG_FRONTEND, "DEBUG: JoystickTestWidget::cleanupPalette()");
#endif

  int i;
  for (i = 0; i < buttonLabels.count(); i++)
    buttonLabels[i]->setPalette(QApplication::palette());
  for (i = 0; i < hatValueLabels.count(); i++)
    hatValueLabels[i]->setPalette(QApplication::palette());
  for (i = 0; i < trackballDeltaXLabels.count(); i++)
    trackballDeltaXLabels[i]->setPalette(QApplication::palette());
  for (i = 0; i < trackballDeltaYLabels.count(); i++)
    trackballDeltaYLabels[i]->setPalette(QApplication::palette());
}
#endif
