<commit_before>/*==============================================================================

  Program: 3D Slicer

  Portions (c) Copyright Brigham and Women's Hospital (BWH) All Rights Reserved.

  See COPYRIGHT.txt
  or http://www.slicer.org/copyright/copyright.txt for details.

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

==============================================================================*/

// Qt includes
#include <QDebug>
#include <QtPlugin>

// Slicer includes
#include <qSlicerCoreApplication.h>
#include <qSlicerModuleManager.h>
#include <qSlicerCoreIOManager.h>
#include <qSlicerNodeWriter.h>

// ParticlesDisplay Logic includes
#include <vtkSlicerCLIModuleLogic.h>
#include <vtkSlicerParticlesDisplayLogic.h>
#include <vtkSlicerVolumesLogic.h>

// ParticlesDisplay includes
#include "qSlicerParticlesDisplayModule.h"
#include "qSlicerParticlesDisplayModuleWidget.h"
#include "qSlicerParticlesReader.h"

#include <vtkMRMLThreeDViewDisplayableManagerFactory.h>
//-----------------------------------------------------------------------------
Q_EXPORT_PLUGIN2(qSlicerParticlesDisplayModule, qSlicerParticlesDisplayModule);

//-----------------------------------------------------------------------------
/// \ingroup Slicer_QtModules_ExtensionTemplate
class qSlicerParticlesDisplayModulePrivate
{
public:
  qSlicerParticlesDisplayModulePrivate();
};

//-----------------------------------------------------------------------------
// qSlicerParticlesDisplayModulePrivate methods

//-----------------------------------------------------------------------------
qSlicerParticlesDisplayModulePrivate
::qSlicerParticlesDisplayModulePrivate()
{
}

//-----------------------------------------------------------------------------
// qSlicerParticlesDisplayModule methods

//-----------------------------------------------------------------------------
qSlicerParticlesDisplayModule
::qSlicerParticlesDisplayModule(QObject* _parent)
  : Superclass(_parent)
  , d_ptr(new qSlicerParticlesDisplayModulePrivate)
{
}

//-----------------------------------------------------------------------------
qSlicerParticlesDisplayModule::~qSlicerParticlesDisplayModule()
{
}

//-----------------------------------------------------------------------------
QString qSlicerParticlesDisplayModule::helpText()const
{
  return "This is a loadable module to display selected region and type";
}

//-----------------------------------------------------------------------------
QString qSlicerParticlesDisplayModule::acknowledgementText()const
{
  return "This module was developed by Pietro Nardelli";
}

//-----------------------------------------------------------------------------
QStringList qSlicerParticlesDisplayModule::contributors()const
{
  QStringList moduleContributors;
  moduleContributors << QString("Pietro Nardelli (UCC)");
  return moduleContributors;
}

//-----------------------------------------------------------------------------
QIcon qSlicerParticlesDisplayModule::icon()const
{
  return QIcon(":/Icons/ParticlesDisplay.png");
}

//-----------------------------------------------------------------------------
QStringList qSlicerParticlesDisplayModule::categories() const
{
  return QStringList() << "Converters";
}

//-----------------------------------------------------------------------------
QStringList qSlicerParticlesDisplayModule::dependencies() const
{
  return QStringList() << "RegionType";
}

//-----------------------------------------------------------------------------
void qSlicerParticlesDisplayModule::setup()
{
  this->Superclass::setup();

  vtkMRMLThreeDViewDisplayableManagerFactory::GetInstance()->
    RegisterDisplayableManager("vtkMRMLTractographyDisplayDisplayableManager");

  vtkSlicerParticlesDisplayLogic* particlesDisplayLogic =
    vtkSlicerParticlesDisplayLogic::SafeDownCast(this->logic());

  qSlicerCoreIOManager* coreIOManager =
    qSlicerCoreApplication::application()->coreIOManager();
  coreIOManager->registerIO(
    new qSlicerParticlesReader(particlesDisplayLogic, this));
  coreIOManager->registerIO(new qSlicerNodeWriter(
    "Particles", QString("ParticlesFile"),
    QStringList() << "vtkMRMLParticlesNode", true, this));
}

//-----------------------------------------------------------------------------
qSlicerAbstractModuleRepresentation * qSlicerParticlesDisplayModule
::createWidgetRepresentation()
{
  return new qSlicerParticlesDisplayModuleWidget;
}

//-----------------------------------------------------------------------------
vtkMRMLAbstractLogic* qSlicerParticlesDisplayModule::createLogic()
{
  return vtkSlicerParticlesDisplayLogic::New();
}
<commit_msg>BUG: Re-register TractographyDisplay DM only once. Fixes #6<commit_after>/*==============================================================================

  Program: 3D Slicer

  Portions (c) Copyright Brigham and Women's Hospital (BWH) All Rights Reserved.

  See COPYRIGHT.txt
  or http://www.slicer.org/copyright/copyright.txt for details.

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

==============================================================================*/

// Qt includes
#include <QDebug>
#include <QtPlugin>

// Slicer includes
#include <qSlicerCoreApplication.h>
#include <qSlicerModuleManager.h>
#include <qSlicerCoreIOManager.h>
#include <qSlicerNodeWriter.h>

// ParticlesDisplay Logic includes
#include <vtkSlicerCLIModuleLogic.h>
#include <vtkSlicerParticlesDisplayLogic.h>
#include <vtkSlicerVolumesLogic.h>

// ParticlesDisplay includes
#include "qSlicerParticlesDisplayModule.h"
#include "qSlicerParticlesDisplayModuleWidget.h"
#include "qSlicerParticlesReader.h"

//-----------------------------------------------------------------------------
Q_EXPORT_PLUGIN2(qSlicerParticlesDisplayModule, qSlicerParticlesDisplayModule);

//-----------------------------------------------------------------------------
/// \ingroup Slicer_QtModules_ExtensionTemplate
class qSlicerParticlesDisplayModulePrivate
{
public:
  qSlicerParticlesDisplayModulePrivate();
};

//-----------------------------------------------------------------------------
// qSlicerParticlesDisplayModulePrivate methods

//-----------------------------------------------------------------------------
qSlicerParticlesDisplayModulePrivate
::qSlicerParticlesDisplayModulePrivate()
{
}

//-----------------------------------------------------------------------------
// qSlicerParticlesDisplayModule methods

//-----------------------------------------------------------------------------
qSlicerParticlesDisplayModule
::qSlicerParticlesDisplayModule(QObject* _parent)
  : Superclass(_parent)
  , d_ptr(new qSlicerParticlesDisplayModulePrivate)
{
}

//-----------------------------------------------------------------------------
qSlicerParticlesDisplayModule::~qSlicerParticlesDisplayModule()
{
}

//-----------------------------------------------------------------------------
QString qSlicerParticlesDisplayModule::helpText()const
{
  return "This is a loadable module to display selected region and type";
}

//-----------------------------------------------------------------------------
QString qSlicerParticlesDisplayModule::acknowledgementText()const
{
  return "This module was developed by Pietro Nardelli";
}

//-----------------------------------------------------------------------------
QStringList qSlicerParticlesDisplayModule::contributors()const
{
  QStringList moduleContributors;
  moduleContributors << QString("Pietro Nardelli (UCC)");
  return moduleContributors;
}

//-----------------------------------------------------------------------------
QIcon qSlicerParticlesDisplayModule::icon()const
{
  return QIcon(":/Icons/ParticlesDisplay.png");
}

//-----------------------------------------------------------------------------
QStringList qSlicerParticlesDisplayModule::categories() const
{
  return QStringList() << "Converters";
}

//-----------------------------------------------------------------------------
QStringList qSlicerParticlesDisplayModule::dependencies() const
{
  return QStringList() << "RegionType" << "TractographyDisplay";
}

//-----------------------------------------------------------------------------
void qSlicerParticlesDisplayModule::setup()
{
  this->Superclass::setup();

  vtkSlicerParticlesDisplayLogic* particlesDisplayLogic =
    vtkSlicerParticlesDisplayLogic::SafeDownCast(this->logic());

  qSlicerCoreIOManager* coreIOManager =
    qSlicerCoreApplication::application()->coreIOManager();
  coreIOManager->registerIO(
    new qSlicerParticlesReader(particlesDisplayLogic, this));
  coreIOManager->registerIO(new qSlicerNodeWriter(
    "Particles", QString("ParticlesFile"),
    QStringList() << "vtkMRMLParticlesNode", true, this));
}

//-----------------------------------------------------------------------------
qSlicerAbstractModuleRepresentation * qSlicerParticlesDisplayModule
::createWidgetRepresentation()
{
  return new qSlicerParticlesDisplayModuleWidget;
}

//-----------------------------------------------------------------------------
vtkMRMLAbstractLogic* qSlicerParticlesDisplayModule::createLogic()
{
  return vtkSlicerParticlesDisplayLogic::New();
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2011 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$
** 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.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** 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.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <qtest.h>
#include <QtTest/QtTest>
#include <private/qdeclarativepixmapcache_p.h>
#include <QtDeclarative/qdeclarativeengine.h>
#include <QtDeclarative/qdeclarativeimageprovider.h>
#include <QNetworkReply>
#include "testhttpserver.h"

#ifndef QT_NO_CONCURRENT
#include <qtconcurrentrun.h>
#include <qfuture.h>
#endif

// These don't let normal people run tests!
//#include "../network-settings.h"

class tst_qdeclarativepixmapcache : public QObject
{
    Q_OBJECT
public:
    tst_qdeclarativepixmapcache() :
        thisfile(QUrl::fromLocalFile(QCoreApplication::applicationFilePath())),
        server(14452)
    {
        server.serveDirectory(QCoreApplication::applicationDirPath() + "/data/http");
    }

private slots:
    void single();
    void single_data();
    void parallel();
    void parallel_data();
    void massive();
    void cancelcrash();
    void shrinkcache();
#ifndef QT_NO_CONCURRENT
    void networkCrash();
#endif
private:
    QDeclarativeEngine engine;
    QUrl thisfile;
    TestHTTPServer server;
};

static int slotters=0;

class Slotter : public QObject
{
    Q_OBJECT
public:
    Slotter()
    {
        gotslot = false;
        slotters++;
    }
    bool gotslot;

public slots:
    void got()
    {
        gotslot = true;
        --slotters;
        if (slotters==0)
            QTestEventLoop::instance().exitLoop();
    }
};

#ifndef QT_NO_LOCALFILE_OPTIMIZED_QML
static const bool localfile_optimized = true;
#else
static const bool localfile_optimized = false;
#endif

void tst_qdeclarativepixmapcache::single_data()
{
    // Note, since QDeclarativePixmapCache is shared, tests affect each other!
    // so use different files fore all test functions.

    QTest::addColumn<QUrl>("target");
    QTest::addColumn<bool>("incache");
    QTest::addColumn<bool>("exists");
    QTest::addColumn<bool>("neterror");

    // File URLs are optimized
    QTest::newRow("local") << thisfile.resolved(QUrl("data/exists.png")) << localfile_optimized << true << false;
    QTest::newRow("local") << thisfile.resolved(QUrl("data/notexists.png")) << localfile_optimized << false << false;
    QTest::newRow("remote") << QUrl("http://127.0.0.1:14452/exists.png") << false << true << false;
    QTest::newRow("remote") << QUrl("http://127.0.0.1:14452/notexists.png") << false << false << true;
}

void tst_qdeclarativepixmapcache::single()
{
    QFETCH(QUrl, target);
    QFETCH(bool, incache);
    QFETCH(bool, exists);
    QFETCH(bool, neterror);

    QString expectedError;
    if (neterror) {
        expectedError = "Error downloading " + target.toString() + " - server replied: Not found";
    } else if (!exists) {
        expectedError = "Cannot open: " + target.toString();
    }

    QDeclarativePixmap pixmap;
    QVERIFY(pixmap.width() <= 0); // Check Qt assumption

    pixmap.load(&engine, target);

    if (incache) {
        QCOMPARE(pixmap.error(), expectedError);
        if (exists) {
            QVERIFY(pixmap.status() == QDeclarativePixmap::Ready);
            QVERIFY(pixmap.width() > 0);
        } else {
            QVERIFY(pixmap.status() == QDeclarativePixmap::Error);
            QVERIFY(pixmap.width() <= 0);
        }
    } else {
        QVERIFY(pixmap.width() <= 0);

        Slotter getter;
        pixmap.connectFinished(&getter, SLOT(got()));
        QTestEventLoop::instance().enterLoop(10);
        QVERIFY(!QTestEventLoop::instance().timeout());
        QVERIFY(getter.gotslot);
        if (exists) {
            QVERIFY(pixmap.status() == QDeclarativePixmap::Ready);
            QVERIFY(pixmap.width() > 0);
        } else {
            QVERIFY(pixmap.status() == QDeclarativePixmap::Error);
            QVERIFY(pixmap.width() <= 0);
        }
        QCOMPARE(pixmap.error(), expectedError);
    }
}

void tst_qdeclarativepixmapcache::parallel_data()
{
    // Note, since QDeclarativePixmapCache is shared, tests affect each other!
    // so use different files fore all test functions.

    QTest::addColumn<QUrl>("target1");
    QTest::addColumn<QUrl>("target2");
    QTest::addColumn<int>("incache");
    QTest::addColumn<int>("cancel"); // which one to cancel

    QTest::newRow("local")
            << thisfile.resolved(QUrl("data/exists1.png"))
            << thisfile.resolved(QUrl("data/exists2.png"))
            << (localfile_optimized ? 2 : 0)
            << -1;

    QTest::newRow("remote")
            << QUrl("http://127.0.0.1:14452/exists2.png")
            << QUrl("http://127.0.0.1:14452/exists3.png")
            << 0
            << -1;

    QTest::newRow("remoteagain")
            << QUrl("http://127.0.0.1:14452/exists2.png")
            << QUrl("http://127.0.0.1:14452/exists3.png")
            << 2
            << -1;

    QTest::newRow("remotecopy")
            << QUrl("http://127.0.0.1:14452/exists4.png")
            << QUrl("http://127.0.0.1:14452/exists4.png")
            << 0
            << -1;

    QTest::newRow("remotecopycancel")
            << QUrl("http://127.0.0.1:14452/exists5.png")
            << QUrl("http://127.0.0.1:14452/exists5.png")
            << 0
            << 0;
}

void tst_qdeclarativepixmapcache::parallel()
{
    QFETCH(QUrl, target1);
    QFETCH(QUrl, target2);
    QFETCH(int, incache);
    QFETCH(int, cancel);

    QList<QUrl> targets;
    targets << target1 << target2;

    QList<QDeclarativePixmap *> pixmaps;
    QList<bool> pending;
    QList<Slotter*> getters;

    for (int i=0; i<targets.count(); ++i) {
        QUrl target = targets.at(i);
        QDeclarativePixmap *pixmap = new QDeclarativePixmap;

        pixmap->load(&engine, target);

        QVERIFY(pixmap->status() != QDeclarativePixmap::Error);
        pixmaps.append(pixmap);
        if (pixmap->isReady()) {
            QVERIFY(pixmap->width() >  0);
            getters.append(0);
            pending.append(false);
        } else {
            QVERIFY(pixmap->width() <= 0);
            getters.append(new Slotter);
            pixmap->connectFinished(getters[i], SLOT(got()));
            pending.append(true);
        }
    }

    QCOMPARE(incache+slotters, targets.count());

    if (cancel >= 0) {
        pixmaps.at(cancel)->clear(getters[cancel]);
        slotters--;
    }

    if (slotters) {
        QTestEventLoop::instance().enterLoop(10);
        QVERIFY(!QTestEventLoop::instance().timeout());
    }

    for (int i=0; i<targets.count(); ++i) {
        QDeclarativePixmap *pixmap = pixmaps[i];

        if (i == cancel) {
            QVERIFY(!getters[i]->gotslot);
        } else {
            if (pending[i])
                QVERIFY(getters[i]->gotslot);

            QVERIFY(pixmap->isReady());
            QVERIFY(pixmap->width() > 0);
            delete getters[i];
        }
    }

    qDeleteAll(pixmaps);
}

void tst_qdeclarativepixmapcache::massive()
{
    QDeclarativeEngine engine;
    QUrl url = thisfile.resolved(QUrl("data/massive.png"));

    // Confirm that massive images remain in the cache while they are
    // in use by the application.
    {
    qint64 cachekey = 0;
    QDeclarativePixmap p(&engine, url);
    QVERIFY(p.isReady());
    QVERIFY(p.pixmap().size() == QSize(10000, 1000));
    cachekey = p.pixmap().cacheKey();

    QDeclarativePixmap p2(&engine, url);
    QVERIFY(p2.isReady());
    QVERIFY(p2.pixmap().size() == QSize(10000, 1000));

    QVERIFY(p2.pixmap().cacheKey() == cachekey);
    }

    // Confirm that massive images are removed from the cache when
    // they become unused
    {
    qint64 cachekey = 0;
    {
        QDeclarativePixmap p(&engine, url);
        QVERIFY(p.isReady());
        QVERIFY(p.pixmap().size() == QSize(10000, 1000));
        cachekey = p.pixmap().cacheKey();
    }

    QDeclarativePixmap p2(&engine, url);
    QVERIFY(p2.isReady());
    QVERIFY(p2.pixmap().size() == QSize(10000, 1000));

    QVERIFY(p2.pixmap().cacheKey() != cachekey);
    }
}

// QTBUG-12729
void tst_qdeclarativepixmapcache::cancelcrash()
{
    QUrl url("http://127.0.0.1:14452/cancelcrash_notexist.png");
    for (int ii = 0; ii < 1000; ++ii) {
        QDeclarativePixmap pix(&engine, url);
    }
}

class MyPixmapProvider : public QDeclarativeImageProvider
{
public:
    MyPixmapProvider()
    : QDeclarativeImageProvider(Pixmap) {}

    virtual QPixmap requestPixmap(const QString &d, QSize *, const QSize &) {
        Q_UNUSED(d)
        QPixmap pix(800, 600);
        pix.fill(Qt::red);
        return pix;
    }
};

// QTBUG-13345
void tst_qdeclarativepixmapcache::shrinkcache()
{
    QDeclarativeEngine engine;
    engine.addImageProvider(QLatin1String("mypixmaps"), new MyPixmapProvider);

    for (int ii = 0; ii < 4000; ++ii) {
        QUrl url("image://mypixmaps/" + QString::number(ii));
        QDeclarativePixmap p(&engine, url);
    }
}

#ifndef QT_NO_CONCURRENT

void createNetworkServer()
{
   QEventLoop eventLoop;
   TestHTTPServer server(14453);
   server.serveDirectory(QCoreApplication::applicationDirPath() + "/data/http");
   QTimer::singleShot(100, &eventLoop, SLOT(quit()));
   eventLoop.exec();
}

#ifndef QT_NO_CONCURRENT
// QT-3957
void tst_qdeclarativepixmapcache::networkCrash()
{
    QFuture<void> future = QtConcurrent::run(createNetworkServer);
    QDeclarativeEngine engine;
    for (int ii = 0; ii < 100 ; ++ii) {
        QDeclarativePixmap* pixmap = new QDeclarativePixmap;
        pixmap->load(&engine,  QUrl(QString("http://127.0.0.1:14453/exists.png")));
        QTest::qSleep(1);
        pixmap->clear();
        delete pixmap;
    }
    future.cancel();
}
#endif

#endif

QTEST_MAIN(tst_qdeclarativepixmapcache)

#include "tst_qdeclarativepixmapcache.moc"
<commit_msg>Remove obsolete include from QDeclarativePixmapCache test<commit_after>/****************************************************************************
**
** Copyright (C) 2011 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$
** 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.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** 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.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <qtest.h>
#include <QtTest/QtTest>
#include <private/qdeclarativepixmapcache_p.h>
#include <QtDeclarative/qdeclarativeengine.h>
#include <QtDeclarative/qdeclarativeimageprovider.h>
#include <QNetworkReply>
#include "testhttpserver.h"

#ifndef QT_NO_CONCURRENT
#include <qtconcurrentrun.h>
#include <qfuture.h>
#endif

class tst_qdeclarativepixmapcache : public QObject
{
    Q_OBJECT
public:
    tst_qdeclarativepixmapcache() :
        thisfile(QUrl::fromLocalFile(QCoreApplication::applicationFilePath())),
        server(14452)
    {
        server.serveDirectory(QCoreApplication::applicationDirPath() + "/data/http");
    }

private slots:
    void single();
    void single_data();
    void parallel();
    void parallel_data();
    void massive();
    void cancelcrash();
    void shrinkcache();
#ifndef QT_NO_CONCURRENT
    void networkCrash();
#endif
private:
    QDeclarativeEngine engine;
    QUrl thisfile;
    TestHTTPServer server;
};

static int slotters=0;

class Slotter : public QObject
{
    Q_OBJECT
public:
    Slotter()
    {
        gotslot = false;
        slotters++;
    }
    bool gotslot;

public slots:
    void got()
    {
        gotslot = true;
        --slotters;
        if (slotters==0)
            QTestEventLoop::instance().exitLoop();
    }
};

#ifndef QT_NO_LOCALFILE_OPTIMIZED_QML
static const bool localfile_optimized = true;
#else
static const bool localfile_optimized = false;
#endif

void tst_qdeclarativepixmapcache::single_data()
{
    // Note, since QDeclarativePixmapCache is shared, tests affect each other!
    // so use different files fore all test functions.

    QTest::addColumn<QUrl>("target");
    QTest::addColumn<bool>("incache");
    QTest::addColumn<bool>("exists");
    QTest::addColumn<bool>("neterror");

    // File URLs are optimized
    QTest::newRow("local") << thisfile.resolved(QUrl("data/exists.png")) << localfile_optimized << true << false;
    QTest::newRow("local") << thisfile.resolved(QUrl("data/notexists.png")) << localfile_optimized << false << false;
    QTest::newRow("remote") << QUrl("http://127.0.0.1:14452/exists.png") << false << true << false;
    QTest::newRow("remote") << QUrl("http://127.0.0.1:14452/notexists.png") << false << false << true;
}

void tst_qdeclarativepixmapcache::single()
{
    QFETCH(QUrl, target);
    QFETCH(bool, incache);
    QFETCH(bool, exists);
    QFETCH(bool, neterror);

    QString expectedError;
    if (neterror) {
        expectedError = "Error downloading " + target.toString() + " - server replied: Not found";
    } else if (!exists) {
        expectedError = "Cannot open: " + target.toString();
    }

    QDeclarativePixmap pixmap;
    QVERIFY(pixmap.width() <= 0); // Check Qt assumption

    pixmap.load(&engine, target);

    if (incache) {
        QCOMPARE(pixmap.error(), expectedError);
        if (exists) {
            QVERIFY(pixmap.status() == QDeclarativePixmap::Ready);
            QVERIFY(pixmap.width() > 0);
        } else {
            QVERIFY(pixmap.status() == QDeclarativePixmap::Error);
            QVERIFY(pixmap.width() <= 0);
        }
    } else {
        QVERIFY(pixmap.width() <= 0);

        Slotter getter;
        pixmap.connectFinished(&getter, SLOT(got()));
        QTestEventLoop::instance().enterLoop(10);
        QVERIFY(!QTestEventLoop::instance().timeout());
        QVERIFY(getter.gotslot);
        if (exists) {
            QVERIFY(pixmap.status() == QDeclarativePixmap::Ready);
            QVERIFY(pixmap.width() > 0);
        } else {
            QVERIFY(pixmap.status() == QDeclarativePixmap::Error);
            QVERIFY(pixmap.width() <= 0);
        }
        QCOMPARE(pixmap.error(), expectedError);
    }
}

void tst_qdeclarativepixmapcache::parallel_data()
{
    // Note, since QDeclarativePixmapCache is shared, tests affect each other!
    // so use different files fore all test functions.

    QTest::addColumn<QUrl>("target1");
    QTest::addColumn<QUrl>("target2");
    QTest::addColumn<int>("incache");
    QTest::addColumn<int>("cancel"); // which one to cancel

    QTest::newRow("local")
            << thisfile.resolved(QUrl("data/exists1.png"))
            << thisfile.resolved(QUrl("data/exists2.png"))
            << (localfile_optimized ? 2 : 0)
            << -1;

    QTest::newRow("remote")
            << QUrl("http://127.0.0.1:14452/exists2.png")
            << QUrl("http://127.0.0.1:14452/exists3.png")
            << 0
            << -1;

    QTest::newRow("remoteagain")
            << QUrl("http://127.0.0.1:14452/exists2.png")
            << QUrl("http://127.0.0.1:14452/exists3.png")
            << 2
            << -1;

    QTest::newRow("remotecopy")
            << QUrl("http://127.0.0.1:14452/exists4.png")
            << QUrl("http://127.0.0.1:14452/exists4.png")
            << 0
            << -1;

    QTest::newRow("remotecopycancel")
            << QUrl("http://127.0.0.1:14452/exists5.png")
            << QUrl("http://127.0.0.1:14452/exists5.png")
            << 0
            << 0;
}

void tst_qdeclarativepixmapcache::parallel()
{
    QFETCH(QUrl, target1);
    QFETCH(QUrl, target2);
    QFETCH(int, incache);
    QFETCH(int, cancel);

    QList<QUrl> targets;
    targets << target1 << target2;

    QList<QDeclarativePixmap *> pixmaps;
    QList<bool> pending;
    QList<Slotter*> getters;

    for (int i=0; i<targets.count(); ++i) {
        QUrl target = targets.at(i);
        QDeclarativePixmap *pixmap = new QDeclarativePixmap;

        pixmap->load(&engine, target);

        QVERIFY(pixmap->status() != QDeclarativePixmap::Error);
        pixmaps.append(pixmap);
        if (pixmap->isReady()) {
            QVERIFY(pixmap->width() >  0);
            getters.append(0);
            pending.append(false);
        } else {
            QVERIFY(pixmap->width() <= 0);
            getters.append(new Slotter);
            pixmap->connectFinished(getters[i], SLOT(got()));
            pending.append(true);
        }
    }

    QCOMPARE(incache+slotters, targets.count());

    if (cancel >= 0) {
        pixmaps.at(cancel)->clear(getters[cancel]);
        slotters--;
    }

    if (slotters) {
        QTestEventLoop::instance().enterLoop(10);
        QVERIFY(!QTestEventLoop::instance().timeout());
    }

    for (int i=0; i<targets.count(); ++i) {
        QDeclarativePixmap *pixmap = pixmaps[i];

        if (i == cancel) {
            QVERIFY(!getters[i]->gotslot);
        } else {
            if (pending[i])
                QVERIFY(getters[i]->gotslot);

            QVERIFY(pixmap->isReady());
            QVERIFY(pixmap->width() > 0);
            delete getters[i];
        }
    }

    qDeleteAll(pixmaps);
}

void tst_qdeclarativepixmapcache::massive()
{
    QDeclarativeEngine engine;
    QUrl url = thisfile.resolved(QUrl("data/massive.png"));

    // Confirm that massive images remain in the cache while they are
    // in use by the application.
    {
    qint64 cachekey = 0;
    QDeclarativePixmap p(&engine, url);
    QVERIFY(p.isReady());
    QVERIFY(p.pixmap().size() == QSize(10000, 1000));
    cachekey = p.pixmap().cacheKey();

    QDeclarativePixmap p2(&engine, url);
    QVERIFY(p2.isReady());
    QVERIFY(p2.pixmap().size() == QSize(10000, 1000));

    QVERIFY(p2.pixmap().cacheKey() == cachekey);
    }

    // Confirm that massive images are removed from the cache when
    // they become unused
    {
    qint64 cachekey = 0;
    {
        QDeclarativePixmap p(&engine, url);
        QVERIFY(p.isReady());
        QVERIFY(p.pixmap().size() == QSize(10000, 1000));
        cachekey = p.pixmap().cacheKey();
    }

    QDeclarativePixmap p2(&engine, url);
    QVERIFY(p2.isReady());
    QVERIFY(p2.pixmap().size() == QSize(10000, 1000));

    QVERIFY(p2.pixmap().cacheKey() != cachekey);
    }
}

// QTBUG-12729
void tst_qdeclarativepixmapcache::cancelcrash()
{
    QUrl url("http://127.0.0.1:14452/cancelcrash_notexist.png");
    for (int ii = 0; ii < 1000; ++ii) {
        QDeclarativePixmap pix(&engine, url);
    }
}

class MyPixmapProvider : public QDeclarativeImageProvider
{
public:
    MyPixmapProvider()
    : QDeclarativeImageProvider(Pixmap) {}

    virtual QPixmap requestPixmap(const QString &d, QSize *, const QSize &) {
        Q_UNUSED(d)
        QPixmap pix(800, 600);
        pix.fill(Qt::red);
        return pix;
    }
};

// QTBUG-13345
void tst_qdeclarativepixmapcache::shrinkcache()
{
    QDeclarativeEngine engine;
    engine.addImageProvider(QLatin1String("mypixmaps"), new MyPixmapProvider);

    for (int ii = 0; ii < 4000; ++ii) {
        QUrl url("image://mypixmaps/" + QString::number(ii));
        QDeclarativePixmap p(&engine, url);
    }
}

#ifndef QT_NO_CONCURRENT

void createNetworkServer()
{
   QEventLoop eventLoop;
   TestHTTPServer server(14453);
   server.serveDirectory(QCoreApplication::applicationDirPath() + "/data/http");
   QTimer::singleShot(100, &eventLoop, SLOT(quit()));
   eventLoop.exec();
}

#ifndef QT_NO_CONCURRENT
// QT-3957
void tst_qdeclarativepixmapcache::networkCrash()
{
    QFuture<void> future = QtConcurrent::run(createNetworkServer);
    QDeclarativeEngine engine;
    for (int ii = 0; ii < 100 ; ++ii) {
        QDeclarativePixmap* pixmap = new QDeclarativePixmap;
        pixmap->load(&engine,  QUrl(QString("http://127.0.0.1:14453/exists.png")));
        QTest::qSleep(1);
        pixmap->clear();
        delete pixmap;
    }
    future.cancel();
}
#endif

#endif

QTEST_MAIN(tst_qdeclarativepixmapcache)

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


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_xmloff.hxx"

#include "XMLIndexBibliographyConfigurationContext.hxx"
#include "XMLIndexBibliographyEntryContext.hxx"
#include <xmloff/xmlictxt.hxx>
#include <xmloff/xmlimp.hxx>
#include <xmloff/txtimp.hxx>
#include <xmloff/nmspmap.hxx>
#include "xmlnmspe.hxx"
#include <xmloff/xmltoken.hxx>
#include <xmloff/xmluconv.hxx>
#include <tools/debug.hxx>
#include <rtl/ustring.hxx>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>

using namespace ::com::sun::star::text;
using namespace ::com::sun::star::uno;
using namespace ::xmloff::token;

using ::rtl::OUString;
using ::com::sun::star::xml::sax::XAttributeList;
using ::com::sun::star::beans::PropertyValue;
using ::com::sun::star::beans::XPropertySet;
using ::com::sun::star::lang::XMultiServiceFactory;

const sal_Char sAPI_FieldMaster_Bibliography[] =
                                "com.sun.star.text.FieldMaster.Bibliography";

TYPEINIT1( XMLIndexBibliographyConfigurationContext, SvXMLStyleContext );

XMLIndexBibliographyConfigurationContext::XMLIndexBibliographyConfigurationContext(
    SvXMLImport& rImport,
    sal_uInt16 nPrfx,
    const OUString& rLocalName,
    const Reference<XAttributeList> & xAttrList) :
        SvXMLStyleContext(rImport, nPrfx, rLocalName, xAttrList, XML_STYLE_FAMILY_TEXT_BIBLIOGRAPHYCONFIG),
        sFieldMaster_Bibliography(
            RTL_CONSTASCII_USTRINGPARAM(sAPI_FieldMaster_Bibliography)),
        sBracketBefore(RTL_CONSTASCII_USTRINGPARAM("BracketBefore")),
        sBracketAfter(RTL_CONSTASCII_USTRINGPARAM("BracketAfter")),
        sIsNumberEntries(RTL_CONSTASCII_USTRINGPARAM("IsNumberEntries")),
        sIsSortByPosition(RTL_CONSTASCII_USTRINGPARAM("IsSortByPosition")),
        sSortKeys(RTL_CONSTASCII_USTRINGPARAM("SortKeys")),
        sSortKey(RTL_CONSTASCII_USTRINGPARAM("SortKey")),
        sIsSortAscending(RTL_CONSTASCII_USTRINGPARAM("IsSortAscending")),
        sSortAlgorithm(RTL_CONSTASCII_USTRINGPARAM("SortAlgorithm")),
        sLocale(RTL_CONSTASCII_USTRINGPARAM("Locale")),
        sSuffix(),
        sPrefix(),
        sAlgorithm(),
        aLocale(),
        bNumberedEntries(sal_False),
        bSortByPosition(sal_True)
{
}

XMLIndexBibliographyConfigurationContext::~XMLIndexBibliographyConfigurationContext()
{
}

void XMLIndexBibliographyConfigurationContext::StartElement(
    const Reference<XAttributeList> & xAttrList)
{
    sal_Int16 nLength = xAttrList->getLength();
    for(sal_Int16 nAttr = 0; nAttr < nLength; nAttr++)
    {
        OUString sLocalName;
        sal_uInt16 nPrefix = GetImport().GetNamespaceMap().
            GetKeyByAttrName( xAttrList->getNameByIndex(nAttr),
                              &sLocalName );

        ProcessAttribute(nPrefix, sLocalName,
                         xAttrList->getValueByIndex(nAttr));
        // else: ignore
    }
}

void XMLIndexBibliographyConfigurationContext::ProcessAttribute(
    sal_uInt16 nPrefix,
    OUString sLocalName,
    OUString sValue)
{
    if( XML_NAMESPACE_TEXT == nPrefix )
    {
        if( IsXMLToken(sLocalName, XML_PREFIX) )
        {
            sPrefix = sValue;
        }
        else if( IsXMLToken(sLocalName, XML_SUFFIX) )
        {
            sSuffix = sValue;
        }
        else if( IsXMLToken(sLocalName, XML_NUMBERED_ENTRIES) )
        {
            sal_Bool bTmp;
            if( SvXMLUnitConverter::convertBool(bTmp, sValue) )
            {
                bNumberedEntries = bTmp;
            }
        }
        else if( IsXMLToken(sLocalName, XML_SORT_BY_POSITION) )
        {
            bool bTmp;
            if (SvXMLUnitConverter::convertBool(bTmp, sValue))
            {
                bSortByPosition = bTmp;
            }
        }
        else if( IsXMLToken(sLocalName, XML_SORT_ALGORITHM) )
        {
            sAlgorithm = sValue;
        }
    }
    else if( XML_NAMESPACE_FO == nPrefix )
    {
        if( IsXMLToken(sLocalName, XML_LANGUAGE) )
        {
            aLocale.Language = sValue;
        }
        else if( IsXMLToken(sLocalName, XML_COUNTRY) )
        {
            aLocale.Country = sValue;
        }
    }
}

SvXMLImportContext *XMLIndexBibliographyConfigurationContext::CreateChildContext(
    sal_uInt16 nPrefix,
    const OUString& rLocalName,
    const Reference<XAttributeList> & xAttrList )
{
    OUString sKey;
    sal_Bool bSort(sal_True);

    // process children here and use default context!
    if ( ( nPrefix == XML_NAMESPACE_TEXT ) &&
         IsXMLToken( rLocalName, XML_SORT_KEY ) )
    {
        sal_Int16 nLength = xAttrList->getLength();
        for(sal_Int16 nAttr = 0; nAttr < nLength; nAttr++)
        {
            OUString sLocalName;
            sal_uInt16 nPrfx = GetImport().GetNamespaceMap().
                GetKeyByAttrName( xAttrList->getNameByIndex(nAttr),
                                  &sLocalName );

            if (nPrfx == XML_NAMESPACE_TEXT)
            {
                if ( IsXMLToken( sLocalName, XML_KEY ) )
                {
                    sKey = xAttrList->getValueByIndex(nAttr);
                }
                else if ( IsXMLToken( sLocalName, XML_SORT_ASCENDING ) )
                {
                    bool bTmp;
                    if (SvXMLUnitConverter::convertBool(
                        bTmp, xAttrList->getValueByIndex(nAttr)))
                    {
                        bSort = bTmp;
                    }
                }
            }
        }

        // valid data?
        sal_uInt16 nKey;
        if (SvXMLUnitConverter::convertEnum(nKey, sKey,
                                            aBibliographyDataFieldMap))
        {

            Any aAny;
            Sequence<PropertyValue> aKey(2);

            PropertyValue aNameValue;
            aNameValue.Name = sSortKey;
            aAny <<= (sal_Int16)nKey;
            aNameValue.Value = aAny;
            aKey[0] = aNameValue;

            PropertyValue aSortValue;
            aSortValue.Name = sIsSortAscending;
            aAny.setValue(&bSort, ::getBooleanCppuType());
            aSortValue.Value = aAny;
            aKey[1] = aSortValue;

            aSortKeys.push_back(aKey);
        }
    }

    return SvXMLImportContext::CreateChildContext(nPrefix, rLocalName,
                                                  xAttrList);
}

void XMLIndexBibliographyConfigurationContext::CreateAndInsert(sal_Bool)
{
    // (code almost the same as export...)

    // insert and block mode is handled in insertStyleFamily

    // first: get field master
    // (we'll create one, and get the only master for this type)
    Reference<XMultiServiceFactory> xFactory(GetImport().GetModel(),UNO_QUERY);
    if( xFactory.is() )
    {
        Sequence<rtl::OUString> aServices = xFactory->getAvailableServiceNames();
        sal_Bool bFound(sal_False);
        sal_Int32 i(0);
        sal_Int32 nServiceCount(aServices.getLength());
        while (i < nServiceCount && !bFound)
        {
            if (aServices[i].equals(sFieldMaster_Bibliography))
            // here we should use a methode which compares in reverse order if available
            // #85282#
                bFound = sal_True;
            else
                i++;
        }
        if (bFound)
        {
            Reference<XInterface> xIfc =
                xFactory->createInstance(sFieldMaster_Bibliography);
            if( xIfc.is() )
            {
                Reference<XPropertySet> xPropSet( xIfc, UNO_QUERY );
                Any aAny;

                aAny <<= sSuffix;
                xPropSet->setPropertyValue(sBracketAfter, aAny);

                aAny <<= sPrefix;
                xPropSet->setPropertyValue(sBracketBefore, aAny);

                aAny.setValue(&bNumberedEntries, ::getBooleanCppuType());
                xPropSet->setPropertyValue(sIsNumberEntries, aAny);

                aAny.setValue(&bSortByPosition, ::getBooleanCppuType());
                xPropSet->setPropertyValue(sIsSortByPosition, aAny);

                if( (aLocale.Language.getLength() > 0) &&
                    (aLocale.Country.getLength() > 0)     )
                {
                    aAny <<= aLocale;
                    xPropSet->setPropertyValue(sLocale, aAny);
                }

                if( sAlgorithm.getLength() > 0 )
                {
                    aAny <<= sAlgorithm;
                    xPropSet->setPropertyValue(sSortAlgorithm, aAny);
                }

                sal_Int32 nCount = aSortKeys.size();
                Sequence<Sequence<PropertyValue> > aKeysSeq(nCount);
                for(i = 0; i < nCount; i++)
                {
                    aKeysSeq[i] = aSortKeys[i];
                }
                aAny <<= aKeysSeq;
                xPropSet->setPropertyValue(sSortKeys, aAny);
            }
            // else: can't get FieldMaster -> ignore
        }
    }
    // else: can't even get Factory -> ignore
}
<commit_msg>tweak missing bool<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_xmloff.hxx"

#include "XMLIndexBibliographyConfigurationContext.hxx"
#include "XMLIndexBibliographyEntryContext.hxx"
#include <xmloff/xmlictxt.hxx>
#include <xmloff/xmlimp.hxx>
#include <xmloff/txtimp.hxx>
#include <xmloff/nmspmap.hxx>
#include "xmlnmspe.hxx"
#include <xmloff/xmltoken.hxx>
#include <xmloff/xmluconv.hxx>
#include <tools/debug.hxx>
#include <rtl/ustring.hxx>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>

using namespace ::com::sun::star::text;
using namespace ::com::sun::star::uno;
using namespace ::xmloff::token;

using ::rtl::OUString;
using ::com::sun::star::xml::sax::XAttributeList;
using ::com::sun::star::beans::PropertyValue;
using ::com::sun::star::beans::XPropertySet;
using ::com::sun::star::lang::XMultiServiceFactory;

const sal_Char sAPI_FieldMaster_Bibliography[] =
                                "com.sun.star.text.FieldMaster.Bibliography";

TYPEINIT1( XMLIndexBibliographyConfigurationContext, SvXMLStyleContext );

XMLIndexBibliographyConfigurationContext::XMLIndexBibliographyConfigurationContext(
    SvXMLImport& rImport,
    sal_uInt16 nPrfx,
    const OUString& rLocalName,
    const Reference<XAttributeList> & xAttrList) :
        SvXMLStyleContext(rImport, nPrfx, rLocalName, xAttrList, XML_STYLE_FAMILY_TEXT_BIBLIOGRAPHYCONFIG),
        sFieldMaster_Bibliography(
            RTL_CONSTASCII_USTRINGPARAM(sAPI_FieldMaster_Bibliography)),
        sBracketBefore(RTL_CONSTASCII_USTRINGPARAM("BracketBefore")),
        sBracketAfter(RTL_CONSTASCII_USTRINGPARAM("BracketAfter")),
        sIsNumberEntries(RTL_CONSTASCII_USTRINGPARAM("IsNumberEntries")),
        sIsSortByPosition(RTL_CONSTASCII_USTRINGPARAM("IsSortByPosition")),
        sSortKeys(RTL_CONSTASCII_USTRINGPARAM("SortKeys")),
        sSortKey(RTL_CONSTASCII_USTRINGPARAM("SortKey")),
        sIsSortAscending(RTL_CONSTASCII_USTRINGPARAM("IsSortAscending")),
        sSortAlgorithm(RTL_CONSTASCII_USTRINGPARAM("SortAlgorithm")),
        sLocale(RTL_CONSTASCII_USTRINGPARAM("Locale")),
        sSuffix(),
        sPrefix(),
        sAlgorithm(),
        aLocale(),
        bNumberedEntries(sal_False),
        bSortByPosition(sal_True)
{
}

XMLIndexBibliographyConfigurationContext::~XMLIndexBibliographyConfigurationContext()
{
}

void XMLIndexBibliographyConfigurationContext::StartElement(
    const Reference<XAttributeList> & xAttrList)
{
    sal_Int16 nLength = xAttrList->getLength();
    for(sal_Int16 nAttr = 0; nAttr < nLength; nAttr++)
    {
        OUString sLocalName;
        sal_uInt16 nPrefix = GetImport().GetNamespaceMap().
            GetKeyByAttrName( xAttrList->getNameByIndex(nAttr),
                              &sLocalName );

        ProcessAttribute(nPrefix, sLocalName,
                         xAttrList->getValueByIndex(nAttr));
        // else: ignore
    }
}

void XMLIndexBibliographyConfigurationContext::ProcessAttribute(
    sal_uInt16 nPrefix,
    OUString sLocalName,
    OUString sValue)
{
    if( XML_NAMESPACE_TEXT == nPrefix )
    {
        if( IsXMLToken(sLocalName, XML_PREFIX) )
        {
            sPrefix = sValue;
        }
        else if( IsXMLToken(sLocalName, XML_SUFFIX) )
        {
            sSuffix = sValue;
        }
        else if( IsXMLToken(sLocalName, XML_NUMBERED_ENTRIES) )
        {
            bool bTmp;
            if( SvXMLUnitConverter::convertBool(bTmp, sValue) )
            {
                bNumberedEntries = bTmp;
            }
        }
        else if( IsXMLToken(sLocalName, XML_SORT_BY_POSITION) )
        {
            bool bTmp;
            if (SvXMLUnitConverter::convertBool(bTmp, sValue))
            {
                bSortByPosition = bTmp;
            }
        }
        else if( IsXMLToken(sLocalName, XML_SORT_ALGORITHM) )
        {
            sAlgorithm = sValue;
        }
    }
    else if( XML_NAMESPACE_FO == nPrefix )
    {
        if( IsXMLToken(sLocalName, XML_LANGUAGE) )
        {
            aLocale.Language = sValue;
        }
        else if( IsXMLToken(sLocalName, XML_COUNTRY) )
        {
            aLocale.Country = sValue;
        }
    }
}

SvXMLImportContext *XMLIndexBibliographyConfigurationContext::CreateChildContext(
    sal_uInt16 nPrefix,
    const OUString& rLocalName,
    const Reference<XAttributeList> & xAttrList )
{
    OUString sKey;
    sal_Bool bSort(sal_True);

    // process children here and use default context!
    if ( ( nPrefix == XML_NAMESPACE_TEXT ) &&
         IsXMLToken( rLocalName, XML_SORT_KEY ) )
    {
        sal_Int16 nLength = xAttrList->getLength();
        for(sal_Int16 nAttr = 0; nAttr < nLength; nAttr++)
        {
            OUString sLocalName;
            sal_uInt16 nPrfx = GetImport().GetNamespaceMap().
                GetKeyByAttrName( xAttrList->getNameByIndex(nAttr),
                                  &sLocalName );

            if (nPrfx == XML_NAMESPACE_TEXT)
            {
                if ( IsXMLToken( sLocalName, XML_KEY ) )
                {
                    sKey = xAttrList->getValueByIndex(nAttr);
                }
                else if ( IsXMLToken( sLocalName, XML_SORT_ASCENDING ) )
                {
                    bool bTmp;
                    if (SvXMLUnitConverter::convertBool(
                        bTmp, xAttrList->getValueByIndex(nAttr)))
                    {
                        bSort = bTmp;
                    }
                }
            }
        }

        // valid data?
        sal_uInt16 nKey;
        if (SvXMLUnitConverter::convertEnum(nKey, sKey,
                                            aBibliographyDataFieldMap))
        {

            Any aAny;
            Sequence<PropertyValue> aKey(2);

            PropertyValue aNameValue;
            aNameValue.Name = sSortKey;
            aAny <<= (sal_Int16)nKey;
            aNameValue.Value = aAny;
            aKey[0] = aNameValue;

            PropertyValue aSortValue;
            aSortValue.Name = sIsSortAscending;
            aAny.setValue(&bSort, ::getBooleanCppuType());
            aSortValue.Value = aAny;
            aKey[1] = aSortValue;

            aSortKeys.push_back(aKey);
        }
    }

    return SvXMLImportContext::CreateChildContext(nPrefix, rLocalName,
                                                  xAttrList);
}

void XMLIndexBibliographyConfigurationContext::CreateAndInsert(sal_Bool)
{
    // (code almost the same as export...)

    // insert and block mode is handled in insertStyleFamily

    // first: get field master
    // (we'll create one, and get the only master for this type)
    Reference<XMultiServiceFactory> xFactory(GetImport().GetModel(),UNO_QUERY);
    if( xFactory.is() )
    {
        Sequence<rtl::OUString> aServices = xFactory->getAvailableServiceNames();
        sal_Bool bFound(sal_False);
        sal_Int32 i(0);
        sal_Int32 nServiceCount(aServices.getLength());
        while (i < nServiceCount && !bFound)
        {
            if (aServices[i].equals(sFieldMaster_Bibliography))
            // here we should use a methode which compares in reverse order if available
            // #85282#
                bFound = sal_True;
            else
                i++;
        }
        if (bFound)
        {
            Reference<XInterface> xIfc =
                xFactory->createInstance(sFieldMaster_Bibliography);
            if( xIfc.is() )
            {
                Reference<XPropertySet> xPropSet( xIfc, UNO_QUERY );
                Any aAny;

                aAny <<= sSuffix;
                xPropSet->setPropertyValue(sBracketAfter, aAny);

                aAny <<= sPrefix;
                xPropSet->setPropertyValue(sBracketBefore, aAny);

                aAny.setValue(&bNumberedEntries, ::getBooleanCppuType());
                xPropSet->setPropertyValue(sIsNumberEntries, aAny);

                aAny.setValue(&bSortByPosition, ::getBooleanCppuType());
                xPropSet->setPropertyValue(sIsSortByPosition, aAny);

                if( (aLocale.Language.getLength() > 0) &&
                    (aLocale.Country.getLength() > 0)     )
                {
                    aAny <<= aLocale;
                    xPropSet->setPropertyValue(sLocale, aAny);
                }

                if( sAlgorithm.getLength() > 0 )
                {
                    aAny <<= sAlgorithm;
                    xPropSet->setPropertyValue(sSortAlgorithm, aAny);
                }

                sal_Int32 nCount = aSortKeys.size();
                Sequence<Sequence<PropertyValue> > aKeysSeq(nCount);
                for(i = 0; i < nCount; i++)
                {
                    aKeysSeq[i] = aSortKeys[i];
                }
                aAny <<= aKeysSeq;
                xPropSet->setPropertyValue(sSortKeys, aAny);
            }
            // else: can't get FieldMaster -> ignore
        }
    }
    // else: can't even get Factory -> ignore
}
<|endoftext|>


<commit_before>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2012-2015 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <inviwo/core/util/formats.h>
#include <modules/opengl/image/imagegl.h>
#include <modules/opengl/texture/textureunit.h>
#include <modules/opengl/canvasgl.h>
#include <inviwo/core/datastructures/image/image.h>

namespace inviwo {

ImageGL::ImageGL()
    : ImageRepresentation()
    , frameBufferObject_()
    , shader_("standard.vert", "img_copy.frag", false)
    , colorLayerCopyCount_(0)
    , singleChanelCopy_(false) {}

ImageGL::ImageGL(const ImageGL& rhs)
    : ImageRepresentation(rhs)
    , frameBufferObject_()
    , shader_("standard.vert", "img_copy.frag", false)
    , colorLayerCopyCount_(0)
    , singleChanelCopy_(false) {}

ImageGL::~ImageGL() {
    LGL_ERROR;
    frameBufferObject_.deactivate();
    LGL_ERROR;
}

ImageGL* ImageGL::clone() const { return new ImageGL(*this); }

void ImageGL::reAttachAllLayers(ImageType type) {
    frameBufferObject_.activate();
    frameBufferObject_.detachAllTextures();
    pickingAttachmentID_ = 0;

    for (auto layer : colorLayersGL_) {
        layer->getTexture()->bind();
        frameBufferObject_.attachColorTexture(layer->getTexture().get());
    }

    if (depthLayerGL_ && typeContainsDepth(type)) {
        depthLayerGL_->getTexture()->bind();
        frameBufferObject_.attachTexture(depthLayerGL_->getTexture().get(),
                                         static_cast<GLenum>(GL_DEPTH_ATTACHMENT));
    }

    if (pickingLayerGL_ && typeContainsPicking(type)) {
        pickingLayerGL_->getTexture()->bind();
        pickingAttachmentID_ =
            frameBufferObject_.attachColorTexture(pickingLayerGL_->getTexture().get(), 0, true, 1);
    }

    glBindTexture(GL_TEXTURE_2D, 0);

    frameBufferObject_.checkStatus();
    frameBufferObject_.deactivate();
}

void ImageGL::activateBuffer(ImageType type) {
    frameBufferObject_.activate();

    std::vector<GLenum> drawBuffers{frameBufferObject_.getDrawBuffers()};
    if (!drawBuffers.empty()) {
        GLsizei numBuffersToDrawTo = static_cast<GLsizei>(drawBuffers.size());

        // remove second render target (location = 1) when picking is disabled
        if (!typeContainsPicking(type) && (numBuffersToDrawTo > 1) &&
            (drawBuffers[1] == GL_COLOR_ATTACHMENT7)) {
            drawBuffers.erase(drawBuffers.begin() + 1);
            --numBuffersToDrawTo;
        }

        glDrawBuffers(numBuffersToDrawTo, &drawBuffers[0]);
        LGL_ERROR;
    }

    glGetBooleanv(GL_DEPTH_TEST, &prevDepthMask_);
    glGetBooleanv(GL_DEPTH_WRITEMASK, &prevDepthTest_);

    if (!typeContainsDepth(type)) {
        glDisable(GL_DEPTH_TEST);
        glDepthMask(GL_FALSE);
    } else {
        glEnable(GL_DEPTH_TEST);
        glDepthMask(GL_TRUE);
    }

    prevViewport_.get();

    uvec2 dim = getDimensions();
    glViewport(0, 0, dim.x, dim.y);
}

void ImageGL::deactivateBuffer() {
    // restore previous state
    frameBufferObject_.deactivate(); // this will activate the previous frame buffer.

    glDepthMask(prevDepthMask_);

    if (prevDepthTest_ == GL_TRUE) {
        glEnable(GL_DEPTH_TEST);
    } else {
        glDisable(GL_DEPTH_TEST);
    }
    prevViewport_.set();
}

bool ImageGL::copyRepresentationsTo(DataRepresentation* targetRep) const {
    return copyRepresentationsTo(dynamic_cast<ImageGL*>(targetRep));
}

bool ImageGL::copyRepresentationsTo(ImageGL* target) const {
    const ImageGL* source = this;

    LogInfo("COPY");

    auto singleChannel = source->getColorLayerGL()->getDataFormat()->getComponents() == 1;

    // Set shader to copy all color layers
    if (!shader_.isReady() || singleChanelCopy_ != singleChannel ||
        colorLayerCopyCount_ != colorLayersGL_.size()) {
        std::stringstream ssUniform;
        for (size_t i = 1; i < colorLayersGL_.size(); ++i) {
            ssUniform << "layout(location = " << i + 1 << ") out vec4 FragData" << i << ";";
        }
        for (size_t i = 1; i < colorLayersGL_.size(); ++i) {
            ssUniform << "uniform sampler2D color" << i << ";";
        }
        shader_.getFragmentShaderObject()->addShaderDefine("ADDITIONAL_COLOR_LAYER_OUT_UNIFORMS",
                                                           ssUniform.str());

        std::stringstream ssWrite;
        for (size_t i = 1; i < colorLayersGL_.size(); ++i) {
            if (singleChannel) {
                ssWrite << "FragData" << i << " = vec4(texture(color" << i << ", texCoord_.xy).r);";
            } else {
                ssWrite << "FragData" << i << " = texture(color" << i << ", texCoord_.xy);";
            }
        }
        shader_.getFragmentShaderObject()->addShaderDefine("ADDITIONAL_COLOR_LAYER_WRITE",
                                                           ssWrite.str());

        if (colorLayersGL_.size() > 1) {
            shader_.getFragmentShaderObject()->addShaderDefine("ADDITIONAL_COLOR_LAYERS");
        } else {
            shader_.getFragmentShaderObject()->removeShaderDefine("ADDITIONAL_COLOR_LAYERS");
        }

        if (singleChannel) {
            shader_.getFragmentShaderObject()->addShaderDefine("SINGLE_CHANNEL");
        } else {
            shader_.getFragmentShaderObject()->removeShaderDefine("SINGLE_CHANNEL");
        }

        colorLayerCopyCount_ = colorLayersGL_.size();
        singleChanelCopy_ = singleChannel;

        shader_.build();
    }

    TextureUnit colorUnit, depthUnit, pickingUnit;
    source->getColorLayerGL()->bindTexture(colorUnit.getEnum());
    if (source->getDepthLayerGL()) {
        source->getDepthLayerGL()->bindTexture(depthUnit.getEnum());
    }
    if (source->getPickingLayerGL()) {
        source->getPickingLayerGL()->bindTexture(pickingUnit.getEnum());
    }
    TextureUnitContainer additionalColorUnits;
    for (size_t i = 0; i < colorLayersGL_.size(); ++i) {
        TextureUnit unit;
        source->getColorLayerGL(i)->bindTexture(unit.getEnum());
        additionalColorUnits.push_back(std::move(unit));
    }

    // Render to FBO, with correct scaling
    target->activateBuffer(ImageType::AllLayers);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    float ratioSource = (float)source->getDimensions().x / (float)source->getDimensions().y;
    float ratioTarget = (float)target->getDimensions().x / (float)target->getDimensions().y;
    glm::mat4 scale;

    if (ratioTarget < ratioSource)
        scale = glm::scale(glm::vec3(1.0f, ratioTarget / ratioSource, 1.0f));
    else
        scale = glm::scale(glm::vec3(ratioSource / ratioTarget, 1.0f, 1.0f));

    GLint prog;
    glGetIntegerv(GL_CURRENT_PROGRAM, &prog);

    shader_.activate();
    shader_.setUniform("color_", colorUnit.getUnitNumber());
    if (source->getDepthLayerGL()) {
        shader_.setUniform("depth_", depthUnit.getUnitNumber());
    }
    if (source->getPickingLayerGL()) {
        shader_.setUniform("picking_", pickingUnit.getUnitNumber());
    }
    for (size_t i = 0; i < additionalColorUnits.size(); ++i) {
        shader_.setUniform("color" + toString<size_t>(i + 1),
                           additionalColorUnits[i].getUnitNumber());
    }
    shader_.setUniform("dataToClip", scale);

    LGL_ERROR;
    target->renderImagePlaneRect();
    LGL_ERROR;
    shader_.deactivate();
    target->deactivateBuffer();
    LGL_ERROR;

    glUseProgram(prog);

    return true;
}

bool ImageGL::updateFrom(const ImageGL* source) {
    ImageGL* target = this;

    // Primarily Copy by FBO blitting, all from source FBO to target FBO
    const FrameBufferObject* srcFBO = source->getFBO();
    FrameBufferObject* tgtFBO = target->getFBO();
    const Texture2D* sTex = source->getColorLayerGL()->getTexture().get();
    Texture2D* tTex = target->getColorLayerGL()->getTexture().get();

    const std::vector<bool>& srcBuffers = srcFBO->getDrawBuffersInUse();
    const std::vector<bool>& targetBuffers = tgtFBO->getDrawBuffersInUse();
    srcFBO->setRead_Blit();
    tgtFBO->setDraw_Blit();
    GLbitfield mask = GL_COLOR_BUFFER_BIT;

    if (srcFBO->hasDepthAttachment() && tgtFBO->hasDepthAttachment()) mask |= GL_DEPTH_BUFFER_BIT;

    if (srcFBO->hasStencilAttachment() && tgtFBO->hasStencilAttachment())
        mask |= GL_STENCIL_BUFFER_BIT;

    glBlitFramebufferEXT(0, 0, sTex->getWidth(), sTex->getHeight(), 0, 0, tTex->getWidth(),
                         tTex->getHeight(), mask, GL_NEAREST);
    bool pickingCopied = false;

    for (int i = 1; i < srcFBO->getMaxColorAttachments(); i++) {
        if (srcBuffers[i] && targetBuffers[i]) {
            glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + i);
            glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + i);
            glBlitFramebufferEXT(0, 0, sTex->getWidth(), sTex->getHeight(), 0, 0, tTex->getWidth(),
                                 tTex->getHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST);

            if (GL_COLOR_ATTACHMENT0_EXT + i == static_cast<int>(pickingAttachmentID_))
                pickingCopied = true;
        }
    }

    glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
    glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
    srcFBO->setRead_Blit(false);
    tgtFBO->setDraw_Blit(false);

    LGL_ERROR;

    // Secondary copy using PBO

    // Depth texture
    if ((mask & GL_DEPTH_BUFFER_BIT) == 0) {
        sTex = source->getDepthLayerGL()->getTexture().get();
        tTex = target->getDepthLayerGL()->getTexture().get();

        if (sTex && tTex) tTex->loadFromPBO(sTex);
    }

    LGL_ERROR;

    // Picking texture
    if (!pickingCopied && pickingAttachmentID_ != 0) {
        sTex = source->getPickingLayerGL()->getTexture().get();
        tTex = target->getPickingLayerGL()->getTexture().get();

        if (sTex && tTex) tTex->loadFromPBO(sTex);
    }

    LGL_ERROR;
    return true;
}

FrameBufferObject* ImageGL::getFBO() { return &frameBufferObject_; }

const FrameBufferObject* ImageGL::getFBO() const { return &frameBufferObject_; }

LayerGL* ImageGL::getLayerGL(LayerType type, size_t idx) {
    switch (type) {
        case LayerType::Color:
            return getColorLayerGL(idx);

        case LayerType::Depth:
            return getDepthLayerGL();

        case LayerType::Picking:
            return getPickingLayerGL();
    }

    return nullptr;
}

const LayerGL* ImageGL::getLayerGL(LayerType type, size_t idx) const {
    switch (type) {
        case LayerType::Color:
            return getColorLayerGL(idx);

        case LayerType::Depth:
            return getDepthLayerGL();

        case LayerType::Picking:
            return getPickingLayerGL();
    }

    return nullptr;
}

LayerGL* ImageGL::getColorLayerGL(size_t idx) { return colorLayersGL_.at(idx); }

LayerGL* ImageGL::getDepthLayerGL() { return depthLayerGL_; }

LayerGL* ImageGL::getPickingLayerGL() { return pickingLayerGL_; }

const LayerGL* ImageGL::getColorLayerGL(size_t idx) const { return colorLayersGL_.at(idx); }

const LayerGL* ImageGL::getDepthLayerGL() const { return depthLayerGL_; }

const LayerGL* ImageGL::getPickingLayerGL() const { return pickingLayerGL_; }

void ImageGL::updateExistingLayers() const {
    auto owner = static_cast<const Image*>(this->getOwner());

    for (size_t i = 0; i < owner->getNumberOfColorLayers(); ++i) {
        owner->getColorLayer(i)->getRepresentation<LayerGL>();
    }

    const Layer* depthLayer = owner->getDepthLayer();

    if (depthLayer) depthLayer->getRepresentation<LayerGL>();

    const Layer* pickingLayer = owner->getPickingLayer();

    if (pickingLayer) pickingLayer->getRepresentation<LayerGL>();
}

void ImageGL::update(bool editable) {
    colorLayersGL_.clear();
    depthLayerGL_ = nullptr;
    pickingLayerGL_ = nullptr;

    if (editable) {
        auto owner = static_cast<Image*>(this->getOwner());

        for (size_t i = 0; i < owner->getNumberOfColorLayers(); ++i) {
            colorLayersGL_.push_back(owner->getColorLayer(i)->getEditableRepresentation<LayerGL>());
        }

        Layer* depthLayer = owner->getDepthLayer();
        if (depthLayer) {
            depthLayerGL_ = depthLayer->getEditableRepresentation<LayerGL>();
        }

        Layer* pickingLayer = owner->getPickingLayer();
        if (pickingLayer) {
            pickingLayerGL_ = pickingLayer->getEditableRepresentation<LayerGL>();
        }

    } else {
        auto owner = static_cast<const Image*>(this->getOwner());

        for (size_t i = 0; i < owner->getNumberOfColorLayers(); ++i) {
            colorLayersGL_.push_back(
                const_cast<LayerGL*>(owner->getColorLayer(i)->getRepresentation<LayerGL>()));
        }

        const Layer* depthLayer = owner->getDepthLayer();
        if (depthLayer) {
            depthLayerGL_ = const_cast<LayerGL*>(depthLayer->getRepresentation<LayerGL>());
        }

        const Layer* pickingLayer = owner->getPickingLayer();
        if (pickingLayer) {
            pickingLayerGL_ = const_cast<LayerGL*>(pickingLayer->getRepresentation<LayerGL>());
        }
    }

    // Attach all targets
    reAttachAllLayers(ImageType::AllLayers);
}

void ImageGL::renderImagePlaneRect() const {
    BufferObjectArray rectArray{};
    CanvasGL::attachImagePlanRect(&rectArray);
    LGL_ERROR;
    glDepthFunc(GL_ALWAYS);
    rectArray.bind();
    LGL_ERROR;
    CanvasGL::singleDrawImagePlaneRect();
    rectArray.unbind();
    glDepthFunc(GL_LESS);
    LGL_ERROR;
}

std::type_index ImageGL::getTypeIndex() const { return std::type_index(typeid(ImageGL)); }

GLenum ImageGL::getPickingAttachmentID() const { return pickingAttachmentID_; }

}  // namespace
<commit_msg>OpenGL: removed log print<commit_after>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2012-2015 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <inviwo/core/util/formats.h>
#include <modules/opengl/image/imagegl.h>
#include <modules/opengl/texture/textureunit.h>
#include <modules/opengl/canvasgl.h>
#include <inviwo/core/datastructures/image/image.h>

namespace inviwo {

ImageGL::ImageGL()
    : ImageRepresentation()
    , frameBufferObject_()
    , shader_("standard.vert", "img_copy.frag", false)
    , colorLayerCopyCount_(0)
    , singleChanelCopy_(false) {}

ImageGL::ImageGL(const ImageGL& rhs)
    : ImageRepresentation(rhs)
    , frameBufferObject_()
    , shader_("standard.vert", "img_copy.frag", false)
    , colorLayerCopyCount_(0)
    , singleChanelCopy_(false) {}

ImageGL::~ImageGL() {
    LGL_ERROR;
    frameBufferObject_.deactivate();
    LGL_ERROR;
}

ImageGL* ImageGL::clone() const { return new ImageGL(*this); }

void ImageGL::reAttachAllLayers(ImageType type) {
    frameBufferObject_.activate();
    frameBufferObject_.detachAllTextures();
    pickingAttachmentID_ = 0;

    for (auto layer : colorLayersGL_) {
        layer->getTexture()->bind();
        frameBufferObject_.attachColorTexture(layer->getTexture().get());
    }

    if (depthLayerGL_ && typeContainsDepth(type)) {
        depthLayerGL_->getTexture()->bind();
        frameBufferObject_.attachTexture(depthLayerGL_->getTexture().get(),
                                         static_cast<GLenum>(GL_DEPTH_ATTACHMENT));
    }

    if (pickingLayerGL_ && typeContainsPicking(type)) {
        pickingLayerGL_->getTexture()->bind();
        pickingAttachmentID_ =
            frameBufferObject_.attachColorTexture(pickingLayerGL_->getTexture().get(), 0, true, 1);
    }

    glBindTexture(GL_TEXTURE_2D, 0);

    frameBufferObject_.checkStatus();
    frameBufferObject_.deactivate();
}

void ImageGL::activateBuffer(ImageType type) {
    frameBufferObject_.activate();

    std::vector<GLenum> drawBuffers{frameBufferObject_.getDrawBuffers()};
    if (!drawBuffers.empty()) {
        GLsizei numBuffersToDrawTo = static_cast<GLsizei>(drawBuffers.size());

        // remove second render target (location = 1) when picking is disabled
        if (!typeContainsPicking(type) && (numBuffersToDrawTo > 1) &&
            (drawBuffers[1] == GL_COLOR_ATTACHMENT7)) {
            drawBuffers.erase(drawBuffers.begin() + 1);
            --numBuffersToDrawTo;
        }

        glDrawBuffers(numBuffersToDrawTo, &drawBuffers[0]);
        LGL_ERROR;
    }

    glGetBooleanv(GL_DEPTH_TEST, &prevDepthMask_);
    glGetBooleanv(GL_DEPTH_WRITEMASK, &prevDepthTest_);

    if (!typeContainsDepth(type)) {
        glDisable(GL_DEPTH_TEST);
        glDepthMask(GL_FALSE);
    } else {
        glEnable(GL_DEPTH_TEST);
        glDepthMask(GL_TRUE);
    }

    prevViewport_.get();

    uvec2 dim = getDimensions();
    glViewport(0, 0, dim.x, dim.y);
}

void ImageGL::deactivateBuffer() {
    // restore previous state
    frameBufferObject_.deactivate(); // this will activate the previous frame buffer.

    glDepthMask(prevDepthMask_);

    if (prevDepthTest_ == GL_TRUE) {
        glEnable(GL_DEPTH_TEST);
    } else {
        glDisable(GL_DEPTH_TEST);
    }
    prevViewport_.set();
}

bool ImageGL::copyRepresentationsTo(DataRepresentation* targetRep) const {
    return copyRepresentationsTo(dynamic_cast<ImageGL*>(targetRep));
}

bool ImageGL::copyRepresentationsTo(ImageGL* target) const {
    const ImageGL* source = this;

    auto singleChannel = source->getColorLayerGL()->getDataFormat()->getComponents() == 1;

    // Set shader to copy all color layers
    if (!shader_.isReady() || singleChanelCopy_ != singleChannel ||
        colorLayerCopyCount_ != colorLayersGL_.size()) {
        std::stringstream ssUniform;
        for (size_t i = 1; i < colorLayersGL_.size(); ++i) {
            ssUniform << "layout(location = " << i + 1 << ") out vec4 FragData" << i << ";";
        }
        for (size_t i = 1; i < colorLayersGL_.size(); ++i) {
            ssUniform << "uniform sampler2D color" << i << ";";
        }
        shader_.getFragmentShaderObject()->addShaderDefine("ADDITIONAL_COLOR_LAYER_OUT_UNIFORMS",
                                                           ssUniform.str());

        std::stringstream ssWrite;
        for (size_t i = 1; i < colorLayersGL_.size(); ++i) {
            if (singleChannel) {
                ssWrite << "FragData" << i << " = vec4(texture(color" << i << ", texCoord_.xy).r);";
            } else {
                ssWrite << "FragData" << i << " = texture(color" << i << ", texCoord_.xy);";
            }
        }
        shader_.getFragmentShaderObject()->addShaderDefine("ADDITIONAL_COLOR_LAYER_WRITE",
                                                           ssWrite.str());

        if (colorLayersGL_.size() > 1) {
            shader_.getFragmentShaderObject()->addShaderDefine("ADDITIONAL_COLOR_LAYERS");
        } else {
            shader_.getFragmentShaderObject()->removeShaderDefine("ADDITIONAL_COLOR_LAYERS");
        }

        if (singleChannel) {
            shader_.getFragmentShaderObject()->addShaderDefine("SINGLE_CHANNEL");
        } else {
            shader_.getFragmentShaderObject()->removeShaderDefine("SINGLE_CHANNEL");
        }

        colorLayerCopyCount_ = colorLayersGL_.size();
        singleChanelCopy_ = singleChannel;

        shader_.build();
    }

    TextureUnit colorUnit, depthUnit, pickingUnit;
    source->getColorLayerGL()->bindTexture(colorUnit.getEnum());
    if (source->getDepthLayerGL()) {
        source->getDepthLayerGL()->bindTexture(depthUnit.getEnum());
    }
    if (source->getPickingLayerGL()) {
        source->getPickingLayerGL()->bindTexture(pickingUnit.getEnum());
    }
    TextureUnitContainer additionalColorUnits;
    for (size_t i = 0; i < colorLayersGL_.size(); ++i) {
        TextureUnit unit;
        source->getColorLayerGL(i)->bindTexture(unit.getEnum());
        additionalColorUnits.push_back(std::move(unit));
    }

    // Render to FBO, with correct scaling
    target->activateBuffer(ImageType::AllLayers);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    float ratioSource = (float)source->getDimensions().x / (float)source->getDimensions().y;
    float ratioTarget = (float)target->getDimensions().x / (float)target->getDimensions().y;
    glm::mat4 scale;

    if (ratioTarget < ratioSource)
        scale = glm::scale(glm::vec3(1.0f, ratioTarget / ratioSource, 1.0f));
    else
        scale = glm::scale(glm::vec3(ratioSource / ratioTarget, 1.0f, 1.0f));

    GLint prog;
    glGetIntegerv(GL_CURRENT_PROGRAM, &prog);

    shader_.activate();
    shader_.setUniform("color_", colorUnit.getUnitNumber());
    if (source->getDepthLayerGL()) {
        shader_.setUniform("depth_", depthUnit.getUnitNumber());
    }
    if (source->getPickingLayerGL()) {
        shader_.setUniform("picking_", pickingUnit.getUnitNumber());
    }
    for (size_t i = 0; i < additionalColorUnits.size(); ++i) {
        shader_.setUniform("color" + toString<size_t>(i + 1),
                           additionalColorUnits[i].getUnitNumber());
    }
    shader_.setUniform("dataToClip", scale);

    LGL_ERROR;
    target->renderImagePlaneRect();
    LGL_ERROR;
    shader_.deactivate();
    target->deactivateBuffer();
    LGL_ERROR;

    glUseProgram(prog);

    return true;
}

bool ImageGL::updateFrom(const ImageGL* source) {
    ImageGL* target = this;

    // Primarily Copy by FBO blitting, all from source FBO to target FBO
    const FrameBufferObject* srcFBO = source->getFBO();
    FrameBufferObject* tgtFBO = target->getFBO();
    const Texture2D* sTex = source->getColorLayerGL()->getTexture().get();
    Texture2D* tTex = target->getColorLayerGL()->getTexture().get();

    const std::vector<bool>& srcBuffers = srcFBO->getDrawBuffersInUse();
    const std::vector<bool>& targetBuffers = tgtFBO->getDrawBuffersInUse();
    srcFBO->setRead_Blit();
    tgtFBO->setDraw_Blit();
    GLbitfield mask = GL_COLOR_BUFFER_BIT;

    if (srcFBO->hasDepthAttachment() && tgtFBO->hasDepthAttachment()) mask |= GL_DEPTH_BUFFER_BIT;

    if (srcFBO->hasStencilAttachment() && tgtFBO->hasStencilAttachment())
        mask |= GL_STENCIL_BUFFER_BIT;

    glBlitFramebufferEXT(0, 0, sTex->getWidth(), sTex->getHeight(), 0, 0, tTex->getWidth(),
                         tTex->getHeight(), mask, GL_NEAREST);
    bool pickingCopied = false;

    for (int i = 1; i < srcFBO->getMaxColorAttachments(); i++) {
        if (srcBuffers[i] && targetBuffers[i]) {
            glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + i);
            glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + i);
            glBlitFramebufferEXT(0, 0, sTex->getWidth(), sTex->getHeight(), 0, 0, tTex->getWidth(),
                                 tTex->getHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST);

            if (GL_COLOR_ATTACHMENT0_EXT + i == static_cast<int>(pickingAttachmentID_))
                pickingCopied = true;
        }
    }

    glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
    glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
    srcFBO->setRead_Blit(false);
    tgtFBO->setDraw_Blit(false);

    LGL_ERROR;

    // Secondary copy using PBO

    // Depth texture
    if ((mask & GL_DEPTH_BUFFER_BIT) == 0) {
        sTex = source->getDepthLayerGL()->getTexture().get();
        tTex = target->getDepthLayerGL()->getTexture().get();

        if (sTex && tTex) tTex->loadFromPBO(sTex);
    }

    LGL_ERROR;

    // Picking texture
    if (!pickingCopied && pickingAttachmentID_ != 0) {
        sTex = source->getPickingLayerGL()->getTexture().get();
        tTex = target->getPickingLayerGL()->getTexture().get();

        if (sTex && tTex) tTex->loadFromPBO(sTex);
    }

    LGL_ERROR;
    return true;
}

FrameBufferObject* ImageGL::getFBO() { return &frameBufferObject_; }

const FrameBufferObject* ImageGL::getFBO() const { return &frameBufferObject_; }

LayerGL* ImageGL::getLayerGL(LayerType type, size_t idx) {
    switch (type) {
        case LayerType::Color:
            return getColorLayerGL(idx);

        case LayerType::Depth:
            return getDepthLayerGL();

        case LayerType::Picking:
            return getPickingLayerGL();
    }

    return nullptr;
}

const LayerGL* ImageGL::getLayerGL(LayerType type, size_t idx) const {
    switch (type) {
        case LayerType::Color:
            return getColorLayerGL(idx);

        case LayerType::Depth:
            return getDepthLayerGL();

        case LayerType::Picking:
            return getPickingLayerGL();
    }

    return nullptr;
}

LayerGL* ImageGL::getColorLayerGL(size_t idx) { return colorLayersGL_.at(idx); }

LayerGL* ImageGL::getDepthLayerGL() { return depthLayerGL_; }

LayerGL* ImageGL::getPickingLayerGL() { return pickingLayerGL_; }

const LayerGL* ImageGL::getColorLayerGL(size_t idx) const { return colorLayersGL_.at(idx); }

const LayerGL* ImageGL::getDepthLayerGL() const { return depthLayerGL_; }

const LayerGL* ImageGL::getPickingLayerGL() const { return pickingLayerGL_; }

void ImageGL::updateExistingLayers() const {
    auto owner = static_cast<const Image*>(this->getOwner());

    for (size_t i = 0; i < owner->getNumberOfColorLayers(); ++i) {
        owner->getColorLayer(i)->getRepresentation<LayerGL>();
    }

    const Layer* depthLayer = owner->getDepthLayer();

    if (depthLayer) depthLayer->getRepresentation<LayerGL>();

    const Layer* pickingLayer = owner->getPickingLayer();

    if (pickingLayer) pickingLayer->getRepresentation<LayerGL>();
}

void ImageGL::update(bool editable) {
    colorLayersGL_.clear();
    depthLayerGL_ = nullptr;
    pickingLayerGL_ = nullptr;

    if (editable) {
        auto owner = static_cast<Image*>(this->getOwner());

        for (size_t i = 0; i < owner->getNumberOfColorLayers(); ++i) {
            colorLayersGL_.push_back(owner->getColorLayer(i)->getEditableRepresentation<LayerGL>());
        }

        Layer* depthLayer = owner->getDepthLayer();
        if (depthLayer) {
            depthLayerGL_ = depthLayer->getEditableRepresentation<LayerGL>();
        }

        Layer* pickingLayer = owner->getPickingLayer();
        if (pickingLayer) {
            pickingLayerGL_ = pickingLayer->getEditableRepresentation<LayerGL>();
        }

    } else {
        auto owner = static_cast<const Image*>(this->getOwner());

        for (size_t i = 0; i < owner->getNumberOfColorLayers(); ++i) {
            colorLayersGL_.push_back(
                const_cast<LayerGL*>(owner->getColorLayer(i)->getRepresentation<LayerGL>()));
        }

        const Layer* depthLayer = owner->getDepthLayer();
        if (depthLayer) {
            depthLayerGL_ = const_cast<LayerGL*>(depthLayer->getRepresentation<LayerGL>());
        }

        const Layer* pickingLayer = owner->getPickingLayer();
        if (pickingLayer) {
            pickingLayerGL_ = const_cast<LayerGL*>(pickingLayer->getRepresentation<LayerGL>());
        }
    }

    // Attach all targets
    reAttachAllLayers(ImageType::AllLayers);
}

void ImageGL::renderImagePlaneRect() const {
    BufferObjectArray rectArray{};
    CanvasGL::attachImagePlanRect(&rectArray);
    LGL_ERROR;
    glDepthFunc(GL_ALWAYS);
    rectArray.bind();
    LGL_ERROR;
    CanvasGL::singleDrawImagePlaneRect();
    rectArray.unbind();
    glDepthFunc(GL_LESS);
    LGL_ERROR;
}

std::type_index ImageGL::getTypeIndex() const { return std::type_index(typeid(ImageGL)); }

GLenum ImageGL::getPickingAttachmentID() const { return pickingAttachmentID_; }

}  // namespace
<|endoftext|>