<commit_before>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * Razor - a lightweight, Qt based, desktop toolset
 * http://razor-qt.org
 *
 * Copyright: 2012 Razor team
 * Authors:
 *   Petr Vanek <petr@scribus.info>
 *
 * This program or 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
 *
 * END_COMMON_COPYRIGHT_HEADER */

#include <QtGui/QPainter>
#include <QtCore/QUrl>
#include <QtCore/QFile>
#include <QtCore/QDateTime>
#include <QtDBus/QDBusArgument>

#include <qtxdg/xdgicon.h>

#include "notification.h"
#include "notificationwidgets.h"

#include <QtDebug>

#define ICONSIZE QSize(32, 32)

Notification::Notification(const QString &application,
                           const QString &summary, const QString &body,
                           const QString &icon, int timeout,
                           const QStringList& actions, const QVariantMap& hints,
                           QWidget *parent)
    : QWidget(parent),
      m_timer(0),
      m_actionWidget(0)
{
    setupUi(this);
    setObjectName("Notification");
    setMouseTracking(true);

    setMaximumWidth(parent->width());
    setMinimumWidth(parent->width());

    setValues(application, summary, body, icon, timeout, actions, hints);

    connect(closeButton, SIGNAL(clicked()), this, SLOT(closeButton_clicked()));
}

void Notification::setValues(const QString &application,
                             const QString &summary, const QString &body,
                             const QString &icon, int timeout,
                             const QStringList& actions, const QVariantMap& hints)
{
    // Basic properties *********************

    // Notifications spec set real order here:
    // An implementation which only displays one image or icon must
    // choose which one to display using the following order:
    //  - "image-data"
    //  - "image-path"
    //  - app_icon parameter
    //  - for compatibility reason, "icon_data"
    if (!hints["image_data"].isNull())
    {
        m_pixmap = getPixmapFromHint(hints["image_data"]);
//        qDebug() << application << "from image_data" << m_pixmap.isNull();
    }
    else if (!hints["image_path"].isNull())
    {
        m_pixmap = getPixmapFromString(hints["image_path"].toString());
//        qDebug() << application << "from image_path" << m_pixmap.isNull();
    }
    else if (!icon.isEmpty())
    {
        m_pixmap = getPixmapFromString(icon);
//        qDebug() << application << "from icon" << icon << m_pixmap.isNull();
    }
    else if (!hints["icon_data"].isNull())
    {
       m_pixmap = getPixmapFromHint(hints["icon_data"]);
//       qDebug() << application << "from icon_data" << m_pixmap.isNull();
    }
    // failback
    if (m_pixmap.isNull())
    {
//        qDebug() << "An icon for name:" << icon << "or hints" << hints << "not found. Using failback.";
        m_pixmap = XdgIcon::defaultApplicationIcon().pixmap(ICONSIZE);
    }

    if (m_pixmap.size().width() > ICONSIZE.width()
    	|| m_pixmap.size().height() > ICONSIZE.height())
    {
    	m_pixmap = m_pixmap.scaled(ICONSIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation);
    }
    iconLabel->setPixmap(m_pixmap);

    // application
	appLabel->setVisible(!application.isEmpty());
    appLabel->setText(application);

    // summary
    summaryLabel->setVisible(!summary.isEmpty());
    summaryLabel->setText(summary);

    // body
    bodyLabel->setVisible(!body.isEmpty());
    bodyLabel->setText(body);

    // Timeout
    // Special values:
    //  < 0: server decides timeout
    //    0: infifite
    if (m_timer)
    {
        m_timer->stop();
        m_timer->deleteLater();
    }

    // -1 for server decides is handled in notifyd to save QSettings instance
    if (timeout > 0)
    {
        m_timer = new NotificationTimer(this);
        connect(m_timer, SIGNAL(timeout()), this, SIGNAL(timeout()));
        m_timer->start(timeout);
    }

    // Categories *********************
    // TODO/FIXME: Categories - how to handle it?
    if (!hints["category"].isNull())
    {
        qDebug() << "Notification" << application << "category" << hints["category"];
    }

    // Urgency Levels *********************
    // Type    Description
    // 0   Low
    // 1   Normal
    // 2   Critical
    // TODO/FIXME: Urgencies - how to handle it?
    if (!hints["urgency"].isNull())
    {
        qDebug() << "Notification" << application << "urgency" << hints["urgency"];
    }

    // Actions
    if (actions.count() && m_actionWidget == 0)
    {
        m_actionWidget = new NotificationActionsWidget(actions, this);
        connect(m_actionWidget, SIGNAL(actionTriggered(const QString &)),
                this, SIGNAL(actionTriggered(const QString &)));
        actionsLayout->addWidget(m_actionWidget);
        m_actionWidget->show();
    }

    adjustSize();
    // ensure layout expansion
    setMinimumHeight(qMax(rect().height(), childrenRect().height()));
}

void Notification::closeButton_clicked()
{
    if (m_timer)
        m_timer->stop();
    emit userCanceled();
}

void Notification::paintEvent(QPaintEvent *)
{
    QStyleOption opt;
    opt.init(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

QPixmap Notification::getPixmapFromHint(const QVariant &argument) const
{
    int width, height, rowstride, bitsPerSample, channels;
    bool hasAlpha;
    QByteArray data;

    const QDBusArgument arg = argument.value<QDBusArgument>();
    arg.beginStructure();
    arg >> width;
    arg >> height;
    arg >> rowstride;
    arg >> hasAlpha;
    arg >> bitsPerSample;
    arg >> channels;
    arg >> data;
    arg.endStructure();
    QImage img = QImage((uchar*)data.constData(), width, height, QImage::Format_ARGB32).rgbSwapped();

    return QPixmap::fromImage(img);
}

QPixmap Notification::getPixmapFromString(const QString &str) const
{
    QUrl url(str);
    if (url.isValid() && QFile::exists(url.toLocalFile()))
    {
//        qDebug() << "    getPixmapFromString by URL" << url;
        return QPixmap(url.toLocalFile());
    }
    else
    {
//        qDebug() << "    getPixmapFromString by XdgIcon theme" << str << ICONSIZE << XdgIcon::themeName();
//        qDebug() << "       " << XdgIcon::fromTheme(str) << "isnull:" << XdgIcon::fromTheme(str).isNull();
        return XdgIcon::fromTheme(str, XdgIcon::defaultApplicationIcon()).pixmap(ICONSIZE);
    }
}

void Notification::enterEvent(QEvent * event)
{
    if (m_timer)
        m_timer->pause();
}

void Notification::leaveEvent(QEvent * event)
{
    if (m_timer)
        m_timer->resume();
}

NotificationTimer::NotificationTimer(QObject *parent)
    : QTimer(parent)
{
}

void NotificationTimer::start(int msec)
{
    m_startMsec = QDateTime::currentMSecsSinceEpoch();
    m_intervalMsec = msec;
    QTimer::start(msec);
}

void NotificationTimer::pause()
{
    if (!isActive())
        return;

    stop();
    m_intervalMsec -= QDateTime::currentMSecsSinceEpoch() - m_startMsec;
}

void NotificationTimer::resume()
{
    if (isActive())
        return;

    start(m_intervalMsec);
}
<commit_msg>issue #325: do not display default app icon if there is no icon found for notification<commit_after>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * Razor - a lightweight, Qt based, desktop toolset
 * http://razor-qt.org
 *
 * Copyright: 2012 Razor team
 * Authors:
 *   Petr Vanek <petr@scribus.info>
 *
 * This program or 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
 *
 * END_COMMON_COPYRIGHT_HEADER */

#include <QtGui/QPainter>
#include <QtCore/QUrl>
#include <QtCore/QFile>
#include <QtCore/QDateTime>
#include <QtDBus/QDBusArgument>

#include <qtxdg/xdgicon.h>

#include "notification.h"
#include "notificationwidgets.h"

#include <QtDebug>

#define ICONSIZE QSize(32, 32)

Notification::Notification(const QString &application,
                           const QString &summary, const QString &body,
                           const QString &icon, int timeout,
                           const QStringList& actions, const QVariantMap& hints,
                           QWidget *parent)
    : QWidget(parent),
      m_timer(0),
      m_actionWidget(0)
{
    setupUi(this);
    setObjectName("Notification");
    setMouseTracking(true);

    setMaximumWidth(parent->width());
    setMinimumWidth(parent->width());

    setValues(application, summary, body, icon, timeout, actions, hints);

    connect(closeButton, SIGNAL(clicked()), this, SLOT(closeButton_clicked()));
}

void Notification::setValues(const QString &application,
                             const QString &summary, const QString &body,
                             const QString &icon, int timeout,
                             const QStringList& actions, const QVariantMap& hints)
{
    // Basic properties *********************

    // Notifications spec set real order here:
    // An implementation which only displays one image or icon must
    // choose which one to display using the following order:
    //  - "image-data"
    //  - "image-path"
    //  - app_icon parameter
    //  - for compatibility reason, "icon_data"
    if (!hints["image_data"].isNull())
    {
        m_pixmap = getPixmapFromHint(hints["image_data"]);
//        qDebug() << application << "from image_data" << m_pixmap.isNull();
    }
    else if (!hints["image_path"].isNull())
    {
        m_pixmap = getPixmapFromString(hints["image_path"].toString());
//        qDebug() << application << "from image_path" << m_pixmap.isNull();
    }
    else if (!icon.isEmpty())
    {
        m_pixmap = getPixmapFromString(icon);
//        qDebug() << application << "from icon" << icon << m_pixmap.isNull();
    }
    else if (!hints["icon_data"].isNull())
    {
       m_pixmap = getPixmapFromHint(hints["icon_data"]);
//       qDebug() << application << "from icon_data" << m_pixmap.isNull();
    }
    // issue #325: Do not display icon if it's not found...
    if (m_pixmap.isNull())
    {
        iconLabel->hide();
    }
    else
    {
        if (m_pixmap.size().width() > ICONSIZE.width()
            || m_pixmap.size().height() > ICONSIZE.height())
        {
            m_pixmap = m_pixmap.scaled(ICONSIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation);
        }
        iconLabel->setPixmap(m_pixmap);
        iconLabel->show();
    }

    // application
	appLabel->setVisible(!application.isEmpty());
    appLabel->setText(application);

    // summary
    summaryLabel->setVisible(!summary.isEmpty());
    summaryLabel->setText(summary);

    // body
    bodyLabel->setVisible(!body.isEmpty());
    bodyLabel->setText(body);

    // Timeout
    // Special values:
    //  < 0: server decides timeout
    //    0: infifite
    if (m_timer)
    {
        m_timer->stop();
        m_timer->deleteLater();
    }

    // -1 for server decides is handled in notifyd to save QSettings instance
    if (timeout > 0)
    {
        m_timer = new NotificationTimer(this);
        connect(m_timer, SIGNAL(timeout()), this, SIGNAL(timeout()));
        m_timer->start(timeout);
    }

    // Categories *********************
    // TODO/FIXME: Categories - how to handle it?
    if (!hints["category"].isNull())
    {
        qDebug() << "Notification" << application << "category" << hints["category"];
    }

    // Urgency Levels *********************
    // Type    Description
    // 0   Low
    // 1   Normal
    // 2   Critical
    // TODO/FIXME: Urgencies - how to handle it?
    if (!hints["urgency"].isNull())
    {
        qDebug() << "Notification" << application << "urgency" << hints["urgency"];
    }

    // Actions
    if (actions.count() && m_actionWidget == 0)
    {
        m_actionWidget = new NotificationActionsWidget(actions, this);
        connect(m_actionWidget, SIGNAL(actionTriggered(const QString &)),
                this, SIGNAL(actionTriggered(const QString &)));
        actionsLayout->addWidget(m_actionWidget);
        m_actionWidget->show();
    }

    adjustSize();
    // ensure layout expansion
    setMinimumHeight(qMax(rect().height(), childrenRect().height()));
}

void Notification::closeButton_clicked()
{
    if (m_timer)
        m_timer->stop();
    emit userCanceled();
}

void Notification::paintEvent(QPaintEvent *)
{
    QStyleOption opt;
    opt.init(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

QPixmap Notification::getPixmapFromHint(const QVariant &argument) const
{
    int width, height, rowstride, bitsPerSample, channels;
    bool hasAlpha;
    QByteArray data;

    const QDBusArgument arg = argument.value<QDBusArgument>();
    arg.beginStructure();
    arg >> width;
    arg >> height;
    arg >> rowstride;
    arg >> hasAlpha;
    arg >> bitsPerSample;
    arg >> channels;
    arg >> data;
    arg.endStructure();
    QImage img = QImage((uchar*)data.constData(), width, height, QImage::Format_ARGB32).rgbSwapped();

    return QPixmap::fromImage(img);
}

QPixmap Notification::getPixmapFromString(const QString &str) const
{
    QUrl url(str);
    if (url.isValid() && QFile::exists(url.toLocalFile()))
    {
//        qDebug() << "    getPixmapFromString by URL" << url;
        return QPixmap(url.toLocalFile());
    }
    else
    {
//        qDebug() << "    getPixmapFromString by XdgIcon theme" << str << ICONSIZE << XdgIcon::themeName();
//        qDebug() << "       " << XdgIcon::fromTheme(str) << "isnull:" << XdgIcon::fromTheme(str).isNull();
        // They say: do not display an icon if it;s not found - see #325
        return XdgIcon::fromTheme(str/*, XdgIcon::defaultApplicationIcon()*/).pixmap(ICONSIZE);
    }
}

void Notification::enterEvent(QEvent * event)
{
    if (m_timer)
        m_timer->pause();
}

void Notification::leaveEvent(QEvent * event)
{
    if (m_timer)
        m_timer->resume();
}

NotificationTimer::NotificationTimer(QObject *parent)
    : QTimer(parent)
{
}

void NotificationTimer::start(int msec)
{
    m_startMsec = QDateTime::currentMSecsSinceEpoch();
    m_intervalMsec = msec;
    QTimer::start(msec);
}

void NotificationTimer::pause()
{
    if (!isActive())
        return;

    stop();
    m_intervalMsec -= QDateTime::currentMSecsSinceEpoch() - m_startMsec;
}

void NotificationTimer::resume()
{
    if (isActive())
        return;

    start(m_intervalMsec);
}
<|endoftext|>


<commit_before>/**
 ** \file object/object.cc
 ** \brief Implementation of object::Object.
 */

#include <algorithm>

#include <boost/assign.hpp> // for 'list_of'
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/lambda/lambda.hpp>
using namespace boost::assign; // bring 'list_of' into scope

#include <libport/containers.hh>
#include <libport/foreach.hh>

#include <object/atom.hh>
#include <object/dictionary-class.hh>
#include <object/float-class.hh>
#include <object/global-class.hh>
#include <object/hash-slots.hh>
#include <object/list-class.hh>
#include <object/object.hh>
#include <object/object-class.hh>
#include <object/urbi-exception.hh>

#include <runner/runner.hh>

namespace object
{

  /*---------.
  | Callers. |
  `---------*/

  rObject urbi_call(runner::Runner& r,
		    rObject self,
		    libport::Symbol msg,
		    objects_type args)
  {
    return urbi_call_function(r, self, self, msg, args);
  }

#define CHECK_ARG(N)				\
  if (!arg ## N)				\
    goto done;					\
  args.push_back(arg ## N)

  rObject urbi_call(runner::Runner& r,
		    rObject self,
		    libport::Symbol msg,
		    rObject arg1,
		    rObject arg2,
		    rObject arg3,
		    rObject arg4,
		    rObject arg5)
  {
    objects_type args;
    CHECK_ARG(1);
    CHECK_ARG(2);
    CHECK_ARG(3);
    CHECK_ARG(4);
    CHECK_ARG(5);
  done:
    return urbi_call_function(r, self, self, msg, args);
  }

#undef CHECK_ARG

  rObject urbi_call_function(runner::Runner& r, rObject self,
                             rObject owner, libport::Symbol msg)
  {
    objects_type args; // Call with no args.
    return urbi_call_function(r, self, owner, msg, args);
  }

  rObject urbi_call_function(runner::Runner& r, rObject self,
                             rObject owner, libport::Symbol msg,
                             objects_type args)
  {
    assertion(self);
    rObject message = owner->slot_get(msg);
    if (!message)
      throw LookupError(msg);
    args.insert(args.begin(), self);
    rObject res = r.apply(message, msg, args);
    assertion(res);
    return res;
  }

  /*---------.
  | Scopes.  |
  `---------*/

  typedef boost::optional<rObject> lookup_result;
  typedef boost::function1<lookup_result, rObject> lookup_action;

  rObject
  Object::make_scope(const rObject& parent)
  {
    rObject res = new object::Object();
    res->proto_add(parent);
    return res;
  }

  rObject
  Object::make_method_scope(const rObject& parent)
  {
    rObject res = Object::make_scope(parent ? parent : object_class);
    res->slot_set(SYMBOL(self), this);
    return res;
  }

  /*--------.
  | Slots.  |
  `--------*/

  rObject
  Object::urbi_protos_get ()
  {
    if (!protos_cache_)
    {
      rList protos = new List(*protos_);
      protos_cache_ = protos;
      delete protos_;
      protos_ = &protos->value_get ();
    }
    return protos_cache_;
  }

  void
  Object::protos_set (rObject l)
  {
    if (!protos_cache_)
      delete protos_;
    protos_cache_ = l;
    protos_ = &l.unsafe_cast<object::List>()->value_get ();
  }

  template <typename R>
  boost::optional<R>
  Object::lookup(boost::function1<boost::optional<R>, rObject> action,
		 objects_set_type& marks) const
  {
    if (!libport::mhas(marks, this))
    {
      marks.insert(this);
      // FIXME: rConstObject?
      boost::optional<R> res = action(const_cast<Object*>(this));
      if (res)
	return res;
      else
	foreach (const rObject& proto, protos_get())
	  if (boost::optional<R> res = proto->lookup(action, marks))
	    return res;
    }
    return boost::optional<R>();
  }

  template <typename R>
  boost::optional<R>
  Object::lookup(boost::function1<boost::optional<R>, rObject> action) const
  {
    objects_set_type marks;
    return lookup(action, marks);
  }

  namespace
  {
    class SlotLookup
    {
    public:
      lookup_result
      slot_lookup(rObject obj, const Object::key_type& k, bool value)
      {
	assertion(obj);
	if (rObject x = obj->own_slot_get(k))
	  return value ? x : obj;
	if (!fallback)
          if (rObject f = obj->own_slot_get(SYMBOL(fallback)))
            fallback = value ? f : obj;
	return boost::optional<rObject>();
      }
      rObject fallback;
    };
  }

  rObject
  Object::slot_locate(const key_type& k,
                      bool fallback, bool value) const
  {
    SlotLookup looker;
    lookup_action action =
      boost::bind(&SlotLookup::slot_lookup, &looker, _1, k, value);
    boost::optional<rObject> res = lookup(action);
    if (!res && fallback && looker.fallback)
      res = looker.fallback;
    if (res)
      return res.get();
    else
      return 0;
  }

  rObject
  Object::safe_slot_locate(const key_type& k, bool value) const
  {
    rObject r = slot_locate(k, true, value);
    if (!r)
      throw LookupError(k);
    return iassertion(r);
  }

  rObject
  Object::slot_get (const key_type& k, boost::optional<rObject> def) const
  {
    rObject value;
    if (def)
      value = slot_locate(k, true, true);
    else
      value = safe_slot_locate(k, true);
    if (value)
      return value;
    else
      return def.get();
  }

  Object&
  Object::slot_set(const key_type& k, rObject o)
  {
    if (!slots_.set(k, o))
      throw RedefinitionError(k);
    return *this;
  }

  Object&
  Object::slot_copy(const key_type& name, rObject from)
  {
    this->slot_set(name, from->slot_get(name));
    return *this;
  }

  void
  Object::slot_update(runner::Runner& r,
                      const key_type& k, rObject o,
                      bool hook)
  {
    // The owner of the updated slot
    rObject owner = safe_slot_locate(k);

    // If the current value in the slot to be written in has a slot
    // named 'updateHook', call it, passing the object owning the
    // slot, the slot name and the target.
    if (hook)
      if (rObject hook = owner->property_get(k, SYMBOL(updateHook)))
      {
        objects_type args = list_of (rObject(this)) (new String(k)) (o);
        rObject ret = r.apply(hook, SYMBOL(updateHook), args);
        // If the updateHook returned void, do nothing. Otherwise let
        // the slot be overwritten.
        if (ret == object::void_class)
          return;
      }
    // If return-value of hook is not void, write it to slot.
    own_slot_update(k, o);
  };

  void
  Object::own_slot_update (const key_type& k, rObject v)
  {
    slots_.update(k, v);
  }

  void
  Object::all_slots_copy(const rObject& other)
  {
    foreach (const Slots::slot_type& slot, other->slots_get())
      if (!own_slot_get(slot.first))
        slot_set(slot.first, slot.second);
  }

  /*-------------.
  | Properties.  |
  `-------------*/

  rDictionary
  Object::properties_get()
  {
    rDictionary res;
    if (slots_.has(SYMBOL(properties)))
      res = slots_.get(SYMBOL(properties)).unsafe_cast<Dictionary>();
    return res;
  }

  rDictionary
  Object::properties_get(const key_type& k)
  {
    rDictionary res;
    if (rDictionary ps = properties_get())
      res = libport::find0(ps->value_get(), k).unsafe_cast<Dictionary>();
    return res;
  }

  rObject
  Object::property_get(const key_type& k, const key_type& p)
  {
    rObject res;
    if (rDictionary ps = properties_get(k))
      res = libport::find0(ps->value_get(), p);
    return res;
  }

  bool
  Object::property_has(const key_type& k, const key_type& p)
  {
    if (rDictionary ps = properties_get(k))
      return libport::find0(ps->value_get(), p);
    return false;
  }

  rObject
  Object::property_set(const key_type& k, const key_type& p, rObject value)
  {
    // Make sure the object has a properties dictionary.
    rDictionary props = properties_get();
    if (!props)
    {
      props = new Dictionary();
      // This should die if there is a slot name "properties" which is
      // not a dictionary, which is what we want, don't we?
      slot_set(SYMBOL(properties), props);
    }

    // Make sure we have a dict for slot k.
    rDictionary prop =
      libport::find0(props->value_get(), k).unsafe_cast<Dictionary>();
    if (!prop)
    {
      prop = new Dictionary();
      props->value_get()[k] = prop;
    }

    prop->value_get()[p] = value;
    return value;
  }

  /*-----------.
  | Printing.  |
  `-----------*/

  std::ostream&
  Object::special_slots_dump (std::ostream& o, runner::Runner&) const
  {
    return o;
  }

  bool
  Object::operator< (const Object& rhs) const
  {
    return this < &rhs;
  }

  std::ostream&
  Object::id_dump(std::ostream& o, runner::Runner& r) const
  {
    rObject data = urbi_call(r, const_cast<Object*>(this), SYMBOL(id));
    type_check<String>(data, SYMBOL(id_dump));
    libport::Symbol s = data->as<String>()->value_get();
    return o << s;
  }

  std::ostream&
  Object::protos_dump(std::ostream& o, runner::Runner& runner) const
  {
    if (!protos_->empty())
    {
      o << "protos = ";
      bool tail = false;
      foreach (const rObject& p, *protos_)
      {
	if (tail++)
	  o << ", ";
	p->id_dump (o, runner);
      }
      o << libport::iendl;
    }
    return o;
  }

  std::ostream&
  Object::dump (std::ostream& o, runner::Runner& runner, int depth_max) const
  {
    id_dump(o, runner);
    /// Use xalloc/iword to store our current depth within the stream object.
    static const long idx = o.xalloc();
    long& current_depth = o.iword(idx);

    // Stop recursion at depth_max.
    if (current_depth > depth_max)
      return o << " <...>";
    ++current_depth;
    o << " {" << libport::incendl;
    protos_dump(o, runner);
    special_slots_dump (o, runner);
    foreach(const Slots::slot_type& s, slots_.container())
    {
      o << s.first << " = ";
      s.second->dump(o, runner, depth_max) << libport::iendl;
    }

    o << libport::decindent << '}';
    //We can not reuse current_depth variable above according to spec.
    o.iword(idx)--;
    return o;
  }

  std::ostream&
  Object::print(std::ostream& o, runner::Runner& runner) const
  {
    try
    {
      rObject s = urbi_call(runner, const_cast<Object*>(this), SYMBOL(asString));
      type_check<String>(s, SYMBOL(print));
      o << s->as<String>()->value_get();
      return o;
    }
    // Check if asString was found, especially for bootstrap: asString
    // is implemented in urbi/urbi.u, but print is called to show
    // result in the toplevel before its definition.
    catch (LookupError&)
    {
      // If no asString method is supplied, print the unique id
      return o << std::hex << this;
    }
  }

  bool
  is_a(const rObject& c, const rObject& p)
  {
    return for_all_protos(c, boost::lambda::_1 == p);
  }

  bool
  is_true(const rObject& o, const libport::Symbol& fun)
  {
    if (o == nil_class)
      return false;
    if (o->is_a<object::Float>())
      return o.unsafe_cast<object::Float>()->value_get();
    if (o == true_class)
      return true;
    if (o == false_class)
      return false;
    if (o == void_class)
      throw WrongArgumentType(fun);
    // FIXME: We will probably want to throw here.  This is related to
    // maybe calling asBool on every tested value.
    return true;
    // throw WrongArgumentType("Boolean", "Object", fun.name_get());
  }

} // namespace object
<commit_msg>Raise error when setting/reading/testing properties on nonexistent slots.<commit_after>/**
 ** \file object/object.cc
 ** \brief Implementation of object::Object.
 */

#include <algorithm>

#include <boost/assign.hpp> // for 'list_of'
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/lambda/lambda.hpp>
using namespace boost::assign; // bring 'list_of' into scope

#include <libport/containers.hh>
#include <libport/foreach.hh>

#include <object/atom.hh>
#include <object/dictionary-class.hh>
#include <object/float-class.hh>
#include <object/global-class.hh>
#include <object/hash-slots.hh>
#include <object/list-class.hh>
#include <object/object.hh>
#include <object/object-class.hh>
#include <object/urbi-exception.hh>

#include <runner/runner.hh>

namespace object
{

  /*---------.
  | Callers. |
  `---------*/

  rObject urbi_call(runner::Runner& r,
		    rObject self,
		    libport::Symbol msg,
		    objects_type args)
  {
    return urbi_call_function(r, self, self, msg, args);
  }

#define CHECK_ARG(N)				\
  if (!arg ## N)				\
    goto done;					\
  args.push_back(arg ## N)

  rObject urbi_call(runner::Runner& r,
		    rObject self,
		    libport::Symbol msg,
		    rObject arg1,
		    rObject arg2,
		    rObject arg3,
		    rObject arg4,
		    rObject arg5)
  {
    objects_type args;
    CHECK_ARG(1);
    CHECK_ARG(2);
    CHECK_ARG(3);
    CHECK_ARG(4);
    CHECK_ARG(5);
  done:
    return urbi_call_function(r, self, self, msg, args);
  }

#undef CHECK_ARG

  rObject urbi_call_function(runner::Runner& r, rObject self,
                             rObject owner, libport::Symbol msg)
  {
    objects_type args; // Call with no args.
    return urbi_call_function(r, self, owner, msg, args);
  }

  rObject urbi_call_function(runner::Runner& r, rObject self,
                             rObject owner, libport::Symbol msg,
                             objects_type args)
  {
    assertion(self);
    rObject message = owner->slot_get(msg);
    if (!message)
      throw LookupError(msg);
    args.insert(args.begin(), self);
    rObject res = r.apply(message, msg, args);
    assertion(res);
    return res;
  }

  /*---------.
  | Scopes.  |
  `---------*/

  typedef boost::optional<rObject> lookup_result;
  typedef boost::function1<lookup_result, rObject> lookup_action;

  rObject
  Object::make_scope(const rObject& parent)
  {
    rObject res = new object::Object();
    res->proto_add(parent);
    return res;
  }

  rObject
  Object::make_method_scope(const rObject& parent)
  {
    rObject res = Object::make_scope(parent ? parent : object_class);
    res->slot_set(SYMBOL(self), this);
    return res;
  }

  /*--------.
  | Slots.  |
  `--------*/

  rObject
  Object::urbi_protos_get ()
  {
    if (!protos_cache_)
    {
      rList protos = new List(*protos_);
      protos_cache_ = protos;
      delete protos_;
      protos_ = &protos->value_get ();
    }
    return protos_cache_;
  }

  void
  Object::protos_set (rObject l)
  {
    if (!protos_cache_)
      delete protos_;
    protos_cache_ = l;
    protos_ = &l.unsafe_cast<object::List>()->value_get ();
  }

  template <typename R>
  boost::optional<R>
  Object::lookup(boost::function1<boost::optional<R>, rObject> action,
		 objects_set_type& marks) const
  {
    if (!libport::mhas(marks, this))
    {
      marks.insert(this);
      // FIXME: rConstObject?
      boost::optional<R> res = action(const_cast<Object*>(this));
      if (res)
	return res;
      else
	foreach (const rObject& proto, protos_get())
	  if (boost::optional<R> res = proto->lookup(action, marks))
	    return res;
    }
    return boost::optional<R>();
  }

  template <typename R>
  boost::optional<R>
  Object::lookup(boost::function1<boost::optional<R>, rObject> action) const
  {
    objects_set_type marks;
    return lookup(action, marks);
  }

  namespace
  {
    class SlotLookup
    {
    public:
      lookup_result
      slot_lookup(rObject obj, const Object::key_type& k, bool value)
      {
	assertion(obj);
	if (rObject x = obj->own_slot_get(k))
	  return value ? x : obj;
	if (!fallback)
          if (rObject f = obj->own_slot_get(SYMBOL(fallback)))
            fallback = value ? f : obj;
	return boost::optional<rObject>();
      }
      rObject fallback;
    };
  }

  rObject
  Object::slot_locate(const key_type& k,
                      bool fallback, bool value) const
  {
    SlotLookup looker;
    lookup_action action =
      boost::bind(&SlotLookup::slot_lookup, &looker, _1, k, value);
    boost::optional<rObject> res = lookup(action);
    if (!res && fallback && looker.fallback)
      res = looker.fallback;
    if (res)
      return res.get();
    else
      return 0;
  }

  rObject
  Object::safe_slot_locate(const key_type& k, bool value) const
  {
    rObject r = slot_locate(k, true, value);
    if (!r)
      throw LookupError(k);
    return iassertion(r);
  }

  rObject
  Object::slot_get (const key_type& k, boost::optional<rObject> def) const
  {
    rObject value;
    if (def)
      value = slot_locate(k, true, true);
    else
      value = safe_slot_locate(k, true);
    if (value)
      return value;
    else
      return def.get();
  }

  Object&
  Object::slot_set(const key_type& k, rObject o)
  {
    if (!slots_.set(k, o))
      throw RedefinitionError(k);
    return *this;
  }

  Object&
  Object::slot_copy(const key_type& name, rObject from)
  {
    this->slot_set(name, from->slot_get(name));
    return *this;
  }

  void
  Object::slot_update(runner::Runner& r,
                      const key_type& k, rObject o,
                      bool hook)
  {
    // The owner of the updated slot
    rObject owner = safe_slot_locate(k);

    // If the current value in the slot to be written in has a slot
    // named 'updateHook', call it, passing the object owning the
    // slot, the slot name and the target.
    if (hook)
      if (rObject hook = owner->property_get(k, SYMBOL(updateHook)))
      {
        objects_type args = list_of (rObject(this)) (new String(k)) (o);
        rObject ret = r.apply(hook, SYMBOL(updateHook), args);
        // If the updateHook returned void, do nothing. Otherwise let
        // the slot be overwritten.
        if (ret == object::void_class)
          return;
      }
    // If return-value of hook is not void, write it to slot.
    own_slot_update(k, o);
  };

  void
  Object::own_slot_update (const key_type& k, rObject v)
  {
    slots_.update(k, v);
  }

  void
  Object::all_slots_copy(const rObject& other)
  {
    foreach (const Slots::slot_type& slot, other->slots_get())
      if (!own_slot_get(slot.first))
        slot_set(slot.first, slot.second);
  }

  /*-------------.
  | Properties.  |
  `-------------*/

  rDictionary
  Object::properties_get()
  {
    rDictionary res;
    if (slots_.has(SYMBOL(properties)))
      res = slots_.get(SYMBOL(properties)).unsafe_cast<Dictionary>();
    return res;
  }

  rDictionary
  Object::properties_get(const key_type& k)
  {
    // Forbid searching properties on nonexistent slots
    safe_slot_locate(k);

    rDictionary res;
    if (rDictionary ps = properties_get())
      res = libport::find0(ps->value_get(), k).unsafe_cast<Dictionary>();
    return res;
  }

  rObject
  Object::property_get(const key_type& k, const key_type& p)
  {
    rObject res;
    if (rDictionary ps = properties_get(k))
      res = libport::find0(ps->value_get(), p);
    return res;
  }

  bool
  Object::property_has(const key_type& k, const key_type& p)
  {
    // Forbid searching properties on nonexistent slots
    safe_slot_locate(k);

    if (rDictionary ps = properties_get(k))
      return libport::find0(ps->value_get(), p);
    return false;
  }

  rObject
  Object::property_set(const key_type& k, const key_type& p, rObject value)
  {
    // Forbid setting properties on nonexistent slots
    safe_slot_locate(k);

    // Make sure the object has a properties dictionary.
    rDictionary props = properties_get();
    if (!props)
    {
      props = new Dictionary();
      // This should die if there is a slot name "properties" which is
      // not a dictionary, which is what we want, don't we?
      slot_set(SYMBOL(properties), props);
    }

    // Make sure we have a dict for slot k.
    rDictionary prop =
      libport::find0(props->value_get(), k).unsafe_cast<Dictionary>();
    if (!prop)
    {
      prop = new Dictionary();
      props->value_get()[k] = prop;
    }

    prop->value_get()[p] = value;
    return value;
  }

  /*-----------.
  | Printing.  |
  `-----------*/

  std::ostream&
  Object::special_slots_dump (std::ostream& o, runner::Runner&) const
  {
    return o;
  }

  bool
  Object::operator< (const Object& rhs) const
  {
    return this < &rhs;
  }

  std::ostream&
  Object::id_dump(std::ostream& o, runner::Runner& r) const
  {
    rObject data = urbi_call(r, const_cast<Object*>(this), SYMBOL(id));
    type_check<String>(data, SYMBOL(id_dump));
    libport::Symbol s = data->as<String>()->value_get();
    return o << s;
  }

  std::ostream&
  Object::protos_dump(std::ostream& o, runner::Runner& runner) const
  {
    if (!protos_->empty())
    {
      o << "protos = ";
      bool tail = false;
      foreach (const rObject& p, *protos_)
      {
	if (tail++)
	  o << ", ";
	p->id_dump (o, runner);
      }
      o << libport::iendl;
    }
    return o;
  }

  std::ostream&
  Object::dump (std::ostream& o, runner::Runner& runner, int depth_max) const
  {
    id_dump(o, runner);
    /// Use xalloc/iword to store our current depth within the stream object.
    static const long idx = o.xalloc();
    long& current_depth = o.iword(idx);

    // Stop recursion at depth_max.
    if (current_depth > depth_max)
      return o << " <...>";
    ++current_depth;
    o << " {" << libport::incendl;
    protos_dump(o, runner);
    special_slots_dump (o, runner);
    foreach(const Slots::slot_type& s, slots_.container())
    {
      o << s.first << " = ";
      s.second->dump(o, runner, depth_max) << libport::iendl;
    }

    o << libport::decindent << '}';
    //We can not reuse current_depth variable above according to spec.
    o.iword(idx)--;
    return o;
  }

  std::ostream&
  Object::print(std::ostream& o, runner::Runner& runner) const
  {
    try
    {
      rObject s = urbi_call(runner, const_cast<Object*>(this), SYMBOL(asString));
      type_check<String>(s, SYMBOL(print));
      o << s->as<String>()->value_get();
      return o;
    }
    // Check if asString was found, especially for bootstrap: asString
    // is implemented in urbi/urbi.u, but print is called to show
    // result in the toplevel before its definition.
    catch (LookupError&)
    {
      // If no asString method is supplied, print the unique id
      return o << std::hex << this;
    }
  }

  bool
  is_a(const rObject& c, const rObject& p)
  {
    return for_all_protos(c, boost::lambda::_1 == p);
  }

  bool
  is_true(const rObject& o, const libport::Symbol& fun)
  {
    if (o == nil_class)
      return false;
    if (o->is_a<object::Float>())
      return o.unsafe_cast<object::Float>()->value_get();
    if (o == true_class)
      return true;
    if (o == false_class)
      return false;
    if (o == void_class)
      throw WrongArgumentType(fun);
    // FIXME: We will probably want to throw here.  This is related to
    // maybe calling asBool on every tested value.
    return true;
    // throw WrongArgumentType("Boolean", "Object", fun.name_get());
  }

} // namespace object
<|endoftext|>


<commit_before>#include <string.h>

#include <Arduino.h>

#if USE_I2C_LCD
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#else
#include <LiquidCrystal.h>
#endif  // USE_I2C_LCD

#include "pitches.h"
#include "mode.h"
#include "main.h"

const int kResetDelay = 2000;

// Pin numbers for buttons and LEDs are defined in the corresponding config:
// config_v[01].h
DECLARE_KBUTTON_PINS();
DECLARE_KLED_PINS();
DECLARE_KSPEAKER_PIN();

// Button debounce delay in milliseconds.
const unsigned long kDebounceMs = 100;

// GLOBAL STATE

#if USE_I2C_LCD
// An I2C-connected 16x2 character LCD screen.
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7);
#else
LiquidCrystal lcd(/*rs=*/14, /*en=*/15, /*d0=*/16, /*d1=*/17, /*d2=*/18,
                  /*d3=*/19);
#endif

#if USE_LAMP
DECLARE_KLAMP_PIN();
#endif

SelectMode selectMode;

// Selected game mode.
Mode *mode = &selectMode;

// Button state, true means pressed.
bool buttons[BUTTON_COUNT] = { false };
// Button state before the latest update.
bool buttonsBefore[BUTTON_COUNT] = { false };

// For each button, when it was last time pressed in milliseconds since device
// start.
unsigned long lastPressedMs[BUTTON_COUNT] = {0};

char caption[DISPLAY_SIZE + 1];
char lastLeft[DISPLAY_SIZE + 1];
char lastRight[DISPLAY_SIZE + 1];
char lastMiddle[DISPLAY_SIZE + 1];
char lastCaption[DISPLAY_SIZE + 1];
bool lastLeds[PLAYER_COUNT];
bool resetStarted = false;
unsigned long resetStartTime;

void setup() {
  for (const int buttonPin : kButtonPins) {
    xPinMode(buttonPin, INPUT_PULLUP);
  }
  for (const int ledPin : kLedPins) {
    xPinMode(ledPin, OUTPUT);
    xDigitalWrite(ledPin, LOW);
  }
  xPinMode(kSpeakerPin, OUTPUT);

#if USE_LAMP
  xPinMode(kLampPin, OUTPUT);
#endif

  // Initialize the screen.
  lcd.begin(/*cols=*/16, /*rows=*/2);
#if USE_I2C_LCD
  lcd.setBacklightPin(3, POSITIVE);  // TODO: Use a constant.
  lcd.setBacklight(HIGH);
#endif

  mode->init();
  tone(kSpeakerPin, NOTE_A7, 300/*ms*/);
}

void updateScreenAndLeds() {
  caption[0] = '\0';
  mode->getCaption(caption, sizeof(caption));
  const char* left = mode->getLabel(BUTTON_RESET);
  const char* right = mode->getLabel(BUTTON_START);
  const char* middle = 0;
  if (SHOW_SCORES != 0) {
    middle = mode->getLabel(BUTTON_CONTROL_2);
  }
  if (strcmp(lastCaption, caption) != 0 ||
      strcmp(lastLeft, left) != 0 ||
      strcmp(lastRight, right) != 0 ||
      (SHOW_SCORES != 0 && strcmp(lastMiddle, middle) != 0)) {
    lcd.clear();
    lcd.print(caption);
    lcd.setCursor(/*row=*/0, /*col=*/1);
    // Print button functions on the lower line of the screen.
    if (SHOW_SCORES == 0) {
      lcd.print(left);
      const int spaces = DISPLAY_SIZE - strlen(left) - strlen(right);
      for (int i = 0; i < spaces; ++i) {
        lcd.print(' ');
      }
      lcd.print(right);
    } else {
      lcd.print(left);
      const int spaces = DISPLAY_SIZE - strlen(left) - strlen(right) - strlen(middle);
      for (int i = 0; i < spaces / 2; ++i) {
        lcd.print(' ');
      }
      lcd.print(middle);
      for (int i = 0; i < (spaces + 1) / 2; ++i) {
        lcd.print(' ');
      }
      lcd.print(right);
      strcpy(lastMiddle, middle);
    }
    strcpy(lastLeft, left);
    strcpy(lastRight, right);
    strcpy(lastCaption, caption);
  }
  for (int i = BUTTON_PLAYER_1; i <= LAST_PLAYER_BUTTON; i++) {
    xDigitalWrite(kLedPins[i], mode->getLedState(i) ? HIGH : LOW);
  }
#if USE_LAMP
  xDigitalWrite(kLampPin, mode->getLampState() ? HIGH : LOW);
#endif
}

void loop() {
  unsigned long now = millis();
  // Read all buttons and save their state in a global array.
  for (int i = 0; i < BUTTON_COUNT; ++i) {
    buttonsBefore[i] = buttons[i];
    // Ignore the button state changes if it was pressed less than kDebounceMs
    // milliseconds ago to account for contact bouncing.
    if (now - lastPressedMs[i] > kDebounceMs) {
      // The buttons pins are active LOW.
      buttons[i] = (xDigitalRead(kButtonPins[i]) == LOW);
    }
  }
  if (xDigitalRead(kButtonPins[BUTTON_RESET]) == LOW &&
      xDigitalRead(kButtonPins[BUTTON_START]) == LOW) {
    if (resetStarted && millis() - resetStartTime > kResetDelay) {
      mode = &selectMode;
      mode->init();
      return;
    }
    if (!resetStarted) {
      resetStarted = true;
      resetStartTime = millis();
    }
  }
  mode->update();
  updateScreenAndLeds();
}

bool isPlayerPressed(int playerId) {
  return buttons[playerId] && !buttonsBefore[playerId];
}

bool isControlPressed(int buttonId) {
  return buttons[buttonId] && !buttonsBefore[buttonId];
}

void playStartSound() {
  tone(kSpeakerPin, NOTE_DS6, 300/*ms*/);
}

void playTimeSound() {
  tone(kSpeakerPin, NOTE_DS6, 1000/*ms*/);
}

void playResetSound() {
  tone(kSpeakerPin, NOTE_D6, 1000/*ms*/);
}

void playPlayerSound() {
  tone(kSpeakerPin, NOTE_F6, 300/*ms*/);
}

void playTimerSound() {
  tone(kSpeakerPin, NOTE_F6, 100/*ms*/);
}

void playCorrectSound() {
  tone(kSpeakerPin, NOTE_C6, 300/*ms*/);
}

void playFalseStartSound() {
  tone(kSpeakerPin, NOTE_G6, 500/*ms*/);
}

void playAttentionSound() {
  tone(kSpeakerPin, NOTE_F6, 300/*ms*/);
}

void setMode(Mode *newMode) {
  mode = newMode;
  mode->init();
}

int xDigitalRead(uint8_t pin) {
  if (pin == kPinPB6) {
    return (PINB & _BV(PINB6)) ? HIGH : LOW;
  } else if (pin == kPinPB7) {
    return (PINB & _BV(PINB7)) ? HIGH : LOW;
  } else {
    return digitalRead(pin);
  }
}

void xDigitalWrite(uint8_t pin, uint8_t val) {
  uint8_t mask;
  if (pin == kPinPB6) {
    mask = _BV(PORTB6);
  } else if (pin == kPinPB7) {
    mask = _BV(PORTB7);
  } else {
    digitalWrite(pin, val);
    return;
  }
  if (val == HIGH) {
    PORTB |= mask;
  } else {
    PORTB &= ~mask;
  }
}

void xPinMode(uint8_t pin, uint8_t mode) {
  uint8_t mask;
  if (pin == kPinPB6) {
    mask = _BV(PORTB6);
  } else if (pin == kPinPB7) {
    mask = _BV(PORTB7);
  } else {
    pinMode(pin, mode);
    return;
  }
  if (mode == INPUT) {
    DDRB &= ~mask;
    PORTB &= ~mask;
  } else if (mode == INPUT_PULLUP) {
    DDRB &= ~mask;
    PORTB |= mask;
  } else {
    DDRB |= mask;
  }
}
<commit_msg>update lastPressedMs<commit_after>#include <string.h>

#include <Arduino.h>

#if USE_I2C_LCD
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#else
#include <LiquidCrystal.h>
#endif  // USE_I2C_LCD

#include "pitches.h"
#include "mode.h"
#include "main.h"

const int kResetDelay = 2000;

// Pin numbers for buttons and LEDs are defined in the corresponding config:
// config_v[01].h
DECLARE_KBUTTON_PINS();
DECLARE_KLED_PINS();
DECLARE_KSPEAKER_PIN();

// Button debounce delay in milliseconds.
const unsigned long kDebounceMs = 100;

// GLOBAL STATE

#if USE_I2C_LCD
// An I2C-connected 16x2 character LCD screen.
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7);
#else
LiquidCrystal lcd(/*rs=*/14, /*en=*/15, /*d0=*/16, /*d1=*/17, /*d2=*/18,
                  /*d3=*/19);
#endif

#if USE_LAMP
DECLARE_KLAMP_PIN();
#endif

SelectMode selectMode;

// Selected game mode.
Mode *mode = &selectMode;

// Button state, true means pressed.
bool buttons[BUTTON_COUNT] = { false };
// Button state before the latest update.
bool buttonsBefore[BUTTON_COUNT] = { false };

// For each button, when it was last time pressed in milliseconds since device
// start.
unsigned long lastPressedMs[BUTTON_COUNT] = {0};

char caption[DISPLAY_SIZE + 1];
char lastLeft[DISPLAY_SIZE + 1];
char lastRight[DISPLAY_SIZE + 1];
char lastMiddle[DISPLAY_SIZE + 1];
char lastCaption[DISPLAY_SIZE + 1];
bool lastLeds[PLAYER_COUNT];
bool resetStarted = false;
unsigned long resetStartTime;

void setup() {
  for (const int buttonPin : kButtonPins) {
    xPinMode(buttonPin, INPUT_PULLUP);
  }
  for (const int ledPin : kLedPins) {
    xPinMode(ledPin, OUTPUT);
    xDigitalWrite(ledPin, LOW);
  }
  xPinMode(kSpeakerPin, OUTPUT);

#if USE_LAMP
  xPinMode(kLampPin, OUTPUT);
#endif

  // Initialize the screen.
  lcd.begin(/*cols=*/16, /*rows=*/2);
#if USE_I2C_LCD
  lcd.setBacklightPin(3, POSITIVE);  // TODO: Use a constant.
  lcd.setBacklight(HIGH);
#endif

  mode->init();
  tone(kSpeakerPin, NOTE_A7, 300/*ms*/);
}

void updateScreenAndLeds() {
  caption[0] = '\0';
  mode->getCaption(caption, sizeof(caption));
  const char* left = mode->getLabel(BUTTON_RESET);
  const char* right = mode->getLabel(BUTTON_START);
  const char* middle = 0;
  if (SHOW_SCORES != 0) {
    middle = mode->getLabel(BUTTON_CONTROL_2);
  }
  if (strcmp(lastCaption, caption) != 0 ||
      strcmp(lastLeft, left) != 0 ||
      strcmp(lastRight, right) != 0 ||
      (SHOW_SCORES != 0 && strcmp(lastMiddle, middle) != 0)) {
    lcd.clear();
    lcd.print(caption);
    lcd.setCursor(/*row=*/0, /*col=*/1);
    // Print button functions on the lower line of the screen.
    if (SHOW_SCORES == 0) {
      lcd.print(left);
      const int spaces = DISPLAY_SIZE - strlen(left) - strlen(right);
      for (int i = 0; i < spaces; ++i) {
        lcd.print(' ');
      }
      lcd.print(right);
    } else {
      lcd.print(left);
      const int spaces = DISPLAY_SIZE - strlen(left) - strlen(right) - strlen(middle);
      for (int i = 0; i < spaces / 2; ++i) {
        lcd.print(' ');
      }
      lcd.print(middle);
      for (int i = 0; i < (spaces + 1) / 2; ++i) {
        lcd.print(' ');
      }
      lcd.print(right);
      strcpy(lastMiddle, middle);
    }
    strcpy(lastLeft, left);
    strcpy(lastRight, right);
    strcpy(lastCaption, caption);
  }
  for (int i = BUTTON_PLAYER_1; i <= LAST_PLAYER_BUTTON; i++) {
    xDigitalWrite(kLedPins[i], mode->getLedState(i) ? HIGH : LOW);
  }
#if USE_LAMP
  xDigitalWrite(kLampPin, mode->getLampState() ? HIGH : LOW);
#endif
}

void loop() {
  unsigned long now = millis();
  // Read all buttons and save their state in a global array.
  for (int i = 0; i < BUTTON_COUNT; ++i) {
    buttonsBefore[i] = buttons[i];
    // Ignore the button state changes if it was pressed less than kDebounceMs
    // milliseconds ago to account for contact bouncing.
    if (now - lastPressedMs[i] > kDebounceMs) {
      // The buttons pins are active LOW.
      if (xDigitalRead(kButtonPins[i]) == LOW) {
        buttons[i] = true;
        lastPressedMs[i] = now;
      } else {
        buttons[i] = false;
      }
    }
  }
  if (xDigitalRead(kButtonPins[BUTTON_RESET]) == LOW &&
      xDigitalRead(kButtonPins[BUTTON_START]) == LOW) {
    if (resetStarted && millis() - resetStartTime > kResetDelay) {
      mode = &selectMode;
      mode->init();
      return;
    }
    if (!resetStarted) {
      resetStarted = true;
      resetStartTime = millis();
    }
  }
  mode->update();
  updateScreenAndLeds();
}

bool isPlayerPressed(int playerId) {
  return buttons[playerId] && !buttonsBefore[playerId];
}

bool isControlPressed(int buttonId) {
  return buttons[buttonId] && !buttonsBefore[buttonId];
}

void playStartSound() {
  tone(kSpeakerPin, NOTE_DS6, 300/*ms*/);
}

void playTimeSound() {
  tone(kSpeakerPin, NOTE_DS6, 1000/*ms*/);
}

void playResetSound() {
  tone(kSpeakerPin, NOTE_D6, 1000/*ms*/);
}

void playPlayerSound() {
  tone(kSpeakerPin, NOTE_F6, 300/*ms*/);
}

void playTimerSound() {
  tone(kSpeakerPin, NOTE_F6, 100/*ms*/);
}

void playCorrectSound() {
  tone(kSpeakerPin, NOTE_C6, 300/*ms*/);
}

void playFalseStartSound() {
  tone(kSpeakerPin, NOTE_G6, 500/*ms*/);
}

void playAttentionSound() {
  tone(kSpeakerPin, NOTE_F6, 300/*ms*/);
}

void setMode(Mode *newMode) {
  mode = newMode;
  mode->init();
}

int xDigitalRead(uint8_t pin) {
  if (pin == kPinPB6) {
    return (PINB & _BV(PINB6)) ? HIGH : LOW;
  } else if (pin == kPinPB7) {
    return (PINB & _BV(PINB7)) ? HIGH : LOW;
  } else {
    return digitalRead(pin);
  }
}

void xDigitalWrite(uint8_t pin, uint8_t val) {
  uint8_t mask;
  if (pin == kPinPB6) {
    mask = _BV(PORTB6);
  } else if (pin == kPinPB7) {
    mask = _BV(PORTB7);
  } else {
    digitalWrite(pin, val);
    return;
  }
  if (val == HIGH) {
    PORTB |= mask;
  } else {
    PORTB &= ~mask;
  }
}

void xPinMode(uint8_t pin, uint8_t mode) {
  uint8_t mask;
  if (pin == kPinPB6) {
    mask = _BV(PORTB6);
  } else if (pin == kPinPB7) {
    mask = _BV(PORTB7);
  } else {
    pinMode(pin, mode);
    return;
  }
  if (mode == INPUT) {
    DDRB &= ~mask;
    PORTB &= ~mask;
  } else if (mode == INPUT_PULLUP) {
    DDRB &= ~mask;
    PORTB |= mask;
  } else {
    DDRB |= mask;
  }
}
<|endoftext|>


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

#include "runtime/notification_manager.h"

#include <notification.h>
#include <memory>

#include "common/logger.h"

namespace wrt {

NotificationManager* NotificationManager::GetInstance() {
  static NotificationManager instance;
  return &instance;
}

NotificationManager::NotificationManager() {
}

bool NotificationManager::Show(uint64_t tag,
                               const std::string& title,
                               const std::string& body,
                               const std::string& icon_path) {
  auto found = keymapper_.find(tag);
  if (found != keymapper_.end()) {
    Hide(tag);
  }

  notification_h noti_h = NULL;
  int ret = NOTIFICATION_ERROR_NONE;
  noti_h = notification_new(
      NOTIFICATION_TYPE_NOTI,
      NOTIFICATION_GROUP_ID_DEFAULT,
      NOTIFICATION_PRIV_ID_NONE);
  if (noti_h == NULL) {
    LOGGER(ERROR) << "Can't create notification handle";
    return false;
  }

  std::unique_ptr<std::remove_pointer<notification_h>::type,
                  decltype(notification_free)*>
      auto_release {noti_h, notification_free};

  // set notification title
  ret = notification_set_text(
      noti_h,
      NOTIFICATION_TEXT_TYPE_TITLE,
      title.c_str(),
      NULL,
      NOTIFICATION_VARIABLE_TYPE_NONE);
  if (ret != NOTIFICATION_ERROR_NONE) {
    LOGGER(ERROR) << "Can't set title";
    return false;
  }

  // set notification content
  ret = notification_set_text(
      noti_h,
      NOTIFICATION_TEXT_TYPE_CONTENT,
      body.c_str(),
      NULL,
      NOTIFICATION_VARIABLE_TYPE_NONE);
  if (ret != NOTIFICATION_ERROR_NONE) {
    LOGGER(ERROR) << "Can't set content";
    return false;
  }

  if (!icon_path.empty()) {
    ret = notification_set_image(
        noti_h,
        NOTIFICATION_IMAGE_TYPE_ICON,
        icon_path.c_str());
    if (ret != NOTIFICATION_ERROR_NONE) {
      LOGGER(ERROR) << "Can't set icon";
      return false;
    }
  }

  // insert notification
  int platform_key = NOTIFICATION_PRIV_ID_NONE;
  ret = notification_insert(noti_h, &platform_key);
  if (ret != NOTIFICATION_ERROR_NONE) {
    LOGGER(ERROR) << "Can't insert notification";
    return false;
  }
  keymapper_[tag] = platform_key;
  return true;
}

bool NotificationManager::Hide(uint64_t tag) {
  auto found = keymapper_.find(tag);
  if (found == keymapper_.end()) {
    LOGGER(ERROR) << "Can't find notification";
    return false;
  }
  notification_delete_by_priv_id(NULL,
                                 NOTIFICATION_TYPE_NOTI,
                                 found->second);
  keymapper_.erase(found);
  return true;
}

}  // namespace wrt
<commit_msg>Revert "Revert "Revert "Revert "Update Notification API""""<commit_after>/*
 * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

#include "runtime/notification_manager.h"

#include <notification.h>
#include <notification_internal.h>

#include <memory>

#include "common/logger.h"

namespace wrt {

NotificationManager* NotificationManager::GetInstance() {
  static NotificationManager instance;
  return &instance;
}

NotificationManager::NotificationManager() {
}

bool NotificationManager::Show(uint64_t tag,
                               const std::string& title,
                               const std::string& body,
                               const std::string& icon_path) {
  auto found = keymapper_.find(tag);
  if (found != keymapper_.end()) {
    Hide(tag);
  }

  notification_h noti_h = NULL;
  int ret = NOTIFICATION_ERROR_NONE;
  noti_h = notification_new(
      NOTIFICATION_TYPE_NOTI,
      NOTIFICATION_GROUP_ID_DEFAULT,
      NOTIFICATION_PRIV_ID_NONE);
  if (noti_h == NULL) {
    LOGGER(ERROR) << "Can't create notification handle";
    return false;
  }

  std::unique_ptr<std::remove_pointer<notification_h>::type,
                  decltype(notification_free)*>
      auto_release {noti_h, notification_free};

  // set notification title
  ret = notification_set_text(
      noti_h,
      NOTIFICATION_TEXT_TYPE_TITLE,
      title.c_str(),
      NULL,
      NOTIFICATION_VARIABLE_TYPE_NONE);
  if (ret != NOTIFICATION_ERROR_NONE) {
    LOGGER(ERROR) << "Can't set title";
    return false;
  }

  // set notification content
  ret = notification_set_text(
      noti_h,
      NOTIFICATION_TEXT_TYPE_CONTENT,
      body.c_str(),
      NULL,
      NOTIFICATION_VARIABLE_TYPE_NONE);
  if (ret != NOTIFICATION_ERROR_NONE) {
    LOGGER(ERROR) << "Can't set content";
    return false;
  }

  if (!icon_path.empty()) {
    ret = notification_set_image(
        noti_h,
        NOTIFICATION_IMAGE_TYPE_ICON,
        icon_path.c_str());
    if (ret != NOTIFICATION_ERROR_NONE) {
      LOGGER(ERROR) << "Can't set icon";
      return false;
    }
  }

  // insert notification
  int platform_key = NOTIFICATION_PRIV_ID_NONE;
  ret = notification_insert(noti_h, &platform_key);
  if (ret != NOTIFICATION_ERROR_NONE) {
    LOGGER(ERROR) << "Can't insert notification";
    return false;
  }
  keymapper_[tag] = platform_key;
  return true;
}

bool NotificationManager::Hide(uint64_t tag) {
  auto found = keymapper_.find(tag);
  if (found == keymapper_.end()) {
    LOGGER(ERROR) << "Can't find notification";
    return false;
  }
  notification_delete_by_priv_id(NULL,
                                 NOTIFICATION_TYPE_NOTI,
                                 found->second);
  keymapper_.erase(found);
  return true;
}

}  // namespace wrt
<|endoftext|>


<commit_before>// Begin CVS Header
//   $Source: /Volumes/Home/Users/shoops/cvs/copasi_dev/copasi/function/CEvaluationNodeNumber.cpp,v $
//   $Revision: 1.29 $
//   $Name:  $
//   $Author: shoops $
//   $Date: 2009/02/20 17:56:22 $
// End CVS Header

// Copyright (C) 2008 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., EML Research, gGmbH, University of Heidelberg,
// and The University of Manchester.
// All rights reserved.

// Copyright (C) 2001 - 2007 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc. and EML Research, gGmbH.
// All rights reserved.

#include <sstream>
#include <stdlib.h>

#include "copasi.h"
#include "CEvaluationNode.h"

#include "sbml/math/ASTNode.h"

CEvaluationNodeNumber::CEvaluationNodeNumber():
    CEvaluationNode(CEvaluationNode::INVALID, "")
{mPrecedence = PRECEDENCE_NUMBER;}

CEvaluationNodeNumber::CEvaluationNodeNumber(const SubType & subType,
    const Data & data):
    CEvaluationNode((Type) (CEvaluationNode::NUMBER | subType), data)
{
  char * end;
  const char * str = mData.c_str();

  switch (subType)
    {
    case DOUBLE:
    case INTEGER:
    case ENOTATION:
      mValue = strtod(str, NULL);
      break;

    case RATIONALE:
      str++; // Skip the '('
      mValue = strtod(str, &end);
      end++; // Skip the '/'
      mValue /= strtod(end, NULL);
      break;

    case INVALID:
      fatalError();
      break;
    }

  mPrecedence = PRECEDENCE_NUMBER;
}

CEvaluationNodeNumber::CEvaluationNodeNumber(const CEvaluationNodeNumber & src):
    CEvaluationNode(src)
{}

CEvaluationNodeNumber::~CEvaluationNodeNumber() {}

#ifdef WIN32
// warning C4056: overflow in floating-point constant arithmetic
// warning C4756: overflow in constant arithmetic
# pragma warning (disable: 4056 4756)
#endif

CEvaluationNode* CEvaluationNodeNumber::createNodeFromASTTree(const ASTNode& node)
{
  ASTNodeType_t type = node.getType();
  std::stringstream ss;
  SubType subType;
  std::string data = "";
  CEvaluationNode* pNode = NULL;
  switch (type)
    {
    case AST_INTEGER:
      subType = INTEGER;
      if (node.getInteger() < 0)
        {
          pNode = new CEvaluationNodeFunction(CEvaluationNodeFunction::MINUS, "-");

          ss << abs(node.getInteger());
          data = ss.str();
          pNode->addChild(new CEvaluationNodeNumber(subType, data));
        }
      else
        {
          ss << node.getInteger();
          data = ss.str();
          pNode = new CEvaluationNodeNumber(subType, data);
        }
      break;
    case AST_REAL:
      subType = DOUBLE;
      if (node.getReal() == (2*DBL_MAX))
        {
          pNode = new CEvaluationNodeConstant(CEvaluationNodeConstant::_INFINITY, "INFINITY");
        }
      else if (node.getReal() == (-2*DBL_MAX))
        {
          pNode = new CEvaluationNodeFunction(CEvaluationNodeFunction::MINUS, "-");
          pNode->addChild(new CEvaluationNodeConstant(CEvaluationNodeConstant::_INFINITY, "INFINITY"));
        }
      else if (isnan(node.getReal()))
        {
          pNode = new CEvaluationNodeConstant(CEvaluationNodeConstant::_NaN, "NAN");
        }
      else if (node.getReal() < 0.0)
        {
          pNode = new CEvaluationNodeFunction(CEvaluationNodeFunction::MINUS, "-");

          ss << fabs(node.getReal());
          data = ss.str();
          pNode->addChild(new CEvaluationNodeNumber(subType, data));
        }
      else
        {
          ss << node.getReal();
          data = ss.str();
          pNode = new CEvaluationNodeNumber(subType, data);
        }
      break;
    case AST_REAL_E:
      subType = ENOTATION;
      if (node.getReal() == (2*DBL_MAX))
        {
          pNode = new CEvaluationNodeConstant(CEvaluationNodeConstant::_INFINITY, "INFINITY");
        }
      else if (node.getReal() == (-2*DBL_MAX))
        {
          pNode = new CEvaluationNodeFunction(CEvaluationNodeFunction::MINUS, "-");
          pNode->addChild(new CEvaluationNodeConstant(CEvaluationNodeConstant::_INFINITY, "INFINITY"));
        }
      else if (isnan(node.getReal()))
        {
          pNode = new CEvaluationNodeConstant(CEvaluationNodeConstant::_NaN, "NAN");
        }
      else if (node.getReal() < 0.0)
        {
          pNode = new CEvaluationNodeFunction(CEvaluationNodeFunction::MINUS, "-");

          ss << fabs(node.getReal());
          data = ss.str();
          pNode->addChild(new CEvaluationNodeNumber(subType, data));
        }
      else
        {
          ss << node.getReal();
          data = ss.str();
          pNode = new CEvaluationNodeNumber(subType, data);
        }
      break;
    case AST_RATIONAL:
      subType = RATIONALE;
      if (node.getReal() < 0.0) // getReal returns the value of the node
        {
          pNode = new CEvaluationNodeFunction(CEvaluationNodeFunction::MINUS, "-");

          ss << "(" << abs(node.getNumerator()) << "/" << abs(node.getDenominator()) << ")";
          data = ss.str();
          pNode->addChild(new CEvaluationNodeNumber(subType, data));
        }
      else
        {
          ss << "(" << node.getNumerator() << "/" << node.getDenominator() << ")";
          data = ss.str();
          pNode = new CEvaluationNodeNumber(subType, data);
        }
      break;
    default:
      subType = INVALID;
      break;
    }
  return pNode;
}

#ifdef WIN32
# pragma warning (default: 4056 4756)
#endif

ASTNode* CEvaluationNodeNumber::toAST(const CCopasiDataModel* /* pDataModel */) const
  {
    SubType subType = (SubType)CEvaluationNode::subType(this->getType());
    ASTNode* node = new ASTNode();
    double num1;
    double num2;
    char* end;
    const char * str = mData.c_str();

    switch (subType)
      {
      case DOUBLE:
        node->setType(AST_REAL);
        node->setValue(this->value());
        break;
      case INTEGER:
        node->setType(AST_INTEGER);
        node->setValue((long)this->value());
        break;
      case ENOTATION:
        node->setType(AST_REAL_E);
        num2 = floor(log10(this->value()));
        num1 = pow(10.0, log10(this->value()) - num2);
        node->setValue(num1, (long)num2);
        break;
      case RATIONALE:
        node->setType(AST_RATIONAL);
        str++; // Skip the '('
        num1 = strtod(str, &end);
        end++; // Skip the '/'
        num2 = strtod(end, NULL);
        node->setValue((long)num1, (long)num2);
        break;
      case INVALID:
        break;
      }
    return node;
  }

#include "utilities/copasimathml.h"

void CEvaluationNodeNumber::writeMathML(std::ostream & out,
                                        const std::vector<std::vector<std::string> > & /* env */,
                                        bool /* expand */,
                                        unsigned C_INT32 l) const
  {
    out << SPC(l) << "<mn>" << mData << "</mn>" << std::endl;
    //or use mValue instead?
  }
<commit_msg>try a fix for #1262. use istringstream instead of strtod<commit_after>// Begin CVS Header
//   $Source: /Volumes/Home/Users/shoops/cvs/copasi_dev/copasi/function/CEvaluationNodeNumber.cpp,v $
//   $Revision: 1.30 $
//   $Name:  $
//   $Author: ssahle $
//   $Date: 2009/07/17 14:33:12 $
// End CVS Header

// Copyright (C) 2008 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., EML Research, gGmbH, University of Heidelberg,
// and The University of Manchester.
// All rights reserved.

// Copyright (C) 2001 - 2007 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc. and EML Research, gGmbH.
// All rights reserved.

#include <sstream>
#include <stdlib.h>

#include "copasi.h"
#include "CEvaluationNode.h"

#include "sbml/math/ASTNode.h"

CEvaluationNodeNumber::CEvaluationNodeNumber():
    CEvaluationNode(CEvaluationNode::INVALID, "")
{mPrecedence = PRECEDENCE_NUMBER;}

CEvaluationNodeNumber::CEvaluationNodeNumber(const SubType & subType,
    const Data & data):
    CEvaluationNode((Type)(CEvaluationNode::NUMBER | subType), data)
{
  char * end;
  const char * str = mData.c_str();

  switch (subType)
    {
      case DOUBLE:
      case INTEGER:
      case ENOTATION:
      {
        //mValue = strtod(str, NULL);
        std::istringstream in;
        in.imbue(std::locale::classic());
        in.str(str);
        in >> mValue;
      }
      break;

      case RATIONALE:
        str++; // Skip the '('
        mValue = strtod(str, &end);
        end++; // Skip the '/'
        mValue /= strtod(end, NULL);
        break;

      case INVALID:
        fatalError();
        break;
    }

  mPrecedence = PRECEDENCE_NUMBER;
}

CEvaluationNodeNumber::CEvaluationNodeNumber(const CEvaluationNodeNumber & src):
    CEvaluationNode(src)
{}

CEvaluationNodeNumber::~CEvaluationNodeNumber() {}

#ifdef WIN32
// warning C4056: overflow in floating-point constant arithmetic
// warning C4756: overflow in constant arithmetic
# pragma warning (disable: 4056 4756)
#endif

CEvaluationNode* CEvaluationNodeNumber::createNodeFromASTTree(const ASTNode& node)
{
  ASTNodeType_t type = node.getType();
  std::stringstream ss;
  SubType subType;
  std::string data = "";
  CEvaluationNode* pNode = NULL;

  switch (type)
    {
      case AST_INTEGER:
        subType = INTEGER;

        if (node.getInteger() < 0)
          {
            pNode = new CEvaluationNodeFunction(CEvaluationNodeFunction::MINUS, "-");

            ss << abs(node.getInteger());
            data = ss.str();
            pNode->addChild(new CEvaluationNodeNumber(subType, data));
          }
        else
          {
            ss << node.getInteger();
            data = ss.str();
            pNode = new CEvaluationNodeNumber(subType, data);
          }

        break;
      case AST_REAL:
        subType = DOUBLE;

        if (node.getReal() == (2*DBL_MAX))
          {
            pNode = new CEvaluationNodeConstant(CEvaluationNodeConstant::_INFINITY, "INFINITY");
          }
        else if (node.getReal() == (-2*DBL_MAX))
          {
            pNode = new CEvaluationNodeFunction(CEvaluationNodeFunction::MINUS, "-");
            pNode->addChild(new CEvaluationNodeConstant(CEvaluationNodeConstant::_INFINITY, "INFINITY"));
          }
        else if (isnan(node.getReal()))
          {
            pNode = new CEvaluationNodeConstant(CEvaluationNodeConstant::_NaN, "NAN");
          }
        else if (node.getReal() < 0.0)
          {
            pNode = new CEvaluationNodeFunction(CEvaluationNodeFunction::MINUS, "-");

            ss << fabs(node.getReal());
            data = ss.str();
            pNode->addChild(new CEvaluationNodeNumber(subType, data));
          }
        else
          {
            ss << node.getReal();
            data = ss.str();
            pNode = new CEvaluationNodeNumber(subType, data);
          }

        break;
      case AST_REAL_E:
        subType = ENOTATION;

        if (node.getReal() == (2*DBL_MAX))
          {
            pNode = new CEvaluationNodeConstant(CEvaluationNodeConstant::_INFINITY, "INFINITY");
          }
        else if (node.getReal() == (-2*DBL_MAX))
          {
            pNode = new CEvaluationNodeFunction(CEvaluationNodeFunction::MINUS, "-");
            pNode->addChild(new CEvaluationNodeConstant(CEvaluationNodeConstant::_INFINITY, "INFINITY"));
          }
        else if (isnan(node.getReal()))
          {
            pNode = new CEvaluationNodeConstant(CEvaluationNodeConstant::_NaN, "NAN");
          }
        else if (node.getReal() < 0.0)
          {
            pNode = new CEvaluationNodeFunction(CEvaluationNodeFunction::MINUS, "-");

            ss << fabs(node.getReal());
            data = ss.str();
            pNode->addChild(new CEvaluationNodeNumber(subType, data));
          }
        else
          {
            ss << node.getReal();
            data = ss.str();
            pNode = new CEvaluationNodeNumber(subType, data);
          }

        break;
      case AST_RATIONAL:
        subType = RATIONALE;

        if (node.getReal() < 0.0) // getReal returns the value of the node
          {
            pNode = new CEvaluationNodeFunction(CEvaluationNodeFunction::MINUS, "-");

            ss << "(" << abs(node.getNumerator()) << "/" << abs(node.getDenominator()) << ")";
            data = ss.str();
            pNode->addChild(new CEvaluationNodeNumber(subType, data));
          }
        else
          {
            ss << "(" << node.getNumerator() << "/" << node.getDenominator() << ")";
            data = ss.str();
            pNode = new CEvaluationNodeNumber(subType, data);
          }

        break;
      default:
        subType = INVALID;
        break;
    }

  return pNode;
}

#ifdef WIN32
# pragma warning (default: 4056 4756)
#endif

ASTNode* CEvaluationNodeNumber::toAST(const CCopasiDataModel* /* pDataModel */) const
{
  SubType subType = (SubType)CEvaluationNode::subType(this->getType());
  ASTNode* node = new ASTNode();
  double num1;
  double num2;
  char* end;
  const char * str = mData.c_str();

  switch (subType)
    {
      case DOUBLE:
        node->setType(AST_REAL);
        node->setValue(this->value());
        break;
      case INTEGER:
        node->setType(AST_INTEGER);
        node->setValue((long)this->value());
        break;
      case ENOTATION:
        node->setType(AST_REAL_E);
        num2 = floor(log10(this->value()));
        num1 = pow(10.0, log10(this->value()) - num2);
        node->setValue(num1, (long)num2);
        break;
      case RATIONALE:
        node->setType(AST_RATIONAL);
        str++; // Skip the '('
        num1 = strtod(str, &end);
        end++; // Skip the '/'
        num2 = strtod(end, NULL);
        node->setValue((long)num1, (long)num2);
        break;
      case INVALID:
        break;
    }

  return node;
}

#include "utilities/copasimathml.h"

void CEvaluationNodeNumber::writeMathML(std::ostream & out,
                                        const std::vector<std::vector<std::string> > & /* env */,
                                        bool /* expand */,
                                        unsigned C_INT32 l) const
{
  out << SPC(l) << "<mn>" << mData << "</mn>" << std::endl;
  //or use mValue instead?
}
<|endoftext|>


<commit_before>// Begin CVS Header
//   $Source: /Volumes/Home/Users/shoops/cvs/copasi_dev/copasi/function/CEvaluationNodeNumber.cpp,v $
//   $Revision: 1.28 $
//   $Name:  $
//   $Author: gauges $
//   $Date: 2009/02/19 15:37:57 $
// End CVS Header

// Copyright (C) 2008 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., EML Research, gGmbH, University of Heidelberg,
// and The University of Manchester.
// All rights reserved.

// Copyright (C) 2001 - 2007 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc. and EML Research, gGmbH.
// All rights reserved.

#include <sstream>
#include <stdlib.h>

#include "copasi.h"
#include "CEvaluationNode.h"

#include "sbml/math/ASTNode.h"

CEvaluationNodeNumber::CEvaluationNodeNumber():
    CEvaluationNode(CEvaluationNode::INVALID, "")
{mPrecedence = PRECEDENCE_NUMBER;}

CEvaluationNodeNumber::CEvaluationNodeNumber(const SubType & subType,
    const Data & data):
    CEvaluationNode((Type) (CEvaluationNode::NUMBER | subType), data)
{
  char * end;
  const char * str = mData.c_str();

  switch (subType)
    {
    case DOUBLE:
    case INTEGER:
    case ENOTATION:
      mValue = strtod(str, NULL);
      break;

    case RATIONALE:
      str++; // Skip the '('
      mValue = strtod(str, &end);
      end++; // Skip the '/'
      mValue /= strtod(end, NULL);
      break;

    case INVALID:
      fatalError();
      break;
    }

  mPrecedence = PRECEDENCE_NUMBER;
}

CEvaluationNodeNumber::CEvaluationNodeNumber(const CEvaluationNodeNumber & src):
    CEvaluationNode(src)
{}

CEvaluationNodeNumber::~CEvaluationNodeNumber() {}

#ifdef WIN32
// warning C4056: overflow in floating-point constant arithmetic
// warning C4756: overflow in constant arithmetic
# pragma warning (disable: 4056 4756)
#endif

CEvaluationNode* CEvaluationNodeNumber::createNodeFromASTTree(const ASTNode& node)
{
  ASTNodeType_t type = node.getType();
  std::stringstream ss;
  SubType subType;
  std::string data = "";
  CEvaluationNode* pNode = NULL;
  switch (type)
    {
    case AST_INTEGER:
      subType = INTEGER;
      if (node.getInteger() < 0)
        {
          pNode = new CEvaluationNodeFunction(CEvaluationNodeFunction::MINUS, "-");

          ss << abs(node.getInteger());
          data = ss.str();
          pNode->addChild(new CEvaluationNodeNumber(subType, data));
        }
      else
        {
          ss << node.getInteger();
          data = ss.str();
          pNode = new CEvaluationNodeNumber(subType, data);
        }
      break;
    case AST_REAL:
      subType = DOUBLE;
      if (node.getReal() == (2*DBL_MAX))
        {
          pNode = new CEvaluationNodeConstant(CEvaluationNodeConstant::_INFINITY, "INFINITY");
        }
      else if (node.getReal() == (-2*DBL_MAX))
        {
          pNode = new CEvaluationNodeFunction(CEvaluationNodeFunction::MINUS, "-");
          pNode->addChild(new CEvaluationNodeConstant(CEvaluationNodeConstant::_INFINITY, "INFINITY"));
        }
      else if (isnan(node.getReal()))
        {
          pNode = new CEvaluationNodeConstant(CEvaluationNodeConstant::_NaN, "NAN");
        }
      else if (node.getReal() < 0.0)
        {
          pNode = new CEvaluationNodeFunction(CEvaluationNodeFunction::MINUS, "-");

          ss << fabs(node.getReal());
          data = ss.str();
          pNode->addChild(new CEvaluationNodeNumber(subType, data));
        }
      else
        {
          ss << node.getReal();
          data = ss.str();
          pNode = new CEvaluationNodeNumber(subType, data);
        }
      break;
    case AST_REAL_E:
      subType = ENOTATION;
      if (node.getReal() == (2*DBL_MAX))
        {
          pNode = new CEvaluationNodeConstant(CEvaluationNodeConstant::_INFINITY, "INFINITY");
        }
      else if (node.getReal() == (-2*DBL_MAX))
        {
          pNode = new CEvaluationNodeFunction(CEvaluationNodeFunction::MINUS, "-");
          pNode->addChild(new CEvaluationNodeConstant(CEvaluationNodeConstant::_INFINITY, "INFINITY"));
        }
      else if (isnan(node.getReal()))
        {
          pNode = new CEvaluationNodeConstant(CEvaluationNodeConstant::_NaN, "NAN");
        }
      else if (node.getReal() < 0.0)
        {
          pNode = new CEvaluationNodeFunction(CEvaluationNodeFunction::MINUS, "-");

          ss << fabs(node.getReal());
          data = ss.str();
          pNode->addChild(new CEvaluationNodeNumber(subType, data));
        }
      else
        {
          ss << node.getReal();
          data = ss.str();
          pNode = new CEvaluationNodeNumber(subType, data);
        }
      break;
    case AST_RATIONAL:
      subType = RATIONALE;
      if (node.getReal() < 0.0) // getReal returns the value of the node
        {
          pNode = new CEvaluationNodeFunction(CEvaluationNodeFunction::MINUS, "-");

          ss << "(" << abs(node.getNumerator()) << "/" << abs(node.getDenominator()) << ")";
          data = ss.str();
          pNode->addChild(new CEvaluationNodeNumber(subType, data));
        }
      else
        {
          ss << "(" << node.getNumerator() << "/" << node.getDenominator() << ")";
          data = ss.str();
          pNode = new CEvaluationNodeNumber(subType, data);
        }
      break;
    default:
      subType = INVALID;
      break;
    }
  return pNode;
}

#ifdef WIN32
# pragma warning (default: 4056 4756)
#endif

ASTNode* CEvaluationNodeNumber::toAST(const CCopasiDataModel* pDataModel) const
  {
    SubType subType = (SubType)CEvaluationNode::subType(this->getType());
    ASTNode* node = new ASTNode();
    double num1;
    double num2;
    char* end;
    const char * str = mData.c_str();

    switch (subType)
      {
      case DOUBLE:
        node->setType(AST_REAL);
        node->setValue(this->value());
        break;
      case INTEGER:
        node->setType(AST_INTEGER);
        node->setValue((long)this->value());
        break;
      case ENOTATION:
        node->setType(AST_REAL_E);
        num2 = floor(log10(this->value()));
        num1 = pow(10.0, log10(this->value()) - num2);
        node->setValue(num1, (long)num2);
        break;
      case RATIONALE:
        node->setType(AST_RATIONAL);
        str++; // Skip the '('
        num1 = strtod(str, &end);
        end++; // Skip the '/'
        num2 = strtod(end, NULL);
        node->setValue((long)num1, (long)num2);
        break;
      case INVALID:
        break;
      }
    return node;
  }

#include "utilities/copasimathml.h"

void CEvaluationNodeNumber::writeMathML(std::ostream & out,
                                        const std::vector<std::vector<std::string> > & /* env */,
                                        bool /* expand */,
                                        unsigned C_INT32 l) const
  {
    out << SPC(l) << "<mn>" << mData << "</mn>" << std::endl;
    //or use mValue instead?
  }
<commit_msg>Removed warning message.<commit_after>// Begin CVS Header
//   $Source: /Volumes/Home/Users/shoops/cvs/copasi_dev/copasi/function/CEvaluationNodeNumber.cpp,v $
//   $Revision: 1.29 $
//   $Name:  $
//   $Author: shoops $
//   $Date: 2009/02/20 17:56:22 $
// End CVS Header

// Copyright (C) 2008 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., EML Research, gGmbH, University of Heidelberg,
// and The University of Manchester.
// All rights reserved.

// Copyright (C) 2001 - 2007 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc. and EML Research, gGmbH.
// All rights reserved.

#include <sstream>
#include <stdlib.h>

#include "copasi.h"
#include "CEvaluationNode.h"

#include "sbml/math/ASTNode.h"

CEvaluationNodeNumber::CEvaluationNodeNumber():
    CEvaluationNode(CEvaluationNode::INVALID, "")
{mPrecedence = PRECEDENCE_NUMBER;}

CEvaluationNodeNumber::CEvaluationNodeNumber(const SubType & subType,
    const Data & data):
    CEvaluationNode((Type) (CEvaluationNode::NUMBER | subType), data)
{
  char * end;
  const char * str = mData.c_str();

  switch (subType)
    {
    case DOUBLE:
    case INTEGER:
    case ENOTATION:
      mValue = strtod(str, NULL);
      break;

    case RATIONALE:
      str++; // Skip the '('
      mValue = strtod(str, &end);
      end++; // Skip the '/'
      mValue /= strtod(end, NULL);
      break;

    case INVALID:
      fatalError();
      break;
    }

  mPrecedence = PRECEDENCE_NUMBER;
}

CEvaluationNodeNumber::CEvaluationNodeNumber(const CEvaluationNodeNumber & src):
    CEvaluationNode(src)
{}

CEvaluationNodeNumber::~CEvaluationNodeNumber() {}

#ifdef WIN32
// warning C4056: overflow in floating-point constant arithmetic
// warning C4756: overflow in constant arithmetic
# pragma warning (disable: 4056 4756)
#endif

CEvaluationNode* CEvaluationNodeNumber::createNodeFromASTTree(const ASTNode& node)
{
  ASTNodeType_t type = node.getType();
  std::stringstream ss;
  SubType subType;
  std::string data = "";
  CEvaluationNode* pNode = NULL;
  switch (type)
    {
    case AST_INTEGER:
      subType = INTEGER;
      if (node.getInteger() < 0)
        {
          pNode = new CEvaluationNodeFunction(CEvaluationNodeFunction::MINUS, "-");

          ss << abs(node.getInteger());
          data = ss.str();
          pNode->addChild(new CEvaluationNodeNumber(subType, data));
        }
      else
        {
          ss << node.getInteger();
          data = ss.str();
          pNode = new CEvaluationNodeNumber(subType, data);
        }
      break;
    case AST_REAL:
      subType = DOUBLE;
      if (node.getReal() == (2*DBL_MAX))
        {
          pNode = new CEvaluationNodeConstant(CEvaluationNodeConstant::_INFINITY, "INFINITY");
        }
      else if (node.getReal() == (-2*DBL_MAX))
        {
          pNode = new CEvaluationNodeFunction(CEvaluationNodeFunction::MINUS, "-");
          pNode->addChild(new CEvaluationNodeConstant(CEvaluationNodeConstant::_INFINITY, "INFINITY"));
        }
      else if (isnan(node.getReal()))
        {
          pNode = new CEvaluationNodeConstant(CEvaluationNodeConstant::_NaN, "NAN");
        }
      else if (node.getReal() < 0.0)
        {
          pNode = new CEvaluationNodeFunction(CEvaluationNodeFunction::MINUS, "-");

          ss << fabs(node.getReal());
          data = ss.str();
          pNode->addChild(new CEvaluationNodeNumber(subType, data));
        }
      else
        {
          ss << node.getReal();
          data = ss.str();
          pNode = new CEvaluationNodeNumber(subType, data);
        }
      break;
    case AST_REAL_E:
      subType = ENOTATION;
      if (node.getReal() == (2*DBL_MAX))
        {
          pNode = new CEvaluationNodeConstant(CEvaluationNodeConstant::_INFINITY, "INFINITY");
        }
      else if (node.getReal() == (-2*DBL_MAX))
        {
          pNode = new CEvaluationNodeFunction(CEvaluationNodeFunction::MINUS, "-");
          pNode->addChild(new CEvaluationNodeConstant(CEvaluationNodeConstant::_INFINITY, "INFINITY"));
        }
      else if (isnan(node.getReal()))
        {
          pNode = new CEvaluationNodeConstant(CEvaluationNodeConstant::_NaN, "NAN");
        }
      else if (node.getReal() < 0.0)
        {
          pNode = new CEvaluationNodeFunction(CEvaluationNodeFunction::MINUS, "-");

          ss << fabs(node.getReal());
          data = ss.str();
          pNode->addChild(new CEvaluationNodeNumber(subType, data));
        }
      else
        {
          ss << node.getReal();
          data = ss.str();
          pNode = new CEvaluationNodeNumber(subType, data);
        }
      break;
    case AST_RATIONAL:
      subType = RATIONALE;
      if (node.getReal() < 0.0) // getReal returns the value of the node
        {
          pNode = new CEvaluationNodeFunction(CEvaluationNodeFunction::MINUS, "-");

          ss << "(" << abs(node.getNumerator()) << "/" << abs(node.getDenominator()) << ")";
          data = ss.str();
          pNode->addChild(new CEvaluationNodeNumber(subType, data));
        }
      else
        {
          ss << "(" << node.getNumerator() << "/" << node.getDenominator() << ")";
          data = ss.str();
          pNode = new CEvaluationNodeNumber(subType, data);
        }
      break;
    default:
      subType = INVALID;
      break;
    }
  return pNode;
}

#ifdef WIN32
# pragma warning (default: 4056 4756)
#endif

ASTNode* CEvaluationNodeNumber::toAST(const CCopasiDataModel* /* pDataModel */) const
  {
    SubType subType = (SubType)CEvaluationNode::subType(this->getType());
    ASTNode* node = new ASTNode();
    double num1;
    double num2;
    char* end;
    const char * str = mData.c_str();

    switch (subType)
      {
      case DOUBLE:
        node->setType(AST_REAL);
        node->setValue(this->value());
        break;
      case INTEGER:
        node->setType(AST_INTEGER);
        node->setValue((long)this->value());
        break;
      case ENOTATION:
        node->setType(AST_REAL_E);
        num2 = floor(log10(this->value()));
        num1 = pow(10.0, log10(this->value()) - num2);
        node->setValue(num1, (long)num2);
        break;
      case RATIONALE:
        node->setType(AST_RATIONAL);
        str++; // Skip the '('
        num1 = strtod(str, &end);
        end++; // Skip the '/'
        num2 = strtod(end, NULL);
        node->setValue((long)num1, (long)num2);
        break;
      case INVALID:
        break;
      }
    return node;
  }

#include "utilities/copasimathml.h"

void CEvaluationNodeNumber::writeMathML(std::ostream & out,
                                        const std::vector<std::vector<std::string> > & /* env */,
                                        bool /* expand */,
                                        unsigned C_INT32 l) const
  {
    out << SPC(l) << "<mn>" << mData << "</mn>" << std::endl;
    //or use mValue instead?
  }
<|endoftext|>


<commit_before><commit_msg>Delete ApeEventManagerImpl.cpp<commit_after><|endoftext|>