Chris@0: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@0: Chris@0: #ifndef _CLASSICAL_DATA_OBJECTS_H_ Chris@0: #define _CLASSICAL_DATA_OBJECTS_H_ Chris@0: Chris@19: #include Chris@21: #include Chris@19: Chris@0: #include Chris@0: #include Chris@0: #include Chris@0: #include Chris@0: #include Chris@0: #include Chris@0: #include Chris@0: #include Chris@0: #include Chris@0: Chris@24: #include Chris@24: Chris@33: #include "data/fileio/FileSource.h" Chris@33: Chris@0: namespace ClassicalData { Chris@0: Chris@26: //!!! need to review ownership more carefully -- and use deletion notify signals? Chris@26: Chris@21: class Year Chris@21: { Chris@21: public: Chris@21: Year() : m_year(0) { } Chris@21: Year(int y) : m_year(y) { } Chris@21: Chris@22: int toInt() const { return m_year; } Chris@21: operator int() { return m_year; } Chris@21: Chris@21: struct Encoder : public Dataquay::Node::VariantEncoder { Chris@21: QString fromVariant(const QVariant &v) { Chris@42: int y = v.value().toInt(); Chris@42: if (y == 0) return ""; Chris@42: QString s = QString("%1").arg(y); Chris@24: return s; Chris@21: } Chris@21: QVariant toVariant(const QString &s) { Chris@42: if (s == "") return QVariant::fromValue(Year()); Chris@24: QVariant v = QVariant::fromValue(s.toInt()); Chris@24: return v; Chris@21: } Chris@21: }; Chris@21: Chris@21: private: Chris@21: int m_year; Chris@21: }; Chris@21: Chris@0: class HistoricalEvent : public QObject Chris@0: { Chris@0: Q_OBJECT Chris@0: Chris@31: Q_PROPERTY(ClassicalData::Year year READ year WRITE setYear NOTIFY yearChanged STORED true) Chris@31: Q_PROPERTY(QString place READ place WRITE setPlace NOTIFY placeChanged STORED true) Chris@31: Q_PROPERTY(bool approximate READ approximate WRITE setApproximate NOTIFY approximateChanged STORED true) Chris@0: Chris@0: public: Chris@0: HistoricalEvent() : m_year(0), m_place(), m_approximate(false) { } Chris@21: HistoricalEvent(Year y) : m_year(y), m_approximate(false) { } Chris@21: HistoricalEvent(Year y, QString p) : m_year(y), m_place(p), m_approximate(false) { } Chris@24: HistoricalEvent(const HistoricalEvent &h) : QObject(), m_year(h.m_year), m_place(h.m_place), m_approximate(h.m_approximate) { } Chris@0: Chris@21: Year year() const { return m_year; } Chris@31: void setYear(Year y) { m_year = y; emit yearChanged(y); } Chris@0: QString place() const { return m_place; } Chris@31: void setPlace(QString p) { m_place = p; emit placeChanged(p); } Chris@0: bool approximate() const { return m_approximate; } Chris@31: void setApproximate(bool a) { m_approximate = a; emit approximateChanged(a); } Chris@0: Chris@31: signals: Chris@31: void yearChanged(Year); Chris@31: void placeChanged(QString); Chris@31: void approximateChanged(bool); Chris@31: Chris@0: private: Chris@21: Year m_year; Chris@0: QString m_place; Chris@0: bool m_approximate; Chris@0: }; Chris@0: Chris@0: class Birth : public HistoricalEvent Chris@0: { Chris@0: Q_OBJECT Chris@0: Chris@0: public: Chris@0: Birth() : HistoricalEvent() { } Chris@21: Birth(Year y) : HistoricalEvent(y) { } Chris@21: Birth(Year y, QString p) : HistoricalEvent(y, p) { } Chris@0: }; Chris@0: Chris@0: class Death : public HistoricalEvent Chris@0: { Chris@0: Q_OBJECT Chris@0: Chris@0: public: Chris@0: Death() : HistoricalEvent() { } Chris@21: Death(Year y) : HistoricalEvent(y) { } Chris@21: Death(Year y, QString p) : HistoricalEvent(y, p) { } Chris@0: }; Chris@0: Chris@0: class Composer; Chris@0: class Work; Chris@0: Chris@0: class Composition : public HistoricalEvent Chris@0: { Chris@0: Q_OBJECT Chris@0: Chris@31: Q_PROPERTY(ClassicalData::Composer *composer READ composer WRITE setComposer NOTIFY composerChanged STORED true) Chris@31: Q_PROPERTY(QSet works READ works WRITE setWorks NOTIFY worksChanged STORED true) Chris@37: Q_PROPERTY(QString composerName READ getComposerName WRITE setComposerName STORED false) Chris@0: Chris@0: public: Chris@0: Composition() : HistoricalEvent(), m_composer(0) { } Chris@21: Composition(Year y) : HistoricalEvent(y), m_composer(0) { } Chris@21: Composition(Year y, QString p) : HistoricalEvent(y, p), m_composer(0) { } Chris@0: Chris@0: Composer *composer() { return m_composer; } Chris@31: void setComposer(Composer *c) { m_composer = c; emit composerChanged(c); } Chris@0: Chris@0: QSet works() { return m_works; } Chris@31: void setWorks(QSet c) { m_works = c; emit worksChanged(c); } Chris@31: void addWork(Work *w) { m_works.insert(w); emit worksChanged(m_works); } Chris@0: Chris@37: // Not a storable property; set temporarily while composer record Chris@37: // is found, or else looked up from composer after composer has Chris@37: // been found Chris@37: QString getComposerName() const; Chris@0: void setComposerName(QString n) { m_cname = n; } Chris@0: Chris@31: signals: Chris@31: void composerChanged(Composer *); Chris@31: void worksChanged(QSet); Chris@31: Chris@0: private: Chris@0: Composer *m_composer; Chris@0: QSet m_works; Chris@0: QString m_cname; Chris@0: }; Chris@0: Chris@0: class Document : public QObject Chris@0: { Chris@0: Q_OBJECT Chris@0: Chris@31: Q_PROPERTY(Dataquay::Uri uri READ uri WRITE setUri NOTIFY uriChanged STORED true) Chris@31: Q_PROPERTY(QString siteName READ siteName WRITE setSiteName NOTIFY siteNameChanged STORED true) Chris@31: Q_PROPERTY(QObject *topic READ topic WRITE setTopic NOTIFY topicChanged STORED true) Chris@0: Chris@0: public: Chris@0: Document(QObject *parent = 0) : QObject(parent), m_topic(0) { } Chris@0: Chris@18: Dataquay::Uri uri() const { return m_uri; } Chris@31: void setUri(Dataquay::Uri uri) { m_uri = uri; emit uriChanged(uri); } Chris@0: Chris@0: QString siteName() const { return m_siteName; } Chris@31: void setSiteName(QString n) { m_siteName = n; emit siteNameChanged(n); } Chris@0: Chris@26: QObject *topic() const { return m_topic; } // I don't own this Chris@31: void setTopic(QObject *t) { m_topic = t; emit topicChanged(t); } Chris@31: Chris@31: signals: Chris@31: void uriChanged(Dataquay::Uri); Chris@31: void siteNameChanged(QString); Chris@31: void topicChanged(QObject *); Chris@0: Chris@0: private: Chris@18: Dataquay::Uri m_uri; Chris@0: QString m_siteName; Chris@0: QObject *m_topic; Chris@0: }; Chris@0: Chris@0: Chris@0: class NamedEntity : public QObject Chris@0: { Chris@0: Q_OBJECT Chris@0: Chris@31: Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged STORED true) Chris@33: Q_PROPERTY(Dataquay::Uri uri READ uri WRITE setUri NOTIFY uriChanged STORED true) Chris@31: Q_PROPERTY(QSet aliases READ aliases WRITE setAliases NOTIFY aliasesChanged STORED true) Chris@31: Q_PROPERTY(QString remarks READ remarks WRITE setRemarks NOTIFY remarksChanged STORED true) Chris@31: Q_PROPERTY(QSet pages READ pages WRITE setPages NOTIFY pagesChanged STORED true) Chris@31: Q_PROPERTY(QSet otherURIs READ otherURIs WRITE setOtherURIs NOTIFY otherURIsChanged STORED true) Chris@0: Chris@0: public: Chris@0: NamedEntity(QObject *parent = 0) : QObject(parent) { } Chris@33: ~NamedEntity() { } Chris@0: Chris@0: QString name() const { return m_name; } Chris@31: virtual void setName(QString n) { m_name = n; emit nameChanged(n); } Chris@33: Chris@33: Dataquay::Uri uri() const { return m_uri; } Chris@33: void setUri(Dataquay::Uri uri) { m_uri = uri; emit uriChanged(uri); } Chris@0: Chris@0: QString remarks() const { return m_remarks; } Chris@31: void setRemarks(QString n) { m_remarks = n; emit remarksChanged(n); } Chris@0: Chris@0: QSet aliases() const { return m_aliases; } Chris@31: virtual void setAliases(QSet l) { m_aliases = l; emit aliasesChanged(l); } Chris@31: virtual void addAlias(QString a) { m_aliases.insert(a); emit aliasesChanged(m_aliases); } Chris@0: Chris@0: QSet pages() const { return m_pages; } Chris@31: void addPage(Document *p) { m_pages.insert(p); emit pagesChanged(m_pages); } Chris@26: void setPages(QSet p) { Chris@26: m_pages = p; Chris@31: emit pagesChanged(p); Chris@26: } Chris@0: Chris@24: QSet otherURIs() const { return m_otherURIs; } Chris@31: void addOtherURI(Dataquay::Uri u) { m_otherURIs.insert(u); emit otherURIsChanged(m_otherURIs); } Chris@31: void setOtherURIs(QSet u) { m_otherURIs = u; emit otherURIsChanged(u); } Chris@31: Chris@31: signals: Chris@33: void uriChanged(Dataquay::Uri); Chris@31: void nameChanged(QString); Chris@31: void remarksChanged(QString); Chris@31: void aliasesChanged(QSet); Chris@31: void pagesChanged(QSet); Chris@31: void otherURIsChanged(QSet); Chris@24: Chris@11: protected: Chris@33: Dataquay::Uri m_uri; Chris@0: QString m_name; Chris@0: QString m_remarks; Chris@0: QSet m_aliases; Chris@33: QSet m_pages; Chris@24: QSet m_otherURIs; Chris@0: }; Chris@0: Chris@0: class Movement; Chris@0: Chris@0: class Form; Chris@0: Chris@0: class Work : public NamedEntity Chris@0: { Chris@0: Q_OBJECT Chris@0: Chris@31: Q_PROPERTY(QString key READ key WRITE setKey NOTIFY keyChanged STORED true) Chris@31: Q_PROPERTY(QString opus READ opus WRITE setOpus NOTIFY opusChanged STORED true) Chris@31: Q_PROPERTY(QString catalogue READ catalogue WRITE setCatalogue NOTIFY catalogueChanged STORED true) Chris@31: Q_PROPERTY(QString number READ number WRITE setNumber NOTIFY numberChanged STORED true) Chris@31: Q_PROPERTY(QSet forms READ forms WRITE setForms NOTIFY formsChanged STORED true) Chris@31: Q_PROPERTY(ClassicalData::Work* partOf READ partOf WRITE setPartOf NOTIFY partOfChanged STORED true) Chris@31: Q_PROPERTY(QSet parts READ parts WRITE setParts NOTIFY partsChanged STORED true) Chris@31: Q_PROPERTY(QSet movements READ movements WRITE setMovements NOTIFY movementsChanged STORED true) Chris@31: Q_PROPERTY(ClassicalData::Composition *composition READ composition WRITE setComposition NOTIFY compositionChanged STORED true) Chris@0: Chris@0: public: Chris@0: Work(QObject *parent = 0) : NamedEntity(parent), m_partOf(0), m_composition(0) { } Chris@0: Chris@0: QString key() const { return m_key; } Chris@31: void setKey(QString n) { m_key = n; emit keyChanged(n); } Chris@0: Chris@34: /// Should omit Op prefix, e.g. in opus 102 no 2, this would be "102" Chris@0: QString opus() const { return m_opus; } Chris@31: void setOpus(QString n) { m_opus = n; emit opusChanged(n); } Chris@0: Chris@34: /// For part of a catalogue entry, e.g. in opus 102 no 2, this Chris@34: /// would be "2". Should normally be used only with partOf Chris@34: QString number() const { return m_number; } Chris@34: void setNumber(QString n) { m_number = n; emit numberChanged(n); } Chris@34: Chris@34: /// Including catalogue prefix, e.g. "BWV 1066"; only for non-opus numbers Chris@0: QString catalogue() const { return m_catalogue; } Chris@31: void setCatalogue(QString n) { m_catalogue = n; emit catalogueChanged(n); } Chris@0: Chris@0: QSet
forms() const { return m_forms; } Chris@31: void setForms(QSet f) { m_forms = f; emit formsChanged(f); } Chris@31: void addForm(Form *f) { m_forms.insert(f); emit formsChanged(m_forms); } Chris@0: Chris@0: Work *partOf() const { return m_partOf; } Chris@31: void setPartOf(Work *w) { m_partOf = w; emit partOfChanged(w); } Chris@0: Chris@0: QSet parts() const { return m_parts; } Chris@31: void setParts(QSet l) { m_parts = l; emit partsChanged(l); } Chris@31: void addPart(Work *w) { m_parts.insert(w); emit partsChanged(m_parts); } Chris@0: Chris@0: QSet movements() const { return m_movements; } Chris@31: void setMovements(QSet l) { m_movements = l; emit movementsChanged(l); } Chris@31: void addMovement(Movement *w) { m_movements.insert(w); emit movementsChanged(m_movements); } Chris@0: Chris@0: Composition *composition() { return m_composition; } Chris@0: const Composition *composition() const { return m_composition; } Chris@31: void setComposition(Composition *c) { m_composition = c; emit compositionChanged(c); } Chris@0: Chris@37: Composer *getComposer() const { Chris@34: if (m_composition) { Chris@34: return m_composition->composer(); Chris@34: } else { Chris@34: return 0; Chris@34: } Chris@34: } Chris@34: Chris@37: QString getComposerName() const; Chris@37: Chris@0: struct Ordering { Chris@0: bool operator()(Work *, Work *); Chris@0: }; Chris@0: Chris@10: /** Chris@10: * Compare the ordering of two strings that are known to contain Chris@10: * catalogue number texts, such as "Op. 1 no 4" and "Op. 3 no 2" Chris@10: * (which should compare in that order). Return value is as for Chris@10: * strcmp. Chris@10: */ Chris@10: //!!! todo: unit tests Chris@10: static int compareCatalogueNumberTexts(QString a, QString b); Chris@10: Chris@34: /** Chris@34: * Where data (possibly a title string, including opus number or Chris@34: * equivalent) appears to contain some text of a suitable form for Chris@34: * use with compareCatalogueNumberTexts, extract and return each Chris@34: * example. Chris@34: */ Chris@34: static QStringList extractCatalogueNumberTexts(QString data); Chris@34: Chris@37: /// Return name composed from title and catalogue, e.g. Symphony no. 4, Op. 42 Chris@37: QString getDisplayName() const; Chris@37: Chris@31: signals: Chris@31: void keyChanged(QString); Chris@31: void opusChanged(QString); Chris@31: void catalogueChanged(QString); Chris@31: void numberChanged(QString); Chris@31: void formsChanged(QSet); Chris@31: void partOfChanged(Work *); Chris@31: void partsChanged(QSet); Chris@31: void movementsChanged(QSet); Chris@31: void compositionChanged(Composition *); Chris@31: Chris@0: private: Chris@0: QString m_key; Chris@0: QString m_opus; Chris@0: QString m_catalogue; Chris@0: QString m_number; Chris@0: QSet m_forms; Chris@0: Work *m_partOf; Chris@0: QSet m_parts; Chris@0: QSet m_movements; Chris@0: Composition *m_composition; Chris@0: }; Chris@0: Chris@0: class Movement : public NamedEntity Chris@0: { Chris@0: Q_OBJECT Chris@0: Chris@31: Q_PROPERTY(QString key READ key WRITE setKey NOTIFY keyChanged STORED true) Chris@31: Q_PROPERTY(QString number READ number WRITE setNumber NOTIFY numberChanged STORED true) Chris@31: Q_PROPERTY(ClassicalData::Work* partOf READ partOf WRITE setPartOf NOTIFY partOfChanged STORED true) Chris@31: Q_PROPERTY(QSet parts READ parts WRITE setParts NOTIFY partsChanged STORED true) // movements can be nested Chris@31: Q_PROPERTY(ClassicalData::Composition *composition READ composition WRITE setComposition NOTIFY compositionChanged STORED true) Chris@0: Chris@0: public: Chris@0: Movement(QObject *parent = 0) : NamedEntity(parent), m_partOf(0), m_composition(0) { } Chris@0: Chris@0: QString key() const { return m_key; } Chris@31: void setKey(QString n) { m_key = n; emit keyChanged(n); } Chris@0: Chris@0: QString number() const { return m_number; } Chris@31: void setNumber(QString n) { m_number = n; emit numberChanged(n); } Chris@0: Chris@0: Work *partOf() const { return m_partOf; } Chris@31: void setPartOf(Work *w) { m_partOf = w; emit partOfChanged(w); } Chris@0: Chris@0: QSet parts() const { return m_parts; } Chris@31: void setParts(QSet l) { m_parts = l; emit partsChanged(l); } Chris@31: void addPart(Movement *w) { m_parts.insert(w); emit partsChanged(m_parts); } Chris@0: Chris@0: Composition *composition() { return m_composition; } Chris@0: const Composition *composition() const { return m_composition; } Chris@31: void setComposition(Composition *c) { m_composition = c; emit compositionChanged(c); } Chris@31: Chris@31: signals: Chris@31: void keyChanged(QString); Chris@31: void numberChanged(QString); Chris@31: void partOfChanged(Work *); Chris@31: void partsChanged(QSet); Chris@31: void compositionChanged(Composition *); Chris@0: Chris@0: private: Chris@0: QString m_key; Chris@0: QString m_number; Chris@0: Work *m_partOf; Chris@0: QSet m_parts; Chris@0: Composition *m_composition; Chris@0: }; Chris@0: Chris@0: class Composer : public NamedEntity Chris@0: { Chris@0: Q_OBJECT Chris@0: Chris@31: Q_PROPERTY(QString gender READ gender WRITE setGender NOTIFY genderChanged STORED true) Chris@31: Q_PROPERTY(QSet nationality READ nationality WRITE setNationality NOTIFY nationalityChanged STORED true) Chris@31: Q_PROPERTY(QSet geonameURIs READ geonameURIs WRITE setGeonameURIs NOTIFY geonameURIsChanged STORED true) Chris@31: Q_PROPERTY(QString period READ period WRITE setPeriod NOTIFY periodChanged STORED true) Chris@31: Q_PROPERTY(ClassicalData::Birth *birth READ birth WRITE setBirth NOTIFY birthChanged STORED true) Chris@31: Q_PROPERTY(ClassicalData::Death *death READ death WRITE setDeath NOTIFY deathChanged STORED true) Chris@0: Chris@10: Q_PROPERTY(QString surname READ getSurname STORED false) Chris@10: Q_PROPERTY(QString forenames READ getForenames STORED false) Chris@10: Chris@0: public: Chris@11: Composer(QObject *parent = 0) : Chris@11: NamedEntity(parent), m_birth(0), m_death(0), m_namesCached(false) { } Chris@0: Chris@0: QString gender() const { return m_gender; } Chris@31: void setGender(QString n) { m_gender = n; emit genderChanged(n); } Chris@0: Chris@4: QSet nationality() const { return m_nationality; } Chris@31: void setNationality(QSet n) { m_nationality = n; emit nationalityChanged(n); } Chris@31: void addNationality(QString n) { m_nationality.insert(n); emit nationalityChanged(m_nationality); } Chris@4: Chris@18: QSet geonameURIs() const { return m_geonameURIs; } Chris@31: void setGeonameURIs(QSet n) { m_geonameURIs = n; emit geonameURIsChanged(n); } Chris@31: void addGeonameURI(Dataquay::Uri n) { m_geonameURIs.insert(n); emit geonameURIsChanged(m_geonameURIs); } Chris@0: Chris@0: QString period() const { return m_period; } Chris@31: void setPeriod(QString n) { m_period = n; emit periodChanged(n); } Chris@0: Chris@0: Birth *birth() { return m_birth; } Chris@0: const Birth *birth() const { return m_birth; } Chris@31: void setBirth(Birth *b) { m_birth = b; emit birthChanged(b); } Chris@0: Chris@0: Death *death() { return m_death; } Chris@0: const Death *death() const { return m_death; } Chris@31: void setDeath(Death *d) { m_death = d; emit deathChanged(d); } Chris@0: Chris@11: virtual void setName(QString n) { Chris@11: NamedEntity::setName(n); Chris@11: m_namesCached = false; Chris@11: } Chris@11: virtual void setAliases(QSet l) { Chris@11: NamedEntity::setAliases(l); Chris@11: m_namesCached = false; Chris@11: } Chris@11: virtual void addAlias(QString a) { Chris@11: NamedEntity::addAlias(a); Chris@11: m_namesCached = false; Chris@11: } Chris@11: Chris@10: QString getSurname() const; Chris@10: QString getForenames() const; Chris@0: QString getSortName(bool caps) const; Chris@0: QString getDisplayDates() const; Chris@0: Chris@10: /** Chris@10: * Given another composer, return true if the other composer's Chris@10: * dates match outs. This is mostly intended (like Chris@10: * matchCatalogueName) for use in merging distinct catalogues. Chris@10: * Matching is somewhat fuzzy; more slack is cut when the dates Chris@10: * are very long ago or are marked as approximate. Chris@10: */ Chris@10: bool matchDates(const Composer *other) const; // "well enough" Chris@10: Chris@10: /** Chris@10: * Given another name which is intended to be a well-formatted Chris@10: * catalogue name for a composer (but which may differ in Chris@10: * ordering, number of forenames, and perhaps in spelling), test Chris@10: * whether the name is a plausible match for our own. This is Chris@10: * mostly intended (like matchDates) for use in merging distinct Chris@10: * catalogues. Return true if the given name is highly likely to Chris@10: * match our own. Chris@10: */ Chris@10: bool matchCatalogueName(QString otherName) const; Chris@10: Chris@10: /** Chris@10: * Given another name which is believed to be a user-entered Chris@10: * composer name with unpredictable formatting and spelling (and Chris@10: * probably incomplete), return an estimate for the likelihood Chris@10: * that the intended composer was this one. Higher return values Chris@16: * indicate greater confidence; a value of 1.0 or more indicates Chris@16: * that all of the input is at least close to perfectly matched. Chris@10: */ Chris@14: float matchFuzzyName(QString name) const; Chris@10: Chris@10: /** Chris@13: * Given another name which is believed to be a user-entered Chris@13: * composer name with unpredictable formatting and spelling (and Chris@13: * probably incomplete), return an estimate for the likelihood Chris@13: * that the intended composer was this one. Higher return values Chris@16: * indicate greater confidence; a value of 1.0 or more indicates Chris@16: * that all of the input is at least close to perfectly matched. Chris@16: * The supplied name should have been lower-cased and split on Chris@16: * non-alphabetical characters. Chris@13: */ Chris@14: float matchFuzzyName(QStringList name) const; Chris@13: Chris@13: /** Chris@16: * Given a string that is in the process of being typed by the Chris@16: * user, return an estimate of the likelihood that the text is Chris@28: * intended to become this composer's name. If quick is true, do Chris@28: * a quick(er) scan only and avoid very expensive tests. Chris@16: */ Chris@16: float matchTyping(QString text) const; Chris@16: Chris@16: /** Chris@28: * Given a string that is in the process of being typed by the Chris@28: * user, return an estimate of the likelihood that the text is Chris@28: * intended to become this composer's name. In contrast to Chris@28: * matchTyping, do a quick(er) scan only, avoiding more expensive Chris@28: * tests. Chris@28: */ Chris@28: float matchTypingQuick(QString text) const; Chris@28: Chris@28: /** Chris@24: * Merge data from the given composer into this composer record. Chris@24: * That is, add the composer's name and aliases as aliases of this Chris@24: * composer, copy its dates where we lack them, etc. In all Chris@24: * cases, values that exist in this composer already are preferred Chris@24: * over values from the "other" composer. Chris@24: */ Chris@24: void mergeFrom(Composer *c); Chris@24: Chris@24: /** Chris@10: * Return the supplied name reduced into a "simplified" form, Chris@10: * eliminating many of the differences often found particularly in Chris@10: * European language names that have been anglicised. Used in Chris@10: * catalogue and fuzzy name matching. Chris@10: */ Chris@10: static QString reduceName(QString name); Chris@10: Chris@31: signals: Chris@31: void genderChanged(QString); Chris@31: void nationalityChanged(QSet); Chris@31: void geonameURIsChanged(QSet); Chris@31: void periodChanged(QString); Chris@31: void birthChanged(Birth *); Chris@31: void deathChanged(Death *); Chris@31: Chris@0: private: Chris@0: QString m_gender; Chris@4: QSet m_nationality; Chris@18: QSet m_geonameURIs; Chris@0: QString m_period; Chris@0: Birth *m_birth; Chris@0: Death *m_death; Chris@11: Chris@11: void cacheNames() const; Chris@28: float doMatchTyping(QString, bool) const; Chris@11: mutable bool m_namesCached; Chris@11: mutable QString m_surname; Chris@11: mutable QString m_forenames; Chris@11: mutable QStringList m_surnameElements; Chris@11: mutable QStringList m_connectiveElements; Chris@11: mutable QStringList m_forenameElements; Chris@11: mutable QStringList m_otherElements; Chris@11: mutable QStringList m_reducedSurnameElements; Chris@11: mutable QStringList m_reducedForenameElements; Chris@0: }; Chris@0: Chris@0: class Form : public NamedEntity Chris@0: { Chris@0: Q_OBJECT Chris@0: Chris@31: Q_PROPERTY(Dataquay::Uri uri READ uri) Chris@0: Chris@0: public: Chris@0: Form(QObject *parent = 0) : NamedEntity(parent) { } Chris@0: Chris@0: static Form *getFormByName(QString name) { Chris@0: QMutexLocker locker(&m_mutex); Chris@0: if (!m_map.contains(name)) { Chris@0: Form *f = new Form(); Chris@0: f->setName(name); Chris@0: m_map[name] = f; Chris@0: } Chris@0: return m_map[name]; Chris@0: } Chris@0: Chris@31: Dataquay::Uri uri() const { Chris@31: return Dataquay::Uri Chris@31: (QString(":form_%1").arg(name()).toLower().replace(' ', '_')); Chris@0: } Chris@0: Chris@0: private: Chris@0: static QMap m_map; Chris@0: static QMutex m_mutex; Chris@0: }; Chris@0: Chris@48: class AudioFileTag : public QObject Chris@48: { Chris@48: Q_OBJECT Chris@48: Chris@48: Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged STORED true) Chris@48: Q_PROPERTY(QString value READ value WRITE setValue NOTIFY valueChanged STORED true) Chris@48: Chris@48: public: Chris@48: AudioFileTag(QObject *parent = 0) : QObject(parent) { } Chris@48: AudioFileTag(QString name, QString value, QObject *parent = 0) : Chris@48: QObject(parent), m_name(name), m_value(value) { } Chris@48: Chris@48: QString name() const { return m_name; } Chris@48: void setName(QString n) { m_name = n; emit nameChanged(m_name); } Chris@48: Chris@48: QString value() const { return m_value; } Chris@48: void setValue(QString v) { m_value = v; emit valueChanged(m_value); } Chris@48: Chris@48: signals: Chris@48: void nameChanged(QString); Chris@48: void valueChanged(QString); Chris@48: Chris@48: private: Chris@48: QString m_name; Chris@48: QString m_value; Chris@48: }; Chris@48: Chris@48: // Separate AudioFile and Signal, to correspond with MO Chris@45: Chris@45: class AudioFile : public QObject Chris@33: { Chris@33: Q_OBJECT Chris@33: Chris@33: Q_PROPERTY(QString hash READ hash WRITE setHash NOTIFY hashChanged STORED true) Chris@33: Q_PROPERTY(Dataquay::Uri uri READ uri WRITE setUri NOTIFY uriChanged STORED true) Chris@48: Q_PROPERTY(QSet tags READ tags WRITE setTags NOTIFY tagsChanged STORED true) Chris@33: Chris@33: public: Chris@45: AudioFile(QObject *parent = 0); Chris@45: AudioFile(FileSource file, QObject *parent = 0); Chris@48: ~AudioFile(); Chris@45: Chris@45: /// The URI is set automatically from the FileSource at construction Chris@45: Dataquay::Uri uri() const { return m_uri; } Chris@45: void setUri(Dataquay::Uri u) { m_uri = u; emit uriChanged(u); } Chris@45: Chris@43: /// The hash is set automatically from the FileSource at construction Chris@33: QString hash() const { return m_hash; } Chris@33: void setHash(QString hash) { m_hash = hash; emit hashChanged(hash); } Chris@33: Chris@48: /// I take ownership of all tags Chris@48: QSet tags() { return m_tags; } Chris@48: void setTags(QSet t); Chris@48: void addTag(AudioFileTag *t); Chris@48: Chris@45: signals: Chris@45: void uriChanged(Dataquay::Uri); Chris@45: void hashChanged(QString); Chris@48: void tagsChanged(QSet); Chris@45: Chris@45: private: Chris@45: Dataquay::Uri m_uri; Chris@45: QString m_hash; Chris@48: QSet m_tags; Chris@45: }; Chris@45: Chris@45: class Signal : public QObject Chris@45: { Chris@45: Q_OBJECT Chris@45: Chris@45: Q_PROPERTY(QString ofaFingerprint READ ofaFingerprint WRITE setOfaFingerprint NOTIFY ofaFingerprintChanged STORED true) Chris@45: Q_PROPERTY(QString puid READ puid WRITE setPuid NOTIFY puidChanged STORED true) Chris@45: Q_PROPERTY(QSet availableAs READ availableAs WRITE setAvailableAs NOTIFY availableAsChanged STORED true) Chris@45: Q_PROPERTY(ClassicalData::Composer *composer READ composer WRITE setComposer NOTIFY composerChanged STORED true) Chris@45: Q_PROPERTY(ClassicalData::Work *work READ work WRITE setWork NOTIFY workChanged STORED true) Chris@45: Q_PROPERTY(ClassicalData::Movement *movement READ movement WRITE setMovement NOTIFY movementChanged STORED true) Chris@45: Chris@45: public: Chris@45: Signal() : m_composer(0), m_work(0), m_movement(0) { } Chris@33: Chris@33: QString ofaFingerprint() const { return m_ofaFingerprint; } Chris@33: void setOfaFingerprint(QString fprint) { m_ofaFingerprint = fprint; emit ofaFingerprintChanged(fprint); } Chris@33: Chris@33: QString puid() const { return m_puid; } Chris@33: void setPuid(QString puid) { m_puid = puid; emit puidChanged(puid); } Chris@33: Chris@45: QSet availableAs() const { return m_availableAs; } Chris@45: void setAvailableAs(QSet aa) { m_availableAs = aa; emit availableAsChanged(m_availableAs); } Chris@45: void addAvailableAs(AudioFile *aa) { m_availableAs.insert(aa); emit availableAsChanged(m_availableAs); } Chris@45: Chris@33: Composer *composer() const { return m_composer; } Chris@33: void setComposer(Composer *c) { m_composer = c; emit composerChanged(c); } Chris@33: Chris@33: Work *work() const { return m_work; } Chris@33: void setWork(Work *w) { m_work = w; emit workChanged(w); } Chris@33: Chris@33: Movement *movement() const { return m_movement; } Chris@33: void setMovement(Movement *m) { m_movement = m; emit movementChanged(m); } Chris@33: Chris@33: signals: Chris@33: void ofaFingerprintChanged(QString); Chris@33: void puidChanged(QString); Chris@33: void composerChanged(Composer *); Chris@33: void workChanged(Work *); Chris@33: void movementChanged(Movement *); Chris@45: void availableAsChanged(QSet); Chris@33: Chris@33: private: Chris@33: QString m_ofaFingerprint; Chris@33: QString m_puid; Chris@33: Composer *m_composer; Chris@33: Work *m_work; Chris@33: Movement *m_movement; Chris@45: QSet m_availableAs; Chris@33: }; Chris@33: Chris@0: } Chris@0: Chris@21: Q_DECLARE_METATYPE(ClassicalData::Year); Chris@0: Q_DECLARE_METATYPE(ClassicalData::HistoricalEvent*); Chris@0: Q_DECLARE_METATYPE(ClassicalData::Birth*); Chris@0: Q_DECLARE_METATYPE(ClassicalData::Death*); Chris@0: Q_DECLARE_METATYPE(ClassicalData::Composition*); Chris@0: Q_DECLARE_METATYPE(ClassicalData::Work*); Chris@0: Q_DECLARE_METATYPE(ClassicalData::Movement*); Chris@0: Q_DECLARE_METATYPE(ClassicalData::Document*); Chris@48: Q_DECLARE_METATYPE(ClassicalData::AudioFileTag*); Chris@45: Q_DECLARE_METATYPE(ClassicalData::AudioFile*); Chris@45: Q_DECLARE_METATYPE(ClassicalData::Signal*); Chris@0: Q_DECLARE_METATYPE(QSet); Chris@18: Q_DECLARE_METATYPE(QSet); Chris@0: Q_DECLARE_METATYPE(QSet); Chris@0: Q_DECLARE_METATYPE(QSet); Chris@0: Q_DECLARE_METATYPE(QSet); Chris@48: Q_DECLARE_METATYPE(QSet); Chris@45: Q_DECLARE_METATYPE(QSet); Chris@45: Q_DECLARE_METATYPE(QSet); Chris@0: Q_DECLARE_METATYPE(ClassicalData::Composer*); Chris@0: Q_DECLARE_METATYPE(ClassicalData::Form*); Chris@0: Q_DECLARE_METATYPE(QSet); Chris@30: Q_DECLARE_METATYPE(ClassicalData::NamedEntity*); Chris@0: Chris@0: #endif