summaryrefslogtreecommitdiff
path: root/sqlitebackend.h
blob: a1e8026935b6ed2f78c9bf8a08fcf23b62f1a649 (plain)
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