summaryrefslogtreecommitdiff
path: root/sqlitebackend.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sqlitebackend.cpp')
-rw-r--r--sqlitebackend.cpp200
1 files changed, 147 insertions, 53 deletions
diff --git a/sqlitebackend.cpp b/sqlitebackend.cpp
index 89b7b07..4a9f8b9 100644
--- a/sqlitebackend.cpp
+++ b/sqlitebackend.cpp
@@ -14,8 +14,8 @@ SQLiteSaveFile::SQLiteSaveFile(QObject *parent) :
bool SQLiteSaveFile::open(const QString &filename)
{
- qDebug() << "open";
- {
+ auto dbg = qDebug() << "open";
+ { /* Emit signals only after unlocking mutex to allow accesses by receivers */
QMutexLocker l(&m_dbMut);
QFile f(filename);
if (!f.exists()) {
@@ -44,15 +44,16 @@ bool SQLiteSaveFile::open(const QString &filename)
m_dirty = false;
m_open = true;
m_image = q.value(0).toByteArray();
+ dbg << QString("Loaded %1 byte image").arg(m_image.size());
}
- fileReload(); /* Call after unlocking mutex to allow accesses by receivers */
+ fileReload();
return true;
}
bool SQLiteSaveFile::clearNew()
{
qDebug() << "clearNew";
- {
+ { /* Emit signals only after unlocking mutex to allow accesses by receivers */
QMutexLocker l(&m_dbMut);
QSqlDatabase new_db(QSqlDatabase::addDatabase("QSQLITE", QUuid::createUuid().toString()));
@@ -148,7 +149,7 @@ bool SQLiteSaveFile::saveAs(const QString &filename)
QList<Tag> SQLiteSaveFile::getAllTags()
{
- qDebug() << "getAllTags";
+ auto dbg = qDebug() << "getAllTags()";
QMutexLocker l(&m_dbMut);
resetError();
QList<Tag> rv;
@@ -170,56 +171,134 @@ QList<Tag> SQLiteSaveFile::getAllTags()
if (!setDatabaseError(q))
return QList<Tag>();
+ dbg << QString("%1 tags").arg(rv.size());
return rv;
}
bool SQLiteSaveFile::updateTag(Tag tag)
{
- QMutexLocker l(&m_dbMut);
- if (!runSql("UPDATE tags SET name=?, anchor_x=?, anchor_y=?, meta=? WHERE id=?", {
- tag.name, tag.anchor.x(), tag.anchor.y(), QJsonDocument::fromVariant(tag.metadata).toJson(), tag.id
- }))
- return false;
+ auto dbg = qDebug() << "updating tag" << tag.id << tag.name;
+ {
+ QMutexLocker l(&m_dbMut);
+ QSqlQuery q(m_db);
+ q.prepare("SELECT 1 FROM tags WHERE id=? AND name=?");
+ q.addBindValue(tag.id);
+ q.addBindValue(tag.name);
+ if (!q.exec()) {
+ setDatabaseError(q);
+ return false;
+ }
+ bool nameChanged = !q.next();
+ if (!setDatabaseError(q))
+ return false;
- m_dirty = true;
+ if (nameChanged)
+ setMetaLocked("lastTagName", tag.name);
+
+ if (!runSql("UPDATE tags SET name=?, anchor_x=?, anchor_y=?, meta=? WHERE id=?", {
+ tag.name, tag.anchor.x(), tag.anchor.y(), QJsonDocument::fromVariant(tag.metadata).toJson(), tag.id
+ })) {
+ return false;
+ }
+
+ m_dirty = true;
+ }
+ dbg << "calling handlers";
tagChange(TagChange::CHANGED, tag);
return true;
}
bool SQLiteSaveFile::deleteTag(Tag tag)
{
- QMutexLocker l(&m_dbMut);
- if (!runSql("DELETE FROM tags WHERE id=?", {tag.id}))
- return false;
+ {
+ QMutexLocker l(&m_dbMut);
+ if (!runSql("DELETE FROM tags WHERE id=?", {tag.id}))
+ return false;
- m_dirty = true;
+ m_dirty = true;
+ }
tagChange(TagChange::DELETED, tag);
return true;
}
bool SQLiteSaveFile::createTag(Tag tag)
{
- qDebug() << "createTag";
+ QSqlQuery q(m_db);
+ auto dbg = qDebug() << "createTag";
+ {
+ QMutexLocker l(&m_dbMut);
+ resetError();
+ if (!runSql("INSERT INTO tags(name, anchor_x, anchor_y, meta) VALUES (?, ?, ?, ?)", {
+ tag.name,
+ tag.anchor.x(),
+ tag.anchor.y(),
+ QJsonDocument::fromVariant(tag.metadata).toJson()
+ })) {
+ return false;
+ }
+ m_dirty = true;
+ }
+ auto id = q.lastInsertId().toLongLong();
+ dbg << "id" << id;
+ tagChange(TagChange::CREATED, Tag(id, tag));
+ return true;
+}
+
+QString SQLiteSaveFile::getNextAutoTagName()
+{
+ QVariant lookupResult = getMeta("lastTagName");
+ QString lastTagName = "U0";
+ if (lookupResult.isValid() && !lookupResult.toString().isNull())
+ lastTagName = lookupResult.toString();
+ QString newName = "U1";
+
+ QRegularExpression name_re("^(.*?)(\\d+)$");
+ auto res = name_re.match(lastTagName);
+ if (res.hasMatch()) {
+ bool ok = false;
+ int numericSuffix = res.captured(2).toInt(&ok);
+ QString stringPrefix = res.captured(1);
+ qDebug() << "Name has match" << stringPrefix << numericSuffix;
+
+ if (ok) {
+ do {
+ numericSuffix ++;
+ newName = QString("%1%2").arg(stringPrefix).arg(numericSuffix);
+ } while (numericSuffix<10000 && !tagNameIsFree(newName));
+ }
+ }
+ return newName;
+}
+
+bool SQLiteSaveFile::createTagAt(const QPointF &anchor)
+{
+ QString newName = getNextAutoTagName();
+ if (!setMeta("lastTagName", newName))
+ return false;
+ return createTag(Tag(newName, anchor));
+}
+
+bool SQLiteSaveFile::tagNameIsFree(const QString &name)
+{
QMutexLocker l(&m_dbMut);
- resetError();
QSqlQuery q(m_db);
- q.prepare("INSERT INTO tags(name, anchor_x, anchor_y, meta) VALUES (?, ?, ?, ?)");
- q.addBindValue(tag.name);
- q.addBindValue(tag.anchor.x());
- q.addBindValue(tag.anchor.y());
- q.addBindValue(QJsonDocument::fromVariant(tag.metadata).toJson());
+ q.prepare("SELECT name FROM tags WHERE name=?");
+ q.addBindValue(name);
+ if (!q.exec()) {
+ setDatabaseError(q);
+ return true;
+ }
- if (!setDatabaseError(q))
+ if (q.next())
return false;
- Tag created_tag(q.lastInsertId().toLongLong(), tag);
- m_dirty = true;
- tagChange(TagChange::CREATED, created_tag);
+ setDatabaseError(q);
return true;
}
bool SQLiteSaveFile::setMetaLocked(const QString &key, const QVariant &value)
{
+ qDebug() << QString("setMeta: %1=%2").arg(key).arg(value.toString());
return runSql("INSERT OR REPLACE INTO metadata(key, value) VALUES (?, ?)", {key, value});
}
@@ -232,15 +311,15 @@ bool SQLiteSaveFile::setMetaLocked(std::initializer_list<QPair<QString, QVariant
return true;
}
-bool SQLiteSaveFile::setMeta(const QString &key, const QVariant &value) {
+bool SQLiteSaveFile::setMeta(const QString &key, const QVariant &value, bool setDirty) {
QMutexLocker l(&m_dbMut);
- m_dirty = true;
+ m_dirty = m_dirty || setDirty;
return setMetaLocked(key, value);
}
-bool SQLiteSaveFile::setMeta(std::initializer_list<QPair<QString, QVariant>> metas) {
+bool SQLiteSaveFile::setMeta(std::initializer_list<QPair<QString, QVariant>> metas, bool setDirty) {
QMutexLocker l(&m_dbMut);
- m_dirty = true;
+ m_dirty = m_dirty || setDirty;
return setMetaLocked(metas);
}
@@ -251,7 +330,6 @@ const QVariant SQLiteSaveFile::getMeta(const QString &key) const {
const QVariant SQLiteSaveFile::getMetaLocked(const QString &key) const
{
- qDebug() << "getMeta " << key;
resetError();
QSqlQuery q(m_db);
q.prepare("SELECT value FROM metadata WHERE key=?");
@@ -267,6 +345,7 @@ const QVariant SQLiteSaveFile::getMetaLocked(const QString &key) const
return QVariant();
}
+ qDebug() << QString("getMeta: %1=%2").arg(key).arg(q.value(0).toString());
return q.value(0);
}
@@ -288,29 +367,35 @@ bool SQLiteSaveFile::runSql(QString query, std::initializer_list<QVariant> bindi
bool SQLiteSaveFile::loadImageFromDisk(const QString &filename)
{
- QMutexLocker l(&m_dbMut);
- QFile f(filename);
- resetError();
-
- if (!f.open(QIODevice::ReadOnly)) {
- setError(ImageOpenError, QString("Failed to open image: %1").arg(f.errorString()));
- return false;
- }
-
- m_image = f.readAll();
- if (f.error() != QFileDevice::NoError) {
- setError(ImageReadError, QString("Failed to read image: %1").arg(f.errorString()));
- return false;
+ {
+ QMutexLocker l(&m_dbMut);
+ QFile f(filename);
+ resetError();
+
+ if (!f.open(QIODevice::ReadOnly)) {
+ setError(ImageOpenError, QString("Failed to open image: %1").arg(f.errorString()));
+ return false;
+ }
+
+ m_image = f.readAll();
+ if (f.error() != QFileDevice::NoError) {
+ setError(ImageReadError, QString("Failed to read image: %1").arg(f.errorString()));
+ return false;
+ }
+
+ if (!setMetaLocked({
+ {"imagePathOriginal", f.fileName()},
+ {"imagePathAbsolute", QFileInfo(f).absoluteFilePath()},
+ {"imageLoadedTime", QDateTime::currentDateTimeUtc().toMSecsSinceEpoch()}}))
+ return false;
+
+ m_dirty = true;
+ if (!runSql("INSERT OR REPLACE INTO blobs(name, data) VALUES ('image', ?)", {m_image}))
+ return false;
}
-
- if (!setMetaLocked({
- {"imagePathOriginal", f.fileName()},
- {"imagePathAbsolute", QFileInfo(f).absoluteFilePath()},
- {"imageLoadedTime", QDateTime::currentDateTimeUtc().toMSecsSinceEpoch()}}))
- return false;
-
- m_dirty = true;
- return runSql("INSERT OR REPLACE INTO blobs(name, data) VALUES ('image', ?)", {m_image});
+ /* Emit signal with mutex unlocked */
+ imageLoaded(m_image);
+ return true;
}
bool SQLiteSaveFile::reloadImageFromDisk()
@@ -344,6 +429,15 @@ Tag::Tag(long long id, const Tag &other)
{
}
+Tag::Tag(QString name, const QPointF &anchor, const QVariantMap metadata)
+ : id(-1)
+ , name(name)
+ , anchor(anchor)
+ , metadata(metadata)
+ , valid(false)
+{
+}
+
bool SQLiteSaveFile::setDatabaseError(const QSqlQuery &q) const
{
if (!q.lastError().isValid())