summaryrefslogtreecommitdiffstats
path: root/src/base/Event.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/base/Event.cpp')
-rw-r--r--src/base/Event.cpp445
1 files changed, 445 insertions, 0 deletions
diff --git a/src/base/Event.cpp b/src/base/Event.cpp
new file mode 100644
index 0000000..e63e51b
--- /dev/null
+++ b/src/base/Event.cpp
@@ -0,0 +1,445 @@
+// -*- c-basic-offset: 4 -*-
+
+/*
+ Rosegarden
+ A sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <glaurent@telegraph-road.org>,
+ Chris Cannam <cannam@all-day-breakfast.com>,
+ Richard Bown <bownie@bownie.com>
+
+ The moral right of the authors to claim authorship of this work
+ has been asserted.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version. See the file
+ COPYING included with this distribution for more information.
+*/
+
+#include <cstdio>
+#include <cctype>
+#include <iostream>
+#include "Event.h"
+#include "XmlExportable.h"
+
+#if (__GNUC__ < 3)
+#include <strstream>
+#define stringstream strstream
+#else
+#include <sstream>
+#endif
+
+namespace Rosegarden
+{
+using std::string;
+using std::ostream;
+
+PropertyName Event::EventData::NotationTime = "!notationtime";
+PropertyName Event::EventData::NotationDuration = "!notationduration";
+
+
+Event::EventData::EventData(const std::string &type, timeT absoluteTime,
+ timeT duration, short subOrdering) :
+ m_refCount(1),
+ m_type(type),
+ m_absoluteTime(absoluteTime),
+ m_duration(duration),
+ m_subOrdering(subOrdering),
+ m_properties(0)
+{
+ // empty
+}
+
+Event::EventData::EventData(const std::string &type, timeT absoluteTime,
+ timeT duration, short subOrdering,
+ const PropertyMap *properties) :
+ m_refCount(1),
+ m_type(type),
+ m_absoluteTime(absoluteTime),
+ m_duration(duration),
+ m_subOrdering(subOrdering),
+ m_properties(properties ? new PropertyMap(*properties) : 0)
+{
+ // empty
+}
+
+Event::EventData *Event::EventData::unshare()
+{
+ --m_refCount;
+
+ EventData *newData = new EventData
+ (m_type, m_absoluteTime, m_duration, m_subOrdering, m_properties);
+
+ return newData;
+}
+
+Event::EventData::~EventData()
+{
+ if (m_properties) delete m_properties;
+}
+
+timeT
+Event::EventData::getNotationTime() const
+{
+ if (!m_properties) return m_absoluteTime;
+ PropertyMap::const_iterator i = m_properties->find(NotationTime);
+ if (i == m_properties->end()) return m_absoluteTime;
+ else return static_cast<PropertyStore<Int> *>(i->second)->getData();
+}
+
+timeT
+Event::EventData::getNotationDuration() const
+{
+ if (!m_properties) return m_duration;
+ PropertyMap::const_iterator i = m_properties->find(NotationDuration);
+ if (i == m_properties->end()) return m_duration;
+ else return static_cast<PropertyStore<Int> *>(i->second)->getData();
+}
+
+void
+Event::EventData::setTime(const PropertyName &name, timeT t, timeT deft)
+{
+ if (!m_properties) m_properties = new PropertyMap();
+ PropertyMap::iterator i = m_properties->find(name);
+
+ if (t != deft) {
+ if (i == m_properties->end()) {
+ m_properties->insert(PropertyPair(name, new PropertyStore<Int>(t)));
+ } else {
+ static_cast<PropertyStore<Int> *>(i->second)->setData(t);
+ }
+ } else if (i != m_properties->end()) {
+ delete i->second;
+ m_properties->erase(i);
+ }
+}
+
+PropertyMap *
+Event::find(const PropertyName &name, PropertyMap::iterator &i)
+{
+ PropertyMap *map = m_data->m_properties;
+
+ if (!map || ((i = map->find(name)) == map->end())) {
+
+ map = m_nonPersistentProperties;
+ if (!map) return 0;
+
+ i = map->find(name);
+ if (i == map->end()) return 0;
+ }
+
+ return map;
+}
+
+bool
+Event::has(const PropertyName &name) const
+{
+#ifndef NDEBUG
+ ++m_hasCount;
+#endif
+
+ PropertyMap::const_iterator i;
+ const PropertyMap *map = find(name, i);
+ if (map) return true;
+ else return false;
+}
+
+void
+Event::unset(const PropertyName &name)
+{
+#ifndef NDEBUG
+ ++m_unsetCount;
+#endif
+
+ unshare();
+ PropertyMap::iterator i;
+ PropertyMap *map = find(name, i);
+ if (map) {
+ delete i->second;
+ map->erase(i);
+ }
+}
+
+
+PropertyType
+Event::getPropertyType(const PropertyName &name) const
+ // throw (NoData)
+{
+ PropertyMap::const_iterator i;
+ const PropertyMap *map = find(name, i);
+ if (map) {
+ return i->second->getType();
+ } else {
+ throw NoData(name.getName(), __FILE__, __LINE__);
+ }
+}
+
+
+string
+Event::getPropertyTypeAsString(const PropertyName &name) const
+ // throw (NoData)
+{
+ PropertyMap::const_iterator i;
+ const PropertyMap *map = find(name, i);
+ if (map) {
+ return i->second->getTypeName();
+ } else {
+ throw NoData(name.getName(), __FILE__, __LINE__);
+ }
+}
+
+
+string
+Event::getAsString(const PropertyName &name) const
+ // throw (NoData)
+{
+ PropertyMap::const_iterator i;
+ const PropertyMap *map = find(name, i);
+ if (map) {
+ return i->second->unparse();
+ } else {
+ throw NoData(name.getName(), __FILE__, __LINE__);
+ }
+}
+
+// We could derive from XmlExportable and make this a virtual method
+// overriding XmlExportable's pure virtual. We don't, because this
+// class has no other virtual methods and for such a core class we
+// could do without the overhead (given that it wouldn't really gain
+// us anything anyway).
+
+string
+Event::toXmlString()
+{
+ return toXmlString(0);
+}
+
+string
+Event::toXmlString(timeT expectedTime)
+{
+ std::stringstream out;
+
+ out << "<event";
+
+ if (getType().length() != 0) {
+ out << " type=\"" << getType() << "\"";
+ }
+
+ if (getDuration() != 0) {
+ out << " duration=\"" << getDuration() << "\"";
+ }
+
+ if (getSubOrdering() != 0) {
+ out << " subordering=\"" << getSubOrdering() << "\"";
+ }
+
+ if (expectedTime == 0) {
+ out << " absoluteTime=\"" << getAbsoluteTime() << "\"";
+ } else if (getAbsoluteTime() != expectedTime) {
+ out << " timeOffset=\"" << (getAbsoluteTime() - expectedTime) << "\"";
+ }
+
+ out << ">";
+
+ // Save all persistent properties as <property> elements
+
+ PropertyNames propertyNames(getPersistentPropertyNames());
+ for (PropertyNames::const_iterator i = propertyNames.begin();
+ i != propertyNames.end(); ++i) {
+
+ out << "<property name=\""
+ << XmlExportable::encode(i->getName()) << "\" ";
+ string type = getPropertyTypeAsString(*i);
+ for (unsigned int j = 0; j < type.size(); ++j) {
+ type[j] = (isupper(type[j]) ? tolower(type[j]) : type[j]);
+ }
+
+ out << type << "=\""
+ << XmlExportable::encode(getAsString(*i))
+ << "\"/>";
+ }
+
+ // Save non-persistent properties (the persistence applies to
+ // copying events, not load/save) as <nproperty> elements
+ // unless they're view-local. View-local properties are
+ // assumed to have "::" in their name somewhere.
+
+ propertyNames = getNonPersistentPropertyNames();
+ for (PropertyNames::const_iterator i = propertyNames.begin();
+ i != propertyNames.end(); ++i) {
+
+ std::string s(i->getName());
+ if (s.find("::") != std::string::npos) continue;
+
+ out << "<nproperty name=\""
+ << XmlExportable::encode(s) << "\" ";
+ string type = getPropertyTypeAsString(*i);
+ for (unsigned int j = 0; j < type.size(); ++j) {
+ type[j] = (isupper(type[j]) ? tolower(type[j]) : type[j]);
+ }
+ out << type << "=\""
+ << XmlExportable::encode(getAsString(*i))
+ << "\"/>";
+ }
+
+ out << "</event>";
+
+#if (__GNUC__ < 3)
+ out << std::ends;
+#endif
+
+ return out.str();
+}
+
+
+#ifndef NDEBUG
+void
+Event::dump(ostream& out) const
+{
+ out << "Event type : " << m_data->m_type.c_str() << '\n';
+
+ out << "\tAbsolute Time : " << m_data->m_absoluteTime
+ << "\n\tDuration : " << m_data->m_duration
+ << "\n\tSub-ordering : " << m_data->m_subOrdering
+ << "\n\tPersistent properties : \n";
+
+ if (m_data->m_properties) {
+ for (PropertyMap::const_iterator i = m_data->m_properties->begin();
+ i != m_data->m_properties->end(); ++i) {
+ out << "\t\t" << i->first.getName() << " [" << i->first.getValue() << "] \t" << *(i->second) << "\n";
+ }
+ }
+
+ if (m_nonPersistentProperties) {
+ out << "\n\tNon-persistent properties : \n";
+
+ for (PropertyMap::const_iterator i = m_nonPersistentProperties->begin();
+ i != m_nonPersistentProperties->end(); ++i) {
+ out << "\t\t" << i->first.getName() << " [" << i->first.getValue() << "] \t" << *(i->second) << '\n';
+ }
+ }
+
+ out << "Event storage size : " << getStorageSize() << '\n';
+}
+
+
+int Event::m_getCount = 0;
+int Event::m_setCount = 0;
+int Event::m_setMaybeCount = 0;
+int Event::m_hasCount = 0;
+int Event::m_unsetCount = 0;
+clock_t Event::m_lastStats = clock();
+
+void
+Event::dumpStats(ostream& out)
+{
+ clock_t now = clock();
+ int ms = (now - m_lastStats) * 1000 / CLOCKS_PER_SEC;
+ out << "\nEvent stats, since start of run or last report ("
+ << ms << "ms ago):" << std::endl;
+
+ out << "Calls to get<>: " << m_getCount << std::endl;
+ out << "Calls to set<>: " << m_setCount << std::endl;
+ out << "Calls to setMaybe<>: " << m_setMaybeCount << std::endl;
+ out << "Calls to has: " << m_hasCount << std::endl;
+ out << "Calls to unset: " << m_unsetCount << std::endl;
+
+ m_getCount = m_setCount = m_setMaybeCount = m_hasCount = m_unsetCount = 0;
+ m_lastStats = clock();
+}
+
+#else
+
+void
+Event::dumpStats(ostream&)
+{
+ // nothing
+}
+
+#endif
+
+Event::PropertyNames
+Event::getPropertyNames() const
+{
+ PropertyNames v;
+ if (m_data->m_properties) {
+ for (PropertyMap::const_iterator i = m_data->m_properties->begin();
+ i != m_data->m_properties->end(); ++i) {
+ v.push_back(i->first);
+ }
+ }
+ if (m_nonPersistentProperties) {
+ for (PropertyMap::const_iterator i = m_nonPersistentProperties->begin();
+ i != m_nonPersistentProperties->end(); ++i) {
+ v.push_back(i->first);
+ }
+ }
+ return v;
+}
+
+Event::PropertyNames
+Event::getPersistentPropertyNames() const
+{
+ PropertyNames v;
+ if (m_data->m_properties) {
+ for (PropertyMap::const_iterator i = m_data->m_properties->begin();
+ i != m_data->m_properties->end(); ++i) {
+ v.push_back(i->first);
+ }
+ }
+ return v;
+}
+
+Event::PropertyNames
+Event::getNonPersistentPropertyNames() const
+{
+ PropertyNames v;
+ if (m_nonPersistentProperties) {
+ for (PropertyMap::const_iterator i = m_nonPersistentProperties->begin();
+ i != m_nonPersistentProperties->end(); ++i) {
+ v.push_back(i->first);
+ }
+ }
+ return v;
+}
+
+void
+Event::clearNonPersistentProperties()
+{
+ if (m_nonPersistentProperties) m_nonPersistentProperties->clear();
+}
+
+size_t
+Event::getStorageSize() const
+{
+ size_t s = sizeof(Event) + sizeof(EventData) + m_data->m_type.size();
+ if (m_data->m_properties) {
+ for (PropertyMap::const_iterator i = m_data->m_properties->begin();
+ i != m_data->m_properties->end(); ++i) {
+ s += sizeof(i->first);
+ s += i->second->getStorageSize();
+ }
+ }
+ if (m_nonPersistentProperties) {
+ for (PropertyMap::const_iterator i = m_nonPersistentProperties->begin();
+ i != m_nonPersistentProperties->end(); ++i) {
+ s += sizeof(i->first);
+ s += i->second->getStorageSize();
+ }
+ }
+ return s;
+}
+
+bool
+operator<(const Event &a, const Event &b)
+{
+ timeT at = a.getAbsoluteTime();
+ timeT bt = b.getAbsoluteTime();
+ if (at != bt) return at < bt;
+ else return a.getSubOrdering() < b.getSubOrdering();
+}
+
+}