<commit_before>/******************************************************************************
 * This file is part of the Gluon Development Platform
 * Copyright (c) 2010 Arjen Hiemstra <ahiemstra@heimr.nl>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "mainwindow.h"

#include <QtCore/QVariantList>

#include <KFileDialog>
#include <KStandardAction>
#include <KActionCollection>
#include <KAction>
#include <KStatusBar>
#include <KMessageBox>
#include <KConfigDialog>
#include <KLocalizedString>
#include <KPluginSelector>
#include <KRun>
#include <KRecentFilesAction>
#include <KDE/KTabWidget>
#include <KDE/KToolBar>
#include <KDE/KRichTextEdit>

#include <core/debughelper.h>
#include <engine/game.h>
#include <engine/gameproject.h>
#include <engine/scene.h>

#include "lib/plugin.h"
#include "lib/pluginmanager.h"
#include "lib/objectmanager.h"
#include "lib/historymanager.h"
#include "lib/selectionmanager.h"
#include "lib/dockmanager.h"
#include "lib/filemanager.h"
#include "lib/widgets/filearea.h"

#include "gluoncreatorsettings.h"
#include "dialogs/configdialog.h"
#include <QVBoxLayout>
#include <KParts/PartManager>

using namespace GluonCreator;

class MainWindow::MainWindowPrivate
{
    public:
        MainWindowPrivate()
        {
        }

        bool modified;
        QString fileName;
        KRecentFilesAction* recentFiles;
        ProjectSelectionDialog* projectDialog;

        FileArea* mainArea;
};

MainWindow::MainWindow( const QString& fileName )
    : KParts::MainWindow(),
      d( new MainWindowPrivate )
{
    d->modified = false;

    GluonCore::GluonObjectFactory::instance()->loadPlugins();

    PluginManager::instance()->setParent( this );
    ObjectManager::instance()->setParent( this );
    HistoryManager::instance()->setParent( this );
    SelectionManager::instance()->setParent( this );

    DockManager::instance()->setParent( this );
    DockManager::instance()->setMainWindow( this );

    FileManager::instance()->initialize( this );
    connect( FileManager::instance()->partManager(), SIGNAL( activePartChanged( KParts::Part* ) ), this, SLOT( createGUI( KParts::Part* ) ) );

    PluginManager::instance()->setMainWindow( this );
    PluginManager::instance()->loadPlugins();

    setDockNestingEnabled( true );
    setCorner( Qt::TopLeftCorner, Qt::LeftDockWidgetArea );
    setCorner( Qt::BottomLeftCorner, Qt::LeftDockWidgetArea );
    setCorner( Qt::TopRightCorner, Qt::RightDockWidgetArea );
    setCorner( Qt::BottomRightCorner, Qt::RightDockWidgetArea );

    d->mainArea = new FileArea( this );
    setCentralWidget( d->mainArea );

    setupActions();
    setupGUI();
    stateChanged( "initial" );

    d->projectDialog = new ProjectSelectionDialog( this );
    d->projectDialog->setModal( true );
    connect( d->projectDialog, SIGNAL( accepted() ), SLOT( projectDialogClosed() ) );

    DockManager::instance()->setDocksEnabled( false );
    DockManager::instance()->setDocksLocked( GluonCreator::Settings::lockLayout() );

    if( fileName.isEmpty() )
    {
        showNewProjectDialog();
    }
    else
    {
        openProject( fileName );
    }
}

MainWindow::~MainWindow()
{
    d->recentFiles->saveEntries( KGlobal::config()->group( "Recent Files" ) );
    GluonCreator::Settings::setLockLayout( actionCollection()->action( "lockLayout" )->isChecked() );
    GluonCreator::Settings::self()->writeConfig();
    GluonEngine::Game::instance()->stopGame();
}

void MainWindow::openProject( KUrl url )
{
    openProject( url.path() );
}

void MainWindow::openProject( const QString& fileName )
{
    if( !fileName.isEmpty() && QFile::exists( fileName ) )
    {
        statusBar()->showMessage( i18n( "Opening project..." ) );

        FileManager::instance()->openFile( fileName, i18nc( "View Game Tab", "View" ), "gluon_viewer_part", QVariantList() << QString( "autoplay=false" ) );

        GluonEngine::Game::instance()->initializeAll();
        GluonEngine::Game::instance()->drawAll();

        d->fileName = fileName;
        d->recentFiles->addUrl( KUrl( fileName ) );

        stateChanged( "fileOpened" );
        DockManager::instance()->setDocksEnabled( true );

        if( centralWidget() )
            centralWidget()->setEnabled( true );

        statusBar()->showMessage( i18n( "Project successfully opened" ) );
        setCaption( i18n( "%1 - Gluon Creator", fileName.section( '/', -1 ) ) );
        HistoryManager::instance()->clear();
        connect( HistoryManager::instance(), SIGNAL( historyChanged( const QUndoCommand* ) ), SLOT( historyChanged() ) );
    }
    else
    {
        statusBar()->showMessage( i18n( "Unable to open project file..." ) );
    }
}

void MainWindow::saveProject()
{
    saveProject( d->fileName );
}

void MainWindow::saveProject( const QString& fileName )
{
    if( !fileName.isEmpty() )
    {
        statusBar()->showMessage( i18n( "Saving project..." ) );
        GluonEngine::Game::instance()->gameProject()->setFilename( QUrl( fileName ) );
        QDir::setCurrent( KUrl( fileName ).directory() );
        if( !GluonEngine::Game::instance()->gameProject()->saveToFile() )
        {
            KMessageBox::error( this, i18n( "Could not save file." ) );
            return;
        }
        statusBar()->showMessage( i18n( "Project successfully saved." ) );
        setCaption( i18n( "%1 - Gluon Creator", fileName.section( '/', -1 ) ) );
        HistoryManager::instance()->setClean();

        d->recentFiles->addUrl( KUrl( fileName ) );
    }
    else
    {
        saveProjectAs();
    }
}

void MainWindow::saveProjectAs()
{
    d->fileName = KFileDialog::getSaveFileName( KUrl(), i18n( "*.gluon|Gluon Project Files" ) );
    if( !d->fileName.isEmpty() ) saveProject();
}

void MainWindow::setupActions()
{
    KStandardAction::openNew( this, SLOT( showNewProjectDialog() ), actionCollection() );
    KStandardAction::open( this, SLOT( showOpenProjectDialog() ), actionCollection() );
    KStandardAction::save( this, SLOT( saveProject() ), actionCollection() );
    KStandardAction::saveAs( this, SLOT( saveProjectAs() ), actionCollection() );
    KStandardAction::quit( this, SLOT( close() ), actionCollection() );
    KStandardAction::preferences( this, SLOT( showPreferences() ), actionCollection() );

    KAction* undo = KStandardAction::undo( HistoryManager::instance(), SLOT( undo() ), actionCollection() );
    connect( HistoryManager::instance(), SIGNAL( canUndoChanged( bool ) ), undo, SLOT( setEnabled( bool ) ) );

    KAction* redo = KStandardAction::redo( HistoryManager::instance(), SLOT( redo() ), actionCollection() );
    connect( HistoryManager::instance(), SIGNAL( canRedoChanged( bool ) ), redo, SLOT( setEnabled( bool ) ) );

    connect( HistoryManager::instance(), SIGNAL( cleanChanged( bool ) ), SLOT( cleanChanged( bool ) ) );

    d->recentFiles = KStandardAction::openRecent( this, SLOT( openProject( KUrl ) ), actionCollection() );
    d->recentFiles->loadEntries( KGlobal::config()->group( "Recent Files" ) );

    KAction* newObject = new KAction( KIcon( "document-new" ), i18n( "New Object" ), actionCollection() );
    actionCollection()->addAction( "newObject", newObject );
    connect( newObject, SIGNAL( triggered( bool ) ), ObjectManager::instance(), SLOT( createNewGameObject() ) );

    KAction* newScene = new KAction( KIcon( "document-new" ), i18n( "New Scene" ), actionCollection() );
    actionCollection()->addAction( "newScene", newScene );
    connect( newScene, SIGNAL( triggered( bool ) ), ObjectManager::instance(), SLOT( createNewScene() ) );

    KAction* play = new KAction( KIcon( "media-playback-start" ), i18n( "Play Game" ), actionCollection() );
    actionCollection()->addAction( "playGame", play );
    connect( play, SIGNAL( triggered( bool ) ), SLOT( playGame() ) );

    KAction* pause = new KAction( KIcon( "media-playback-pause" ), i18n( "Pause Game" ), actionCollection() );
    actionCollection()->addAction( "pauseGame", pause );
    connect( pause, SIGNAL( triggered( bool ) ), SLOT( pauseGame() ) );

    KAction* stop = new KAction( KIcon( "media-playback-stop" ), i18n( "Stop Game" ), actionCollection() );
    actionCollection()->addAction( "stopGame", stop );
    connect( stop, SIGNAL( triggered( bool ) ), SLOT( stopGame() ) );

    KAction* addAsset = new KAction( KIcon( "document-new" ), i18n( "Add Assets..." ), actionCollection() );
    actionCollection()->addAction( "addAsset", addAsset );
    connect( addAsset, SIGNAL( triggered( bool ) ), SLOT( addAsset() ) );

    KAction* chooseEntryPoint = new KAction( KIcon( "media-playback-start" ), i18n( "Set current scene as entry point" ), actionCollection() );
    actionCollection()->addAction( "chooseEntryPoint", chooseEntryPoint );
    connect( chooseEntryPoint, SIGNAL( triggered( bool ) ), SLOT( chooseEntryPoint() ) );

    KAction* lockLayout = new KAction( KIcon( "object-locked" ), i18n( "Lock layout" ), actionCollection() );
    actionCollection()->addAction( "lockLayout", lockLayout );
    lockLayout->setCheckable( true );
    lockLayout->setChecked( GluonCreator::Settings::lockLayout() );
    connect( lockLayout, SIGNAL( triggered( bool ) ), DockManager::instance(), SLOT( setDocksLocked( bool ) ) );
}

void MainWindow::showPreferences()
{
    if( KConfigDialog::showDialog( "settings" ) )
    {
        return;
    }
    ConfigDialog* dialog = new ConfigDialog( this, "settings", GluonCreator::Settings::self() );
    dialog->setAttribute( Qt::WA_DeleteOnClose );
    dialog->show();
}

void MainWindow::playGame( )
{
    if( GluonEngine::Game::instance()->isRunning() )
    {
        GluonEngine::Game::instance()->setPause( false );
        stateChanged( "paused", StateReverse );
    }
    else
    {
        stateChanged( "playing" );

        d->mainArea->setActiveTab( 0 );

        QString currentSceneName = GluonEngine::Game::instance()->currentScene()->fullyQualifiedName();
        saveProject();

        //Set the focus to the entire window, so that we do not accidentally trigger actions
        setFocus();

        //Start the game loop
        //Note that this starts an infinite loop in Game
        GluonEngine::Game::instance()->runGame();

        //This happens after we exit the game loop
        stateChanged( "playing", StateReverse );

        openProject( d->fileName );
        GluonEngine::Game::instance()->setCurrentScene( currentSceneName );
    }
}

void MainWindow::pauseGame()
{
    GluonEngine::Game::instance()->setPause( true );
    stateChanged( "paused" );
}

void MainWindow::stopGame()
{
    GluonEngine::Game::instance()->stopGame();
}

void MainWindow::historyChanged()
{
    GluonEngine::Game::instance()->drawAll();
    GluonEngine::Game::instance()->currentScene()->savableDirty = true;
    d->modified = true;

    setCaption( i18n( "%1 [modified]", d->fileName.isEmpty() ? i18n( "New Project" ) : d->fileName.section( '/', -1 ) ) );
}

void MainWindow::cleanChanged( bool clean )
{
    if( clean )
    {
        d->modified = false;
        setCaption( i18n( "%1", d->fileName.isEmpty() ? i18n( "New Project" ) : d->fileName.section( '/', -1 ) ) );
    }
}

bool MainWindow::queryClose()
{
    if( d->modified )
    {
        int code = KMessageBox::questionYesNoCancel( this, i18n( "The project has been changed. Do you want to save before closing?" ), i18n( "Save Before Closing?" ),
                   KStandardGuiItem::save(), KStandardGuiItem::dontSave() );

        if( code == KMessageBox::Cancel )
            return false;

        if( code == KMessageBox::No )
            return true;

        saveProject();
        return true;
    }

    return true;
}

void MainWindow::addAsset()
{
    QStringList assets = KFileDialog::getOpenFileNames();

    foreach( const QString & asset, assets )
    {
        ObjectManager::instance()->createNewAsset( asset );
    }
}

void MainWindow::chooseEntryPoint()
{
    if( GluonEngine::Game::instance()->gameProject() )
    {
        if( GluonEngine::Game::instance()->currentScene() )
        {
            GluonEngine::Game::instance()->gameProject()->setEntryPoint( GluonEngine::Game::instance()->currentScene() );
        }
    }
}

void GluonCreator::MainWindow::showNewProjectDialog()
{
    d->projectDialog->setPage( ProjectSelectionDialog::NewProjectPage );
    d->projectDialog->show();
}

void GluonCreator::MainWindow::showOpenProjectDialog()
{
    d->projectDialog->setPage( ProjectSelectionDialog::OpenProjectPage );
    d->projectDialog->show();
}

void GluonCreator::MainWindow::projectDialogClosed()
{
    openProject( d->projectDialog->fileName() );
}

void MainWindow::initializeGame()
{

}
<commit_msg>Call initializeAll() after setCurrentScene, which calls stopAll() and cleanupAll().<commit_after>/******************************************************************************
 * This file is part of the Gluon Development Platform
 * Copyright (c) 2010 Arjen Hiemstra <ahiemstra@heimr.nl>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "mainwindow.h"

#include <QtCore/QVariantList>

#include <KFileDialog>
#include <KStandardAction>
#include <KActionCollection>
#include <KAction>
#include <KStatusBar>
#include <KMessageBox>
#include <KConfigDialog>
#include <KLocalizedString>
#include <KPluginSelector>
#include <KRun>
#include <KRecentFilesAction>
#include <KDE/KTabWidget>
#include <KDE/KToolBar>
#include <KDE/KRichTextEdit>

#include <core/debughelper.h>
#include <engine/game.h>
#include <engine/gameproject.h>
#include <engine/scene.h>

#include "lib/plugin.h"
#include "lib/pluginmanager.h"
#include "lib/objectmanager.h"
#include "lib/historymanager.h"
#include "lib/selectionmanager.h"
#include "lib/dockmanager.h"
#include "lib/filemanager.h"
#include "lib/widgets/filearea.h"

#include "gluoncreatorsettings.h"
#include "dialogs/configdialog.h"
#include <QVBoxLayout>
#include <KParts/PartManager>

using namespace GluonCreator;

class MainWindow::MainWindowPrivate
{
    public:
        MainWindowPrivate()
        {
        }

        bool modified;
        QString fileName;
        KRecentFilesAction* recentFiles;
        ProjectSelectionDialog* projectDialog;

        FileArea* mainArea;
};

MainWindow::MainWindow( const QString& fileName )
    : KParts::MainWindow(),
      d( new MainWindowPrivate )
{
    d->modified = false;

    GluonCore::GluonObjectFactory::instance()->loadPlugins();

    PluginManager::instance()->setParent( this );
    ObjectManager::instance()->setParent( this );
    HistoryManager::instance()->setParent( this );
    SelectionManager::instance()->setParent( this );

    DockManager::instance()->setParent( this );
    DockManager::instance()->setMainWindow( this );

    FileManager::instance()->initialize( this );
    connect( FileManager::instance()->partManager(), SIGNAL( activePartChanged( KParts::Part* ) ), this, SLOT( createGUI( KParts::Part* ) ) );

    PluginManager::instance()->setMainWindow( this );
    PluginManager::instance()->loadPlugins();

    setDockNestingEnabled( true );
    setCorner( Qt::TopLeftCorner, Qt::LeftDockWidgetArea );
    setCorner( Qt::BottomLeftCorner, Qt::LeftDockWidgetArea );
    setCorner( Qt::TopRightCorner, Qt::RightDockWidgetArea );
    setCorner( Qt::BottomRightCorner, Qt::RightDockWidgetArea );

    d->mainArea = new FileArea( this );
    setCentralWidget( d->mainArea );

    setupActions();
    setupGUI();
    stateChanged( "initial" );

    d->projectDialog = new ProjectSelectionDialog( this );
    d->projectDialog->setModal( true );
    connect( d->projectDialog, SIGNAL( accepted() ), SLOT( projectDialogClosed() ) );

    DockManager::instance()->setDocksEnabled( false );
    DockManager::instance()->setDocksLocked( GluonCreator::Settings::lockLayout() );

    if( fileName.isEmpty() )
    {
        showNewProjectDialog();
    }
    else
    {
        openProject( fileName );
    }
}

MainWindow::~MainWindow()
{
    d->recentFiles->saveEntries( KGlobal::config()->group( "Recent Files" ) );
    GluonCreator::Settings::setLockLayout( actionCollection()->action( "lockLayout" )->isChecked() );
    GluonCreator::Settings::self()->writeConfig();
    GluonEngine::Game::instance()->stopGame();
}

void MainWindow::openProject( KUrl url )
{
    openProject( url.path() );
}

void MainWindow::openProject( const QString& fileName )
{
    if( !fileName.isEmpty() && QFile::exists( fileName ) )
    {
        statusBar()->showMessage( i18n( "Opening project..." ) );

        FileManager::instance()->openFile( fileName, i18nc( "View Game Tab", "View" ), "gluon_viewer_part", QVariantList() << QString( "autoplay=false" ) );

        GluonEngine::Game::instance()->initializeAll();
        GluonEngine::Game::instance()->drawAll();

        d->fileName = fileName;
        d->recentFiles->addUrl( KUrl( fileName ) );

        stateChanged( "fileOpened" );
        DockManager::instance()->setDocksEnabled( true );

        if( centralWidget() )
            centralWidget()->setEnabled( true );

        statusBar()->showMessage( i18n( "Project successfully opened" ) );
        setCaption( i18n( "%1 - Gluon Creator", fileName.section( '/', -1 ) ) );
        HistoryManager::instance()->clear();
        connect( HistoryManager::instance(), SIGNAL( historyChanged( const QUndoCommand* ) ), SLOT( historyChanged() ) );
    }
    else
    {
        statusBar()->showMessage( i18n( "Unable to open project file..." ) );
    }
}

void MainWindow::saveProject()
{
    saveProject( d->fileName );
}

void MainWindow::saveProject( const QString& fileName )
{
    if( !fileName.isEmpty() )
    {
        statusBar()->showMessage( i18n( "Saving project..." ) );
        GluonEngine::Game::instance()->gameProject()->setFilename( QUrl( fileName ) );
        QDir::setCurrent( KUrl( fileName ).directory() );
        if( !GluonEngine::Game::instance()->gameProject()->saveToFile() )
        {
            KMessageBox::error( this, i18n( "Could not save file." ) );
            return;
        }
        statusBar()->showMessage( i18n( "Project successfully saved." ) );
        setCaption( i18n( "%1 - Gluon Creator", fileName.section( '/', -1 ) ) );
        HistoryManager::instance()->setClean();

        d->recentFiles->addUrl( KUrl( fileName ) );
    }
    else
    {
        saveProjectAs();
    }
}

void MainWindow::saveProjectAs()
{
    d->fileName = KFileDialog::getSaveFileName( KUrl(), i18n( "*.gluon|Gluon Project Files" ) );
    if( !d->fileName.isEmpty() ) saveProject();
}

void MainWindow::setupActions()
{
    KStandardAction::openNew( this, SLOT( showNewProjectDialog() ), actionCollection() );
    KStandardAction::open( this, SLOT( showOpenProjectDialog() ), actionCollection() );
    KStandardAction::save( this, SLOT( saveProject() ), actionCollection() );
    KStandardAction::saveAs( this, SLOT( saveProjectAs() ), actionCollection() );
    KStandardAction::quit( this, SLOT( close() ), actionCollection() );
    KStandardAction::preferences( this, SLOT( showPreferences() ), actionCollection() );

    KAction* undo = KStandardAction::undo( HistoryManager::instance(), SLOT( undo() ), actionCollection() );
    connect( HistoryManager::instance(), SIGNAL( canUndoChanged( bool ) ), undo, SLOT( setEnabled( bool ) ) );

    KAction* redo = KStandardAction::redo( HistoryManager::instance(), SLOT( redo() ), actionCollection() );
    connect( HistoryManager::instance(), SIGNAL( canRedoChanged( bool ) ), redo, SLOT( setEnabled( bool ) ) );

    connect( HistoryManager::instance(), SIGNAL( cleanChanged( bool ) ), SLOT( cleanChanged( bool ) ) );

    d->recentFiles = KStandardAction::openRecent( this, SLOT( openProject( KUrl ) ), actionCollection() );
    d->recentFiles->loadEntries( KGlobal::config()->group( "Recent Files" ) );

    KAction* newObject = new KAction( KIcon( "document-new" ), i18n( "New Object" ), actionCollection() );
    actionCollection()->addAction( "newObject", newObject );
    connect( newObject, SIGNAL( triggered( bool ) ), ObjectManager::instance(), SLOT( createNewGameObject() ) );

    KAction* newScene = new KAction( KIcon( "document-new" ), i18n( "New Scene" ), actionCollection() );
    actionCollection()->addAction( "newScene", newScene );
    connect( newScene, SIGNAL( triggered( bool ) ), ObjectManager::instance(), SLOT( createNewScene() ) );

    KAction* play = new KAction( KIcon( "media-playback-start" ), i18n( "Play Game" ), actionCollection() );
    actionCollection()->addAction( "playGame", play );
    connect( play, SIGNAL( triggered( bool ) ), SLOT( playGame() ) );

    KAction* pause = new KAction( KIcon( "media-playback-pause" ), i18n( "Pause Game" ), actionCollection() );
    actionCollection()->addAction( "pauseGame", pause );
    connect( pause, SIGNAL( triggered( bool ) ), SLOT( pauseGame() ) );

    KAction* stop = new KAction( KIcon( "media-playback-stop" ), i18n( "Stop Game" ), actionCollection() );
    actionCollection()->addAction( "stopGame", stop );
    connect( stop, SIGNAL( triggered( bool ) ), SLOT( stopGame() ) );

    KAction* addAsset = new KAction( KIcon( "document-new" ), i18n( "Add Assets..." ), actionCollection() );
    actionCollection()->addAction( "addAsset", addAsset );
    connect( addAsset, SIGNAL( triggered( bool ) ), SLOT( addAsset() ) );

    KAction* chooseEntryPoint = new KAction( KIcon( "media-playback-start" ), i18n( "Set current scene as entry point" ), actionCollection() );
    actionCollection()->addAction( "chooseEntryPoint", chooseEntryPoint );
    connect( chooseEntryPoint, SIGNAL( triggered( bool ) ), SLOT( chooseEntryPoint() ) );

    KAction* lockLayout = new KAction( KIcon( "object-locked" ), i18n( "Lock layout" ), actionCollection() );
    actionCollection()->addAction( "lockLayout", lockLayout );
    lockLayout->setCheckable( true );
    lockLayout->setChecked( GluonCreator::Settings::lockLayout() );
    connect( lockLayout, SIGNAL( triggered( bool ) ), DockManager::instance(), SLOT( setDocksLocked( bool ) ) );
}

void MainWindow::showPreferences()
{
    if( KConfigDialog::showDialog( "settings" ) )
    {
        return;
    }
    ConfigDialog* dialog = new ConfigDialog( this, "settings", GluonCreator::Settings::self() );
    dialog->setAttribute( Qt::WA_DeleteOnClose );
    dialog->show();
}

void MainWindow::playGame( )
{
    if( GluonEngine::Game::instance()->isRunning() )
    {
        GluonEngine::Game::instance()->setPause( false );
        stateChanged( "paused", StateReverse );
    }
    else
    {
        stateChanged( "playing" );

        d->mainArea->setActiveTab( 0 );

        QString currentSceneName = GluonEngine::Game::instance()->currentScene()->fullyQualifiedName();
        saveProject();

        //Set the focus to the entire window, so that we do not accidentally trigger actions
        setFocus();

        //Start the game loop
        //Note that this starts an infinite loop in Game
        GluonEngine::Game::instance()->runGame();

        //This happens after we exit the game loop
        stateChanged( "playing", StateReverse );

        openProject( d->fileName );
        GluonEngine::Game::instance()->setCurrentScene( currentSceneName );
        GluonEngine::Game::instance()->initializeAll();
    }
}

void MainWindow::pauseGame()
{
    GluonEngine::Game::instance()->setPause( true );
    stateChanged( "paused" );
}

void MainWindow::stopGame()
{
    GluonEngine::Game::instance()->stopGame();
}

void MainWindow::historyChanged()
{
    GluonEngine::Game::instance()->drawAll();
    GluonEngine::Game::instance()->currentScene()->savableDirty = true;
    d->modified = true;

    setCaption( i18n( "%1 [modified]", d->fileName.isEmpty() ? i18n( "New Project" ) : d->fileName.section( '/', -1 ) ) );
}

void MainWindow::cleanChanged( bool clean )
{
    if( clean )
    {
        d->modified = false;
        setCaption( i18n( "%1", d->fileName.isEmpty() ? i18n( "New Project" ) : d->fileName.section( '/', -1 ) ) );
    }
}

bool MainWindow::queryClose()
{
    if( d->modified )
    {
        int code = KMessageBox::questionYesNoCancel( this, i18n( "The project has been changed. Do you want to save before closing?" ), i18n( "Save Before Closing?" ),
                   KStandardGuiItem::save(), KStandardGuiItem::dontSave() );

        if( code == KMessageBox::Cancel )
            return false;

        if( code == KMessageBox::No )
            return true;

        saveProject();
        return true;
    }

    return true;
}

void MainWindow::addAsset()
{
    QStringList assets = KFileDialog::getOpenFileNames();

    foreach( const QString & asset, assets )
    {
        ObjectManager::instance()->createNewAsset( asset );
    }
}

void MainWindow::chooseEntryPoint()
{
    if( GluonEngine::Game::instance()->gameProject() )
    {
        if( GluonEngine::Game::instance()->currentScene() )
        {
            GluonEngine::Game::instance()->gameProject()->setEntryPoint( GluonEngine::Game::instance()->currentScene() );
        }
    }
}

void GluonCreator::MainWindow::showNewProjectDialog()
{
    d->projectDialog->setPage( ProjectSelectionDialog::NewProjectPage );
    d->projectDialog->show();
}

void GluonCreator::MainWindow::showOpenProjectDialog()
{
    d->projectDialog->setPage( ProjectSelectionDialog::OpenProjectPage );
    d->projectDialog->show();
}

void GluonCreator::MainWindow::projectDialogClosed()
{
    openProject( d->projectDialog->fileName() );
}

void MainWindow::initializeGame()
{

}
<|endoftext|>


<commit_before>// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id: dockWidget.C,v 1.4 2003/09/09 23:23:22 amoll Exp $

#include <BALL/VIEW/WIDGETS/dockWidget.h>
#include <BALL/VIEW/KERNEL/mainControl.h>
#include <qmenubar.h>
#include <qlabel.h>

using std::endl;

namespace BALL
{
	namespace VIEW
	{

DockWidget::DockWidget(QWidget* parent, const char* name)
: QDockWindow(QDockWindow::InDock, parent),
	ModularWidget(name)
{
	layout_ = new QVBoxLayout(this);
  caption_label_ = new QLabel(this, "caption_label");
	caption_label_->resize(120, 12);
  caption_label_->setSizePolicy( QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed, 0, 0, false));
  caption_label_->setPaletteBackgroundColor( QColor( 255, 255, 127 ) );
  QFont caption_label_font(caption_label_->font());
  caption_label_font.setFamily( "Helvetica" );
  caption_label_font.setPointSize( 11 );
  caption_label_->setFont( caption_label_font );
  caption_label_->setFrameShape(QLabel::NoFrame);
  caption_label_->setAlignment(QLabel::AlignCenter);
	layout_->addWidget(caption_label_);
	boxLayout()->addItem(layout_);

	setOrientation(Qt::Vertical);
  resize( QSize(132, 293));

	if (name != 0)
	{
		setCaption(name);
		setName(name);
		caption_label_->setText(name);
	}
	else
	{
		setName("DockWidget");
	}

	registerWidget(this);
}

void DockWidget::setGuest(QWidget& guest)
{
	QPoint p;
	guest.reparent(this, p, true);
	guest.resize(120,1000);
  guest.setSizePolicy( QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding, 0, 0, false));
	layout_->addWidget(&guest);
	setMinimumSize(20, 20);
	setCloseMode(QDockWindow::Always);
	setResizeEnabled(true);
}

void DockWidget::initializeWidget(MainControl& main_control)
	throw()
{
	window_menu_entry_id_ =
		main_control.insertMenuEntry(MainControl::WINDOWS, getIdentifier(), this, SLOT(switchShowWidget()));
	getMainControl()->menuBar()->setItemChecked(window_menu_entry_id_, true);
}

void DockWidget::finalizeWidget(MainControl& main_control)
	throw()
{
	main_control.removeMenuEntry(MainControl::WINDOWS, getIdentifier(), this, SLOT(switchShowWidget()));
}

void DockWidget::switchShowWidget()
	throw()
{
	QMenuBar* menu = getMainControl()->menuBar();
	if (menu->isItemChecked(window_menu_entry_id_))
	{
		hide();
		menu->setItemChecked(window_menu_entry_id_, false);
	}
	else
	{
		show();
		menu->setItemChecked(window_menu_entry_id_, true);
	}
}

void DockWidget::writePreferences(INIFile& inifile)
	throw()
{
	inifile.insertValue("WINDOWS", getIdentifier() + "::on",
		String(getMainControl()->menuBar()->isItemChecked(window_menu_entry_id_)));
}

void DockWidget::fetchPreferences(INIFile & inifile)
	throw()
{
	if (!inifile.hasEntry("WINDOWS", getIdentifier() + "::on")) return;
	if (inifile.getValue( "WINDOWS", getIdentifier() + "::on").toUnsignedInt() == 0)
	{
		switchShowWidget();
	}
}

void DockWidget::close()
{
Log.error() << "#~~#   1" << std::endl;
	QDockWindow::close();
}

} } // namespaces
<commit_msg>no message<commit_after>// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id: dockWidget.C,v 1.5 2003/09/10 01:27:49 amoll Exp $

#include <BALL/VIEW/WIDGETS/dockWidget.h>
#include <BALL/VIEW/KERNEL/mainControl.h>
#include <qmenubar.h>
#include <qlabel.h>

using std::endl;

namespace BALL
{
	namespace VIEW
	{

DockWidget::DockWidget(QWidget* parent, const char* name)
: QDockWindow(QDockWindow::InDock, parent),
	ModularWidget(name),
	default_visible_(true)
{
	layout_ = new QVBoxLayout(this);
  caption_label_ = new QLabel(this, "caption_label");
	caption_label_->resize(120, 12);
  caption_label_->setSizePolicy( QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed, 0, 0, false));
  caption_label_->setPaletteBackgroundColor( QColor( 255, 255, 127 ) );
  QFont caption_label_font(caption_label_->font());
  caption_label_font.setFamily( "Helvetica" );
  caption_label_font.setPointSize( 11 );
  caption_label_->setFont( caption_label_font );
  caption_label_->setFrameShape(QLabel::NoFrame);
  caption_label_->setAlignment(QLabel::AlignCenter);
	layout_->addWidget(caption_label_);
	boxLayout()->addItem(layout_);

	setOrientation(Qt::Vertical);
  resize( QSize(132, 293));

	if (name != 0)
	{
		setCaption(name);
		setName(name);
		caption_label_->setText(name);
	}
	else
	{
		setName("DockWidget");
	}

	registerWidget(this);
}

void DockWidget::setGuest(QWidget& guest)
{
	QPoint p;
	guest.reparent(this, p, true);
	guest.resize(120,1000);
  guest.setSizePolicy( QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding, 0, 0, false));
	layout_->addWidget(&guest);
	setMinimumSize(20, 20);
	setCloseMode(QDockWindow::Always);
	setResizeEnabled(true);
}

void DockWidget::initializeWidget(MainControl& main_control)
	throw()
{
	window_menu_entry_id_ =
		main_control.insertMenuEntry(MainControl::WINDOWS, getIdentifier(), this, SLOT(switchShowWidget()));
	getMainControl()->menuBar()->setItemChecked(window_menu_entry_id_, true);
}

void DockWidget::finalizeWidget(MainControl& main_control)
	throw()
{
	main_control.removeMenuEntry(MainControl::WINDOWS, getIdentifier(), this, SLOT(switchShowWidget()));
}

void DockWidget::switchShowWidget()
	throw()
{
	QMenuBar* menu = getMainControl()->menuBar();
	if (menu->isItemChecked(window_menu_entry_id_))
	{
		hide();
		menu->setItemChecked(window_menu_entry_id_, false);
	}
	else
	{
		show();
		menu->setItemChecked(window_menu_entry_id_, true);
	}
}

void DockWidget::writePreferences(INIFile& inifile)
	throw()
{
	inifile.insertValue("WINDOWS", getIdentifier() + "::on",
		String(getMainControl()->menuBar()->isItemChecked(window_menu_entry_id_)));

	inifile.insertValue("WINDOWS", getIdentifier() + "::x", String(x()));
	inifile.insertValue("WINDOWS", getIdentifier() + "::y", String(y()));
	inifile.insertValue("WINDOWS", getIdentifier() + "::width", String(width()));
	inifile.insertValue("WINDOWS", getIdentifier() + "::height", String(height()));

	inifile.insertValue("WINDOWS", getIdentifier() + "::docked", String(place()));
}

void DockWidget::fetchPreferences(INIFile & inifile)
	throw()
{
	if (	 (inifile.hasEntry("WINDOWS", getIdentifier() + "::on") &&
				  inifile.getValue("WINDOWS", getIdentifier() + "::on").toUnsignedInt() == 0)
		  || (!default_visible_))
	{
		switchShowWidget();
	}

	if (inifile.hasEntry("WINDOWS", getIdentifier() + "::x"))
	{
		setGeometry(inifile.getValue("WINDOWS", getIdentifier() + "::x").toUnsignedInt(),
		            inifile.getValue("WINDOWS", getIdentifier() + "::y").toUnsignedInt(),
		            inifile.getValue("WINDOWS", getIdentifier() + "::width").toUnsignedInt(),
		            inifile.getValue("WINDOWS", getIdentifier() + "::height").toUnsignedInt());
	}

	if (inifile.hasEntry("WINDOWS", getIdentifier() + "::docked") &&
			inifile.getValue("WINDOWS", getIdentifier() + "::docked").toUnsignedInt() != 0)
	{
		undock();
	}
}

} } // namespaces
<|endoftext|>


<commit_before>/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * OpenDmxThread.h
 * Thread for the open dmx device
 * Copyright (C) 2005-2007  Simon Newton
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <time.h>

#include <llad/logger.h>
#include "OpenDmxThread.h"

namespace lla {
namespace plugin {

using std::string;

typedef struct {
  OpenDmxThread *th;
  string path;
} t_args;

void *thread_run(void *d) {
  t_args *args = (t_args*) d;

  args->th->Run(args->path);
  free(args);
}

/*
 * Create a new OpenDmxThread object
 *
 */
OpenDmxThread::OpenDmxThread() {
  m_fd = -1;
  memset(m_dmx, 0x00, DMX_UNIVERSE_SIZE);
  pthread_mutex_init(&m_mutex, NULL);
  m_term = false;
  pthread_mutex_init(&m_term_mutex, NULL);
  pthread_cond_init(&m_term_cond, NULL);

  m_tid = 0;
}

/*
 *
 */
OpenDmxThread::~OpenDmxThread() {
  pthread_cond_destroy(&m_term_cond);
  pthread_mutex_destroy(&m_term_mutex);
  pthread_mutex_destroy(&m_mutex);
}

/*
 * run this thread
 *
 */
void *OpenDmxThread::Run(const string &path) {
  uint8_t buf[DMX_UNIVERSE_SIZE+1];
  struct timeval tv;
  struct timespec ts;

  // should close other fd here

  // start code
  buf[0] = 0x00;
  m_fd = open(path.c_str(), O_WRONLY);

  while (1) {
    pthread_mutex_lock(&m_term_mutex);
    if (m_term) {
      pthread_mutex_unlock(&m_term_mutex);
      break;
    }
    pthread_mutex_unlock(&m_term_mutex);

    if (m_fd == -1) {
      if (gettimeofday(&tv, NULL) < 0) {
        printf("gettimeofday error\n");
        break;
      }
      ts.tv_sec = tv.tv_sec + 1;
      ts.tv_nsec = tv.tv_usec * 1000;

      pthread_cond_timedwait(&m_term_cond, &m_term_mutex, &ts);
      pthread_mutex_unlock(&m_term_mutex);

      m_fd = open(path.c_str(), O_WRONLY);

      if (m_fd == -1)
        printf("open %d: %s\n", m_fd, strerror(errno));

    } else {
      pthread_mutex_lock(&m_mutex);
      memcpy(&buf[1], m_dmx, DMX_UNIVERSE_SIZE);
      pthread_mutex_unlock(&m_mutex);

      do_write(buf, DMX_UNIVERSE_SIZE + 1);
    }
  }
  return NULL;
}

/*
 * Start this thread
 *
 */
int OpenDmxThread::Start(const string &path) {
  // this is passed to the thread and free'ed there
  t_args *args = (t_args*) malloc(sizeof(t_args));

  args->th = this;
  args->path = path;

  if (pthread_create(&m_tid, NULL, lla::plugin::thread_run, (void*) args)) {
    Logger::instance()->log(Logger::WARN, "pthread create failed");
    return -1;
  }
  return 0;
}

/*
 * Stop the thread
 *
 */
int OpenDmxThread::Stop() {
  pthread_mutex_lock(&m_term_mutex);
  m_term = true;
  pthread_mutex_unlock(&m_term_mutex);

  pthread_cond_signal(&m_term_cond);
  pthread_join(m_tid, NULL);
}

/*
 * Store the data in the shared buffer
 *
 */
int OpenDmxThread::WriteDmx(uint8_t *data, int length) {
  pthread_mutex_lock(&m_mutex);
  memcpy(m_dmx, data, length);
  pthread_mutex_unlock(&m_mutex);
}

int OpenDmxThread::do_write(uint8_t *buf, int length) {
  int res = write(m_fd, buf, length);

  if (res < 0) {
    // if you unplug devices from the dongle
    perror("Error writing to device");

    res = close(m_fd);
    if (res < 0)
      perror("close");
    else
      m_fd = -1;

    return -1;
  }
  return 0;
}

} // plugin
} // lla
<commit_msg> * fix a bug in the OpenDmx plugin - thanks Christopher Staite<commit_after>/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * OpenDmxThread.h
 * Thread for the open dmx device
 * Copyright (C) 2005-2007  Simon Newton
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <time.h>

#include <llad/logger.h>
#include "OpenDmxThread.h"

namespace lla {
namespace plugin {

using std::string;

typedef struct {
  OpenDmxThread *th;
  string path;
} t_args;

void *thread_run(void *d) {
  t_args *args = (t_args*) d;

  args->th->Run(args->path);
  delete args;
}

/*
 * Create a new OpenDmxThread object
 *
 */
OpenDmxThread::OpenDmxThread() {
  m_fd = -1;
  memset(m_dmx, 0x00, DMX_UNIVERSE_SIZE);
  pthread_mutex_init(&m_mutex, NULL);
  m_term = false;
  pthread_mutex_init(&m_term_mutex, NULL);
  pthread_cond_init(&m_term_cond, NULL);

  m_tid = 0;
}

/*
 *
 */
OpenDmxThread::~OpenDmxThread() {
  pthread_cond_destroy(&m_term_cond);
  pthread_mutex_destroy(&m_term_mutex);
  pthread_mutex_destroy(&m_mutex);
}

/*
 * run this thread
 *
 */
void *OpenDmxThread::Run(const string &path) {
  uint8_t buf[DMX_UNIVERSE_SIZE+1];
  struct timeval tv;
  struct timespec ts;

  // should close other fd here

  // start code
  buf[0] = 0x00;
  m_fd = open(path.c_str(), O_WRONLY);

  while (1) {
    pthread_mutex_lock(&m_term_mutex);
    if (m_term) {
      pthread_mutex_unlock(&m_term_mutex);
      break;
    }
    pthread_mutex_unlock(&m_term_mutex);

    if (m_fd == -1) {
      if (gettimeofday(&tv, NULL) < 0) {
        printf("gettimeofday error\n");
        break;
      }
      ts.tv_sec = tv.tv_sec + 1;
      ts.tv_nsec = tv.tv_usec * 1000;

      pthread_cond_timedwait(&m_term_cond, &m_term_mutex, &ts);
      pthread_mutex_unlock(&m_term_mutex);

      m_fd = open(path.c_str(), O_WRONLY);

      if (m_fd == -1)
        printf("open %d: %s\n", m_fd, strerror(errno));

    } else {
      pthread_mutex_lock(&m_mutex);
      memcpy(&buf[1], m_dmx, DMX_UNIVERSE_SIZE);
      pthread_mutex_unlock(&m_mutex);

      do_write(buf, DMX_UNIVERSE_SIZE + 1);
    }
  }
  return NULL;
}

/*
 * Start this thread
 *
 */
int OpenDmxThread::Start(const string &path) {
  // this is passed to the thread and free'ed there
  t_args *args = new t_args;

  args->th = this;
  args->path = path;

  if (pthread_create(&m_tid, NULL, lla::plugin::thread_run, (void*) args)) {
    Logger::instance()->log(Logger::WARN, "pthread create failed");
    return -1;
  }
  return 0;
}

/*
 * Stop the thread
 *
 */
int OpenDmxThread::Stop() {
  pthread_mutex_lock(&m_term_mutex);
  m_term = true;
  pthread_mutex_unlock(&m_term_mutex);

  pthread_cond_signal(&m_term_cond);
  pthread_join(m_tid, NULL);
}

/*
 * Store the data in the shared buffer
 *
 */
int OpenDmxThread::WriteDmx(uint8_t *data, int length) {
  pthread_mutex_lock(&m_mutex);
  memcpy(m_dmx, data, length);
  pthread_mutex_unlock(&m_mutex);
}

int OpenDmxThread::do_write(uint8_t *buf, int length) {
  int res = write(m_fd, buf, length);

  if (res < 0) {
    // if you unplug devices from the dongle
    perror("Error writing to device");

    res = close(m_fd);
    if (res < 0)
      perror("close");
    else
      m_fd = -1;

    return -1;
  }
  return 0;
}

} // plugin
} // lla
<|endoftext|>


<commit_before><commit_msg>Small fix for krystal scene (removed DebugFrameRender).<commit_after><|endoftext|>


<commit_before>//
// PROJECT:         Aspia Remote Desktop
// FILE:            desktop_capture/differ.cc
// LICENSE:         Mozilla Public License Version 2.0
// PROGRAMMERS:     Dmitry Chapyshev (dmitry@aspia.ru)
//

#include "desktop_capture/differ.h"

#include "desktop_capture/diff_block_sse2.h"

namespace aspia {

static const int kBytesPerPixel = 4;
static const int kBlockSize = 16;
static const int kBytesPerBlock = kBytesPerPixel * kBlockSize;

static INLINE uint8_t DiffFullBlock_C(const uint8_t* image1,
                                      const uint8_t* image2,
                                      int bytes_per_row)
{
    for (int y = 0; y < kBlockSize; ++y)
    {
        if (memcmp(image1, image2, kBytesPerBlock) != 0)
        {
            return 1U;
        }

        image1 += bytes_per_row;
        image2 += bytes_per_row;
    }

    return 0U;
}

//
// Check for diffs in upper-left portion of the block. The size of the portion
// to check is specified by the |width| and |height| values.
// Note that if we force the capturer to always return images whose width and
// height are multiples of kBlockSize, then this will never be called.
//
static INLINE uint8_t DiffPartialBlock(const uint8_t* prev_image,
                                       const uint8_t* curr_image,
                                       int bytes_per_row,
                                       int bytes_per_block,
                                       int height)
{
    for (int y = 0; y < height; ++y)
    {
        if (memcmp(prev_image, curr_image, bytes_per_block) != 0)
        {
            return 1U;
        }

        prev_image += bytes_per_row;
        curr_image += bytes_per_row;
    }

    return 0U;
}

Differ::Differ(const DesktopSize& size)
    : size_(size),
      bytes_per_row_(size.Width() * kBytesPerPixel),
      diff_width_(((size.Width() + kBlockSize - 1) / kBlockSize) + 1),
      diff_height_(((size.Height() + kBlockSize - 1) / kBlockSize) + 1),
      full_blocks_x_(size.Width() / kBlockSize),
      full_blocks_y_(size.Height() / kBlockSize)
{
    const int diff_info_size = diff_width_ * diff_height_;

    diff_info_ = std::make_unique<uint8_t[]>(diff_info_size);
    memset(diff_info_.get(), 0, diff_info_size);

    // Calc size of partial blocks which may be present on right and bottom
    // edge.
    partial_column_width_ = size.Width() - (full_blocks_x_ * kBlockSize);
    partial_row_height_ = size.Height() - (full_blocks_y_ * kBlockSize);

    // Offset from the start of one block-row to the next.
    block_stride_y_ = bytes_per_row_ * kBlockSize;
}

//
// Identify all of the blocks that contain changed pixels.
//
void Differ::MarkDirtyBlocks(const uint8_t* prev_image, const uint8_t* curr_image)
{
    const uint8_t* prev_block_row_start = prev_image;
    const uint8_t* curr_block_row_start = curr_image;

    // Offset from the start of one diff_info row to the next.
    const int diff_stride = diff_width_;

    uint8_t* is_diff_row_start = diff_info_.get();

    for (int y = 0; y < full_blocks_y_; ++y)
    {
        const uint8_t* prev_block = prev_block_row_start;
        const uint8_t* curr_block = curr_block_row_start;

        uint8_t* is_different = is_diff_row_start;

        for (int x = 0; x < full_blocks_x_; ++x)
        {
            // For x86 and x86_64, we do not support processors that do not
            // have SSE2 instructions support.
            if (kBlockSize == 16)
            {
                // Mark this block as being modified so that it gets
                // incorporated into a dirty rect.
                *is_different = DiffFullBlock_16x16_SSE2(prev_block,
                                                         curr_block,
                                                         bytes_per_row_);
            }
            else if (kBlockSize == 32)
            {
                // Mark this block as being modified so that it gets
                // incorporated into a dirty rect.
                *is_different = DiffFullBlock_32x32_SSE2(prev_block,
                                                         curr_block,
                                                         bytes_per_row_);
            }

            prev_block += kBytesPerBlock;
            curr_block += kBytesPerBlock;

            ++is_different;
        }

        //
        // If there is a partial column at the end, handle it.
        // This condition should rarely, if ever, occur.
        //
        if (partial_column_width_ != 0)
        {
            *is_different = DiffPartialBlock(prev_block,
                                             curr_block,
                                             bytes_per_row_,
                                             kBytesPerBlock,
                                             kBlockSize);

            ++is_different;
        }

        // Update pointers for next row.
        prev_block_row_start += block_stride_y_;
        curr_block_row_start += block_stride_y_;

        is_diff_row_start += diff_stride;
    }

    // If the screen height is not a multiple of the block size, then this
    // handles the last partial row. This situation is far more common than
    // the 'partial column' case.
    if (partial_row_height_ != 0)
    {
        const uint8_t* prev_block = prev_block_row_start;
        const uint8_t* curr_block = curr_block_row_start;

        uint8_t* is_different = is_diff_row_start;

        for (int x = 0; x < full_blocks_x_; ++x)
        {
            *is_different = DiffPartialBlock(prev_block,
                                             curr_block,
                                             bytes_per_row_,
                                             kBytesPerBlock,
                                             partial_row_height_);

            prev_block += kBytesPerBlock;
            curr_block += kBytesPerBlock;
            ++is_different;
        }

        if (partial_column_width_ != 0)
        {
            *is_different =
                DiffPartialBlock(prev_block,
                                 curr_block,
                                 bytes_per_row_,
                                 partial_column_width_ * kBytesPerPixel,
                                 partial_row_height_);
        }
    }
}

//
// After the dirty blocks have been identified, this routine merges adjacent
// blocks into a region.
// The goal is to minimize the region that covers the dirty blocks.
//
void Differ::MergeBlocks(DesktopRegion* dirty_region)
{
    uint8_t* is_diff_row_start = diff_info_.get();
    const int diff_stride = diff_width_;

    for (int y = 0; y < diff_height_; ++y)
    {
        uint8_t* is_different = is_diff_row_start;

        for (int x = 0; x < diff_width_; ++x)
        {
            // We've found a modified block. Look at blocks to the right and
            // below to group this block with as many others as we can.
            if (*is_different != 0)
            {
                // Width and height of the rectangle in blocks.
                int width  = 1;
                int height = 1;

                *is_different = 0;

                // Group with blocks to the right.
                // We can keep looking until we find an unchanged block because
                // we have a boundary block which is never marked as having
                // diffs.
                uint8_t* right = is_different + 1;

                while (*right != 0)
                {
                    *right++ = 0;
                    ++width;
                }

                // Group with blocks below.
                // The entire width of blocks that we matched above much match
                // for each row that we add.
                uint8_t* bottom = is_different;
                bool found_new_row;

                do
                {
                    found_new_row = true;
                    bottom += diff_stride;
                    right = bottom;

                    for (int x2 = 0; x2 < width; ++x2)
                    {
                        if (*right++ == 0)
                            found_new_row = false;
                    }

                    if (found_new_row)
                    {
                        ++height;

                        // We need to go back and erase the diff markers so
                        // that we don't try to add these blocks a second time.
                        right = bottom;

                        for (int x2 = 0; x2 < width; ++x2)
                        {
                            *right++ = 0;
                        }
                    }
                } while (found_new_row);

                int32_t l = x * kBlockSize;
                int32_t t = y * kBlockSize;
                int32_t r = l + (width * kBlockSize);
                int32_t b = t + (height * kBlockSize);

                if (r > size_.Width())
                    r = size_.Width();

                if (b > size_.Height())
                    b = size_.Height();

                // Add rect to region.
                dirty_region->AddRect(DesktopRect::MakeLTRB(l, t, r, b));
            }

            // Increment to next block in this row.
            ++is_different;
        }

        // Go to start of next row.
        is_diff_row_start += diff_stride;
    }
}

void Differ::CalcDirtyRegion(const uint8_t* prev_image,
                             const uint8_t* curr_image,
                             DesktopRegion* dirty_region)
{
    dirty_region->Clear();

    // Identify all the blocks that contain changed pixels.
    MarkDirtyBlocks(prev_image, curr_image);

    //
    // Now that we've identified the blocks that have changed, merge adjacent
    // blocks to minimize the number of rects that we return.
    //
    MergeBlocks(dirty_region);
}

} // namespace aspia
<commit_msg>- Remove unneeded increment<commit_after>//
// PROJECT:         Aspia Remote Desktop
// FILE:            desktop_capture/differ.cc
// LICENSE:         Mozilla Public License Version 2.0
// PROGRAMMERS:     Dmitry Chapyshev (dmitry@aspia.ru)
//

#include "desktop_capture/differ.h"

#include "desktop_capture/diff_block_sse2.h"

namespace aspia {

static const int kBytesPerPixel = 4;
static const int kBlockSize = 16;
static const int kBytesPerBlock = kBytesPerPixel * kBlockSize;

static INLINE uint8_t DiffFullBlock_C(const uint8_t* image1,
                                      const uint8_t* image2,
                                      int bytes_per_row)
{
    for (int y = 0; y < kBlockSize; ++y)
    {
        if (memcmp(image1, image2, kBytesPerBlock) != 0)
        {
            return 1U;
        }

        image1 += bytes_per_row;
        image2 += bytes_per_row;
    }

    return 0U;
}

//
// Check for diffs in upper-left portion of the block. The size of the portion
// to check is specified by the |width| and |height| values.
// Note that if we force the capturer to always return images whose width and
// height are multiples of kBlockSize, then this will never be called.
//
static INLINE uint8_t DiffPartialBlock(const uint8_t* prev_image,
                                       const uint8_t* curr_image,
                                       int bytes_per_row,
                                       int bytes_per_block,
                                       int height)
{
    for (int y = 0; y < height; ++y)
    {
        if (memcmp(prev_image, curr_image, bytes_per_block) != 0)
        {
            return 1U;
        }

        prev_image += bytes_per_row;
        curr_image += bytes_per_row;
    }

    return 0U;
}

Differ::Differ(const DesktopSize& size)
    : size_(size),
      bytes_per_row_(size.Width() * kBytesPerPixel),
      diff_width_(((size.Width() + kBlockSize - 1) / kBlockSize) + 1),
      diff_height_(((size.Height() + kBlockSize - 1) / kBlockSize) + 1),
      full_blocks_x_(size.Width() / kBlockSize),
      full_blocks_y_(size.Height() / kBlockSize)
{
    const int diff_info_size = diff_width_ * diff_height_;

    diff_info_ = std::make_unique<uint8_t[]>(diff_info_size);
    memset(diff_info_.get(), 0, diff_info_size);

    // Calc size of partial blocks which may be present on right and bottom
    // edge.
    partial_column_width_ = size.Width() - (full_blocks_x_ * kBlockSize);
    partial_row_height_ = size.Height() - (full_blocks_y_ * kBlockSize);

    // Offset from the start of one block-row to the next.
    block_stride_y_ = bytes_per_row_ * kBlockSize;
}

//
// Identify all of the blocks that contain changed pixels.
//
void Differ::MarkDirtyBlocks(const uint8_t* prev_image, const uint8_t* curr_image)
{
    const uint8_t* prev_block_row_start = prev_image;
    const uint8_t* curr_block_row_start = curr_image;

    // Offset from the start of one diff_info row to the next.
    const int diff_stride = diff_width_;

    uint8_t* is_diff_row_start = diff_info_.get();

    for (int y = 0; y < full_blocks_y_; ++y)
    {
        const uint8_t* prev_block = prev_block_row_start;
        const uint8_t* curr_block = curr_block_row_start;

        uint8_t* is_different = is_diff_row_start;

        for (int x = 0; x < full_blocks_x_; ++x)
        {
            // For x86 and x86_64, we do not support processors that do not
            // have SSE2 instructions support.
            if (kBlockSize == 16)
            {
                // Mark this block as being modified so that it gets
                // incorporated into a dirty rect.
                *is_different = DiffFullBlock_16x16_SSE2(prev_block,
                                                         curr_block,
                                                         bytes_per_row_);
            }
            else if (kBlockSize == 32)
            {
                // Mark this block as being modified so that it gets
                // incorporated into a dirty rect.
                *is_different = DiffFullBlock_32x32_SSE2(prev_block,
                                                         curr_block,
                                                         bytes_per_row_);
            }

            prev_block += kBytesPerBlock;
            curr_block += kBytesPerBlock;

            ++is_different;
        }

        // If there is a partial column at the end, handle it.
        // This condition should rarely, if ever, occur.
        if (partial_column_width_ != 0)
        {
            *is_different = DiffPartialBlock(prev_block,
                                             curr_block,
                                             bytes_per_row_,
                                             kBytesPerBlock,
                                             kBlockSize);
        }

        // Update pointers for next row.
        prev_block_row_start += block_stride_y_;
        curr_block_row_start += block_stride_y_;

        is_diff_row_start += diff_stride;
    }

    // If the screen height is not a multiple of the block size, then this
    // handles the last partial row. This situation is far more common than
    // the 'partial column' case.
    if (partial_row_height_ != 0)
    {
        const uint8_t* prev_block = prev_block_row_start;
        const uint8_t* curr_block = curr_block_row_start;

        uint8_t* is_different = is_diff_row_start;

        for (int x = 0; x < full_blocks_x_; ++x)
        {
            *is_different = DiffPartialBlock(prev_block,
                                             curr_block,
                                             bytes_per_row_,
                                             kBytesPerBlock,
                                             partial_row_height_);

            prev_block += kBytesPerBlock;
            curr_block += kBytesPerBlock;
            ++is_different;
        }

        if (partial_column_width_ != 0)
        {
            *is_different =
                DiffPartialBlock(prev_block,
                                 curr_block,
                                 bytes_per_row_,
                                 partial_column_width_ * kBytesPerPixel,
                                 partial_row_height_);
        }
    }
}

//
// After the dirty blocks have been identified, this routine merges adjacent
// blocks into a region.
// The goal is to minimize the region that covers the dirty blocks.
//
void Differ::MergeBlocks(DesktopRegion* dirty_region)
{
    uint8_t* is_diff_row_start = diff_info_.get();
    const int diff_stride = diff_width_;

    for (int y = 0; y < diff_height_; ++y)
    {
        uint8_t* is_different = is_diff_row_start;

        for (int x = 0; x < diff_width_; ++x)
        {
            // We've found a modified block. Look at blocks to the right and
            // below to group this block with as many others as we can.
            if (*is_different != 0)
            {
                // Width and height of the rectangle in blocks.
                int width  = 1;
                int height = 1;

                *is_different = 0;

                // Group with blocks to the right.
                // We can keep looking until we find an unchanged block because
                // we have a boundary block which is never marked as having
                // diffs.
                uint8_t* right = is_different + 1;

                while (*right != 0)
                {
                    *right++ = 0;
                    ++width;
                }

                // Group with blocks below.
                // The entire width of blocks that we matched above much match
                // for each row that we add.
                uint8_t* bottom = is_different;
                bool found_new_row;

                do
                {
                    found_new_row = true;
                    bottom += diff_stride;
                    right = bottom;

                    for (int x2 = 0; x2 < width; ++x2)
                    {
                        if (*right++ == 0)
                            found_new_row = false;
                    }

                    if (found_new_row)
                    {
                        ++height;

                        // We need to go back and erase the diff markers so
                        // that we don't try to add these blocks a second time.
                        right = bottom;

                        for (int x2 = 0; x2 < width; ++x2)
                        {
                            *right++ = 0;
                        }
                    }
                } while (found_new_row);

                int32_t l = x * kBlockSize;
                int32_t t = y * kBlockSize;
                int32_t r = l + (width * kBlockSize);
                int32_t b = t + (height * kBlockSize);

                if (r > size_.Width())
                    r = size_.Width();

                if (b > size_.Height())
                    b = size_.Height();

                // Add rect to region.
                dirty_region->AddRect(DesktopRect::MakeLTRB(l, t, r, b));
            }

            // Increment to next block in this row.
            ++is_different;
        }

        // Go to start of next row.
        is_diff_row_start += diff_stride;
    }
}

void Differ::CalcDirtyRegion(const uint8_t* prev_image,
                             const uint8_t* curr_image,
                             DesktopRegion* dirty_region)
{
    dirty_region->Clear();

    // Identify all the blocks that contain changed pixels.
    MarkDirtyBlocks(prev_image, curr_image);

    //
    // Now that we've identified the blocks that have changed, merge adjacent
    // blocks to minimize the number of rects that we return.
    //
    MergeBlocks(dirty_region);
}

} // namespace aspia
<|endoftext|>


<commit_before>//
//  CalcCoordinator.cpp

#include "CalcCoordinator.h"

CalcCoordinator::CalcCoordinator(OutputResult::OutputType out_t, std::string resultFileName) : outFileName(resultFileName), outputMutex(new boost::mutex()), calcValuesMutex(new boost::mutex()), calcInfo(new vector<CalcInfo>()), outResults(new OutputResult(out_t, resultFileName)) {

}

CalcCoordinator::~CalcCoordinator() {

}

void CalcCoordinator::RunCalculations() {
	int numberOfThreads = thread::hardware_concurrency();

	for (int i = 0; i < numberOfThreads; i++) {
		CalcThread calcThread(i, calcInfo, calcValuesMutex, outputMutex, outResults);
		calcThreads.push_back(thread(calcThread));
	}

	while (calcThreads.size() > 0) {
		calcThreads[calcThreads.size() - 1].join();
		calcThreads.pop_back();
	}
}

void CalcCoordinator::AddCalculation(const Detector &det, Detector::CalcType cType, double fpPerHour, double beta, int uncertLoops) {
	calcInfo->push_back(CalcInfo(det, cType, fpPerHour, beta, uncertLoops));
}

void CalcCoordinator::AddFixedCalculation(const Detector &det, Detector::CalcType cType, double fpPerHour, double beta, double intTime, int uncertLoops) {
	CalcInfo tmp(det, cType, fpPerHour, beta, uncertLoops);
	tmp.FixIntegrationTime(intTime);
	calcInfo->push_back(tmp);
}

void CalcCoordinator::AddPlotCalculation(const Detector &det, Detector::CalcType cType, double fpPerHour, double beta, double start_time, double stop_time, unsigned int steps) {
	CalcInfo tmp(det, cType, fpPerHour, beta, 0);
	tmp.SetPlotDetails(start_time, stop_time, steps);
	calcInfo->push_back(tmp);
}

CalcThread::CalcThread(int threadId, boost::shared_ptr<vector<CalcInfo>> calcValues, boost::shared_ptr<boost::mutex> calcValuesMutex, boost::shared_ptr<boost::mutex> outputMutex, boost::shared_ptr<OutputResult> outResults) : calcValues(calcValues), calcValuesMutex(calcValuesMutex), threadId(threadId), outputMutex(outputMutex), outResults(outResults) {

}

void CalcThread::operator()() {
	CalcInfo tmpInfo;
	while (true) {
		{
			boost::mutex::scoped_lock lock(*calcValuesMutex.get());
			if (calcValues->size() == 0) {
				break;
			}
			tmpInfo = calcValues->at(calcValues->size() - 1);
			calcValues->pop_back();
			PRINT_T(std::string("CalcThread(): Thread starts work on new job. ") + lexical_cast<std::string>(calcValues->size()) + std::string(" jobs are still queued up."));
		}
		if (tmpInfo.plotCalc) {
			CalcTimeVsActData(tmpInfo);
		} else {
			CalcTimeAndAct(tmpInfo);
		}
	}
}

int CalcThread::CalcTimeVsActData(CalcInfo &info) {
	std::vector<std::pair<double, double>> timeActVec;
	std::vector<double> clTime;
	std::vector<unsigned int> clValue;

	PRINT_T(std::string("CalcThread::CalcTimeVsActData(): Locating minimas between ") + lexical_cast<std::string>(info.start_time) + std::string(" and ") + lexical_cast<std::string>(info.stop_time) + std::string(" seconds."));
	double currentTime = info.start_time;
	double currentM;
	int current_C_L = int(info.start_time * info.det.GetSimBkg() + 0.5);
	if (current_C_L < 2) {
		current_C_L = 2;
	}
	while (currentTime < info.stop_time) {
		FindLocalMinima(info, current_C_L, currentTime, currentM);
		if (currentTime > info.start_time and currentTime < info.stop_time) {
			clTime.push_back(currentTime);
			clValue.push_back(current_C_L);

			timeActVec.push_back(std::pair<double, double>(currentTime, currentM));
			PRINT_T(std::string("CalcThread::CalcTimeVsActData(): Storing results for C_L = ") + lexical_cast<std::string>(current_C_L) + std::string("."));
		} else {
			PRINT_T(std::string("CalcThread::CalcTimeVsActData(): Throwing away results for C_L = ") + lexical_cast<std::string>(current_C_L) + std::string("."));
		}
		current_C_L++;
	}

	PRINT_T(std::string("CalcThread::CalcTimeVsActData(): Calculating remaining sensitivity values between ") + lexical_cast<std::string>(info.start_time) + std::string(" and ") + lexical_cast<std::string>(info.stop_time) + std::string(" seconds."));
	ArrayXd testTimes = ArrayXd::LinSpaced(info.steps, info.start_time, info.stop_time);
	for (int u = 0; u < testTimes.size(); u++) {
		info.det.SetIntegrationTime(testTimes[u]);
		double act = info.det.CalcActivityFPH(info.fpPerHour, info.beta, info.cType);
		timeActVec.push_back(std::pair<double, double>(testTimes[u], act));
	}
	struct c_sorter
	{
		inline bool operator() (const std::pair<double, double>& p1, const std::pair<double, double>& p2)
		{
			return (p1.first < p2.first);
		}
	};

	std::sort(timeActVec.begin(), timeActVec.end(), c_sorter());

	std::string calcTypeStr;
	if (info.cType == Detector::CalcType::BEST) {
		calcTypeStr = string("BEST");
	} else if (info.cType == Detector::CalcType::MEAN) {
		calcTypeStr = string("MEAN");
	} else if (info.cType == Detector::CalcType::WORST) {
		calcTypeStr = string("WORST");
	} else if (info.cType == Detector::CalcType::LIST_MODE) {
		calcTypeStr = string("LIST_MODE");
	} else {
		calcTypeStr = string("UNKNOWN");
	}

	{
		boost::mutex::scoped_lock lock(*outputMutex.get());
		outResults->StartResult();
		outResults->Write("calc_type", calcTypeStr);
		outResults->Write("distance", info.det.GetDistance());
		outResults->Write("velocity", info.det.GetVelocity());
		outResults->Write("background", info.det.GetSimBkg());
		outResults->Write("cl_values", clValue);
		outResults->Write("cl_times", clTime);
		outResults->Write("times_and_acts", timeActVec);
		outResults->EndResult();
	}

	return 0;
}

int CalcThread::CalcTimeAndAct(CalcInfo &info) {
	vector<pair<string,string>> result;

	double time, actValue;
	vector<double> timeVec;
	vector<double> actVec;
	if (info.fixedInt) {
		time = info.intTime;
		info.det.SetIntegrationTime(time);
		actValue = info.det.CalcActivityFPH(info.fpPerHour, info.beta, info.cType);
	} else {
		FindGlobalMinima(info, time, actValue);
	}

	std::string calcTypeStr;
	if (info.cType == Detector::CalcType::BEST) {
		calcTypeStr = string("BEST");
	} else if (info.cType == Detector::CalcType::MEAN) {
		calcTypeStr = string("MEAN");
	} else if (info.cType == Detector::CalcType::WORST) {
		calcTypeStr = string("WORST");
	} else if (info.cType == Detector::CalcType::LIST_MODE) {
		calcTypeStr = string("LIST_MODE");
	} else {
		calcTypeStr = string("UNKNOWN");
	}
	info.det.SetIntegrationTime(time);
	double srcDetectProb = info.det.CalcTruePositiveProbFPH(info.fpPerHour, actValue, info.cType);
	int crit_limit = info.det.CriticalLimitFPH(info.fpPerHour, info.cType);

	ArrayXd signalArray = info.det.CalcSignal(actValue, info.cType);

	std::vector<std::pair<double, double>> periodsVector = info.det.GetIntTimes(info.cType);

	double timeStdDev = -1;
	double actStdDev = -1;
	double actMean = -1;
	double timeMean = -1;

	if (info.uncertLoops > 1) {
		double tempTime, tempAct, timeSum = 0, actSum = 0;
		double timeDiffSum = 0;
		double actDiffSum = 0;

		if (info.fixedInt) {
			for (int y = 0; y < info.uncertLoops; y++) {
				info.det.RandomizeParameters();
				tempAct = info.det.CalcActivityFPH(info.fpPerHour, info.beta, info.cType);
				actSum += tempAct;
				timeVec.push_back(tempTime);
				actVec.push_back(tempAct);

			}
			actMean = actSum / info.uncertLoops;
			timeMean = info.intTime;

			for (int i = 0; i < info.uncertLoops; i++) {
				actDiffSum += (actVec[i] - actMean) * (actVec[i] - actMean);
			}

			timeStdDev = 0.0;
			actStdDev = sqrt(actDiffSum / info.uncertLoops);

		} else {
			for (int y = 0; y < info.uncertLoops; y++) {
				info.det.RandomizeParameters();
				FindGlobalMinima(info, tempTime, tempAct);
				actSum += tempAct;
				timeSum += tempTime;
				timeVec.push_back(tempTime);
				actVec.push_back(tempAct);
			}
			actMean = actSum / info.uncertLoops;
			timeMean = timeSum / info.uncertLoops;

			for (int i = 0; i < info.uncertLoops; i++) {
				timeDiffSum += (timeVec[i] - timeMean) * (timeVec[i] - timeMean);
				actDiffSum += (actVec[i] - actMean) * (actVec[i] - actMean);
			}

			timeStdDev = sqrt(timeDiffSum / info.uncertLoops);
			actStdDev = sqrt(actDiffSum / info.uncertLoops);
		}
	}

	{
		boost::mutex::scoped_lock lock(*outputMutex.get());
		outResults->StartResult();
		outResults->Write("calc_type", calcTypeStr);
		outResults->Write("distance", info.det.GetDistance());
		outResults->Write("velocity", info.det.GetVelocity());
		outResults->Write("background", info.det.GetSimBkg());
		outResults->Write("fix_int_time", info.fixedInt);
		outResults->Write("int_time", time);
		outResults->Write("min_act", actValue);
		outResults->Write("true_pos_prob", srcDetectProb);
		outResults->Write("critical_limit", crit_limit);
		outResults->Write("int_periods", periodsVector);
		outResults->Write("mean_signal", signalArray);
		if (info.uncertLoops > 1) {
			outResults->Write("int_time_std_dev", timeStdDev);
			outResults->Write("int_time_mean", timeMean);
			outResults->Write("min_act_std_dev", actStdDev);
			outResults->Write("min_act_mean", actMean);
		}
		outResults->EndResult();
	}
	return 0;
}

void FindGlobalMinima(CalcInfo &info, double &time, double &bestM) {
	double currentTime = 0.0, lastTime = 5.0;
	double lastM = 1.0, currentM = 1.0;
	int current_C_L = 3; //Fix me: starting C_L value influences speed quite a bit. Find better starting value!
	FindLocalMinima(info, current_C_L, lastTime, lastM);
	currentTime = lastTime;
	current_C_L++;
	while (true) {
		PRINT_T(std::string("FindGlobalMinima(): Locating global minima for C_L = ") + lexical_cast<std::string>(current_C_L));
		FindLocalMinima(info, current_C_L, currentTime, currentM);
		if (currentM < lastM) {
			lastM = currentM;
			lastTime = currentTime;
			current_C_L++;
		} else {
			break;
		}
	}
	time = lastTime;
	bestM = lastM;
}

void FindLocalMinima(CalcInfo &info, int target_C_L, double &iTime, double &minM) {
	const double maxTimeDiff = 0.00001; //The maximum time step allowed when finding minimas, might need to be changed
	double upper_time = iTime + maxTimeDiff * 2; //To assist the algorithm slightly, we add the maximum time diff
	double lower_time = 0.0;

	//Find where we have C_L = target_C_L
	//This is done by stepping up and down in integration time until C_L = target_C_L
	int current_C_L;
	do {
		info.det.SetIntegrationTime(upper_time);
		current_C_L = info.det.CriticalLimitFPH(info.fpPerHour, info.cType);

		if (current_C_L > target_C_L) {
			upper_time = lower_time + (upper_time - lower_time) / 2.0;
		} else if (current_C_L < target_C_L) {
			lower_time = upper_time;
			upper_time *= 2;
		}
	 } while (current_C_L != target_C_L);

	lower_time = upper_time; //This is now our minimum time

	//Find some integration time where C_L > target_C_L
	//This is needed in order for the algorithm to do a binary search in the later stages of the algorithm
	do {
		upper_time *= 1.3; //Potentially fix me, probably a bit to radical to double the upper time
		info.det.SetIntegrationTime(upper_time);
	} while (info.det.CriticalLimitFPH(info.fpPerHour, info.cType) == target_C_L);

	//Now do the actual minima-finding part
	//This is done by moving the upper and lower time limits closer to each other which results in the algorithm closing in on when target_C_L becomes target_C_L + 1
	double c_time;
	while (upper_time - lower_time > maxTimeDiff) {
		c_time = (upper_time - lower_time) / 2.0 + lower_time;
		info.det.SetIntegrationTime(c_time);
		current_C_L = info.det.CriticalLimitFPH(info.fpPerHour, info.cType);
		if (current_C_L == target_C_L) {
			lower_time = c_time;
		} else {
			upper_time = c_time;
		}
	}
	//The actual integration time is the lower one as we really want C_L = target_C_L
	iTime = lower_time;
	info.det.SetIntegrationTime(iTime);
	minM = info.det.CalcActivityFPH(info.fpPerHour, info.beta, info.cType);
}
<commit_msg>Added information in verbose message.<commit_after>//
//  CalcCoordinator.cpp

#include "CalcCoordinator.h"

CalcCoordinator::CalcCoordinator(OutputResult::OutputType out_t, std::string resultFileName) : outFileName(resultFileName), outputMutex(new boost::mutex()), calcValuesMutex(new boost::mutex()), calcInfo(new vector<CalcInfo>()), outResults(new OutputResult(out_t, resultFileName)) {

}

CalcCoordinator::~CalcCoordinator() {

}

void CalcCoordinator::RunCalculations() {
	int numberOfThreads = thread::hardware_concurrency();

	for (int i = 0; i < numberOfThreads; i++) {
		CalcThread calcThread(i, calcInfo, calcValuesMutex, outputMutex, outResults);
		calcThreads.push_back(thread(calcThread));
	}

	while (calcThreads.size() > 0) {
		calcThreads[calcThreads.size() - 1].join();
		calcThreads.pop_back();
	}
}

void CalcCoordinator::AddCalculation(const Detector &det, Detector::CalcType cType, double fpPerHour, double beta, int uncertLoops) {
	calcInfo->push_back(CalcInfo(det, cType, fpPerHour, beta, uncertLoops));
}

void CalcCoordinator::AddFixedCalculation(const Detector &det, Detector::CalcType cType, double fpPerHour, double beta, double intTime, int uncertLoops) {
	CalcInfo tmp(det, cType, fpPerHour, beta, uncertLoops);
	tmp.FixIntegrationTime(intTime);
	calcInfo->push_back(tmp);
}

void CalcCoordinator::AddPlotCalculation(const Detector &det, Detector::CalcType cType, double fpPerHour, double beta, double start_time, double stop_time, unsigned int steps) {
	CalcInfo tmp(det, cType, fpPerHour, beta, 0);
	tmp.SetPlotDetails(start_time, stop_time, steps);
	calcInfo->push_back(tmp);
}

CalcThread::CalcThread(int threadId, boost::shared_ptr<vector<CalcInfo>> calcValues, boost::shared_ptr<boost::mutex> calcValuesMutex, boost::shared_ptr<boost::mutex> outputMutex, boost::shared_ptr<OutputResult> outResults) : calcValues(calcValues), calcValuesMutex(calcValuesMutex), threadId(threadId), outputMutex(outputMutex), outResults(outResults) {

}

void CalcThread::operator()() {
	CalcInfo tmpInfo;
	while (true) {
		{
			boost::mutex::scoped_lock lock(*calcValuesMutex.get());
			if (calcValues->size() == 0) {
				break;
			}
			tmpInfo = calcValues->at(calcValues->size() - 1);
			calcValues->pop_back();
			PRINT_T(std::string("CalcThread(): Thread starts work on new job. ") + lexical_cast<std::string>(calcValues->size()) + std::string(" jobs are still queued up."));
		}
		if (tmpInfo.plotCalc) {
			CalcTimeVsActData(tmpInfo);
		} else {
			CalcTimeAndAct(tmpInfo);
		}
	}
}

int CalcThread::CalcTimeVsActData(CalcInfo &info) {
	std::vector<std::pair<double, double>> timeActVec;
	std::vector<double> clTime;
	std::vector<unsigned int> clValue;

	PRINT_T(std::string("CalcThread::CalcTimeVsActData(): Locating minimas between ") + lexical_cast<std::string>(info.start_time) + std::string(" and ") + lexical_cast<std::string>(info.stop_time) + std::string(" seconds."));
	double currentTime = info.start_time;
	double currentM;
	int current_C_L = int(info.start_time * info.det.GetSimBkg() + 0.5);
	if (current_C_L < 2) {
		current_C_L = 2;
	}
	while (currentTime < info.stop_time) {
		FindLocalMinima(info, current_C_L, currentTime, currentM);
		if (currentTime > info.start_time and currentTime < info.stop_time) {
			clTime.push_back(currentTime);
			clValue.push_back(current_C_L);

			timeActVec.push_back(std::pair<double, double>(currentTime, currentM));
			PRINT_T(std::string("CalcThread::CalcTimeVsActData(): Storing results for C_L = ") + lexical_cast<std::string>(current_C_L) + std::string(" (t=") + lexical_cast<std::string>(currentTime) + std::string(", m=") + lexical_cast<std::string>(currentM) + std::string(")."));
		} else {
			PRINT_T(std::string("CalcThread::CalcTimeVsActData(): Throwing away results for C_L = ") + lexical_cast<std::string>(current_C_L) + std::string(" (t=") + lexical_cast<std::string>(currentTime) + std::string(", m=") + lexical_cast<std::string>(currentM) + std::string(")."));
		}
		current_C_L++;
	}

	PRINT_T(std::string("CalcThread::CalcTimeVsActData(): Calculating remaining sensitivity values between ") + lexical_cast<std::string>(info.start_time) + std::string(" and ") + lexical_cast<std::string>(info.stop_time) + std::string(" seconds."));
	ArrayXd testTimes = ArrayXd::LinSpaced(info.steps, info.start_time, info.stop_time);
	for (int u = 0; u < testTimes.size(); u++) {
		info.det.SetIntegrationTime(testTimes[u]);
		double act = info.det.CalcActivityFPH(info.fpPerHour, info.beta, info.cType);
		timeActVec.push_back(std::pair<double, double>(testTimes[u], act));
	}
	struct c_sorter
	{
		inline bool operator() (const std::pair<double, double>& p1, const std::pair<double, double>& p2)
		{
			return (p1.first < p2.first);
		}
	};

	std::sort(timeActVec.begin(), timeActVec.end(), c_sorter());

	std::string calcTypeStr;
	if (info.cType == Detector::CalcType::BEST) {
		calcTypeStr = string("BEST");
	} else if (info.cType == Detector::CalcType::MEAN) {
		calcTypeStr = string("MEAN");
	} else if (info.cType == Detector::CalcType::WORST) {
		calcTypeStr = string("WORST");
	} else if (info.cType == Detector::CalcType::LIST_MODE) {
		calcTypeStr = string("LIST_MODE");
	} else {
		calcTypeStr = string("UNKNOWN");
	}

	{
		boost::mutex::scoped_lock lock(*outputMutex.get());
		outResults->StartResult();
		outResults->Write("calc_type", calcTypeStr);
		outResults->Write("distance", info.det.GetDistance());
		outResults->Write("velocity", info.det.GetVelocity());
		outResults->Write("background", info.det.GetSimBkg());
		outResults->Write("cl_values", clValue);
		outResults->Write("cl_times", clTime);
		outResults->Write("times_and_acts", timeActVec);
		outResults->EndResult();
	}

	return 0;
}

int CalcThread::CalcTimeAndAct(CalcInfo &info) {
	vector<pair<string,string>> result;

	double time, actValue;
	vector<double> timeVec;
	vector<double> actVec;
	if (info.fixedInt) {
		time = info.intTime;
		info.det.SetIntegrationTime(time);
		actValue = info.det.CalcActivityFPH(info.fpPerHour, info.beta, info.cType);
	} else {
		FindGlobalMinima(info, time, actValue);
	}

	std::string calcTypeStr;
	if (info.cType == Detector::CalcType::BEST) {
		calcTypeStr = string("BEST");
	} else if (info.cType == Detector::CalcType::MEAN) {
		calcTypeStr = string("MEAN");
	} else if (info.cType == Detector::CalcType::WORST) {
		calcTypeStr = string("WORST");
	} else if (info.cType == Detector::CalcType::LIST_MODE) {
		calcTypeStr = string("LIST_MODE");
	} else {
		calcTypeStr = string("UNKNOWN");
	}
	info.det.SetIntegrationTime(time);
	double srcDetectProb = info.det.CalcTruePositiveProbFPH(info.fpPerHour, actValue, info.cType);
	int crit_limit = info.det.CriticalLimitFPH(info.fpPerHour, info.cType);

	ArrayXd signalArray = info.det.CalcSignal(actValue, info.cType);

	std::vector<std::pair<double, double>> periodsVector = info.det.GetIntTimes(info.cType);

	double timeStdDev = -1;
	double actStdDev = -1;
	double actMean = -1;
	double timeMean = -1;

	if (info.uncertLoops > 1) {
		double tempTime, tempAct, timeSum = 0, actSum = 0;
		double timeDiffSum = 0;
		double actDiffSum = 0;

		if (info.fixedInt) {
			for (int y = 0; y < info.uncertLoops; y++) {
				info.det.RandomizeParameters();
				tempAct = info.det.CalcActivityFPH(info.fpPerHour, info.beta, info.cType);
				actSum += tempAct;
				timeVec.push_back(tempTime);
				actVec.push_back(tempAct);

			}
			actMean = actSum / info.uncertLoops;
			timeMean = info.intTime;

			for (int i = 0; i < info.uncertLoops; i++) {
				actDiffSum += (actVec[i] - actMean) * (actVec[i] - actMean);
			}

			timeStdDev = 0.0;
			actStdDev = sqrt(actDiffSum / info.uncertLoops);

		} else {
			for (int y = 0; y < info.uncertLoops; y++) {
				info.det.RandomizeParameters();
				FindGlobalMinima(info, tempTime, tempAct);
				actSum += tempAct;
				timeSum += tempTime;
				timeVec.push_back(tempTime);
				actVec.push_back(tempAct);
			}
			actMean = actSum / info.uncertLoops;
			timeMean = timeSum / info.uncertLoops;

			for (int i = 0; i < info.uncertLoops; i++) {
				timeDiffSum += (timeVec[i] - timeMean) * (timeVec[i] - timeMean);
				actDiffSum += (actVec[i] - actMean) * (actVec[i] - actMean);
			}

			timeStdDev = sqrt(timeDiffSum / info.uncertLoops);
			actStdDev = sqrt(actDiffSum / info.uncertLoops);
		}
	}

	{
		boost::mutex::scoped_lock lock(*outputMutex.get());
		outResults->StartResult();
		outResults->Write("calc_type", calcTypeStr);
		outResults->Write("distance", info.det.GetDistance());
		outResults->Write("velocity", info.det.GetVelocity());
		outResults->Write("background", info.det.GetSimBkg());
		outResults->Write("fix_int_time", info.fixedInt);
		outResults->Write("int_time", time);
		outResults->Write("min_act", actValue);
		outResults->Write("true_pos_prob", srcDetectProb);
		outResults->Write("critical_limit", crit_limit);
		outResults->Write("int_periods", periodsVector);
		outResults->Write("mean_signal", signalArray);
		if (info.uncertLoops > 1) {
			outResults->Write("int_time_std_dev", timeStdDev);
			outResults->Write("int_time_mean", timeMean);
			outResults->Write("min_act_std_dev", actStdDev);
			outResults->Write("min_act_mean", actMean);
		}
		outResults->EndResult();
	}
	return 0;
}

void FindGlobalMinima(CalcInfo &info, double &time, double &bestM) {
	double currentTime = 0.0, lastTime = 5.0;
	double lastM = 1.0, currentM = 1.0;
	int current_C_L = 3; //Fix me: starting C_L value influences speed quite a bit. Find better starting value!
	FindLocalMinima(info, current_C_L, lastTime, lastM);
	currentTime = lastTime;
	current_C_L++;
	while (true) {
		PRINT_T(std::string("FindGlobalMinima(): Locating global minima for C_L = ") + lexical_cast<std::string>(current_C_L));
		FindLocalMinima(info, current_C_L, currentTime, currentM);
		if (currentM < lastM) {
			lastM = currentM;
			lastTime = currentTime;
			current_C_L++;
		} else {
			break;
		}
	}
	time = lastTime;
	bestM = lastM;
}

void FindLocalMinima(CalcInfo &info, int target_C_L, double &iTime, double &minM) {
	const double maxTimeDiff = 0.00001; //The maximum time step allowed when finding minimas, might need to be changed
	double upper_time = iTime + maxTimeDiff * 2; //To assist the algorithm slightly, we add the maximum time diff
	double lower_time = 0.0;

	//Find where we have C_L = target_C_L
	//This is done by stepping up and down in integration time until C_L = target_C_L
	int current_C_L;
	do {
		info.det.SetIntegrationTime(upper_time);
		current_C_L = info.det.CriticalLimitFPH(info.fpPerHour, info.cType);

		if (current_C_L > target_C_L) {
			upper_time = lower_time + (upper_time - lower_time) / 2.0;
		} else if (current_C_L < target_C_L) {
			lower_time = upper_time;
			upper_time *= 2;
		}
	 } while (current_C_L != target_C_L);

	lower_time = upper_time; //This is now our minimum time

	//Find some integration time where C_L > target_C_L
	//This is needed in order for the algorithm to do a binary search in the later stages of the algorithm
	do {
		upper_time *= 1.3; //Potentially fix me, probably a bit to radical to double the upper time
		info.det.SetIntegrationTime(upper_time);
	} while (info.det.CriticalLimitFPH(info.fpPerHour, info.cType) == target_C_L);

	//Now do the actual minima-finding part
	//This is done by moving the upper and lower time limits closer to each other which results in the algorithm closing in on when target_C_L becomes target_C_L + 1
	double c_time;
	while (upper_time - lower_time > maxTimeDiff) {
		c_time = (upper_time - lower_time) / 2.0 + lower_time;
		info.det.SetIntegrationTime(c_time);
		current_C_L = info.det.CriticalLimitFPH(info.fpPerHour, info.cType);
		if (current_C_L == target_C_L) {
			lower_time = c_time;
		} else {
			upper_time = c_time;
		}
	}
	//The actual integration time is the lower one as we really want C_L = target_C_L
	iTime = lower_time;
	info.det.SetIntegrationTime(iTime);
	minM = info.det.CalcActivityFPH(info.fpPerHour, info.beta, info.cType);
}
<|endoftext|>


<commit_before>/**
 * This file is part of the CernVM File System.
 *
 * This is a simple test program to test the facilities of the libcvmfs C
 * (not C++) library, which is used by Parrot and some other tools.
 *
 * The goal here is not so much to build the ultimate testing tool, but to
 * provide a simple build target which can verify that libcvmfs is exporting the
 * proper set of symbols to be used by a C program.
 */

#define __STDC_FORMAT_MACROS

#include "cvmfs_config.h"

#include <errno.h>
#include <inttypes.h>

#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <map>
#include <string>

#include "libcvmfs.h"

#define TEST_LINE_MAX 1024

typedef std::map<std::string, cvmfs_context*> RepoMap;
static RepoMap attached_repos;

void cvmfs_test_help()
{
  printf("commands are:\n");
  printf("   attach <repo name (without .cern.ch)>\n");
  printf("   detach <repo name (without .cern.ch)>\n");
  printf("   list <path>\n");
  printf("   cat  <path>\n");
  printf("   quit\n");
}

int cvmfs_test_list(cvmfs_context *ctx, const char *path)
{
  if (ctx == NULL) {
    fprintf(stderr, "%s\n", "please attach a repo first!");
    return -1;
  }

  char filepath[TEST_LINE_MAX];
  struct stat info;

  char **buffer = 0;
  size_t length = 0;
  int i;

  int result = cvmfs_listdir(ctx, path, &buffer, &length);
  if (result < 0) {
    fprintf(stderr, "%s: %s\n", path, strerror(errno));
    return -1;
  }

  for (i = 0; buffer[i]; i++) {
    snprintf(filepath, TEST_LINE_MAX, "%s/%s", path, buffer[i]);
    cvmfs_stat(ctx, filepath, &info);
    printf("%10"PRIu64" %s\n", static_cast<uint64_t>(info.st_size), buffer[i]);
  }

  free(buffer);

  return 0;
}

int cvmfs_test_cat(cvmfs_context *ctx, const char *path)
{
  if (ctx == NULL) {
    fprintf(stderr, "%s\n", "please attach a repo first!");
    return -1;
  }

  char buffer[TEST_LINE_MAX];

  int fd = cvmfs_open(ctx, path);
  if (fd < 0) {
    fprintf(stderr, "%s: %s\n", path, strerror(errno));
    return fd;
  }

  while (1) {
    int length = read(fd, buffer, sizeof(buffer));
    if (length <= 0) break;
    int retval = write(1, buffer, length);
    assert(retval == length);
  }

  cvmfs_close(ctx, fd);

  return 0;
}

cvmfs_context* cvmfs_test_attach(const char *repo_name)
{
  cvmfs_context *ctx = NULL;

  RepoMap::const_iterator i = attached_repos.find(repo_name);
  if (i == attached_repos.end()) {
    const char *repo_options =
      "repo_name=%s.cern.ch,url=http://cvmfs-stratum-one.cern.ch/opt/%s;"
      "http://cernvmfs.gridpp.rl.ac.uk/opt/%s;http://cvmfs.racf.bnl.gov/opt/%s,"
      "pubkey=/etc/cvmfs/keys/cern.ch/cern.ch.pub,"
      "proxies=http://ca-proxy.cern.ch:3128";
    char options[TEST_LINE_MAX];
    snprintf(options, TEST_LINE_MAX, repo_options, repo_name, repo_name,
             repo_name, repo_name);

    printf("attaching repo with options: %s\n", options);
    ctx = cvmfs_attach_repo(options);
    if (ctx == NULL) {
      fprintf(stderr, "couldn't initialize cvmfs!\n");
    } else {
      attached_repos[repo_name] = ctx;
    }
  } else {
    printf("switching to previously attached repo: %s\n", repo_name);
    ctx = i->second;
  }

  return ctx;
}

void cvmfs_test_detach(const char *repo_name, const cvmfs_context *active_ctx) {
  RepoMap::iterator i = attached_repos.find(repo_name);
  if (i == attached_repos.end()) {
    printf("Did not find '%s' to detach\n", repo_name);
    return;
  }

  cvmfs_context *ctx = i->second;
  if (ctx == active_ctx) {
    printf("'%s' is currently active and cannot be detached.\n", repo_name);
    return;
  }

  attached_repos.erase(i);
  cvmfs_detach_repo(ctx);
}

int main(int argc, char *argv[])
{
  char line[TEST_LINE_MAX];
  char path[TEST_LINE_MAX];
  char repo_name[TEST_LINE_MAX];

  const char *global_options = "cache_directory=/tmp/test-libcvmfs-cache";

  printf("%s: initializing with options: %s\n", argv[0], global_options);
  int retval = cvmfs_init(global_options);
  if (retval != 0) {
    fprintf(stderr, "couldn't initialize libcvmfs!\n");
    return -1;
  }

  cvmfs_context *ctx = NULL;

  while (1) {
    printf("cvmfs> ");
    fflush(stdout);

    if (!fgets(line, sizeof(line), stdin)) break;

    line[strlen(line)-1] = 0;

    if (sscanf(line, "list %s", path) == 1) {
      cvmfs_test_list(ctx, path);
    } else if (sscanf(line, "cat %s", path) == 1) {
      cvmfs_test_cat(ctx, path);
    } else if (sscanf(line, "attach %s", repo_name) == 1) {
      ctx = cvmfs_test_attach(repo_name);
    } else if (sscanf(line, "detach %s", repo_name) == 1) {
      cvmfs_test_detach(repo_name, ctx);
    } else if (!strcmp(line, "quit")) {
      break;
    } else {
      cvmfs_test_help();
    }
  }

  cvmfs_fini();

  return 0;
}

<commit_msg>FIX: test_libcvmfs initialization options<commit_after>/**
 * This file is part of the CernVM File System.
 *
 * This is a simple test program to test the facilities of the libcvmfs C
 * (not C++) library, which is used by Parrot and some other tools.
 *
 * The goal here is not so much to build the ultimate testing tool, but to
 * provide a simple build target which can verify that libcvmfs is exporting the
 * proper set of symbols to be used by a C program.
 */

#define __STDC_FORMAT_MACROS

#include "cvmfs_config.h"

#include <errno.h>
#include <inttypes.h>

#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <map>
#include <string>

#include "libcvmfs.h"

#define TEST_LINE_MAX 1024

typedef std::map<std::string, cvmfs_context*> RepoMap;
static RepoMap attached_repos;

void cvmfs_test_help()
{
  printf("commands are:\n");
  printf("   attach <repo name (without .cern.ch)>\n");
  printf("   detach <repo name (without .cern.ch)>\n");
  printf("   list <path>\n");
  printf("   cat  <path>\n");
  printf("   quit\n");
}

int cvmfs_test_list(cvmfs_context *ctx, const char *path)
{
  if (ctx == NULL) {
    fprintf(stderr, "%s\n", "please attach a repo first!");
    return -1;
  }

  char filepath[TEST_LINE_MAX];
  struct stat info;

  char **buffer = 0;
  size_t length = 0;
  int i;

  int result = cvmfs_listdir(ctx, path, &buffer, &length);
  if (result < 0) {
    fprintf(stderr, "%s: %s\n", path, strerror(errno));
    return -1;
  }

  for (i = 0; buffer[i]; i++) {
    snprintf(filepath, TEST_LINE_MAX, "%s/%s", path, buffer[i]);
    cvmfs_stat(ctx, filepath, &info);
    printf("%10"PRIu64" %s\n", static_cast<uint64_t>(info.st_size), buffer[i]);
  }

  free(buffer);

  return 0;
}

int cvmfs_test_cat(cvmfs_context *ctx, const char *path)
{
  if (ctx == NULL) {
    fprintf(stderr, "%s\n", "please attach a repo first!");
    return -1;
  }

  char buffer[TEST_LINE_MAX];

  int fd = cvmfs_open(ctx, path);
  if (fd < 0) {
    fprintf(stderr, "%s: %s\n", path, strerror(errno));
    return fd;
  }

  while (1) {
    int length = read(fd, buffer, sizeof(buffer));
    if (length <= 0) break;
    int retval = write(1, buffer, length);
    assert(retval == length);
  }

  cvmfs_close(ctx, fd);

  return 0;
}

cvmfs_context* cvmfs_test_attach(const char *repo_name)
{
  cvmfs_context *ctx = NULL;

  RepoMap::const_iterator i = attached_repos.find(repo_name);
  if (i == attached_repos.end()) {
    const char *repo_options =
      "repo_name=%s.cern.ch,url=http://cvmfs-stratum-one.cern.ch/opt/%s;"
      "http://cernvmfs.gridpp.rl.ac.uk/opt/%s;http://cvmfs.racf.bnl.gov/opt/%s,"
      "pubkey=/etc/cvmfs/keys/cern.ch/cern.ch.pub";
    char options[TEST_LINE_MAX];
    snprintf(options, TEST_LINE_MAX, repo_options, repo_name, repo_name,
             repo_name, repo_name);

    printf("attaching repo with options: %s\n", options);
    ctx = cvmfs_attach_repo(options);
    if (ctx == NULL) {
      fprintf(stderr, "couldn't initialize cvmfs!\n");
    } else {
      attached_repos[repo_name] = ctx;
    }
  } else {
    printf("switching to previously attached repo: %s\n", repo_name);
    ctx = i->second;
  }

  return ctx;
}

void cvmfs_test_detach(const char *repo_name, const cvmfs_context *active_ctx) {
  RepoMap::iterator i = attached_repos.find(repo_name);
  if (i == attached_repos.end()) {
    printf("Did not find '%s' to detach\n", repo_name);
    return;
  }

  cvmfs_context *ctx = i->second;
  if (ctx == active_ctx) {
    printf("'%s' is currently active and cannot be detached.\n", repo_name);
    return;
  }

  attached_repos.erase(i);
  cvmfs_detach_repo(ctx);
}

int main(int argc, char *argv[])
{
  char line[TEST_LINE_MAX];
  char path[TEST_LINE_MAX];
  char repo_name[TEST_LINE_MAX];

  const char *global_options = "cache_directory=/tmp/test-libcvmfs-cache";

  printf("%s: initializing with options: %s\n", argv[0], global_options);
  int retval = cvmfs_init(global_options);
  if (retval != 0) {
    fprintf(stderr, "couldn't initialize libcvmfs!\n");
    return -1;
  }

  cvmfs_context *ctx = NULL;

  while (1) {
    printf("cvmfs> ");
    fflush(stdout);

    if (!fgets(line, sizeof(line), stdin)) break;

    line[strlen(line)-1] = 0;

    if (sscanf(line, "list %s", path) == 1) {
      cvmfs_test_list(ctx, path);
    } else if (sscanf(line, "cat %s", path) == 1) {
      cvmfs_test_cat(ctx, path);
    } else if (sscanf(line, "attach %s", repo_name) == 1) {
      ctx = cvmfs_test_attach(repo_name);
    } else if (sscanf(line, "detach %s", repo_name) == 1) {
      cvmfs_test_detach(repo_name, ctx);
    } else if (!strcmp(line, "quit")) {
      break;
    } else {
      cvmfs_test_help();
    }
  }

  cvmfs_fini();

  return 0;
}

<|endoftext|>


<commit_before>// Coding Standard: Unpublishable
// This crap is going to work if it is the last thing I do tonight
// I really miss having a desk that fits me, I dont even know what is going on 'osajgnnd[onea
// Lets go

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/algorithm/string.hpp>
#include <iostream>
using namespace std;

int main() {
	cout << "Loading the JSON file" << endl;
	using boost::property_tree::ptree;
	ptree pt;

	// Load the JSON into the property tree ometrherfke
	string testfile = "db_schema.json";
	read_json(testfile, pt);

	cout << "JSON file loaded" << endl;

	cout << "Parsing File" << endl;
	for ( ptree::value_type const& v : pt.get_child("")) {

		string columnName = v.first;

		ptree subtree = v.second;
		string type = subtree.get<std::string>("Type");
		string size = subtree.get("Size", "");
		string description = subtree.get("Description", "");
		bool isIndex = subtree.get("Index", false);
		string defaultValue = subtree.get("Default", "");
		bool isNullable = subtree.get("Nullable", true);
		string extraData = subtree.get("Extra", "");
		bool isDepricated = subtree.get("Depricated", false);

		cout << "  `" << boost::to_lower_copy(columnName) << "`";
		cout << " " << boost::to_lower_copy(type); if (size.length() > 0) cout << "(" << size << ")"; cout << " ";
		if (!isNullable) cout << "NOT NULL";
		if (extraData.length() > 0) cout << " " << extraData;
		cout << "," << endl;

		// CREATE TABLE `virtual_aliases` (
		//   `id` int(11) NOT NULL auto_increment,
		//   `domain_id` int(11) NOT NULL,
		//   `source` varchar(100) NOT NULL,
		//   `destination` varchar(100) NOT NULL,
		//   PRIMARY KEY (`id`),
		//   FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE
		// ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

	}

}<commit_msg>modified the schema compiler to handle indexes beter and generate c++ code<commit_after>// Coding Standard: Unpublishable
// This crap is going to work if it is the last thing I do tonight
// I really miss having a desk that fits me, I dont even know what is going on 'osajgnnd[onea
// Lets go

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/algorithm/string.hpp>
#include <iostream>
#include <vector>
#include <sstream>
#include <map>
using namespace std;

map <string, string> SQLtoC {
	{"varchar", "string"},
	{"int", "int"},
	{"timestamp", "sql_timestamp"}
};

int main() {
	cout << "Loading the JSON file" << endl;
	using boost::property_tree::ptree;
	ptree pt;

	// Load the JSON into the property tree ometrherfke
	string testfile = "db_schema.json";
	read_json(testfile, pt);

	cout << "JSON file loaded" << endl;

	cout << "Parsing File" << endl;

	stringstream cfile;        // Really these should all be files
	stringstream sqlrows;    // to be joined and encapsulated
	vector<string> slqindexes; // to be joined as is

	sqlrows << "CREATE TABLE rules (";

	string concatinator = "";
	for ( ptree::value_type const& v : pt.get_child("columns")) {

		string columnName = v.first;

		ptree subtree = v.second;
		string type = subtree.get<std::string>("Type");
		string size = subtree.get("Size", "");
		string description = subtree.get("Description", "");
		string indexName = subtree.get("Index", "");
		string defaultValue = subtree.get("Default", "");
		bool isNullable = subtree.get("Nullable", true);
		string extraData = subtree.get("Extra", "");
		bool isDepricated = subtree.get("Depricated", false);

		sqlrows << concatinator << endl << "  `" << boost::to_lower_copy(columnName) << "`";
		sqlrows << " " << boost::to_lower_copy(type); if (size.length() > 0) sqlrows << "(" << size << ")"; sqlrows << " ";
		if (!isNullable) sqlrows << "NOT NULL";
		if (defaultValue.length() > 0) sqlrows << " DEFAULT " << defaultValue;
		if (extraData.length() > 0) sqlrows << " " << extraData;
		concatinator = ",";

		cfile << SQLtoC[type] << " " << columnName << ";" << endl;

		// CREATE TABLE `virtual_aliases` (
		//   `id` int(11) NOT NULL auto_increment,
		//   `domain_id` int(11) NOT NULL,
		//   `source` varchar(100) NOT NULL,
		//   `destination` varchar(100) NOT NULL,
		//   PRIMARY KEY (`id`),
		//   FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE
		// ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

	}

	sqlrows << endl << ") ENGINE=InnoDB DEFAULT CHARSET=utf8;" << endl; // the engine data might not be nessasary but IDK
	// cout << "CREATE INDEX " << indexName << "ON rules (" << columnName << ");" << endl;
	cout << sqlrows.rdbuf() << endl;
	cout << cfile.rdbuf() << endl;
}<|endoftext|>