diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-03-01 18:37:05 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-03-01 18:37:05 +0000 |
commit | 145364a8af6a1fec06556221e66d4b724a62fc9a (patch) | |
tree | 53bd71a544008c518034f208d64c932dc2883f50 /src/base/Event.h | |
download | rosegarden-145364a8af6a1fec06556221e66d4b724a62fc9a.tar.gz rosegarden-145364a8af6a1fec06556221e66d4b724a62fc9a.zip |
Added old abandoned KDE3 version of the RoseGarden MIDI tool
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/rosegarden@1097595 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/base/Event.h')
-rw-r--r-- | src/base/Event.h | 584 |
1 files changed, 584 insertions, 0 deletions
diff --git a/src/base/Event.h b/src/base/Event.h new file mode 100644 index 0000000..f236681 --- /dev/null +++ b/src/base/Event.h @@ -0,0 +1,584 @@ +// -*- c-basic-offset: 4 -*- + + +/* + Rosegarden + A sequencer and musical notation editor. + + This program is Copyright 2000-2008 + Guillaume Laurent <[email protected]>, + Chris Cannam <[email protected]>, + Richard Bown <[email protected]> + + 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. +*/ + +#ifndef _EVENT_H_ +#define _EVENT_H_ + +#include "PropertyMap.h" +#include "Exception.h" + +#include <string> +#include <vector> +#ifndef NDEBUG +#include <iostream> +#include <ctime> +#endif + + +namespace Rosegarden +{ + +typedef long timeT; + +/** + * The Event class represents an event with some basic attributes and + * an arbitrary number of properties of dynamically-determined name + * and type. + * + * An Event has a type; a duration, often zero for events other than + * notes; an absolute time, the time at which the event begins, which + * is used to order events within a Segment; and a "sub-ordering", used + * to determine an order for events that have the same absolute time + * (for example to ensure that the clef always appears before the key + * signature at the start of a piece). Besides these, an event can + * have any number of properties, which are typed values stored and + * retrieved by name. Properties may be persistent or non-persistent, + * depending on whether they are saved to file with the rest of the + * event data or are considered to be only cached values that can be + * recomputed at will if necessary. + */ + +class Event +{ +public: + class NoData : public Exception { + public: + NoData(std::string property) : + Exception("No data found for property " + property) { } + NoData(std::string property, std::string file, int line) : + Exception("No data found for property " + property, file, line) { } + }; + + class BadType : public Exception { + public: + BadType(std::string property, std::string expected, std::string actl) : + Exception("Bad type for " + property + " (expected " + + expected + ", found " + actl + ")") { } + BadType(std::string property, std::string expected, std::string actual, + std::string file, int line) : + Exception("Bad type for " + property + " (expected " + + expected + ", found " + actual + ")", file, line) { } + }; + + Event(const std::string &type, + timeT absoluteTime, timeT duration = 0, short subOrdering = 0) : + m_data(new EventData(type, absoluteTime, duration, subOrdering)), + m_nonPersistentProperties(0) { } + + Event(const std::string &type, + timeT absoluteTime, timeT duration, short subOrdering, + timeT notationAbsoluteTime, timeT notationDuration) : + m_data(new EventData(type, absoluteTime, duration, subOrdering)), + m_nonPersistentProperties(0) { + setNotationAbsoluteTime(notationAbsoluteTime); + setNotationDuration(notationDuration); + } + + Event(const Event &e) : + m_nonPersistentProperties(0) { share(e); } + + // these ctors can't use default args: default has to be obtained from e + + Event(const Event &e, timeT absoluteTime) : + m_nonPersistentProperties(0) { + share(e); + unshare(); + m_data->m_absoluteTime = absoluteTime; + setNotationAbsoluteTime(absoluteTime); + setNotationDuration(m_data->m_duration); + } + + Event(const Event &e, timeT absoluteTime, timeT duration) : + m_nonPersistentProperties(0) { + share(e); + unshare(); + m_data->m_absoluteTime = absoluteTime; + m_data->m_duration = duration; + setNotationAbsoluteTime(absoluteTime); + setNotationDuration(duration); + } + + Event(const Event &e, timeT absoluteTime, timeT duration, short subOrdering): + m_nonPersistentProperties(0) { + share(e); + unshare(); + m_data->m_absoluteTime = absoluteTime; + m_data->m_duration = duration; + m_data->m_subOrdering = subOrdering; + setNotationAbsoluteTime(absoluteTime); + setNotationDuration(duration); + } + + Event(const Event &e, timeT absoluteTime, timeT duration, short subOrdering, + timeT notationAbsoluteTime) : + m_nonPersistentProperties(0) { + share(e); + unshare(); + m_data->m_absoluteTime = absoluteTime; + m_data->m_duration = duration; + m_data->m_subOrdering = subOrdering; + setNotationAbsoluteTime(notationAbsoluteTime); + setNotationDuration(duration); + } + + Event(const Event &e, timeT absoluteTime, timeT duration, short subOrdering, + timeT notationAbsoluteTime, timeT notationDuration) : + m_nonPersistentProperties(0) { + share(e); + unshare(); + m_data->m_absoluteTime = absoluteTime; + m_data->m_duration = duration; + m_data->m_subOrdering = subOrdering; + setNotationAbsoluteTime(notationAbsoluteTime); + setNotationDuration(notationDuration); + } + + ~Event() { lose(); } + + Event *copyMoving(timeT offset) const { + return new Event(*this, + m_data->m_absoluteTime + offset, + m_data->m_duration, + m_data->m_subOrdering, + getNotationAbsoluteTime() + offset, + getNotationDuration()); + } + + Event &operator=(const Event &e) { + if (&e != this) { lose(); share(e); } + return *this; + } + + friend bool operator<(const Event&, const Event&); + + // Accessors + const std::string &getType() const { return m_data->m_type; } + bool isa(const std::string &t) const { return (m_data->m_type == t); } + timeT getAbsoluteTime() const { return m_data->m_absoluteTime; } + timeT getDuration() const { return m_data->m_duration; } + short getSubOrdering() const { return m_data->m_subOrdering; } + + bool has(const PropertyName &name) const; + + template <PropertyType P> + typename PropertyDefn<P>::basic_type get(const PropertyName &name) const; + // throw (NoData, BadType); + + // no throw, returns bool + template <PropertyType P> + bool get(const PropertyName &name, typename PropertyDefn<P>::basic_type &val) const; + + template <PropertyType P> + bool isPersistent(const PropertyName &name) const; + // throw (NoData); + + template <PropertyType P> + void setPersistence(const PropertyName &name, bool persistent); + // throw (NoData); + + PropertyType getPropertyType(const PropertyName &name) const; + // throw (NoData); + + std::string getPropertyTypeAsString(const PropertyName &name) const; + // throw (NoData); + + std::string getAsString(const PropertyName &name) const; + // throw (NoData); + + template <PropertyType P> + void set(const PropertyName &name, typename PropertyDefn<P>::basic_type value, + bool persistent = true); + // throw (BadType); + + // set non-persistent, but only if there's no persistent value already + template <PropertyType P> + void setMaybe(const PropertyName &name, typename PropertyDefn<P>::basic_type value); + // throw (BadType); + + template <PropertyType P> + void setFromString(const PropertyName &name, std::string value, + bool persistent = true); + // throw (BadType); + + void unset(const PropertyName &name); + + timeT getNotationAbsoluteTime() const { return m_data->getNotationTime(); } + timeT getNotationDuration() const { return m_data->getNotationDuration(); } + + typedef std::vector<PropertyName> PropertyNames; + PropertyNames getPropertyNames() const; + PropertyNames getPersistentPropertyNames() const; + PropertyNames getNonPersistentPropertyNames() const; + + void clearNonPersistentProperties(); + + struct EventCmp + { + bool operator()(const Event &e1, const Event &e2) const { + return e1 < e2; + } + bool operator()(const Event *e1, const Event *e2) const { + return *e1 < *e2; + } + }; + + struct EventEndCmp + { + bool operator()(const Event &e1, const Event &e2) const { + return e1.getAbsoluteTime() + e1.getDuration() <= + e2.getAbsoluteTime() + e2.getDuration(); + } + bool operator()(const Event *e1, const Event *e2) const { + return e1->getAbsoluteTime() + e1->getDuration() <= + e2->getAbsoluteTime() + e2->getDuration(); + } + }; + + static bool compareEvent2Time(const Event *e, timeT t) { + return e->getAbsoluteTime() < t; + } + + static bool compareTime2Event(timeT t, const Event *e) { + return t < e->getAbsoluteTime(); + } + + // approximate, for debugging and inspection purposes + size_t getStorageSize() const; + + /** + * Get the XML string representing the object. + */ + std::string toXmlString(); + + /** + * Get the XML string representing the object. If the absolute + * time of the event differs from the given absolute time, include + * the difference between the two as a timeOffset attribute. + * If expectedTime == 0, include an absoluteTime attribute instead. + */ + std::string toXmlString(timeT expectedTime); + +#ifndef NDEBUG + void dump(std::ostream&) const; +#else + void dump(std::ostream&) const {} +#endif + static void dumpStats(std::ostream&); + +protected: + // these are for subclasses such as XmlStorableEvent + + Event() : + m_data(new EventData("", 0, 0, 0)), + m_nonPersistentProperties(0) { } + + void setType(const std::string &t) { unshare(); m_data->m_type = t; } + void setAbsoluteTime(timeT t) { unshare(); m_data->m_absoluteTime = t; } + void setDuration(timeT d) { unshare(); m_data->m_duration = d; } + void setSubOrdering(short o) { unshare(); m_data->m_subOrdering = o; } + void setNotationAbsoluteTime(timeT t) { unshare(); m_data->setNotationTime(t); } + void setNotationDuration(timeT d) { unshare(); m_data->setNotationDuration(d); } + +private: + bool operator==(const Event &); // not implemented + + struct EventData // Data that are shared between shallow-copied instances + { + EventData(const std::string &type, + timeT absoluteTime, timeT duration, short subOrdering); + EventData(const std::string &type, + timeT absoluteTime, timeT duration, short subOrdering, + const PropertyMap *properties); + EventData *unshare(); + ~EventData(); + unsigned int m_refCount; + + std::string m_type; + timeT m_absoluteTime; + timeT m_duration; + short m_subOrdering; + + PropertyMap *m_properties; + + // These are properties because we don't care so much about + // raw speed in get/set, but we do care about storage size for + // events that don't have them or that have zero values: + timeT getNotationTime() const; + timeT getNotationDuration() const; + void setNotationTime(timeT t) { + setTime(NotationTime, t, m_absoluteTime); + } + void setNotationDuration(timeT d) { + setTime(NotationDuration, d, m_duration); + } + + private: + EventData(const EventData &); + EventData &operator=(const EventData &); + static PropertyName NotationTime; + static PropertyName NotationDuration; + void setTime(const PropertyName &name, timeT value, timeT deft); + }; + + EventData *m_data; + PropertyMap *m_nonPersistentProperties; // Unique to an instance + + void share(const Event &e) { + m_data = e.m_data; + m_data->m_refCount++; + } + + bool unshare() { // returns true if unshare was necessary + if (m_data->m_refCount > 1) { + m_data = m_data->unshare(); + return true; + } else { + return false; + } + } + + void lose() { + if (--m_data->m_refCount == 0) delete m_data; + delete m_nonPersistentProperties; + m_nonPersistentProperties = 0; + } + + // returned iterator (in i) only valid if return map value is non-zero + PropertyMap *find(const PropertyName &name, PropertyMap::iterator &i); + + const PropertyMap *find(const PropertyName &name, + PropertyMap::const_iterator &i) const { + PropertyMap::iterator j; + PropertyMap *map = const_cast<Event *>(this)->find(name, j); + i = j; + return map; + } + + PropertyMap::iterator insert(const PropertyPair &pair, bool persistent) { + PropertyMap **map = + (persistent ? &m_data->m_properties : &m_nonPersistentProperties); + if (!*map) *map = new PropertyMap(); + return (*map)->insert(pair).first; + } + +#ifndef NDEBUG + static int m_getCount; + static int m_setCount; + static int m_setMaybeCount; + static int m_hasCount; + static int m_unsetCount; + static clock_t m_lastStats; +#endif +}; + + +template <PropertyType P> +bool +Event::get(const PropertyName &name, typename PropertyDefn<P>::basic_type &val) const +{ +#ifndef NDEBUG + ++m_getCount; +#endif + + PropertyMap::const_iterator i; + const PropertyMap *map = find(name, i); + + if (map) { + + PropertyStoreBase *sb = i->second; + if (sb->getType() == P) { + val = (static_cast<PropertyStore<P> *>(sb))->getData(); + return true; + } + else { +#ifndef NDEBUG + std::cerr << "Event::get() Error: Attempt to get property \"" << name + << "\" as " << PropertyDefn<P>::typeName() <<", actual type is " + << sb->getTypeName() << std::endl; +#endif + return false; + } + + } else { + return false; + } +} + + +template <PropertyType P> +typename PropertyDefn<P>::basic_type +Event::get(const PropertyName &name) const + // throw (NoData, BadType) +{ +#ifndef NDEBUG + ++m_getCount; +#endif + + PropertyMap::const_iterator i; + const PropertyMap *map = find(name, i); + + if (map) { + + PropertyStoreBase *sb = i->second; + if (sb->getType() == P) + return (static_cast<PropertyStore<P> *>(sb))->getData(); + else { + throw BadType(name.getName(), + PropertyDefn<P>::typeName(), sb->getTypeName(), + __FILE__, __LINE__); + } + + } else { + +#ifndef NDEBUG + std::cerr << "Event::get(): Error dump follows:" << std::endl; + dump(std::cerr); +#endif + throw NoData(name.getName(), __FILE__, __LINE__); + } +} + + +template <PropertyType P> +bool +Event::isPersistent(const PropertyName &name) const + // throw (NoData) +{ + PropertyMap::const_iterator i; + const PropertyMap *map = find(name, i); + + if (map) { + return (map == m_data->m_properties); + } else { + throw NoData(name.getName(), __FILE__, __LINE__); + } +} + + +template <PropertyType P> +void +Event::setPersistence(const PropertyName &name, bool persistent) + // throw (NoData) +{ + unshare(); + PropertyMap::iterator i; + PropertyMap *map = find(name, i); + + if (map) { + insert(*i, persistent); + map->erase(i); + } else { + throw NoData(name.getName(), __FILE__, __LINE__); + } +} + + +template <PropertyType P> +void +Event::set(const PropertyName &name, typename PropertyDefn<P>::basic_type value, + bool persistent) + // throw (BadType) +{ +#ifndef NDEBUG + ++m_setCount; +#endif + + // this is a little slow, could bear improvement + + unshare(); + PropertyMap::iterator i; + PropertyMap *map = find(name, i); + + if (map) { + bool persistentBefore = (map == m_data->m_properties); + if (persistentBefore != persistent) { + i = insert(*i, persistent); + map->erase(name); + } + + PropertyStoreBase *sb = i->second; + if (sb->getType() == P) { + (static_cast<PropertyStore<P> *>(sb))->setData(value); + } else { + throw BadType(name.getName(), + PropertyDefn<P>::typeName(), sb->getTypeName(), + __FILE__, __LINE__); + } + + } else { + PropertyStoreBase *p = new PropertyStore<P>(value); + insert(PropertyPair(name, p), persistent); + } +} + + + +// setMaybe<> is actually called rather more frequently than set<>, so +// it makes sense for best performance to implement it separately +// rather than through calls to has, isPersistent and set<> + +template <PropertyType P> +void +Event::setMaybe(const PropertyName &name, typename PropertyDefn<P>::basic_type value) + // throw (BadType) +{ +#ifndef NDEBUG + ++m_setMaybeCount; +#endif + + unshare(); + PropertyMap::iterator i; + PropertyMap *map = find(name, i); + + if (map) { + if (map == m_data->m_properties) return; // persistent, so ignore it + + PropertyStoreBase *sb = i->second; + + if (sb->getType() == P) { + (static_cast<PropertyStore<P> *>(sb))->setData(value); + } else { + throw BadType(name.getName(), + PropertyDefn<P>::typeName(), sb->getTypeName(), + __FILE__, __LINE__); + } + } else { + PropertyStoreBase *p = new PropertyStore<P>(value); + insert(PropertyPair(name, p), false); + } +} + + +template <PropertyType P> +void +Event::setFromString(const PropertyName &name, std::string value, bool persistent) + // throw (BadType) +{ + set<P>(name, PropertyDefn<P>::parse(value), persistent); +} + + +////////////////////////////////////////////////////////////////////// + +} + +#endif |