<commit_before>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of libmeegotouch.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include "mthemedaemon.h"

#include <QSvgRenderer>
#include <MDebug>
#include <QPixmap>
#include <QDir>
#include <QSettings>
#include <QTimer>
#include <QColor>
#include <QCoreApplication>
#include <QStringList>
#include <MGConfItem>
#include <QPainter>
#include "mthemedaemonclient.h"
#include "mimagedirectory.h"
#include "mthemedaemonprotocol.h"
#include "mthemeresourcemanager.h"

using namespace M::MThemeDaemonProtocol;

MThemeDaemon::MThemeDaemon() :
    mostUsedPixmaps(this)
{
    // check that the base theme ("fallback") directory exists.
    QDir baseThemeDir(systemThemeDirectory() + QDir::separator() + "base" + QDir::separator() +
                      "meegotouch" + QDir::separator() + "libmeegotouchcore" + QDir::separator() + "style");
    if (!baseThemeDir.exists()) {
        // we don't have the base theme ("fallback") directory, so exit!
        qFatal("MThemeDaemon - base theme directory not found: %s. Please (re)install meegotouchtheme package.",
               qPrintable(baseThemeDir.absolutePath()));
    }
}

MThemeDaemon::~MThemeDaemon()
{
    if (!mostUsedPixmaps.save(systemThemeCacheDirectory() + QDir::separator() + currentThemeName + QDir::separator() + "preload.list")) {
        // TODO: print out warning
    }
    mostUsedPixmaps.clear();

    qDeleteAll(themeImageDirs);
    themeImageDirs.clear();
}

QString MThemeDaemon::systemThemeDirectory()
{
#ifdef Q_OS_WIN
    QDir appDir(QCoreApplication::applicationDirPath());
    appDir.cdUp();
    appDir.cd("themes");
    return appDir.absolutePath();
#else
    return THEMEDIR;
#endif
}

QString MThemeDaemon::systemThemeCacheDirectory()
{
#ifdef Q_WS_X11
    return "/var/cache/meegotouch/themedaemon";
#else
    return QDir::tempPath();
#endif
}

void MThemeDaemon::addClient(MThemeDaemonClient *client)
{
    Q_UNUSED(client);
}

void MThemeDaemon::removeClient(MThemeDaemonClient *client)
{
    // release all pixmaps
    while (client->pixmaps.count() > 0) {
        PixmapIdentifier id = client->pixmaps.begin().key();
        releasePixmap(client, id);
    }
}

bool MThemeDaemon::pixmap(MThemeDaemonClient *client, const PixmapIdentifier &id, Qt::HANDLE &handle)
{
    // has the client already requested this pixmap?
    if (client->pixmaps.contains(id)) {
        mWarning("MThemeDaemon") << "    The requested pixmap" << id.imageId << "is already loaded for the client" << client->name();
        return false;
    }

    // try to find the image resource from the client specific paths
    ImageResource *resource = client->findImageResource(id.imageId);
    if (!resource) {
        // application paths didn't contain the image resource, now check from theme
        resource = findImageResource(id.imageId);
        if (!resource) {
            mWarning("MThemeDaemon") << "    The requested pixmap" << id.imageId << "was not found for client" << client->name();
            client->pixmaps.insert(id, NULL);
            handle = 0;
            return true;
        } else {
            mostUsedPixmaps.increaseRequestCount(id, resource);
        }
    }

    // save the information that this client has a reference of this pixmap
    client->pixmaps.insert(id, resource);

    // we have found the correct image resource.
    handle = resource->fetchPixmap(id.size);
    return true;
}

bool MThemeDaemon::releasePixmap(MThemeDaemonClient *client, const PixmapIdentifier &id)
{
    QHash<PixmapIdentifier, ImageResource *>::iterator i = client->pixmaps.find(id);
    if (i == client->pixmaps.end()) {
        // the client has no reference to this pixmap
        mWarning("MThemeDaemon") << "    Pixmap" << id.imageId << "was not loaded by the client" << client->name();
        return false;
    }

    ImageResource *resource = i.value();
    client->pixmaps.erase(i);
    if (resource == NULL) {
        // the pixmap was an invalid pixmap, no need to release anything
        return true;
    }

    // find a cache entry for the pixmap to be released.
    resource->releasePixmap(id.size);
    return true;
}

QString MThemeDaemon::currentTheme() const
{
    return currentThemeName;
}

QStringList MThemeDaemon::themeInheritanceChain() const
{
    return themeInheritance;
}

QStringList MThemeDaemon::themeLibraryNames() const
{
    return themeLibraries;
}

ImageResource *MThemeDaemon::findImageResource(const QString &imageId)
{
    ImageResource *resource = NULL;
    // try to find the image first from current theme,
    // then from theme that the current one is inherited from, and so on.
    foreach(MThemeImagesDirectory * imdir, themeImageDirs) {
        resource = imdir->findImage(imageId);
        if (resource)
            break;
    }

    return resource;
}

void MThemeDaemon::reloadImagePaths(const QString &locale)
{
    qDeleteAll(themeImageDirs);
    themeImageDirs.clear();

    foreach(const QString & theme, themeInheritance) {
        themeImageDirs.append(new MThemeImagesDirectory(theme + "meegotouch", locale));
    }
}

const QSettings *themeFile(const QString &theme)
{
    // Determine whether this is a m theme:
    // step 1: we need to have index.theme file
    const QString themeIndexFileName = MThemeDaemon::systemThemeDirectory() + QDir::separator() + theme + QDir::separator() + "index.theme";
    if (!QFile::exists(themeIndexFileName))
        return NULL;

    // step 2: it needs to be a valid ini file
    const QSettings *themeIndexFile = new QSettings(themeIndexFileName, QSettings::IniFormat);
    if (themeIndexFile->status() != QSettings::NoError) {
        delete themeIndexFile;
        return NULL;
    }

    // step 3: we need to have X-MeegoTouch-Metatheme group in index.theme
    if (!themeIndexFile->childGroups().contains(QString("X-MeegoTouch-Metatheme"))) {
        delete themeIndexFile;
        return NULL;
    }
    return themeIndexFile;
}

bool MThemeDaemon::activateTheme(const QString &newTheme, const QString &locale, const QList<MThemeDaemonClient *>& clientList, QHash<MThemeDaemonClient *, QList<PixmapIdentifier> >& pixmapsToReload)
{
    if (newTheme == currentThemeName) {
        // TODO: check need for warning
        return false;
    }

    QDir dir(systemThemeDirectory() + QDir::separator() + newTheme);
    if (!dir.exists()) {
        mWarning("MThemeDaemon") << "Theme" << newTheme << "does not exist! Not changing theme";
        return false;
    }

#ifdef MTHEME_PRINT_DEBUG
    mDebug("MThemeDaemon") << "Changing theme from" << currentThemeName << "to" << newTheme;
#endif

    // Change the theme

    // 1: find out the inheritance chain for the new theme
    QString tmpTheme = newTheme;
    QStringList newThemeInheritanceChain;
    QSet<QString> themeLibraryNames;

    while (true) {
        const QSettings *themeIndexFile = themeFile(tmpTheme);
        if (!themeIndexFile) {
            // TODO: print out warning, theme inheritance contains invalid theme
            return false;
        }

        newThemeInheritanceChain.append(tmpTheme);
        QString parentTheme = themeIndexFile->value("X-MeegoTouch-Metatheme/X-Inherits", "").toString();

        QStringList libraryNames = themeIndexFile->value("X-MeegoTouch-Metatheme/X-Libraries", "").toString().split(",", QString::SkipEmptyParts);
        foreach(const QString& libname, libraryNames) {
            themeLibraryNames.insert(libname.trimmed());
        }

        delete themeIndexFile;

        if (tmpTheme == "base")
            break;
        tmpTheme = parentTheme;
        if (tmpTheme.isEmpty()) {
            // TODO: print out warning, no base theme for this theme.
            return false;
        }

        // check that there is no cyclic dependencies
        foreach(const QString & themeName, newThemeInheritanceChain) {
            if (tmpTheme == themeName) {
                mWarning("MThemeDaemon") << "Cyclic dependency in theme:" << newTheme;
                return false;
            }
        }
    }

    themeLibraries = themeLibraryNames.toList();
    themeInheritance = newThemeInheritanceChain;

#ifdef MTHEME_PRINT_DEBUG
    mDebug("MThemeDaemon") << "    New theme inheritance chain is" << themeInheritance;
#endif

    // include the path to theme inheritance chain
    for (int i = 0; i != themeInheritance.count(); ++i) {
        themeInheritance[i] = systemThemeDirectory() + QDir::separator() + themeInheritance[i] + QDir::separator();
    }

    // 2. save the most used list for the old theme
    if (!currentThemeName.isEmpty()) {
        if (!mostUsedPixmaps.save(systemThemeCacheDirectory() + QDir::separator() + currentThemeName + QDir::separator() + "preload.list")) {
            // TODO: print out warning
        }
    }

    // 3. release all most used pixmaps
    mostUsedPixmaps.clear();

    currentThemeName = newTheme;

    // 4: go trough all clients and release all pixmaps + put them into load queue
    // plus send a packet for all clients, so they can start releasing and requesting new pixmaps, (so the daemon wouldn't need to reload all pixmaps that aren't needed anymore)

    foreach(MThemeDaemonClient * client, clientList) {

        QList<PixmapIdentifier> pixmapsToBeReloaded = client->pixmaps.keys();

        foreach(const PixmapIdentifier & id, pixmapsToBeReloaded) {
            releasePixmap(client, id);
        }

        pixmapsToReload.insert(client, pixmapsToBeReloaded);

        client->reloadImagePaths(themeInheritance);
    }

    MThemeResourceManager::instance().themeChanged();

    // 5: release rest of the old theme resources and load the new ones
    reloadImagePaths(locale);

    // 6. load the "preload" list
    if (!mostUsedPixmaps.load(systemThemeCacheDirectory() + QDir::separator() + currentThemeName + QDir::separator() + "preload.list")) {
        // TODO: print out warning
    }

    return true;
}

void MThemeDaemon::changeLocale(const QString &newLocale, const QList<MThemeDaemonClient *>& clientList, QHash<MThemeDaemonClient *, QList<PixmapIdentifier> >& pixmapsToReload)
{
    QList<QPair<MThemeDaemonClient *, QList<QPair<PixmapIdentifier, ImageResource *> > > > potentialIconsFromClients;

    foreach(MThemeDaemonClient * client, clientList) {

        QHash<PixmapIdentifier, ImageResource *>::iterator i = client->pixmaps.begin();
        QHash<PixmapIdentifier, ImageResource *>::iterator end = client->pixmaps.end();

        QList<QPair<PixmapIdentifier, ImageResource *> > potentialReloadlist;

        QList<PixmapIdentifier> pixmapsToBeReloaded;

        // get all icons from this client
        for (; i != end; ++i) {
            // is this image an icon?
            if (dynamic_cast<IconImageResource *>(i.value())) {

                bool reload = false;
                foreach(MThemeImagesDirectory * imdir, themeImageDirs) {
                    if (imdir->isLocaleSpecificImage(i.key().imageId)) {
                        reload = true;
                        break;
                    }
                }

                if (reload) {
                    // this image was locale specific icon so mark it to be reloaded
                    pixmapsToBeReloaded.append(i.key());
                    mostUsedPixmaps.reload(i.key(), i.value());
                } else {
                    // this image was icon but not locale specific so mark it as potential
                    potentialReloadlist.append(qMakePair(i.key(), i.value()));
                }
            }
        }

        // release all old locale specific icons
        foreach(const PixmapIdentifier & id, pixmapsToBeReloaded) {
            releasePixmap(client, id);
        }

        pixmapsToReload.insert(client, pixmapsToBeReloaded);
        potentialIconsFromClients.append(qMakePair(client, potentialReloadlist));
    }

    // load the new locale specific images
    foreach(MThemeImagesDirectory * imdir, themeImageDirs) {
        imdir->reloadLocaleSpecificImages(newLocale);
    }

    typedef QPair<PixmapIdentifier, ImageResource *> pi_ir;
    typedef QPair<MThemeDaemonClient *, QList<pi_ir> > c_pi_ir;

    foreach(const c_pi_ir & potentialIconsFromClient, potentialIconsFromClients) {
        foreach(const pi_ir & potentialIcon, potentialIconsFromClient.second) {

            foreach(MThemeImagesDirectory * imdir, themeImageDirs) {
                if (imdir->isLocaleSpecificImage(potentialIcon.first.imageId)) {
                    releasePixmap(potentialIconsFromClient.first, potentialIcon.first);
                    mostUsedPixmaps.reload(potentialIcon.first, potentialIcon.second);
                    pixmapsToReload[potentialIconsFromClient.first].append(potentialIcon.first);
                    break;
                }
            }
        }
    }
}
<commit_msg>Changes: make mthemedaemon work with old theme index files<commit_after>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of libmeegotouch.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include "mthemedaemon.h"

#include <QSvgRenderer>
#include <MDebug>
#include <QPixmap>
#include <QDir>
#include <QSettings>
#include <QTimer>
#include <QColor>
#include <QCoreApplication>
#include <QStringList>
#include <MGConfItem>
#include <QPainter>
#include "mthemedaemonclient.h"
#include "mimagedirectory.h"
#include "mthemedaemonprotocol.h"
#include "mthemeresourcemanager.h"

using namespace M::MThemeDaemonProtocol;

MThemeDaemon::MThemeDaemon() :
    mostUsedPixmaps(this)
{
    // check that the base theme ("fallback") directory exists.
    QDir baseThemeDir(systemThemeDirectory() + QDir::separator() + "base" + QDir::separator() +
                      "meegotouch" + QDir::separator() + "libmeegotouchcore" + QDir::separator() + "style");
    if (!baseThemeDir.exists()) {
        // we don't have the base theme ("fallback") directory, so exit!
        qFatal("MThemeDaemon - base theme directory not found: %s. Please (re)install meegotouchtheme package.",
               qPrintable(baseThemeDir.absolutePath()));
    }
}

MThemeDaemon::~MThemeDaemon()
{
    if (!mostUsedPixmaps.save(systemThemeCacheDirectory() + QDir::separator() + currentThemeName + QDir::separator() + "preload.list")) {
        // TODO: print out warning
    }
    mostUsedPixmaps.clear();

    qDeleteAll(themeImageDirs);
    themeImageDirs.clear();
}

QString MThemeDaemon::systemThemeDirectory()
{
#ifdef Q_OS_WIN
    QDir appDir(QCoreApplication::applicationDirPath());
    appDir.cdUp();
    appDir.cd("themes");
    return appDir.absolutePath();
#else
    return THEMEDIR;
#endif
}

QString MThemeDaemon::systemThemeCacheDirectory()
{
#ifdef Q_WS_X11
    return "/var/cache/meegotouch/themedaemon";
#else
    return QDir::tempPath();
#endif
}

void MThemeDaemon::addClient(MThemeDaemonClient *client)
{
    Q_UNUSED(client);
}

void MThemeDaemon::removeClient(MThemeDaemonClient *client)
{
    // release all pixmaps
    while (client->pixmaps.count() > 0) {
        PixmapIdentifier id = client->pixmaps.begin().key();
        releasePixmap(client, id);
    }
}

bool MThemeDaemon::pixmap(MThemeDaemonClient *client, const PixmapIdentifier &id, Qt::HANDLE &handle)
{
    // has the client already requested this pixmap?
    if (client->pixmaps.contains(id)) {
        mWarning("MThemeDaemon") << "    The requested pixmap" << id.imageId << "is already loaded for the client" << client->name();
        return false;
    }

    // try to find the image resource from the client specific paths
    ImageResource *resource = client->findImageResource(id.imageId);
    if (!resource) {
        // application paths didn't contain the image resource, now check from theme
        resource = findImageResource(id.imageId);
        if (!resource) {
            mWarning("MThemeDaemon") << "    The requested pixmap" << id.imageId << "was not found for client" << client->name();
            client->pixmaps.insert(id, NULL);
            handle = 0;
            return true;
        } else {
            mostUsedPixmaps.increaseRequestCount(id, resource);
        }
    }

    // save the information that this client has a reference of this pixmap
    client->pixmaps.insert(id, resource);

    // we have found the correct image resource.
    handle = resource->fetchPixmap(id.size);
    return true;
}

bool MThemeDaemon::releasePixmap(MThemeDaemonClient *client, const PixmapIdentifier &id)
{
    QHash<PixmapIdentifier, ImageResource *>::iterator i = client->pixmaps.find(id);
    if (i == client->pixmaps.end()) {
        // the client has no reference to this pixmap
        mWarning("MThemeDaemon") << "    Pixmap" << id.imageId << "was not loaded by the client" << client->name();
        return false;
    }

    ImageResource *resource = i.value();
    client->pixmaps.erase(i);
    if (resource == NULL) {
        // the pixmap was an invalid pixmap, no need to release anything
        return true;
    }

    // find a cache entry for the pixmap to be released.
    resource->releasePixmap(id.size);
    return true;
}

QString MThemeDaemon::currentTheme() const
{
    return currentThemeName;
}

QStringList MThemeDaemon::themeInheritanceChain() const
{
    return themeInheritance;
}

QStringList MThemeDaemon::themeLibraryNames() const
{
    return themeLibraries;
}

ImageResource *MThemeDaemon::findImageResource(const QString &imageId)
{
    ImageResource *resource = NULL;
    // try to find the image first from current theme,
    // then from theme that the current one is inherited from, and so on.
    foreach(MThemeImagesDirectory * imdir, themeImageDirs) {
        resource = imdir->findImage(imageId);
        if (resource)
            break;
    }

    return resource;
}

void MThemeDaemon::reloadImagePaths(const QString &locale)
{
    qDeleteAll(themeImageDirs);
    themeImageDirs.clear();

    foreach(const QString & theme, themeInheritance) {
        themeImageDirs.append(new MThemeImagesDirectory(theme + "meegotouch", locale));
    }
}

const QSettings *themeFile(const QString &theme)
{
    // Determine whether this is a m theme:
    // step 1: we need to have index.theme file
    const QString themeIndexFileName = MThemeDaemon::systemThemeDirectory() + QDir::separator() + theme + QDir::separator() + "index.theme";
    if (!QFile::exists(themeIndexFileName))
        return NULL;

    // step 2: it needs to be a valid ini file
    const QSettings *themeIndexFile = new QSettings(themeIndexFileName, QSettings::IniFormat);
    if (themeIndexFile->status() != QSettings::NoError) {
        delete themeIndexFile;
        return NULL;
    }

    // step 3: we need to have X-MeegoTouch-Metatheme group in index.theme

    // here we accept also the old X-DUI-Metatheme, because the old and new files
    // are in the same directory. remove "X-DUI-Metatheme" when libdui 0.19 and
    // duitheme with it is phased out.

    if ( (!themeIndexFile->childGroups().contains(QString("X-DUI-Metatheme")))
         && (!themeIndexFile->childGroups().contains(QString("X-MeegoTouch-Metatheme"))) )
    {
        delete themeIndexFile;
        return NULL;
    }
    return themeIndexFile;
}

bool MThemeDaemon::activateTheme(const QString &newTheme, const QString &locale, const QList<MThemeDaemonClient *>& clientList, QHash<MThemeDaemonClient *, QList<PixmapIdentifier> >& pixmapsToReload)
{
    if (newTheme == currentThemeName) {
        // TODO: check need for warning
        return false;
    }

    QDir dir(systemThemeDirectory() + QDir::separator() + newTheme);
    if (!dir.exists()) {
        mWarning("MThemeDaemon") << "Theme" << newTheme << "does not exist! Not changing theme";
        return false;
    }

#ifdef MTHEME_PRINT_DEBUG
    mDebug("MThemeDaemon") << "Changing theme from" << currentThemeName << "to" << newTheme;
#endif

    // Change the theme

    // 1: find out the inheritance chain for the new theme
    QString tmpTheme = newTheme;
    QStringList newThemeInheritanceChain;
    QSet<QString> themeLibraryNames;

    while (true) {
        const QSettings *themeIndexFile = themeFile(tmpTheme);
        if (!themeIndexFile) {
            // TODO: print out warning, theme inheritance contains invalid theme
            return false;
        }

        newThemeInheritanceChain.append(tmpTheme);
        QString parentTheme = themeIndexFile->value("X-MeegoTouch-Metatheme/X-Inherits", "").toString();

        // remove when duitheme is phased out
        if ( parentTheme.isEmpty() )
        {
            parentTheme = themeIndexFile->value("X-DUI-Metatheme/X-Inherits", "").toString();
        }
        // end remove

        QStringList libraryNames = themeIndexFile->value("X-MeegoTouch-Metatheme/X-Libraries", "").toString().split(",", QString::SkipEmptyParts);

        // remove when duitheme is phased out
        if ( libraryNames.isEmpty() )
        {
            libraryNames = themeIndexFile->value("X-DUI-Metatheme/X-Libraries", "")
                .toString().split(",", QString::SkipEmptyParts);
        }
        // end remove

        foreach(const QString& libname, libraryNames) {
            themeLibraryNames.insert(libname.trimmed());
        }

        delete themeIndexFile;

        if (tmpTheme == "base")
            break;
        tmpTheme = parentTheme;
        if (tmpTheme.isEmpty()) {
            // TODO: print out warning, no base theme for this theme.
            return false;
        }

        // check that there is no cyclic dependencies
        foreach(const QString & themeName, newThemeInheritanceChain) {
            if (tmpTheme == themeName) {
                mWarning("MThemeDaemon") << "Cyclic dependency in theme:" << newTheme;
                return false;
            }
        }
    }

    themeLibraries = themeLibraryNames.toList();
    themeInheritance = newThemeInheritanceChain;

#ifdef MTHEME_PRINT_DEBUG
    mDebug("MThemeDaemon") << "    New theme inheritance chain is" << themeInheritance;
#endif

    // include the path to theme inheritance chain
    for (int i = 0; i != themeInheritance.count(); ++i) {
        themeInheritance[i] = systemThemeDirectory() + QDir::separator() + themeInheritance[i] + QDir::separator();
    }

    // 2. save the most used list for the old theme
    if (!currentThemeName.isEmpty()) {
        if (!mostUsedPixmaps.save(systemThemeCacheDirectory() + QDir::separator() + currentThemeName + QDir::separator() + "preload.list")) {
            // TODO: print out warning
        }
    }

    // 3. release all most used pixmaps
    mostUsedPixmaps.clear();

    currentThemeName = newTheme;

    // 4: go trough all clients and release all pixmaps + put them into load queue
    // plus send a packet for all clients, so they can start releasing and requesting new pixmaps, (so the daemon wouldn't need to reload all pixmaps that aren't needed anymore)

    foreach(MThemeDaemonClient * client, clientList) {

        QList<PixmapIdentifier> pixmapsToBeReloaded = client->pixmaps.keys();

        foreach(const PixmapIdentifier & id, pixmapsToBeReloaded) {
            releasePixmap(client, id);
        }

        pixmapsToReload.insert(client, pixmapsToBeReloaded);

        client->reloadImagePaths(themeInheritance);
    }

    MThemeResourceManager::instance().themeChanged();

    // 5: release rest of the old theme resources and load the new ones
    reloadImagePaths(locale);

    // 6. load the "preload" list
    if (!mostUsedPixmaps.load(systemThemeCacheDirectory() + QDir::separator() + currentThemeName + QDir::separator() + "preload.list")) {
        // TODO: print out warning
    }

    return true;
}

void MThemeDaemon::changeLocale(const QString &newLocale, const QList<MThemeDaemonClient *>& clientList, QHash<MThemeDaemonClient *, QList<PixmapIdentifier> >& pixmapsToReload)
{
    QList<QPair<MThemeDaemonClient *, QList<QPair<PixmapIdentifier, ImageResource *> > > > potentialIconsFromClients;

    foreach(MThemeDaemonClient * client, clientList) {

        QHash<PixmapIdentifier, ImageResource *>::iterator i = client->pixmaps.begin();
        QHash<PixmapIdentifier, ImageResource *>::iterator end = client->pixmaps.end();

        QList<QPair<PixmapIdentifier, ImageResource *> > potentialReloadlist;

        QList<PixmapIdentifier> pixmapsToBeReloaded;

        // get all icons from this client
        for (; i != end; ++i) {
            // is this image an icon?
            if (dynamic_cast<IconImageResource *>(i.value())) {

                bool reload = false;
                foreach(MThemeImagesDirectory * imdir, themeImageDirs) {
                    if (imdir->isLocaleSpecificImage(i.key().imageId)) {
                        reload = true;
                        break;
                    }
                }

                if (reload) {
                    // this image was locale specific icon so mark it to be reloaded
                    pixmapsToBeReloaded.append(i.key());
                    mostUsedPixmaps.reload(i.key(), i.value());
                } else {
                    // this image was icon but not locale specific so mark it as potential
                    potentialReloadlist.append(qMakePair(i.key(), i.value()));
                }
            }
        }

        // release all old locale specific icons
        foreach(const PixmapIdentifier & id, pixmapsToBeReloaded) {
            releasePixmap(client, id);
        }

        pixmapsToReload.insert(client, pixmapsToBeReloaded);
        potentialIconsFromClients.append(qMakePair(client, potentialReloadlist));
    }

    // load the new locale specific images
    foreach(MThemeImagesDirectory * imdir, themeImageDirs) {
        imdir->reloadLocaleSpecificImages(newLocale);
    }

    typedef QPair<PixmapIdentifier, ImageResource *> pi_ir;
    typedef QPair<MThemeDaemonClient *, QList<pi_ir> > c_pi_ir;

    foreach(const c_pi_ir & potentialIconsFromClient, potentialIconsFromClients) {
        foreach(const pi_ir & potentialIcon, potentialIconsFromClient.second) {

            foreach(MThemeImagesDirectory * imdir, themeImageDirs) {
                if (imdir->isLocaleSpecificImage(potentialIcon.first.imageId)) {
                    releasePixmap(potentialIconsFromClient.first, potentialIcon.first);
                    mostUsedPixmaps.reload(potentialIcon.first, potentialIcon.second);
                    pixmapsToReload[potentialIconsFromClient.first].append(potentialIcon.first);
                    break;
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//******************************************************************************
//*
//*     FULLNAME:  Single-Chip Microcontroller Real-Time Operating System
//*
//*     NICKNAME:  scmRTOS
//*
//*     PROCESSOR: ARM Cortex-M4(F)
//*
//*     TOOLKIT:   ARM GCC
//*
//*     PURPOSE:   Target Dependent Stuff Source
//*
//*     Version: 4.00
//*
//*     $Revision$
//*     $Date::             $
//*
//*     Copyright (c) 2003-2012, Harry E. Zhurov
//*
//*     Permission is hereby granted, free of charge, to any person
//*     obtaining  a copy of this software and associated documentation
//*     files (the "Software"), to deal in the Software without restriction,
//*     including without limitation the rights to use, copy, modify, merge,
//*     publish, distribute, sublicense, and/or sell copies of the Software,
//*     and to permit persons to whom the Software is furnished to do so,
//*     subject to the following conditions:
//*
//*     The above copyright notice and this permission notice shall be included
//*     in all copies or substantial portions of the Software.
//*
//*     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//*     EXPRESS  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
//*     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
//*     IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
//*     CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
//*     TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
//*     THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//*
//*     =================================================================
//*     See http://scmrtos.sourceforge.net for documentation, latest
//*     information, license and contact details.
//*     =================================================================
//*
//******************************************************************************
//*     Cortex-M4(F) GCC port by Anton B. Gusev aka AHTOXA, Copyright (c) 2012

#include <scmRTOS.h>

using namespace OS;

void TBaseProcess::init_stack_frame( stack_item_t * Stack
                                   , void (*exec)()
                                #if scmRTOS_DEBUG_ENABLE == 1
                                   , stack_item_t * StackBegin
                                #endif
                                   )
{
    // ARM Architecture Procedure Call Standard [AAPCS] requires 8-byte stack alignment:
    StackPointer = (stack_item_t*)((uintptr_t)Stack & 0xFFFFFFF8);
#if (!defined __SOFTFP__)
    --StackPointer;
#endif

    *(--StackPointer)  = 0x01000000UL;      // xPSR
    *(--StackPointer)  = reinterpret_cast<uint32_t>(exec); // Entry Point
#if (defined __SOFTFP__)
    StackPointer -= 14;                     // emulate "push LR,R12,R3,R2,R1,R0,R11-R4"
#else
    StackPointer -= 6;                      // emulate "push LR,R12,R3,R2,R1,R0"
    *(--StackPointer)  = 0xFFFFFFFDUL;      // exc_return: Return to Thread mode, floating-point context inactive, execution uses PSP after return.
    StackPointer -= 8;                      // emulate "push R4-R11"
#endif

#if scmRTOS_DEBUG_ENABLE == 1
    for (stack_item_t* pDst = StackBegin; pDst < StackPointer; pDst++)
        *pDst = STACK_DEFAULT_PATTERN;
#endif // scmRTOS_DEBUG_ENABLE
}

/*
 * PendSV is used to perform a context switch. This is a recommended method for Cortex-M3/M4.
 * This is because the Cortex-M3/M4 automatically saves half of the processor context
 * on any exception, and restores same on return from exception.  So only saving of R4-R11
 * and fixing up the stack pointers is required.  Using the PendSV exception this way means
 * that context saving and restoring is identical whether it is initiated from a thread
 * or occurs due to an interrupt or exception.
 *
 * Since PendSV interrupt has the lowest priority in the system (set by os_start() below),
 * we can be sure that it will run only when no other exception or interrupt is active, and
 * therefore safe to assume that context being switched out was using the process stack (PSP).
 */

#if (defined __SOFTFP__)
// This function used for CPU without FPU (cortex-M3, cortex-M4)
extern "C" void PendSVC_ISR()
{
    asm volatile (
        "    CPSID   I                 \n" // Prevent interruption during context switch
        "    MRS     R0, PSP           \n" // PSP is process stack pointer
        "    STMDB   R0!, {R4-R11}     \n" // Save remaining regs r4-11 on process stack

        // At this point, entire context of process has been saved
        "    PUSH    {LR}              \n" // we must save LR (exc_return value) until exception return
        "    BL      os_context_switch_hook  \n" // call os_context_switch_hook();

        // R0 is new process SP;
        "    LDMIA   R0!, {R4-R11}     \n" // Restore r4-11 from new process stack
        "    MSR     PSP, R0           \n" // Load PSP with new process SP
        "    CPSIE   I                 \n"
        "    POP     {PC}              \n" // Return to saved exc_return. Exception return will restore remaining context
        : :
    );
}
#else // #if (defined __SOFTFP__)
// This function used for CPU with FPU (cortex-M4F)
extern "C" void PendSVC_ISR()
{
    asm volatile (
        "    CPSID     I                 \n" // Prevent interruption during context switch
        "    MRS       R0, PSP           \n" // PSP is process stack pointer
        "    TST       LR, #0x10         \n" // exc_return[4]=0? (it means that current process
        "    IT        EQ                \n" // has active floating point context)
        "    VSTMDBEQ  R0!, {S16-S31}    \n" // if so - save it.
        "    STMDB     R0!, {R4-R11, LR} \n" // save remaining regs r4-11 and LR on process stack

        // At this point, entire context of process has been saved
        "    BL        os_context_switch_hook  \n" // call os_context_switch_hook();

        // R0 is new process SP;
        "    LDMIA     R0!, {R4-R11, LR} \n" // Restore r4-11 and LR from new process stack
        "    TST       LR, #0x10         \n" // exc_return[4]=0? (it means that new process
        "    IT        EQ                \n" // has active floating point context)
        "    VLDMIAEQ  R0!, {S16-S31}    \n" // if so - restore it.
        "    MSR       PSP, R0           \n" // Load PSP with new process SP
        "    CPSIE     I                 \n"
        "    BX        LR                \n" // Return to saved exc_return. Exception return will restore remaining context
        : :
    );
}
#endif

/*
 * Some Cortex-M3/M4(F) registers and constants.
 */
namespace
{

template<uint32_t addr, typename type = uint32_t>
struct ioregister_t
{
	type operator=(type value) { *(volatile type*)addr = value; return value; }
	void operator|=(type value) { *(volatile type*)addr |= value; }
	void operator&=(type value) { *(volatile type*)addr &= value; }
	operator type() { return *(volatile type*)addr; }
};

template<uint32_t addr, class T>
struct iostruct_t
{
	volatile T* operator->() { return (volatile T*)addr; }
};

// PendSV and SysTick priority registers
static ioregister_t<0xE000ED22UL, uint8_t> PendSvPriority;
static ioregister_t<0xE000ED23UL, uint8_t> SysTickPriority;

// SysTick stuff
struct systick_t
{
    uint32_t       CTRL;
	uint32_t       LOAD;
  	uint32_t       VAL;
  	uint32_t const CALIB;
};

enum
{
    NVIC_ST_CTRL_CLK_SRC = 0x00000004,       // Clock Source.
    NVIC_ST_CTRL_INTEN   = 0x00000002,       // Interrupt enable.
    NVIC_ST_CTRL_ENABLE  = 0x00000001        // Counter mode.
};

systick_t volatile * const SysTick = (systick_t volatile * const)0xE000E010UL;

// Floating point context control register stuff
static ioregister_t<0xE000EF34UL> FPCCR;
enum
{
	ASPEN =   (0x1UL << 31),  // always save enable
	LSPEN =   (0x1UL << 30)   // lazy save enable
};

}

/*
 * System timer stuff.
 * This is the default (weak) system timer ISR handler.
 * The user can redefine this handler if needed.
 */
#pragma weak SystemTimer_ISR = Default_SystemTimer_ISR
namespace OS
{
extern "C" OS_INTERRUPT void Default_SystemTimer_ISR()
{
    scmRTOS_ISRW_TYPE ISR;

#if scmRTOS_SYSTIMER_HOOK_ENABLE == 1
    system_timer_user_hook();
#endif

    Kernel.system_timer();

#if scmRTOS_SYSTIMER_NEST_INTS_ENABLE == 0
    DISABLE_NESTED_INTERRUPTS();
#endif
}
}

/*
 * Default system timer initialization.
 *
 * Sets SysTick timer interrupt priority to lowest.
 * Configures SysTick timer to interrupt with frequency SYSTICKINTRATE.
 */
#pragma weak __init_system_timer
extern "C" void __init_system_timer()
{
	SysTickPriority = 0xFF;
	SysTick->LOAD = SYSTICKFREQ/SYSTICKINTRATE-1;
	SysTick->CTRL = NVIC_ST_CTRL_CLK_SRC | NVIC_ST_CTRL_INTEN | NVIC_ST_CTRL_ENABLE;
}

/*
 *   START MULTITASKING
 *
 * Note(s) : 1) os_start() MUST:
 *              a) Setup PendSV and SysTick exception priority to lowest;
 *              b) Call System timer initialization function;
 *              c) Enable interrupts (tasks will run with interrupts enabled);
 *              d) Jump to entry point of the highest priority process.
 */
extern "C" NORETURN void os_start(stack_item_t *sp)
{
	PendSvPriority = 0xFF;     // PendSV priority value (lowest)
#if (!defined __SOFTFP__)
    FPCCR |= ASPEN | LSPEN;    // move this to os_start
#endif

    asm volatile (
#if (defined __SOFTFP__)  // code without FPU
        "    LDR     R4, [%[stack], #(4 * 14)] \n" // Load process entry point into R4
        "    ADD     %[stack], #(4 * 16)       \n" // emulate context restore
#else
    	"    LDR     R4, [%[stack], #(4 * 15)] \n" // Load process entry point into R4
        "    ADD     %[stack], #(4 * 17)       \n" // emulate context restore
#endif
        "    MSR     PSP, %[stack]             \n" // store process SP to PSP
        "    MOV     R0, #2                    \n" // set up the current (thread) mode: use PSP as stack pointer, privileged level
        "    MSR     CONTROL, R0               \n"
        "    ISB                               \n" // Insert a barrier
   	    "    BL      __init_system_timer       \n" // run system timer
   	    "    CPSIE   I                         \n" // Enable interrupts at processor level
   	    "    BX      R4                        \n" // Jump to process exec() function
        : [stack]"+r" (sp)  // output
    );
    __builtin_unreachable(); // suppress compiler warning "'noreturn' func does return"
}
<commit_msg>Cortex-M4F/GCC port: TBaseProcess::init_stack_frame() - make stack alignment more accurate  (save up to 4 bytes of RAM per process)<commit_after>//******************************************************************************
//*
//*     FULLNAME:  Single-Chip Microcontroller Real-Time Operating System
//*
//*     NICKNAME:  scmRTOS
//*
//*     PROCESSOR: ARM Cortex-M4(F)
//*
//*     TOOLKIT:   ARM GCC
//*
//*     PURPOSE:   Target Dependent Stuff Source
//*
//*     Version: 4.00
//*
//*     $Revision$
//*     $Date::             $
//*
//*     Copyright (c) 2003-2012, Harry E. Zhurov
//*
//*     Permission is hereby granted, free of charge, to any person
//*     obtaining  a copy of this software and associated documentation
//*     files (the "Software"), to deal in the Software without restriction,
//*     including without limitation the rights to use, copy, modify, merge,
//*     publish, distribute, sublicense, and/or sell copies of the Software,
//*     and to permit persons to whom the Software is furnished to do so,
//*     subject to the following conditions:
//*
//*     The above copyright notice and this permission notice shall be included
//*     in all copies or substantial portions of the Software.
//*
//*     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//*     EXPRESS  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
//*     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
//*     IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
//*     CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
//*     TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
//*     THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//*
//*     =================================================================
//*     See http://scmrtos.sourceforge.net for documentation, latest
//*     information, license and contact details.
//*     =================================================================
//*
//******************************************************************************
//*     Cortex-M4(F) GCC port by Anton B. Gusev aka AHTOXA, Copyright (c) 2012

#include <scmRTOS.h>

using namespace OS;

namespace{
enum {
#if (defined __SOFTFP__)
    CONTEXT_SIZE = 16 * sizeof(stack_item_t)   // Cortex-M3/M4 context size
#else
    CONTEXT_SIZE = 17 * sizeof(stack_item_t)   // Cortex-M4F initial context size
#endif
};
}

void TBaseProcess::init_stack_frame( stack_item_t * Stack
                                   , void (*exec)()
                                #if scmRTOS_DEBUG_ENABLE == 1
                                   , stack_item_t * StackBegin
                                #endif
                                   )
{
    /*
     * ARM Architecture Procedure Call Standard [AAPCS] requires 8-byte stack alignment.
     * This means that we must get top of stack aligned _after_ context "pushing", at
     * interrupt entry.
     */
    uintptr_t sptr = (((uintptr_t)Stack - CONTEXT_SIZE) & 0xFFFFFFF8UL) + CONTEXT_SIZE;
    StackPointer = (stack_item_t*)sptr;

    *(--StackPointer)  = 0x01000000UL;      // xPSR
    *(--StackPointer)  = reinterpret_cast<uint32_t>(exec); // Entry Point
#if (defined __SOFTFP__)
    StackPointer -= 14;                     // emulate "push LR,R12,R3,R2,R1,R0,R11-R4"
#else
    StackPointer -= 6;                      // emulate "push LR,R12,R3,R2,R1,R0"
    *(--StackPointer)  = 0xFFFFFFFDUL;      // exc_return: Return to Thread mode, floating-point context inactive, execution uses PSP after return.
    StackPointer -= 8;                      // emulate "push R4-R11"
#endif

#if scmRTOS_DEBUG_ENABLE == 1
    for (stack_item_t* pDst = StackBegin; pDst < StackPointer; pDst++)
        *pDst = STACK_DEFAULT_PATTERN;
#endif // scmRTOS_DEBUG_ENABLE
}

/*
 * PendSV is used to perform a context switch. This is a recommended method for Cortex-M3/M4.
 * This is because the Cortex-M3/M4 automatically saves half of the processor context
 * on any exception, and restores same on return from exception.  So only saving of R4-R11
 * and fixing up the stack pointers is required.  Using the PendSV exception this way means
 * that context saving and restoring is identical whether it is initiated from a thread
 * or occurs due to an interrupt or exception.
 *
 * Since PendSV interrupt has the lowest priority in the system (set by os_start() below),
 * we can be sure that it will run only when no other exception or interrupt is active, and
 * therefore safe to assume that context being switched out was using the process stack (PSP).
 */

#if (defined __SOFTFP__)
// This function used for CPU without FPU (cortex-M3, cortex-M4)
extern "C" void PendSVC_ISR()
{
    asm volatile (
        "    CPSID   I                 \n" // Prevent interruption during context switch
        "    MRS     R0, PSP           \n" // PSP is process stack pointer
        "    STMDB   R0!, {R4-R11}     \n" // Save remaining regs r4-11 on process stack

        // At this point, entire context of process has been saved
        "    PUSH    {LR}              \n" // we must save LR (exc_return value) until exception return
        "    BL      os_context_switch_hook  \n" // call os_context_switch_hook();

        // R0 is new process SP;
        "    LDMIA   R0!, {R4-R11}     \n" // Restore r4-11 from new process stack
        "    MSR     PSP, R0           \n" // Load PSP with new process SP
        "    CPSIE   I                 \n"
        "    POP     {PC}              \n" // Return to saved exc_return. Exception return will restore remaining context
        : :
    );
}
#else // #if (defined __SOFTFP__)
// This function used for CPU with FPU (cortex-M4F)
extern "C" void PendSVC_ISR()
{
    asm volatile (
        "    CPSID     I                 \n" // Prevent interruption during context switch
        "    MRS       R0, PSP           \n" // PSP is process stack pointer
        "    TST       LR, #0x10         \n" // exc_return[4]=0? (it means that current process
        "    IT        EQ                \n" // has active floating point context)
        "    VSTMDBEQ  R0!, {S16-S31}    \n" // if so - save it.
        "    STMDB     R0!, {R4-R11, LR} \n" // save remaining regs r4-11 and LR on process stack

        // At this point, entire context of process has been saved
        "    BL        os_context_switch_hook  \n" // call os_context_switch_hook();

        // R0 is new process SP;
        "    LDMIA     R0!, {R4-R11, LR} \n" // Restore r4-11 and LR from new process stack
        "    TST       LR, #0x10         \n" // exc_return[4]=0? (it means that new process
        "    IT        EQ                \n" // has active floating point context)
        "    VLDMIAEQ  R0!, {S16-S31}    \n" // if so - restore it.
        "    MSR       PSP, R0           \n" // Load PSP with new process SP
        "    CPSIE     I                 \n"
        "    BX        LR                \n" // Return to saved exc_return. Exception return will restore remaining context
        : :
    );
}
#endif

/*
 * Some Cortex-M3/M4(F) registers and constants.
 */
namespace
{

template<uint32_t addr, typename type = uint32_t>
struct ioregister_t
{
	type operator=(type value) { *(volatile type*)addr = value; return value; }
	void operator|=(type value) { *(volatile type*)addr |= value; }
	void operator&=(type value) { *(volatile type*)addr &= value; }
	operator type() { return *(volatile type*)addr; }
};

template<uint32_t addr, class T>
struct iostruct_t
{
	volatile T* operator->() { return (volatile T*)addr; }
};

// PendSV and SysTick priority registers
static ioregister_t<0xE000ED22UL, uint8_t> PendSvPriority;
static ioregister_t<0xE000ED23UL, uint8_t> SysTickPriority;

// SysTick stuff
struct systick_t
{
    uint32_t       CTRL;
	uint32_t       LOAD;
  	uint32_t       VAL;
  	uint32_t const CALIB;
};

enum
{
    NVIC_ST_CTRL_CLK_SRC = 0x00000004,       // Clock Source.
    NVIC_ST_CTRL_INTEN   = 0x00000002,       // Interrupt enable.
    NVIC_ST_CTRL_ENABLE  = 0x00000001        // Counter mode.
};

systick_t volatile * const SysTick = (systick_t volatile * const)0xE000E010UL;

#if (!defined __SOFTFP__)
// Floating point context control register stuff
static ioregister_t<0xE000EF34UL> FPCCR;
enum
{
	ASPEN =   (0x1UL << 31),  // always save enable
	LSPEN =   (0x1UL << 30)   // lazy save enable
};
#endif

}

/*
 * System timer stuff.
 * This is the default (weak) system timer ISR handler.
 * The user can redefine this handler if needed.
 */
#pragma weak SystemTimer_ISR = Default_SystemTimer_ISR
namespace OS
{
extern "C" OS_INTERRUPT void Default_SystemTimer_ISR()
{
    scmRTOS_ISRW_TYPE ISR;

#if scmRTOS_SYSTIMER_HOOK_ENABLE == 1
    system_timer_user_hook();
#endif

    Kernel.system_timer();

#if scmRTOS_SYSTIMER_NEST_INTS_ENABLE == 0
    DISABLE_NESTED_INTERRUPTS();
#endif
}
}

/*
 * Default system timer initialization.
 *
 * Sets SysTick timer interrupt priority to lowest.
 * Configures SysTick timer to interrupt with frequency SYSTICKINTRATE.
 */
#pragma weak __init_system_timer
extern "C" void __init_system_timer()
{
	SysTickPriority = 0xFF;
	SysTick->LOAD = SYSTICKFREQ/SYSTICKINTRATE-1;
	SysTick->CTRL = NVIC_ST_CTRL_CLK_SRC | NVIC_ST_CTRL_INTEN | NVIC_ST_CTRL_ENABLE;
}

/*
 *   START MULTITASKING
 *
 * Note(s) : 1) os_start() MUST:
 *              a) Setup PendSV and SysTick exception priority to lowest;
 *              b) Call System timer initialization function;
 *              c) Enable interrupts (tasks will run with interrupts enabled);
 *              d) Jump to entry point of the highest priority process.
 */
extern "C" NORETURN void os_start(stack_item_t *sp)
{
	PendSvPriority = 0xFF;     // PendSV priority value (lowest)
#if (!defined __SOFTFP__)
    FPCCR |= ASPEN | LSPEN;    // move this to os_start
#endif

    asm volatile (
#if (defined __SOFTFP__)  // code without FPU
        "    LDR     R4, [%[stack], #(4 * 14)] \n" // Load process entry point into R4
        "    ADD     %[stack], #(4 * 16)       \n" // emulate context restore
#else
    	"    LDR     R4, [%[stack], #(4 * 15)] \n" // Load process entry point into R4
        "    ADD     %[stack], #(4 * 17)       \n" // emulate context restore
#endif
        "    MSR     PSP, %[stack]             \n" // store process SP to PSP
        "    MOV     R0, #2                    \n" // set up the current (thread) mode: use PSP as stack pointer, privileged level
        "    MSR     CONTROL, R0               \n"
        "    ISB                               \n" // Insert a barrier
   	    "    BL      __init_system_timer       \n" // run system timer
   	    "    CPSIE   I                         \n" // Enable interrupts at processor level
   	    "    BX      R4                        \n" // Jump to process exec() function
        : [stack]"+r" (sp)  // output
    );
    __builtin_unreachable(); // suppress compiler warning "'noreturn' func does return"
}
<|endoftext|>


<commit_before>/**
  * @file EventoHistorico.hpp
  * @brief Fichero cabecera del TDA EventoHistorico
  *
  */

#ifndef EVENTO_HISTORICO
#define EVENTO_HISTORICO

#include <iostream>
#include <vector>

struct Fecha{
  int anio;
  bool dc;
};

typedef std::string Acontecimiento;

class EventoHistorico{
private:
  Fecha f;
  std::vector<Acontecimiento> evento;

public:
  //Constructores
  EventoHistorico();
  EventoHistorico(int f);
  EventoHistorico(int f, std::vector<Acontecimiento> v);

  //Set Get
  int getFecha();
  std::vector<Acontecimiento> getEvento();
  void setFecha(int f);
  void setEvento(std::vector<Acontecimiento> v);
  void addEvento(Acontecimiento a);
  void addEvento(std::vector<Acontecimiento> evento);

  //Eliminar
  bool eliminarAcontecimiento(Acontecimiento a);
  bool eliminar(std::string key);

  //Busqueda
  std::vector<Acontecimiento> buscarAcontecimientos(std::string key); //Busca acontecimientos que contienen

  //Entrada Salida
  std::ostream& mostrarEvento(std::ostream& os) const;
  std::istream& leerEvento(std::istream& is); //Haria falta añadir algun parametro para saber como leer?

};

#endif
<commit_msg>Minor Update<commit_after>/**
  * @file EventoHistorico.hpp
  * @brief Fichero cabecera del TDA EventoHistorico
  *
  */

#ifndef EVENTO_HISTORICO
#define EVENTO_HISTORICO

#include <iostream>
#include <vector>

//Definimos el struct fecha que incluye el año que siempre es positivo y un booleano para saber si es ac/dc
struct Fecha{
  int anio;
  bool dc;
};

typedef std::string Acontecimiento; //Llamamos acontecimiento a un string que va a contener su nombre

class EventoHistorico{

private:
  Fecha f;
  std::vector<Acontecimiento> evento;

  std::vector<Acontecimiento>::iterator busquedaAcontecimiento(Acontecimiento a);

public:
  //Constructores
  EventoHistorico();
  EventoHistorico(int f);
  EventoHistorico(int f, std::vector<Acontecimiento> v);

  //Set Get
  int getFecha();
  std::vector<Acontecimiento> getEvento();
  void setFecha(int f);
  void setEvento(std::vector<Acontecimiento> v);
  void addEvento(Acontecimiento a);
  void addEvento(std::vector<Acontecimiento> evento);

  //Eliminar
  bool eliminarAcontecimiento(Acontecimiento a);
  bool eliminar(std::string key);

  //Busqueda
  std::vector<Acontecimiento> buscarAcontecimientos(std::string key); //Busca acontecimientos que contienen la palabra clave "key"

  //Entrada Salida
  std::ostream& mostrarEvento(std::ostream& os) const;
  std::istream& leerEvento(std::istream& is);
  std::ostream& prettyPrint(std::ostream& os) const;

};

#endif
<|endoftext|>


<commit_before>/*
 * datasetplane.cpp
 *
 *  Created on: Apr 10, 2014
 *      Author: schurade
 */

#include "datasetplane.h"

#include "../models.h"

#include "../../gui/gl/glfunctions.h"

#include <QtOpenGL/QGLShaderProgram>
#include <QVector3D>

DatasetPlane::DatasetPlane() :
    Dataset( QDir( "new plane" ), Fn::DatasetType::PLANE ),
    vbo0( 0 ),
    m_handle0( GLFunctions::getPickIndex() ),
    m_handle1( GLFunctions::getPickIndex() ),
    m_handle2( GLFunctions::getPickIndex() ),
    dirty( true )
{
    QList<Dataset*>dsl = Models::getDatasets( Fn::DatasetType::NIFTI_ANY );

    int nx = 160;
    int ny = 200;
    int nz = 160;
    float dx = 1.0f;
    float dy = 1.0f;
    float dz = 1.0f;
    float ax = 0.0f;
    float ay = 0.0f;
    float az = 0.0f;
    if ( dsl.size() > 0 )
    {
        nx = dsl[0]->properties().get( Fn::Property::D_NX ).toInt();
        ny = dsl[0]->properties().get( Fn::Property::D_NY ).toInt();
        nz = dsl[0]->properties().get( Fn::Property::D_NZ ).toInt();
        dx = dsl[0]->properties().get( Fn::Property::D_DX ).toFloat();
        dy = dsl[0]->properties().get( Fn::Property::D_DY ).toFloat();
        dz = dsl[0]->properties().get( Fn::Property::D_DZ ).toFloat();
        ax = dsl[0]->properties().get( Fn::Property::D_ADJUST_X ).toFloat();
        ay = dsl[0]->properties().get( Fn::Property::D_ADJUST_Y ).toFloat();
        az = dsl[0]->properties().get( Fn::Property::D_ADJUST_Z ).toFloat();
    }

    QVector3D h0( nx * dx / 2 + ax, ny * dy / 2 + ay, nz * dz / 2 + az );
    QVector3D h1( ax, h0.y(), h0.z() );
    QVector3D h2( h0.x(), ay, h0.z() );

    m_properties["maingl"].createBool( Fn::Property::D_SHOW_PLANE_HANDLES, true, "general" );
    m_properties["maingl"].createColor( Fn::Property::D_HANDLE_COLOR, QColor( 255, 0, 0 ), "general" );

    m_properties["maingl"].createVector( Fn::Property::D_HANDLE_0, h0, "handles" );
    m_properties["maingl"].createVector( Fn::Property::D_HANDLE_1, h1, "handles" );
    m_properties["maingl"].createVector( Fn::Property::D_HANDLE_2, h2, "handles" );

    PropertyGroup props2( m_properties["maingl"] );
    m_properties.insert( "maingl2", props2 );
    m_properties["maingl2"].createBool( Fn::Property::D_SHOW_PLANE_HANDLES, true, "general" );
    m_properties["maingl2"].createColor( Fn::Property::D_HANDLE_COLOR, QColor( 255, 0, 0 ), "general" );
}

DatasetPlane::~DatasetPlane()
{
}

void DatasetPlane::draw( QMatrix4x4 pMatrix, QMatrix4x4 mvMatrix, int width, int height, int renderMode, QString target )
{
    if ( !properties( target ).get( Fn::Property::D_ACTIVE ).toBool() )
    {
        return;
    }

    QVector3D h0 = m_properties["maingl"].get( Fn::Property::D_HANDLE_0 ).value<QVector3D>();
    QVector3D h1 = m_properties["maingl"].get( Fn::Property::D_HANDLE_1 ).value<QVector3D>();
    QVector3D h2 = m_properties["maingl"].get( Fn::Property::D_HANDLE_2 ).value<QVector3D>();

    if ( m_properties["maingl"].get( Fn::Property::D_SHOW_PLANE_HANDLES ).toBool() )
    {
        QColor color = m_properties["maingl"].get( Fn::Property::D_HANDLE_COLOR ).value<QColor>();
        color.setAlpha( 254 );
        GLFunctions::renderSphere( pMatrix, mvMatrix, h0.x(), h0.y(), h0.z(), 5, 5, 5,
                                  color, m_handle0, width, height, renderMode );
        GLFunctions::renderSphere( pMatrix, mvMatrix, h1.x(), h1.y(), h1.z(), 5, 5, 5,
                                  color, m_handle1, width, height, renderMode );
        GLFunctions::renderSphere( pMatrix, mvMatrix, h2.x(), h2.y(), h2.z(), 5, 5, 5,
                                  color, m_handle2, width, height, renderMode );
    }

    if ( dirty )
    {
        initGeometry();
    }

    float alpha = GLFunctions::sliceAlpha[target];

    switch ( renderMode )
    {
        case 0:
            break;
        case 1:
        {
            if ( alpha < 1.0 ) // obviously not opaque
            {
                return;
            }
            break;
        }
        default:
        {
            if ( alpha == 1.0  ) // not transparent
            {
                return;
            }
            break;
        }
    }

    if ( !GLFunctions::setupTextures() )
    {
        return;
    }
    QGLShaderProgram* program = GLFunctions::getShader( "slice" );

    program->bind();
    GLFunctions::f->glBindBuffer( GL_ARRAY_BUFFER, vbo0 );

    intptr_t offset = 0;
    // Tell OpenGL programmable pipeline how to locate vertex position data
    int vertexLocation = program->attributeLocation( "a_position" );
    program->enableAttributeArray( vertexLocation );
    GLFunctions::f->glVertexAttribPointer( vertexLocation, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, (const void *) offset );

    // Set modelview-projection matrix
    program->setUniformValue( "mvp_matrix", pMatrix * mvMatrix );

    program->setUniformValue( "u_alpha", alpha );
    program->setUniformValue( "u_renderMode", renderMode );
    program->setUniformValue( "u_canvasSize", width, height );
    program->setUniformValue( "D0", 9 );
    program->setUniformValue( "D1", 10 );
    program->setUniformValue( "D2", 11 );
    program->setUniformValue( "P0", 12 );

    GLFunctions::setTextureUniforms( program, target );

    // Draw cube geometry using indices from VBO 0
    glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
    GLFunctions::f->glBindBuffer( GL_ARRAY_BUFFER, 0 );

}
void DatasetPlane::initGeometry()
{
    if( vbo0 )
    {
        GLFunctions::f->glDeleteBuffers( 1, &vbo0 );
    }
    GLFunctions::f->glGenBuffers( 1, &vbo0 );

    QVector3D h0 = m_properties["maingl"].get( Fn::Property::D_HANDLE_0 ).value<QVector3D>();
    QVector3D h1 = m_properties["maingl"].get( Fn::Property::D_HANDLE_1 ).value<QVector3D>();
    QVector3D h2 = m_properties["maingl"].get( Fn::Property::D_HANDLE_2 ).value<QVector3D>();

    QVector3D d1 = ( h0 - h1 );
    QVector3D d2 = ( h0 - h2 );

    QVector3D h1m = h0 + d1;
    QVector3D h2m = h0 + d2;

     QVector3D e0 = h2 - d1;
     QVector3D e1 = h2m - d1;
     QVector3D e2 = h2m + d1;
     QVector3D e3 = h2 + d1;

    float x0 = e0.x();
    float y0 = e0.y();
    float z0 = e0.z();

    float x1 = e1.x();
    float y1 = e1.y();
    float z1 = e1.z();

    float x2 = e2.x();
    float y2 = e2.y();
    float z2 = e2.z();

    float x3 = e3.x();
    float y3 = e3.y();
    float z3 = e3.z();

    float vertices[] =
    {
        x0, y0, z0,
        x1, y1, z1,
        x3, y3, z3,
        x2, y2, z2,
    };

    // Transfer vertex data to VBO 1
    GLFunctions::f->glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, vbo0 );
    GLFunctions::f->glBufferData( GL_ELEMENT_ARRAY_BUFFER, 4 * 3 * sizeof(GLfloat), vertices, GL_STATIC_DRAW );
    GLFunctions::f->glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );

    dirty = false;
}

bool DatasetPlane::rightMouseDrag( int pickId, QVector3D dir, Qt::KeyboardModifiers modifiers, QString target )
{
    QVector3D h0 = m_properties["maingl"].get( Fn::Property::D_HANDLE_0 ).value<QVector3D>();
    QVector3D h1 = m_properties["maingl"].get( Fn::Property::D_HANDLE_1 ).value<QVector3D>();
    QVector3D h2 = m_properties["maingl"].get( Fn::Property::D_HANDLE_2 ).value<QVector3D>();

    float dist1 = ( h0 - h1 ).length();
    float dist2 = ( h0 - h2 ).length();

    if ( pickId == m_handle0 )
    {
        h0.setX( h0.x() + dir.x() );
        h0.setY( h0.y() + dir.y() );
        h0.setZ( h0.z() + dir.z() );
        h1.setX( h1.x() + dir.x() );
        h1.setY( h1.y() + dir.y() );
        h1.setZ( h1.z() + dir.z() );
        h2.setX( h2.x() + dir.x() );
        h2.setY( h2.y() + dir.y() );
        h2.setZ( h2.z() + dir.z() );

        m_properties["maingl"].set( Fn::Property::D_HANDLE_0, h0 );
        m_properties["maingl"].set( Fn::Property::D_HANDLE_1, h1 );
        m_properties["maingl"].set( Fn::Property::D_HANDLE_2, h2 );

        dirty = true;
        return true;
    }
    else if ( pickId == m_handle1 )
    {
        QVector3D d1 = QVector3D::crossProduct( ( h0 - h1 ).normalized(), ( h0 - h2 ).normalized() );
        float dist = dir.length();
        int neg = 1;
        if ( QVector3D::dotProduct( d1, dir ) < 0 )
        {
            neg = -1;
        }

        h1.setX( h1.x() + d1.x() * dist * neg );
        h1.setY( h1.y() + d1.y() * dist * neg );
        h1.setZ( h1.z() + d1.z() * dist * neg  );

        QVector3D e1 = ( h1 - h0 ).normalized();
        h1.setX( h0.x() + e1.x() * dist1 );
        h1.setY( h0.y() + e1.y() * dist1 );
        h1.setZ( h0.z() + e1.z() * dist1 );

        m_properties["maingl"].set( Fn::Property::D_HANDLE_1, h1 );
        dirty = true;
        return true;
    }
    else if ( pickId == m_handle2 )
    {
        QVector3D d1 = QVector3D::crossProduct( ( h0 - h1 ).normalized(), ( h0 - h2 ).normalized() );
        float dist = dir.length();
        int neg = 1;
        if ( QVector3D::dotProduct( d1, dir ) < 0 )
        {
            neg = -1;
        }
        h2.setX( h2.x() + d1.x() * dist * neg );
        h2.setY( h2.y() + d1.y() * dist * neg );
        h2.setZ( h2.z() + d1.z() * dist * neg  );

        QVector3D e2 = ( h2 - h0 ).normalized();
        h2.setX( h0.x() + e2.x() * dist2 );
        h2.setY( h0.y() + e2.y() * dist2 );
        h2.setZ( h0.z() + e2.z() * dist2 );

        m_properties["maingl"].set( Fn::Property::D_HANDLE_2, h2 );
        dirty = true;
        return true;
    }

    return false;
}
<commit_msg>improved plane handles, added shift movement to adjust distance from center point<commit_after>/*
 * datasetplane.cpp
 *
 *  Created on: Apr 10, 2014
 *      Author: schurade
 */

#include "datasetplane.h"

#include "../models.h"

#include "../../gui/gl/glfunctions.h"

#include <QtOpenGL/QGLShaderProgram>
#include <QVector3D>

DatasetPlane::DatasetPlane() :
    Dataset( QDir( "new plane" ), Fn::DatasetType::PLANE ),
    vbo0( 0 ),
    m_handle0( GLFunctions::getPickIndex() ),
    m_handle1( GLFunctions::getPickIndex() ),
    m_handle2( GLFunctions::getPickIndex() ),
    dirty( true )
{
    QList<Dataset*>dsl = Models::getDatasets( Fn::DatasetType::NIFTI_ANY );

    int nx = 160;
    int ny = 200;
    int nz = 160;
    float dx = 1.0f;
    float dy = 1.0f;
    float dz = 1.0f;
    float ax = 0.0f;
    float ay = 0.0f;
    float az = 0.0f;
    if ( dsl.size() > 0 )
    {
        nx = dsl[0]->properties().get( Fn::Property::D_NX ).toInt();
        ny = dsl[0]->properties().get( Fn::Property::D_NY ).toInt();
        nz = dsl[0]->properties().get( Fn::Property::D_NZ ).toInt();
        dx = dsl[0]->properties().get( Fn::Property::D_DX ).toFloat();
        dy = dsl[0]->properties().get( Fn::Property::D_DY ).toFloat();
        dz = dsl[0]->properties().get( Fn::Property::D_DZ ).toFloat();
        ax = dsl[0]->properties().get( Fn::Property::D_ADJUST_X ).toFloat();
        ay = dsl[0]->properties().get( Fn::Property::D_ADJUST_Y ).toFloat();
        az = dsl[0]->properties().get( Fn::Property::D_ADJUST_Z ).toFloat();
    }

    QVector3D h0( nx * dx / 2 + ax, ny * dy / 2 + ay, nz * dz / 2 + az );
    QVector3D h1( ax, h0.y(), h0.z() );
    QVector3D h2( h0.x(), ay, h0.z() );

    m_properties["maingl"].createBool( Fn::Property::D_SHOW_PLANE_HANDLES, true, "general" );
    m_properties["maingl"].createColor( Fn::Property::D_HANDLE_COLOR, QColor( 255, 0, 0 ), "general" );

    m_properties["maingl"].createVector( Fn::Property::D_HANDLE_0, h0, "handles" );
    m_properties["maingl"].createVector( Fn::Property::D_HANDLE_1, h1, "handles" );
    m_properties["maingl"].createVector( Fn::Property::D_HANDLE_2, h2, "handles" );

    PropertyGroup props2( m_properties["maingl"] );
    m_properties.insert( "maingl2", props2 );
    m_properties["maingl2"].createBool( Fn::Property::D_SHOW_PLANE_HANDLES, true, "general" );
    m_properties["maingl2"].createColor( Fn::Property::D_HANDLE_COLOR, QColor( 255, 0, 0 ), "general" );
}

DatasetPlane::~DatasetPlane()
{
}

void DatasetPlane::draw( QMatrix4x4 pMatrix, QMatrix4x4 mvMatrix, int width, int height, int renderMode, QString target )
{
    if ( !properties( target ).get( Fn::Property::D_ACTIVE ).toBool() )
    {
        return;
    }

    QVector3D h0 = m_properties["maingl"].get( Fn::Property::D_HANDLE_0 ).value<QVector3D>();
    QVector3D h1 = m_properties["maingl"].get( Fn::Property::D_HANDLE_1 ).value<QVector3D>();
    QVector3D h2 = m_properties["maingl"].get( Fn::Property::D_HANDLE_2 ).value<QVector3D>();

    if ( m_properties["maingl"].get( Fn::Property::D_SHOW_PLANE_HANDLES ).toBool() )
    {
        QColor color = m_properties["maingl"].get( Fn::Property::D_HANDLE_COLOR ).value<QColor>();
        color.setAlpha( 254 );
        GLFunctions::renderSphere( pMatrix, mvMatrix, h0.x(), h0.y(), h0.z(), 5, 5, 5,
                                  color, m_handle0, width, height, renderMode );
        GLFunctions::renderSphere( pMatrix, mvMatrix, h1.x(), h1.y(), h1.z(), 5, 5, 5,
                                  color, m_handle1, width, height, renderMode );
        GLFunctions::renderSphere( pMatrix, mvMatrix, h2.x(), h2.y(), h2.z(), 5, 5, 5,
                                  color, m_handle2, width, height, renderMode );
    }

    if ( dirty )
    {
        initGeometry();
    }

    float alpha = GLFunctions::sliceAlpha[target];

    switch ( renderMode )
    {
        case 0:
            break;
        case 1:
        {
            if ( alpha < 1.0 ) // obviously not opaque
            {
                return;
            }
            break;
        }
        default:
        {
            if ( alpha == 1.0  ) // not transparent
            {
                return;
            }
            break;
        }
    }

    if ( !GLFunctions::setupTextures() )
    {
        return;
    }
    QGLShaderProgram* program = GLFunctions::getShader( "slice" );

    program->bind();
    GLFunctions::f->glBindBuffer( GL_ARRAY_BUFFER, vbo0 );

    intptr_t offset = 0;
    // Tell OpenGL programmable pipeline how to locate vertex position data
    int vertexLocation = program->attributeLocation( "a_position" );
    program->enableAttributeArray( vertexLocation );
    GLFunctions::f->glVertexAttribPointer( vertexLocation, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, (const void *) offset );

    // Set modelview-projection matrix
    program->setUniformValue( "mvp_matrix", pMatrix * mvMatrix );

    program->setUniformValue( "u_alpha", alpha );
    program->setUniformValue( "u_renderMode", renderMode );
    program->setUniformValue( "u_canvasSize", width, height );
    program->setUniformValue( "D0", 9 );
    program->setUniformValue( "D1", 10 );
    program->setUniformValue( "D2", 11 );
    program->setUniformValue( "P0", 12 );

    GLFunctions::setTextureUniforms( program, target );

    // Draw cube geometry using indices from VBO 0
    glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
    GLFunctions::f->glBindBuffer( GL_ARRAY_BUFFER, 0 );

}
void DatasetPlane::initGeometry()
{
    if( vbo0 )
    {
        GLFunctions::f->glDeleteBuffers( 1, &vbo0 );
    }
    GLFunctions::f->glGenBuffers( 1, &vbo0 );

    QVector3D h0 = m_properties["maingl"].get( Fn::Property::D_HANDLE_0 ).value<QVector3D>();
    QVector3D h1 = m_properties["maingl"].get( Fn::Property::D_HANDLE_1 ).value<QVector3D>();
    QVector3D h2 = m_properties["maingl"].get( Fn::Property::D_HANDLE_2 ).value<QVector3D>();

    QVector3D d1 = ( h0 - h1 );
    QVector3D d2 = ( h0 - h2 );

    QVector3D h1m = h0 + d1;
    QVector3D h2m = h0 + d2;

     QVector3D e0 = h2 - d1;
     QVector3D e1 = h2m - d1;
     QVector3D e2 = h2m + d1;
     QVector3D e3 = h2 + d1;

    float x0 = e0.x();
    float y0 = e0.y();
    float z0 = e0.z();

    float x1 = e1.x();
    float y1 = e1.y();
    float z1 = e1.z();

    float x2 = e2.x();
    float y2 = e2.y();
    float z2 = e2.z();

    float x3 = e3.x();
    float y3 = e3.y();
    float z3 = e3.z();

    float vertices[] =
    {
        x0, y0, z0,
        x1, y1, z1,
        x3, y3, z3,
        x2, y2, z2,
    };

    // Transfer vertex data to VBO 1
    GLFunctions::f->glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, vbo0 );
    GLFunctions::f->glBufferData( GL_ELEMENT_ARRAY_BUFFER, 4 * 3 * sizeof(GLfloat), vertices, GL_STATIC_DRAW );
    GLFunctions::f->glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );

    dirty = false;
}

bool DatasetPlane::rightMouseDrag( int pickId, QVector3D dir, Qt::KeyboardModifiers modifiers, QString target )
{
    QVector3D h0 = m_properties["maingl"].get( Fn::Property::D_HANDLE_0 ).value<QVector3D>();
    QVector3D h1 = m_properties["maingl"].get( Fn::Property::D_HANDLE_1 ).value<QVector3D>();
    QVector3D h2 = m_properties["maingl"].get( Fn::Property::D_HANDLE_2 ).value<QVector3D>();

    float dist1 = ( h0 - h1 ).length();
    float dist2 = ( h0 - h2 ).length();

    if ( pickId == m_handle0 )
    {
        h0.setX( h0.x() + dir.x() );
        h0.setY( h0.y() + dir.y() );
        h0.setZ( h0.z() + dir.z() );
        h1.setX( h1.x() + dir.x() );
        h1.setY( h1.y() + dir.y() );
        h1.setZ( h1.z() + dir.z() );
        h2.setX( h2.x() + dir.x() );
        h2.setY( h2.y() + dir.y() );
        h2.setZ( h2.z() + dir.z() );

        m_properties["maingl"].set( Fn::Property::D_HANDLE_0, h0 );
        m_properties["maingl"].set( Fn::Property::D_HANDLE_1, h1 );
        m_properties["maingl"].set( Fn::Property::D_HANDLE_2, h2 );

        dirty = true;
        return true;
    }
    else if ( pickId == m_handle1 )
    {
        QVector3D d1 = QVector3D::crossProduct( ( h0 - h1 ).normalized(), ( h0 - h2 ).normalized() );
        float dist = dir.length();
        int neg = 1;
        if ( QVector3D::dotProduct( d1, dir ) < 0 )
        {
            neg = -1;
        }

        if ( modifiers & Qt::ShiftModifier )
        {
            QVector3D e1 = ( h1 - h0 ).normalized();
            h1.setX( h1.x() + dir.x() );
            h1.setY( h1.y() + dir.y() );
            h1.setZ( h1.z() + dir.z()  );

            if ( ( h0 - h1 ).length() < dist1 )
            {
                h1.setX( h0.x() + e1.x() * ( dist1 - dist ) );
                h1.setY( h0.y() + e1.y() * ( dist1 - dist ) );
                h1.setZ( h0.z() + e1.z() * ( dist1 - dist ) );
            }
            else
            {
                h1.setX( h0.x() + e1.x() * ( dist1 + dist ) );
                h1.setY( h0.y() + e1.y() * ( dist1 + dist ) );
                h1.setZ( h0.z() + e1.z() * ( dist1 + dist ) );
            }
        }
        else
        {
            h1.setX( h1.x() + d1.x() * dist * neg );
            h1.setY( h1.y() + d1.y() * dist * neg );
            h1.setZ( h1.z() + d1.z() * dist * neg  );

            QVector3D e1 = ( h1 - h0 ).normalized();
            h1.setX( h0.x() + e1.x() * dist1 );
            h1.setY( h0.y() + e1.y() * dist1 );
            h1.setZ( h0.z() + e1.z() * dist1 );
        }

        m_properties["maingl"].set( Fn::Property::D_HANDLE_1, h1 );
        dirty = true;
        return true;
    }
    else if ( pickId == m_handle2 )
    {
        QVector3D d1 = QVector3D::crossProduct( ( h0 - h1 ).normalized(), ( h0 - h2 ).normalized() );
        float dist = dir.length();
        int neg = 1;
        if ( QVector3D::dotProduct( d1, dir ) < 0 )
        {
            neg = -1;
        }
        if ( modifiers & Qt::ShiftModifier )
        {
            QVector3D e2 = ( h2 - h0 ).normalized();
            h2.setX( h2.x() + dir.x() );
            h2.setY( h2.y() + dir.y() );
            h2.setZ( h2.z() + dir.z()  );

            if ( ( h0 - h2 ).length() < dist2 )
            {
                h2.setX( h0.x() + e2.x() * ( dist2 - dist ) );
                h2.setY( h0.y() + e2.y() * ( dist2 - dist ) );
                h2.setZ( h0.z() + e2.z() * ( dist2 - dist ) );
            }
            else
            {
                h2.setX( h0.x() + e2.x() * ( dist2 + dist ) );
                h2.setY( h0.y() + e2.y() * ( dist2 + dist ) );
                h2.setZ( h0.z() + e2.z() * ( dist2 + dist ) );
            }
        }
        else
        {
            h2.setX( h2.x() + d1.x() * dist * neg );
            h2.setY( h2.y() + d1.y() * dist * neg );
            h2.setZ( h2.z() + d1.z() * dist * neg  );

            QVector3D e2 = ( h2 - h0 ).normalized();
            h2.setX( h0.x() + e2.x() * dist2 );
            h2.setY( h0.y() + e2.y() * dist2 );
            h2.setZ( h0.z() + e2.z() * dist2 );
        }
        m_properties["maingl"].set( Fn::Property::D_HANDLE_2, h2 );
        dirty = true;
        return true;
    }

    return false;
}
<|endoftext|>


<commit_before>/*
 * C S O U N D
 *
 * L I C E N S E
 *
 * This software 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 software 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 software; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#ifndef LINDENMAYER_TO_SOUND_H
#define LINDENMAYER_TO_SOUND_H

#include "Platform.hpp"
#ifdef SWIG
%module CsoundAC
%include "std_string.i"
%include "std_vector.i"
%{
#include "Silence.hpp"
#include <stack>
#include <string>
#include <map>
#include <vector>
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/matrix.hpp>
  %}
#else
#include "Silence.hpp"
#include <stack>
#include <string>
#include <map>
#include <vector>
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/matrix.hpp>
using namespace boost::numeric;
#endif

namespace csound
{
  /**
   * This class implements a Lindenmayer system in music space
   * for a turtle that writes either notes into a score, or Jones-Parks grains into a memory soundfile.
   * The Z dimension of note space is used for chirp rate.
   * The actions of the turtle are rescaled to fit the specified bounding hypercube.
   * The turtle commands are represented by letters (all n default to 1):
   *

   *
G     = Write the current state of the turtle into the soundfile as a grain.

   *
Mn    = Translate the turtle by adding to its state its step times its orientation times n.

   *
Rabn  = Rotate the turtle from dimension a to dimension b by angle 2 pi / (angleCount * n)

   *
Uan   = Vary the turtle state on dimension a by a normalized (-1 through +1) uniformly distributed random variable times n.

   *
Gan   = Vary the turtle state on dimension a by a normalized (-1 through +1) Gaussian random variable times n.

   *
T=an  = Assign to dimension a of the turtle state the value n.

   *
T*an  = Multiply dimension a of the turtle state by n.

   *
T/an  = Divide dimension a of the turtle state by n.

   *
T+an  = Add to dimension a of the turtle state the value n.

   *
T-an  = Subtract from dimension a of the turtle state the value n.

   *
S=an  = Assign to dimension a of the turtle step the value n.

   *
S*an  = Multiply dimension a of the turtle step by n.

   *
S/an  = Divide dimension a of the turtle step by n.

   *
S+an  = Add to dimension a of the turtle step the value n.

   *
S-an  = Subtract from dimension a of the turtle step the value n.

   *
[     = Push the current state of the turtle state onto a stack.

   *
]     = Pop the current state of the turtle from the stack.

   *

   */
  class Lindenmayer :
    public ScoreNode
  {
  protected:
    int iterationCount;
    double angle;
    std::string axiom;
    Event turtle;
    Event turtleStep;
    Event turtleOrientation;
    std::map<std::string, std::string> rules;
    std::stack<Event> turtleStack;
    std::stack<Event> turtleStepStack;
    std::stack<Event> turtleOrientationStack;
    clock_t beganAt;
    clock_t endedAt;
    clock_t elapsed;
    virtual void interpret(std::string command, bool render);
    virtual int getDimension (char dimension) const;
    virtual void rewrite();
    virtual ublas::matrix<double> createRotation (int dimension1, int dimension2, double angle) const;
    virtual void updateActual(Event &event);
    virtual void initialize();
  public:
    Lindenmayer();
    virtual ~Lindenmayer();
    virtual int getIterationCount() const;
    virtual void setIterationCount(int count);
    virtual double getAngle() const;
    virtual void setAngle(double angle);
    virtual std::string getAxiom() const;
    virtual void setAxiom(std::string axiom);
    virtual void addRule(std::string command, std::string replacement);
    virtual std::string getReplacement(std::string command);
    virtual void generate();
    virtual void clear();
  };
}
#endif
<commit_msg>Improved documentation.<commit_after>/*
 * C S O U N D
 *
 * L I C E N S E
 *
 * This software 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 software 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 software; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#ifndef LINDENMAYER_TO_SOUND_H
#define LINDENMAYER_TO_SOUND_H

#include "Platform.hpp"
#ifdef SWIG
%module CsoundAC
%include "std_string.i"
%include "std_vector.i"
%{
#include "Silence.hpp"
#include <stack>
#include <string>
#include <map>
#include <vector>
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/matrix.hpp>
  %}
#else
#include "Silence.hpp"
#include <stack>
#include <string>
#include <map>
#include <vector>
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/matrix.hpp>
using namespace boost::numeric;
#endif

namespace csound
{
  /**
   * This class implements a Lindenmayer system in music space
   * for a turtle that writes either notes into a score, or Jones-Parks grains into a memory soundfile.
   * The Z dimension of note space is used for chirp rate.
   * The actions of the turtle are rescaled to fit the specified bounding hypercube.
   * The turtle commands are represented by letters (all n default to 1):
   *

   *
G     = Write the current state of the turtle into the soundfile as a grain.

   *
Mn    = Translate the turtle by adding to its state its step times its orientation times n.

   *
Rabn  = Rotate the turtle from dimension a to dimension b by angle 2 pi / (angleCount * n)

   *
Uan   = Vary the turtle state on dimension a by a normalized (-1 through +1) uniformly distributed random variable times n.

   *
Gan   = Vary the turtle state on dimension a by a normalized (-1 through +1) Gaussian random variable times n.

   *
T=an  = Assign to dimension a of the turtle state the value n.

   *
T*an  = Multiply dimension a of the turtle state by n.

   *
T/an  = Divide dimension a of the turtle state by n.

   *
T+an  = Add to dimension a of the turtle state the value n.

   *
T-an  = Subtract from dimension a of the turtle state the value n.

   *
S=an  = Assign to dimension a of the turtle step the value n.

   *
S*an  = Multiply dimension a of the turtle step by n.

   *
S/an  = Divide dimension a of the turtle step by n.

   *
S+an  = Add to dimension a of the turtle step the value n.

   *
S-an  = Subtract from dimension a of the turtle step the value n.

   *
[     = Push the current state of the turtle state onto a stack.

   *
]     = Pop the current state of the turtle from the stack.

   *

   * The abbreviations for the dimensions are:
   *

   *
i = instrument

   *
t = time

   *
d = duration

   *
k = MIDI key number

   *
v = MIDI velocity number

   *
p = phase

   *
x = pan

   *
y = height

   *
z = depth

   *
s = pitch-class set as Mason number

   *

   */
   */
  class Lindenmayer :
    public ScoreNode
  {
  protected:
    int iterationCount;
    double angle;
    std::string axiom;
    Event turtle;
    Event turtleStep;
    Event turtleOrientation;
    std::map<std::string, std::string> rules;
    std::stack<Event> turtleStack;
    std::stack<Event> turtleStepStack;
    std::stack<Event> turtleOrientationStack;
    clock_t beganAt;
    clock_t endedAt;
    clock_t elapsed;
    virtual void interpret(std::string command, bool render);
    virtual int getDimension (char dimension) const;
    virtual void rewrite();
    virtual ublas::matrix<double> createRotation (int dimension1, int dimension2, double angle) const;
    virtual void updateActual(Event &event);
    virtual void initialize();
  public:
    Lindenmayer();
    virtual ~Lindenmayer();
    virtual int getIterationCount() const;
    virtual void setIterationCount(int count);
    virtual double getAngle() const;
    virtual void setAngle(double angle);
    virtual std::string getAxiom() const;
    virtual void setAxiom(std::string axiom);
    virtual void addRule(std::string command, std::string replacement);
    virtual std::string getReplacement(std::string command);
    virtual void generate();
    virtual void clear();
  };
}
#endif
<|endoftext|>


<commit_before>/***************************************************************
 *
 * Copyright (C) 2014-2015, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

#define CURL_STATICLIB
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <curl/curl.h>
#include <string.h>

#ifdef WIN32
#define strcasecmp _strcmpi
#endif

/*condor_urlfetch
 *This program downloads the url specified as the first argument into the
 *file specified in the second argument, as well as stdout.
 *If the fetch fails, the file will not be overwritten, but it will still
 *be printed to stdout.
 *Errorcode Definitions: (0 successful execution)
 * 1 - usage error
 * 2 - Error writing to file
 * 3 - Error opening the prevfile to read from
 * 4 - curl_easy_perform failed
 * 5 - could not fetch url and no cache file was available
 */

using namespace std;

size_t write_data(void *ptr, size_t size, size_t nmemb, void *userp);
int write_prevfile(const char *prev);
//bool isEmpty(FILE *file);

std::string readBuffer;

/*********************************************************************
    main()
*********************************************************************/

int main(int argc, const char *argv[])
{
    std::string readBuffer;

    if((argc < 2) || (argc > 4))
    {
        fprintf(stderr, "usage: condor_urlfetch  [-<subsystem>]  http://my.site/condor_config  last_config.url");
        return 1;
    }
  //Determines whether the -daemon flag is present, and set argv offets accordingly
  //If the -daemon flag is there and is not master, the program will not download
  //a new page. If no flag was specified, it always downloads
    int lastLoc = 2;
    bool forcePull = true;
    bool cacheExists = false;

    if(argv[1][0] == '-')
    {
        lastLoc++;
        forcePull = (0 == strcasecmp(argv[1], "-MASTER"));
    }

  //Check to see if the cache file exists is readable and is non-empty
  // if -MASTER was not passed, we only want to pull
  // if the cached file is missing or cannot be read.
    if ( ! forcePull && argv[lastLoc])
    {
        FILE *fp = fopen(argv[lastLoc], "r");
        if(fp)
        {
            char buf[4];
            size_t cb = fread(buf, 1, sizeof(buf), fp);
            cacheExists = (cb > 0);
            fclose(fp);
        }
    }

    CURL *curl;
    CURLcode res;
    const char *url = argv[lastLoc - 1];

    curl = curl_easy_init();
    if ((curl) && (forcePull || ! cacheExists))
    {

      //Setting up curl
        curl_easy_setopt(curl, CURLOPT_URL, url);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
        res = curl_easy_perform(curl);

        if(res != CURLE_OK)
        {
            fprintf(stderr, "curl_easy_perform() failed: %s\n",
               curl_easy_strerror(res));
        }
        curl_easy_cleanup(curl);

      //If something has been written to the buffer, copy this to our output file.
        if(res == CURLE_OK)
        {
            if ( ! argv[lastLoc])
            {
                fwrite(readBuffer.c_str(), 1, readBuffer.length(), stdout);
                return 0;
            }
            else
            {
                ofstream out(argv[lastLoc]);

                out.write(readBuffer.c_str(), readBuffer.length());
                out.close();
            }
        }
    }

  // open the cache file and write it to stdout.
    if ( ! argv[lastLoc])
    {
        fprintf(stderr, "Error: no cache file specified, and could not fetch URL\n");
        exit(3);
    }
    else if(write_prevfile(argv[lastLoc]) != 0)
    {
        fprintf(stderr, "Error: could not from cache file %s\n", argv[lastLoc]);
        exit(3);
    }
    return 0;
}

size_t write_data(void *ptr, size_t size, size_t nmemb, void *userp)
{

    ((std::string*)userp)->append((char*)ptr, size * nmemb);
    return size * nmemb;
 // Alternate write_data to be used to write to a file rather than buffer
 /*   size_t realsize = size * nmemb;
    readBuffer.append(ptr, realsize);
    return realsize;*/

   /* size_t written = 0;
    if((size != 0) && (nmemb != 0))
    {
        written = fwrite(ptr, size, nmemb, stream);
        if(written!= nmemb)
        {
            perror("Error reading file.");
            exit(2);
        }
    }

    return written;*/
}

int write_prevfile(const char *prev)
{
    FILE *ptrFile;

    ptrFile = fopen(prev, "r");

    if(!ptrFile)
    {
        printf("Error: Failed to open previous file for reading.\n");
        return 1;
    }

    std::ifstream  toPrint(prev, std::ios::binary);

    cout << toPrint.rdbuf();
    fclose(ptrFile);

    return 0;
}

/*
// check if our cache file is empty.
bool isEmpty(FILE *ptrFile)
{
    long offset = ftell(ptrFile);
    fseek(ptrFile, 0, SEEK_END);

    if (ftell(ptrFile) == 0)
    {
        return true;
    }

    fseek(ptrFile, offset, SEEK_SET);
    return false;
}
*/
<commit_msg>Check return values from curl functions #6992<commit_after>/***************************************************************
 *
 * Copyright (C) 2014-2015, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

#define CURL_STATICLIB
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <curl/curl.h>
#include <string.h>

#ifdef WIN32
#define strcasecmp _strcmpi
#endif

/*condor_urlfetch
 *This program downloads the url specified as the first argument into the
 *file specified in the second argument, as well as stdout.
 *If the fetch fails, the file will not be overwritten, but it will still
 *be printed to stdout.
 *Errorcode Definitions: (0 successful execution)
 * 1 - usage error
 * 2 - Error writing to file
 * 3 - Error opening the prevfile to read from
 * 4 - curl_easy_perform failed
 * 5 - could not fetch url and no cache file was available
 */

using namespace std;

size_t write_data(void *ptr, size_t size, size_t nmemb, void *userp);
int write_prevfile(const char *prev);
//bool isEmpty(FILE *file);

std::string readBuffer;

/*********************************************************************
    main()
*********************************************************************/

int main(int argc, const char *argv[])
{
    std::string readBuffer;

    if((argc < 2) || (argc > 4))
    {
        fprintf(stderr, "usage: condor_urlfetch  [-<subsystem>]  http://my.site/condor_config  last_config.url");
        return 1;
    }
  //Determines whether the -daemon flag is present, and set argv offets accordingly
  //If the -daemon flag is there and is not master, the program will not download
  //a new page. If no flag was specified, it always downloads
    int lastLoc = 2;
    bool forcePull = true;
    bool cacheExists = false;

    if(argv[1][0] == '-')
    {
        lastLoc++;
        forcePull = (0 == strcasecmp(argv[1], "-MASTER"));
    }

  //Check to see if the cache file exists is readable and is non-empty
  // if -MASTER was not passed, we only want to pull
  // if the cached file is missing or cannot be read.
    if ( ! forcePull && argv[lastLoc])
    {
        FILE *fp = fopen(argv[lastLoc], "r");
        if(fp)
        {
            char buf[4];
            size_t cb = fread(buf, 1, sizeof(buf), fp);
            cacheExists = (cb > 0);
            fclose(fp);
        }
    }

    CURL *curl;
    CURLcode res;
    const char *url = argv[lastLoc - 1];

    curl = curl_easy_init();
    if ((curl) && (forcePull || ! cacheExists))
    {

      //Setting up curl
		CURLcode r = CURLE_OK;
        r = curl_easy_setopt(curl, CURLOPT_URL, url);
		if (r != CURLE_OK) {
        	fprintf(stderr, "condor_urlfetch: Can't setopt CUROPT_URL\n");
        	return 1;
		}

        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
		if (r != CURLE_OK) {
        	fprintf(stderr, "condor_urlfetch: Can't setopt CUROPT_WRITEFUNCTION\n");
        	return 1;
		}
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
		if (r != CURLE_OK) {
        	fprintf(stderr, "condor_urlfetch: Can't setopt CUROPT_WRITEDATA\n");
        	return 1;
		}
        res = curl_easy_perform(curl);

        if(res != CURLE_OK)
        {
            fprintf(stderr, "curl_easy_perform() failed: %s\n",
               curl_easy_strerror(res));
        }
        curl_easy_cleanup(curl);

      //If something has been written to the buffer, copy this to our output file.
        if(res == CURLE_OK)
        {
            if ( ! argv[lastLoc])
            {
                fwrite(readBuffer.c_str(), 1, readBuffer.length(), stdout);
                return 0;
            }
            else
            {
                ofstream out(argv[lastLoc]);

                out.write(readBuffer.c_str(), readBuffer.length());
                out.close();
            }
        }
    }

  // open the cache file and write it to stdout.
    if ( ! argv[lastLoc])
    {
        fprintf(stderr, "Error: no cache file specified, and could not fetch URL\n");
        exit(3);
    }
    else if(write_prevfile(argv[lastLoc]) != 0)
    {
        fprintf(stderr, "Error: could not from cache file %s\n", argv[lastLoc]);
        exit(3);
    }
    return 0;
}

size_t write_data(void *ptr, size_t size, size_t nmemb, void *userp)
{

    ((std::string*)userp)->append((char*)ptr, size * nmemb);
    return size * nmemb;
 // Alternate write_data to be used to write to a file rather than buffer
 /*   size_t realsize = size * nmemb;
    readBuffer.append(ptr, realsize);
    return realsize;*/

   /* size_t written = 0;
    if((size != 0) && (nmemb != 0))
    {
        written = fwrite(ptr, size, nmemb, stream);
        if(written!= nmemb)
        {
            perror("Error reading file.");
            exit(2);
        }
    }

    return written;*/
}

int write_prevfile(const char *prev)
{
    FILE *ptrFile;

    ptrFile = fopen(prev, "r");

    if(!ptrFile)
    {
        printf("Error: Failed to open previous file for reading.\n");
        return 1;
    }

    std::ifstream  toPrint(prev, std::ios::binary);

    cout << toPrint.rdbuf();
    fclose(ptrFile);

    return 0;
}

/*
// check if our cache file is empty.
bool isEmpty(FILE *ptrFile)
{
    long offset = ftell(ptrFile);
    fseek(ptrFile, 0, SEEK_END);

    if (ftell(ptrFile) == 0)
    {
        return true;
    }

    fseek(ptrFile, offset, SEEK_SET);
    return false;
}
*/
<|endoftext|>