1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
#ifndef SQLITEBACKEND_H
#define SQLITEBACKEND_H
#include <QObject>
#include <QPointF>
#include <QHash>
#include <QtSql>
#include <QFile>
enum TagChange {
CREATED,
CHANGED,
DELETED
};
class Tag
{
public:
Tag() : valid(false) {}
Tag(long long int id, QString name, qreal anchor_x, qreal anchor_y, QByteArray metadata);
Tag(long long int id, const Tag &other);
Tag(QString name, const QPointF &anchor=QPointF(), const QVariantMap metadata=QVariantMap());
bool operator==(const Tag &t2) const { return id == t2.id; }
bool isValid() const { return valid; }
QString humanReadableAnchor() { return QString("%1, %2").arg(anchor.x()).arg(anchor.y()); }
long long int id;
QString name;
QPointF anchor;
QPointF labelPos;
QVariantMap metadata;
private:
bool valid;
};
class SQLiteSaveFile : public QObject
{
Q_OBJECT
public:
explicit SQLiteSaveFile(QObject *parent = nullptr);
QList<Tag> getAllTags();
const QByteArray &getImage() const { return m_image; };
bool updateTag(Tag tag);
bool deleteTag(Tag tag);
bool createTag(Tag tag);
bool createTagAt(const QPointF &anchor);
QString getNextAutoTagName();
bool tagNameIsFree(const QString &name);
bool isMemory() { return m_memory; } /* backend db points to temporary memory db */
bool isDirty() { return m_dirty; } /* backend db was changed since opening */
bool isOpen() { return m_open; } /* backend db is open */
bool setMeta(const QString &key, const QVariant &value, bool setDirty=false);
bool setMeta(std::initializer_list<QPair<QString, QVariant>> metas, bool setDirty=false);
const QVariant getMeta(const QString &key) const;
const QString &errorString() const { return m_lastErrorString; }
enum Error {
NoError = 0,
FileNotFoundError,
SQLiteError,
ImageOpenError,
ImageReadError,
MaxError
};
inline const static QString errorNames[MaxError] = {
[NoError] = "No Error",
[FileNotFoundError] = "File not found",
[SQLiteError] = "Database Error",
[ImageOpenError] = "Error Opening Image",
[ImageReadError] = "Error Reading Image"
};
Error error();
void resetError() const { m_lastError = NoError; m_lastErrorString = QString(); }
public slots:
/** Save this project file under a new name. This changes the backend database this project file object points to, and copies all data.
* Callers can continue to use the same project file object afterwards.
*/
bool saveAs(const QString &filename);
bool open(const QString &filename);
bool reloadImageFromDisk();
bool loadImageFromDisk(const QString &m_filename);
bool clearNew();
signals:
void tagChange(TagChange change, const Tag &tag);
void fileReload();
void fileIOError(Error e, QString errorName, QString description) const;
void imageLoaded(const QByteArray &image);
private:
bool connect();
bool initDb(bool setCreationDate=true, const QString &schema_name="main");
bool runSql(QString query, std::initializer_list<QVariant> bindings={});
bool setMetaLocked(const QString &key, const QVariant &value);
bool setMetaLocked(std::initializer_list<QPair<QString, QVariant>> metas);
const QVariant getMetaLocked(const QString &key) const;
void setError(Error e, QString desc) const { m_lastError = e; m_lastErrorString = desc; fileIOError(e, errorNames[e], desc); }
bool setDatabaseError(const QSqlQuery &q) const;
bool setDatabaseError(const QSqlDatabase &m_db) const;
mutable Error m_lastError;
mutable QString m_lastErrorString;
QSqlDatabase m_db;
mutable QMutex m_dbMut;
QString m_filename;
QByteArray m_image;
bool m_open;
bool m_dirty;
bool m_memory;
};
#endif // SQLITEBACKEND_H
|