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