To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.
root / common / Objects.h
History | View | Annotate | Download (25.8 KB)
| 1 |
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
|---|---|
| 2 |
|
| 3 |
#ifndef _CLASSICAL_DATA_OBJECTS_H_
|
| 4 |
#define _CLASSICAL_DATA_OBJECTS_H_
|
| 5 |
|
| 6 |
#include <dataquay/Uri.h> |
| 7 |
#include <dataquay/Node.h> |
| 8 |
|
| 9 |
#include <QObject> |
| 10 |
#include <QMetaType> |
| 11 |
#include <QString> |
| 12 |
#include <QStringList> |
| 13 |
#include <QSharedPointer> |
| 14 |
#include <QSet> |
| 15 |
#include <QMutex> |
| 16 |
#include <QMutexLocker> |
| 17 |
#include <QMap> |
| 18 |
|
| 19 |
#include <iostream> |
| 20 |
|
| 21 |
#include "data/fileio/FileSource.h" |
| 22 |
|
| 23 |
namespace ClassicalData {
|
| 24 |
|
| 25 |
//!!! need to review ownership more carefully -- and use deletion notify signals?
|
| 26 |
|
| 27 |
class Year |
| 28 |
{
|
| 29 |
public:
|
| 30 |
Year() : m_year(0) { }
|
| 31 |
Year(int y) : m_year(y) { }
|
| 32 |
|
| 33 |
int toInt() const { return m_year; } |
| 34 |
operator int() { return m_year; } |
| 35 |
|
| 36 |
struct Encoder : public Dataquay::Node::VariantEncoder {
|
| 37 |
QString fromVariant(const QVariant &v) {
|
| 38 |
int y = v.value<Year>().toInt();
|
| 39 |
if (y == 0) return ""; |
| 40 |
QString s = QString("%1").arg(y);
|
| 41 |
return s;
|
| 42 |
} |
| 43 |
QVariant toVariant(const QString &s) {
|
| 44 |
if (s == "") return QVariant::fromValue<Year>(Year()); |
| 45 |
QVariant v = QVariant::fromValue<Year>(s.toInt()); |
| 46 |
return v;
|
| 47 |
} |
| 48 |
}; |
| 49 |
|
| 50 |
private:
|
| 51 |
int m_year;
|
| 52 |
}; |
| 53 |
|
| 54 |
class HistoricalEvent : public QObject |
| 55 |
{
|
| 56 |
Q_OBJECT |
| 57 |
|
| 58 |
Q_PROPERTY(ClassicalData::Year year READ year WRITE setYear NOTIFY yearChanged STORED true)
|
| 59 |
Q_PROPERTY(QString place READ place WRITE setPlace NOTIFY placeChanged STORED true)
|
| 60 |
Q_PROPERTY(bool approximate READ approximate WRITE setApproximate NOTIFY approximateChanged STORED true) |
| 61 |
|
| 62 |
public: |
| 63 |
HistoricalEvent() : m_year(0), m_place(), m_approximate(false) { } |
| 64 |
HistoricalEvent(Year y) : m_year(y), m_approximate(false) { }
|
| 65 |
HistoricalEvent(Year y, QString p) : m_year(y), m_place(p), m_approximate(false) { }
|
| 66 |
HistoricalEvent(const HistoricalEvent &h) : QObject(), m_year(h.m_year), m_place(h.m_place), m_approximate(h.m_approximate) { }
|
| 67 |
|
| 68 |
Year year() const { return m_year; } |
| 69 |
void setYear(Year y) { m_year = y; emit yearChanged(y); }
|
| 70 |
QString place() const { return m_place; } |
| 71 |
void setPlace(QString p) { m_place = p; emit placeChanged(p); }
|
| 72 |
bool approximate() const { return m_approximate; } |
| 73 |
void setApproximate(bool a) { m_approximate = a; emit approximateChanged(a); } |
| 74 |
|
| 75 |
signals:
|
| 76 |
void yearChanged(Year);
|
| 77 |
void placeChanged(QString);
|
| 78 |
void approximateChanged(bool); |
| 79 |
|
| 80 |
private:
|
| 81 |
Year m_year; |
| 82 |
QString m_place; |
| 83 |
bool m_approximate;
|
| 84 |
}; |
| 85 |
|
| 86 |
class Birth : public HistoricalEvent |
| 87 |
{
|
| 88 |
Q_OBJECT |
| 89 |
|
| 90 |
public: |
| 91 |
Birth() : HistoricalEvent() { }
|
| 92 |
Birth(Year y) : HistoricalEvent(y) { }
|
| 93 |
Birth(Year y, QString p) : HistoricalEvent(y, p) { }
|
| 94 |
}; |
| 95 |
|
| 96 |
class Death : public HistoricalEvent |
| 97 |
{
|
| 98 |
Q_OBJECT |
| 99 |
|
| 100 |
public: |
| 101 |
Death() : HistoricalEvent() { }
|
| 102 |
Death(Year y) : HistoricalEvent(y) { }
|
| 103 |
Death(Year y, QString p) : HistoricalEvent(y, p) { }
|
| 104 |
}; |
| 105 |
|
| 106 |
class Composer; |
| 107 |
class Work; |
| 108 |
|
| 109 |
class Composition : public HistoricalEvent |
| 110 |
{
|
| 111 |
Q_OBJECT |
| 112 |
|
| 113 |
Q_PROPERTY(ClassicalData::Composer *composer READ composer WRITE setComposer NOTIFY composerChanged STORED true)
|
| 114 |
Q_PROPERTY(QSet<ClassicalData::Work *> works READ works WRITE setWorks NOTIFY worksChanged STORED true)
|
| 115 |
Q_PROPERTY(QString composerName READ getComposerName WRITE setComposerName STORED false)
|
| 116 |
|
| 117 |
public: |
| 118 |
Composition() : HistoricalEvent(), m_composer(0) { }
|
| 119 |
Composition(Year y) : HistoricalEvent(y), m_composer(0) { }
|
| 120 |
Composition(Year y, QString p) : HistoricalEvent(y, p), m_composer(0) { }
|
| 121 |
|
| 122 |
Composer *composer() { return m_composer; }
|
| 123 |
void setComposer(Composer *c) { m_composer = c; emit composerChanged(c); }
|
| 124 |
|
| 125 |
QSet<Work *> works() { return m_works; }
|
| 126 |
void setWorks(QSet<Work *> c) { m_works = c; emit worksChanged(c); }
|
| 127 |
void addWork(Work *w) { m_works.insert(w); emit worksChanged(m_works); }
|
| 128 |
|
| 129 |
// Not a storable property; set temporarily while composer record
|
| 130 |
// is found, or else looked up from composer after composer has
|
| 131 |
// been found
|
| 132 |
QString getComposerName() const;
|
| 133 |
void setComposerName(QString n) { m_cname = n; }
|
| 134 |
|
| 135 |
signals:
|
| 136 |
void composerChanged(Composer *);
|
| 137 |
void worksChanged(QSet<Work *>);
|
| 138 |
|
| 139 |
private:
|
| 140 |
Composer *m_composer; |
| 141 |
QSet<Work *> m_works; |
| 142 |
QString m_cname; |
| 143 |
}; |
| 144 |
|
| 145 |
class Document : public QObject |
| 146 |
{
|
| 147 |
Q_OBJECT |
| 148 |
|
| 149 |
Q_PROPERTY(Dataquay::Uri uri READ uri WRITE setUri NOTIFY uriChanged STORED true)
|
| 150 |
Q_PROPERTY(QString siteName READ siteName WRITE setSiteName NOTIFY siteNameChanged STORED true)
|
| 151 |
Q_PROPERTY(QObject *topic READ topic WRITE setTopic NOTIFY topicChanged STORED true)
|
| 152 |
|
| 153 |
public: |
| 154 |
Document(QObject *parent = 0) : QObject(parent), m_topic(0) { } |
| 155 |
|
| 156 |
Dataquay::Uri uri() const { return m_uri; } |
| 157 |
void setUri(Dataquay::Uri uri) { m_uri = uri; emit uriChanged(uri); }
|
| 158 |
|
| 159 |
QString siteName() const { return m_siteName; } |
| 160 |
void setSiteName(QString n) { m_siteName = n; emit siteNameChanged(n); }
|
| 161 |
|
| 162 |
QObject *topic() const { return m_topic; } // I don't own this |
| 163 |
void setTopic(QObject *t) { m_topic = t; emit topicChanged(t); }
|
| 164 |
|
| 165 |
signals:
|
| 166 |
void uriChanged(Dataquay::Uri);
|
| 167 |
void siteNameChanged(QString);
|
| 168 |
void topicChanged(QObject *);
|
| 169 |
|
| 170 |
private:
|
| 171 |
Dataquay::Uri m_uri; |
| 172 |
QString m_siteName; |
| 173 |
QObject *m_topic; |
| 174 |
}; |
| 175 |
|
| 176 |
|
| 177 |
class NamedEntity : public QObject |
| 178 |
{
|
| 179 |
Q_OBJECT |
| 180 |
|
| 181 |
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged STORED true)
|
| 182 |
Q_PROPERTY(Dataquay::Uri uri READ uri WRITE setUri NOTIFY uriChanged STORED true)
|
| 183 |
Q_PROPERTY(QSet<QString> aliases READ aliases WRITE setAliases NOTIFY aliasesChanged STORED true)
|
| 184 |
Q_PROPERTY(QString remarks READ remarks WRITE setRemarks NOTIFY remarksChanged STORED true)
|
| 185 |
Q_PROPERTY(QSet<ClassicalData::Document*> pages READ pages WRITE setPages NOTIFY pagesChanged STORED true)
|
| 186 |
Q_PROPERTY(QSet<Dataquay::Uri> otherURIs READ otherURIs WRITE setOtherURIs NOTIFY otherURIsChanged STORED true)
|
| 187 |
|
| 188 |
public: |
| 189 |
NamedEntity(QObject *parent = 0) : QObject(parent) { }
|
| 190 |
~NamedEntity() { }
|
| 191 |
|
| 192 |
QString name() const { return m_name; } |
| 193 |
virtual void setName(QString n) { m_name = n; emit nameChanged(n); }
|
| 194 |
|
| 195 |
Dataquay::Uri uri() const { return m_uri; } |
| 196 |
void setUri(Dataquay::Uri uri) { m_uri = uri; emit uriChanged(uri); }
|
| 197 |
|
| 198 |
QString remarks() const { return m_remarks; } |
| 199 |
void setRemarks(QString n) { m_remarks = n; emit remarksChanged(n); }
|
| 200 |
|
| 201 |
QSet<QString> aliases() const { return m_aliases; } |
| 202 |
virtual void setAliases(QSet<QString> l) { m_aliases = l; emit aliasesChanged(l); }
|
| 203 |
virtual void addAlias(QString a) { m_aliases.insert(a); emit aliasesChanged(m_aliases); }
|
| 204 |
|
| 205 |
QSet<Document *> pages() const { return m_pages; } |
| 206 |
void addPage(Document *p) { m_pages.insert(p); emit pagesChanged(m_pages); }
|
| 207 |
void setPages(QSet<Document *> p) {
|
| 208 |
m_pages = p; |
| 209 |
emit pagesChanged(p); |
| 210 |
} |
| 211 |
|
| 212 |
QSet<Dataquay::Uri> otherURIs() const { return m_otherURIs; } |
| 213 |
void addOtherURI(Dataquay::Uri u) { m_otherURIs.insert(u); emit otherURIsChanged(m_otherURIs); }
|
| 214 |
void setOtherURIs(QSet<Dataquay::Uri> u) { m_otherURIs = u; emit otherURIsChanged(u); }
|
| 215 |
|
| 216 |
signals:
|
| 217 |
void uriChanged(Dataquay::Uri);
|
| 218 |
void nameChanged(QString);
|
| 219 |
void remarksChanged(QString);
|
| 220 |
void aliasesChanged(QSet<QString>);
|
| 221 |
void pagesChanged(QSet<Document *>);
|
| 222 |
void otherURIsChanged(QSet<Dataquay::Uri>);
|
| 223 |
|
| 224 |
protected:
|
| 225 |
Dataquay::Uri m_uri; |
| 226 |
QString m_name; |
| 227 |
QString m_remarks; |
| 228 |
QSet<QString> m_aliases; |
| 229 |
QSet<Document *> m_pages; |
| 230 |
QSet<Dataquay::Uri> m_otherURIs; |
| 231 |
}; |
| 232 |
|
| 233 |
class Movement; |
| 234 |
|
| 235 |
class Form; |
| 236 |
|
| 237 |
class Work : public NamedEntity |
| 238 |
{
|
| 239 |
Q_OBJECT |
| 240 |
|
| 241 |
Q_PROPERTY(QString key READ key WRITE setKey NOTIFY keyChanged STORED true)
|
| 242 |
Q_PROPERTY(QString opus READ opus WRITE setOpus NOTIFY opusChanged STORED true)
|
| 243 |
Q_PROPERTY(QString catalogue READ catalogue WRITE setCatalogue NOTIFY catalogueChanged STORED true)
|
| 244 |
Q_PROPERTY(QString number READ number WRITE setNumber NOTIFY numberChanged STORED true)
|
| 245 |
Q_PROPERTY(QSet<ClassicalData::Form*> forms READ forms WRITE setForms NOTIFY formsChanged STORED true)
|
| 246 |
Q_PROPERTY(ClassicalData::Work* partOf READ partOf WRITE setPartOf NOTIFY partOfChanged STORED true)
|
| 247 |
Q_PROPERTY(QSet<ClassicalData::Work*> parts READ parts WRITE setParts NOTIFY partsChanged STORED true)
|
| 248 |
Q_PROPERTY(QSet<ClassicalData::Movement*> movements READ movements WRITE setMovements NOTIFY movementsChanged STORED true)
|
| 249 |
Q_PROPERTY(ClassicalData::Composition *composition READ composition WRITE setComposition NOTIFY compositionChanged STORED true)
|
| 250 |
|
| 251 |
public: |
| 252 |
Work(QObject *parent = 0) : NamedEntity(parent), m_partOf(0), m_composition(0) { } |
| 253 |
|
| 254 |
QString key() const { return m_key; } |
| 255 |
void setKey(QString n) { m_key = n; emit keyChanged(n); }
|
| 256 |
|
| 257 |
/// Should omit Op prefix, e.g. in opus 102 no 2, this would be "102"
|
| 258 |
QString opus() const { return m_opus; } |
| 259 |
void setOpus(QString n) { m_opus = n; emit opusChanged(n); }
|
| 260 |
|
| 261 |
/// For part of a catalogue entry, e.g. in opus 102 no 2, this
|
| 262 |
/// would be "2". Should normally be used only with partOf
|
| 263 |
QString number() const { return m_number; } |
| 264 |
void setNumber(QString n) { m_number = n; emit numberChanged(n); }
|
| 265 |
|
| 266 |
/// Including catalogue prefix, e.g. "BWV 1066"; only for non-opus numbers
|
| 267 |
QString catalogue() const { return m_catalogue; } |
| 268 |
void setCatalogue(QString n) { m_catalogue = n; emit catalogueChanged(n); }
|
| 269 |
|
| 270 |
QSet<Form *> forms() const { return m_forms; } |
| 271 |
void setForms(QSet<Form *> f) { m_forms = f; emit formsChanged(f); }
|
| 272 |
void addForm(Form *f) { m_forms.insert(f); emit formsChanged(m_forms); }
|
| 273 |
|
| 274 |
Work *partOf() const { return m_partOf; } |
| 275 |
void setPartOf(Work *w) { m_partOf = w; emit partOfChanged(w); }
|
| 276 |
|
| 277 |
QSet<Work *> parts() const { return m_parts; } |
| 278 |
void setParts(QSet<Work *> l) { m_parts = l; emit partsChanged(l); }
|
| 279 |
void addPart(Work *w) { m_parts.insert(w); emit partsChanged(m_parts); }
|
| 280 |
|
| 281 |
QSet<Movement *> movements() const { return m_movements; } |
| 282 |
void setMovements(QSet<Movement *> l) { m_movements = l; emit movementsChanged(l); }
|
| 283 |
void addMovement(Movement *w) { m_movements.insert(w); emit movementsChanged(m_movements); }
|
| 284 |
|
| 285 |
Composition *composition() { return m_composition; }
|
| 286 |
const Composition *composition() const { return m_composition; } |
| 287 |
void setComposition(Composition *c) { m_composition = c; emit compositionChanged(c); }
|
| 288 |
|
| 289 |
Composer *getComposer() const {
|
| 290 |
if (m_composition) {
|
| 291 |
return m_composition->composer();
|
| 292 |
} else {
|
| 293 |
return 0; |
| 294 |
} |
| 295 |
} |
| 296 |
|
| 297 |
QString getComposerName() const;
|
| 298 |
|
| 299 |
struct Ordering {
|
| 300 |
bool operator()(Work *, Work *);
|
| 301 |
}; |
| 302 |
|
| 303 |
/**
|
| 304 |
* Compare the ordering of two strings that are known to contain
|
| 305 |
* catalogue number texts, such as "Op. 1 no 4" and "Op. 3 no 2"
|
| 306 |
* (which should compare in that order). Return value is as for
|
| 307 |
* strcmp.
|
| 308 |
*/
|
| 309 |
//!!! todo: unit tests
|
| 310 |
static int compareCatalogueNumberTexts(QString a, QString b); |
| 311 |
|
| 312 |
/**
|
| 313 |
* Where data (possibly a title string, including opus number or
|
| 314 |
* equivalent) appears to contain some text of a suitable form for
|
| 315 |
* use with compareCatalogueNumberTexts, extract and return each
|
| 316 |
* example.
|
| 317 |
*/
|
| 318 |
static QStringList extractCatalogueNumberTexts(QString data);
|
| 319 |
|
| 320 |
/// Return name composed from title and catalogue, e.g. Symphony no. 4, Op. 42
|
| 321 |
QString getDisplayName() const;
|
| 322 |
|
| 323 |
signals:
|
| 324 |
void keyChanged(QString);
|
| 325 |
void opusChanged(QString);
|
| 326 |
void catalogueChanged(QString);
|
| 327 |
void numberChanged(QString);
|
| 328 |
void formsChanged(QSet<Form *>);
|
| 329 |
void partOfChanged(Work *);
|
| 330 |
void partsChanged(QSet<Work *>);
|
| 331 |
void movementsChanged(QSet<Movement *>);
|
| 332 |
void compositionChanged(Composition *);
|
| 333 |
|
| 334 |
private:
|
| 335 |
QString m_key; |
| 336 |
QString m_opus; |
| 337 |
QString m_catalogue; |
| 338 |
QString m_number; |
| 339 |
QSet<Form *> m_forms; |
| 340 |
Work *m_partOf; |
| 341 |
QSet<Work *> m_parts; |
| 342 |
QSet<Movement *> m_movements; |
| 343 |
Composition *m_composition; |
| 344 |
}; |
| 345 |
|
| 346 |
class Movement : public NamedEntity |
| 347 |
{
|
| 348 |
Q_OBJECT |
| 349 |
|
| 350 |
Q_PROPERTY(QString key READ key WRITE setKey NOTIFY keyChanged STORED true)
|
| 351 |
Q_PROPERTY(QString number READ number WRITE setNumber NOTIFY numberChanged STORED true)
|
| 352 |
Q_PROPERTY(ClassicalData::Work* partOf READ partOf WRITE setPartOf NOTIFY partOfChanged STORED true)
|
| 353 |
Q_PROPERTY(QSet<ClassicalData::Movement*> parts READ parts WRITE setParts NOTIFY partsChanged STORED true) // movements can be nested |
| 354 |
Q_PROPERTY(ClassicalData::Composition *composition READ composition WRITE setComposition NOTIFY compositionChanged STORED true)
|
| 355 |
|
| 356 |
public: |
| 357 |
Movement(QObject *parent = 0) : NamedEntity(parent), m_partOf(0), m_composition(0) { } |
| 358 |
|
| 359 |
QString key() const { return m_key; } |
| 360 |
void setKey(QString n) { m_key = n; emit keyChanged(n); }
|
| 361 |
|
| 362 |
QString number() const { return m_number; } |
| 363 |
void setNumber(QString n) { m_number = n; emit numberChanged(n); }
|
| 364 |
|
| 365 |
Work *partOf() const { return m_partOf; } |
| 366 |
void setPartOf(Work *w) { m_partOf = w; emit partOfChanged(w); }
|
| 367 |
|
| 368 |
QSet<Movement *> parts() const { return m_parts; } |
| 369 |
void setParts(QSet<Movement *> l) { m_parts = l; emit partsChanged(l); }
|
| 370 |
void addPart(Movement *w) { m_parts.insert(w); emit partsChanged(m_parts); }
|
| 371 |
|
| 372 |
Composition *composition() { return m_composition; }
|
| 373 |
const Composition *composition() const { return m_composition; } |
| 374 |
void setComposition(Composition *c) { m_composition = c; emit compositionChanged(c); }
|
| 375 |
|
| 376 |
signals:
|
| 377 |
void keyChanged(QString);
|
| 378 |
void numberChanged(QString);
|
| 379 |
void partOfChanged(Work *);
|
| 380 |
void partsChanged(QSet<Movement *>);
|
| 381 |
void compositionChanged(Composition *);
|
| 382 |
|
| 383 |
private:
|
| 384 |
QString m_key; |
| 385 |
QString m_number; |
| 386 |
Work *m_partOf; |
| 387 |
QSet<Movement *> m_parts; |
| 388 |
Composition *m_composition; |
| 389 |
}; |
| 390 |
|
| 391 |
class Composer : public NamedEntity |
| 392 |
{
|
| 393 |
Q_OBJECT |
| 394 |
|
| 395 |
Q_PROPERTY(QString gender READ gender WRITE setGender NOTIFY genderChanged STORED true)
|
| 396 |
Q_PROPERTY(QSet<QString> nationality READ nationality WRITE setNationality NOTIFY nationalityChanged STORED true)
|
| 397 |
Q_PROPERTY(QSet<Dataquay::Uri> geonameURIs READ geonameURIs WRITE setGeonameURIs NOTIFY geonameURIsChanged STORED true)
|
| 398 |
Q_PROPERTY(QString period READ period WRITE setPeriod NOTIFY periodChanged STORED true)
|
| 399 |
Q_PROPERTY(ClassicalData::Birth *birth READ birth WRITE setBirth NOTIFY birthChanged STORED true)
|
| 400 |
Q_PROPERTY(ClassicalData::Death *death READ death WRITE setDeath NOTIFY deathChanged STORED true)
|
| 401 |
|
| 402 |
Q_PROPERTY(QString surname READ getSurname STORED false)
|
| 403 |
Q_PROPERTY(QString forenames READ getForenames STORED false)
|
| 404 |
|
| 405 |
public: |
| 406 |
Composer(QObject *parent = 0) :
|
| 407 |
NamedEntity(parent), m_birth(0), m_death(0), m_namesCached(false) { } |
| 408 |
|
| 409 |
QString gender() const { return m_gender; } |
| 410 |
void setGender(QString n) { m_gender = n; emit genderChanged(n); }
|
| 411 |
|
| 412 |
QSet<QString> nationality() const { return m_nationality; } |
| 413 |
void setNationality(QSet<QString> n) { m_nationality = n; emit nationalityChanged(n); }
|
| 414 |
void addNationality(QString n) { m_nationality.insert(n); emit nationalityChanged(m_nationality); }
|
| 415 |
|
| 416 |
QSet<Dataquay::Uri> geonameURIs() const { return m_geonameURIs; } |
| 417 |
void setGeonameURIs(QSet<Dataquay::Uri> n) { m_geonameURIs = n; emit geonameURIsChanged(n); }
|
| 418 |
void addGeonameURI(Dataquay::Uri n) { m_geonameURIs.insert(n); emit geonameURIsChanged(m_geonameURIs); }
|
| 419 |
|
| 420 |
QString period() const { return m_period; } |
| 421 |
void setPeriod(QString n) { m_period = n; emit periodChanged(n); }
|
| 422 |
|
| 423 |
Birth *birth() { return m_birth; }
|
| 424 |
const Birth *birth() const { return m_birth; } |
| 425 |
void setBirth(Birth *b) { m_birth = b; emit birthChanged(b); }
|
| 426 |
|
| 427 |
Death *death() { return m_death; }
|
| 428 |
const Death *death() const { return m_death; } |
| 429 |
void setDeath(Death *d) { m_death = d; emit deathChanged(d); }
|
| 430 |
|
| 431 |
virtual void setName(QString n) {
|
| 432 |
NamedEntity::setName(n); |
| 433 |
m_namesCached = false;
|
| 434 |
} |
| 435 |
virtual void setAliases(QSet<QString> l) {
|
| 436 |
NamedEntity::setAliases(l); |
| 437 |
m_namesCached = false;
|
| 438 |
} |
| 439 |
virtual void addAlias(QString a) {
|
| 440 |
NamedEntity::addAlias(a); |
| 441 |
m_namesCached = false;
|
| 442 |
} |
| 443 |
|
| 444 |
QString getSurname() const;
|
| 445 |
QString getForenames() const;
|
| 446 |
QString getSortName(bool caps) const; |
| 447 |
QString getDisplayDates() const;
|
| 448 |
|
| 449 |
/**
|
| 450 |
* Given another composer, return true if the other composer's
|
| 451 |
* dates match outs. This is mostly intended (like
|
| 452 |
* matchCatalogueName) for use in merging distinct catalogues.
|
| 453 |
* Matching is somewhat fuzzy; more slack is cut when the dates
|
| 454 |
* are very long ago or are marked as approximate.
|
| 455 |
*/
|
| 456 |
bool matchDates(const Composer *other) const; // "well enough" |
| 457 |
|
| 458 |
/**
|
| 459 |
* Given another name which is intended to be a well-formatted
|
| 460 |
* catalogue name for a composer (but which may differ in
|
| 461 |
* ordering, number of forenames, and perhaps in spelling), test
|
| 462 |
* whether the name is a plausible match for our own. This is
|
| 463 |
* mostly intended (like matchDates) for use in merging distinct
|
| 464 |
* catalogues. Return true if the given name is highly likely to
|
| 465 |
* match our own.
|
| 466 |
*/
|
| 467 |
bool matchCatalogueName(QString otherName) const; |
| 468 |
|
| 469 |
/**
|
| 470 |
* Given another name which is believed to be a user-entered
|
| 471 |
* composer name with unpredictable formatting and spelling (and
|
| 472 |
* probably incomplete), return an estimate for the likelihood
|
| 473 |
* that the intended composer was this one. Higher return values
|
| 474 |
* indicate greater confidence; a value of 1.0 or more indicates
|
| 475 |
* that all of the input is at least close to perfectly matched.
|
| 476 |
*/
|
| 477 |
float matchFuzzyName(QString name) const; |
| 478 |
|
| 479 |
/**
|
| 480 |
* Given another name which is believed to be a user-entered
|
| 481 |
* composer name with unpredictable formatting and spelling (and
|
| 482 |
* probably incomplete), return an estimate for the likelihood
|
| 483 |
* that the intended composer was this one. Higher return values
|
| 484 |
* indicate greater confidence; a value of 1.0 or more indicates
|
| 485 |
* that all of the input is at least close to perfectly matched.
|
| 486 |
* The supplied name should have been lower-cased and split on
|
| 487 |
* non-alphabetical characters.
|
| 488 |
*/
|
| 489 |
float matchFuzzyName(QStringList name) const; |
| 490 |
|
| 491 |
/**
|
| 492 |
* Given a string that is in the process of being typed by the
|
| 493 |
* user, return an estimate of the likelihood that the text is
|
| 494 |
* intended to become this composer's name. If quick is true, do
|
| 495 |
* a quick(er) scan only and avoid very expensive tests.
|
| 496 |
*/
|
| 497 |
float matchTyping(QString text) const; |
| 498 |
|
| 499 |
/**
|
| 500 |
* Given a string that is in the process of being typed by the
|
| 501 |
* user, return an estimate of the likelihood that the text is
|
| 502 |
* intended to become this composer's name. In contrast to
|
| 503 |
* matchTyping, do a quick(er) scan only, avoiding more expensive
|
| 504 |
* tests.
|
| 505 |
*/
|
| 506 |
float matchTypingQuick(QString text) const; |
| 507 |
|
| 508 |
/**
|
| 509 |
* Merge data from the given composer into this composer record.
|
| 510 |
* That is, add the composer's name and aliases as aliases of this
|
| 511 |
* composer, copy its dates where we lack them, etc. In all
|
| 512 |
* cases, values that exist in this composer already are preferred
|
| 513 |
* over values from the "other" composer.
|
| 514 |
*/
|
| 515 |
void mergeFrom(Composer *c);
|
| 516 |
|
| 517 |
/**
|
| 518 |
* Return the supplied name reduced into a "simplified" form,
|
| 519 |
* eliminating many of the differences often found particularly in
|
| 520 |
* European language names that have been anglicised. Used in
|
| 521 |
* catalogue and fuzzy name matching.
|
| 522 |
*/
|
| 523 |
static QString reduceName(QString name);
|
| 524 |
|
| 525 |
signals:
|
| 526 |
void genderChanged(QString);
|
| 527 |
void nationalityChanged(QSet<QString>);
|
| 528 |
void geonameURIsChanged(QSet<Dataquay::Uri>);
|
| 529 |
void periodChanged(QString);
|
| 530 |
void birthChanged(Birth *);
|
| 531 |
void deathChanged(Death *);
|
| 532 |
|
| 533 |
private:
|
| 534 |
QString m_gender; |
| 535 |
QSet<QString> m_nationality; |
| 536 |
QSet<Dataquay::Uri> m_geonameURIs; |
| 537 |
QString m_period; |
| 538 |
Birth *m_birth; |
| 539 |
Death *m_death; |
| 540 |
|
| 541 |
void cacheNames() const; |
| 542 |
float doMatchTyping(QString, bool) const; |
| 543 |
mutable bool m_namesCached;
|
| 544 |
mutable QString m_surname; |
| 545 |
mutable QString m_forenames; |
| 546 |
mutable QStringList m_surnameElements; |
| 547 |
mutable QStringList m_connectiveElements; |
| 548 |
mutable QStringList m_forenameElements; |
| 549 |
mutable QStringList m_otherElements; |
| 550 |
mutable QStringList m_reducedSurnameElements; |
| 551 |
mutable QStringList m_reducedForenameElements; |
| 552 |
}; |
| 553 |
|
| 554 |
class Form : public NamedEntity |
| 555 |
{
|
| 556 |
Q_OBJECT |
| 557 |
|
| 558 |
Q_PROPERTY(Dataquay::Uri uri READ uri) |
| 559 |
|
| 560 |
public: |
| 561 |
Form(QObject *parent = 0) : NamedEntity(parent) { }
|
| 562 |
|
| 563 |
static Form *getFormByName(QString name) {
|
| 564 |
QMutexLocker locker(&m_mutex); |
| 565 |
if (!m_map.contains(name)) {
|
| 566 |
Form *f = new Form(); |
| 567 |
f->setName(name); |
| 568 |
m_map[name] = f; |
| 569 |
} |
| 570 |
return m_map[name];
|
| 571 |
} |
| 572 |
|
| 573 |
Dataquay::Uri uri() const {
|
| 574 |
return Dataquay::Uri
|
| 575 |
(QString(":form_%1").arg(name()).toLower().replace(' ', '_')); |
| 576 |
} |
| 577 |
|
| 578 |
private:
|
| 579 |
static QMap<QString, Form *> m_map;
|
| 580 |
static QMutex m_mutex;
|
| 581 |
}; |
| 582 |
|
| 583 |
class AudioFileTag : public QObject |
| 584 |
{
|
| 585 |
Q_OBJECT |
| 586 |
|
| 587 |
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged STORED true)
|
| 588 |
Q_PROPERTY(QString value READ value WRITE setValue NOTIFY valueChanged STORED true)
|
| 589 |
|
| 590 |
public: |
| 591 |
AudioFileTag(QObject *parent = 0) : QObject(parent) { }
|
| 592 |
AudioFileTag(QString name, QString value, QObject *parent = 0) :
|
| 593 |
QObject(parent), m_name(name), m_value(value) { }
|
| 594 |
|
| 595 |
QString name() const { return m_name; } |
| 596 |
void setName(QString n) { m_name = n; emit nameChanged(m_name); }
|
| 597 |
|
| 598 |
QString value() const { return m_value; } |
| 599 |
void setValue(QString v) { m_value = v; emit valueChanged(m_value); }
|
| 600 |
|
| 601 |
signals:
|
| 602 |
void nameChanged(QString);
|
| 603 |
void valueChanged(QString);
|
| 604 |
|
| 605 |
private:
|
| 606 |
QString m_name; |
| 607 |
QString m_value; |
| 608 |
}; |
| 609 |
|
| 610 |
// Separate AudioFile and Signal, to correspond with MO
|
| 611 |
|
| 612 |
class AudioFile : public QObject |
| 613 |
{
|
| 614 |
Q_OBJECT |
| 615 |
|
| 616 |
Q_PROPERTY(QString hash READ hash WRITE setHash NOTIFY hashChanged STORED true)
|
| 617 |
Q_PROPERTY(Dataquay::Uri uri READ uri WRITE setUri NOTIFY uriChanged STORED true)
|
| 618 |
Q_PROPERTY(QSet<ClassicalData::AudioFileTag *> tags READ tags WRITE setTags NOTIFY tagsChanged STORED true)
|
| 619 |
|
| 620 |
public: |
| 621 |
AudioFile(QObject *parent = 0);
|
| 622 |
AudioFile(FileSource file, QObject *parent = 0);
|
| 623 |
~AudioFile(); |
| 624 |
|
| 625 |
/// The URI is set automatically from the FileSource at construction
|
| 626 |
Dataquay::Uri uri() const { return m_uri; } |
| 627 |
void setUri(Dataquay::Uri u) { m_uri = u; emit uriChanged(u); }
|
| 628 |
|
| 629 |
/// The hash is set automatically from the FileSource at construction
|
| 630 |
QString hash() const { return m_hash; } |
| 631 |
void setHash(QString hash) { m_hash = hash; emit hashChanged(hash); }
|
| 632 |
|
| 633 |
/// I take ownership of all tags
|
| 634 |
QSet<AudioFileTag *> tags() { return m_tags; }
|
| 635 |
void setTags(QSet<AudioFileTag *> t);
|
| 636 |
void addTag(AudioFileTag *t);
|
| 637 |
|
| 638 |
signals:
|
| 639 |
void uriChanged(Dataquay::Uri);
|
| 640 |
void hashChanged(QString);
|
| 641 |
void tagsChanged(QSet<AudioFileTag *>);
|
| 642 |
|
| 643 |
private:
|
| 644 |
Dataquay::Uri m_uri; |
| 645 |
QString m_hash; |
| 646 |
QSet<AudioFileTag *> m_tags; |
| 647 |
}; |
| 648 |
|
| 649 |
class Signal : public QObject |
| 650 |
{
|
| 651 |
Q_OBJECT |
| 652 |
|
| 653 |
Q_PROPERTY(QString ofaFingerprint READ ofaFingerprint WRITE setOfaFingerprint NOTIFY ofaFingerprintChanged STORED true)
|
| 654 |
Q_PROPERTY(QString puid READ puid WRITE setPuid NOTIFY puidChanged STORED true)
|
| 655 |
Q_PROPERTY(QSet<ClassicalData::AudioFile *> availableAs READ availableAs WRITE setAvailableAs NOTIFY availableAsChanged STORED true)
|
| 656 |
Q_PROPERTY(ClassicalData::Composer *composer READ composer WRITE setComposer NOTIFY composerChanged STORED true)
|
| 657 |
Q_PROPERTY(ClassicalData::Work *work READ work WRITE setWork NOTIFY workChanged STORED true)
|
| 658 |
Q_PROPERTY(ClassicalData::Movement *movement READ movement WRITE setMovement NOTIFY movementChanged STORED true)
|
| 659 |
|
| 660 |
public: |
| 661 |
Signal() : m_composer(0), m_work(0), m_movement(0) { } |
| 662 |
|
| 663 |
QString ofaFingerprint() const { return m_ofaFingerprint; } |
| 664 |
void setOfaFingerprint(QString fprint) { m_ofaFingerprint = fprint; emit ofaFingerprintChanged(fprint); }
|
| 665 |
|
| 666 |
QString puid() const { return m_puid; } |
| 667 |
void setPuid(QString puid) { m_puid = puid; emit puidChanged(puid); }
|
| 668 |
|
| 669 |
QSet<AudioFile *> availableAs() const { return m_availableAs; } |
| 670 |
void setAvailableAs(QSet<AudioFile *> aa) { m_availableAs = aa; emit availableAsChanged(m_availableAs); }
|
| 671 |
void addAvailableAs(AudioFile *aa) { m_availableAs.insert(aa); emit availableAsChanged(m_availableAs); }
|
| 672 |
|
| 673 |
Composer *composer() const { return m_composer; } |
| 674 |
void setComposer(Composer *c) { m_composer = c; emit composerChanged(c); }
|
| 675 |
|
| 676 |
Work *work() const { return m_work; } |
| 677 |
void setWork(Work *w) { m_work = w; emit workChanged(w); }
|
| 678 |
|
| 679 |
Movement *movement() const { return m_movement; } |
| 680 |
void setMovement(Movement *m) { m_movement = m; emit movementChanged(m); }
|
| 681 |
|
| 682 |
signals:
|
| 683 |
void ofaFingerprintChanged(QString);
|
| 684 |
void puidChanged(QString);
|
| 685 |
void composerChanged(Composer *);
|
| 686 |
void workChanged(Work *);
|
| 687 |
void movementChanged(Movement *);
|
| 688 |
void availableAsChanged(QSet<AudioFile *>);
|
| 689 |
|
| 690 |
private:
|
| 691 |
QString m_ofaFingerprint; |
| 692 |
QString m_puid; |
| 693 |
Composer *m_composer; |
| 694 |
Work *m_work; |
| 695 |
Movement *m_movement; |
| 696 |
QSet<AudioFile *> m_availableAs; |
| 697 |
}; |
| 698 |
|
| 699 |
} |
| 700 |
|
| 701 |
Q_DECLARE_METATYPE(ClassicalData::Year); |
| 702 |
Q_DECLARE_METATYPE(ClassicalData::HistoricalEvent*); |
| 703 |
Q_DECLARE_METATYPE(ClassicalData::Birth*); |
| 704 |
Q_DECLARE_METATYPE(ClassicalData::Death*); |
| 705 |
Q_DECLARE_METATYPE(ClassicalData::Composition*); |
| 706 |
Q_DECLARE_METATYPE(ClassicalData::Work*); |
| 707 |
Q_DECLARE_METATYPE(ClassicalData::Movement*); |
| 708 |
Q_DECLARE_METATYPE(ClassicalData::Document*); |
| 709 |
Q_DECLARE_METATYPE(ClassicalData::AudioFileTag*); |
| 710 |
Q_DECLARE_METATYPE(ClassicalData::AudioFile*); |
| 711 |
Q_DECLARE_METATYPE(ClassicalData::Signal*); |
| 712 |
Q_DECLARE_METATYPE(QSet<QString>); |
| 713 |
Q_DECLARE_METATYPE(QSet<Dataquay::Uri>); |
| 714 |
Q_DECLARE_METATYPE(QSet<ClassicalData::Work*>); |
| 715 |
Q_DECLARE_METATYPE(QSet<ClassicalData::Movement*>); |
| 716 |
Q_DECLARE_METATYPE(QSet<ClassicalData::Document*>); |
| 717 |
Q_DECLARE_METATYPE(QSet<ClassicalData::AudioFileTag*>); |
| 718 |
Q_DECLARE_METATYPE(QSet<ClassicalData::AudioFile*>); |
| 719 |
Q_DECLARE_METATYPE(QSet<ClassicalData::Signal*>); |
| 720 |
Q_DECLARE_METATYPE(ClassicalData::Composer*); |
| 721 |
Q_DECLARE_METATYPE(ClassicalData::Form*); |
| 722 |
Q_DECLARE_METATYPE(QSet<ClassicalData::Form*>); |
| 723 |
Q_DECLARE_METATYPE(ClassicalData::NamedEntity*); |
| 724 |
|
| 725 |
#endif
|