To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Revision:

root / common / Objects.h @ 45:0033259c6772

History | View | Annotate | Download (24.5 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
// Separate AudioFile and Signal, to correspond with 
584

    
585
class AudioFile : public QObject
586
{
587
    Q_OBJECT
588

    
589
    Q_PROPERTY(QString hash READ hash WRITE setHash NOTIFY hashChanged STORED true)
590
    Q_PROPERTY(Dataquay::Uri uri READ uri WRITE setUri NOTIFY uriChanged STORED true)
591

    
592
public:
593
    AudioFile(QObject *parent = 0);
594
    AudioFile(FileSource file, QObject *parent = 0);
595

    
596
    /// The URI is set automatically from the FileSource at construction
597
    Dataquay::Uri uri() const { return m_uri; }
598
    void setUri(Dataquay::Uri u) { m_uri = u; emit uriChanged(u); }
599

    
600
    /// The hash is set automatically from the FileSource at construction
601
    QString hash() const { return m_hash; }
602
    void setHash(QString hash) { m_hash = hash; emit hashChanged(hash); }
603

    
604
signals:
605
    void uriChanged(Dataquay::Uri);
606
    void hashChanged(QString);
607

    
608
private:
609
    Dataquay::Uri m_uri;
610
    QString m_hash;
611
};
612

    
613
class Signal : public QObject
614
{
615
    Q_OBJECT
616

    
617
    Q_PROPERTY(QString ofaFingerprint READ ofaFingerprint WRITE setOfaFingerprint NOTIFY ofaFingerprintChanged STORED true)
618
    Q_PROPERTY(QString puid READ puid WRITE setPuid NOTIFY puidChanged STORED true)
619
    Q_PROPERTY(QSet<ClassicalData::AudioFile *> availableAs READ availableAs WRITE setAvailableAs NOTIFY availableAsChanged STORED true)
620
    Q_PROPERTY(ClassicalData::Composer *composer READ composer WRITE setComposer NOTIFY composerChanged STORED true)
621
    Q_PROPERTY(ClassicalData::Work *work READ work WRITE setWork NOTIFY workChanged STORED true)
622
    Q_PROPERTY(ClassicalData::Movement *movement READ movement WRITE setMovement NOTIFY movementChanged STORED true)
623

    
624
public:
625
    Signal() : m_composer(0), m_work(0), m_movement(0) { }
626

    
627
    QString ofaFingerprint() const { return m_ofaFingerprint; }
628
    void setOfaFingerprint(QString fprint) { m_ofaFingerprint = fprint; emit ofaFingerprintChanged(fprint); }
629
    
630
    QString puid() const { return m_puid; }
631
    void setPuid(QString puid) { m_puid = puid; emit puidChanged(puid); }
632

    
633
    QSet<AudioFile *> availableAs() const { return m_availableAs; }
634
    void setAvailableAs(QSet<AudioFile *> aa) { m_availableAs = aa; emit availableAsChanged(m_availableAs); }
635
    void addAvailableAs(AudioFile *aa) { m_availableAs.insert(aa); emit availableAsChanged(m_availableAs); }
636

    
637
    Composer *composer() const { return m_composer; }
638
    void setComposer(Composer *c) { m_composer = c; emit composerChanged(c); }
639

    
640
    Work *work() const { return m_work; }
641
    void setWork(Work *w) { m_work = w; emit workChanged(w); }
642

    
643
    Movement *movement() const { return m_movement; }
644
    void setMovement(Movement *m) { m_movement = m; emit movementChanged(m); }
645

    
646
signals:
647
    void ofaFingerprintChanged(QString);
648
    void puidChanged(QString);
649
    void composerChanged(Composer *);
650
    void workChanged(Work *);
651
    void movementChanged(Movement *);
652
    void availableAsChanged(QSet<AudioFile *>);
653

    
654
private:
655
    QString m_ofaFingerprint;
656
    QString m_puid;
657
    Composer *m_composer;
658
    Work *m_work;
659
    Movement *m_movement;
660
    QSet<AudioFile *> m_availableAs;
661
};
662

    
663
}
664

    
665
Q_DECLARE_METATYPE(ClassicalData::Year);
666
Q_DECLARE_METATYPE(ClassicalData::HistoricalEvent*);
667
Q_DECLARE_METATYPE(ClassicalData::Birth*);
668
Q_DECLARE_METATYPE(ClassicalData::Death*);
669
Q_DECLARE_METATYPE(ClassicalData::Composition*);
670
Q_DECLARE_METATYPE(ClassicalData::Work*);
671
Q_DECLARE_METATYPE(ClassicalData::Movement*);
672
Q_DECLARE_METATYPE(ClassicalData::Document*);
673
Q_DECLARE_METATYPE(ClassicalData::AudioFile*);
674
Q_DECLARE_METATYPE(ClassicalData::Signal*);
675
Q_DECLARE_METATYPE(QSet<QString>);
676
Q_DECLARE_METATYPE(QSet<Dataquay::Uri>);
677
Q_DECLARE_METATYPE(QSet<ClassicalData::Work*>);
678
Q_DECLARE_METATYPE(QSet<ClassicalData::Movement*>);
679
Q_DECLARE_METATYPE(QSet<ClassicalData::Document*>);
680
Q_DECLARE_METATYPE(QSet<ClassicalData::AudioFile*>);
681
Q_DECLARE_METATYPE(QSet<ClassicalData::Signal*>);
682
Q_DECLARE_METATYPE(ClassicalData::Composer*);
683
Q_DECLARE_METATYPE(ClassicalData::Form*);
684
Q_DECLARE_METATYPE(QSet<ClassicalData::Form*>);
685
Q_DECLARE_METATYPE(ClassicalData::NamedEntity*);
686
        
687
#endif