<commit_before>#include "mainwindow.h"
#include "helpwindow.h"
#include "utils.h"

#include "ui_mainwindow.h"

#ifdef Q_WS_WIN
    #include <windows.h>
#endif

#include <QCoreApplication>
#include <QCloseEvent>
#include <QDebug>
#include <QDesktopServices>
#include <QDesktopWidget>
#include <QDir>
#include <QHelpEngine>
#include <QLibraryInfo>
#include <QMessageBox>
#include <QProcess>
#include <QSettings>
#include <QTemporaryFile>
#include <QTranslator>
#include <QUrl>

#define OPENCOR_HOMEPAGE "http://opencor.sourceforge.net/"
#define OPENCOR_HELP_HOMEPAGE "qthelp://world.opencor/doc/userIndex.html"

#define SETTINGS_INSTITUTION "World"
#define SETTINGS_GENERAL_LOCALE "General_Locale"
#define SETTINGS_GENERAL_GEOMETRY "General_Geometry"
#define SETTINGS_GENERAL_STATE "General_State"
#define SETTINGS_HELPWINDOW_ZOOMLEVEL "HelpWindow_ZoomLevel"

#define ENGLISH_LOCALE "en"
#define FRENCH_LOCALE  "fr"

MainWindow::MainWindow(QWidget *pParent) :
    QMainWindow(pParent),
    mUi(new Ui::MainWindow),
    mLocale("")   // This will ensure that the locale is properly set the first
                  // time setLocale is called
{
    // Set up the UI

    mUi->setupUi(this);
    // Note: the application icon (which needs to be set in the case of Linux,
    //       unlike in the case of Windows and Mac OS X, since it's set through
    //       CMake in those cases (see CMakeLists.txt)) is set within the UI
    //       file. Otherwise, it's good to have it set for all three platforms,
    //       since it can then be used in, for example, the about box...

    // Set the name of the main window to that of the application

    setWindowTitle(qApp->applicationName());

    // Create a temporary directory where to put OpenCOR's resources

    QTemporaryFile tempDir;

    tempDir.open();    // Note: this is required to get a 'valid' temporary
    tempDir.close();   //       directory name...

    mTempDirName = tempDir.fileName().append("."+qApp->applicationName());

    QDir().mkdir(mTempDirName);

    // Extract the help files

    QString applicationBaseName(QFileInfo(qApp->applicationFilePath()).baseName());

    mQchFileName = mTempDirName+QDir::separator()+applicationBaseName+".qch";
    mQhcFileName = mTempDirName+QDir::separator()+applicationBaseName+".qhc";

    saveResourceAs(":qchFile", mQchFileName);
    saveResourceAs(":qhcFile", mQhcFileName);

    // Set up the help engine

    mHelpEngine = new QHelpEngine(mQhcFileName);

    mHelpEngine->setupData();

    // Create the help window

    mHelpWindow = new HelpWindow(mHelpEngine, QUrl(OPENCOR_HELP_HOMEPAGE));

    // Some connections

    connect(mUi->actionExit, SIGNAL(triggered(bool)),
            this, SLOT(close()));
    connect(mUi->actionResetAll, SIGNAL(triggered(bool)),
            this, SLOT(resetAll()));

    connect(mUi->actionHelpToolbar, SIGNAL(triggered(bool)),
            mUi->helpToolbar, SLOT(setVisible(bool)));
    connect(mUi->helpToolbar->toggleViewAction(), SIGNAL(toggled(bool)),
            mUi->actionHelpToolbar, SLOT(setChecked(bool)));

    connect(mUi->actionHelp, SIGNAL(triggered(bool)),
            mHelpWindow, SLOT(setVisible(bool)));
    connect(mHelpWindow, SIGNAL(visibilityChanged(bool)),
            mUi->actionHelp, SLOT(setChecked(bool)));

    // Default user settings (useful the very first time we start OpenCOR or
    // after a reset all)

    defaultSettings();

    // Retrieve our default settings

    loadSettings();

    // Update the GUI, which may have changed (e.g. hidden toolbar) as a result
    // of loading OpenCOR's settings

    updateGUI();

    // Bring ourselves to the foreground. Indeed, when restarting OpenCOR (as a
    // result of a reset all), OpenCOR will on Mac OS X be behind other
    // applications. This behaviour has, on occasions, also been observed on
    // Windows, so... rather than making the following code Mac OS X specific,
    // we may as well make it general, since it doesn't have any adverse effect
    // on Windows or Linux

    activateWindow();
    raise();   // Just to be on the safe side
}

MainWindow::~MainWindow()
{
    // Delete some internal objects

    delete mHelpEngine;
    delete mUi;

    // Delete the help files

    QFile(mQchFileName).remove();
    QFile(mQhcFileName).remove();

    // Delete the temporary directory

    QDir().rmdir(mTempDirName);
}

void MainWindow::closeEvent(QCloseEvent *pEvent)
{
    // Keep track of our default settings
    // Note: it must be done here, as opposed to the destructor, otherwise some
    //       settings (e.g. docked windows) won't be properly saved

    saveSettings();

    // Accept the event

    pEvent->accept();
}

void MainWindow::defaultSettings()
{
    // Default language to be used by OpenCOR

    setLocale(ENGLISH_LOCALE);

    // Default size and position of the main window

    double spaceRatio = 1.0/13.0;
    QRect desktopGeometry = qApp->desktop()->availableGeometry();
    int horizSpace = spaceRatio*desktopGeometry.width();
    int vertSpace  = spaceRatio*desktopGeometry.height();

    setGeometry(desktopGeometry.left()+horizSpace, desktopGeometry.top()+vertSpace, desktopGeometry.width()-2*horizSpace, desktopGeometry.height()-2*vertSpace);

    // Default visibility and location of the various toolbars

    addToolBar(Qt::TopToolBarArea, mUi->helpToolbar);

    mUi->helpToolbar->setVisible(true);

    // Default size and position of the help window

    mHelpWindow->setVisible(false);   // So we can set things up without having
                                      // the screen flashing

    addDockWidget(Qt::RightDockWidgetArea, mHelpWindow);

    mHelpWindow->defaultSettings();

    mHelpWindow->setVisible(true);
}

void MainWindow::loadSettings()
{
    QSettings settings(SETTINGS_INSTITUTION, qApp->applicationName());

    // Retrieve the language to be used by OpenCOR

    setLocale(settings.value(SETTINGS_GENERAL_LOCALE, ENGLISH_LOCALE).toString());

    // Retrieve the geometry of the main window

    restoreGeometry(settings.value(SETTINGS_GENERAL_GEOMETRY).toByteArray());

    // Retrieve the state of the main window

    restoreState(settings.value(SETTINGS_GENERAL_STATE).toByteArray());

    // Retrieve the zoom level for the help widget

    mHelpWindow->setZoomLevel(settings.value(SETTINGS_HELPWINDOW_ZOOMLEVEL, mHelpWindow->defaultZoomLevel()).toInt());
}

void MainWindow::saveSettings()
{
    QSettings settings(SETTINGS_INSTITUTION, qApp->applicationName());

    // Keep track of the language to be used by OpenCOR

    settings.setValue(SETTINGS_GENERAL_LOCALE, mLocale);

    // Keep track of the geometry of the main window

    settings.setValue(SETTINGS_GENERAL_GEOMETRY, saveGeometry());

    // Keep track of the state of the main window

    settings.setValue(SETTINGS_GENERAL_STATE, saveState());

    // Keep track of the text size multiplier for the help widget

    settings.setValue(SETTINGS_HELPWINDOW_ZOOMLEVEL, mHelpWindow->zoomLevel());
}

void MainWindow::setLocale(const QString& pLocale)
{
    if (pLocale != mLocale)
    {
        mLocale = pLocale;

        // Specify the language to be used by OpenCOR

        qApp->removeTranslator(&mQtTranslator);
        mQtTranslator.load("qt_"+mLocale, QLibraryInfo::location(QLibraryInfo::TranslationsPath));
        qApp->installTranslator(&mQtTranslator);

        qApp->removeTranslator(&mAppTranslator);
        mAppTranslator.load(":app_"+mLocale);
        qApp->installTranslator(&mAppTranslator);

        // Translate the whole GUI (including any 'child' window), should the
        // language have changed

        mUi->retranslateUi(this);

        mHelpWindow->retranslateUi();
    }

    // Update the checked menu item
    // Note: it has to be done every single time, since selecting a menu item
    //       will automatically toggle its checked status, so...

    mUi->actionEnglish->setChecked(mLocale == ENGLISH_LOCALE);
    mUi->actionFrench->setChecked(mLocale == FRENCH_LOCALE);
}

void MainWindow::updateGUI()
{
    // Update the checked status of the toolbars menu items

    mUi->actionHelpToolbar->setChecked(mUi->helpToolbar->isVisible());
}

void MainWindow::singleAppMsgRcvd(const QString&)
{
    // We have just received a message from another instance of OpenCOR, so
    // bring ourselves to the foreground
    // Note: one would normally use activateWindow(), but depending on the
    //       operating system it may or not bring OpenCOR to the foreground,
    //       so... instead we do what follows, depending on the operating
    //       system...

#ifdef Q_WS_WIN
    // Retrieve OpenCOR's window Id

    WId mwWinId = winId();

    // Restore OpenCOR, should it be minimized

    if (IsIconic(mwWinId))
        SendMessage(mwWinId, WM_SYSCOMMAND, SC_RESTORE, 0);

    // Bring OpenCOR to the foreground

    DWORD foregroundThreadPId = GetWindowThreadProcessId(GetForegroundWindow(), NULL);
    DWORD mwThreadPId         = GetWindowThreadProcessId(mwWinId, NULL);

    if (foregroundThreadPId != mwThreadPId)
    {
        // OpenCOR's thread process Id is not that of the foreground window, so
        // attach the foreground thread to OpenCOR's, set OpenCOR to the
        // foreground, and detach the foreground thread from OpenCOR's

        AttachThreadInput(foregroundThreadPId, mwThreadPId, true);

        SetForegroundWindow(mwWinId);

        AttachThreadInput(foregroundThreadPId, mwThreadPId, false);
    }
    else
        // OpenCOR's thread process Id is that of the foreground window, so
        // just set OpenCOR to the foreground

        SetForegroundWindow(mwWinId);

    // Note: under Windows, to use activateWindow() will only highlight the
    //       application in the taskbar, since under Windows no application
    //       should be allowed to bring itself to the foreground when another
    //       application is already in the foreground. Fair enough, but it
    //       happens that, here, the user wants OpenCOR to be brought to the
    //       foreground, hence the above code to get the effect we are after...
#else
    // Do what one should normally do

    activateWindow();
    raise();   // Just to be on the safe side
    // Note: raise() never seems to be required on Mac OS X, but to use
    //       activateWindow() under Linux may or not give the expected result,
    //       so...
#endif

    // Now, we must handle the arguments that were passed to OpenCOR

    // TODO: handle the arguments passed to the 'official' instance of OpenCOR
}

void MainWindow::on_actionEnglish_triggered()
{
    // Select English as the language used by OpenCOR

    setLocale(ENGLISH_LOCALE);
}

void MainWindow::on_actionFrench_triggered()
{
    // Select French as the language used by OpenCOR

    setLocale(FRENCH_LOCALE);
}

void MainWindow::on_actionHomePage_triggered()
{
    // Look up OpenCOR's home page

    QDesktopServices::openUrl(QUrl(OPENCOR_HOMEPAGE));
}

void MainWindow::on_actionAbout_triggered()
{
    QMessageBox::about(this, qApp->applicationName(),
                       QString("")+
                       ""+
                           "
"+qApp->applicationName()+" "+qApp->applicationVersion()+"
"+
                           "
"+getOsName()+"
"+
                       ""+
                       "
"+
                       ""+qApp->applicationName()+" "+tr("is a cross-platform CellML-based modelling environment which can be used to organise, edit, simulate and analyse CellML files."));
}

void MainWindow::resetAll()
{
    // Clear all the user settings and restart OpenCOR (indeed, a restart will
    // ensure that all the docked windows are, for instance, properly
    // reset with regards to their dimensions)

    QSettings(SETTINGS_INSTITUTION, qApp->applicationName()).clear();

    // Restart OpenCOR, but without providing any of the argument with which
    // OpenCOR was originally started, since we indeed want to reset everything

    QProcess::startDetached(qApp->applicationFilePath(), QStringList(), qApp->applicationDirPath());

    // Quit OpenCOR
    // Note: the closeEvent method won't get called and this is exactly what we
    //       want, since we don't want to save OpenCOR's settings

    qApp->quit();
}
<commit_msg>Minor reformatting.<commit_after>#include "mainwindow.h"
#include "helpwindow.h"
#include "utils.h"

#include "ui_mainwindow.h"

#ifdef Q_WS_WIN
    #include <windows.h>
#endif

#include <QCoreApplication>
#include <QCloseEvent>
#include <QDebug>
#include <QDesktopServices>
#include <QDesktopWidget>
#include <QDir>
#include <QHelpEngine>
#include <QLibraryInfo>
#include <QMessageBox>
#include <QProcess>
#include <QSettings>
#include <QTemporaryFile>
#include <QTranslator>
#include <QUrl>

#define OPENCOR_HOMEPAGE "http://opencor.sourceforge.net/"
#define OPENCOR_HELP_HOMEPAGE "qthelp://world.opencor/doc/userIndex.html"

#define SETTINGS_INSTITUTION "World"
#define SETTINGS_GENERAL_LOCALE "General_Locale"
#define SETTINGS_GENERAL_GEOMETRY "General_Geometry"
#define SETTINGS_GENERAL_STATE "General_State"
#define SETTINGS_HELPWINDOW_ZOOMLEVEL "HelpWindow_ZoomLevel"

#define ENGLISH_LOCALE "en"
#define FRENCH_LOCALE  "fr"

MainWindow::MainWindow(QWidget *pParent) :
    QMainWindow(pParent),
    mUi(new Ui::MainWindow),
    mLocale("")   // This will ensure that the locale is properly set the first
                  // time setLocale is called
{
    // Set up the UI

    mUi->setupUi(this);
    // Note: the application icon (which needs to be set in the case of Linux,
    //       unlike in the case of Windows and Mac OS X, since it's set through
    //       CMake in those cases (see CMakeLists.txt)) is set within the UI
    //       file. Otherwise, it's good to have it set for all three platforms,
    //       since it can then be used in, for example, the about box...

    // Set the name of the main window to that of the application

    setWindowTitle(qApp->applicationName());

    // Create a temporary directory where to put OpenCOR's resources

    QTemporaryFile tempDir;

    tempDir.open();    // Note: this is required to get a 'valid' temporary
    tempDir.close();   //       directory name...

    mTempDirName = tempDir.fileName().append("."+qApp->applicationName());

    QDir().mkdir(mTempDirName);

    // Extract the help files

    QString applicationBaseName(QFileInfo(qApp->applicationFilePath()).baseName());

    mQchFileName = mTempDirName+QDir::separator()+applicationBaseName+".qch";
    mQhcFileName = mTempDirName+QDir::separator()+applicationBaseName+".qhc";

    saveResourceAs(":qchFile", mQchFileName);
    saveResourceAs(":qhcFile", mQhcFileName);

    // Set up the help engine

    mHelpEngine = new QHelpEngine(mQhcFileName);

    mHelpEngine->setupData();

    // Create the help window

    mHelpWindow = new HelpWindow(mHelpEngine, QUrl(OPENCOR_HELP_HOMEPAGE));

    // Some connections

    connect(mUi->actionExit, SIGNAL(triggered(bool)),
            this, SLOT(close()));
    connect(mUi->actionResetAll, SIGNAL(triggered(bool)),
            this, SLOT(resetAll()));

    connect(mUi->actionHelpToolbar, SIGNAL(triggered(bool)),
            mUi->helpToolbar, SLOT(setVisible(bool)));
    connect(mUi->helpToolbar->toggleViewAction(), SIGNAL(toggled(bool)),
            mUi->actionHelpToolbar, SLOT(setChecked(bool)));

    connect(mUi->actionHelp, SIGNAL(triggered(bool)),
            mHelpWindow, SLOT(setVisible(bool)));
    connect(mHelpWindow, SIGNAL(visibilityChanged(bool)),
            mUi->actionHelp, SLOT(setChecked(bool)));

    // Default user settings (useful the very first time we start OpenCOR or
    // after a reset all)

    defaultSettings();

    // Retrieve our default settings

    loadSettings();

    // Update the GUI, which may have changed (e.g. hidden toolbar) as a result
    // of loading OpenCOR's settings

    updateGUI();

    // Bring ourselves to the foreground. Indeed, when restarting OpenCOR (as a
    // result of a reset all), OpenCOR will on Mac OS X be behind other
    // applications. This behaviour has, on occasions, also been observed on
    // Windows, so... rather than making the following code Mac OS X specific,
    // we may as well make it general, since it doesn't have any adverse effect
    // on Windows or Linux

    activateWindow();

    raise();   // Just to be on the safe side
}

MainWindow::~MainWindow()
{
    // Delete some internal objects

    delete mHelpEngine;
    delete mUi;

    // Delete the help files

    QFile(mQchFileName).remove();
    QFile(mQhcFileName).remove();

    // Delete the temporary directory

    QDir().rmdir(mTempDirName);
}

void MainWindow::closeEvent(QCloseEvent *pEvent)
{
    // Keep track of our default settings
    // Note: it must be done here, as opposed to the destructor, otherwise some
    //       settings (e.g. docked windows) won't be properly saved

    saveSettings();

    // Accept the event

    pEvent->accept();
}

void MainWindow::defaultSettings()
{
    // Default language to be used by OpenCOR

    setLocale(ENGLISH_LOCALE);

    // Default size and position of the main window

    double spaceRatio = 1.0/13.0;
    QRect desktopGeometry = qApp->desktop()->availableGeometry();
    int horizSpace = spaceRatio*desktopGeometry.width();
    int vertSpace  = spaceRatio*desktopGeometry.height();

    setGeometry(desktopGeometry.left()+horizSpace, desktopGeometry.top()+vertSpace, desktopGeometry.width()-2*horizSpace, desktopGeometry.height()-2*vertSpace);

    // Default visibility and location of the various toolbars

    addToolBar(Qt::TopToolBarArea, mUi->helpToolbar);

    mUi->helpToolbar->setVisible(true);

    // Default size and position of the help window

    mHelpWindow->setVisible(false);   // So we can set things up without having
                                      // the screen flashing

    addDockWidget(Qt::RightDockWidgetArea, mHelpWindow);

    mHelpWindow->defaultSettings();

    mHelpWindow->setVisible(true);
}

void MainWindow::loadSettings()
{
    QSettings settings(SETTINGS_INSTITUTION, qApp->applicationName());

    // Retrieve the language to be used by OpenCOR

    setLocale(settings.value(SETTINGS_GENERAL_LOCALE, ENGLISH_LOCALE).toString());

    // Retrieve the geometry of the main window

    restoreGeometry(settings.value(SETTINGS_GENERAL_GEOMETRY).toByteArray());

    // Retrieve the state of the main window

    restoreState(settings.value(SETTINGS_GENERAL_STATE).toByteArray());

    // Retrieve the zoom level for the help widget

    mHelpWindow->setZoomLevel(settings.value(SETTINGS_HELPWINDOW_ZOOMLEVEL, mHelpWindow->defaultZoomLevel()).toInt());
}

void MainWindow::saveSettings()
{
    QSettings settings(SETTINGS_INSTITUTION, qApp->applicationName());

    // Keep track of the language to be used by OpenCOR

    settings.setValue(SETTINGS_GENERAL_LOCALE, mLocale);

    // Keep track of the geometry of the main window

    settings.setValue(SETTINGS_GENERAL_GEOMETRY, saveGeometry());

    // Keep track of the state of the main window

    settings.setValue(SETTINGS_GENERAL_STATE, saveState());

    // Keep track of the text size multiplier for the help widget

    settings.setValue(SETTINGS_HELPWINDOW_ZOOMLEVEL, mHelpWindow->zoomLevel());
}

void MainWindow::setLocale(const QString& pLocale)
{
    if (pLocale != mLocale)
    {
        mLocale = pLocale;

        // Specify the language to be used by OpenCOR

        qApp->removeTranslator(&mQtTranslator);
        mQtTranslator.load("qt_"+mLocale, QLibraryInfo::location(QLibraryInfo::TranslationsPath));
        qApp->installTranslator(&mQtTranslator);

        qApp->removeTranslator(&mAppTranslator);
        mAppTranslator.load(":app_"+mLocale);
        qApp->installTranslator(&mAppTranslator);

        // Translate the whole GUI (including any 'child' window), should the
        // language have changed

        mUi->retranslateUi(this);

        mHelpWindow->retranslateUi();
    }

    // Update the checked menu item
    // Note: it has to be done every single time, since selecting a menu item
    //       will automatically toggle its checked status, so...

    mUi->actionEnglish->setChecked(mLocale == ENGLISH_LOCALE);
    mUi->actionFrench->setChecked(mLocale == FRENCH_LOCALE);
}

void MainWindow::updateGUI()
{
    // Update the checked status of the toolbars menu items

    mUi->actionHelpToolbar->setChecked(mUi->helpToolbar->isVisible());
}

void MainWindow::singleAppMsgRcvd(const QString&)
{
    // We have just received a message from another instance of OpenCOR, so
    // bring ourselves to the foreground
    // Note: one would normally use activateWindow(), but depending on the
    //       operating system it may or not bring OpenCOR to the foreground,
    //       so... instead we do what follows, depending on the operating
    //       system...

#ifdef Q_WS_WIN
    // Retrieve OpenCOR's window Id

    WId mwWinId = winId();

    // Restore OpenCOR, should it be minimized

    if (IsIconic(mwWinId))
        SendMessage(mwWinId, WM_SYSCOMMAND, SC_RESTORE, 0);

    // Bring OpenCOR to the foreground

    DWORD foregroundThreadPId = GetWindowThreadProcessId(GetForegroundWindow(), NULL);
    DWORD mwThreadPId         = GetWindowThreadProcessId(mwWinId, NULL);

    if (foregroundThreadPId != mwThreadPId)
    {
        // OpenCOR's thread process Id is not that of the foreground window, so
        // attach the foreground thread to OpenCOR's, set OpenCOR to the
        // foreground, and detach the foreground thread from OpenCOR's

        AttachThreadInput(foregroundThreadPId, mwThreadPId, true);

        SetForegroundWindow(mwWinId);

        AttachThreadInput(foregroundThreadPId, mwThreadPId, false);
    }
    else
        // OpenCOR's thread process Id is that of the foreground window, so
        // just set OpenCOR to the foreground

        SetForegroundWindow(mwWinId);

    // Note: under Windows, to use activateWindow() will only highlight the
    //       application in the taskbar, since under Windows no application
    //       should be allowed to bring itself to the foreground when another
    //       application is already in the foreground. Fair enough, but it
    //       happens that, here, the user wants OpenCOR to be brought to the
    //       foreground, hence the above code to get the effect we are after...
#else
    // Do what one should normally do

    activateWindow();

    raise();   // Just to be on the safe side
    // Note: raise() never seems to be required on Mac OS X, but to use
    //       activateWindow() under Linux may or not give the expected result,
    //       so...
#endif

    // Now, we must handle the arguments that were passed to OpenCOR

    // TODO: handle the arguments passed to the 'official' instance of OpenCOR
}

void MainWindow::on_actionEnglish_triggered()
{
    // Select English as the language used by OpenCOR

    setLocale(ENGLISH_LOCALE);
}

void MainWindow::on_actionFrench_triggered()
{
    // Select French as the language used by OpenCOR

    setLocale(FRENCH_LOCALE);
}

void MainWindow::on_actionHomePage_triggered()
{
    // Look up OpenCOR's home page

    QDesktopServices::openUrl(QUrl(OPENCOR_HOMEPAGE));
}

void MainWindow::on_actionAbout_triggered()
{
    QMessageBox::about(this, qApp->applicationName(),
                       QString("")+
                       ""+
                           "
"+qApp->applicationName()+" "+qApp->applicationVersion()+"
"+
                           "
"+getOsName()+"
"+
                       ""+
                       "
"+
                       ""+qApp->applicationName()+" "+tr("is a cross-platform CellML-based modelling environment which can be used to organise, edit, simulate and analyse CellML files."));
}

void MainWindow::resetAll()
{
    // Clear all the user settings and restart OpenCOR (indeed, a restart will
    // ensure that all the docked windows are, for instance, properly
    // reset with regards to their dimensions)

    QSettings(SETTINGS_INSTITUTION, qApp->applicationName()).clear();

    // Restart OpenCOR, but without providing any of the argument with which
    // OpenCOR was originally started, since we indeed want to reset everything

    QProcess::startDetached(qApp->applicationFilePath(), QStringList(), qApp->applicationDirPath());

    // Quit OpenCOR
    // Note: the closeEvent method won't get called and this is exactly what we
    //       want, since we don't want to save OpenCOR's settings

    qApp->quit();
}
<|endoftext|>


<commit_before>#include "./volume_reader.h"
#include <string>
#include <itkImageFileReader.h>
#include <itkImageRegionIterator.h>
#include <itkMinimumMaximumImageCalculator.h>
#include "./utils/path_helper.h"

typedef itk::ImageFileReader<ImageType> VolumeReaderType;
typedef itk::MinimumMaximumImageCalculator<ImageType> MinMaxCalculator;

VolumeReader::VolumeReader(std::string filename)
{
  VolumeReaderType::Pointer reader = VolumeReaderType::New();
  reader->SetFileName(absolutePathOfProjectRelativePath(filename).c_str());

  reader->Update();
  image = reader->GetOutput();

  itk::ImageRegionIterator<ImageType> imageIterator(
      image, image->GetRequestedRegion());
  MinMaxCalculator::Pointer calculator = MinMaxCalculator::New();

  calculator->SetImage(image);
  calculator->Compute();

  max = calculator->GetMaximum();
  min = calculator->GetMinimum();

  // normalizeToCT(imageIterator);
  normalizeTo01(imageIterator);
}

VolumeReader::~VolumeReader()
{
}

float *VolumeReader::getDataPointer()
{
  return image->GetBufferPointer();
}

Eigen::Matrix4f VolumeReader::getTransformationMatrix()
{
  itk::Point<float, 3> originItk = image->GetOrigin();
  Eigen::Vector3f origin(originItk[0], originItk[1], originItk[2]);

  ImageType::DirectionType directionItk = image->GetDirection();

  Eigen::Matrix3f rotation;
  for (int rowIndex = 0; rowIndex < 3; ++rowIndex)
    for (int columnIndex = 0; columnIndex < 3; ++columnIndex)
      rotation(rowIndex, columnIndex) = directionItk(rowIndex, columnIndex);

  Eigen::Matrix4f transformation = Eigen::Matrix4f::Identity();
  transformation.block<3, 3>(0, 0) = rotation;
  transformation.col(3).head<3>() = origin;

  return transformation;
}

Eigen::Vector3i VolumeReader::getSize()
{
  ImageType::RegionType region = image->GetLargestPossibleRegion();
  ImageType::SizeType size = region.GetSize();

  return Eigen::Vector3i(size[0], size[1], size[2]);
}

bool VolumeReader::isCT()
{
  auto size = getSize();
  return size.x() == 512 && size.y() == 512;
}

void
VolumeReader::normalizeToCT(itk::ImageRegionIterator<ImageType> imageIterator)
{
  const float maxAllowedValue = 3071;
  const float minAllowedValue = -1024;

  for (imageIterator.GoToBegin(); !imageIterator.IsAtEnd(); ++imageIterator)
  {
    float value = (imageIterator.Get() > maxAllowedValue) ? maxAllowedValue
                                                          : imageIterator.Get();
    value = (value < minAllowedValue) ? minAllowedValue : value;

    auto normalizedValue =
        (value - minAllowedValue) / (maxAllowedValue - minAllowedValue);
    imageIterator.Set(normalizedValue);
  }

  if (min < minAllowedValue)
  {
    std::cout << "VolumeReader adjusting min value!" << std::endl;
    min = minAllowedValue;
  }

  if (max > maxAllowedValue)
  {
    std::cout << "VolumeReader adjusting max value!" << std::endl;
    max = maxAllowedValue;
  }
}

void
VolumeReader::normalizeTo01(itk::ImageRegionIterator<ImageType> imageIterator)
{
  for (imageIterator.GoToBegin(); !imageIterator.IsAtEnd(); ++imageIterator)
  {
    auto normalizedValue = (imageIterator.Get() - min) / (max - min);
    imageIterator.Set(normalizedValue);
  }
}

<commit_msg>Change normalization method according to modality.<commit_after>#include "./volume_reader.h"
#include <string>
#include <itkImageFileReader.h>
#include <itkImageRegionIterator.h>
#include <itkMinimumMaximumImageCalculator.h>
#include "./utils/path_helper.h"

typedef itk::ImageFileReader<ImageType> VolumeReaderType;
typedef itk::MinimumMaximumImageCalculator<ImageType> MinMaxCalculator;

VolumeReader::VolumeReader(std::string filename)
{
  VolumeReaderType::Pointer reader = VolumeReaderType::New();
  reader->SetFileName(absolutePathOfProjectRelativePath(filename).c_str());

  reader->Update();
  image = reader->GetOutput();

  itk::ImageRegionIterator<ImageType> imageIterator(
      image, image->GetRequestedRegion());
  MinMaxCalculator::Pointer calculator = MinMaxCalculator::New();

  calculator->SetImage(image);
  calculator->Compute();

  max = calculator->GetMaximum();
  min = calculator->GetMinimum();

  if (isCT())
    normalizeToCT(imageIterator);
  else
    normalizeTo01(imageIterator);
}

VolumeReader::~VolumeReader()
{
}

float *VolumeReader::getDataPointer()
{
  return image->GetBufferPointer();
}

Eigen::Matrix4f VolumeReader::getTransformationMatrix()
{
  itk::Point<float, 3> originItk = image->GetOrigin();
  Eigen::Vector3f origin(originItk[0], originItk[1], originItk[2]);

  ImageType::DirectionType directionItk = image->GetDirection();

  Eigen::Matrix3f rotation;
  for (int rowIndex = 0; rowIndex < 3; ++rowIndex)
    for (int columnIndex = 0; columnIndex < 3; ++columnIndex)
      rotation(rowIndex, columnIndex) = directionItk(rowIndex, columnIndex);

  Eigen::Matrix4f transformation = Eigen::Matrix4f::Identity();
  transformation.block<3, 3>(0, 0) = rotation;
  transformation.col(3).head<3>() = origin;

  return transformation;
}

Eigen::Vector3i VolumeReader::getSize()
{
  ImageType::RegionType region = image->GetLargestPossibleRegion();
  ImageType::SizeType size = region.GetSize();

  return Eigen::Vector3i(size[0], size[1], size[2]);
}

bool VolumeReader::isCT()
{
  auto size = getSize();
  return size.x() == 512 && size.y() == 512;
}

void
VolumeReader::normalizeToCT(itk::ImageRegionIterator<ImageType> imageIterator)
{
  const float maxAllowedValue = 3071;
  const float minAllowedValue = -1024;

  for (imageIterator.GoToBegin(); !imageIterator.IsAtEnd(); ++imageIterator)
  {
    float value = (imageIterator.Get() > maxAllowedValue) ? maxAllowedValue
                                                          : imageIterator.Get();
    value = (value < minAllowedValue) ? minAllowedValue : value;

    auto normalizedValue =
        (value - minAllowedValue) / (maxAllowedValue - minAllowedValue);
    imageIterator.Set(normalizedValue);
  }

  if (min < minAllowedValue)
  {
    std::cout << "VolumeReader adjusting min value!" << std::endl;
    min = minAllowedValue;
  }

  if (max > maxAllowedValue)
  {
    std::cout << "VolumeReader adjusting max value!" << std::endl;
    max = maxAllowedValue;
  }
}

void
VolumeReader::normalizeTo01(itk::ImageRegionIterator<ImageType> imageIterator)
{
  for (imageIterator.GoToBegin(); !imageIterator.IsAtEnd(); ++imageIterator)
  {
    auto normalizedValue = (imageIterator.Get() - min) / (max - min);
    imageIterator.Set(normalizedValue);
  }
}

<|endoftext|>


<commit_before>#include "saiga/window/window.h"
#include "saiga/rendering/deferred_renderer.h"
#include "saiga/opengl/shader/shaderLoader.h"
#include "saiga/opengl/texture/textureLoader.h"

#include "saiga/rendering/deferred_renderer.h"
#include "saiga/rendering/renderer.h"

#include "saiga/util/error.h"
#include "saiga/framework.h"
#include <cstring>
#include <vector>
#include <ctime>
#include <thread>

using std::cout;
using std::endl;

void WindowParameters::setMode(bool fullscreen, bool borderLess)
{
    if(fullscreen){
        mode = (borderLess) ? Mode::borderLessFullscreen : Mode::fullscreen;
    }else{
        mode = (borderLess) ? Mode::borderLessWindowed : Mode::windowed;
    }
}

OpenGLWindow::OpenGLWindow(WindowParameters _windowParameters)
    :windowParameters(_windowParameters),
      updateTimer(0.97f),interpolationTimer(0.97f),renderCPUTimer(0.97f),swapBuffersTimer(0.97f),fpsTimer(50),upsTimer(50){

}

OpenGLWindow::~OpenGLWindow(){
    delete renderer;
}

void OpenGLWindow::close(){
    cout<<"Window: close"<<endl;
    running = false;
}

bool OpenGLWindow::init(const RenderingParameters& params){
    initSaiga();

    //init window and opengl context
    if(!initWindow()){
        std::cerr<<"Failed to initialize Window!"<<std::endl;
        return false;
    }

    //inits opengl (loads functions)
    initOpenGL();
    assert_no_glerror();

    if(!initInput()){
        std::cerr<<"Failed to initialize Input!"<<std::endl;
        return false;
    }

    //this somehow doesn't work in 32 bit windows

    //in older glew versions the last parameter of the function is void* instead of const void*
#if defined(GLEW_VERSION_4_5) || defined(USE_GLBINDING)
   // glDebugMessageCallback(Error::DebugLogConst,NULL);
#else
    glDebugMessageCallback(Error::DebugLog,NULL);
#endif

    cout<<">> Window inputs initialized!"<<endl;
    assert_no_glerror();

    initDeferredRendering(params);
    assert_no_glerror();
    return true;
}

void OpenGLWindow::initDeferredRendering(const RenderingParameters &params)
{

    renderer = new Deferred_Renderer(getWidth(),getHeight(),params);

    PostProcessingShader* pps = ShaderLoader::instance()->load<PostProcessingShader>("post_processing/post_processing.glsl"); //this shader does nothing
    std::vector<PostProcessingShader*> defaultEffects;
    defaultEffects.push_back(pps);

    renderer->postProcessor.setPostProcessingEffects(defaultEffects);

    renderer->lighting.setRenderDebug( false);

    renderer->currentCamera = &this->currentCamera;

}

void OpenGLWindow::resize(int width, int height)
{
    this->windowParameters.width = width;
    this->windowParameters.height = height;
    renderer->resize(width,height);
}

void OpenGLWindow::readToImage(Image& out){
    int w = renderer->windowWidth;
    int h = renderer->windowHeight;

    out.width = w;
    out.height = h;
    out.Format() = ImageFormat(3,8,ImageElementFormat::UnsignedNormalized);
    out.create();

    //read data from default framebuffer and restore currently bound fb.
    GLint fb;
    glGetIntegerv(GL_FRAMEBUFFER_BINDING,&fb);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glReadPixels(0,0,w,h,GL_RGB,GL_UNSIGNED_BYTE,out.getRawData());
    glBindFramebuffer(GL_FRAMEBUFFER, fb);
}

void OpenGLWindow::screenshot(const std::string &file)
{
//    cout<<"Window::screenshot "<<file<<endl;

    Image img;
    readToImage(img);

    TextureLoader::instance()->saveImage(file,img);
}

void OpenGLWindow::screenshotRender(const std::string &file)
{
//    cout<<"Window::screenshotRender "<<file<<endl;
    int w = renderer->width;
    int h = renderer->height;

    Image img;
    img.width = w;
    img.height = h;
    img.Format() = ImageFormat(3,8,ImageElementFormat::UnsignedNormalized);
    img.create();

    auto tex = getRenderer()->postProcessor.getCurrentTexture();
    tex->bind();
    glGetTexImage(tex->getTarget(),0,GL_RGB,GL_UNSIGNED_BYTE,img.getRawData());
    tex->unbind();

    TextureLoader::instance()->saveImage(file,img);
}

std::string OpenGLWindow::getTimeString()
{
    time_t t = time(0);   // get time now
    struct tm * now = localtime( & t );

    std::string str;
    str =     std::to_string(now->tm_year + 1900) + '-'
            + std::to_string(now->tm_mon + 1) + '-'
            + std::to_string(now->tm_mday) + '_'
            + std::to_string(now->tm_hour) + '-'
            + std::to_string(now->tm_min) + '-'
            + std::to_string(now->tm_sec);

    ;

    return str;
}

void OpenGLWindow::setProgram(Program *program)
{
    renderer->renderer = program;
}

Ray OpenGLWindow::createPixelRay(const vec2 &pixel) const
{
    vec4 p = vec4(2*pixel.x/getWidth()-1.f,1.f-(2*pixel.y/getHeight()),0,1.f);
    p = glm::inverse(OpenGLWindow::currentCamera->proj)*p;
    p /= p.w;

    mat4 inverseView = glm::inverse(OpenGLWindow::currentCamera->view);
    vec3 ray_world =vec3(inverseView*p);
    vec3 origin = vec3(inverseView[3]);
    return Ray(glm::normalize(ray_world-origin),origin);
}

Ray OpenGLWindow::createPixelRay(const vec2 &pixel, const vec2& resolution, const mat4& inverseProj) const
{
    vec4 p = vec4(2*pixel.x/resolution.x-1.f,1.f-(2*pixel.y/resolution.y),0,1.f);
    p = inverseProj*p;
    p /= p.w;

    mat4 inverseView = glm::inverse(OpenGLWindow::currentCamera->view);
    vec3 ray_world =vec3(inverseView*p);
    vec3 origin = vec3(inverseView[3]);
    return Ray(glm::normalize(ray_world-origin),origin);
}

vec3 OpenGLWindow::screenToWorld(const vec2 &pixel) const
{
    vec4 p = vec4(2*pixel.x/getWidth()-1.f,1.f-(2*pixel.y/getHeight()),0,1.f);
    p = glm::inverse(OpenGLWindow::currentCamera->proj)*p;
    p /= p.w;

    mat4 inverseView = glm::inverse(OpenGLWindow::currentCamera->view);
    vec3 ray_world =vec3(inverseView*p);
    return ray_world;
}

vec3 OpenGLWindow::screenToWorld(const vec2 &pixel, const vec2& resolution, const mat4& inverseProj) const
{
    vec4 p = vec4(2*pixel.x/resolution.x-1.f,1.f-(2*pixel.y/resolution.y),0,1.f);
    p = inverseProj*p;
    p /= p.w;

    mat4 inverseView = glm::inverse(OpenGLWindow::currentCamera->view);
    vec3 ray_world =vec3(inverseView*p);
    return ray_world;
}

vec2 OpenGLWindow::projectToScreen(const vec3 &pos) const
{
    vec4 r = OpenGLWindow::currentCamera->proj * OpenGLWindow::currentCamera->view * vec4(pos,1);
    r /= r.w;

    vec2 pixel;
    pixel.x = (r.x +1.f)*getWidth() *0.5f;
    pixel.y = -(r.y - 1.f) * getHeight() * 0.5f;

    return pixel;
}

void OpenGLWindow::update(float dt)
{
    updateTimer.start();
    endParallelUpdate();
    renderer->renderer->update(dt);
    startParallelUpdate(dt);
    updateTimer.stop();

    numUpdates++;

    upsTimer.stop();
    upsTimer.start();
}

void OpenGLWindow::startParallelUpdate(float dt)
{

    if(parallelUpdate){
        semStartUpdate.notify();
    }else{
        parallelUpdateCaller(dt);
    }
}

void OpenGLWindow::endParallelUpdate()
{
    if(parallelUpdate)
        semFinishUpdate.wait();
}

void OpenGLWindow::parallelUpdateThread(float dt)
{
    semFinishUpdate.notify();
    semStartUpdate.wait();
    while(running){
            parallelUpdateCaller(dt);
            semFinishUpdate.notify();
            semStartUpdate.wait();
    }
}

void OpenGLWindow::parallelUpdateCaller(float dt)
{
    renderer->renderer->parallelUpdate(dt);
}

void OpenGLWindow::render(float dt, float interpolation)
{
    interpolationTimer.start();
    renderer->renderer->interpolate(dt,interpolation);
    interpolationTimer.stop();

    renderCPUTimer.start();
    renderer->render_intern();
    renderCPUTimer.stop();

    numFrames++;

    swapBuffersTimer.start();
    swapBuffers();
    swapBuffersTimer.stop();

    fpsTimer.stop();
    fpsTimer.start();
}

void OpenGLWindow::sleep(tick_t ticks)
{
    if(ticks > tick_t(0)){
        std::this_thread::sleep_for(ticks);
    }
}

void OpenGLWindow::startMainLoop(int updatesPerSecond, int framesPerSecond, float mainLoopInfoTime, int maxFrameSkip, bool _parallelUpdate, bool catchUp)
{
    parallelUpdate = _parallelUpdate;

    cout << "> Starting the main loop..." << endl;
    cout << "> updatesPerSecond=" << updatesPerSecond << " framesPerSecond=" << framesPerSecond << " maxFrameSkip=" << maxFrameSkip << endl;

    if(updatesPerSecond <= 0)
        updatesPerSecond = gameTime.base.count();
    if(framesPerSecond <= 0)
        framesPerSecond = gameTime.base.count();

    float updateDT = 1.0f / updatesPerSecond;
    //    float framesDT = 1.0f / framesPerSecond;

    tick_t ticksPerUpdate = gameTime.base / updatesPerSecond;
    tick_t ticksPerFrame = gameTime.base / framesPerSecond;

    tick_t ticksPerInfo = std::chrono::duration_cast<tick_t>(gameTime.base * mainLoopInfoTime);

    tick_t ticksPerScreenshot = std::chrono::duration_cast<tick_t>(gameTime.base * 5.0f);

    if(windowParameters.debugScreenshotTime < 0)
        ticksPerScreenshot = std::chrono::duration_cast<tick_t>(std::chrono::hours(100000));

    gameTime.init(ticksPerUpdate,ticksPerFrame);

    tick_t nextInfoTick = gameTime.getTime();
    tick_t nextScreenshotTick = gameTime.getTime() + ticksPerScreenshot;

    if(!catchUp){
        gameTime.maxGameLoopDelay = std::chrono::duration_cast<tick_t>(std::chrono::milliseconds(1000));
    }

    if(parallelUpdate){
        updateThread = std::thread(&OpenGLWindow::parallelUpdateThread,this,updateDT);
    }

    while(true){
        checkEvents();

        if(shouldClose()){
            break;
        }

        //With this loop we are able to skip frames if the system can't keep up.
        for(int i = 0; i <= maxFrameSkip && gameTime.shouldUpdate(); ++i){
            update(updateDT);
        }

        if(gameTime.shouldRender()){
            render(updateDT,gameTime.interpolation);
        }

        if(gameTime.getTime() > nextInfoTick){
            auto gt = std::chrono::duration_cast<std::chrono::seconds>(gameTime.getTime());
            cout << "> Time: " << gt.count() << "s  Total number of updates/frames: " << numUpdates << "/" << numFrames << "  UPS/FPS: " << (1000.0f/upsTimer.getTimeMS()) << "/" << (1000.0f/fpsTimer.getTimeMS()) << endl;
            nextInfoTick += ticksPerInfo;
        }

        if(gameTime.getTime() > nextScreenshotTick){
            string file = windowParameters.debugScreenshotPath+getTimeString()+".png";
            this->screenshot(file);
            nextScreenshotTick += ticksPerScreenshot;
        }

        //sleep until the next interesting event
        sleep(gameTime.getSleepTime());
        assert_no_glerror_end_frame();
    }
    running = false;

    if(parallelUpdate){
        //cleanup the update thread
        cout << "Finished main loop. Exiting update thread." << endl;
        endParallelUpdate();
        semStartUpdate.notify();
        updateThread.join();
    }

    auto gt = std::chrono::duration_cast<std::chrono::seconds>(gameTime.getTime());
    cout << "> Main loop finished in " << gt.count() << "s  Total number of updates/frames: " << numUpdates << "/" << numFrames  << endl;
}
<commit_msg>gl debug log<commit_after>#include "saiga/window/window.h"
#include "saiga/rendering/deferred_renderer.h"
#include "saiga/opengl/shader/shaderLoader.h"
#include "saiga/opengl/texture/textureLoader.h"

#include "saiga/rendering/deferred_renderer.h"
#include "saiga/rendering/renderer.h"

#include "saiga/util/error.h"
#include "saiga/framework.h"
#include <cstring>
#include <vector>
#include <ctime>
#include <thread>

using std::cout;
using std::endl;

void WindowParameters::setMode(bool fullscreen, bool borderLess)
{
    if(fullscreen){
        mode = (borderLess) ? Mode::borderLessFullscreen : Mode::fullscreen;
    }else{
        mode = (borderLess) ? Mode::borderLessWindowed : Mode::windowed;
    }
}

OpenGLWindow::OpenGLWindow(WindowParameters _windowParameters)
    :windowParameters(_windowParameters),
      updateTimer(0.97f),interpolationTimer(0.97f),renderCPUTimer(0.97f),swapBuffersTimer(0.97f),fpsTimer(50),upsTimer(50){

}

OpenGLWindow::~OpenGLWindow(){
    delete renderer;
}

void OpenGLWindow::close(){
    cout<<"Window: close"<<endl;
    running = false;
}

bool OpenGLWindow::init(const RenderingParameters& params){
    initSaiga();

    //init window and opengl context
    if(!initWindow()){
        std::cerr<<"Failed to initialize Window!"<<std::endl;
        return false;
    }

    //inits opengl (loads functions)
    initOpenGL();
    assert_no_glerror();

    if(!initInput()){
        std::cerr<<"Failed to initialize Input!"<<std::endl;
        return false;
    }

    //this somehow doesn't work in 32 bit windows

    //in older glew versions the last parameter of the function is void* instead of const void*
#if defined(GLEW_VERSION_4_5) || defined(USE_GLBINDING)

	//this somehow doesn't work on windows 32 bit
#if !defined _WIN32 || defined _WIN64
   glDebugMessageCallback(Error::DebugLogConst,NULL);
#endif

#else
    glDebugMessageCallback(Error::DebugLog,NULL);
#endif

    cout<<">> Window inputs initialized!"<<endl;
    assert_no_glerror();

    initDeferredRendering(params);
    assert_no_glerror();
    return true;
}

void OpenGLWindow::initDeferredRendering(const RenderingParameters &params)
{

    renderer = new Deferred_Renderer(getWidth(),getHeight(),params);

    PostProcessingShader* pps = ShaderLoader::instance()->load<PostProcessingShader>("post_processing/post_processing.glsl"); //this shader does nothing
    std::vector<PostProcessingShader*> defaultEffects;
    defaultEffects.push_back(pps);

    renderer->postProcessor.setPostProcessingEffects(defaultEffects);

    renderer->lighting.setRenderDebug( false);

    renderer->currentCamera = &this->currentCamera;

}

void OpenGLWindow::resize(int width, int height)
{
    this->windowParameters.width = width;
    this->windowParameters.height = height;
    renderer->resize(width,height);
}

void OpenGLWindow::readToImage(Image& out){
    int w = renderer->windowWidth;
    int h = renderer->windowHeight;

    out.width = w;
    out.height = h;
    out.Format() = ImageFormat(3,8,ImageElementFormat::UnsignedNormalized);
    out.create();

    //read data from default framebuffer and restore currently bound fb.
    GLint fb;
    glGetIntegerv(GL_FRAMEBUFFER_BINDING,&fb);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glReadPixels(0,0,w,h,GL_RGB,GL_UNSIGNED_BYTE,out.getRawData());
    glBindFramebuffer(GL_FRAMEBUFFER, fb);
}

void OpenGLWindow::screenshot(const std::string &file)
{
//    cout<<"Window::screenshot "<<file<<endl;

    Image img;
    readToImage(img);

    TextureLoader::instance()->saveImage(file,img);
}

void OpenGLWindow::screenshotRender(const std::string &file)
{
//    cout<<"Window::screenshotRender "<<file<<endl;
    int w = renderer->width;
    int h = renderer->height;

    Image img;
    img.width = w;
    img.height = h;
    img.Format() = ImageFormat(3,8,ImageElementFormat::UnsignedNormalized);
    img.create();

    auto tex = getRenderer()->postProcessor.getCurrentTexture();
    tex->bind();
    glGetTexImage(tex->getTarget(),0,GL_RGB,GL_UNSIGNED_BYTE,img.getRawData());
    tex->unbind();

    TextureLoader::instance()->saveImage(file,img);
}

std::string OpenGLWindow::getTimeString()
{
    time_t t = time(0);   // get time now
    struct tm * now = localtime( & t );

    std::string str;
    str =     std::to_string(now->tm_year + 1900) + '-'
            + std::to_string(now->tm_mon + 1) + '-'
            + std::to_string(now->tm_mday) + '_'
            + std::to_string(now->tm_hour) + '-'
            + std::to_string(now->tm_min) + '-'
            + std::to_string(now->tm_sec);

    ;

    return str;
}

void OpenGLWindow::setProgram(Program *program)
{
    renderer->renderer = program;
}

Ray OpenGLWindow::createPixelRay(const vec2 &pixel) const
{
    vec4 p = vec4(2*pixel.x/getWidth()-1.f,1.f-(2*pixel.y/getHeight()),0,1.f);
    p = glm::inverse(OpenGLWindow::currentCamera->proj)*p;
    p /= p.w;

    mat4 inverseView = glm::inverse(OpenGLWindow::currentCamera->view);
    vec3 ray_world =vec3(inverseView*p);
    vec3 origin = vec3(inverseView[3]);
    return Ray(glm::normalize(ray_world-origin),origin);
}

Ray OpenGLWindow::createPixelRay(const vec2 &pixel, const vec2& resolution, const mat4& inverseProj) const
{
    vec4 p = vec4(2*pixel.x/resolution.x-1.f,1.f-(2*pixel.y/resolution.y),0,1.f);
    p = inverseProj*p;
    p /= p.w;

    mat4 inverseView = glm::inverse(OpenGLWindow::currentCamera->view);
    vec3 ray_world =vec3(inverseView*p);
    vec3 origin = vec3(inverseView[3]);
    return Ray(glm::normalize(ray_world-origin),origin);
}

vec3 OpenGLWindow::screenToWorld(const vec2 &pixel) const
{
    vec4 p = vec4(2*pixel.x/getWidth()-1.f,1.f-(2*pixel.y/getHeight()),0,1.f);
    p = glm::inverse(OpenGLWindow::currentCamera->proj)*p;
    p /= p.w;

    mat4 inverseView = glm::inverse(OpenGLWindow::currentCamera->view);
    vec3 ray_world =vec3(inverseView*p);
    return ray_world;
}

vec3 OpenGLWindow::screenToWorld(const vec2 &pixel, const vec2& resolution, const mat4& inverseProj) const
{
    vec4 p = vec4(2*pixel.x/resolution.x-1.f,1.f-(2*pixel.y/resolution.y),0,1.f);
    p = inverseProj*p;
    p /= p.w;

    mat4 inverseView = glm::inverse(OpenGLWindow::currentCamera->view);
    vec3 ray_world =vec3(inverseView*p);
    return ray_world;
}

vec2 OpenGLWindow::projectToScreen(const vec3 &pos) const
{
    vec4 r = OpenGLWindow::currentCamera->proj * OpenGLWindow::currentCamera->view * vec4(pos,1);
    r /= r.w;

    vec2 pixel;
    pixel.x = (r.x +1.f)*getWidth() *0.5f;
    pixel.y = -(r.y - 1.f) * getHeight() * 0.5f;

    return pixel;
}

void OpenGLWindow::update(float dt)
{
    updateTimer.start();
    endParallelUpdate();
    renderer->renderer->update(dt);
    startParallelUpdate(dt);
    updateTimer.stop();

    numUpdates++;

    upsTimer.stop();
    upsTimer.start();
}

void OpenGLWindow::startParallelUpdate(float dt)
{

    if(parallelUpdate){
        semStartUpdate.notify();
    }else{
        parallelUpdateCaller(dt);
    }
}

void OpenGLWindow::endParallelUpdate()
{
    if(parallelUpdate)
        semFinishUpdate.wait();
}

void OpenGLWindow::parallelUpdateThread(float dt)
{
    semFinishUpdate.notify();
    semStartUpdate.wait();
    while(running){
            parallelUpdateCaller(dt);
            semFinishUpdate.notify();
            semStartUpdate.wait();
    }
}

void OpenGLWindow::parallelUpdateCaller(float dt)
{
    renderer->renderer->parallelUpdate(dt);
}

void OpenGLWindow::render(float dt, float interpolation)
{
    interpolationTimer.start();
    renderer->renderer->interpolate(dt,interpolation);
    interpolationTimer.stop();

    renderCPUTimer.start();
    renderer->render_intern();
    renderCPUTimer.stop();

    numFrames++;

    swapBuffersTimer.start();
    swapBuffers();
    swapBuffersTimer.stop();

    fpsTimer.stop();
    fpsTimer.start();
}

void OpenGLWindow::sleep(tick_t ticks)
{
    if(ticks > tick_t(0)){
        std::this_thread::sleep_for(ticks);
    }
}

void OpenGLWindow::startMainLoop(int updatesPerSecond, int framesPerSecond, float mainLoopInfoTime, int maxFrameSkip, bool _parallelUpdate, bool catchUp)
{
    parallelUpdate = _parallelUpdate;

    cout << "> Starting the main loop..." << endl;
    cout << "> updatesPerSecond=" << updatesPerSecond << " framesPerSecond=" << framesPerSecond << " maxFrameSkip=" << maxFrameSkip << endl;

    if(updatesPerSecond <= 0)
        updatesPerSecond = gameTime.base.count();
    if(framesPerSecond <= 0)
        framesPerSecond = gameTime.base.count();

    float updateDT = 1.0f / updatesPerSecond;
    //    float framesDT = 1.0f / framesPerSecond;

    tick_t ticksPerUpdate = gameTime.base / updatesPerSecond;
    tick_t ticksPerFrame = gameTime.base / framesPerSecond;

    tick_t ticksPerInfo = std::chrono::duration_cast<tick_t>(gameTime.base * mainLoopInfoTime);

    tick_t ticksPerScreenshot = std::chrono::duration_cast<tick_t>(gameTime.base * 5.0f);

    if(windowParameters.debugScreenshotTime < 0)
        ticksPerScreenshot = std::chrono::duration_cast<tick_t>(std::chrono::hours(100000));

    gameTime.init(ticksPerUpdate,ticksPerFrame);

    tick_t nextInfoTick = gameTime.getTime();
    tick_t nextScreenshotTick = gameTime.getTime() + ticksPerScreenshot;

    if(!catchUp){
        gameTime.maxGameLoopDelay = std::chrono::duration_cast<tick_t>(std::chrono::milliseconds(1000));
    }

    if(parallelUpdate){
        updateThread = std::thread(&OpenGLWindow::parallelUpdateThread,this,updateDT);
    }

    while(true){
        checkEvents();

        if(shouldClose()){
            break;
        }

        //With this loop we are able to skip frames if the system can't keep up.
        for(int i = 0; i <= maxFrameSkip && gameTime.shouldUpdate(); ++i){
            update(updateDT);
        }

        if(gameTime.shouldRender()){
            render(updateDT,gameTime.interpolation);
        }

        if(gameTime.getTime() > nextInfoTick){
            auto gt = std::chrono::duration_cast<std::chrono::seconds>(gameTime.getTime());
            cout << "> Time: " << gt.count() << "s  Total number of updates/frames: " << numUpdates << "/" << numFrames << "  UPS/FPS: " << (1000.0f/upsTimer.getTimeMS()) << "/" << (1000.0f/fpsTimer.getTimeMS()) << endl;
            nextInfoTick += ticksPerInfo;
        }

        if(gameTime.getTime() > nextScreenshotTick){
            string file = windowParameters.debugScreenshotPath+getTimeString()+".png";
            this->screenshot(file);
            nextScreenshotTick += ticksPerScreenshot;
        }

        //sleep until the next interesting event
        sleep(gameTime.getSleepTime());
        assert_no_glerror_end_frame();
    }
    running = false;

    if(parallelUpdate){
        //cleanup the update thread
        cout << "Finished main loop. Exiting update thread." << endl;
        endParallelUpdate();
        semStartUpdate.notify();
        updateThread.join();
    }

    auto gt = std::chrono::duration_cast<std::chrono::seconds>(gameTime.getTime());
    cout << "> Main loop finished in " << gt.count() << "s  Total number of updates/frames: " << numUpdates << "/" << numFrames  << endl;
}
<|endoftext|>


<commit_before>#include <wx/docview.h>
#include <wx/cmdproc.h>
#include <wx/menu.h>
#include <wx/image.h>
#include <wx/cmdline.h>
#include <wx/process.h>
#include <wx/stream.h>
#include <wx/msgdlg.h>
#include <list>

#include "wxUnivDiffApp.hpp"

#include "ui.h"

using namespace ui;
using std::list;

static const wxCmdLineEntryDesc cmdLineDesc[] = {
  { wxCMD_LINE_SWITCH, "v", "verbose", "be verbose" },
  //{ wxCMD_LINE_SWITCH, "q", "quiet",   "be quiet" },

  // { wxCMD_LINE_OPTION, "o", "output",  "output file" },
  { wxCMD_LINE_OPTION, "i", "interactive",   "interactive mode" },

  { wxCMD_LINE_OPTION, "l", "list",   "list " },
  { wxCMD_LINE_OPTION, "a", "add",   "add entry" },
  { wxCMD_LINE_OPTION, "del", "del",   "del entry" },

  { wxCMD_LINE_PARAM,  NULL, NULL, "input file", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_MULTIPLE| wxCMD_LINE_PARAM_OPTIONAL },

  { wxCMD_LINE_NONE }
};

IMPLEMENT_APP(wxUnivDiffApp)

wxUnivDiffApp::wxUnivDiffApp(void)
{}

wxUnivDiffApp::~wxUnivDiffApp(void)
{}

struct options_t {
  bool verbose;
  bool list;
  bool add;
  bool del;
  bool interactive;
  bool diff;
} options = { false,false,false,false,false,false };

list<wxString> parameters;

void wxUnivDiffApp::OnInitCmdLine(wxCmdLineParser& parser)
{
  parser.SetDesc(cmdLineDesc);
}

bool isCmdLineSwitch(const wxString& param)
{
  for (size_t option_index=0;
              option_index < sizeof(cmdLineDesc)/sizeof(cmdLineDesc[0]);
              ++option_index)
  {
    if ( param.substr(1).StartsWith(cmdLineDesc[option_index].shortName ) ) {
      return true;
    }
  }
  return false;
}

bool wxUnivDiffApp::OnCmdLineParsed	(	wxCmdLineParser & 	parser	)
{
  options.verbose = parser.FoundSwitch("v")==wxCMD_SWITCH_ON;

  options.list = parser.FoundSwitch("l")==wxCMD_SWITCH_ON;
  options.add  = parser.FoundSwitch("a")==wxCMD_SWITCH_ON;
  options.del  = parser.FoundSwitch("del")==wxCMD_SWITCH_ON;
  options.interactive = parser.FoundSwitch("i")==wxCMD_SWITCH_ON || parser.GetParamCount()<2;
  options.diff = !(options.list||options.add||options.del||options.interactive);

  //Parse commandline parameters which are not switches
  wxString param;
  for (size_t i=0; i <parser.GetParamCount(); ++i) {
    param = parser.GetParam(i);
    if (!isCmdLineSwitch(param)) {
      parameters.push_back(param);
    }
  }
  return true;
}

wxStringToStringHashMap extensions;

void LoadExtensions()
{
  wxConfigBase* config= wxConfig::Get();

  if (!config->HasGroup(_("extensions")) ) {
    config->Write("extensions/txt","self");
    config->Write("extensions/bin","selfbin");
    config->Flush();
  } else {

    wxString str;
    long lIndex;
    wxString value;
    config->SetPath("/extensions");
    bool cont = config->GetFirstEntry(str, lIndex);
    do {
      config->Read(str,&value);
      extensions[str] = value;
      cont = config->GetNextEntry(str,lIndex);
    } while(cont);
  }
}

bool wxUnivDiffApp::RunInteractive()
{
  //  wxArrayString r;
  //  // long result = wxShell("echo abc; exit", r);
  //  p.Redirect();
  //  long  result =  wxExecute("date",wxEXEC_ASYNC,&p);
  //  wxInputStream* in = p.GetInputStream();
  //
  //  wxChar buf[1024];
  //  while(in->CanRead())
  //  {
  //    in->ReadAll(buf,sizeof(buf));
  //    wxLogDebug(buf);
  //  };
  // Create the main frame window
  //MyFrame *frame = new MyFrame(wxT("wxListCtrl Test"));
  //MainFrame *frame = new MainFrame(NULL,wxID_ANY,wxT("tesme"));
  //// Show the frame
  //frame->Show(true);
  class MimeTypeListFrame: public MimetypeListFrameBase
  {
  public:
    MimeTypeListFrame()
      : MimetypeListFrameBase(NULL,wxID_ANY,wxT("Verknuepfte Anwendungen")) {}

    void OnApply( wxCommandEvent& event )
    {
      wxMessageBox(_T("Apply"));
    }
    void OnCancel( wxCommandEvent& event )
    {
      Close();
    }
    void OnOk( wxCommandEvent& event )
    {
      Close();
    }
    void OnHelp( wxCommandEvent& event )
    {
      wxMessageBox(_T("Help"));
    }

    void OnListItemActivated( wxListEvent& event )
    {
      wxMessageBox(_T("OnItemActivated"));
    }

  };

  MimetypeListFrameBase* mimetypeListFrame = new MimeTypeListFrame;

  mimetypeListFrame->m_listCtrlMimetypes->InsertColumn(1,"Extensions");
  mimetypeListFrame->m_listCtrlMimetypes->InsertColumn(2,"Aufruf");

  long index=0;
  wxListItem item;
  for (wxStringToStringHashMap::iterator it = extensions.begin();
       it != extensions.end();
       ++it) {
    item.SetText(it->first);
    item.SetColumn(0);
    item.SetId(index);
    index = mimetypeListFrame->m_listCtrlMimetypes->InsertItem( item );

    item.SetId(index);
    item.SetColumn(1);
    item.SetText(it->second);

    mimetypeListFrame->m_listCtrlMimetypes->SetItem(index, 1,it->second );
  }

  return mimetypeListFrame->Show(true);

  /*
   // start transaction
   //// Give it an icon (this is ignored in MDI mode: uses resources)
   #ifdef __WXMSW__
   pMainframe->SetIcon(wxIcon(_T("doc")));
   #endif
   #ifdef __X__
   pMainframe->SetIcon(wxIcon(_T("doc.xbm")));
   #endif

   #ifdef __WXMAC__
   wxMenuBar::MacSetCommonMenuBar(pMainframe->GetMenuBar());
   #endif //def __WXMAC__

   pMainframe->Centre(wxBOTH);

   SetTopWindow(pMainframe);
   #ifndef __WXMAC__
   pMainframe->Show(true);
   #endif //ndef __WXMAC__
   return true;
   */
}

int wxUnivDiffApp::RunCmdMode()
{
  static wxProcess runProc;
  wxString cmd = "C:\\Tools\\WinMerge\\WinMergeU.exe";
  for (list<wxString>::const_iterator
       param = parameters.begin();
       param != parameters.end();
       ++param) {
    cmd.append(" ");
    cmd.append(*param);
  }

  wxExecute(cmd,wxEXEC_ASYNC,&runProc);
  return 0;
}

bool wxUnivDiffApp::OnInit(void)
{
  ::wxInitAllImageHandlers();

  if ( !wxApp::OnInit() )
    return false;

  LoadExtensions();
  if (!options.diff)
    return RunInteractive();
  return true;
}

int wxUnivDiffApp::OnRun(void)
{
  // TODO check other flags
  if (options.diff) {
    return RunCmdMode();
  } else {
    return wxApp::OnRun();
  }
}

<commit_msg>parameter names commented out to prevent compiler warning<commit_after>#include <wx/docview.h>
#include <wx/cmdproc.h>
#include <wx/menu.h>
#include <wx/image.h>
#include <wx/cmdline.h>
#include <wx/process.h>
#include <wx/stream.h>
#include <wx/msgdlg.h>
#include <list>

#include "wxUnivDiffApp.hpp"

#include "ui.h"

using namespace ui;
using std::list;

static const wxCmdLineEntryDesc cmdLineDesc[] = {
  { wxCMD_LINE_SWITCH, "v", "verbose", "be verbose" },
  //{ wxCMD_LINE_SWITCH, "q", "quiet",   "be quiet" },

  // { wxCMD_LINE_OPTION, "o", "output",  "output file" },
  { wxCMD_LINE_OPTION, "i", "interactive",   "interactive mode" },

  { wxCMD_LINE_OPTION, "l", "list",   "list " },
  { wxCMD_LINE_OPTION, "a", "add",   "add entry" },
  { wxCMD_LINE_OPTION, "del", "del",   "del entry" },

  { wxCMD_LINE_PARAM,  NULL, NULL, "input file", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_MULTIPLE| wxCMD_LINE_PARAM_OPTIONAL },

  { wxCMD_LINE_NONE }
};

IMPLEMENT_APP(wxUnivDiffApp)

wxUnivDiffApp::wxUnivDiffApp(void)
{}

wxUnivDiffApp::~wxUnivDiffApp(void)
{}

struct options_t {
  bool verbose;
  bool list;
  bool add;
  bool del;
  bool interactive;
  bool diff;
} options = { false,false,false,false,false,false };

list<wxString> parameters;

void wxUnivDiffApp::OnInitCmdLine(wxCmdLineParser& parser)
{
  parser.SetDesc(cmdLineDesc);
}

bool isCmdLineSwitch(const wxString& param)
{
  for (size_t option_index=0;
              option_index < sizeof(cmdLineDesc)/sizeof(cmdLineDesc[0]);
              ++option_index)
  {
    if ( param.substr(1).StartsWith(cmdLineDesc[option_index].shortName ) ) {
      return true;
    }
  }
  return false;
}

bool wxUnivDiffApp::OnCmdLineParsed	(	wxCmdLineParser & 	parser	)
{
  options.verbose = parser.FoundSwitch("v")==wxCMD_SWITCH_ON;

  options.list = parser.FoundSwitch("l")==wxCMD_SWITCH_ON;
  options.add  = parser.FoundSwitch("a")==wxCMD_SWITCH_ON;
  options.del  = parser.FoundSwitch("del")==wxCMD_SWITCH_ON;
  options.interactive = parser.FoundSwitch("i")==wxCMD_SWITCH_ON || parser.GetParamCount()<2;
  options.diff = !(options.list||options.add||options.del||options.interactive);

  //Parse commandline parameters which are not switches
  wxString param;
  for (size_t i=0; i <parser.GetParamCount(); ++i) {
    param = parser.GetParam(i);
    if (!isCmdLineSwitch(param)) {
      parameters.push_back(param);
    }
  }
  return true;
}

wxStringToStringHashMap extensions;

void LoadExtensions()
{
  wxConfigBase* config= wxConfig::Get();

  if (!config->HasGroup(_("extensions")) ) {
    config->Write("extensions/txt","self");
    config->Write("extensions/bin","selfbin");
    config->Flush();
  } else {

    wxString str;
    long lIndex;
    wxString value;
    config->SetPath("/extensions");
    bool cont = config->GetFirstEntry(str, lIndex);
    do {
      config->Read(str,&value);
      extensions[str] = value;
      cont = config->GetNextEntry(str,lIndex);
    } while(cont);
  }
}

bool wxUnivDiffApp::RunInteractive()
{
  //  wxArrayString r;
  //  // long result = wxShell("echo abc; exit", r);
  //  p.Redirect();
  //  long  result =  wxExecute("date",wxEXEC_ASYNC,&p);
  //  wxInputStream* in = p.GetInputStream();
  //
  //  wxChar buf[1024];
  //  while(in->CanRead())
  //  {
  //    in->ReadAll(buf,sizeof(buf));
  //    wxLogDebug(buf);
  //  };
  // Create the main frame window
  //MyFrame *frame = new MyFrame(wxT("wxListCtrl Test"));
  //MainFrame *frame = new MainFrame(NULL,wxID_ANY,wxT("tesme"));
  //// Show the frame
  //frame->Show(true);
  class MimeTypeListFrame: public MimetypeListFrameBase
  {
  public:
    MimeTypeListFrame()
      : MimetypeListFrameBase(NULL,wxID_ANY,wxT("Verknuepfte Anwendungen")) {}

    void OnApply( wxCommandEvent& /*event*/ )
    {
      wxMessageBox(_T("Apply"));
    }
    void OnCancel( wxCommandEvent& /*event */)
    {
      Close();
    }
    void OnOk( wxCommandEvent& /*event*/ )
    {
      Close();
    }
    void OnHelp( wxCommandEvent& /*event*/ )
    {
      wxMessageBox(_T("Help"));
    }

    void OnListItemActivated( wxListEvent& /*event*/ )
    {
      wxMessageBox(_T("OnItemActivated"));
    }

  };

  MimetypeListFrameBase* mimetypeListFrame = new MimeTypeListFrame;

  mimetypeListFrame->m_listCtrlMimetypes->InsertColumn(1,"Extensions");
  mimetypeListFrame->m_listCtrlMimetypes->InsertColumn(2,"Aufruf");

  long index=0;
  wxListItem item;
  for (wxStringToStringHashMap::iterator it = extensions.begin();
       it != extensions.end();
       ++it) {
    item.SetText(it->first);
    item.SetColumn(0);
    item.SetId(index);
    index = mimetypeListFrame->m_listCtrlMimetypes->InsertItem( item );

    item.SetId(index);
    item.SetColumn(1);
    item.SetText(it->second);

    mimetypeListFrame->m_listCtrlMimetypes->SetItem(index, 1,it->second );
  }

  return mimetypeListFrame->Show(true);

  /*
   // start transaction
   //// Give it an icon (this is ignored in MDI mode: uses resources)
   #ifdef __WXMSW__
   pMainframe->SetIcon(wxIcon(_T("doc")));
   #endif
   #ifdef __X__
   pMainframe->SetIcon(wxIcon(_T("doc.xbm")));
   #endif

   #ifdef __WXMAC__
   wxMenuBar::MacSetCommonMenuBar(pMainframe->GetMenuBar());
   #endif //def __WXMAC__

   pMainframe->Centre(wxBOTH);

   SetTopWindow(pMainframe);
   #ifndef __WXMAC__
   pMainframe->Show(true);
   #endif //ndef __WXMAC__
   return true;
   */
}

int wxUnivDiffApp::RunCmdMode()
{
  static wxProcess runProc;
  wxString cmd = "C:\\Tools\\WinMerge\\WinMergeU.exe";
  for (list<wxString>::const_iterator
       param = parameters.begin();
       param != parameters.end();
       ++param) {
    cmd.append(" ");
    cmd.append(*param);
  }

  wxExecute(cmd,wxEXEC_ASYNC,&runProc);
  return 0;
}

bool wxUnivDiffApp::OnInit(void)
{
  ::wxInitAllImageHandlers();

  if ( !wxApp::OnInit() )
    return false;

  LoadExtensions();
  if (!options.diff)
    return RunInteractive();
  return true;
}

int wxUnivDiffApp::OnRun(void)
{
  // TODO check other flags
  if (options.diff) {
    return RunCmdMode();
  } else {
    return wxApp::OnRun();
  }
}

<|endoftext|>


<commit_before>/*
Copyright (C) 2011-2013 Yubico AB.  All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

   1. Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

   2. Redistributions in binary form must reproduce the above
      copyright notice, this list of conditions and the following
      disclaimer in the documentation and/or other materials provided
      with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "yubikeylogger.h"
#include <QFile>
#include <QDir>
#include <QDebug>
#include <QDateTime>
#include <QFileDialog>
#include <QSettings>

#define LOG_FILENAME_DEF   "configuration_log.csv"
#define LOG_SEPARATOR      ","

QString YubiKeyLogger::m_filename   = defaultLogFilename();
bool YubiKeyLogger::m_enabled       = true;
bool YubiKeyLogger::m_started       = true;
YubiKeyLogger::Format YubiKeyLogger::m_format = Format_Traditional;
QFile* YubiKeyLogger::m_logFile     = NULL;
QString YubiKeyLogger::m_flexibleFormat = "";

#define STRING 1
#define BOOL   2
#define INT    3
#define UINT   4

struct logging_st YubiKeyLogger::logging_map[] = {
    { "eventType", NULL, STRING, YubiKeyLogger::resolve_eventType },
    { "timestampLocal", NULL, STRING, YubiKeyLogger::resolve_timestamp },
    { "configSlot", "configSlot", INT, NULL },
    { "pubIdTxt", "pubIdTxt", STRING, NULL },
    { "pvtIdTxt", "pvtIdTxt", STRING, NULL },
    { "secretKeyTxt", "secretKeyTxt", STRING, NULL },
    { "secretKeyB64", NULL, STRING, YubiKeyLogger::resolve_secretKeyB64 },
    { "currentAccessCodeTxt", "currentAccessCodeTxt", STRING, NULL },
    { "newAccessCodeTxt", "newAccessCodeTxt", STRING, NULL },
    { "hotpDigits", NULL, STRING, YubiKeyLogger::resolve_hotpDigits },
    { "oathMovingFactorSeed", "oathMovingFactorSeed", UINT, NULL },
    { "strongPw1", "strongPw1", BOOL, NULL },
    { "strongPw2", "strongPw2", BOOL, NULL },
    { "sendRef", "sendRef", BOOL, NULL },
    { "chalBtnTrig", "chalBtnTrig", BOOL, NULL },
    { "hmacLT64", "hmacLT64", BOOL, NULL },
    { "timestampFixed", NULL, STRING, YubiKeyLogger::resolve_timestamp },
    { "oathFixedModhex1", "oathFixedModhex1", BOOL, NULL },
    { "oathFixedModhex2", "oathFixedModhex2", BOOL, NULL },
    { "oathFixedModhex", "oathFixedModhex", BOOL, NULL },
    { "tokenLength", NULL, STRING, YubiKeyLogger::resolve_tokenLength },
    { "serial", "serial", STRING, NULL },
    { "endl", NULL, STRING, YubiKeyLogger::resolve_symbol },
    { "tab", NULL, STRING, YubiKeyLogger::resolve_symbol },
};

YubiKeyLogger::~YubiKeyLogger() {
}

QFile *YubiKeyLogger::getLogFile() {
    if(m_logFile == NULL) {
        m_filename = QFileDialog::getSaveFileName(NULL, tr("Select Log File"), m_filename, "Comma-sepparated values (*.csv)", NULL, QFileDialog::DontConfirmOverwrite);
        if(m_filename.isEmpty()) {
            qDebug() << "No filename returned for logging";
            return NULL;
        }
        m_logFile = new QFile(m_filename);
        if(!m_logFile->open(QIODevice::WriteOnly | QIODevice::Append)) {
            qDebug() << "File could not be opened for writing";
            return NULL;
        }
        QSettings settings;
        settings.setValue(SG_LOG_FILENAME, m_filename);
    }
    return m_logFile;
}

void YubiKeyLogger::closeLogFile() {
    if(m_logFile != NULL) {
        if(m_format == Format_PSKC) {
            endPSKC();
        }
        m_logFile->close();
        delete(m_logFile);
        m_logFile = NULL;
        m_started = true;
    }
}

QString YubiKeyLogger::formatLog(YubiKeyConfig *ykConfig, QString format) {
    for(unsigned long i = 0; i < (sizeof(logging_map) / sizeof(logging_st)); i++) {
        QString token = QString("{") + logging_map[i].name + QString("}");
        if(!format.contains(token)) {
            continue;
        }
        QString out;
        int type = logging_map[i].returnType;
        const char *configName = logging_map[i].configName;
        if(logging_map[i].resolver != NULL) {
            out = logging_map[i].resolver(ykConfig, logging_map[i].name);
        } else if(type == STRING) {
            QMetaObject::invokeMethod(ykConfig, configName,
                    Qt::DirectConnection, Q_RETURN_ARG(QString, out));
        } else if(type == BOOL) {
            bool ret;
            QMetaObject::invokeMethod(ykConfig, configName,
                    Qt::DirectConnection, Q_RETURN_ARG(bool, ret));
            out = ret ? "1" : "0";
        } else if(type == INT) {
            int ret;
            QMetaObject::invokeMethod(ykConfig, configName,
                    Qt::DirectConnection, Q_RETURN_ARG(int, ret));
            out = QString::number(ret);
        } else if(type == UINT) {
            unsigned int ret;
            QMetaObject::invokeMethod(ykConfig, configName,
                    Qt::DirectConnection, Q_RETURN_ARG(unsigned int, ret));
            out = QString::number(ret);
        }

        qDebug() << "replacing " << token << " with " << out << " from " << configName << " type " << type;
        format.replace(token, out);
    }
    return format;
}

void YubiKeyLogger::logConfig(YubiKeyConfig *ykConfig) {
    //Check if logging is enabled
    if(!m_enabled) {
        return;
    }

    QString format = "";
    if(m_format == Format_Traditional) {
        if(m_started) {
            format += "LOGGING START,{timestampLocal}{endl}";
            m_started = false;
        }

        format += "{eventType},{timestampLocal},{configSlot},{pubIdTxt},{pvtIdTxt},{secretKeyTxt},{currentAccessCodeTxt},{newAccessCodeTxt},{oathFixedModhex1},{oathFixedModhex2},{oathFixedModhex},{hotpDigits},{oathMovingFactorSeed},{strongPw1},{strongPw2},{sendRef},{chalBtnTrig},{hmacLT64}";
    } else if(m_format == Format_Yubico) {
        format = "{serial},";
        if(ykConfig->programmingMode() == YubiKeyConfig::Mode_YubicoOtp) {
            format += "{pubIdTxt},{pvtIdTxt},";
        } else if(ykConfig->programmingMode() == YubiKeyConfig::Mode_OathHotp) {
            format += "{pubIdTxt},{oathMovingFactorSeed},";
        } else if(ykConfig->programmingMode() == YubiKeyConfig::Mode_ChalRespHmac) {
            format += ",0,";
        } else {
            format += ",,";
        }
        format += "{secretKeyTxt},{newAccessCodeTxt},{timestampFixed},";
    } else if(m_format == Format_PSKC) {
        if(m_started) {
            format += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>{endl}<KeyContainer Version=\"1.0\" xmlns=\"urn:ietf:params:xml:ns:keyprov:pskc\">{endl}";
            m_started = false;
        }
        format += "<KeyPackage><DeviceInfo><Manufacturer>Yubico</Manufacturer><SerialNo>{serial}</SerialNo></DeviceInfo>";
        format += "<CryptoModuleInfo><Id>{configSlot}</Id></CryptoModuleInfo><Key Id=\"{serial}:{configSlot}\"";
        if(ykConfig->programmingMode() == YubiKeyConfig::Mode_YubicoOtp) {
            format += "Algorithm=\"http://www.yubico.com/#yubikey-aes\"><AlgorithmParameters><ResponseFormat Length=\"{tokenLength}\" Encoding=\"ALPHANUMERIC\"/></AlgorithmParameters>";
        } else if(ykConfig->programmingMode() == YubiKeyConfig::Mode_OathHotp) {
            format += "Algorithm=\"urn:ietf:params:xml:ns:keyprov:pskc:hotp\"><AlgorithmParameters><ResponseFormat Length=\"{tokenLength}\" Encoding=\"DECIMAL\"/></AlgorithmParameters>";
        } else {
            qDebug() << "PSKC is primarily for Oath-HOTP and Yubico-OTP";
            format += ">";
        }
        format += "<Data><Secret><PlainValue>{secretKeyB64}</PlainValue></Secret>";
        if(ykConfig->programmingMode() == YubiKeyConfig::Mode_OathHotp) {
            format += "<Counter><PlainValue>{oathMovingFactorSeed}</PlainValue></Counter>";
        }
        format += "</Data>";
        if(ykConfig->programmingMode() == YubiKeyConfig::Mode_YubicoOtp) {
            format += "<UserId>CN={pubIdTxt}, UID={pvtIdTxt}</UserId>";
        }
        format += "</Key></KeyPackage>";
    } else if(m_format == Format_Flexible) {
        format = m_flexibleFormat;
    } else {
        qDebug() << "unknown format" << m_format;
        return;
    }
    format = formatLog(ykConfig, format);
    logString(format);
}

void YubiKeyLogger::enableLogging() {
    m_enabled = true;
}

void YubiKeyLogger::disableLogging() {
    m_enabled = false;
}

bool YubiKeyLogger::isLogging() {
    return m_enabled;
}

void YubiKeyLogger::setLogFilename(const QString &filename) {
    closeLogFile();
    m_filename = filename;
}

QString YubiKeyLogger::logFilename() {
    return m_filename;
}

QString YubiKeyLogger::defaultLogFilename() {
    return QDir::homePath() + "/" + LOG_FILENAME_DEF;
}

void YubiKeyLogger::setLogFormat(Format format) {
    closeLogFile();
    m_format = format;
}

void YubiKeyLogger::setFlexibleFormat(QString format) {
    m_flexibleFormat = format;
}

QString YubiKeyLogger::resolve_hotpDigits(YubiKeyConfig *ykConfig, QString name __attribute__((unused))) {
    QString ret = "0";
    if(ykConfig->programmingMode() == YubiKeyConfig::Mode_OathHotp) {
        ret = (ykConfig->oathHotp8()? "8": "6");
    }
    return ret;
}

QString YubiKeyLogger::resolve_eventType(YubiKeyConfig *ykConfig, QString name __attribute__((unused))) {
    switch(ykConfig->programmingMode()) {
        case YubiKeyConfig::Mode_YubicoOtp:
            return(tr("Yubico OTP"));
        case YubiKeyConfig::Mode_Static:
            {
                QString eventType = tr("Static Password");
                if(ykConfig->shortTicket()) {
                    if(ykConfig->staticTicket()) {
                        eventType.append(tr(": Short"));
                    } else {
                        eventType.append(tr(": Scan Code"));
                    }
                }
                return eventType;
            }
        case YubiKeyConfig::Mode_OathHotp:
            return(tr("OATH-HOTP"));
        case YubiKeyConfig::Mode_ChalRespYubico:
            return(tr("Challenge-Response: Yubico OTP"));
        case YubiKeyConfig::Mode_ChalRespHmac:
            return(tr("Challenge-Response: HMAC-SHA1"));
        case YubiKeyConfig::Mode_Update:
            return(tr("Configuration Update"));
        case YubiKeyConfig::Mode_Swap:
            return(tr("Configuration Swap"));
    }
    return(tr("Unknown programming mode"));
}

QString YubiKeyLogger::resolve_timestamp(YubiKeyConfig *ykConfig __attribute__((unused)), QString name) {
        QDateTime ts = QDateTime::currentDateTime();
        if(name == "timestampLocal") {
            return ts.toString(Qt::SystemLocaleDate);
        } else {
            return ts.toString("yyyy-MM-ddThh:mm:ss");
        }
}

QString YubiKeyLogger::resolve_symbol(YubiKeyConfig *ykConfig __attribute__((unused)), QString name) {
    if(name == "endl") {
        return "\n";
    } else if(name == "tab") {
        return "\t";
    }
    return "";
}

QString YubiKeyLogger::resolve_secretKeyB64(YubiKeyConfig *ykConfig, QString name __attribute__((unused))) {
    QByteArray decodedSecret = QByteArray::fromHex(ykConfig->secretKeyTxt().toLatin1());
    return decodedSecret.toBase64();
}

QString YubiKeyLogger::resolve_tokenLength(YubiKeyConfig *ykConfig, QString name __attribute__((unused))) {
    int len = ykConfig->pubIdTxt().length();

    if(ykConfig->programmingMode() == YubiKeyConfig::Mode_YubicoOtp) {
        len += 32;
    } else if(ykConfig->programmingMode() == YubiKeyConfig::Mode_OathHotp) {
        len += ykConfig->oathHotp8() ? 8 : 6;
    }
    return QString::number(len);
}

QStringList YubiKeyLogger::getLogNames() {
    QStringList list;
    for(unsigned int i = 0; i < (sizeof(logging_map) / sizeof(logging_st)); i++) {
        list << logging_map[i].name;
    }
    return list;
}

void YubiKeyLogger::endPSKC() {
    logString("</KeyContainer>");
}

void YubiKeyLogger::logString(QString string) {
    QFile *file = getLogFile();
    if(file == NULL) {
        qDebug() << "Failed to get logfile";
        return;
    }

    QTextStream out(file);
    out << string << endl;
    file->flush();
}
<commit_msg>fixup xml syntax<commit_after>/*
Copyright (C) 2011-2013 Yubico AB.  All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

   1. Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

   2. Redistributions in binary form must reproduce the above
      copyright notice, this list of conditions and the following
      disclaimer in the documentation and/or other materials provided
      with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "yubikeylogger.h"
#include <QFile>
#include <QDir>
#include <QDebug>
#include <QDateTime>
#include <QFileDialog>
#include <QSettings>

#define LOG_FILENAME_DEF   "configuration_log.csv"
#define LOG_SEPARATOR      ","

QString YubiKeyLogger::m_filename   = defaultLogFilename();
bool YubiKeyLogger::m_enabled       = true;
bool YubiKeyLogger::m_started       = true;
YubiKeyLogger::Format YubiKeyLogger::m_format = Format_Traditional;
QFile* YubiKeyLogger::m_logFile     = NULL;
QString YubiKeyLogger::m_flexibleFormat = "";

#define STRING 1
#define BOOL   2
#define INT    3
#define UINT   4

struct logging_st YubiKeyLogger::logging_map[] = {
    { "eventType", NULL, STRING, YubiKeyLogger::resolve_eventType },
    { "timestampLocal", NULL, STRING, YubiKeyLogger::resolve_timestamp },
    { "configSlot", "configSlot", INT, NULL },
    { "pubIdTxt", "pubIdTxt", STRING, NULL },
    { "pvtIdTxt", "pvtIdTxt", STRING, NULL },
    { "secretKeyTxt", "secretKeyTxt", STRING, NULL },
    { "secretKeyB64", NULL, STRING, YubiKeyLogger::resolve_secretKeyB64 },
    { "currentAccessCodeTxt", "currentAccessCodeTxt", STRING, NULL },
    { "newAccessCodeTxt", "newAccessCodeTxt", STRING, NULL },
    { "hotpDigits", NULL, STRING, YubiKeyLogger::resolve_hotpDigits },
    { "oathMovingFactorSeed", "oathMovingFactorSeed", UINT, NULL },
    { "strongPw1", "strongPw1", BOOL, NULL },
    { "strongPw2", "strongPw2", BOOL, NULL },
    { "sendRef", "sendRef", BOOL, NULL },
    { "chalBtnTrig", "chalBtnTrig", BOOL, NULL },
    { "hmacLT64", "hmacLT64", BOOL, NULL },
    { "timestampFixed", NULL, STRING, YubiKeyLogger::resolve_timestamp },
    { "oathFixedModhex1", "oathFixedModhex1", BOOL, NULL },
    { "oathFixedModhex2", "oathFixedModhex2", BOOL, NULL },
    { "oathFixedModhex", "oathFixedModhex", BOOL, NULL },
    { "tokenLength", NULL, STRING, YubiKeyLogger::resolve_tokenLength },
    { "serial", "serial", STRING, NULL },
    { "endl", NULL, STRING, YubiKeyLogger::resolve_symbol },
    { "tab", NULL, STRING, YubiKeyLogger::resolve_symbol },
};

YubiKeyLogger::~YubiKeyLogger() {
}

QFile *YubiKeyLogger::getLogFile() {
    if(m_logFile == NULL) {
        m_filename = QFileDialog::getSaveFileName(NULL, tr("Select Log File"), m_filename, "Comma-sepparated values (*.csv)", NULL, QFileDialog::DontConfirmOverwrite);
        if(m_filename.isEmpty()) {
            qDebug() << "No filename returned for logging";
            return NULL;
        }
        m_logFile = new QFile(m_filename);
        if(!m_logFile->open(QIODevice::WriteOnly | QIODevice::Append)) {
            qDebug() << "File could not be opened for writing";
            return NULL;
        }
        QSettings settings;
        settings.setValue(SG_LOG_FILENAME, m_filename);
    }
    return m_logFile;
}

void YubiKeyLogger::closeLogFile() {
    if(m_logFile != NULL) {
        if(m_format == Format_PSKC) {
            endPSKC();
        }
        m_logFile->close();
        delete(m_logFile);
        m_logFile = NULL;
        m_started = true;
    }
}

QString YubiKeyLogger::formatLog(YubiKeyConfig *ykConfig, QString format) {
    for(unsigned long i = 0; i < (sizeof(logging_map) / sizeof(logging_st)); i++) {
        QString token = QString("{") + logging_map[i].name + QString("}");
        if(!format.contains(token)) {
            continue;
        }
        QString out;
        int type = logging_map[i].returnType;
        const char *configName = logging_map[i].configName;
        if(logging_map[i].resolver != NULL) {
            out = logging_map[i].resolver(ykConfig, logging_map[i].name);
        } else if(type == STRING) {
            QMetaObject::invokeMethod(ykConfig, configName,
                    Qt::DirectConnection, Q_RETURN_ARG(QString, out));
        } else if(type == BOOL) {
            bool ret;
            QMetaObject::invokeMethod(ykConfig, configName,
                    Qt::DirectConnection, Q_RETURN_ARG(bool, ret));
            out = ret ? "1" : "0";
        } else if(type == INT) {
            int ret;
            QMetaObject::invokeMethod(ykConfig, configName,
                    Qt::DirectConnection, Q_RETURN_ARG(int, ret));
            out = QString::number(ret);
        } else if(type == UINT) {
            unsigned int ret;
            QMetaObject::invokeMethod(ykConfig, configName,
                    Qt::DirectConnection, Q_RETURN_ARG(unsigned int, ret));
            out = QString::number(ret);
        }

        qDebug() << "replacing " << token << " with " << out << " from " << configName << " type " << type;
        format.replace(token, out);
    }
    return format;
}

void YubiKeyLogger::logConfig(YubiKeyConfig *ykConfig) {
    //Check if logging is enabled
    if(!m_enabled) {
        return;
    }

    QString format = "";
    if(m_format == Format_Traditional) {
        if(m_started) {
            format += "LOGGING START,{timestampLocal}{endl}";
            m_started = false;
        }

        format += "{eventType},{timestampLocal},{configSlot},{pubIdTxt},{pvtIdTxt},{secretKeyTxt},{currentAccessCodeTxt},{newAccessCodeTxt},{oathFixedModhex1},{oathFixedModhex2},{oathFixedModhex},{hotpDigits},{oathMovingFactorSeed},{strongPw1},{strongPw2},{sendRef},{chalBtnTrig},{hmacLT64}";
    } else if(m_format == Format_Yubico) {
        format = "{serial},";
        if(ykConfig->programmingMode() == YubiKeyConfig::Mode_YubicoOtp) {
            format += "{pubIdTxt},{pvtIdTxt},";
        } else if(ykConfig->programmingMode() == YubiKeyConfig::Mode_OathHotp) {
            format += "{pubIdTxt},{oathMovingFactorSeed},";
        } else if(ykConfig->programmingMode() == YubiKeyConfig::Mode_ChalRespHmac) {
            format += ",0,";
        } else {
            format += ",,";
        }
        format += "{secretKeyTxt},{newAccessCodeTxt},{timestampFixed},";
    } else if(m_format == Format_PSKC) {
        if(m_started) {
            format += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>{endl}<KeyContainer Version=\"1.0\" xmlns=\"urn:ietf:params:xml:ns:keyprov:pskc\">{endl}";
            m_started = false;
        }
        format += "<KeyPackage><DeviceInfo><Manufacturer>Yubico</Manufacturer><SerialNo>{serial}</SerialNo></DeviceInfo>";
        format += "<CryptoModuleInfo><Id>{configSlot}</Id></CryptoModuleInfo><Key Id=\"{serial}:{configSlot}\"";
        if(ykConfig->programmingMode() == YubiKeyConfig::Mode_YubicoOtp) {
            format += " Algorithm=\"http://www.yubico.com/#yubikey-aes\"><AlgorithmParameters><ResponseFormat Length=\"{tokenLength}\" Encoding=\"ALPHANUMERIC\"/></AlgorithmParameters>";
        } else if(ykConfig->programmingMode() == YubiKeyConfig::Mode_OathHotp) {
            format += " Algorithm=\"urn:ietf:params:xml:ns:keyprov:pskc:hotp\"><AlgorithmParameters><ResponseFormat Length=\"{tokenLength}\" Encoding=\"DECIMAL\"/></AlgorithmParameters>";
        } else {
            qDebug() << "PSKC is primarily for Oath-HOTP and Yubico-OTP";
            format += ">";
        }
        format += "<Data><Secret><PlainValue>{secretKeyB64}</PlainValue></Secret>";
        if(ykConfig->programmingMode() == YubiKeyConfig::Mode_OathHotp) {
            format += "<Counter><PlainValue>{oathMovingFactorSeed}</PlainValue></Counter>";
        }
        format += "</Data>";
        if(ykConfig->programmingMode() == YubiKeyConfig::Mode_YubicoOtp) {
            format += "<UserId>CN={pubIdTxt}, UID={pvtIdTxt}</UserId>";
        }
        format += "</Key></KeyPackage>";
    } else if(m_format == Format_Flexible) {
        format = m_flexibleFormat;
    } else {
        qDebug() << "unknown format" << m_format;
        return;
    }
    format = formatLog(ykConfig, format);
    logString(format);
}

void YubiKeyLogger::enableLogging() {
    m_enabled = true;
}

void YubiKeyLogger::disableLogging() {
    m_enabled = false;
}

bool YubiKeyLogger::isLogging() {
    return m_enabled;
}

void YubiKeyLogger::setLogFilename(const QString &filename) {
    closeLogFile();
    m_filename = filename;
}

QString YubiKeyLogger::logFilename() {
    return m_filename;
}

QString YubiKeyLogger::defaultLogFilename() {
    return QDir::homePath() + "/" + LOG_FILENAME_DEF;
}

void YubiKeyLogger::setLogFormat(Format format) {
    closeLogFile();
    m_format = format;
}

void YubiKeyLogger::setFlexibleFormat(QString format) {
    m_flexibleFormat = format;
}

QString YubiKeyLogger::resolve_hotpDigits(YubiKeyConfig *ykConfig, QString name __attribute__((unused))) {
    QString ret = "0";
    if(ykConfig->programmingMode() == YubiKeyConfig::Mode_OathHotp) {
        ret = (ykConfig->oathHotp8()? "8": "6");
    }
    return ret;
}

QString YubiKeyLogger::resolve_eventType(YubiKeyConfig *ykConfig, QString name __attribute__((unused))) {
    switch(ykConfig->programmingMode()) {
        case YubiKeyConfig::Mode_YubicoOtp:
            return(tr("Yubico OTP"));
        case YubiKeyConfig::Mode_Static:
            {
                QString eventType = tr("Static Password");
                if(ykConfig->shortTicket()) {
                    if(ykConfig->staticTicket()) {
                        eventType.append(tr(": Short"));
                    } else {
                        eventType.append(tr(": Scan Code"));
                    }
                }
                return eventType;
            }
        case YubiKeyConfig::Mode_OathHotp:
            return(tr("OATH-HOTP"));
        case YubiKeyConfig::Mode_ChalRespYubico:
            return(tr("Challenge-Response: Yubico OTP"));
        case YubiKeyConfig::Mode_ChalRespHmac:
            return(tr("Challenge-Response: HMAC-SHA1"));
        case YubiKeyConfig::Mode_Update:
            return(tr("Configuration Update"));
        case YubiKeyConfig::Mode_Swap:
            return(tr("Configuration Swap"));
    }
    return(tr("Unknown programming mode"));
}

QString YubiKeyLogger::resolve_timestamp(YubiKeyConfig *ykConfig __attribute__((unused)), QString name) {
        QDateTime ts = QDateTime::currentDateTime();
        if(name == "timestampLocal") {
            return ts.toString(Qt::SystemLocaleDate);
        } else {
            return ts.toString("yyyy-MM-ddThh:mm:ss");
        }
}

QString YubiKeyLogger::resolve_symbol(YubiKeyConfig *ykConfig __attribute__((unused)), QString name) {
    if(name == "endl") {
        return "\n";
    } else if(name == "tab") {
        return "\t";
    }
    return "";
}

QString YubiKeyLogger::resolve_secretKeyB64(YubiKeyConfig *ykConfig, QString name __attribute__((unused))) {
    QByteArray decodedSecret = QByteArray::fromHex(ykConfig->secretKeyTxt().toLatin1());
    return decodedSecret.toBase64();
}

QString YubiKeyLogger::resolve_tokenLength(YubiKeyConfig *ykConfig, QString name __attribute__((unused))) {
    int len = ykConfig->pubIdTxt().length();

    if(ykConfig->programmingMode() == YubiKeyConfig::Mode_YubicoOtp) {
        len += 32;
    } else if(ykConfig->programmingMode() == YubiKeyConfig::Mode_OathHotp) {
        len += ykConfig->oathHotp8() ? 8 : 6;
    }
    return QString::number(len);
}

QStringList YubiKeyLogger::getLogNames() {
    QStringList list;
    for(unsigned int i = 0; i < (sizeof(logging_map) / sizeof(logging_st)); i++) {
        list << logging_map[i].name;
    }
    return list;
}

void YubiKeyLogger::endPSKC() {
    logString("</KeyContainer>");
}

void YubiKeyLogger::logString(QString string) {
    QFile *file = getLogFile();
    if(file == NULL) {
        qDebug() << "Failed to get logfile";
        return;
    }

    QTextStream out(file);
    out << string << endl;
    file->flush();
}
<|endoftext|>