annotate common/Objects.h @ 11:98047b91b09d classical-rdf

* Add "proper" composer name matching from user input. Needs to be faster though
author Chris Cannam
date Thu, 18 Feb 2010 18:16:43 +0000
parents d35e5d769c87
children a1d67e136c30
rev   line source
Chris@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 #ifndef _CLASSICAL_DATA_OBJECTS_H_
Chris@0 4 #define _CLASSICAL_DATA_OBJECTS_H_
Chris@0 5
Chris@0 6 #include <QObject>
Chris@0 7 #include <QMetaType>
Chris@0 8 #include <QString>
Chris@0 9 #include <QStringList>
Chris@0 10 #include <QSharedPointer>
Chris@0 11 #include <QUrl>
Chris@0 12 #include <QSet>
Chris@0 13 #include <QMutex>
Chris@0 14 #include <QMutexLocker>
Chris@0 15 #include <QMap>
Chris@0 16
Chris@4 17 extern unsigned int qHash(const QUrl &u);
Chris@4 18
Chris@0 19 namespace ClassicalData {
Chris@0 20
Chris@0 21 class HistoricalEvent : public QObject
Chris@0 22 {
Chris@0 23 Q_OBJECT
Chris@0 24
Chris@0 25 Q_PROPERTY(int year READ year WRITE setYear STORED true)
Chris@0 26 Q_PROPERTY(QString place READ place WRITE setPlace STORED true)
Chris@0 27 Q_PROPERTY(bool approximate READ approximate WRITE setApproximate STORED true)
Chris@0 28
Chris@0 29 public:
Chris@0 30 HistoricalEvent() : m_year(0), m_place(), m_approximate(false) { }
Chris@0 31 HistoricalEvent(int y) : m_year(y), m_approximate(false) { }
Chris@0 32 HistoricalEvent(int y, QString p) : m_year(y), m_place(p), m_approximate(false) { }
Chris@0 33
Chris@0 34 int year() const { return m_year; }
Chris@0 35 void setYear(int y) { m_year = y; }
Chris@0 36 QString place() const { return m_place; }
Chris@0 37 void setPlace(QString p) { m_place = p; }
Chris@0 38 bool approximate() const { return m_approximate; }
Chris@0 39 void setApproximate(bool a) { m_approximate = a; }
Chris@0 40
Chris@0 41 private:
Chris@0 42 int m_year;
Chris@0 43 QString m_place;
Chris@0 44 bool m_approximate;
Chris@0 45 };
Chris@0 46
Chris@0 47 class Birth : public HistoricalEvent
Chris@0 48 {
Chris@0 49 Q_OBJECT
Chris@0 50
Chris@0 51 public:
Chris@0 52 Birth() : HistoricalEvent() { }
Chris@0 53 Birth(int y) : HistoricalEvent(y) { }
Chris@0 54 Birth(int y, QString p) : HistoricalEvent(y, p) { }
Chris@0 55 };
Chris@0 56
Chris@0 57 class Death : public HistoricalEvent
Chris@0 58 {
Chris@0 59 Q_OBJECT
Chris@0 60
Chris@0 61 public:
Chris@0 62 Death() : HistoricalEvent() { }
Chris@0 63 Death(int y) : HistoricalEvent(y) { }
Chris@0 64 Death(int y, QString p) : HistoricalEvent(y, p) { }
Chris@0 65 };
Chris@0 66
Chris@0 67 class Composer;
Chris@0 68 class Work;
Chris@0 69
Chris@0 70 class Composition : public HistoricalEvent
Chris@0 71 {
Chris@0 72 Q_OBJECT
Chris@0 73
Chris@0 74 Q_PROPERTY(ClassicalData::Composer *composer READ composer WRITE setComposer STORED true)
Chris@0 75 Q_PROPERTY(QSet<ClassicalData::Work *> works READ works WRITE setWorks STORED true)
Chris@0 76 Q_PROPERTY(QString composerName READ composerName WRITE setComposerName STORED false)
Chris@0 77
Chris@0 78 public:
Chris@0 79 Composition() : HistoricalEvent(), m_composer(0) { }
Chris@0 80 Composition(int y) : HistoricalEvent(y), m_composer(0) { }
Chris@0 81 Composition(int y, QString p) : HistoricalEvent(y, p), m_composer(0) { }
Chris@0 82
Chris@0 83 Composer *composer() { return m_composer; }
Chris@0 84 void setComposer(Composer *c) { m_composer = c; }
Chris@0 85
Chris@0 86 QSet<Work *> works() { return m_works; }
Chris@0 87 void setWorks(QSet<Work *> c) { m_works = c; }
Chris@0 88 void addWork(Work *w) { m_works.insert(w); }
Chris@0 89
Chris@0 90 // Not a storable property, set temporarily while composer record is found
Chris@0 91 QString composerName() const { return m_cname; }
Chris@0 92 void setComposerName(QString n) { m_cname = n; }
Chris@0 93
Chris@0 94 private:
Chris@0 95 Composer *m_composer;
Chris@0 96 QSet<Work *> m_works;
Chris@0 97 QString m_cname;
Chris@0 98 };
Chris@0 99
Chris@0 100 class Document : public QObject
Chris@0 101 {
Chris@0 102 Q_OBJECT
Chris@0 103
Chris@0 104 Q_PROPERTY(QUrl uri READ uri WRITE setUri STORED true)
Chris@0 105 Q_PROPERTY(QString siteName READ siteName WRITE setSiteName STORED true)
Chris@0 106 Q_PROPERTY(QObject *topic READ topic WRITE setTopic STORED true)
Chris@0 107
Chris@0 108 public:
Chris@0 109 Document(QObject *parent = 0) : QObject(parent), m_topic(0) { }
Chris@0 110
Chris@0 111 QUrl uri() const { return m_uri; }
Chris@0 112 void setUri(QUrl uri) { m_uri = uri; }
Chris@0 113
Chris@0 114 QString siteName() const { return m_siteName; }
Chris@0 115 void setSiteName(QString n) { m_siteName = n; }
Chris@0 116
Chris@0 117 QObject *topic() const { return m_topic; }
Chris@0 118 void setTopic(QObject *t) { m_topic = t; }
Chris@0 119
Chris@0 120 private:
Chris@0 121 QUrl m_uri;
Chris@0 122 QString m_siteName;
Chris@0 123 QObject *m_topic;
Chris@0 124 };
Chris@0 125
Chris@0 126
Chris@0 127 class NamedEntity : public QObject
Chris@0 128 {
Chris@0 129 Q_OBJECT
Chris@0 130
Chris@0 131 Q_PROPERTY(QString name READ name WRITE setName STORED true)
Chris@0 132 Q_PROPERTY(QSet<QString> aliases READ aliases WRITE setAliases STORED true)
Chris@0 133 Q_PROPERTY(QString remarks READ remarks WRITE setRemarks STORED true)
Chris@0 134 Q_PROPERTY(QSet<ClassicalData::Document*> pages READ pages WRITE setPages STORED true)
Chris@0 135
Chris@0 136 public:
Chris@0 137 NamedEntity(QObject *parent = 0) : QObject(parent) { }
Chris@0 138
Chris@0 139 QString name() const { return m_name; }
Chris@11 140 virtual void setName(QString n) { m_name = n; }
Chris@0 141
Chris@0 142 QString remarks() const { return m_remarks; }
Chris@0 143 void setRemarks(QString n) { m_remarks = n; }
Chris@0 144
Chris@0 145 QSet<QString> aliases() const { return m_aliases; }
Chris@11 146 virtual void setAliases(QSet<QString> l) { m_aliases = l; }
Chris@11 147 virtual void addAlias(QString a) { m_aliases.insert(a); }
Chris@0 148
Chris@0 149 QSet<Document *> pages() const { return m_pages; }
Chris@0 150 void addPage(Document *p) { m_pages.insert(p); }
Chris@0 151 void setPages(QSet<Document *> p) { m_pages = p; } //!!! destroy old ones? do we own?
Chris@0 152
Chris@11 153 protected:
Chris@0 154 QString m_name;
Chris@0 155 QString m_remarks;
Chris@0 156 QSet<QString> m_aliases;
Chris@0 157 QSet<Document *> m_pages;
Chris@0 158 };
Chris@0 159
Chris@0 160 class Movement;
Chris@0 161
Chris@0 162 class Form;
Chris@0 163
Chris@0 164 class Work : public NamedEntity
Chris@0 165 {
Chris@0 166 Q_OBJECT
Chris@0 167
Chris@0 168 Q_PROPERTY(QString key READ key WRITE setKey STORED true)
Chris@0 169 Q_PROPERTY(QString opus READ opus WRITE setOpus STORED true)
Chris@0 170 Q_PROPERTY(QString catalogue READ catalogue WRITE setCatalogue STORED true)
Chris@0 171 Q_PROPERTY(QString number READ number WRITE setNumber STORED true)
Chris@0 172 Q_PROPERTY(QSet<ClassicalData::Form*> forms READ forms WRITE setForms STORED true)
Chris@0 173 Q_PROPERTY(ClassicalData::Work* partOf READ partOf WRITE setPartOf STORED true)
Chris@0 174 Q_PROPERTY(QSet<ClassicalData::Work*> parts READ parts WRITE setParts STORED true)
Chris@0 175 Q_PROPERTY(QSet<ClassicalData::Movement*> movements READ movements WRITE setMovements STORED true)
Chris@0 176 Q_PROPERTY(ClassicalData::Composition *composition READ composition WRITE setComposition STORED true)
Chris@0 177
Chris@0 178 public:
Chris@0 179 Work(QObject *parent = 0) : NamedEntity(parent), m_partOf(0), m_composition(0) { }
Chris@0 180
Chris@0 181 QString key() const { return m_key; }
Chris@0 182 void setKey(QString n) { m_key = n; }
Chris@0 183
Chris@0 184 QString opus() const { return m_opus; }
Chris@0 185 void setOpus(QString n) { m_opus = n; }
Chris@0 186
Chris@0 187 QString catalogue() const { return m_catalogue; }
Chris@0 188 void setCatalogue(QString n) { m_catalogue = n; }
Chris@0 189
Chris@0 190 QString number() const { return m_number; }
Chris@0 191 void setNumber(QString n) { m_number = n; }
Chris@0 192
Chris@0 193 QSet<Form *> forms() const { return m_forms; }
Chris@0 194 void setForms(QSet<Form *> f) { m_forms = f; }
Chris@0 195 void addForm(Form *f) { m_forms.insert(f); }
Chris@0 196
Chris@0 197 Work *partOf() const { return m_partOf; }
Chris@0 198 void setPartOf(Work *w) { m_partOf = w; }
Chris@0 199
Chris@0 200 QSet<Work *> parts() const { return m_parts; }
Chris@0 201 void setParts(QSet<Work *> l) { m_parts = l; }
Chris@0 202 void addPart(Work *w) { m_parts.insert(w); }
Chris@0 203
Chris@0 204 QSet<Movement *> movements() const { return m_movements; }
Chris@0 205 void setMovements(QSet<Movement *> l) { m_movements = l; }
Chris@0 206 void addMovement(Movement *w) { m_movements.insert(w); }
Chris@0 207
Chris@0 208 Composition *composition() { return m_composition; }
Chris@0 209 const Composition *composition() const { return m_composition; }
Chris@0 210 void setComposition(Composition *c) { m_composition = c; }
Chris@0 211
Chris@0 212 struct Ordering {
Chris@0 213 bool operator()(Work *, Work *);
Chris@0 214 };
Chris@0 215
Chris@10 216 /**
Chris@10 217 * Compare the ordering of two strings that are known to contain
Chris@10 218 * catalogue number texts, such as "Op. 1 no 4" and "Op. 3 no 2"
Chris@10 219 * (which should compare in that order). Return value is as for
Chris@10 220 * strcmp.
Chris@10 221 */
Chris@10 222 //!!! todo: unit tests
Chris@10 223 static int compareCatalogueNumberTexts(QString a, QString b);
Chris@10 224
Chris@0 225 private:
Chris@0 226 QString m_key;
Chris@0 227 QString m_opus;
Chris@0 228 QString m_catalogue;
Chris@0 229 QString m_number;
Chris@0 230 QSet<Form *> m_forms;
Chris@0 231 Work *m_partOf;
Chris@0 232 QSet<Work *> m_parts;
Chris@0 233 QSet<Movement *> m_movements;
Chris@0 234 Composition *m_composition;
Chris@0 235 };
Chris@0 236
Chris@0 237 class Movement : public NamedEntity
Chris@0 238 {
Chris@0 239 Q_OBJECT
Chris@0 240
Chris@0 241 Q_PROPERTY(QString key READ key WRITE setKey STORED true)
Chris@0 242 Q_PROPERTY(QString number READ number WRITE setNumber STORED true)
Chris@0 243 Q_PROPERTY(ClassicalData::Work* partOf READ partOf WRITE setPartOf STORED true)
Chris@0 244 Q_PROPERTY(QSet<ClassicalData::Movement*> parts READ parts WRITE setParts STORED true) // movements can be nested
Chris@0 245 Q_PROPERTY(ClassicalData::Composition *composition READ composition WRITE setComposition STORED true)
Chris@0 246
Chris@0 247 public:
Chris@0 248 Movement(QObject *parent = 0) : NamedEntity(parent), m_partOf(0), m_composition(0) { }
Chris@0 249
Chris@0 250 QString key() const { return m_key; }
Chris@0 251 void setKey(QString n) { m_key = n; }
Chris@0 252
Chris@0 253 QString number() const { return m_number; }
Chris@0 254 void setNumber(QString n) { m_number = n; }
Chris@0 255
Chris@0 256 Work *partOf() const { return m_partOf; }
Chris@0 257 void setPartOf(Work *w) { m_partOf = w; }
Chris@0 258
Chris@0 259 QSet<Movement *> parts() const { return m_parts; }
Chris@0 260 void setParts(QSet<Movement *> l) { m_parts = l; }
Chris@0 261 void addPart(Movement *w) { m_parts.insert(w); }
Chris@0 262
Chris@0 263 Composition *composition() { return m_composition; }
Chris@0 264 const Composition *composition() const { return m_composition; }
Chris@0 265 void setComposition(Composition *c) { m_composition = c; }
Chris@0 266
Chris@0 267 private:
Chris@0 268 QString m_key;
Chris@0 269 QString m_number;
Chris@0 270 Work *m_partOf;
Chris@0 271 QSet<Movement *> m_parts;
Chris@0 272 Composition *m_composition;
Chris@0 273 };
Chris@0 274
Chris@0 275 class Composer : public NamedEntity
Chris@0 276 {
Chris@0 277 Q_OBJECT
Chris@0 278
Chris@0 279 Q_PROPERTY(QString gender READ gender WRITE setGender STORED true)
Chris@4 280 Q_PROPERTY(QSet<QString> nationality READ nationality WRITE setNationality STORED true)
Chris@4 281 Q_PROPERTY(QSet<QUrl> geonameURIs READ geonameURIs WRITE setGeonameURIs STORED true)
Chris@0 282 Q_PROPERTY(QString period READ period WRITE setPeriod STORED true)
Chris@0 283 Q_PROPERTY(ClassicalData::Birth *birth READ birth WRITE setBirth STORED true)
Chris@0 284 Q_PROPERTY(ClassicalData::Death *death READ death WRITE setDeath STORED true)
Chris@0 285
Chris@10 286 Q_PROPERTY(QString surname READ getSurname STORED false)
Chris@10 287 Q_PROPERTY(QString forenames READ getForenames STORED false)
Chris@10 288
Chris@0 289 public:
Chris@11 290 Composer(QObject *parent = 0) :
Chris@11 291 NamedEntity(parent), m_birth(0), m_death(0), m_namesCached(false) { }
Chris@0 292
Chris@0 293 QString gender() const { return m_gender; }
Chris@0 294 void setGender(QString n) { m_gender = n; }
Chris@0 295
Chris@4 296 QSet<QString> nationality() const { return m_nationality; }
Chris@4 297 void setNationality(QSet<QString> n) { m_nationality = n; }
Chris@4 298 void addNationality(QString n) { m_nationality.insert(n); }
Chris@4 299
Chris@4 300 QSet<QUrl> geonameURIs() const { return m_geonameURIs; }
Chris@4 301 void setGeonameURIs(QSet<QUrl> n) { m_geonameURIs = n; }
Chris@4 302 void addGeonameURI(QUrl n) { m_geonameURIs.insert(n); }
Chris@0 303
Chris@0 304 QString period() const { return m_period; }
Chris@0 305 void setPeriod(QString n) { m_period = n; }
Chris@0 306
Chris@0 307 Birth *birth() { return m_birth; }
Chris@0 308 const Birth *birth() const { return m_birth; }
Chris@0 309 void setBirth(Birth *b) { m_birth = b; }
Chris@0 310
Chris@0 311 Death *death() { return m_death; }
Chris@0 312 const Death *death() const { return m_death; }
Chris@0 313 void setDeath(Death *d) { m_death = d; }
Chris@0 314
Chris@11 315 virtual void setName(QString n) {
Chris@11 316 NamedEntity::setName(n);
Chris@11 317 m_namesCached = false;
Chris@11 318 }
Chris@11 319 virtual void setAliases(QSet<QString> l) {
Chris@11 320 NamedEntity::setAliases(l);
Chris@11 321 m_namesCached = false;
Chris@11 322 }
Chris@11 323 virtual void addAlias(QString a) {
Chris@11 324 NamedEntity::addAlias(a);
Chris@11 325 m_namesCached = false;
Chris@11 326 }
Chris@11 327
Chris@10 328 QString getSurname() const;
Chris@10 329 QString getForenames() const;
Chris@0 330 QString getSortName(bool caps) const;
Chris@0 331 QString getDisplayDates() const;
Chris@0 332
Chris@10 333 /**
Chris@10 334 * Given another composer, return true if the other composer's
Chris@10 335 * dates match outs. This is mostly intended (like
Chris@10 336 * matchCatalogueName) for use in merging distinct catalogues.
Chris@10 337 * Matching is somewhat fuzzy; more slack is cut when the dates
Chris@10 338 * are very long ago or are marked as approximate.
Chris@10 339 */
Chris@10 340 bool matchDates(const Composer *other) const; // "well enough"
Chris@10 341
Chris@10 342 /**
Chris@10 343 * Given another name which is intended to be a well-formatted
Chris@10 344 * catalogue name for a composer (but which may differ in
Chris@10 345 * ordering, number of forenames, and perhaps in spelling), test
Chris@10 346 * whether the name is a plausible match for our own. This is
Chris@10 347 * mostly intended (like matchDates) for use in merging distinct
Chris@10 348 * catalogues. Return true if the given name is highly likely to
Chris@10 349 * match our own.
Chris@10 350 */
Chris@10 351 bool matchCatalogueName(QString otherName) const;
Chris@10 352
Chris@10 353 /**
Chris@10 354 * Given another name which is believed to be a user-entered
Chris@10 355 * composer name with unpredictable formatting and spelling (and
Chris@10 356 * probably incomplete), return an estimate for the likelihood
Chris@10 357 * that the intended composer was this one. Higher return values
Chris@10 358 * indicate greater confidence.
Chris@10 359 */
Chris@10 360 int matchFuzzyName(QString name) const;
Chris@10 361
Chris@10 362 /**
Chris@10 363 * Return the supplied name reduced into a "simplified" form,
Chris@10 364 * eliminating many of the differences often found particularly in
Chris@10 365 * European language names that have been anglicised. Used in
Chris@10 366 * catalogue and fuzzy name matching.
Chris@10 367 */
Chris@10 368 static QString reduceName(QString name);
Chris@10 369
Chris@0 370 private:
Chris@0 371 QString m_gender;
Chris@4 372 QSet<QString> m_nationality;
Chris@4 373 QSet<QUrl> m_geonameURIs;
Chris@0 374 QString m_period;
Chris@0 375 Birth *m_birth;
Chris@0 376 Death *m_death;
Chris@11 377
Chris@11 378 void cacheNames() const;
Chris@11 379 mutable bool m_namesCached;
Chris@11 380 mutable QString m_surname;
Chris@11 381 mutable QString m_forenames;
Chris@11 382 mutable QStringList m_surnameElements;
Chris@11 383 mutable QStringList m_connectiveElements;
Chris@11 384 mutable QStringList m_forenameElements;
Chris@11 385 mutable QStringList m_otherElements;
Chris@11 386 mutable QStringList m_reducedSurnameElements;
Chris@11 387 mutable QStringList m_reducedForenameElements;
Chris@0 388 };
Chris@0 389
Chris@0 390 class Form : public NamedEntity
Chris@0 391 {
Chris@0 392 Q_OBJECT
Chris@0 393
Chris@0 394 Q_PROPERTY(QString uri READ uri)
Chris@0 395
Chris@0 396 public:
Chris@0 397 Form(QObject *parent = 0) : NamedEntity(parent) { }
Chris@0 398
Chris@0 399 static Form *getFormByName(QString name) {
Chris@0 400 QMutexLocker locker(&m_mutex);
Chris@0 401 if (!m_map.contains(name)) {
Chris@0 402 Form *f = new Form();
Chris@0 403 f->setName(name);
Chris@0 404 m_map[name] = f;
Chris@0 405 }
Chris@0 406 return m_map[name];
Chris@0 407 }
Chris@0 408
Chris@0 409 QString uri() const {
Chris@0 410 return QString(":form_%1").arg(name()).toLower().replace(' ', '_');
Chris@0 411 }
Chris@0 412
Chris@0 413 private:
Chris@0 414 static QMap<QString, Form *> m_map;
Chris@0 415 static QMutex m_mutex;
Chris@0 416 };
Chris@0 417
Chris@0 418 }
Chris@0 419
Chris@0 420 Q_DECLARE_METATYPE(ClassicalData::HistoricalEvent*);
Chris@0 421 Q_DECLARE_METATYPE(ClassicalData::Birth*);
Chris@0 422 Q_DECLARE_METATYPE(ClassicalData::Death*);
Chris@0 423 Q_DECLARE_METATYPE(ClassicalData::Composition*);
Chris@0 424 Q_DECLARE_METATYPE(ClassicalData::Work*);
Chris@0 425 Q_DECLARE_METATYPE(ClassicalData::Movement*);
Chris@0 426 Q_DECLARE_METATYPE(ClassicalData::Document*);
Chris@0 427 Q_DECLARE_METATYPE(QSet<QString>);
Chris@4 428 Q_DECLARE_METATYPE(QSet<QUrl>);
Chris@0 429 Q_DECLARE_METATYPE(QSet<ClassicalData::Work*>);
Chris@0 430 Q_DECLARE_METATYPE(QSet<ClassicalData::Movement*>);
Chris@0 431 Q_DECLARE_METATYPE(QSet<ClassicalData::Document*>);
Chris@0 432 Q_DECLARE_METATYPE(ClassicalData::Composer*);
Chris@0 433 Q_DECLARE_METATYPE(ClassicalData::Form*);
Chris@0 434 Q_DECLARE_METATYPE(QSet<ClassicalData::Form*>);
Chris@0 435
Chris@0 436 #endif