<commit_before>#ifndef _LIB_NODETEXT_HPP__
#define _LIB_NODETEXT_HPP__

#include <SFML/Graphics/Font.hpp>
#include <string>
#include <vector>

#include "rendernode.hpp"

namespace lib
{
	namespace draw
	{
		class NodeText : public lib::draw::RenderNode
		{
		public:
			enum Style
			{
				Regular = 0,
				Bold = 1 << 0,
				Italic = 1 << 1,
				Underlined = 1 << 2,
				StrikeThrough = 1 << 3
			};

			NodeText(const std::string &name);
			NodeText(const std::string &name, const sf::String& string, const sf::Font& font, u32 characterSize = 30);
			virtual ~NodeText();
			void setString(const std::string &string);
			void setFont(const sf::Font& font);
			void setCharacterSize(u32 size);
			void setStyle(u32 style);
			const std::string &getString() const;
			const sf::Font* getFont() const;
			u32 getCharacterSize() const;
			u32 getStyle() const;
			vector2df findCharacterPos(u32 index);
			virtual const sf::Texture *texture() const override;
		private:
			virtual u32 draw() override;
			virtual void ensureGeometryUpdate() override;

			std::string m_string;
			const sf::Font* m_font;
			u32 m_characterSize;
			u32 m_style;
		};
	}
}

#endif
<commit_msg>Small refractor<commit_after>#ifndef _LIB_NODETEXT_HPP__
#define _LIB_NODETEXT_HPP__

#include <SFML/Graphics/Font.hpp>
#include <string>
#include <vector>

#include "rendernode.hpp"

namespace lib
{
	namespace draw
	{
		class NodeText : public RenderNode
		{
		public:
			enum Style
			{
				Regular = 0,
				Bold = 1 << 0,
				Italic = 1 << 1,
				Underlined = 1 << 2,
				StrikeThrough = 1 << 3
			};

			NodeText(const std::string &name);
			NodeText(const std::string &name, const sf::String& string, const sf::Font& font, u32 characterSize = 30);
			virtual ~NodeText();
			void setString(const std::string &string);
			void setFont(const sf::Font& font);
			void setCharacterSize(u32 size);
			void setStyle(u32 style);
			const std::string &getString() const;
			const sf::Font* getFont() const;
			u32 getCharacterSize() const;
			u32 getStyle() const;
			vector2df findCharacterPos(u32 index);
			virtual const sf::Texture *texture() const override;
		private:
			virtual u32 draw() override;
			virtual void ensureGeometryUpdate() override;

			std::string m_string;
			const sf::Font* m_font;
			u32 m_characterSize;
			u32 m_style;
		};
	}
}

#endif
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used 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.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "clonewizardpage.h"
#include "gitplugin.h"
#include "gitclient.h"

#include <vcsbase/checkoutjobs.h>
#include <utils/qtcassert.h>

#include <QtGui/QCheckBox>

namespace Git {

struct CloneWizardPagePrivate {
    CloneWizardPagePrivate();

    const QString mainLinePostfix;
    const QString gitPostFix;
    const QString protocolDelimiter;
    QCheckBox *deleteMasterCheckBox;
};

CloneWizardPagePrivate::CloneWizardPagePrivate() :
    mainLinePostfix(QLatin1String("/mainline.git")),
    gitPostFix(QLatin1String(".git")),
    protocolDelimiter(QLatin1String("://")),
    deleteMasterCheckBox(0)
{
}

CloneWizardPage::CloneWizardPage(QWidget *parent) :
    VCSBase::BaseCheckoutWizardPage(parent),
    d(new CloneWizardPagePrivate)
{
    setTitle(tr("Location"));
    setSubTitle(tr("Specify repository URL, checkout directory and path."));
    setRepositoryLabel(tr("Clone URL:"));
    d->deleteMasterCheckBox = new QCheckBox(tr("Delete master branch"));
    addControl(d->deleteMasterCheckBox);
    setDeleteMasterBranch(true);
}

CloneWizardPage::~CloneWizardPage()
{
    delete d;
}

bool CloneWizardPage::deleteMasterBranch() const
{
    return d->deleteMasterCheckBox->isChecked();
}

void CloneWizardPage::setDeleteMasterBranch(bool v)
{
    d->deleteMasterCheckBox->setChecked(v);
}

QString CloneWizardPage::directoryFromRepository(const QString &urlIn) const
{
    /* Try to figure out a good directory name from something like:
     * 'user@host:qt/qt.git', 'http://host/qt/qt.git' 'local repo'
     * ------> 'qt' .  */

    QString url = urlIn.trimmed();
    const QChar slash = QLatin1Char('/');
    // remove host
    const int protocolDelimiterPos = url.indexOf(d->protocolDelimiter); // "://"
    const int startRepoSearchPos = protocolDelimiterPos == -1 ? 0 : protocolDelimiterPos + d->protocolDelimiter.size();
    int repoPos = url.indexOf(QLatin1Char(':'), startRepoSearchPos);
    if (repoPos == -1)
        repoPos = url.indexOf(slash, startRepoSearchPos);
    if (repoPos != -1)
        url.remove(0, repoPos + 1);
    // Remove postfixes
    if (url.endsWith(d->mainLinePostfix)) {
        url.truncate(url.size() - d->mainLinePostfix.size());
    } else {
        if (url.endsWith(d->gitPostFix)) {
            url.truncate(url.size() - d->gitPostFix.size());
        }
    }
    // Check for equal parts, something like "qt/qt" -> "qt"
    const int slashPos = url.indexOf(slash);
    if (slashPos != -1 && slashPos == (url.size() - 1) / 2) {
        if (url.leftRef(slashPos) == url.rightRef(slashPos))
            url.truncate(slashPos);
    }
    // fix invalid characters
    const QChar dash = QLatin1Char('-');
    url.replace(slash, dash);
    url.replace(QLatin1Char('.'), dash);
    return url;
}

QSharedPointer<VCSBase::AbstractCheckoutJob> CloneWizardPage::createCheckoutJob(QString *checkoutPath) const
{
     const Internal::GitClient *client = Internal::GitPlugin::instance()->gitClient();
     const QString workingDirectory = path();
     const QString checkoutDir = directory();
     *checkoutPath = workingDirectory + QLatin1Char('/') + checkoutDir;

     QStringList baseArgs = client->binary();
     const QString binary = baseArgs.front();
     baseArgs.pop_front();

     QStringList args;
     args << QLatin1String("clone") << repository() << checkoutDir;

     VCSBase::ProcessCheckoutJob *job = new VCSBase::ProcessCheckoutJob;
     const QProcessEnvironment env = client->processEnvironment();
     // 1) Basic checkout step
     job->addStep(binary, baseArgs + args, workingDirectory, env);
     const QString checkoutBranch = branch();

     // 2) Checkout branch, change to checkoutDir
     const QString masterBranch = QLatin1String("master");
     if (!checkoutBranch.isEmpty() && checkoutBranch != masterBranch) {
         // Create branch
         args.clear();
         args << QLatin1String("branch") << QLatin1String("--track")
                 << checkoutBranch << (QLatin1String("origin/")  + checkoutBranch);
         job->addStep(binary, baseArgs + args, checkoutDir, env);
         // Checkout branch
         args.clear();
         args << QLatin1String("checkout") << checkoutBranch;
         job->addStep(binary, baseArgs + args, checkoutDir, env);
         // Delete master if desired
         if (deleteMasterBranch()) {
             args.clear();
             args << QLatin1String("branch") << QLatin1String("-D") << masterBranch;
             job->addStep(binary, baseArgs + args, checkoutDir, env);
         }
     }

     return QSharedPointer<VCSBase::AbstractCheckoutJob>(job);
}

QStringList CloneWizardPage::branches(const QString &repository, int *current)
{
    // Run git on remote repository if URL is complete
    *current = 0;
    if (!repository.endsWith(d->gitPostFix))
        return QStringList();
     const QStringList branches = Internal::GitPlugin::instance()->gitClient()->synchronousRepositoryBranches(repository);
     *current = branches.indexOf(QLatin1String("master"));
     return branches;
}

} // namespace Git
<commit_msg>VCS[git]: Fix branch checkout: Use absolute path.<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used 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.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "clonewizardpage.h"
#include "gitplugin.h"
#include "gitclient.h"

#include <vcsbase/checkoutjobs.h>
#include <utils/qtcassert.h>

#include <QtGui/QCheckBox>

namespace Git {

struct CloneWizardPagePrivate {
    CloneWizardPagePrivate();

    const QString mainLinePostfix;
    const QString gitPostFix;
    const QString protocolDelimiter;
    QCheckBox *deleteMasterCheckBox;
};

CloneWizardPagePrivate::CloneWizardPagePrivate() :
    mainLinePostfix(QLatin1String("/mainline.git")),
    gitPostFix(QLatin1String(".git")),
    protocolDelimiter(QLatin1String("://")),
    deleteMasterCheckBox(0)
{
}

CloneWizardPage::CloneWizardPage(QWidget *parent) :
    VCSBase::BaseCheckoutWizardPage(parent),
    d(new CloneWizardPagePrivate)
{
    setTitle(tr("Location"));
    setSubTitle(tr("Specify repository URL, checkout directory and path."));
    setRepositoryLabel(tr("Clone URL:"));
    d->deleteMasterCheckBox = new QCheckBox(tr("Delete master branch"));
    addControl(d->deleteMasterCheckBox);
    setDeleteMasterBranch(true);
}

CloneWizardPage::~CloneWizardPage()
{
    delete d;
}

bool CloneWizardPage::deleteMasterBranch() const
{
    return d->deleteMasterCheckBox->isChecked();
}

void CloneWizardPage::setDeleteMasterBranch(bool v)
{
    d->deleteMasterCheckBox->setChecked(v);
}

QString CloneWizardPage::directoryFromRepository(const QString &urlIn) const
{
    /* Try to figure out a good directory name from something like:
     * 'user@host:qt/qt.git', 'http://host/qt/qt.git' 'local repo'
     * ------> 'qt' .  */

    QString url = urlIn.trimmed();
    const QChar slash = QLatin1Char('/');
    // remove host
    const int protocolDelimiterPos = url.indexOf(d->protocolDelimiter); // "://"
    const int startRepoSearchPos = protocolDelimiterPos == -1 ? 0 : protocolDelimiterPos + d->protocolDelimiter.size();
    int repoPos = url.indexOf(QLatin1Char(':'), startRepoSearchPos);
    if (repoPos == -1)
        repoPos = url.indexOf(slash, startRepoSearchPos);
    if (repoPos != -1)
        url.remove(0, repoPos + 1);
    // Remove postfixes
    if (url.endsWith(d->mainLinePostfix)) {
        url.truncate(url.size() - d->mainLinePostfix.size());
    } else {
        if (url.endsWith(d->gitPostFix)) {
            url.truncate(url.size() - d->gitPostFix.size());
        }
    }
    // Check for equal parts, something like "qt/qt" -> "qt"
    const int slashPos = url.indexOf(slash);
    if (slashPos != -1 && slashPos == (url.size() - 1) / 2) {
        if (url.leftRef(slashPos) == url.rightRef(slashPos))
            url.truncate(slashPos);
    }
    // fix invalid characters
    const QChar dash = QLatin1Char('-');
    url.replace(slash, dash);
    url.replace(QLatin1Char('.'), dash);
    return url;
}

QSharedPointer<VCSBase::AbstractCheckoutJob> CloneWizardPage::createCheckoutJob(QString *checkoutPath) const
{
     const Internal::GitClient *client = Internal::GitPlugin::instance()->gitClient();
     const QString workingDirectory = path();
     const QString checkoutDir = directory();
     *checkoutPath = workingDirectory + QLatin1Char('/') + checkoutDir;

     QStringList baseArgs = client->binary();
     const QString binary = baseArgs.front();
     baseArgs.pop_front();

     QStringList args;
     args << QLatin1String("clone") << repository() << checkoutDir;

     VCSBase::ProcessCheckoutJob *job = new VCSBase::ProcessCheckoutJob;
     const QProcessEnvironment env = client->processEnvironment();
     // 1) Basic checkout step
     job->addStep(binary, baseArgs + args, workingDirectory, env);
     const QString checkoutBranch = branch();

     // 2) Checkout branch, change to checkoutDir
     const QString masterBranch = QLatin1String("master");
     if (!checkoutBranch.isEmpty() && checkoutBranch != masterBranch) {
         // Create branch
         args.clear();
         args << QLatin1String("branch") << QLatin1String("--track")
                 << checkoutBranch << (QLatin1String("origin/")  + checkoutBranch);
         job->addStep(binary, baseArgs + args, *checkoutPath, env);
         // Checkout branch
         args.clear();
         args << QLatin1String("checkout") << checkoutBranch;
         job->addStep(binary, baseArgs + args, *checkoutPath, env);
         // Delete master if desired
         if (deleteMasterBranch()) {
             args.clear();
             args << QLatin1String("branch") << QLatin1String("-D") << masterBranch;
             job->addStep(binary, baseArgs + args, *checkoutPath, env);
         }
     }

     return QSharedPointer<VCSBase::AbstractCheckoutJob>(job);
}

QStringList CloneWizardPage::branches(const QString &repository, int *current)
{
    // Run git on remote repository if URL is complete
    *current = 0;
    if (!repository.endsWith(d->gitPostFix))
        return QStringList();
     const QStringList branches = Internal::GitPlugin::instance()->gitClient()->synchronousRepositoryBranches(repository);
     *current = branches.indexOf(QLatin1String("master"));
     return branches;
}

} // namespace Git
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used 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.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/

#include "helpviewer.h"

#if !defined(QT_NO_WEBKIT)

#include "centralwidget.h"
#include "helpconstants.h"
#include "localhelpmanager.h"
#include "openpagesmanager.h"

#include <QFileInfo>
#include <QString>
#include <QStringBuilder>
#include <QTimer>

#include <QApplication>
#include <QWheelEvent>

#include <QHelpEngine>

#include <QNetworkReply>
#include <QNetworkRequest>

#include <utils/networkaccessmanager.h>

using namespace Find;
using namespace Help;
using namespace Help::Internal;

// -- HelpNetworkReply

class HelpNetworkReply : public QNetworkReply
{
public:
    HelpNetworkReply(const QNetworkRequest &request, const QByteArray &fileData,
        const QString &mimeType);

    virtual void abort() {}

    virtual qint64 bytesAvailable() const
        { return data.length() + QNetworkReply::bytesAvailable(); }

protected:
    virtual qint64 readData(char *data, qint64 maxlen);

private:
    QByteArray data;
    qint64 dataLength;
};

HelpNetworkReply::HelpNetworkReply(const QNetworkRequest &request,
        const QByteArray &fileData, const QString& mimeType)
    : data(fileData)
    , dataLength(fileData.length())
{
    setRequest(request);
    setOpenMode(QIODevice::ReadOnly);

    setHeader(QNetworkRequest::ContentTypeHeader, mimeType);
    setHeader(QNetworkRequest::ContentLengthHeader, QByteArray::number(dataLength));
    QTimer::singleShot(0, this, SIGNAL(metaDataChanged()));
    QTimer::singleShot(0, this, SIGNAL(readyRead()));
}

qint64 HelpNetworkReply::readData(char *buffer, qint64 maxlen)
{
    qint64 len = qMin(qint64(data.length()), maxlen);
    if (len) {
        qMemCopy(buffer, data.constData(), len);
        data.remove(0, len);
    }
    if (!data.length())
        QTimer::singleShot(0, this, SIGNAL(finished()));
    return len;
}

// -- HelpNetworkAccessManager

class HelpNetworkAccessManager : public Utils::NetworkAccessManager
{
public:
    HelpNetworkAccessManager(QObject *parent);

protected:
    virtual QNetworkReply *createRequest(Operation op,
        const QNetworkRequest &request, QIODevice *outgoingData = 0);
};

HelpNetworkAccessManager::HelpNetworkAccessManager(QObject *parent)
    : Utils::NetworkAccessManager(parent)
{
}

QNetworkReply *HelpNetworkAccessManager::createRequest(Operation op,
    const QNetworkRequest &request, QIODevice* outgoingData)
{
    if (!HelpViewer::isLocalUrl(request.url()))
        return Utils::NetworkAccessManager::createRequest(op, request, outgoingData);

    QString url = request.url().toString();
    const QHelpEngineCore &engine = LocalHelpManager::helpEngine();
    // TODO: For some reason the url to load is already wrong (passed from webkit)
    // though the css file and the references inside should work that way. One
    // possible problem might be that the css is loaded at the same level as the
    // html, thus a path inside the css like (../images/foo.png) might cd out of
    // the virtual folder
    if (!engine.findFile(url).isValid()) {
        if (url.startsWith(HelpViewer::NsNokia) || url.startsWith(HelpViewer::NsTrolltech)) {
            QUrl newUrl = request.url();
            if (!newUrl.path().startsWith(QLatin1String("/qdoc/")) ||
                    !newUrl.path().startsWith(QLatin1String("/doc/"))) {
                QString path = newUrl.path();
                newUrl.setPath(QLatin1String("/qdoc/") + path);
                if (!engine.findFile(newUrl).isValid())
                    newUrl.setPath(QLatin1String("/doc/") + path);
                url = newUrl.toString();
            }
        }
    }

    const QString &mimeType = HelpViewer::mimeFromUrl(url);
    const QByteArray &data = engine.findFile(url).isValid() ? engine.fileData(url)
        : HelpViewer::PageNotFoundMessage.arg(url).toUtf8();

    return new HelpNetworkReply(request, data, mimeType.isEmpty()
        ? QLatin1String("application/octet-stream") : mimeType);
}

// -- HelpPage

class HelpPage : public QWebPage
{
public:
    HelpPage(QObject *parent);

protected:
    virtual QWebPage *createWindow(QWebPage::WebWindowType);
    virtual void triggerAction(WebAction action, bool checked = false);

    virtual bool acceptNavigationRequest(QWebFrame *frame,
        const QNetworkRequest &request, NavigationType type);

private:
    bool closeNewTabIfNeeded;

    friend class Help::Internal::HelpViewer;
    Qt::MouseButtons m_pressedButtons;
    Qt::KeyboardModifiers m_keyboardModifiers;
};

HelpPage::HelpPage(QObject *parent)
    : QWebPage(parent)
    , closeNewTabIfNeeded(false)
    , m_pressedButtons(Qt::NoButton)
    , m_keyboardModifiers(Qt::NoModifier)
{
}

QWebPage *HelpPage::createWindow(QWebPage::WebWindowType)
{
    HelpPage* newPage = static_cast<HelpPage*>(OpenPagesManager::instance()
        .createPage()->page());
    newPage->closeNewTabIfNeeded = closeNewTabIfNeeded;
    closeNewTabIfNeeded = false;
    return newPage;
}

void HelpPage::triggerAction(WebAction action, bool checked)
{
    switch (action) {
        case OpenLinkInNewWindow:
            closeNewTabIfNeeded = true;
        default:        // fall through
            QWebPage::triggerAction(action, checked);
            break;
    }
}

bool HelpPage::acceptNavigationRequest(QWebFrame *,
    const QNetworkRequest &request, QWebPage::NavigationType type)
{
    const bool closeNewTab = closeNewTabIfNeeded;
    closeNewTabIfNeeded = false;

    const QUrl &url = request.url();
    if (HelpViewer::launchWithExternalApp(url)) {
        if (closeNewTab)
            QMetaObject::invokeMethod(&OpenPagesManager::instance(), "closeCurrentPage");
        return false;
    }

    if (type == QWebPage::NavigationTypeLinkClicked
        && (m_keyboardModifiers & Qt::ControlModifier || m_pressedButtons == Qt::MidButton)) {
            m_pressedButtons = Qt::NoButton;
            m_keyboardModifiers = Qt::NoModifier;
            OpenPagesManager::instance().createPage(url);
            return false;
    }

    return true;
}

// -- HelpViewer

HelpViewer::HelpViewer(qreal zoom, QWidget *parent)
    : QWebView(parent)
{
    setAcceptDrops(false);
    installEventFilter(this);

    settings()->setAttribute(QWebSettings::JavaEnabled, false);
    settings()->setAttribute(QWebSettings::PluginsEnabled, false);

    setPage(new HelpPage(this));
    HelpNetworkAccessManager *manager = new HelpNetworkAccessManager(this);
    page()->setNetworkAccessManager(manager);
    connect(manager, SIGNAL(finished(QNetworkReply*)), this,
        SLOT(slotNetworkReplyFinished(QNetworkReply*)));

    QAction* action = pageAction(QWebPage::OpenLinkInNewWindow);
    action->setText(tr("Open Link as New Page"));

    pageAction(QWebPage::DownloadLinkToDisk)->setVisible(false);
    pageAction(QWebPage::DownloadImageToDisk)->setVisible(false);
    pageAction(QWebPage::OpenImageInNewWindow)->setVisible(false);

    connect(pageAction(QWebPage::Copy), SIGNAL(changed()), this,
        SLOT(actionChanged()));
    connect(pageAction(QWebPage::Back), SIGNAL(changed()), this,
        SLOT(actionChanged()));
    connect(pageAction(QWebPage::Forward), SIGNAL(changed()), this,
        SLOT(actionChanged()));
    connect(this, SIGNAL(urlChanged(QUrl)), this, SIGNAL(sourceChanged(QUrl)));
    connect(this, SIGNAL(loadStarted()), this, SLOT(slotLoadStarted()));
    connect(this, SIGNAL(loadFinished(bool)), this, SLOT(slotLoadFinished(bool)));
    connect(this, SIGNAL(titleChanged(QString)), this, SIGNAL(titleChanged()));
    connect(page(), SIGNAL(printRequested(QWebFrame*)), this, SIGNAL(printRequested()));

    setFont(viewerFont());
    setTextSizeMultiplier(zoom == 0.0 ? 1.0 : zoom);
}

HelpViewer::~HelpViewer()
{
}

QFont HelpViewer::viewerFont() const
{
    QWebSettings* webSettings = QWebSettings::globalSettings();
    QFont font(QApplication::font().family(),
        webSettings->fontSize(QWebSettings::DefaultFontSize));
    const QHelpEngineCore &engine = LocalHelpManager::helpEngine();
    return qVariantValue<QFont>(engine.customValue(QLatin1String("font"),
        font));
}

void HelpViewer::setViewerFont(const QFont &font)
{
    QWebSettings *webSettings = settings();
    webSettings->setFontFamily(QWebSettings::StandardFont, font.family());
    webSettings->setFontSize(QWebSettings::DefaultFontSize, font.pointSize());
}

void HelpViewer::scaleUp()
{
    setTextSizeMultiplier(textSizeMultiplier() + 0.1);
}

void HelpViewer::scaleDown()
{
    setTextSizeMultiplier(qMax(qreal(0.0), textSizeMultiplier() - qreal(0.1)));
}

void HelpViewer::resetScale()
{
    setTextSizeMultiplier(1.0);
}

qreal HelpViewer::scale() const
{
    return textSizeMultiplier();
}

QString HelpViewer::title() const
{
    return QWebView::title();
}

void HelpViewer::setTitle(const QString &title)
{
    Q_UNUSED(title)
}

QUrl HelpViewer::source() const
{
    return url();
}

void HelpViewer::setSource(const QUrl &url)
{
    load(url);
}

QString HelpViewer::selectedText() const
{
    return QWebView::selectedText();
}

bool HelpViewer::isForwardAvailable() const
{
    return pageAction(QWebPage::Forward)->isEnabled();
}

bool HelpViewer::isBackwardAvailable() const
{
    return pageAction(QWebPage::Back)->isEnabled();
}

bool HelpViewer::findText(const QString &text, Find::FindFlags flags,
    bool incremental, bool fromSearch, bool *wrapped)
{
    Q_UNUSED(incremental);
    Q_UNUSED(fromSearch);
    if (wrapped)
        *wrapped = false;
    QWebPage::FindFlags options;
    if (flags & Find::FindBackward)
        options |= QWebPage::FindBackward;
    if (flags & Find::FindCaseSensitively)
        options |= QWebPage::FindCaseSensitively;

    bool found = QWebView::findText(text, options);
    if (!found) {
        options |= QWebPage::FindWrapsAroundDocument;
        found = QWebView::findText(text, options);
        if (found && wrapped)
            *wrapped = true;
    }
    options = QWebPage::HighlightAllOccurrences;
    QWebView::findText(QLatin1String(""), options); // clear first
    QWebView::findText(text, options); // force highlighting of all other matches
    return found;
}

// -- public slots

void HelpViewer::copy()
{
    triggerPageAction(QWebPage::Copy);
}

void HelpViewer::forward()
{
    QWebView::forward();
}

void HelpViewer::backward()
{
    back();
}

// -- protected

void HelpViewer::keyPressEvent(QKeyEvent *e)
{
    // TODO: remove this once we support multiple keysequences per command
    if (e->key() == Qt::Key_Insert && e->modifiers() == Qt::CTRL) {
        if (!selectedText().isEmpty())
            copy();
    }
    QWebView::keyPressEvent(e);
}

void HelpViewer::wheelEvent(QWheelEvent *event)
{
    if (event->modifiers()& Qt::ControlModifier) {
        event->accept();
        event->delta() > 0 ? scaleUp() : scaleDown();
    } else {
        QWebView::wheelEvent(event);
    }
}

void HelpViewer::mousePressEvent(QMouseEvent *event)
{
#ifdef Q_OS_LINUX
    if (handleForwardBackwardMouseButtons(event))
        return;
#endif

    if (HelpPage *currentPage = static_cast<HelpPage*> (page())) {
        currentPage->m_pressedButtons = event->buttons();
        currentPage->m_keyboardModifiers = event->modifiers();
    }

    QWebView::mousePressEvent(event);
}

void HelpViewer::mouseReleaseEvent(QMouseEvent *event)
{
#ifndef Q_OS_LINUX
    if (handleForwardBackwardMouseButtons(event))
        return;
#endif

    QWebView::mouseReleaseEvent(event);
}

// -- private slots

void HelpViewer::actionChanged()
{
    QAction *a = qobject_cast<QAction *>(sender());
    if (a == pageAction(QWebPage::Back))
        emit backwardAvailable(a->isEnabled());
    else if (a == pageAction(QWebPage::Forward))
        emit forwardAvailable(a->isEnabled());
}

void HelpViewer::slotNetworkReplyFinished(QNetworkReply *reply)
{
    if (reply && reply->error() != QNetworkReply::NoError) {
        setSource(QUrl(Help::Constants::AboutBlank));
        setHtml(HelpViewer::PageNotFoundMessage.arg(reply->url().toString()
            + QString::fromLatin1("

Error: %1").arg(reply->errorString())));
    }
}

// -- private

bool HelpViewer::eventFilter(QObject *obj, QEvent *event)
{
    if (event->type() == QEvent::KeyPress) {
        if (QKeyEvent *keyEvent = static_cast<QKeyEvent*> (event)) {
            if (keyEvent->key() == Qt::Key_Slash)
                emit openFindToolBar();
        }
    }
    return QWebView::eventFilter(obj, event);
}

void HelpViewer::contextMenuEvent(QContextMenuEvent *event)
{
    QWebView::contextMenuEvent(event);
}

#endif  // !QT_NO_WEBKIT
<commit_msg>Help: Do not get stuck with spinning cursor<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used 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.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/

#include "helpviewer.h"

#if !defined(QT_NO_WEBKIT)

#include "centralwidget.h"
#include "helpconstants.h"
#include "localhelpmanager.h"
#include "openpagesmanager.h"

#include <QFileInfo>
#include <QString>
#include <QStringBuilder>
#include <QTimer>

#include <QApplication>
#include <QWheelEvent>

#include <QHelpEngine>

#include <QNetworkReply>
#include <QNetworkRequest>

#include <utils/networkaccessmanager.h>

using namespace Find;
using namespace Help;
using namespace Help::Internal;

// -- HelpNetworkReply

class HelpNetworkReply : public QNetworkReply
{
public:
    HelpNetworkReply(const QNetworkRequest &request, const QByteArray &fileData,
        const QString &mimeType);

    virtual void abort() {}

    virtual qint64 bytesAvailable() const
        { return data.length() + QNetworkReply::bytesAvailable(); }

protected:
    virtual qint64 readData(char *data, qint64 maxlen);

private:
    QByteArray data;
    qint64 dataLength;
};

HelpNetworkReply::HelpNetworkReply(const QNetworkRequest &request,
        const QByteArray &fileData, const QString& mimeType)
    : data(fileData)
    , dataLength(fileData.length())
{
    setRequest(request);
    setOpenMode(QIODevice::ReadOnly);

    setHeader(QNetworkRequest::ContentTypeHeader, mimeType);
    setHeader(QNetworkRequest::ContentLengthHeader, QByteArray::number(dataLength));
    QTimer::singleShot(0, this, SIGNAL(metaDataChanged()));
    QTimer::singleShot(0, this, SIGNAL(readyRead()));
    QTimer::singleShot(0, this, SIGNAL(finished()));
}

qint64 HelpNetworkReply::readData(char *buffer, qint64 maxlen)
{
    qint64 len = qMin(qint64(data.length()), maxlen);
    if (len) {
        qMemCopy(buffer, data.constData(), len);
        data.remove(0, len);
    }
    return len;
}

// -- HelpNetworkAccessManager

class HelpNetworkAccessManager : public Utils::NetworkAccessManager
{
public:
    HelpNetworkAccessManager(QObject *parent);

protected:
    virtual QNetworkReply *createRequest(Operation op,
        const QNetworkRequest &request, QIODevice *outgoingData = 0);
};

HelpNetworkAccessManager::HelpNetworkAccessManager(QObject *parent)
    : Utils::NetworkAccessManager(parent)
{
}

QNetworkReply *HelpNetworkAccessManager::createRequest(Operation op,
    const QNetworkRequest &request, QIODevice* outgoingData)
{
    if (!HelpViewer::isLocalUrl(request.url()))
        return Utils::NetworkAccessManager::createRequest(op, request, outgoingData);

    QString url = request.url().toString();
    const QHelpEngineCore &engine = LocalHelpManager::helpEngine();
    // TODO: For some reason the url to load is already wrong (passed from webkit)
    // though the css file and the references inside should work that way. One
    // possible problem might be that the css is loaded at the same level as the
    // html, thus a path inside the css like (../images/foo.png) might cd out of
    // the virtual folder
    if (!engine.findFile(url).isValid()) {
        if (url.startsWith(HelpViewer::NsNokia) || url.startsWith(HelpViewer::NsTrolltech)) {
            QUrl newUrl = request.url();
            if (!newUrl.path().startsWith(QLatin1String("/qdoc/")) ||
                    !newUrl.path().startsWith(QLatin1String("/doc/"))) {
                QString path = newUrl.path();
                newUrl.setPath(QLatin1String("/qdoc/") + path);
                if (!engine.findFile(newUrl).isValid())
                    newUrl.setPath(QLatin1String("/doc/") + path);
                url = newUrl.toString();
            }
        }
    }

    const QString &mimeType = HelpViewer::mimeFromUrl(url);
    const QByteArray &data = engine.findFile(url).isValid() ? engine.fileData(url)
        : HelpViewer::PageNotFoundMessage.arg(url).toUtf8();

    return new HelpNetworkReply(request, data, mimeType.isEmpty()
        ? QLatin1String("application/octet-stream") : mimeType);
}

// -- HelpPage

class HelpPage : public QWebPage
{
public:
    HelpPage(QObject *parent);

protected:
    virtual QWebPage *createWindow(QWebPage::WebWindowType);
    virtual void triggerAction(WebAction action, bool checked = false);

    virtual bool acceptNavigationRequest(QWebFrame *frame,
        const QNetworkRequest &request, NavigationType type);

private:
    bool closeNewTabIfNeeded;

    friend class Help::Internal::HelpViewer;
    Qt::MouseButtons m_pressedButtons;
    Qt::KeyboardModifiers m_keyboardModifiers;
};

HelpPage::HelpPage(QObject *parent)
    : QWebPage(parent)
    , closeNewTabIfNeeded(false)
    , m_pressedButtons(Qt::NoButton)
    , m_keyboardModifiers(Qt::NoModifier)
{
}

QWebPage *HelpPage::createWindow(QWebPage::WebWindowType)
{
    HelpPage* newPage = static_cast<HelpPage*>(OpenPagesManager::instance()
        .createPage()->page());
    newPage->closeNewTabIfNeeded = closeNewTabIfNeeded;
    closeNewTabIfNeeded = false;
    return newPage;
}

void HelpPage::triggerAction(WebAction action, bool checked)
{
    switch (action) {
        case OpenLinkInNewWindow:
            closeNewTabIfNeeded = true;
        default:        // fall through
            QWebPage::triggerAction(action, checked);
            break;
    }
}

bool HelpPage::acceptNavigationRequest(QWebFrame *,
    const QNetworkRequest &request, QWebPage::NavigationType type)
{
    const bool closeNewTab = closeNewTabIfNeeded;
    closeNewTabIfNeeded = false;

    const QUrl &url = request.url();
    if (HelpViewer::launchWithExternalApp(url)) {
        if (closeNewTab)
            QMetaObject::invokeMethod(&OpenPagesManager::instance(), "closeCurrentPage");
        return false;
    }

    if (type == QWebPage::NavigationTypeLinkClicked
        && (m_keyboardModifiers & Qt::ControlModifier || m_pressedButtons == Qt::MidButton)) {
            m_pressedButtons = Qt::NoButton;
            m_keyboardModifiers = Qt::NoModifier;
            OpenPagesManager::instance().createPage(url);
            return false;
    }

    return true;
}

// -- HelpViewer

HelpViewer::HelpViewer(qreal zoom, QWidget *parent)
    : QWebView(parent)
{
    setAcceptDrops(false);
    installEventFilter(this);

    settings()->setAttribute(QWebSettings::JavaEnabled, false);
    settings()->setAttribute(QWebSettings::PluginsEnabled, false);

    setPage(new HelpPage(this));
    HelpNetworkAccessManager *manager = new HelpNetworkAccessManager(this);
    page()->setNetworkAccessManager(manager);
    connect(manager, SIGNAL(finished(QNetworkReply*)), this,
        SLOT(slotNetworkReplyFinished(QNetworkReply*)));

    QAction* action = pageAction(QWebPage::OpenLinkInNewWindow);
    action->setText(tr("Open Link as New Page"));

    pageAction(QWebPage::DownloadLinkToDisk)->setVisible(false);
    pageAction(QWebPage::DownloadImageToDisk)->setVisible(false);
    pageAction(QWebPage::OpenImageInNewWindow)->setVisible(false);

    connect(pageAction(QWebPage::Copy), SIGNAL(changed()), this,
        SLOT(actionChanged()));
    connect(pageAction(QWebPage::Back), SIGNAL(changed()), this,
        SLOT(actionChanged()));
    connect(pageAction(QWebPage::Forward), SIGNAL(changed()), this,
        SLOT(actionChanged()));
    connect(this, SIGNAL(urlChanged(QUrl)), this, SIGNAL(sourceChanged(QUrl)));
    connect(this, SIGNAL(loadStarted()), this, SLOT(slotLoadStarted()));
    connect(this, SIGNAL(loadFinished(bool)), this, SLOT(slotLoadFinished(bool)));
    connect(this, SIGNAL(titleChanged(QString)), this, SIGNAL(titleChanged()));
    connect(page(), SIGNAL(printRequested(QWebFrame*)), this, SIGNAL(printRequested()));

    setFont(viewerFont());
    setTextSizeMultiplier(zoom == 0.0 ? 1.0 : zoom);
}

HelpViewer::~HelpViewer()
{
}

QFont HelpViewer::viewerFont() const
{
    QWebSettings* webSettings = QWebSettings::globalSettings();
    QFont font(QApplication::font().family(),
        webSettings->fontSize(QWebSettings::DefaultFontSize));
    const QHelpEngineCore &engine = LocalHelpManager::helpEngine();
    return qVariantValue<QFont>(engine.customValue(QLatin1String("font"),
        font));
}

void HelpViewer::setViewerFont(const QFont &font)
{
    QWebSettings *webSettings = settings();
    webSettings->setFontFamily(QWebSettings::StandardFont, font.family());
    webSettings->setFontSize(QWebSettings::DefaultFontSize, font.pointSize());
}

void HelpViewer::scaleUp()
{
    setTextSizeMultiplier(textSizeMultiplier() + 0.1);
}

void HelpViewer::scaleDown()
{
    setTextSizeMultiplier(qMax(qreal(0.0), textSizeMultiplier() - qreal(0.1)));
}

void HelpViewer::resetScale()
{
    setTextSizeMultiplier(1.0);
}

qreal HelpViewer::scale() const
{
    return textSizeMultiplier();
}

QString HelpViewer::title() const
{
    return QWebView::title();
}

void HelpViewer::setTitle(const QString &title)
{
    Q_UNUSED(title)
}

QUrl HelpViewer::source() const
{
    return url();
}

void HelpViewer::setSource(const QUrl &url)
{
    load(url);
}

QString HelpViewer::selectedText() const
{
    return QWebView::selectedText();
}

bool HelpViewer::isForwardAvailable() const
{
    return pageAction(QWebPage::Forward)->isEnabled();
}

bool HelpViewer::isBackwardAvailable() const
{
    return pageAction(QWebPage::Back)->isEnabled();
}

bool HelpViewer::findText(const QString &text, Find::FindFlags flags,
    bool incremental, bool fromSearch, bool *wrapped)
{
    Q_UNUSED(incremental);
    Q_UNUSED(fromSearch);
    if (wrapped)
        *wrapped = false;
    QWebPage::FindFlags options;
    if (flags & Find::FindBackward)
        options |= QWebPage::FindBackward;
    if (flags & Find::FindCaseSensitively)
        options |= QWebPage::FindCaseSensitively;

    bool found = QWebView::findText(text, options);
    if (!found) {
        options |= QWebPage::FindWrapsAroundDocument;
        found = QWebView::findText(text, options);
        if (found && wrapped)
            *wrapped = true;
    }
    options = QWebPage::HighlightAllOccurrences;
    QWebView::findText(QLatin1String(""), options); // clear first
    QWebView::findText(text, options); // force highlighting of all other matches
    return found;
}

// -- public slots

void HelpViewer::copy()
{
    triggerPageAction(QWebPage::Copy);
}

void HelpViewer::forward()
{
    QWebView::forward();
}

void HelpViewer::backward()
{
    back();
}

// -- protected

void HelpViewer::keyPressEvent(QKeyEvent *e)
{
    // TODO: remove this once we support multiple keysequences per command
    if (e->key() == Qt::Key_Insert && e->modifiers() == Qt::CTRL) {
        if (!selectedText().isEmpty())
            copy();
    }
    QWebView::keyPressEvent(e);
}

void HelpViewer::wheelEvent(QWheelEvent *event)
{
    if (event->modifiers()& Qt::ControlModifier) {
        event->accept();
        event->delta() > 0 ? scaleUp() : scaleDown();
    } else {
        QWebView::wheelEvent(event);
    }
}

void HelpViewer::mousePressEvent(QMouseEvent *event)
{
#ifdef Q_OS_LINUX
    if (handleForwardBackwardMouseButtons(event))
        return;
#endif

    if (HelpPage *currentPage = static_cast<HelpPage*> (page())) {
        currentPage->m_pressedButtons = event->buttons();
        currentPage->m_keyboardModifiers = event->modifiers();
    }

    QWebView::mousePressEvent(event);
}

void HelpViewer::mouseReleaseEvent(QMouseEvent *event)
{
#ifndef Q_OS_LINUX
    if (handleForwardBackwardMouseButtons(event))
        return;
#endif

    QWebView::mouseReleaseEvent(event);
}

// -- private slots

void HelpViewer::actionChanged()
{
    QAction *a = qobject_cast<QAction *>(sender());
    if (a == pageAction(QWebPage::Back))
        emit backwardAvailable(a->isEnabled());
    else if (a == pageAction(QWebPage::Forward))
        emit forwardAvailable(a->isEnabled());
}

void HelpViewer::slotNetworkReplyFinished(QNetworkReply *reply)
{
    if (reply && reply->error() != QNetworkReply::NoError) {
        setSource(QUrl(Help::Constants::AboutBlank));
        setHtml(HelpViewer::PageNotFoundMessage.arg(reply->url().toString()
            + QString::fromLatin1("

Error: %1").arg(reply->errorString())));
    }
}

// -- private

bool HelpViewer::eventFilter(QObject *obj, QEvent *event)
{
    if (event->type() == QEvent::KeyPress) {
        if (QKeyEvent *keyEvent = static_cast<QKeyEvent*> (event)) {
            if (keyEvent->key() == Qt::Key_Slash)
                emit openFindToolBar();
        }
    }
    return QWebView::eventFilter(obj, event);
}

void HelpViewer::contextMenuEvent(QContextMenuEvent *event)
{
    QWebView::contextMenuEvent(event);
}

#endif  // !QT_NO_WEBKIT
<|endoftext|>


<commit_before>// Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
#include <rapicorn.hh>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <string.h>
#include "liststore.cc"

namespace {
using namespace Rapicorn;

static void
fill_store (ListStore &lstore, const String &dirname)
{
  DIR *d = opendir (dirname.c_str());
  lstore.clear();
  if (!d)
    {
      critical ("failed to access directory: %s: %s", dirname.c_str(), ::strerror (errno));
      return;
    }
  struct dirent *e = readdir (d);
  size_t i = 0;
  while (e)
    {
#if 0 // FIXME: need proper record support in Aida::Any
      AnySeq row;
      row.append_back() <<= ++i;
      row.append_back() <<= e->d_ino;
      row.append_back() <<= e->d_type;
      row.append_back() <<= e->d_name;
#endif
      Any row;
      row <<= string_format ("%zu) %s %s %d %lu", i, e->d_name,
                             i % 10 == 0 ? string_multiply ("
", 1 + i / 10).c_str() : "",
                             e->d_type, e->d_ino);
      lstore.insert (lstore.count(), row);
      e = readdir (d);
      i++;
    }
  closedir (d);
}

class ListModelBinding {
  class BindingKey : public DataKey<ListModelBinding*> {
    virtual void destroy (ListModelBinding *lbinding)
    { delete (lbinding); }
  };
  static BindingKey lm_binding_key;
  void disconnect ();
  ListStore &store;
  size_t conid_updates_;
  ListModelRelayH lrelay_;
  size_t conid_refill_;
  void refill (const UpdateRequest &urequest);
public:
  ListModelBinding (ListStore &init_store, ListModelRelayH init_lrelay);
  ~ListModelBinding();
};
ListModelBinding::BindingKey ListModelBinding::lm_binding_key;

ListModelBinding::ListModelBinding (ListStore &init_store, ListModelRelayH init_lrelay) :
  store (init_store), lrelay_ (init_lrelay)
{
  assert_return (lrelay_ != NULL);
  store.set_data (&lm_binding_key, this);
  conid_updates_ = store.sig_updates() += slot (lrelay_, &ListModelRelayH::update);
  conid_refill_  = lrelay_.sig_refill() += Aida::slot (*this, &ListModelBinding::refill);
}

ListModelBinding::~ListModelBinding()
{
  if (lrelay_ != NULL)
    disconnect();
}

void
ListModelBinding::disconnect()
{
  assert_return (lrelay_ != NULL);
  store.sig_updates() -= conid_updates_;
  lrelay_.sig_refill() -= conid_refill_;
  lrelay_ = lrelay_.down_cast (lrelay_._null_handle());
}

void
ListModelBinding::refill (const UpdateRequest &urequest)
{
  if (urequest.kind == UPDATE_READ)
    {
      AnySeq aseq;
      for (ssize_t i = urequest.rowspan.start; i < urequest.rowspan.start + urequest.rowspan.length; i++)
        aseq.append_back() = store.row (i);
      lrelay_.fill (urequest.rowspan.start, aseq);
    }
}

static bool
app_bind_list_store (ListStore &store, const String &path)
{
  ListModelRelayH lrelay_ = ApplicationH::the().create_list_model_relay (path);
  if (lrelay_ == NULL)
    return false;
  ListModelBinding *lbinding = new ListModelBinding (store, lrelay_);
  (void) lbinding; // ownership is kept via DataKey on ListStore
  return true;
}

static void
fill_test_store (ListStore &lstore)
{
  lstore.clear();
  for (uint i = 0; i < 20; i++)
    {
      String s;
      if (i && (i % 10) == 0)
        s = string_format ("* %u SMALL ROW (watch scroll direction)", i);
      else
        s = string_format ("|
|
| %u
|
|", i);
      Any row;
      row <<= s;
      lstore.insert (lstore.count(), row);
    }
}

extern "C" int
main (int   argc,
      char *argv[])
{
  // initialize Rapicorn
  ApplicationH app = init_app ("RapicornFileView", &argc, argv);

  // find and load GUI definitions relative to argv[0]
  app.auto_load ("RapicornFileView", "fileview.xml", argv[0]);

  // create and bind list store
  ListStore &store = *new ListStore();
  bool bsuccess = app_bind_list_store (store, "//local/data/fileview/main");
  assert (bsuccess);

  // create, bind and fill testing list store
  ListStore &test_store = *new ListStore();
  bsuccess = app_bind_list_store (test_store, "//local/data/fileview/test_store");
  assert (bsuccess);
  fill_test_store (test_store);

  // create main window
  WindowH window = app.create_window ("RapicornFileView:main-dialog", Strings ("list-model=//local/data/fileview/main"));
  // WindowH window = app.create_window ("RapicornFileView:main-dialog", Strings ("list-model=//local/data/fileview/test_store"));
  window.show();

  // load directory data
  fill_store (store, ".");

  // run event loops while windows are on screen
  return app.run_and_exit();
}

} // anon
<commit_msg>TESTS: remove useless string_format() argument width specifiers<commit_after>// Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
#include <rapicorn.hh>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <string.h>
#include "liststore.cc"

namespace {
using namespace Rapicorn;

static void
fill_store (ListStore &lstore, const String &dirname)
{
  DIR *d = opendir (dirname.c_str());
  lstore.clear();
  if (!d)
    {
      critical ("failed to access directory: %s: %s", dirname.c_str(), ::strerror (errno));
      return;
    }
  struct dirent *e = readdir (d);
  size_t i = 0;
  while (e)
    {
#if 0 // FIXME: need proper record support in Aida::Any
      AnySeq row;
      row.append_back() <<= ++i;
      row.append_back() <<= e->d_ino;
      row.append_back() <<= e->d_type;
      row.append_back() <<= e->d_name;
#endif
      Any row;
      row <<= string_format ("%u) %s %s %d %u", i, e->d_name,
                             i % 10 == 0 ? string_multiply ("
", 1 + i / 10).c_str() : "",
                             e->d_type, e->d_ino);
      lstore.insert (lstore.count(), row);
      e = readdir (d);
      i++;
    }
  closedir (d);
}

class ListModelBinding {
  class BindingKey : public DataKey<ListModelBinding*> {
    virtual void destroy (ListModelBinding *lbinding)
    { delete (lbinding); }
  };
  static BindingKey lm_binding_key;
  void disconnect ();
  ListStore &store;
  size_t conid_updates_;
  ListModelRelayH lrelay_;
  size_t conid_refill_;
  void refill (const UpdateRequest &urequest);
public:
  ListModelBinding (ListStore &init_store, ListModelRelayH init_lrelay);
  ~ListModelBinding();
};
ListModelBinding::BindingKey ListModelBinding::lm_binding_key;

ListModelBinding::ListModelBinding (ListStore &init_store, ListModelRelayH init_lrelay) :
  store (init_store), lrelay_ (init_lrelay)
{
  assert_return (lrelay_ != NULL);
  store.set_data (&lm_binding_key, this);
  conid_updates_ = store.sig_updates() += slot (lrelay_, &ListModelRelayH::update);
  conid_refill_  = lrelay_.sig_refill() += Aida::slot (*this, &ListModelBinding::refill);
}

ListModelBinding::~ListModelBinding()
{
  if (lrelay_ != NULL)
    disconnect();
}

void
ListModelBinding::disconnect()
{
  assert_return (lrelay_ != NULL);
  store.sig_updates() -= conid_updates_;
  lrelay_.sig_refill() -= conid_refill_;
  lrelay_ = lrelay_.down_cast (lrelay_._null_handle());
}

void
ListModelBinding::refill (const UpdateRequest &urequest)
{
  if (urequest.kind == UPDATE_READ)
    {
      AnySeq aseq;
      for (ssize_t i = urequest.rowspan.start; i < urequest.rowspan.start + urequest.rowspan.length; i++)
        aseq.append_back() = store.row (i);
      lrelay_.fill (urequest.rowspan.start, aseq);
    }
}

static bool
app_bind_list_store (ListStore &store, const String &path)
{
  ListModelRelayH lrelay_ = ApplicationH::the().create_list_model_relay (path);
  if (lrelay_ == NULL)
    return false;
  ListModelBinding *lbinding = new ListModelBinding (store, lrelay_);
  (void) lbinding; // ownership is kept via DataKey on ListStore
  return true;
}

static void
fill_test_store (ListStore &lstore)
{
  lstore.clear();
  for (uint i = 0; i < 20; i++)
    {
      String s;
      if (i && (i % 10) == 0)
        s = string_format ("* %u SMALL ROW (watch scroll direction)", i);
      else
        s = string_format ("|
|
| %u
|
|", i);
      Any row;
      row <<= s;
      lstore.insert (lstore.count(), row);
    }
}

extern "C" int
main (int   argc,
      char *argv[])
{
  // initialize Rapicorn
  ApplicationH app = init_app ("RapicornFileView", &argc, argv);

  // find and load GUI definitions relative to argv[0]
  app.auto_load ("RapicornFileView", "fileview.xml", argv[0]);

  // create and bind list store
  ListStore &store = *new ListStore();
  bool bsuccess = app_bind_list_store (store, "//local/data/fileview/main");
  assert (bsuccess);

  // create, bind and fill testing list store
  ListStore &test_store = *new ListStore();
  bsuccess = app_bind_list_store (test_store, "//local/data/fileview/test_store");
  assert (bsuccess);
  fill_test_store (test_store);

  // create main window
  WindowH window = app.create_window ("RapicornFileView:main-dialog", Strings ("list-model=//local/data/fileview/main"));
  // WindowH window = app.create_window ("RapicornFileView:main-dialog", Strings ("list-model=//local/data/fileview/test_store"));
  window.show();

  // load directory data
  fill_store (store, ".");

  // run event loops while windows are on screen
  return app.run_and_exit();
}

} // anon
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used 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.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <qtest.h>
#include <QLibraryInfo>
#include <QDir>
#include <QProcess>
#include <QDebug>

#define CONCURRENT

#ifdef CONCURRENT
#include <QFutureSynchronizer>
#include <QtConcurrentRun>
#endif

class tst_examples : public QObject
{
    Q_OBJECT
public:
    tst_examples();

private slots:
#ifndef CONCURRENT
    void examples_data();
#endif
    void examples();

    void namingConvention();
private:
    QString qmlruntime;
    QStringList excludedDirs;

    void namingConvention(const QDir &);
    QStringList findQmlFiles(const QDir &);
};

tst_examples::tst_examples()
{
    QString binaries = QLibraryInfo::location(QLibraryInfo::BinariesPath);

#if defined(Q_WS_MAC)
    qmlruntime = QDir(binaries).absoluteFilePath("qml.app/Contents/MacOS/qml");
#elif defined(Q_WS_WIN)
    qmlruntime = QDir(binaries).absoluteFilePath("qml.exe");
#else
    qmlruntime = QDir(binaries).absoluteFilePath("qml");
#endif

    // Add directories you want excluded here
    excludedDirs << "examples/declarative/extending";
    excludedDirs << "examples/declarative/plugins";
    excludedDirs << "examples/declarative/proxywidgets";
    excludedDirs << "examples/declarative/gestures";
#ifdef QT_NO_XMLPATTERNS
    excludedDirs << "examples/declarative/xmldata";
    excludedDirs << "demos/declarative/twitter";
    excludedDirs << "demos/declarative/flickr";
    excludedDirs << "demos/declarative/photoviewer";
#endif
}

/*
This tests that the demos and examples follow the naming convention required
to have them tested by the examples() test.
*/
void tst_examples::namingConvention(const QDir &d)
{
    for (int ii = 0; ii < excludedDirs.count(); ++ii) {
        QString s = excludedDirs.at(ii);
        if (d.absolutePath().endsWith(s))
            return;
    }

    QStringList files = d.entryList(QStringList() << QLatin1String("*.qml"),
                                    QDir::Files);

    bool seenQml = !files.isEmpty();
    bool seenLowercase = false;

    foreach (const QString &file, files) {
        if (file.at(0).isLower())
            seenLowercase = true;
    }

    if (!seenQml) {
        QStringList dirs = d.entryList(QDir::Dirs | QDir::NoDotAndDotDot |
                QDir::NoSymLinks);
        foreach (const QString &dir, dirs) {
            QDir sub = d;
            sub.cd(dir);
            namingConvention(sub);
        }
    } else if(!seenLowercase) {
        QTest::qFail(QString("Directory " + d.absolutePath() + " violates naming convention").toLatin1().constData(), __FILE__, __LINE__);
    }
}

void tst_examples::namingConvention()
{
    QString examples = QLibraryInfo::location(QLibraryInfo::ExamplesPath);
    QString demos = QLibraryInfo::location(QLibraryInfo::DemosPath);

    namingConvention(QDir(examples));
    namingConvention(QDir(demos));
}

QStringList tst_examples::findQmlFiles(const QDir &d)
{
    for (int ii = 0; ii < excludedDirs.count(); ++ii) {
        QString s = excludedDirs.at(ii);
        if (d.absolutePath().endsWith(s))
            return QStringList();
    }

    QStringList rv;

    QStringList files = d.entryList(QStringList() << QLatin1String("*.qml"),
                                    QDir::Files);
    foreach (const QString &file, files) {
        if (file.at(0).isLower()) {
            rv << d.absoluteFilePath(file);
        }
    }

    QStringList dirs = d.entryList(QDir::Dirs | QDir::NoDotAndDotDot |
                                   QDir::NoSymLinks);
    foreach (const QString &dir, dirs) {
        QDir sub = d;
        sub.cd(dir);
        rv << findQmlFiles(sub);
    }

    return rv;
}

/*
This test runs all the examples in the declarative UI source tree and ensures
that they start and exit cleanly.

Examples are any .qml files under the examples/ or demos/ directory that start
with a lower case letter.
*/
#ifndef CONCURRENT
void tst_examples::examples_data()
{
    QTest::addColumn<QString>("file");

    QString examples = QLibraryInfo::location(QLibraryInfo::ExamplesPath);
    QString demos = QLibraryInfo::location(QLibraryInfo::DemosPath);
    QString snippets = QLatin1String(SRCDIR) + "/../../../../doc/src/snippets/";

    QStringList files;
    files << findQmlFiles(QDir(examples));
    files << findQmlFiles(QDir(demos));
    files << findQmlFiles(QDir(snippets));

    foreach (const QString &file, files)
        QTest::newRow(file.toLatin1().constData()) << file;
}
#endif

#ifdef CONCURRENT
#define THREADS 5

struct Example {
public:
    Example() : result(Unknown) {}

    enum Result { Pass, Unknown, Fail };
    Result result;
    QString file;
    QString qmlruntime;

    void run();
};

void Example::run()
{
    QFileInfo fi(file);
    QFileInfo dir(fi.path());
    QString script = SRCDIR "/data/"+dir.baseName()+"/"+fi.baseName();
    QFileInfo testdata(script+".qml");
    QStringList arguments;
    arguments << "-script" << (testdata.exists() ? script : QLatin1String(SRCDIR "/data/dummytest"))
              << "-scriptopts" << "play,testerror,exitoncomplete,exitonfailure"
              << file;
    QProcess p;
    p.start(qmlruntime, arguments);
    if (!p.waitForFinished()) {
        result = Fail;
        return;
    }

    if (p.exitStatus() != QProcess::NormalExit || p.exitCode() != 0)
        qWarning() << p.readAllStandardOutput() << p.readAllStandardError();

    if (p.exitStatus() != QProcess::NormalExit ||
        p.exitCode() != 0) {
        result = Fail;
        return;
    } else {
        result = Pass;
        return;
    }
}

#endif
void tst_examples::examples()
{
#ifdef CONCURRENT
    QThreadPool::globalInstance()->setMaxThreadCount(5);

    QString examples = QLibraryInfo::location(QLibraryInfo::ExamplesPath);
    QString demos = QLibraryInfo::location(QLibraryInfo::DemosPath);
    QString snippets = QLatin1String(SRCDIR) + "/../../../../doc/src/snippets/";

    QStringList files;
    files << findQmlFiles(QDir(examples));
    files << findQmlFiles(QDir(demos));
    files << findQmlFiles(QDir(snippets));

    QList<Example> tests;

    for (int ii = 0; ii < files.count(); ++ii) {
        Example e;
        e.file = files.at(ii);
        e.qmlruntime = qmlruntime;
        tests << e;
    }

    QFutureSynchronizer<void> sync;

    for (int ii = 0; ii < tests.count(); ++ii) {
        QFuture<void> r = QtConcurrent::run(tests.at(ii), &Example::run);
        sync.addFuture(r);
    }

    sync.waitForFinished();

    for (int ii = 0; ii < tests.count(); ++ii)
        QVERIFY(tests.at(ii).result == Example::Pass);

#else

    QFETCH(QString, file);

    QFileInfo fi(file);
    QFileInfo dir(fi.path());
    QString script = SRCDIR "/data/"+dir.baseName()+"/"+fi.baseName();
    QFileInfo testdata(script+".qml");
    QStringList arguments;
    arguments << "-script" << (testdata.exists() ? script : QLatin1String(SRCDIR "/data/dummytest"))
              << "-scriptopts" << "play,testerror,exitoncomplete,exitonfailure"
              << file;
#ifdef Q_WS_QWS
    arguments << "-qws";
#endif

    QProcess p;
    p.start(qmlruntime, arguments);
    QVERIFY(p.waitForFinished());
    if (p.exitStatus() != QProcess::NormalExit || p.exitCode() != 0)
        qWarning() << p.readAllStandardOutput() << p.readAllStandardError();
    QCOMPARE(p.exitStatus(), QProcess::NormalExit);
    QCOMPARE(p.exitCode(), 0);
#endif
}

QTEST_MAIN(tst_examples)

#include "tst_examples.moc"
<commit_msg>Fix test (run with -qws on QWS).<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used 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.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <qtest.h>
#include <QLibraryInfo>
#include <QDir>
#include <QProcess>
#include <QDebug>

#define CONCURRENT

#ifdef CONCURRENT
#include <QFutureSynchronizer>
#include <QtConcurrentRun>
#endif

class tst_examples : public QObject
{
    Q_OBJECT
public:
    tst_examples();

private slots:
#ifndef CONCURRENT
    void examples_data();
#endif
    void examples();

    void namingConvention();
private:
    QString qmlruntime;
    QStringList excludedDirs;

    void namingConvention(const QDir &);
    QStringList findQmlFiles(const QDir &);
};

tst_examples::tst_examples()
{
    QString binaries = QLibraryInfo::location(QLibraryInfo::BinariesPath);

#if defined(Q_WS_MAC)
    qmlruntime = QDir(binaries).absoluteFilePath("qml.app/Contents/MacOS/qml");
#elif defined(Q_WS_WIN)
    qmlruntime = QDir(binaries).absoluteFilePath("qml.exe");
#else
    qmlruntime = QDir(binaries).absoluteFilePath("qml");
#endif

    // Add directories you want excluded here
    excludedDirs << "examples/declarative/extending";
    excludedDirs << "examples/declarative/plugins";
    excludedDirs << "examples/declarative/proxywidgets";
    excludedDirs << "examples/declarative/gestures";
#ifdef QT_NO_XMLPATTERNS
    excludedDirs << "examples/declarative/xmldata";
    excludedDirs << "demos/declarative/twitter";
    excludedDirs << "demos/declarative/flickr";
    excludedDirs << "demos/declarative/photoviewer";
#endif
}

/*
This tests that the demos and examples follow the naming convention required
to have them tested by the examples() test.
*/
void tst_examples::namingConvention(const QDir &d)
{
    for (int ii = 0; ii < excludedDirs.count(); ++ii) {
        QString s = excludedDirs.at(ii);
        if (d.absolutePath().endsWith(s))
            return;
    }

    QStringList files = d.entryList(QStringList() << QLatin1String("*.qml"),
                                    QDir::Files);

    bool seenQml = !files.isEmpty();
    bool seenLowercase = false;

    foreach (const QString &file, files) {
        if (file.at(0).isLower())
            seenLowercase = true;
    }

    if (!seenQml) {
        QStringList dirs = d.entryList(QDir::Dirs | QDir::NoDotAndDotDot |
                QDir::NoSymLinks);
        foreach (const QString &dir, dirs) {
            QDir sub = d;
            sub.cd(dir);
            namingConvention(sub);
        }
    } else if(!seenLowercase) {
        QTest::qFail(QString("Directory " + d.absolutePath() + " violates naming convention").toLatin1().constData(), __FILE__, __LINE__);
    }
}

void tst_examples::namingConvention()
{
    QString examples = QLibraryInfo::location(QLibraryInfo::ExamplesPath);
    QString demos = QLibraryInfo::location(QLibraryInfo::DemosPath);

    namingConvention(QDir(examples));
    namingConvention(QDir(demos));
}

QStringList tst_examples::findQmlFiles(const QDir &d)
{
    for (int ii = 0; ii < excludedDirs.count(); ++ii) {
        QString s = excludedDirs.at(ii);
        if (d.absolutePath().endsWith(s))
            return QStringList();
    }

    QStringList rv;

    QStringList files = d.entryList(QStringList() << QLatin1String("*.qml"),
                                    QDir::Files);
    foreach (const QString &file, files) {
        if (file.at(0).isLower()) {
            rv << d.absoluteFilePath(file);
        }
    }

    QStringList dirs = d.entryList(QDir::Dirs | QDir::NoDotAndDotDot |
                                   QDir::NoSymLinks);
    foreach (const QString &dir, dirs) {
        QDir sub = d;
        sub.cd(dir);
        rv << findQmlFiles(sub);
    }

    return rv;
}

/*
This test runs all the examples in the declarative UI source tree and ensures
that they start and exit cleanly.

Examples are any .qml files under the examples/ or demos/ directory that start
with a lower case letter.
*/
#ifndef CONCURRENT
void tst_examples::examples_data()
{
    QTest::addColumn<QString>("file");

    QString examples = QLibraryInfo::location(QLibraryInfo::ExamplesPath);
    QString demos = QLibraryInfo::location(QLibraryInfo::DemosPath);
    QString snippets = QLatin1String(SRCDIR) + "/../../../../doc/src/snippets/";

    QStringList files;
    files << findQmlFiles(QDir(examples));
    files << findQmlFiles(QDir(demos));
    files << findQmlFiles(QDir(snippets));

    foreach (const QString &file, files)
        QTest::newRow(file.toLatin1().constData()) << file;
}
#endif

#ifdef CONCURRENT
#define THREADS 5

struct Example {
public:
    Example() : result(Unknown) {}

    enum Result { Pass, Unknown, Fail };
    Result result;
    QString file;
    QString qmlruntime;

    void run();
};

void Example::run()
{
    QFileInfo fi(file);
    QFileInfo dir(fi.path());
    QString script = SRCDIR "/data/"+dir.baseName()+"/"+fi.baseName();
    QFileInfo testdata(script+".qml");
    QStringList arguments;
    arguments << "-script" << (testdata.exists() ? script : QLatin1String(SRCDIR "/data/dummytest"))
              << "-scriptopts" << "play,testerror,exitoncomplete,exitonfailure"
              << file;
#ifdef Q_WS_QWS
    arguments << "-qws";
#endif

    QProcess p;
    p.start(qmlruntime, arguments);
    if (!p.waitForFinished()) {
        result = Fail;
        return;
    }

    if (p.exitStatus() != QProcess::NormalExit || p.exitCode() != 0)
        qWarning() << p.readAllStandardOutput() << p.readAllStandardError();

    if (p.exitStatus() != QProcess::NormalExit ||
        p.exitCode() != 0) {
        result = Fail;
        return;
    } else {
        result = Pass;
        return;
    }
}

#endif
void tst_examples::examples()
{
#ifdef CONCURRENT
    QThreadPool::globalInstance()->setMaxThreadCount(5);

    QString examples = QLibraryInfo::location(QLibraryInfo::ExamplesPath);
    QString demos = QLibraryInfo::location(QLibraryInfo::DemosPath);
    QString snippets = QLatin1String(SRCDIR) + "/../../../../doc/src/snippets/";

    QStringList files;
    files << findQmlFiles(QDir(examples));
    files << findQmlFiles(QDir(demos));
    files << findQmlFiles(QDir(snippets));

    QList<Example> tests;

    for (int ii = 0; ii < files.count(); ++ii) {
        Example e;
        e.file = files.at(ii);
        e.qmlruntime = qmlruntime;
        tests << e;
    }

    QFutureSynchronizer<void> sync;

    for (int ii = 0; ii < tests.count(); ++ii) {
        QFuture<void> r = QtConcurrent::run(tests.at(ii), &Example::run);
        sync.addFuture(r);
    }

    sync.waitForFinished();

    for (int ii = 0; ii < tests.count(); ++ii)
        QVERIFY(tests.at(ii).result == Example::Pass);

#else

    QFETCH(QString, file);

    QFileInfo fi(file);
    QFileInfo dir(fi.path());
    QString script = SRCDIR "/data/"+dir.baseName()+"/"+fi.baseName();
    QFileInfo testdata(script+".qml");
    QStringList arguments;
    arguments << "-script" << (testdata.exists() ? script : QLatin1String(SRCDIR "/data/dummytest"))
              << "-scriptopts" << "play,testerror,exitoncomplete,exitonfailure"
              << file;
#ifdef Q_WS_QWS
    arguments << "-qws";
#endif

    QProcess p;
    p.start(qmlruntime, arguments);
    QVERIFY(p.waitForFinished());
    if (p.exitStatus() != QProcess::NormalExit || p.exitCode() != 0)
        qWarning() << p.readAllStandardOutput() << p.readAllStandardError();
    QCOMPARE(p.exitStatus(), QProcess::NormalExit);
    QCOMPARE(p.exitCode(), 0);
#endif
}

QTEST_MAIN(tst_examples)

#include "tst_examples.moc"
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used 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.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtTest/QtTest>
#include <QDebug>
#include "multimedia/qmediaplaylist.h"

class tst_QMediaPlaylist : public QObject
{
    Q_OBJECT
public slots:
    void init();
    void cleanup();
    void initTestCase();

private slots:
    void construction();
    void append();
    void insert();
    void clear();
    void removeItems();
    void currentItem();
    void saveAndLoad();
    void playbackMode();
    void playbackMode_data();

private:
    QMediaContent content1;
    QMediaContent content2;
    QMediaContent content3;
};

void tst_QMediaPlaylist::init()
{
}

void tst_QMediaPlaylist::initTestCase()
{
    content1 = QMediaContent(QUrl(QLatin1String("file:///1")));
    content2 = QMediaContent(QUrl(QLatin1String("file:///2")));
    content3 = QMediaContent(QUrl(QLatin1String("file:///3")));
}

void tst_QMediaPlaylist::cleanup()
{
}

void tst_QMediaPlaylist::construction()
{
    QMediaPlaylist playlist;
    QCOMPARE(playlist.size(), 0);
    QVERIFY(playlist.isEmpty());
}

void tst_QMediaPlaylist::append()
{
    QMediaPlaylist playlist;
    QVERIFY(!playlist.isReadOnly());

    playlist.appendItem(content1);
    QCOMPARE(playlist.size(), 1);
    QCOMPARE(playlist.media(0), content1);

    playlist.appendItem(content2);
    QCOMPARE(playlist.size(), 2);
    QCOMPARE(playlist.media(1), content2);
}

void tst_QMediaPlaylist::insert()
{
    QMediaPlaylist playlist;
    QVERIFY(!playlist.isReadOnly());

    playlist.appendItem(content1);
    QCOMPARE(playlist.size(), 1);
    QCOMPARE(playlist.media(0), content1);

    playlist.appendItem(content2);
    QCOMPARE(playlist.size(), 2);
    QCOMPARE(playlist.media(1), content2);

    QSignalSpy aboutToBeInsertedSignalSpy(&playlist, SIGNAL(itemsAboutToBeInserted(int,int)));
    QSignalSpy insertedSignalSpy(&playlist, SIGNAL(itemsInserted(int,int)));

    playlist.insertItem(1, content3);
    QCOMPARE(playlist.size(), 3);
    QCOMPARE(playlist.media(0), content1);
    QCOMPARE(playlist.media(1), content3);
    QCOMPARE(playlist.media(2), content2);

    QCOMPARE(aboutToBeInsertedSignalSpy.count(), 1);
    QCOMPARE(aboutToBeInsertedSignalSpy.first()[0].toInt(), 1);
    QCOMPARE(aboutToBeInsertedSignalSpy.first()[1].toInt(), 1);

    QCOMPARE(insertedSignalSpy.count(), 1);
    QCOMPARE(insertedSignalSpy.first()[0].toInt(), 1);
    QCOMPARE(insertedSignalSpy.first()[1].toInt(), 1);
}

void tst_QMediaPlaylist::currentItem()
{
    QMediaPlaylist playlist;
    playlist.appendItem(content1);
    playlist.appendItem(content2);

    QCOMPARE(playlist.currentPosition(), -1);
    QCOMPARE(playlist.currentMedia(), QMediaContent());

    QCOMPARE(playlist.nextPosition(), 0);
    QCOMPARE(playlist.nextPosition(2), 1);
    QCOMPARE(playlist.previousPosition(), 1);
    QCOMPARE(playlist.previousPosition(2), 0);

    playlist.setCurrentPosition(0);
    QCOMPARE(playlist.currentPosition(), 0);
    QCOMPARE(playlist.currentMedia(), content1);

    QCOMPARE(playlist.nextPosition(), 1);
    QCOMPARE(playlist.nextPosition(2), -1);
    QCOMPARE(playlist.previousPosition(), -1);
    QCOMPARE(playlist.previousPosition(2), -1);

    playlist.setCurrentPosition(1);
    QCOMPARE(playlist.currentPosition(), 1);
    QCOMPARE(playlist.currentMedia(), content2);

    QCOMPARE(playlist.nextPosition(), -1);
    QCOMPARE(playlist.nextPosition(2), -1);
    QCOMPARE(playlist.previousPosition(), 0);
    QCOMPARE(playlist.previousPosition(2), -1);

    //warning is expected, jump outsize of playlist range
    playlist.setCurrentPosition(2);
    QCOMPARE(playlist.currentPosition(), -1);
    QCOMPARE(playlist.currentMedia(), QMediaContent());
}

void tst_QMediaPlaylist::clear()
{
    QMediaPlaylist playlist;
    playlist.appendItem(content1);
    playlist.appendItem(content2);

    playlist.clear();
    QVERIFY(playlist.isEmpty());
    QCOMPARE(playlist.size(), 0);
}

void tst_QMediaPlaylist::removeItems()
{
    QMediaPlaylist playlist;
    playlist.appendItem(content1);
    playlist.appendItem(content2);
    playlist.appendItem(content3);

    QSignalSpy aboutToBeRemovedSignalSpy(&playlist, SIGNAL(itemsAboutToBeRemoved(int,int)));
    QSignalSpy removedSignalSpy(&playlist, SIGNAL(itemsRemoved(int,int)));
    playlist.removeItem(1);
    QCOMPARE(playlist.size(), 2);
    QCOMPARE(playlist.media(1), content3);

    QCOMPARE(aboutToBeRemovedSignalSpy.count(), 1);
    QCOMPARE(aboutToBeRemovedSignalSpy.first()[0].toInt(), 1);
    QCOMPARE(aboutToBeRemovedSignalSpy.first()[1].toInt(), 1);

    QCOMPARE(removedSignalSpy.count(), 1);
    QCOMPARE(removedSignalSpy.first()[0].toInt(), 1);
    QCOMPARE(removedSignalSpy.first()[1].toInt(), 1);

    aboutToBeRemovedSignalSpy.clear();
    removedSignalSpy.clear();

    playlist.removeItems(0,1);
    QVERIFY(playlist.isEmpty());

    QCOMPARE(aboutToBeRemovedSignalSpy.count(), 1);
    QCOMPARE(aboutToBeRemovedSignalSpy.first()[0].toInt(), 0);
    QCOMPARE(aboutToBeRemovedSignalSpy.first()[1].toInt(), 1);

    QCOMPARE(removedSignalSpy.count(), 1);
    QCOMPARE(removedSignalSpy.first()[0].toInt(), 0);
    QCOMPARE(removedSignalSpy.first()[1].toInt(), 1);

    playlist.appendItem(content1);
    playlist.appendItem(content2);
    playlist.appendItem(content3);

    playlist.removeItems(0,1);
    QCOMPARE(playlist.size(), 1);
    QCOMPARE(playlist.media(0), content3);
}

void tst_QMediaPlaylist::saveAndLoad()
{
    QMediaPlaylist playlist;
    playlist.appendItem(content1);
    playlist.appendItem(content2);
    playlist.appendItem(content3);

    QCOMPARE(playlist.error(), QMediaPlaylist::NoError);
    QVERIFY(playlist.errorString().isEmpty());

    QBuffer buffer;
    buffer.open(QBuffer::ReadWrite);

    bool res = playlist.save(&buffer, "unsupported_format");
    QVERIFY(!res);
    QVERIFY(playlist.error() != QMediaPlaylist::NoError);
    QVERIFY(!playlist.errorString().isEmpty());

    QSignalSpy errorSignal(&playlist, SIGNAL(loadFailed()));
    playlist.load(&buffer, "unsupported_format");
    QCOMPARE(errorSignal.size(), 1);
    QVERIFY(playlist.error() != QMediaPlaylist::NoError);
    QVERIFY(!playlist.errorString().isEmpty());

    //it's necessary to ensure the m3u plugin is loaded for this test
    /*
    res = playlist.save(&buffer, "m3u");

    QVERIFY(res);
    QVERIFY(buffer.pos() > 0);
    buffer.seek(0);

    QMediaPlaylist playlist2;
    playlist2.load(&buffer, "m3u");
    QCOMPARE(playlist.error(), QMediaPlaylist::NoError);

    QCOMPARE(playlist.size(), playlist2.size());
    QCOMPARE(playlist.media(0), playlist2.media(0));
    QCOMPARE(playlist.media(1), playlist2.media(1));
    QCOMPARE(playlist.media(3), playlist2.media(3));
    */

}

void tst_QMediaPlaylist::playbackMode_data()
{
    QTest::addColumn<QMediaPlaylist::PlaybackMode>("playbackMode");
    QTest::addColumn<int>("expectedPrevious");
    QTest::addColumn<int>("pos");
    QTest::addColumn<int>("expectedNext");

    QTest::newRow("Linear, 0") << QMediaPlaylist::Linear << -1 << 0 << 1;
    QTest::newRow("Linear, 1") << QMediaPlaylist::Linear << 0 << 1 << 2;
    QTest::newRow("Linear, 2") << QMediaPlaylist::Linear << 1 << 2 << -1;

    QTest::newRow("Loop, 0") << QMediaPlaylist::Loop << 2 << 0 << 1;
    QTest::newRow("Loop, 1") << QMediaPlaylist::Loop << 0 << 1 << 2;
    QTest::newRow("Lopp, 2") << QMediaPlaylist::Loop << 1 << 2 << 0;

    QTest::newRow("ItemOnce, 1") << QMediaPlaylist::CurrentItemOnce << -1 << 1 << -1;
    QTest::newRow("ItemInLoop, 1") << QMediaPlaylist::CurrentItemInLoop << 1 << 1 << 1;

}

void tst_QMediaPlaylist::playbackMode()
{
    QFETCH(QMediaPlaylist::PlaybackMode, playbackMode);
    QFETCH(int, expectedPrevious);
    QFETCH(int, pos);
    QFETCH(int, expectedNext);

    QMediaPlaylist playlist;
    playlist.appendItem(content1);
    playlist.appendItem(content2);
    playlist.appendItem(content3);

    QCOMPARE(playlist.playbackMode(), QMediaPlaylist::Linear);
    QCOMPARE(playlist.currentPosition(), -1);

    playlist.setPlaybackMode(playbackMode);
    QCOMPARE(playlist.playbackMode(), playbackMode);

    playlist.setCurrentPosition(pos);
    QCOMPARE(playlist.currentPosition(), pos);
    QCOMPARE(playlist.nextPosition(), expectedNext);
    QCOMPARE(playlist.previousPosition(), expectedPrevious);

    playlist.next();
    QCOMPARE(playlist.currentPosition(), expectedNext);

    playlist.setCurrentPosition(pos);
    playlist.previous();
    QCOMPARE(playlist.currentPosition(), expectedPrevious);
}

QTEST_MAIN(tst_QMediaPlaylist)
#include "tst_qmediaplaylist.moc"

<commit_msg>added test for QMediaPlaylist::shuffle()<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used 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.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtTest/QtTest>
#include <QDebug>
#include "multimedia/qmediaplaylist.h"

class tst_QMediaPlaylist : public QObject
{
    Q_OBJECT
public slots:
    void init();
    void cleanup();
    void initTestCase();

private slots:
    void construction();
    void append();
    void insert();
    void clear();
    void removeItems();
    void currentItem();
    void saveAndLoad();
    void playbackMode();
    void playbackMode_data();
    void shuffle();

private:
    QMediaContent content1;
    QMediaContent content2;
    QMediaContent content3;
};

void tst_QMediaPlaylist::init()
{
}

void tst_QMediaPlaylist::initTestCase()
{
    content1 = QMediaContent(QUrl(QLatin1String("file:///1")));
    content2 = QMediaContent(QUrl(QLatin1String("file:///2")));
    content3 = QMediaContent(QUrl(QLatin1String("file:///3")));
}

void tst_QMediaPlaylist::cleanup()
{
}

void tst_QMediaPlaylist::construction()
{
    QMediaPlaylist playlist;
    QCOMPARE(playlist.size(), 0);
    QVERIFY(playlist.isEmpty());
}

void tst_QMediaPlaylist::append()
{
    QMediaPlaylist playlist;
    QVERIFY(!playlist.isReadOnly());

    playlist.appendItem(content1);
    QCOMPARE(playlist.size(), 1);
    QCOMPARE(playlist.media(0), content1);

    playlist.appendItem(content2);
    QCOMPARE(playlist.size(), 2);
    QCOMPARE(playlist.media(1), content2);
}

void tst_QMediaPlaylist::insert()
{
    QMediaPlaylist playlist;
    QVERIFY(!playlist.isReadOnly());

    playlist.appendItem(content1);
    QCOMPARE(playlist.size(), 1);
    QCOMPARE(playlist.media(0), content1);

    playlist.appendItem(content2);
    QCOMPARE(playlist.size(), 2);
    QCOMPARE(playlist.media(1), content2);

    QSignalSpy aboutToBeInsertedSignalSpy(&playlist, SIGNAL(itemsAboutToBeInserted(int,int)));
    QSignalSpy insertedSignalSpy(&playlist, SIGNAL(itemsInserted(int,int)));

    playlist.insertItem(1, content3);
    QCOMPARE(playlist.size(), 3);
    QCOMPARE(playlist.media(0), content1);
    QCOMPARE(playlist.media(1), content3);
    QCOMPARE(playlist.media(2), content2);

    QCOMPARE(aboutToBeInsertedSignalSpy.count(), 1);
    QCOMPARE(aboutToBeInsertedSignalSpy.first()[0].toInt(), 1);
    QCOMPARE(aboutToBeInsertedSignalSpy.first()[1].toInt(), 1);

    QCOMPARE(insertedSignalSpy.count(), 1);
    QCOMPARE(insertedSignalSpy.first()[0].toInt(), 1);
    QCOMPARE(insertedSignalSpy.first()[1].toInt(), 1);
}

void tst_QMediaPlaylist::currentItem()
{
    QMediaPlaylist playlist;
    playlist.appendItem(content1);
    playlist.appendItem(content2);

    QCOMPARE(playlist.currentPosition(), -1);
    QCOMPARE(playlist.currentMedia(), QMediaContent());

    QCOMPARE(playlist.nextPosition(), 0);
    QCOMPARE(playlist.nextPosition(2), 1);
    QCOMPARE(playlist.previousPosition(), 1);
    QCOMPARE(playlist.previousPosition(2), 0);

    playlist.setCurrentPosition(0);
    QCOMPARE(playlist.currentPosition(), 0);
    QCOMPARE(playlist.currentMedia(), content1);

    QCOMPARE(playlist.nextPosition(), 1);
    QCOMPARE(playlist.nextPosition(2), -1);
    QCOMPARE(playlist.previousPosition(), -1);
    QCOMPARE(playlist.previousPosition(2), -1);

    playlist.setCurrentPosition(1);
    QCOMPARE(playlist.currentPosition(), 1);
    QCOMPARE(playlist.currentMedia(), content2);

    QCOMPARE(playlist.nextPosition(), -1);
    QCOMPARE(playlist.nextPosition(2), -1);
    QCOMPARE(playlist.previousPosition(), 0);
    QCOMPARE(playlist.previousPosition(2), -1);

    //warning is expected, jump outsize of playlist range
    playlist.setCurrentPosition(2);
    QCOMPARE(playlist.currentPosition(), -1);
    QCOMPARE(playlist.currentMedia(), QMediaContent());
}

void tst_QMediaPlaylist::clear()
{
    QMediaPlaylist playlist;
    playlist.appendItem(content1);
    playlist.appendItem(content2);

    playlist.clear();
    QVERIFY(playlist.isEmpty());
    QCOMPARE(playlist.size(), 0);
}

void tst_QMediaPlaylist::removeItems()
{
    QMediaPlaylist playlist;
    playlist.appendItem(content1);
    playlist.appendItem(content2);
    playlist.appendItem(content3);

    QSignalSpy aboutToBeRemovedSignalSpy(&playlist, SIGNAL(itemsAboutToBeRemoved(int,int)));
    QSignalSpy removedSignalSpy(&playlist, SIGNAL(itemsRemoved(int,int)));
    playlist.removeItem(1);
    QCOMPARE(playlist.size(), 2);
    QCOMPARE(playlist.media(1), content3);

    QCOMPARE(aboutToBeRemovedSignalSpy.count(), 1);
    QCOMPARE(aboutToBeRemovedSignalSpy.first()[0].toInt(), 1);
    QCOMPARE(aboutToBeRemovedSignalSpy.first()[1].toInt(), 1);

    QCOMPARE(removedSignalSpy.count(), 1);
    QCOMPARE(removedSignalSpy.first()[0].toInt(), 1);
    QCOMPARE(removedSignalSpy.first()[1].toInt(), 1);

    aboutToBeRemovedSignalSpy.clear();
    removedSignalSpy.clear();

    playlist.removeItems(0,1);
    QVERIFY(playlist.isEmpty());

    QCOMPARE(aboutToBeRemovedSignalSpy.count(), 1);
    QCOMPARE(aboutToBeRemovedSignalSpy.first()[0].toInt(), 0);
    QCOMPARE(aboutToBeRemovedSignalSpy.first()[1].toInt(), 1);

    QCOMPARE(removedSignalSpy.count(), 1);
    QCOMPARE(removedSignalSpy.first()[0].toInt(), 0);
    QCOMPARE(removedSignalSpy.first()[1].toInt(), 1);

    playlist.appendItem(content1);
    playlist.appendItem(content2);
    playlist.appendItem(content3);

    playlist.removeItems(0,1);
    QCOMPARE(playlist.size(), 1);
    QCOMPARE(playlist.media(0), content3);
}

void tst_QMediaPlaylist::saveAndLoad()
{
    QMediaPlaylist playlist;
    playlist.appendItem(content1);
    playlist.appendItem(content2);
    playlist.appendItem(content3);

    QCOMPARE(playlist.error(), QMediaPlaylist::NoError);
    QVERIFY(playlist.errorString().isEmpty());

    QBuffer buffer;
    buffer.open(QBuffer::ReadWrite);

    bool res = playlist.save(&buffer, "unsupported_format");
    QVERIFY(!res);
    QVERIFY(playlist.error() != QMediaPlaylist::NoError);
    QVERIFY(!playlist.errorString().isEmpty());

    QSignalSpy errorSignal(&playlist, SIGNAL(loadFailed()));
    playlist.load(&buffer, "unsupported_format");
    QCOMPARE(errorSignal.size(), 1);
    QVERIFY(playlist.error() != QMediaPlaylist::NoError);
    QVERIFY(!playlist.errorString().isEmpty());

    //it's necessary to ensure the m3u plugin is loaded for this test
    /*
    res = playlist.save(&buffer, "m3u");

    QVERIFY(res);
    QVERIFY(buffer.pos() > 0);
    buffer.seek(0);

    QMediaPlaylist playlist2;
    playlist2.load(&buffer, "m3u");
    QCOMPARE(playlist.error(), QMediaPlaylist::NoError);

    QCOMPARE(playlist.size(), playlist2.size());
    QCOMPARE(playlist.media(0), playlist2.media(0));
    QCOMPARE(playlist.media(1), playlist2.media(1));
    QCOMPARE(playlist.media(3), playlist2.media(3));
    */

}

void tst_QMediaPlaylist::playbackMode_data()
{
    QTest::addColumn<QMediaPlaylist::PlaybackMode>("playbackMode");
    QTest::addColumn<int>("expectedPrevious");
    QTest::addColumn<int>("pos");
    QTest::addColumn<int>("expectedNext");

    QTest::newRow("Linear, 0") << QMediaPlaylist::Linear << -1 << 0 << 1;
    QTest::newRow("Linear, 1") << QMediaPlaylist::Linear << 0 << 1 << 2;
    QTest::newRow("Linear, 2") << QMediaPlaylist::Linear << 1 << 2 << -1;

    QTest::newRow("Loop, 0") << QMediaPlaylist::Loop << 2 << 0 << 1;
    QTest::newRow("Loop, 1") << QMediaPlaylist::Loop << 0 << 1 << 2;
    QTest::newRow("Lopp, 2") << QMediaPlaylist::Loop << 1 << 2 << 0;

    QTest::newRow("ItemOnce, 1") << QMediaPlaylist::CurrentItemOnce << -1 << 1 << -1;
    QTest::newRow("ItemInLoop, 1") << QMediaPlaylist::CurrentItemInLoop << 1 << 1 << 1;

}

void tst_QMediaPlaylist::playbackMode()
{
    QFETCH(QMediaPlaylist::PlaybackMode, playbackMode);
    QFETCH(int, expectedPrevious);
    QFETCH(int, pos);
    QFETCH(int, expectedNext);

    QMediaPlaylist playlist;
    playlist.appendItem(content1);
    playlist.appendItem(content2);
    playlist.appendItem(content3);

    QCOMPARE(playlist.playbackMode(), QMediaPlaylist::Linear);
    QCOMPARE(playlist.currentPosition(), -1);

    playlist.setPlaybackMode(playbackMode);
    QCOMPARE(playlist.playbackMode(), playbackMode);

    playlist.setCurrentPosition(pos);
    QCOMPARE(playlist.currentPosition(), pos);
    QCOMPARE(playlist.nextPosition(), expectedNext);
    QCOMPARE(playlist.previousPosition(), expectedPrevious);

    playlist.next();
    QCOMPARE(playlist.currentPosition(), expectedNext);

    playlist.setCurrentPosition(pos);
    playlist.previous();
    QCOMPARE(playlist.currentPosition(), expectedPrevious);
}

void tst_QMediaPlaylist::shuffle()
{
    QMediaPlaylist playlist;
    QList<QMediaContent> contentList;

    for (int i=0; i<100; i++) {
        QMediaContent content(QUrl(QString::number(i)));
        contentList.append(content);
        playlist.appendItem(content);
    }

    playlist.shuffle();

    QList<QMediaContent> shuffledContentList;
    for (int i=0; i<playlist.size(); i++)
        shuffledContentList.append(playlist.media(i));

    QVERIFY(contentList != shuffledContentList);

}

QTEST_MAIN(tst_QMediaPlaylist)
#include "tst_qmediaplaylist.moc"

<|endoftext|>


<commit_before>#include <rw.h>
#include <skeleton.h>
#include <assert.h>

rw::V3d zero = { 0.0f, 0.0f, 0.0f };
struct SceneGlobals {
	rw::World *world;
	rw::Camera *camera;
} Scene;
rw::EngineOpenParams engineOpenParams;

void
Init(void)
{
	sk::globals.windowtitle = "ImGui test";
	sk::globals.width = 1280;
	sk::globals.height = 800;
	sk::globals.quit = 0;
}

bool
attachPlugins(void)
{
	rw::ps2::registerPDSPlugin(40);
	rw::ps2::registerPluginPDSPipes();

	rw::registerMeshPlugin();
	rw::registerNativeDataPlugin();
	rw::registerAtomicRightsPlugin();
	rw::registerMaterialRightsPlugin();
	rw::xbox::registerVertexFormatPlugin();
	rw::registerSkinPlugin();
	rw::registerUserDataPlugin();
	rw::registerHAnimPlugin();
	rw::registerMatFXPlugin();
	rw::registerUVAnimPlugin();
	rw::ps2::registerADCPlugin();
	return true;
}

bool
InitRW(void)
{
//	rw::platform = rw::PLATFORM_D3D8;
	if(!sk::InitRW())
		return false;

	Scene.world = rw::World::create();

	rw::Light *ambient = rw::Light::create(rw::Light::AMBIENT);
	ambient->setColor(0.2f, 0.2f, 0.2f);
	Scene.world->addLight(ambient);

	rw::V3d xaxis = { 1.0f, 0.0f, 0.0f };
	rw::Light *direct = rw::Light::create(rw::Light::DIRECTIONAL);
	direct->setColor(0.8f, 0.8f, 0.8f);
	direct->setFrame(rw::Frame::create());
	direct->getFrame()->rotate(&xaxis, 180.0f, rw::COMBINEREPLACE);
	Scene.world->addLight(direct);

	Scene.camera = sk::CameraCreate(sk::globals.width, sk::globals.height, 1);
	Scene.world->addCamera(Scene.camera);

	ImGui_ImplRW_Init();
	ImGui::StyleColorsClassic();

	return true;
}

void
Draw(float timeDelta)
{
	static bool show_demo_window = true;
	static bool show_another_window = false;
	static ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);

	rw::RGBA clearcol = rw::makeRGBA(clear_color.x*255, clear_color.y*255, clear_color.z*255, clear_color.w*255);
	Scene.camera->clear(&clearcol, rw::Camera::CLEARIMAGE|rw::Camera::CLEARZ);
	Scene.camera->beginUpdate();

	ImGui_ImplRW_NewFrame(timeDelta);

	// 1. Show a simple window.
	// Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets automatically appears in a window called "Debug".
	{
		static float f = 0.0f;
		ImGui::Text("Hello, world!");                           // Some text (you can use a format string too)
		ImGui::SliderFloat("float", &f, 0.0f, 1.0f);            // Edit 1 float as a slider from 0.0f to 1.0f
		ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats as a color
		if(ImGui::Button("Demo Window"))                       // Use buttons to toggle our bools. We could use Checkbox() as well.
			show_demo_window ^= 1;
		if(ImGui::Button("Another Window"))
			show_another_window ^= 1;
		ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
	}

        // 2. Show another simple window. In most cases you will use an explicit Begin/End pair to name the window.
	if(show_another_window){
		ImGui::Begin("Another Window", &show_another_window);
		ImGui::Text("Hello from another window!");
		ImGui::End();
	}

        // 3. Show the ImGui demo window. Most of the sample code is in ImGui::ShowDemoWindow().
	if(show_demo_window){
		ImGui::SetNextWindowPos(ImVec2(650, 20), ImGuiCond_FirstUseEver); // Normally user code doesn't need/want to call this because positions are saved in .ini file anyway. Here we just want to make the demo initial state a bit more friendly!
		ImGui::ShowDemoWindow(&show_demo_window);
	}

	ImGui::EndFrame();

	ImGui::Render();

	Scene.camera->endUpdate();
	Scene.camera->showRaster(0);

	ImGui_ImplRW_RenderDrawLists(ImGui::GetDrawData());
}

void
KeyUp(int key)
{
}

void
KeyDown(int key)
{
	switch(key){
	case sk::KEY_ESC:
		sk::globals.quit = 1;
		break;
	}
}

sk::EventStatus
AppEventHandler(sk::Event e, void *param)
{
	using namespace sk;
	Rect *r;

	ImGuiEventHandler(e, param);

	switch(e){
	case INITIALIZE:
		Init();
		return EVENTPROCESSED;
	case RWINITIALIZE:
		return ::InitRW() ? EVENTPROCESSED : EVENTERROR;
	case PLUGINATTACH:
		return attachPlugins() ? EVENTPROCESSED : EVENTERROR;
	case KEYDOWN:
		KeyDown(*(int*)param);
		return EVENTPROCESSED;
	case KEYUP:
		KeyUp(*(int*)param);
		return EVENTPROCESSED;
	case RESIZE:
		r = (Rect*)param;
		// TODO: register when we're minimized
		if(r->w == 0) r->w = 1;
		if(r->h == 0) r->h = 1;

		sk::globals.width = r->w;
		sk::globals.height = r->h;
		// TODO: set aspect ratio
		if(Scene.camera)
			sk::CameraSize(Scene.camera, r);
		break;
	case IDLE:
		Draw(*(float*)param);
		return EVENTPROCESSED;
	}
	return sk::EVENTNOTPROCESSED;
}
<commit_msg>examples: fix imguitest<commit_after>#include <rw.h>
#include <skeleton.h>
#include <assert.h>

rw::V3d zero = { 0.0f, 0.0f, 0.0f };
struct SceneGlobals {
	rw::World *world;
	rw::Camera *camera;
} Scene;
rw::EngineOpenParams engineOpenParams;

void
Init(void)
{
	sk::globals.windowtitle = "ImGui test";
	sk::globals.width = 1280;
	sk::globals.height = 800;
	sk::globals.quit = 0;
}

bool
attachPlugins(void)
{
	rw::ps2::registerPDSPlugin(40);
	rw::ps2::registerPluginPDSPipes();

	rw::registerMeshPlugin();
	rw::registerNativeDataPlugin();
	rw::registerAtomicRightsPlugin();
	rw::registerMaterialRightsPlugin();
	rw::xbox::registerVertexFormatPlugin();
	rw::registerSkinPlugin();
	rw::registerUserDataPlugin();
	rw::registerHAnimPlugin();
	rw::registerMatFXPlugin();
	rw::registerUVAnimPlugin();
	rw::ps2::registerADCPlugin();
	return true;
}

bool
InitRW(void)
{
//	rw::platform = rw::PLATFORM_D3D8;
	if(!sk::InitRW())
		return false;

	Scene.world = rw::World::create();

	rw::Light *ambient = rw::Light::create(rw::Light::AMBIENT);
	ambient->setColor(0.2f, 0.2f, 0.2f);
	Scene.world->addLight(ambient);

	rw::V3d xaxis = { 1.0f, 0.0f, 0.0f };
	rw::Light *direct = rw::Light::create(rw::Light::DIRECTIONAL);
	direct->setColor(0.8f, 0.8f, 0.8f);
	direct->setFrame(rw::Frame::create());
	direct->getFrame()->rotate(&xaxis, 180.0f, rw::COMBINEREPLACE);
	Scene.world->addLight(direct);

	Scene.camera = sk::CameraCreate(sk::globals.width, sk::globals.height, 1);
	Scene.world->addCamera(Scene.camera);

	ImGui_ImplRW_Init();
	ImGui::StyleColorsClassic();

	return true;
}

void
Draw(float timeDelta)
{
	static bool show_demo_window = true;
	static bool show_another_window = false;
	static ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);

	rw::RGBA clearcol = rw::makeRGBA(clear_color.x*255, clear_color.y*255, clear_color.z*255, clear_color.w*255);
	Scene.camera->clear(&clearcol, rw::Camera::CLEARIMAGE|rw::Camera::CLEARZ);
	Scene.camera->beginUpdate();

	ImGui_ImplRW_NewFrame(timeDelta);

	// 1. Show a simple window.
	// Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets automatically appears in a window called "Debug".
	{
		static float f = 0.0f;
		ImGui::Text("Hello, world!");                           // Some text (you can use a format string too)
		ImGui::SliderFloat("float", &f, 0.0f, 1.0f);            // Edit 1 float as a slider from 0.0f to 1.0f
		ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats as a color
		if(ImGui::Button("Demo Window"))                       // Use buttons to toggle our bools. We could use Checkbox() as well.
			show_demo_window ^= 1;
		if(ImGui::Button("Another Window"))
			show_another_window ^= 1;
		ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
	}

        // 2. Show another simple window. In most cases you will use an explicit Begin/End pair to name the window.
	if(show_another_window){
		ImGui::Begin("Another Window", &show_another_window);
		ImGui::Text("Hello from another window!");
		ImGui::End();
	}

        // 3. Show the ImGui demo window. Most of the sample code is in ImGui::ShowDemoWindow().
	if(show_demo_window){
		ImGui::SetNextWindowPos(ImVec2(650, 20), ImGuiCond_FirstUseEver); // Normally user code doesn't need/want to call this because positions are saved in .ini file anyway. Here we just want to make the demo initial state a bit more friendly!
		ImGui::ShowDemoWindow(&show_demo_window);
	}

	ImGui::EndFrame();
	ImGui::Render();

	ImGui_ImplRW_RenderDrawLists(ImGui::GetDrawData());

	Scene.camera->endUpdate();
	Scene.camera->showRaster(0);
}

void
KeyUp(int key)
{
}

void
KeyDown(int key)
{
	switch(key){
	case sk::KEY_ESC:
		sk::globals.quit = 1;
		break;
	}
}

sk::EventStatus
AppEventHandler(sk::Event e, void *param)
{
	using namespace sk;
	Rect *r;

	ImGuiEventHandler(e, param);

	switch(e){
	case INITIALIZE:
		Init();
		return EVENTPROCESSED;
	case RWINITIALIZE:
		return ::InitRW() ? EVENTPROCESSED : EVENTERROR;
	case PLUGINATTACH:
		return attachPlugins() ? EVENTPROCESSED : EVENTERROR;
	case KEYDOWN:
		KeyDown(*(int*)param);
		return EVENTPROCESSED;
	case KEYUP:
		KeyUp(*(int*)param);
		return EVENTPROCESSED;
	case RESIZE:
		r = (Rect*)param;
		// TODO: register when we're minimized
		if(r->w == 0) r->w = 1;
		if(r->h == 0) r->h = 1;

		sk::globals.width = r->w;
		sk::globals.height = r->h;
		// TODO: set aspect ratio
		if(Scene.camera)
			sk::CameraSize(Scene.camera, r);
		break;
	case IDLE:
		Draw(*(float*)param);
		return EVENTPROCESSED;
	}
	return sk::EVENTNOTPROCESSED;
}
<|endoftext|>