<commit_before>/***************************************************************************
 *   Copyright (c) Victor Titov (DeepSOIC)                                 *
 *                                           (vv.titov@gmail.com) 2015     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
# include <QEvent>
# include <QGraphicsItem>
# include <QWidget>
# ifdef FC_OS_WIN32
# include <Windows.h>
# endif
# include <cassert>
#endif

#include "WinNativeGestureRecognizers.h"
#ifdef GESTURE_MESS
//this implementation is a bit incompatible with Qt5, since
//nativegesture members were transformed into properties, and
//the whole event was made public

#include <qgesture.h>

#include <Base/Exception.h>
#include <App/Application.h>
#include <Base/Parameter.h>

QT_BEGIN_NAMESPACE

#if !defined(QT_NO_NATIVE_GESTURES)

//#include <private/qevent_p.h>
//this include is not available on conda Qt, see https://forum.freecadweb.org/viewtopic.php?f=4&t=21405&p=167395#p167395
//copy-pasted from this header:
class QNativeGestureEvent : public QEvent
{
public:
    enum Type {
        None,
        GestureBegin,
        GestureEnd,
        Pan,
        Zoom,
        Rotate,
        Swipe
    };

    QNativeGestureEvent()
        : QEvent(QEvent::NativeGesture), gestureType(None), percentage(0)
#ifdef Q_WS_WIN
        , sequenceId(0), argument(0)
#endif
    {
    }

    Type gestureType;
    float percentage;
    QPoint position;
    float angle;
#ifdef Q_WS_WIN
    ulong sequenceId;
    quint64 argument;
#endif
};

QGesture* WinNativeGestureRecognizerPinch::create(QObject* target)
{
    if (!target)
      return new QPinchGestureN; // a special case
    if (!target->isWidgetType())
      return 0;
    if (qobject_cast<QGraphicsObject *>(target))
      return 0;

    //QWidget* q = static_cast<QWidget *>(target);
    /*QWidgetPrivate *d = q->d_func();
    d->nativeGesturePanEnabled = true;
    d->winSetupGestures();*/ //fails to compile =(, but we can rely on this being done by grabGesture(Pan...

    return new QPinchGestureN;
}

QGestureRecognizer::Result WinNativeGestureRecognizerPinch::recognize(QGesture *gesture, QObject *watched, QEvent *event)
{
    QPinchGestureN* q = static_cast<QPinchGestureN*> (gesture);
    //QPinchGesturePrivate* d = q->d_func();//this fails to compile =( But we can get away without it.

    QGestureRecognizer::Result result = QGestureRecognizer::Ignore;
    if (event->type() == QEvent::NativeGesture) {
        bool bZoom = false;
        bool bRotate = false;
        QNativeGestureEvent *ev = static_cast<QNativeGestureEvent*>(event);
        switch(ev->gestureType) {
        case QNativeGestureEvent::GestureBegin:
            break;
        case QNativeGestureEvent::Zoom:
        case QNativeGestureEvent::Rotate:
            bZoom = ev->gestureType == QNativeGestureEvent::Zoom;
            bRotate = ev->gestureType == QNativeGestureEvent::Rotate;
            result = QGestureRecognizer::TriggerGesture;
            event->accept();
            break;
        case QNativeGestureEvent::GestureEnd:
            if (q->state() == Qt::NoGesture)
                return QGestureRecognizer::Ignore; // some other gesture has ended
            result = QGestureRecognizer::FinishGesture;
            break;
        default:
            return QGestureRecognizer::Ignore;
        }
        double ang = 0.0;
        if (bRotate)
            ang = -GID_ROTATE_ANGLE_FROM_ARGUMENT(LOWORD(ev->argument)) / M_PI * 180.0;
        if (q->state() == Qt::NoGesture) {
            //start of a new gesture, prefill stuff
            //d->isNewSequence = true;
            q->setTotalChangeFlags(0); q->setChangeFlags(0);

            q->setLastCenterPoint(QPointF());
            q->setCenterPoint(
                  QPointF(
                    qreal(ev->position.x()),
                    qreal(ev->position.y())
                  )
            );
            q->setStartCenterPoint(q->centerPoint());
            q->setTotalRotationAngle(0.0); q->setLastRotationAngle(0.0);  q->setRotationAngle(0.0);
            q->setTotalScaleFactor(1.0); q->setLastScaleFactor(1.0); q->setScaleFactor(1.0);
            if(bZoom) {
                q->myLastFingerDistance = ev->argument;
                q->myFingerDistance = ev->argument;
                q->myStartFingerDistance = ev->argument;
            } else if (bRotate) {
                q->myLastRotationAngle = 0;
                q->myRotationAngle = 0;
                q->myStartAngle = 0;
            }
        } else {//in the middle of gesture

            //store new last values
            q->setLastCenterPoint(q->centerPoint());
            q->setLastRotationAngle(q->rotationAngle());
            q->setLastScaleFactor(q->scaleFactor());
            q->myLastFingerDistance = q->myFingerDistance;
            q->myLastRotationAngle = q->myRotationAngle;

            //update the current values
            if (bZoom)
                q->myFingerDistance = ev->argument;
            if (bRotate)
                q->myRotationAngle = ang;
            if(ev->gestureType == QNativeGestureEvent::GestureEnd){
                q->myFingerDistance = q->myLastFingerDistance;//the end-of-gesture event holds no finger separation data, hence we are using the last value.
                q->myRotationAngle = q->myLastRotationAngle;
            }
            if (bZoom)
                q->setScaleFactor(
                        (qreal)(q->myFingerDistance) / (qreal)(q->myLastFingerDistance)
                );
            if (bRotate)
                q->setRotationAngle(q->myRotationAngle);
            q->setCenterPoint(
                  QPointF(
                    qreal(ev->position.x()),
                    qreal(ev->position.y())
                  )
            );

            //detect changes
            QPinchGesture::ChangeFlags cf = 0;
            if ( q->scaleFactor() != 1.0 )
                cf |= QPinchGesture::ScaleFactorChanged;
            if (q->lastCenterPoint() != q->centerPoint())
                cf |= QPinchGesture::CenterPointChanged;
            if (q->rotationAngle() != q->lastRotationAngle())
                cf |= QPinchGesture::RotationAngleChanged;
            q->setChangeFlags(cf);

            //update totals
            q->setTotalChangeFlags (q->totalChangeFlags() | q->changeFlags());
            q->setTotalScaleFactor (q->totalScaleFactor() * q->scaleFactor());
            q->setTotalRotationAngle (q->rotationAngle());
        }
    }
    return result;
}

void WinNativeGestureRecognizerPinch::reset(QGesture* gesture)
{
  QGestureRecognizer::reset(gesture);//resets the state of the gesture, which is not write-accessible otherwise
  QPinchGestureN *q = static_cast<QPinchGestureN*>(gesture);
  q->myLastFingerDistance = 0;
  q->setTotalChangeFlags(0); q->setChangeFlags(0);

  q->setLastCenterPoint(QPointF());
  q->setCenterPoint(
        QPointF(
          0.0,
          0.0
        )
  );
  q->setStartCenterPoint(q->centerPoint());
  q->setTotalRotationAngle(0.0); q->setLastRotationAngle(0.0);  q->setRotationAngle(0.0);
  q->setTotalScaleFactor(1.0); q->setLastScaleFactor(1.0); q->setScaleFactor(1.0);
  q->myLastFingerDistance = 0;
  q->myFingerDistance = 0;
}

//function prototype for dymanic linking
typedef BOOL ( __stdcall * ptrSetGestureConfig) (
     HWND ,              // window for which configuration is specified
     DWORD ,             // reserved, must be 0
     UINT ,              // count of GESTURECONFIG structures
     PGESTURECONFIG ,    // array of GESTURECONFIG structures, dwIDs will be processed in the
                         // order specified and repeated occurrences will overwrite previous ones
     UINT );             // sizeof(GESTURECONFIG)

void WinNativeGestureRecognizerPinch::TuneWindowsGestures(QWidget* target)
{
    //modify windows-specific gesture options
#if WINVER >= _WIN32_WINNT_WIN7
    //dynamic linking - required to be able to run on windows pre-7
    HINSTANCE hinstLib = LoadLibraryA("user32.dll");
    if (hinstLib == 0)
        throw Base::RuntimeError("LoadLibrary(user32.dll) failed. Could not tune Windows gestures.");

    ptrSetGestureConfig dllSetGestureConfig = reinterpret_cast<ptrSetGestureConfig> (GetProcAddress(hinstLib,"SetGestureConfig"));
    if (dllSetGestureConfig == 0)
        throw Base::RuntimeError("DLL entry point for SetGestureConfig not found in user32.dll. Could not tune Windows gestures.");

    HWND w = target->winId();

    //fill in the options
    const UINT nCfg = 2;
    GESTURECONFIG cfgs[nCfg];
    ZeroMemory(&cfgs, sizeof(cfgs));
    cfgs[0].dwID = GID_PAN;
    cfgs[0].dwWant = GC_PAN;
    cfgs[0].dwBlock = GC_PAN_WITH_GUTTER;//disables stickiness to pure vertical/pure horizontal pans

    bool enableGestureTilt = !(App::GetApplication().GetParameterGroupByPath
        ("User parameter:BaseApp/Preferences/View")->GetBool("DisableTouchTilt",true));
    if(enableGestureTilt){
        cfgs[1].dwID = GID_ROTATE;
        cfgs[1].dwWant = GC_ROTATE;
    } else {
        cfgs[1].dwID = GID_ROTATE;
        cfgs[1].dwBlock = GC_ROTATE;
    }

    //set the options
    bool ret = dllSetGestureConfig(w, 0, nCfg, cfgs, sizeof(GESTURECONFIG));
    assert(ret);
    if(!ret){
        DWORD err = GetLastError();
        QString errMsg = QString::fromLatin1("Error in SetGestureConfig. GetLastError = %1").arg(err);
        throw Base::RuntimeError(errMsg.toLatin1());
    }
#endif
}

#endif //!defined(QT_NO_NATIVE_GESTURES)

#endif // GESTURE_MESS
<commit_msg>include cmath header for definition of M_PI<commit_after>/***************************************************************************
 *   Copyright (c) Victor Titov (DeepSOIC)                                 *
 *                                           (vv.titov@gmail.com) 2015     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
# include <QEvent>
# include <QGraphicsItem>
# include <QWidget>
# ifdef FC_OS_WIN32
# include <Windows.h>
# define _USE_MATH_DEFINES
# include <cmath>
# endif
# include <cassert>
#endif

#include "WinNativeGestureRecognizers.h"
#ifdef GESTURE_MESS
//this implementation is a bit incompatible with Qt5, since
//nativegesture members were transformed into properties, and
//the whole event was made public

#include <qgesture.h>

#include <Base/Exception.h>
#include <App/Application.h>
#include <Base/Parameter.h>

QT_BEGIN_NAMESPACE

#if !defined(QT_NO_NATIVE_GESTURES)

//#include <private/qevent_p.h>
//this include is not available on conda Qt, see https://forum.freecadweb.org/viewtopic.php?f=4&t=21405&p=167395#p167395
//copy-pasted from this header:
class QNativeGestureEvent : public QEvent
{
public:
    enum Type {
        None,
        GestureBegin,
        GestureEnd,
        Pan,
        Zoom,
        Rotate,
        Swipe
    };

    QNativeGestureEvent()
        : QEvent(QEvent::NativeGesture), gestureType(None), percentage(0)
#ifdef Q_WS_WIN
        , sequenceId(0), argument(0)
#endif
    {
    }

    Type gestureType;
    float percentage;
    QPoint position;
    float angle;
#ifdef Q_WS_WIN
    ulong sequenceId;
    quint64 argument;
#endif
};

QGesture* WinNativeGestureRecognizerPinch::create(QObject* target)
{
    if (!target)
      return new QPinchGestureN; // a special case
    if (!target->isWidgetType())
      return 0;
    if (qobject_cast<QGraphicsObject *>(target))
      return 0;

    //QWidget* q = static_cast<QWidget *>(target);
    /*QWidgetPrivate *d = q->d_func();
    d->nativeGesturePanEnabled = true;
    d->winSetupGestures();*/ //fails to compile =(, but we can rely on this being done by grabGesture(Pan...

    return new QPinchGestureN;
}

QGestureRecognizer::Result WinNativeGestureRecognizerPinch::recognize(QGesture *gesture, QObject *watched, QEvent *event)
{
    QPinchGestureN* q = static_cast<QPinchGestureN*> (gesture);
    //QPinchGesturePrivate* d = q->d_func();//this fails to compile =( But we can get away without it.

    QGestureRecognizer::Result result = QGestureRecognizer::Ignore;
    if (event->type() == QEvent::NativeGesture) {
        bool bZoom = false;
        bool bRotate = false;
        QNativeGestureEvent *ev = static_cast<QNativeGestureEvent*>(event);
        switch(ev->gestureType) {
        case QNativeGestureEvent::GestureBegin:
            break;
        case QNativeGestureEvent::Zoom:
        case QNativeGestureEvent::Rotate:
            bZoom = ev->gestureType == QNativeGestureEvent::Zoom;
            bRotate = ev->gestureType == QNativeGestureEvent::Rotate;
            result = QGestureRecognizer::TriggerGesture;
            event->accept();
            break;
        case QNativeGestureEvent::GestureEnd:
            if (q->state() == Qt::NoGesture)
                return QGestureRecognizer::Ignore; // some other gesture has ended
            result = QGestureRecognizer::FinishGesture;
            break;
        default:
            return QGestureRecognizer::Ignore;
        }
        double ang = 0.0;
        if (bRotate)
            ang = -GID_ROTATE_ANGLE_FROM_ARGUMENT(LOWORD(ev->argument)) / M_PI * 180.0;
        if (q->state() == Qt::NoGesture) {
            //start of a new gesture, prefill stuff
            //d->isNewSequence = true;
            q->setTotalChangeFlags(0); q->setChangeFlags(0);

            q->setLastCenterPoint(QPointF());
            q->setCenterPoint(
                  QPointF(
                    qreal(ev->position.x()),
                    qreal(ev->position.y())
                  )
            );
            q->setStartCenterPoint(q->centerPoint());
            q->setTotalRotationAngle(0.0); q->setLastRotationAngle(0.0);  q->setRotationAngle(0.0);
            q->setTotalScaleFactor(1.0); q->setLastScaleFactor(1.0); q->setScaleFactor(1.0);
            if(bZoom) {
                q->myLastFingerDistance = ev->argument;
                q->myFingerDistance = ev->argument;
                q->myStartFingerDistance = ev->argument;
            } else if (bRotate) {
                q->myLastRotationAngle = 0;
                q->myRotationAngle = 0;
                q->myStartAngle = 0;
            }
        } else {//in the middle of gesture

            //store new last values
            q->setLastCenterPoint(q->centerPoint());
            q->setLastRotationAngle(q->rotationAngle());
            q->setLastScaleFactor(q->scaleFactor());
            q->myLastFingerDistance = q->myFingerDistance;
            q->myLastRotationAngle = q->myRotationAngle;

            //update the current values
            if (bZoom)
                q->myFingerDistance = ev->argument;
            if (bRotate)
                q->myRotationAngle = ang;
            if(ev->gestureType == QNativeGestureEvent::GestureEnd){
                q->myFingerDistance = q->myLastFingerDistance;//the end-of-gesture event holds no finger separation data, hence we are using the last value.
                q->myRotationAngle = q->myLastRotationAngle;
            }
            if (bZoom)
                q->setScaleFactor(
                        (qreal)(q->myFingerDistance) / (qreal)(q->myLastFingerDistance)
                );
            if (bRotate)
                q->setRotationAngle(q->myRotationAngle);
            q->setCenterPoint(
                  QPointF(
                    qreal(ev->position.x()),
                    qreal(ev->position.y())
                  )
            );

            //detect changes
            QPinchGesture::ChangeFlags cf = 0;
            if ( q->scaleFactor() != 1.0 )
                cf |= QPinchGesture::ScaleFactorChanged;
            if (q->lastCenterPoint() != q->centerPoint())
                cf |= QPinchGesture::CenterPointChanged;
            if (q->rotationAngle() != q->lastRotationAngle())
                cf |= QPinchGesture::RotationAngleChanged;
            q->setChangeFlags(cf);

            //update totals
            q->setTotalChangeFlags (q->totalChangeFlags() | q->changeFlags());
            q->setTotalScaleFactor (q->totalScaleFactor() * q->scaleFactor());
            q->setTotalRotationAngle (q->rotationAngle());
        }
    }
    return result;
}

void WinNativeGestureRecognizerPinch::reset(QGesture* gesture)
{
  QGestureRecognizer::reset(gesture);//resets the state of the gesture, which is not write-accessible otherwise
  QPinchGestureN *q = static_cast<QPinchGestureN*>(gesture);
  q->myLastFingerDistance = 0;
  q->setTotalChangeFlags(0); q->setChangeFlags(0);

  q->setLastCenterPoint(QPointF());
  q->setCenterPoint(
        QPointF(
          0.0,
          0.0
        )
  );
  q->setStartCenterPoint(q->centerPoint());
  q->setTotalRotationAngle(0.0); q->setLastRotationAngle(0.0);  q->setRotationAngle(0.0);
  q->setTotalScaleFactor(1.0); q->setLastScaleFactor(1.0); q->setScaleFactor(1.0);
  q->myLastFingerDistance = 0;
  q->myFingerDistance = 0;
}

//function prototype for dymanic linking
typedef BOOL ( __stdcall * ptrSetGestureConfig) (
     HWND ,              // window for which configuration is specified
     DWORD ,             // reserved, must be 0
     UINT ,              // count of GESTURECONFIG structures
     PGESTURECONFIG ,    // array of GESTURECONFIG structures, dwIDs will be processed in the
                         // order specified and repeated occurrences will overwrite previous ones
     UINT );             // sizeof(GESTURECONFIG)

void WinNativeGestureRecognizerPinch::TuneWindowsGestures(QWidget* target)
{
    //modify windows-specific gesture options
#if WINVER >= _WIN32_WINNT_WIN7
    //dynamic linking - required to be able to run on windows pre-7
    HINSTANCE hinstLib = LoadLibraryA("user32.dll");
    if (hinstLib == 0)
        throw Base::RuntimeError("LoadLibrary(user32.dll) failed. Could not tune Windows gestures.");

    ptrSetGestureConfig dllSetGestureConfig = reinterpret_cast<ptrSetGestureConfig> (GetProcAddress(hinstLib,"SetGestureConfig"));
    if (dllSetGestureConfig == 0)
        throw Base::RuntimeError("DLL entry point for SetGestureConfig not found in user32.dll. Could not tune Windows gestures.");

    HWND w = target->winId();

    //fill in the options
    const UINT nCfg = 2;
    GESTURECONFIG cfgs[nCfg];
    ZeroMemory(&cfgs, sizeof(cfgs));
    cfgs[0].dwID = GID_PAN;
    cfgs[0].dwWant = GC_PAN;
    cfgs[0].dwBlock = GC_PAN_WITH_GUTTER;//disables stickiness to pure vertical/pure horizontal pans

    bool enableGestureTilt = !(App::GetApplication().GetParameterGroupByPath
        ("User parameter:BaseApp/Preferences/View")->GetBool("DisableTouchTilt",true));
    if(enableGestureTilt){
        cfgs[1].dwID = GID_ROTATE;
        cfgs[1].dwWant = GC_ROTATE;
    } else {
        cfgs[1].dwID = GID_ROTATE;
        cfgs[1].dwBlock = GC_ROTATE;
    }

    //set the options
    bool ret = dllSetGestureConfig(w, 0, nCfg, cfgs, sizeof(GESTURECONFIG));
    assert(ret);
    if(!ret){
        DWORD err = GetLastError();
        QString errMsg = QString::fromLatin1("Error in SetGestureConfig. GetLastError = %1").arg(err);
        throw Base::RuntimeError(errMsg.toLatin1());
    }
#endif
}

#endif //!defined(QT_NO_NATIVE_GESTURES)

#endif // GESTURE_MESS
<|endoftext|>


<commit_before>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2012 Scientific Computing and Imaging Institute,
   University of Utah.

   License for the specific language governing rights and limitations under
   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

#include <iostream>
#include <stdexcept>
#include <QtGui>
#include <boost/bind.hpp>
#include <Interface/Application/Connection.h>
#include <Interface/Application/Utility.h>
#include <Interface/Application/Port.h>
#include <Interface/Application/GuiLogger.h>
#include <Core/Logging/Log.h>
#include <Core/Utils/Exception.h>

using namespace SCIRun::Gui;

class EuclideanDrawStrategy : public ConnectionDrawStrategy
{
public:
  void draw(QGraphicsPathItem* item, const QPointF& from, const QPointF& to)
  {
    QPainterPath path;
    path.moveTo(from);
    path.lineTo(to);
    item->setPath(path);
  }
};

class CubicBezierDrawStrategy : public ConnectionDrawStrategy
{
public:
  void draw(QGraphicsPathItem* item, const QPointF& from, const QPointF& to)
  {
    QPainterPath path;
    QPointF start = from;

    path.moveTo(start);
    auto mid = (to - start) / 2 + start;

    QPointF qDir(-(to-start).y() / ((double)(to-start).x()) , 1);
    double qFactor = std::min(std::abs(100.0 / qDir.x()), 80.0);
    //TODO: scale down when start close to end. need a unit test at this point.
    //qFactor /= (end-start).manhattanDistance()

    auto q1 = item->mapToScene(mid + qFactor * qDir);
    auto q2 = item->mapToScene(mid - qFactor * qDir);
    path.cubicTo(q1, q2, to);
    item->setPath(path);
  }
};

class ManhattanDrawStrategy : public ConnectionDrawStrategy
{
public:
  void draw(QGraphicsPathItem* item, const QPointF& from, const QPointF& to)
  {
    QPainterPath path;
    path.moveTo(from);
    const int case1Threshold = 15;
    if (from.y() > to.y() - case1Threshold) // input above output
    {
      path.lineTo(from.x(), from.y() + case1Threshold);
      const int leftSideBuffer = 30;
      auto nextX = std::min(from.x() - leftSideBuffer, to.x() - leftSideBuffer); // TODO will be a function of port position
      path.lineTo(nextX, from.y() + case1Threshold); // TODO will be a function of port position
      path.lineTo(nextX, to.y() - case1Threshold);
      path.lineTo(to.x(), to.y() - case1Threshold);
      path.lineTo(to);
    }
    else  // output above input
    {
      auto midY = (from.y() + to.y()) / 2;
      path.lineTo(from.x(), midY);
      path.lineTo(to.x(), midY);
      path.lineTo(to);
    }
    item->setPath(path);
  }
};

namespace SCIRun
{
  namespace Gui
  {
    const QString deleteAction("Delete");
    const QString insertModuleAction("Insert Module->*");
    const QString disableEnableAction("Disable*");
    const QString editNotesAction("Edit Notes...");

    class ConnectionMenu : public QMenu
    {
    public:
      ConnectionMenu(QWidget* parent = 0) : QMenu(parent)
      {
        addAction(deleteAction);
        addAction(insertModuleAction)->setDisabled(true);
        addAction(disableEnableAction)->setDisabled(true);
        notesAction_ = addAction(editNotesAction);
      }
      QAction* notesAction_;
    };
  }
}

namespace SCIRun
{
  namespace Gui
  {
    class ConnectionLineNoteDisplayStrategy : public NoteDisplayStrategy
    {
    public:
      virtual QPointF relativeNotePosition(QGraphicsItem* item, const QGraphicsTextItem* note, NotePosition position) const
      {
        return QPointF(-100,-100);
      }
    };
  }
}

ConnectionLine::ConnectionLine(PortWidget* fromPort, PortWidget* toPort, const SCIRun::Dataflow::Networks::ConnectionId& id, ConnectionDrawStrategyPtr drawer)
  : HasNotes(id),
  NoteDisplayHelper(boost::make_shared<ConnectionLineNoteDisplayStrategy>()),
  fromPort_(fromPort), toPort_(toPort), id_(id), destroyed_(false), drawer_(drawer), menu_(0)
{
  if (fromPort_)
  {
    fromPort_->addConnection(this);
    fromPort_->turn_on_light();
  }
  else
    LOG_DEBUG("NULL FROM PORT: " << id_.id_ << std::endl);
  if (toPort_)
  {
    toPort_->addConnection(this);
    toPort_->turn_on_light();
  }
  else
    LOG_DEBUG("NULL TO PORT: " << id_.id_ << std::endl);

  if (fromPort_ && toPort_)
    setColor(fromPort_->color());

  setFlags(QGraphicsItem::ItemIsSelectable);
  //TODO: need dynamic zValue
  setZValue(1);
  setToolTip("Left - Highlight*\nDouble-Left - Menu");

  menu_ = new ConnectionMenu();
  connectNoteEditorToAction(menu_->notesAction_);
  connectUpdateNote(this);

  setPositionObject(boost::make_shared<MidpointPositioner>(fromPort_->getPositionObject(), toPort_->getPositionObject()));

  trackNodes();
  GuiLogger::Instance().log("Connection made.");
}

ConnectionLine::~ConnectionLine()
{
  if (!destroyed_)
    destroy();
}

void ConnectionLine::destroy()
{
  delete menu_;
  if (fromPort_ && toPort_)
  {
    fromPort_->removeConnection(this);
    fromPort_->turn_off_light();
    toPort_->removeConnection(this);
    toPort_->turn_off_light();
  }
  drawer_.reset();
  Q_EMIT deleted(id_);
  GuiLogger::Instance().log("Connection deleted.");
  destroyed_ = true;
}

void ConnectionLine::setColor(const QColor& color)
{
  setPen(QPen(color, 5.0));
}

QColor ConnectionLine::color() const
{
  return pen().color();
}

void ConnectionLine::trackNodes()
{
  if (fromPort_ && toPort_)
  {
    drawer_->draw(this, fromPort_->position(), toPort_->position());
  }
  else
    BOOST_THROW_EXCEPTION(InvalidConnection() << Core::ErrorMessage("no from/to set for Connection: " + id_.id_));
}

void ConnectionLine::setDrawStrategy(ConnectionDrawStrategyPtr cds)
{
  if (!destroyed_)
  {
    drawer_ = cds;
    trackNodes();
  }
}

void ConnectionLine::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
  auto action = menu_->exec(event->screenPos());
  if (action && action->text() == deleteAction)
  {
    scene()->removeItem(this);
    destroy();
  }
  else if (action && action->text() == editNotesAction)
  {
    //std::cout << "POP UP NOTES EDITOR. Done. TODO: display note." << std::endl;
  }
}

void ConnectionLine::setNoteGraphicsContext()
{
  scene_ = scene();
  item_ = this;
  positioner_ = getPositionObject();
}

void ConnectionLine::updateNote(const Note& note)
{
  updateNoteImpl(note);
}

ConnectionInProgressStraight::ConnectionInProgressStraight(PortWidget* port, ConnectionDrawStrategyPtr drawer)
  : ConnectionInProgressGraphicsItem<QGraphicsLineItem>(port, drawer)
{
}

void ConnectionInProgressStraight::update(const QPointF& end)
{
  //TODO: use strategy object. probably need to improve first parameter: templatized? or just change this case to use QGraphicsPathItem directly
  //drawStrategy_->draw(this, fromPort_->position(), end);

  setLine(QLineF(fromPort_->position(), end));
}

ConnectionInProgressCurved::ConnectionInProgressCurved(PortWidget* port, ConnectionDrawStrategyPtr drawer)
  : ConnectionInProgressGraphicsItem<QGraphicsPathItem>(port, drawer)
{
}

void ConnectionInProgressCurved::update(const QPointF& end)
{
  drawStrategy_->draw(this, fromPort_->position(), end);
}

ConnectionInProgressManhattan::ConnectionInProgressManhattan(PortWidget* port, ConnectionDrawStrategyPtr drawer)
  : ConnectionInProgressGraphicsItem<QGraphicsPathItem>(port, drawer)
{
}

void ConnectionInProgressManhattan::update(const QPointF& end)
{
  if (fromPort_->isInput())
    drawStrategy_->draw(this, end, fromPort_->position());
  else
    drawStrategy_->draw(this, fromPort_->position(), end);
}

MidpointPositioner::MidpointPositioner(PositionProviderPtr p1, PositionProviderPtr p2) : p1_(p1), p2_(p2)
{
  ENSURE_NOT_NULL(p1, "port1");
  ENSURE_NOT_NULL(p2, "port2");
}

QPointF MidpointPositioner::currentPosition() const
{
  return (p1_->currentPosition() + p2_->currentPosition()) / 2;
}

ConnectionFactory::ConnectionFactory(QGraphicsScene* scene) : currentType_(EUCLIDEAN), scene_(scene),
  euclidean_(new EuclideanDrawStrategy),
  cubic_(new CubicBezierDrawStrategy),
  manhattan_(new ManhattanDrawStrategy)
{}

ConnectionInProgress* ConnectionFactory::makeConnectionInProgress(PortWidget* port) const
{
  switch (currentType_)
  {
    case EUCLIDEAN:
    {
      auto c = new ConnectionInProgressStraight(port, getCurrentDrawer());
      activate(c);
      return c;
    }
    case CUBIC:
    {
      auto c = new ConnectionInProgressCurved(port, getCurrentDrawer());
      activate(c);
      return c;
    }
    case MANHATTAN:
    {
      auto c = new ConnectionInProgressManhattan(port, getCurrentDrawer());
      activate(c);
      return c;
    }
    default:
      std::cerr << "Unknown connection type." << std::endl;
      return 0;
  }
}

void ConnectionFactory::activate(QGraphicsItem* item) const
{
  if (item)
  {
    if (scene_)
      scene_->addItem(item);
    item->setVisible(true);
  }
}

void ConnectionFactory::setType(ConnectionDrawType type)
{
  if (type != currentType_)
  {
    currentType_ = type;
    Q_EMIT typeChanged(getCurrentDrawer());
  }
}

ConnectionDrawType ConnectionFactory::getType() const
{
  return currentType_;
}

ConnectionDrawStrategyPtr ConnectionFactory::getCurrentDrawer() const
{
  switch (currentType_)
  {
  case EUCLIDEAN:
    return euclidean_;
  case CUBIC:
    return cubic_;
  case MANHATTAN:
    return manhattan_;
  default:
    std::cerr << "Unknown connection type." << std::endl;
    return ConnectionDrawStrategyPtr();
  }
}

ConnectionLine* ConnectionFactory::makeFinishedConnection(PortWidget* fromPort, PortWidget* toPort, const SCIRun::Dataflow::Networks::ConnectionId& id) const
{
  auto c = new ConnectionLine(fromPort, toPort, id, getCurrentDrawer());
  activate(c);
  connect(this, SIGNAL(typeChanged(ConnectionDrawStrategyPtr)), c, SLOT(setDrawStrategy(ConnectionDrawStrategyPtr)));
  return c;
}
<commit_msg>Connection note position updated, but needs better positioning<commit_after>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2012 Scientific Computing and Imaging Institute,
   University of Utah.

   License for the specific language governing rights and limitations under
   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

#include <iostream>
#include <stdexcept>
#include <QtGui>
#include <boost/bind.hpp>
#include <Interface/Application/Connection.h>
#include <Interface/Application/Utility.h>
#include <Interface/Application/Port.h>
#include <Interface/Application/GuiLogger.h>
#include <Core/Logging/Log.h>
#include <Core/Utils/Exception.h>

using namespace SCIRun::Gui;

class EuclideanDrawStrategy : public ConnectionDrawStrategy
{
public:
  void draw(QGraphicsPathItem* item, const QPointF& from, const QPointF& to)
  {
    QPainterPath path;
    path.moveTo(from);
    path.lineTo(to);
    item->setPath(path);
  }
};

class CubicBezierDrawStrategy : public ConnectionDrawStrategy
{
public:
  void draw(QGraphicsPathItem* item, const QPointF& from, const QPointF& to)
  {
    QPainterPath path;
    QPointF start = from;

    path.moveTo(start);
    auto mid = (to - start) / 2 + start;

    QPointF qDir(-(to-start).y() / ((double)(to-start).x()) , 1);
    double qFactor = std::min(std::abs(100.0 / qDir.x()), 80.0);
    //TODO: scale down when start close to end. need a unit test at this point.
    //qFactor /= (end-start).manhattanDistance()

    auto q1 = item->mapToScene(mid + qFactor * qDir);
    auto q2 = item->mapToScene(mid - qFactor * qDir);
    path.cubicTo(q1, q2, to);
    item->setPath(path);
  }
};

class ManhattanDrawStrategy : public ConnectionDrawStrategy
{
public:
  void draw(QGraphicsPathItem* item, const QPointF& from, const QPointF& to)
  {
    QPainterPath path;
    path.moveTo(from);
    const int case1Threshold = 15;
    if (from.y() > to.y() - case1Threshold) // input above output
    {
      path.lineTo(from.x(), from.y() + case1Threshold);
      const int leftSideBuffer = 30;
      auto nextX = std::min(from.x() - leftSideBuffer, to.x() - leftSideBuffer); // TODO will be a function of port position
      path.lineTo(nextX, from.y() + case1Threshold); // TODO will be a function of port position
      path.lineTo(nextX, to.y() - case1Threshold);
      path.lineTo(to.x(), to.y() - case1Threshold);
      path.lineTo(to);
    }
    else  // output above input
    {
      auto midY = (from.y() + to.y()) / 2;
      path.lineTo(from.x(), midY);
      path.lineTo(to.x(), midY);
      path.lineTo(to);
    }
    item->setPath(path);
  }
};

namespace SCIRun
{
  namespace Gui
  {
    const QString deleteAction("Delete");
    const QString insertModuleAction("Insert Module->*");
    const QString disableEnableAction("Disable*");
    const QString editNotesAction("Edit Notes...");

    class ConnectionMenu : public QMenu
    {
    public:
      ConnectionMenu(QWidget* parent = 0) : QMenu(parent)
      {
        addAction(deleteAction);
        addAction(insertModuleAction)->setDisabled(true);
        addAction(disableEnableAction)->setDisabled(true);
        notesAction_ = addAction(editNotesAction);
      }
      QAction* notesAction_;
    };
  }
}

namespace SCIRun
{
  namespace Gui
  {
    class ConnectionLineNoteDisplayStrategy : public NoteDisplayStrategy
    {
    public:
      virtual QPointF relativeNotePosition(QGraphicsItem* item, const QGraphicsTextItem* note, NotePosition position) const
      {
        return QPointF(-100,-100);
      }
    };
  }
}

ConnectionLine::ConnectionLine(PortWidget* fromPort, PortWidget* toPort, const SCIRun::Dataflow::Networks::ConnectionId& id, ConnectionDrawStrategyPtr drawer)
  : HasNotes(id),
  NoteDisplayHelper(boost::make_shared<ConnectionLineNoteDisplayStrategy>()),
  fromPort_(fromPort), toPort_(toPort), id_(id), destroyed_(false), drawer_(drawer), menu_(0)
{
  if (fromPort_)
  {
    fromPort_->addConnection(this);
    fromPort_->turn_on_light();
  }
  else
    LOG_DEBUG("NULL FROM PORT: " << id_.id_ << std::endl);
  if (toPort_)
  {
    toPort_->addConnection(this);
    toPort_->turn_on_light();
  }
  else
    LOG_DEBUG("NULL TO PORT: " << id_.id_ << std::endl);

  if (fromPort_ && toPort_)
    setColor(fromPort_->color());

  setFlags(QGraphicsItem::ItemIsSelectable);
  //TODO: need dynamic zValue
  setZValue(1);
  setToolTip("Left - Highlight*\nDouble-Left - Menu");

  menu_ = new ConnectionMenu();
  connectNoteEditorToAction(menu_->notesAction_);
  connectUpdateNote(this);

  setPositionObject(boost::make_shared<MidpointPositioner>(fromPort_->getPositionObject(), toPort_->getPositionObject()));

  trackNodes();
  GuiLogger::Instance().log("Connection made.");
}

ConnectionLine::~ConnectionLine()
{
  if (!destroyed_)
    destroy();
}

void ConnectionLine::destroy()
{
  delete menu_;
  if (fromPort_ && toPort_)
  {
    fromPort_->removeConnection(this);
    fromPort_->turn_off_light();
    toPort_->removeConnection(this);
    toPort_->turn_off_light();
  }
  drawer_.reset();
  Q_EMIT deleted(id_);
  GuiLogger::Instance().log("Connection deleted.");
  destroyed_ = true;
}

void ConnectionLine::setColor(const QColor& color)
{
  setPen(QPen(color, 5.0));
}

QColor ConnectionLine::color() const
{
  return pen().color();
}

void ConnectionLine::trackNodes()
{
  if (fromPort_ && toPort_)
  {
    drawer_->draw(this, fromPort_->position(), toPort_->position());
    updateNotePosition();
  }
  else
    BOOST_THROW_EXCEPTION(InvalidConnection() << Core::ErrorMessage("no from/to set for Connection: " + id_.id_));
}

void ConnectionLine::setDrawStrategy(ConnectionDrawStrategyPtr cds)
{
  if (!destroyed_)
  {
    drawer_ = cds;
    trackNodes();
  }
}

void ConnectionLine::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
  auto action = menu_->exec(event->screenPos());
  if (action && action->text() == deleteAction)
  {
    scene()->removeItem(this);
    destroy();
  }
  else if (action && action->text() == editNotesAction)
  {
    //std::cout << "POP UP NOTES EDITOR. Done. TODO: display note." << std::endl;
  }
}

void ConnectionLine::setNoteGraphicsContext()
{
  scene_ = scene();
  item_ = this;
  positioner_ = getPositionObject();
}

void ConnectionLine::updateNote(const Note& note)
{
  updateNoteImpl(note);
}

ConnectionInProgressStraight::ConnectionInProgressStraight(PortWidget* port, ConnectionDrawStrategyPtr drawer)
  : ConnectionInProgressGraphicsItem<QGraphicsLineItem>(port, drawer)
{
}

void ConnectionInProgressStraight::update(const QPointF& end)
{
  //TODO: use strategy object. probably need to improve first parameter: templatized? or just change this case to use QGraphicsPathItem directly
  //drawStrategy_->draw(this, fromPort_->position(), end);

  setLine(QLineF(fromPort_->position(), end));
}

ConnectionInProgressCurved::ConnectionInProgressCurved(PortWidget* port, ConnectionDrawStrategyPtr drawer)
  : ConnectionInProgressGraphicsItem<QGraphicsPathItem>(port, drawer)
{
}

void ConnectionInProgressCurved::update(const QPointF& end)
{
  drawStrategy_->draw(this, fromPort_->position(), end);
}

ConnectionInProgressManhattan::ConnectionInProgressManhattan(PortWidget* port, ConnectionDrawStrategyPtr drawer)
  : ConnectionInProgressGraphicsItem<QGraphicsPathItem>(port, drawer)
{
}

void ConnectionInProgressManhattan::update(const QPointF& end)
{
  if (fromPort_->isInput())
    drawStrategy_->draw(this, end, fromPort_->position());
  else
    drawStrategy_->draw(this, fromPort_->position(), end);
}

MidpointPositioner::MidpointPositioner(PositionProviderPtr p1, PositionProviderPtr p2) : p1_(p1), p2_(p2)
{
  ENSURE_NOT_NULL(p1, "port1");
  ENSURE_NOT_NULL(p2, "port2");
}

QPointF MidpointPositioner::currentPosition() const
{
  return (p1_->currentPosition() + p2_->currentPosition()) / 2;
}

ConnectionFactory::ConnectionFactory(QGraphicsScene* scene) : currentType_(EUCLIDEAN), scene_(scene),
  euclidean_(new EuclideanDrawStrategy),
  cubic_(new CubicBezierDrawStrategy),
  manhattan_(new ManhattanDrawStrategy)
{}

ConnectionInProgress* ConnectionFactory::makeConnectionInProgress(PortWidget* port) const
{
  switch (currentType_)
  {
    case EUCLIDEAN:
    {
      auto c = new ConnectionInProgressStraight(port, getCurrentDrawer());
      activate(c);
      return c;
    }
    case CUBIC:
    {
      auto c = new ConnectionInProgressCurved(port, getCurrentDrawer());
      activate(c);
      return c;
    }
    case MANHATTAN:
    {
      auto c = new ConnectionInProgressManhattan(port, getCurrentDrawer());
      activate(c);
      return c;
    }
    default:
      std::cerr << "Unknown connection type." << std::endl;
      return 0;
  }
}

void ConnectionFactory::activate(QGraphicsItem* item) const
{
  if (item)
  {
    if (scene_)
      scene_->addItem(item);
    item->setVisible(true);
  }
}

void ConnectionFactory::setType(ConnectionDrawType type)
{
  if (type != currentType_)
  {
    currentType_ = type;
    Q_EMIT typeChanged(getCurrentDrawer());
  }
}

ConnectionDrawType ConnectionFactory::getType() const
{
  return currentType_;
}

ConnectionDrawStrategyPtr ConnectionFactory::getCurrentDrawer() const
{
  switch (currentType_)
  {
  case EUCLIDEAN:
    return euclidean_;
  case CUBIC:
    return cubic_;
  case MANHATTAN:
    return manhattan_;
  default:
    std::cerr << "Unknown connection type." << std::endl;
    return ConnectionDrawStrategyPtr();
  }
}

ConnectionLine* ConnectionFactory::makeFinishedConnection(PortWidget* fromPort, PortWidget* toPort, const SCIRun::Dataflow::Networks::ConnectionId& id) const
{
  auto c = new ConnectionLine(fromPort, toPort, id, getCurrentDrawer());
  activate(c);
  connect(this, SIGNAL(typeChanged(ConnectionDrawStrategyPtr)), c, SLOT(setDrawStrategy(ConnectionDrawStrategyPtr)));
  return c;
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////
//
// DAGON - An Adventure Game Engine
// Copyright (c) 2011 Senscape s.r.l.
// All rights reserved.
//
// NOTICE: Senscape permits you to use, modify, and
// distribute this file in accordance with the terms of the
// license agreement accompanying it.
//
////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////

#include "DGAudio.h"

using namespace std;

////////////////////////////////////////////////////////////
// Implementation - Constructor
////////////////////////////////////////////////////////////

DGAudio::DGAudio() {
    config = &DGConfig::getInstance();
    log = &DGLog::getInstance();

    _oggCallbacks.read_func = _oggRead;
	_oggCallbacks.seek_func = _oggSeek;
	_oggCallbacks.close_func = _oggClose;
	_oggCallbacks.tell_func = _oggTell;

    _isLoaded = false;

    // For convenience, this always defaults to false
    _isLoopable = false;
    _isMatched = false;
    _state = DGAudioInitial;

    this->setType(DGObjectAudio);
}

////////////////////////////////////////////////////////////
// Implementation - Destructor
////////////////////////////////////////////////////////////

DGAudio::~DGAudio() {
    // Force an unload
    this->unload();
}

////////////////////////////////////////////////////////////
// Implementation - Checks
////////////////////////////////////////////////////////////

bool DGAudio::isLoaded() {
    return _isLoaded;
}

bool DGAudio::isLoopable() {
    return _isLoopable;
}

////////////////////////////////////////////////////////////
// Implementation - Gets
////////////////////////////////////////////////////////////

double DGAudio::cursor() {
    return ov_time_tell(&_oggStream);
}

int DGAudio::state() {
    return _state;
}

////////////////////////////////////////////////////////////
// Implementation - Sets
////////////////////////////////////////////////////////////

void DGAudio::setLoopable(bool loopable) {
    _isLoopable = loopable;
}

void DGAudio::setPosition(unsigned int onFace) {
    switch (onFace) {
        case DGNorth:
            alSource3f(_alSource, AL_POSITION, 0.0, 0.0, -1.0);
            break;
        case DGEast:
            alSource3f(_alSource, AL_POSITION, 1.0, 0.0, 0.0);
            break;
        case DGSouth:
            alSource3f(_alSource, AL_POSITION, 0.0, 0.0, 1.0);
            break;
        case DGWest:
            alSource3f(_alSource, AL_POSITION, -1.0, 0.0, 0.0);
            break;
        case DGUp:
            alSource3f(_alSource, AL_POSITION, 0.0, 1.0, 0.0);
            break;
        case DGDown:
            alSource3f(_alSource, AL_POSITION, 0.0, -1.0, 0.0);
            break;
    }

    _verifyError("position");
}

void DGAudio::setResource(const char* fromFileName) {
    strncpy(_resource.name, fromFileName, DGMaxFileLength);
}

////////////////////////////////////////////////////////////
// Implementation - State changes
////////////////////////////////////////////////////////////

void DGAudio::load() {
    if (!_isLoaded) {
        FILE* fh;

        // FIXME: This object shouldn't reference DGConfig, let the manager do it
        const char* fileToLoad = _randomizeFile(_resource.name);
        fh = fopen(config->path(DGPathRes, fileToLoad, DGObjectAudio), "rb");

        if (fh != NULL) {
            fseek(fh, 0, SEEK_END);
            _resource.dataSize = ftell(fh);
            fseek(fh, 0, SEEK_SET);
            _resource.data = (char*)malloc(_resource.dataSize);
            fread(_resource.data, _resource.dataSize, 1, fh);
            _resource.dataRead = 0;

            if (ov_open_callbacks(this, &_oggStream, NULL, 0, _oggCallbacks) < 0) {
                log->error(DGModAudio, "%s", DGMsg270007);
                return;
            }

            // Get file info
            vorbis_info* info = ov_info(&_oggStream, -1);

            _channels = info->channels;
            _rate = (ALsizei)info->rate;

            if (_channels == 1) _alFormat = AL_FORMAT_MONO16;
            else if (_channels == 2 ) _alFormat = AL_FORMAT_STEREO16;
            else {
                // Invalid number of channels
                log->error(DGModAudio, "%s: %s", DGMsg270006, fileToLoad);
                return;
            }

            // We no longer require the file handle
            fclose(fh);

            alGenBuffers(DGAudioNumberOfBuffers, _alBuffers);
            alGenSources(1, &_alSource);

			for (int i = 0; i < DGAudioNumberOfBuffers; i++) {
				if (!_stream(&_alBuffers[i])) {
					_verifyError("prebuffer");

					return;
				}
			}

			alSourceQueueBuffers(_alSource, DGAudioNumberOfBuffers, _alBuffers);

            if (config->mute || this->fadeLevel() < 0.0f) {
                alSourcef(_alSource, AL_GAIN, 0.0f);
            }
            else {
                alSourcef(_alSource, AL_GAIN, this->fadeLevel());
            }

            alSource3f(_alSource, AL_POSITION,        0.0, 0.0, 0.0);
            alSource3f(_alSource, AL_VELOCITY,        0.0, 0.0, 0.0);
            alSource3f(_alSource, AL_DIRECTION,       0.0, 0.0, 0.0);

            _verifyError("load");

            _isLoaded = true;
        }
        else log->error(DGModAudio, "%s: %s", DGMsg270005, fileToLoad);
    }
}

void DGAudio::match(DGAudio* matchedAudio) {
    _matchedAudio = matchedAudio;
    _isMatched = true;
}

void DGAudio::play() {
    if (_isLoaded && (_state != DGAudioPlaying)) {
        if (_isMatched)
            ov_time_seek(&_oggStream, _matchedAudio->cursor());

        alSourcePlay(_alSource);
        _state = DGAudioPlaying;

        _verifyError("play");
    }
}

void DGAudio::pause() {
    if (_state == DGAudioPlaying) {
        alSourceStop(_alSource);

        _state = DGAudioPaused;

        _verifyError("pause");
    }
}

void DGAudio::stop() {
    if ((_state == DGAudioPlaying) || (_state == DGAudioPaused)) {
        alSourceStop(_alSource);

        ov_raw_seek(&_oggStream, 0);
        _state = DGAudioStopped;

        _verifyError("stop");
    }
}

void DGAudio::unload() {
    if (_isLoaded) {
        if (_state == DGAudioPlaying)
            this->stop();

		_emptyBuffers();

		alDeleteSources(1, &_alSource);
		alDeleteBuffers(DGAudioNumberOfBuffers, _alBuffers);
        ov_clear(&_oggStream);
        free(_resource.data);

        _isLoaded = false;

        _verifyError("unload");
    }
}

void DGAudio::update() {
    if (_state == DGAudioPlaying) {
        int processed;

        alGetSourcei(_alSource, AL_BUFFERS_PROCESSED, &processed);

        while (processed--) {
            ALuint buffer;

            alSourceUnqueueBuffers(_alSource, 1, &buffer);
            _stream(&buffer);
            alSourceQueueBuffers(_alSource, 1, &buffer);
        }

        // Run fade operations
        // TODO: Better change the name of the DGObject function
        this->updateFade();

        // FIXME: Not very elegant as we're doing this every time
        if (config->mute) {
            alSourcef(_alSource, AL_GAIN, 0.0f);
        }
        else {
            // Finally check the current volume. If it's zero, let the manager know
            // that we're done with this audio
            if (this->fadeLevel() > 0.0f)
                alSourcef(_alSource, AL_GAIN, this->fadeLevel());
            else
                this->pause();
        }
    }
}

////////////////////////////////////////////////////////////
// Implementation - Private methods
////////////////////////////////////////////////////////////

void DGAudio::_emptyBuffers() {
    ALint state;
    alGetSourcei(_alSource, AL_SOURCE_STATE, &state);

	if (state != AL_PLAYING) {
        int queued;

        alGetSourcei(_alSource, AL_BUFFERS_PROCESSED, &queued);

        while (queued--) {
            ALuint buffer;
            alSourceUnqueueBuffers(_alSource, 1, &buffer);
			_verifyError("unqueue");
        }
    }
}

const char* DGAudio::_randomizeFile(const char* fileName) {
    if (strstr(fileName, ".ogg")) { // Was extension specified?
        return fileName; // Return as-is
    }
    else { // Randomize
        static char fileToLoad[DGMaxFileLength];
        int index = (rand() % 6); // Allow to configure

        snprintf(fileToLoad, DGMaxFileLength, "%s%0" in_between(DGFileSeqDigits) "d.%s", fileName,
                 index + DGFileSeqStart, "ogg");

        return fileToLoad;
    }
}

bool DGAudio::_stream(ALuint* buffer) {
    // This is a failsafe; if this is true, we won't attempt
    // to stream anymore
    static bool _hasStreamingError = false;

    if (!_hasStreamingError) {
        char data[DGAudioBufferSize];
        int size = 0;
        int section;
        long result;

        while (size < DGAudioBufferSize) {
            result = ov_read(&_oggStream, data + size, DGAudioBufferSize - size, 0, 2, 1, &section);

            if (result > 0)
                size += result;
            else if (result == 0) {
                // EOF
                if (_isLoopable)
                    ov_raw_seek(&_oggStream, 0);
                else
                    this->stop();

                return false;
            }
            else if (result == OV_HOLE) {
                // May return OV_HOLE after we rewind the stream,
                // so we just re-loop
                continue;
            }
            else if (result < 0) {
                // Error
                log->error(DGModAudio, "%s: %s", DGMsg270004, _resource.name);
                _hasStreamingError = true;

                return false;
            }
        }

        alBufferData(*buffer, _alFormat, data, size, _rate);

        return true;
    }
    else return false;
}

ALboolean DGAudio::_verifyError(const char* operation) {
   	ALint error = alGetError();

	if (error != AL_NO_ERROR) {
		log->error(DGModAudio, "%s: %s: %s (%d)", DGMsg270003, _resource.name, operation, error);

		return AL_FALSE;
	}

	return AL_TRUE;
}

// And now... The Vorbisfile callbacks

size_t DGAudio::_oggRead(void* ptr, size_t size, size_t nmemb, void* datasource) {
    DGAudio* audio = (DGAudio*)datasource;
    size_t nSize = size * nmemb;

    if ((audio->_resource.dataRead + nSize) > audio->_resource.dataSize)
        nSize = audio->_resource.dataSize - audio->_resource.dataRead;

    memcpy(ptr, audio->_resource.data + audio->_resource.dataRead, nSize);
    audio->_resource.dataRead += nSize;

	return nSize;
}

int DGAudio::_oggSeek(void* datasource, ogg_int64_t offset, int whence) {
    DGAudio* audio = (DGAudio*)datasource;

	switch (whence) {
        case SEEK_SET:
            audio->_resource.dataRead = (size_t)offset;
            break;
        case SEEK_CUR:
            audio->_resource.dataRead += (size_t)offset;
            break;
        case SEEK_END:
            audio->_resource.dataRead = (size_t)(audio->_resource.dataSize - offset);
            break;
	}

	if (audio->_resource.dataRead > audio->_resource.dataSize) {
		audio->_resource.dataRead = 0;
		return -1;
	}

	return 0;
}

int DGAudio::_oggClose(void* datasource) {
    DGAudio* audio = (DGAudio*)datasource;
	audio->_resource.dataRead = 0;

	return 0;
}

long DGAudio::_oggTell(void* datasource) {
    DGAudio* audio = (DGAudio*)datasource;
	return (long)audio->_resource.dataRead;
}
<commit_msg>Cleaned up code.<commit_after>////////////////////////////////////////////////////////////
//
// DAGON - An Adventure Game Engine
// Copyright (c) 2011 Senscape s.r.l.
// All rights reserved.
//
// NOTICE: Senscape permits you to use, modify, and
// distribute this file in accordance with the terms of the
// license agreement accompanying it.
//
////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////

#include "DGAudio.h"

using namespace std;

////////////////////////////////////////////////////////////
// Implementation - Constructor
////////////////////////////////////////////////////////////

DGAudio::DGAudio() {
    config = &DGConfig::getInstance();
    log = &DGLog::getInstance();

    _oggCallbacks.read_func = _oggRead;
	_oggCallbacks.seek_func = _oggSeek;
	_oggCallbacks.close_func = _oggClose;
	_oggCallbacks.tell_func = _oggTell;

    _isLoaded = false;

    // For convenience, this always defaults to false
    _isLoopable = false;
    _isMatched = false;
    _state = DGAudioInitial;

    this->setType(DGObjectAudio);
}

////////////////////////////////////////////////////////////
// Implementation - Destructor
////////////////////////////////////////////////////////////

DGAudio::~DGAudio() {
    // Force an unload
    this->unload();
}

////////////////////////////////////////////////////////////
// Implementation - Checks
////////////////////////////////////////////////////////////

bool DGAudio::isLoaded() {
    return _isLoaded;
}

bool DGAudio::isLoopable() {
    return _isLoopable;
}

////////////////////////////////////////////////////////////
// Implementation - Gets
////////////////////////////////////////////////////////////

double DGAudio::cursor() {
    return ov_time_tell(&_oggStream);
}

int DGAudio::state() {
    return _state;
}

////////////////////////////////////////////////////////////
// Implementation - Sets
////////////////////////////////////////////////////////////

void DGAudio::setLoopable(bool loopable) {
    _isLoopable = loopable;
}

void DGAudio::setPosition(unsigned int onFace) {
    switch (onFace) {
        case DGNorth:
            alSource3f(_alSource, AL_POSITION, 0.0, 0.0, -1.0);
            break;
        case DGEast:
            alSource3f(_alSource, AL_POSITION, 1.0, 0.0, 0.0);
            break;
        case DGSouth:
            alSource3f(_alSource, AL_POSITION, 0.0, 0.0, 1.0);
            break;
        case DGWest:
            alSource3f(_alSource, AL_POSITION, -1.0, 0.0, 0.0);
            break;
        case DGUp:
            alSource3f(_alSource, AL_POSITION, 0.0, 1.0, 0.0);
            break;
        case DGDown:
            alSource3f(_alSource, AL_POSITION, 0.0, -1.0, 0.0);
            break;
    }

    _verifyError("position");
}

void DGAudio::setResource(const char* fromFileName) {
    strncpy(_resource.name, fromFileName, DGMaxFileLength);
}

////////////////////////////////////////////////////////////
// Implementation - State changes
////////////////////////////////////////////////////////////

void DGAudio::load() {
    if (!_isLoaded) {
        FILE* fh;

        // FIXME: This object shouldn't reference DGConfig, let the manager do it
        const char* fileToLoad = _randomizeFile(_resource.name);
        fh = fopen(config->path(DGPathRes, fileToLoad, DGObjectAudio), "rb");

        if (fh != NULL) {
            fseek(fh, 0, SEEK_END);
            _resource.dataSize = ftell(fh);
            fseek(fh, 0, SEEK_SET);
            _resource.data = (char*)malloc(_resource.dataSize);
            fread(_resource.data, _resource.dataSize, 1, fh);
            _resource.dataRead = 0;

            if (ov_open_callbacks(this, &_oggStream, NULL, 0, _oggCallbacks) < 0) {
                log->error(DGModAudio, "%s", DGMsg270007);
                return;
            }

            // Get file info
            vorbis_info* info = ov_info(&_oggStream, -1);

            _channels = info->channels;
            _rate = (ALsizei)info->rate;

            if (_channels == 1) _alFormat = AL_FORMAT_MONO16;
            else if (_channels == 2 ) _alFormat = AL_FORMAT_STEREO16;
            else {
                // Invalid number of channels
                log->error(DGModAudio, "%s: %s", DGMsg270006, fileToLoad);
                return;
            }

            // We no longer require the file handle
            fclose(fh);

            alGenBuffers(DGAudioNumberOfBuffers, _alBuffers);
            alGenSources(1, &_alSource);

			for (int i = 0; i < DGAudioNumberOfBuffers; i++) {
				if (!_stream(&_alBuffers[i])) {
					_verifyError("prebuffer");

					return;
				}
			}

			alSourceQueueBuffers(_alSource, DGAudioNumberOfBuffers, _alBuffers);

            if (config->mute || this->fadeLevel() < 0.0f) {
                alSourcef(_alSource, AL_GAIN, 0.0f);
            }
            else {
                alSourcef(_alSource, AL_GAIN, this->fadeLevel());
            }

            alSource3f(_alSource, AL_POSITION,        0.0, 0.0, 0.0);
            alSource3f(_alSource, AL_VELOCITY,        0.0, 0.0, 0.0);
            alSource3f(_alSource, AL_DIRECTION,       0.0, 0.0, 0.0);

            _verifyError("load");

            _isLoaded = true;
        }
        else log->error(DGModAudio, "%s: %s", DGMsg270005, fileToLoad);
    }
}

void DGAudio::match(DGAudio* matchedAudio) {
    _matchedAudio = matchedAudio;
    _isMatched = true;
}

void DGAudio::play() {
    if (_isLoaded && (_state != DGAudioPlaying)) {
        if (_isMatched)
            ov_time_seek(&_oggStream, _matchedAudio->cursor());

        alSourcePlay(_alSource);
        _state = DGAudioPlaying;

        _verifyError("play");
    }
}

void DGAudio::pause() {
    if (_state == DGAudioPlaying) {
        alSourceStop(_alSource);

        _state = DGAudioPaused;

        _verifyError("pause");
    }
}

void DGAudio::stop() {
    if ((_state == DGAudioPlaying) || (_state == DGAudioPaused)) {
        alSourceStop(_alSource);

        ov_raw_seek(&_oggStream, 0);
        _state = DGAudioStopped;

        _verifyError("stop");
    }
}

void DGAudio::unload() {
    if (_isLoaded) {
        if (_state == DGAudioPlaying)
            this->stop();

		_emptyBuffers();

		alDeleteSources(1, &_alSource);
		alDeleteBuffers(DGAudioNumberOfBuffers, _alBuffers);
        ov_clear(&_oggStream);
        free(_resource.data);

        _isLoaded = false;

        _verifyError("unload");
    }
}

void DGAudio::update() {
    if (_state == DGAudioPlaying) {
        int processed;

        alGetSourcei(_alSource, AL_BUFFERS_PROCESSED, &processed);

        while (processed--) {
            ALuint buffer;

            alSourceUnqueueBuffers(_alSource, 1, &buffer);
            _stream(&buffer);
            alSourceQueueBuffers(_alSource, 1, &buffer);
        }

        // Run fade operations
        // TODO: Better change the name of the DGObject function
        this->updateFade();

        // FIXME: Not very elegant as we're doing this every time
        if (config->mute) {
            alSourcef(_alSource, AL_GAIN, 0.0f);
        }
        else {
            // Finally check the current volume. If it's zero, let the manager know
            // that we're done with this audio
            if (this->fadeLevel() > 0.0f)
                alSourcef(_alSource, AL_GAIN, this->fadeLevel());
            else
                this->pause();
        }
    }
}

////////////////////////////////////////////////////////////
// Implementation - Private methods
////////////////////////////////////////////////////////////

void DGAudio::_emptyBuffers() {
    ALint state;
    alGetSourcei(_alSource, AL_SOURCE_STATE, &state);

	if (state != AL_PLAYING) {
        int queued;

        alGetSourcei(_alSource, AL_BUFFERS_PROCESSED, &queued);

        while (queued--) {
            ALuint buffer;
            alSourceUnqueueBuffers(_alSource, 1, &buffer);
			_verifyError("unqueue");
        }
    }
}

const char* DGAudio::_randomizeFile(const char* fileName) {
    if (strstr(fileName, ".ogg")) { // Was extension specified?
        return fileName; // Return as-is
    }
    else { // Randomize
        static char fileToLoad[DGMaxFileLength];
        int index = (rand() % 6); // Allow to configure

        snprintf(fileToLoad, DGMaxFileLength, "%s%0" in_between(DGFileSeqDigits) "d.%s", fileName,
                 index + DGFileSeqStart, "ogg");

        return fileToLoad;
    }
}

bool DGAudio::_stream(ALuint* buffer) {
    // This is a failsafe; if this is true, we won't attempt
    // to stream anymore
    static bool _hasStreamingError = false;

    if (!_hasStreamingError) {
        char data[DGAudioBufferSize];
        int size = 0;
        int section;
        long result;

        while (size < DGAudioBufferSize) {
            result = ov_read(&_oggStream, data + size, DGAudioBufferSize - size, 0, 2, 1, &section);

            if (result > 0)
                size += result;
            else if (result == 0) {
                // EOF
                if (_isLoopable)
                    ov_raw_seek(&_oggStream, 0);
                else
                    this->stop();

                return false;
            }
            else if (result == OV_HOLE) {
                // May return OV_HOLE after we rewind the stream,
                // so we just re-loop
                continue;
            }
            else if (result < 0) {
                // Error
                log->error(DGModAudio, "%s: %s", DGMsg270004, _resource.name);
                _hasStreamingError = true;

                return false;
            }
        }

        alBufferData(*buffer, _alFormat, data, size, _rate);

        return true;
    }
    else return false;
}

ALboolean DGAudio::_verifyError(const char* operation) {
   	ALint error = alGetError();

	if (error != AL_NO_ERROR) {
		log->error(DGModAudio, "%s: %s: %s (%d)", DGMsg270003, _resource.name, operation, error);

		return AL_FALSE;
	}

	return AL_TRUE;
}

// And now... The Vorbisfile callbacks

size_t DGAudio::_oggRead(void* ptr, size_t size, size_t nmemb, void* datasource) {
    DGAudio* audio = (DGAudio*)datasource;
    size_t nSize = size * nmemb;

    if ((audio->_resource.dataRead + nSize) > audio->_resource.dataSize)
        nSize = audio->_resource.dataSize - audio->_resource.dataRead;

    memcpy(ptr, audio->_resource.data + audio->_resource.dataRead, nSize);
    audio->_resource.dataRead += nSize;

	return nSize;
}

int DGAudio::_oggSeek(void* datasource, ogg_int64_t offset, int whence) {
    DGAudio* audio = (DGAudio*)datasource;

	switch (whence) {
        case SEEK_SET:
            audio->_resource.dataRead = (size_t)offset;
            break;
        case SEEK_CUR:
            audio->_resource.dataRead += (size_t)offset;
            break;
        case SEEK_END:
            audio->_resource.dataRead = (size_t)(audio->_resource.dataSize - offset);
            break;
	}

	if (audio->_resource.dataRead > audio->_resource.dataSize) {
		audio->_resource.dataRead = 0;
		return -1;
	}

	return 0;
}

int DGAudio::_oggClose(void* datasource) {
    DGAudio* audio = (DGAudio*)datasource;
	audio->_resource.dataRead = 0;

	return 0;
}

long DGAudio::_oggTell(void* datasource) {
    DGAudio* audio = (DGAudio*)datasource;
	return (long)audio->_resource.dataRead;
}
<|endoftext|>


<commit_before>// UgridFunctions.cc

// This file is part of bes, A C++ back-end server implementation framework
// for the OPeNDAP Data Access Protocol.

// Copyright (c) 2013 OPeNDAP, Inc.
// Author: James Gallagher <jgallagher@opendap.org>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.

#include <sstream>      // std::stringstream
#include <stdlib.h>     /* abort, NULL */
#include <iostream>

#include <sys/time.h>

#include "DebugFunctions.h"

#include "ServerFunctionsList.h"
#include "BESDebug.h"
#include <Int32.h>
#include <Str.h>
#include <BESError.h>
#include <BESInternalError.h>
#include <BESInternalFatalError.h>
#include <BESSyntaxUserError.h>
#include <BESForbiddenError.h>
#include <BESNotFoundError.h>

namespace debug_function {

static string getFunctionNames()
{
    vector<string> names;
    libdap::ServerFunctionsList::TheList()->getFunctionNames(&names);

    string msg;
    for (std::vector<string>::iterator it = names.begin(); it != names.end(); ++it) {
        if (!msg.empty()) msg += ", ";

        msg += *it;
    }

    return msg;
}

void DebugFunctions::initialize(const string &/*modname*/)
{
    BESDEBUG("DebugFunctions", "initialize() - BEGIN" << std::endl);
    BESDEBUG("DebugFunctions", "initialize() - function names: " << getFunctionNames() << std::endl);

    debug_function::AbortFunc *abortFunc = new debug_function::AbortFunc();
    libdap::ServerFunctionsList::TheList()->add_function(abortFunc);

    debug_function::SleepFunc *sleepFunc = new debug_function::SleepFunc();
    libdap::ServerFunctionsList::TheList()->add_function(sleepFunc);

    debug_function::SumUntilFunc *sumUntilFunc = new debug_function::SumUntilFunc();
    libdap::ServerFunctionsList::TheList()->add_function(sumUntilFunc);

    debug_function::ErrorFunc *errorFunc = new debug_function::ErrorFunc();
    libdap::ServerFunctionsList::TheList()->add_function(errorFunc);

    BESDEBUG("DebugFunctions", "initialize() - function names: " << getFunctionNames() << std::endl);

    BESDEBUG("DebugFunctions", "initialize() - END" << std::endl);
}

void DebugFunctions::terminate(const string &/*modname*/)
{
    BESDEBUG("DebugFunctions", "Removing DebugFunctions Modules (this does nothing)." << std::endl);
}

/** @brief dumps information about this object
 *
 * Displays the pointer value of this instance
 *
 * @param strm C++ i/o stream to dump the information to
 */
void DebugFunctions::dump(ostream &strm) const
{
    strm << BESIndent::LMarg << "DebugFunctions::dump - (" << (void *) this << ")" << std::endl;
}

/*****************************************************************************************
 *
 * Abort Function (Debug Functions)
 *
 * This server side function calls abort(). (boom)
 *
 */
string abort_usage="abort(##) Where ## is the number of milliseconds to sleep before calling abort.";
AbortFunc::AbortFunc()
{
        setName("abort");
        setDescriptionString((string)"This function calls abort() killing the beslistner process.");
        setUsageString(abort_usage);
        setRole("http://services.opendap.org/dap4/server-side-function/debug/abort");
        setDocUrl("http://docs.opendap.org/index.php/Debug_Functions");
        setFunction(debug_function::abort_ssf);
        setVersion("1.0");
}

void abort_ssf(int argc, libdap::BaseType * argv[], libdap::DDS &dds, libdap::BaseType **btpp){

    std::stringstream msg;
    libdap::Str *response = new libdap::Str("info");
    *btpp = response;

    if(argc!=1){
        msg << "Missing time parameter!  USAGE: "
            << abort_usage;
    }
    else {
        libdap::Int32 *param1 = dynamic_cast<libdap::Int32*>(argv[0]) ;
        if(param1){
           libdap::dods_int32 milliseconds = param1->value();

           msg << "abort in " << milliseconds << "ms" << endl;
           response->set_value(msg.str());

           usleep(milliseconds * 1000);
           msg << "abort now. "  << endl;
           std::abort();
           return;
        }
        else {
            msg << "This function only accepts integer values "
                << "for the time (in milliseconds) parameter.  USAGE: "
                << abort_usage;
        }

    }

    response->set_value(msg.str());
    return;
};

/*****************************************************************************************
 *
 * Sleep Function (Debug Functions)
 *
 * This server side function calls sleep() for the number
 * of millisecs passed in at argv[0]. (Zzzzzzzzzzzzzzz)
 *
 */

string sleep_usage = "sleep(##) where ## is the number of milliseconds to sleep.";
SleepFunc::SleepFunc()
{
        setName("sleep");
        setDescriptionString((string)"This function calls sleep() for the specified number of millisecs.");
        setUsageString(sleep_usage);
        setRole("http://services.opendap.org/dap4/server-side-function/debug/sleep");
        setDocUrl("http://docs.opendap.org/index.php/Debug_Functions");
        setFunction(debug_function::sleep_ssf);
        setVersion("1.0");
}

void sleep_ssf(int argc, libdap::BaseType * argv[], libdap::DDS &dds, libdap::BaseType **btpp){

    std::stringstream msg;
    libdap::Str *response = new libdap::Str("info");
    *btpp = response;

    if(argc!=1){
        msg << "Missing time parameter!  USAGE: "
            << sleep_usage;
    }
    else {
        libdap::Int32 *param1 = dynamic_cast<libdap::Int32*>(argv[0]) ;
        if(param1){
           libdap::dods_int32 milliseconds = param1->value();
            usleep(milliseconds * 1000);
            msg << "Slept for "
                << milliseconds
                << " ms.";
        }
        else {
            msg << "This function only accepts integer values "
                << "for the time (in milliseconds) parameter.  USAGE: "
                << sleep_usage;
        }

    }

    response->set_value(msg.str());
    return;
};

/*****************************************************************************************
 *
 * SumUntil (Debug Functions)
 *
 * This server side function computes a sum until the number of
 * millisecs (passed in at argv[0]) has transpired. (+,+...+)
 *
 */

string sum_until_usage = "sum_until(##) Will compute a sum until ## of milliseconds has transpired.";
SumUntilFunc::SumUntilFunc()
{
        setName("sum_until");
        setDescriptionString((string)"This function calls sleep() for the specified number of millisecs.");
        setUsageString(sum_until_usage);
        setRole("http://services.opendap.org/dap4/server-side-function/debug/sum_until");
        setDocUrl("http://docs.opendap.org/index.php/Debug_Functions");
        setFunction(debug_function::sum_until_ssf);
        setVersion("1.0");
}

void sum_until_ssf(int argc, libdap::BaseType * argv[], libdap::DDS &dds, libdap::BaseType **btpp){

    std::stringstream msg;
    libdap::Str *response = new libdap::Str("info");
    *btpp = response;

    if(argc!=1){
        msg << "Missing time parameter!  USAGE: "
            << sum_until_usage;
    }
    else {

        libdap::Int32 *param1 = dynamic_cast<libdap::Int32*>(argv[0]) ;
        if(param1){
            libdap::dods_int32 milliseconds = param1->value();

            struct timeval  tv;
            gettimeofday(&tv, NULL);
            double start_time = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000 ; // convert tv_sec & tv_usec to millisecond
            double end_time = start_time;

            long fib;
            long one_past = 1;
            long two_past = 0;
            long n = 1;

            bool done = false;
            while(!done){
                n++;
                fib = one_past + two_past;
                two_past = one_past;
                one_past = fib;
                gettimeofday(&tv, NULL);
                end_time = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000 ; // convert tv_sec & tv_usec to millisecond
                if( end_time - start_time >= milliseconds){
                    done = true;
                }
            }

            msg << "Summed for "
                << end_time - start_time
                << " ms. n: " << n;
        }
        else {
            msg << "This function only accepts integer values "
                << "for the time (in milliseconds) parameter.  USAGE: "
                << sum_until_usage;
        }

    }

    response->set_value(msg.str());
    return;
};

/*****************************************************************************************
 *
 * Error Function (Debug Functions)
 *
 * This server side function calls calls sleep() for the number
 * of ms passed in at argv[0]. (Zzzzzzzzzzzzzzz)
 *
 */
string error_usage = "error(##) where ## is the BESError type to generate.";
ErrorFunc::ErrorFunc()
{
        setName("error");
        setDescriptionString((string)"This function triggers a BES Error of the type specified");
        setUsageString(error_usage);
        setRole("http://services.opendap.org/dap4/server-side-function/debug/error");
        setDocUrl("http://docs.opendap.org/index.php/Debug_Functions");
        setFunction(debug_function::error_ssf);
        setVersion("1.0");
}

void error_ssf(int argc, libdap::BaseType * argv[], libdap::DDS &dds, libdap::BaseType **btpp){

    std::stringstream msg;
    libdap::Str *response = new libdap::Str("info");
    *btpp = response;

    string location = "error_ssf";

    if(argc!=1){
        msg << "Missing error type parameter!  USAGE: "
            << error_usage;
    }
    else {
        libdap::Int32 *param1 = dynamic_cast<libdap::Int32*>(argv[0]) ;
        if(param1){
            libdap::dods_int32 error_type = param1->value();

            switch(error_type) {

                case BES_INTERNAL_ERROR:
                {
                    msg << "A BESInternalError was requested.";
                    BESInternalError error(msg.str(),location,0);
                    throw error;
                }
                break;

                case BES_INTERNAL_FATAL_ERROR:
                {
                    msg << "A BESInternalFatalError was requested.";
                    BESInternalFatalError error(msg.str(),location,0);
                    throw error;
                }
                break;

                case BES_SYNTAX_USER_ERROR:
                {
                    msg << "A BESSyntaxUserError was requested.";
                    BESSyntaxUserError error(msg.str(),location,0);
                    throw error;
                }
                break;

                case BES_FORBIDDEN_ERROR:
                {
                    msg << "A BESForbiddenError was requested.";
                    BESForbiddenError error(msg.str(),location,0);
                    throw error;
                }
                break;

                case BES_NOT_FOUND_ERROR:
                {
                    msg << "A BESNotFoundError was requested.";
                    BESNotFoundError error(msg.str(),location,0);
                    throw error;
                }
                break;

                default:
                msg << "An unrecognized error_type parameter was received. error_type: " << error_type;
                break;
            }

        }
        else {
            msg << "This function only accepts integer values "
                << "for the error type parameter.  USAGE: "
                << error_usage;
        }

    }

    response->set_value(msg.str());
    return;

};

} // namespace debug_function

extern "C" {
BESAbstractModule *maker()
{
    return new debug_function::DebugFunctions;
}
}
<commit_msg>Minor changes to sleep()<commit_after>// UgridFunctions.cc

// This file is part of bes, A C++ back-end server implementation framework
// for the OPeNDAP Data Access Protocol.

// Copyright (c) 2013 OPeNDAP, Inc.
// Author: James Gallagher <jgallagher@opendap.org>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.

#include <sstream>      // std::stringstream
#include <stdlib.h>     /* abort, NULL */
#include <iostream>

#include <sys/time.h>

#include "DebugFunctions.h"

#include "ServerFunctionsList.h"
#include "BESDebug.h"
#include <Int32.h>
#include <Structure.h>
#include <Str.h>
#include <BESError.h>
#include <BESInternalError.h>
#include <BESInternalFatalError.h>
#include <BESSyntaxUserError.h>
#include <BESForbiddenError.h>
#include <BESNotFoundError.h>

namespace debug_function {

static string getFunctionNames()
{
    vector<string> names;
    libdap::ServerFunctionsList::TheList()->getFunctionNames(&names);

    string msg;
    for (std::vector<string>::iterator it = names.begin(); it != names.end(); ++it) {
        if (!msg.empty()) msg += ", ";

        msg += *it;
    }

    return msg;
}

void DebugFunctions::initialize(const string &/*modname*/)
{
    BESDEBUG("DebugFunctions", "initialize() - BEGIN" << std::endl);
    BESDEBUG("DebugFunctions", "initialize() - function names: " << getFunctionNames() << std::endl);

    debug_function::AbortFunc *abortFunc = new debug_function::AbortFunc();
    libdap::ServerFunctionsList::TheList()->add_function(abortFunc);

    debug_function::SleepFunc *sleepFunc = new debug_function::SleepFunc();
    libdap::ServerFunctionsList::TheList()->add_function(sleepFunc);

    debug_function::SumUntilFunc *sumUntilFunc = new debug_function::SumUntilFunc();
    libdap::ServerFunctionsList::TheList()->add_function(sumUntilFunc);

    debug_function::ErrorFunc *errorFunc = new debug_function::ErrorFunc();
    libdap::ServerFunctionsList::TheList()->add_function(errorFunc);

    BESDEBUG("DebugFunctions", "initialize() - function names: " << getFunctionNames() << std::endl);

    BESDEBUG("DebugFunctions", "initialize() - END" << std::endl);
}

void DebugFunctions::terminate(const string &/*modname*/)
{
    BESDEBUG("DebugFunctions", "Removing DebugFunctions Modules (this does nothing)." << std::endl);
}

/** @brief dumps information about this object
 *
 * Displays the pointer value of this instance
 *
 * @param strm C++ i/o stream to dump the information to
 */
void DebugFunctions::dump(ostream &strm) const
{
    strm << BESIndent::LMarg << "DebugFunctions::dump - (" << (void *) this << ")" << std::endl;
}

/*****************************************************************************************
 *
 * Abort Function (Debug Functions)
 *
 * This server side function calls abort(). (boom)
 *
 */
string abort_usage="abort(##) Where ## is the number of milliseconds to sleep before calling abort.";
AbortFunc::AbortFunc()
{
        setName("abort");
        setDescriptionString((string)"This function calls abort() killing the beslistner process.");
        setUsageString(abort_usage);
        setRole("http://services.opendap.org/dap4/server-side-function/debug/abort");
        setDocUrl("http://docs.opendap.org/index.php/Debug_Functions");
        setFunction(debug_function::abort_ssf);
        setVersion("1.0");
}

void abort_ssf(int argc, libdap::BaseType * argv[], libdap::DDS &dds, libdap::BaseType **btpp){

    std::stringstream msg;
    libdap::Str *response = new libdap::Str("info");
    *btpp = response;

    if(argc!=1){
        msg << "Missing time parameter!  USAGE: "
            << abort_usage;
    }
    else {
        libdap::Int32 *param1 = dynamic_cast<libdap::Int32*>(argv[0]) ;
        if(param1){
           libdap::dods_int32 milliseconds = param1->value();

           msg << "abort in " << milliseconds << "ms" << endl;
           response->set_value(msg.str());

           usleep(milliseconds * 1000);
           msg << "abort now. "  << endl;
           std::abort();
           return;
        }
        else {
            msg << "This function only accepts integer values "
                << "for the time (in milliseconds) parameter.  USAGE: "
                << abort_usage;
        }

    }

    response->set_value(msg.str());
    return;
};

/*****************************************************************************************
 *
 * Sleep Function (Debug Functions)
 *
 * This server side function calls sleep() for the number
 * of millisecs passed in at argv[0]. (Zzzzzzzzzzzzzzz)
 *
 */

string sleep_usage = "sleep(##) where ## is the number of milliseconds to sleep.";
SleepFunc::SleepFunc()
{
        setName("sleep");
        setDescriptionString((string)"This function calls sleep() for the specified number of millisecs.");
        setUsageString(sleep_usage);
        setRole("http://services.opendap.org/dap4/server-side-function/debug/sleep");
        setDocUrl("http://docs.opendap.org/index.php/Debug_Functions");
        setFunction(debug_function::sleep_ssf);
        setVersion("1.0");
}

void sleep_ssf(int argc, libdap::BaseType * argv[], libdap::DDS &dds, libdap::BaseType **btpp){

    std::stringstream msg;
    libdap::Str *sleep_info = new libdap::Str("info");

    //libdap::Structure *sleepResult = new libdap::Structure("sleep_result_unwrap");
    //sleepResult->add_var_nocopy(sleep_info);
    //*btpp = sleepResult;

    *btpp = sleep_info;

    if(argc!=1){
        msg << "Missing time parameter!  USAGE: "
            << sleep_usage;
    }
    else {
        libdap::Int32 *param1 = dynamic_cast<libdap::Int32*>(argv[0]) ;
        if(param1){
           libdap::dods_int32 milliseconds = param1->value();
            usleep(milliseconds * 1000);
            msg << "Slept for "
                << milliseconds
                << " ms.";
        }
        else {
            msg << "This function only accepts integer values "
                << "for the time (in milliseconds) parameter.  USAGE: "
                << sleep_usage;
        }

    }

    sleep_info->set_value(msg.str());

    /*
    for (libdap::DDS::Vars_iter it = dds.var_begin(); it != dds.var_end(); ++it) {
        libdap::BaseType *pBT = *it;
        sleepResult->add_var(pBT);
    }
    */

    return;
};

/*****************************************************************************************
 *
 * SumUntil (Debug Functions)
 *
 * This server side function computes a sum until the number of
 * millisecs (passed in at argv[0]) has transpired. (+,+...+)
 *
 */

string sum_until_usage = "sum_until(##) Will compute a sum until ## of milliseconds has transpired.";
SumUntilFunc::SumUntilFunc()
{
        setName("sum_until");
        setDescriptionString((string)"This function calls sleep() for the specified number of millisecs.");
        setUsageString(sum_until_usage);
        setRole("http://services.opendap.org/dap4/server-side-function/debug/sum_until");
        setDocUrl("http://docs.opendap.org/index.php/Debug_Functions");
        setFunction(debug_function::sum_until_ssf);
        setVersion("1.0");
}

void sum_until_ssf(int argc, libdap::BaseType * argv[], libdap::DDS &dds, libdap::BaseType **btpp){

    std::stringstream msg;
    libdap::Str *response = new libdap::Str("info");
    *btpp = response;

    if(argc!=1){
        msg << "Missing time parameter!  USAGE: "
            << sum_until_usage;
    }
    else {

        libdap::Int32 *param1 = dynamic_cast<libdap::Int32*>(argv[0]) ;
        if(param1){
            libdap::dods_int32 milliseconds = param1->value();

            struct timeval  tv;
            gettimeofday(&tv, NULL);
            double start_time = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000 ; // convert tv_sec & tv_usec to millisecond
            double end_time = start_time;

            long fib;
            long one_past = 1;
            long two_past = 0;
            long n = 1;

            bool done = false;
            while(!done){
                n++;
                fib = one_past + two_past;
                two_past = one_past;
                one_past = fib;
                gettimeofday(&tv, NULL);
                end_time = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000 ; // convert tv_sec & tv_usec to millisecond
                if( end_time - start_time >= milliseconds){
                    done = true;
                }
            }

            msg << "Summed for "
                << end_time - start_time
                << " ms. n: " << n;
        }
        else {
            msg << "This function only accepts integer values "
                << "for the time (in milliseconds) parameter.  USAGE: "
                << sum_until_usage;
        }

    }

    response->set_value(msg.str());
    return;
};

/*****************************************************************************************
 *
 * Error Function (Debug Functions)
 *
 * This server side function calls calls sleep() for the number
 * of ms passed in at argv[0]. (Zzzzzzzzzzzzzzz)
 *
 */
string error_usage = "error(##) where ## is the BESError type to generate.";
ErrorFunc::ErrorFunc()
{
        setName("error");
        setDescriptionString((string)"This function triggers a BES Error of the type specified");
        setUsageString(error_usage);
        setRole("http://services.opendap.org/dap4/server-side-function/debug/error");
        setDocUrl("http://docs.opendap.org/index.php/Debug_Functions");
        setFunction(debug_function::error_ssf);
        setVersion("1.0");
}

void error_ssf(int argc, libdap::BaseType * argv[], libdap::DDS &dds, libdap::BaseType **btpp){

    std::stringstream msg;
    libdap::Str *response = new libdap::Str("info");
    *btpp = response;

    string location = "error_ssf";

    if(argc!=1){
        msg << "Missing error type parameter!  USAGE: "
            << error_usage;
    }
    else {
        libdap::Int32 *param1 = dynamic_cast<libdap::Int32*>(argv[0]) ;
        if(param1){
            libdap::dods_int32 error_type = param1->value();

            switch(error_type) {

                case BES_INTERNAL_ERROR:
                {
                    msg << "A BESInternalError was requested.";
                    BESInternalError error(msg.str(),location,0);
                    throw error;
                }
                break;

                case BES_INTERNAL_FATAL_ERROR:
                {
                    msg << "A BESInternalFatalError was requested.";
                    BESInternalFatalError error(msg.str(),location,0);
                    throw error;
                }
                break;

                case BES_SYNTAX_USER_ERROR:
                {
                    msg << "A BESSyntaxUserError was requested.";
                    BESSyntaxUserError error(msg.str(),location,0);
                    throw error;
                }
                break;

                case BES_FORBIDDEN_ERROR:
                {
                    msg << "A BESForbiddenError was requested.";
                    BESForbiddenError error(msg.str(),location,0);
                    throw error;
                }
                break;

                case BES_NOT_FOUND_ERROR:
                {
                    msg << "A BESNotFoundError was requested.";
                    BESNotFoundError error(msg.str(),location,0);
                    throw error;
                }
                break;

                default:
                msg << "An unrecognized error_type parameter was received. error_type: " << error_type;
                break;
            }

        }
        else {
            msg << "This function only accepts integer values "
                << "for the error type parameter.  USAGE: "
                << error_usage;
        }

    }

    response->set_value(msg.str());
    return;

};

} // namespace debug_function

extern "C" {
BESAbstractModule *maker()
{
    return new debug_function::DebugFunctions;
}
}
<|endoftext|>


<commit_before><commit_msg>More tests added to cctest/tests/test-migrations.cc.<commit_after><|endoftext|>