#ifndef SQLITEBACKEND_H #define SQLITEBACKEND_H #include #include #include #include #include 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 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> 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 bindings={}); bool setMetaLocked(const QString &key, const QVariant &value); bool setMetaLocked(std::initializer_list> 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