|
|
|
/* ============================================================
|
|
|
|
*
|
|
|
|
* This file is a part of digiKam project
|
|
|
|
* http://www.digikam.org
|
|
|
|
*
|
|
|
|
* Date : 2004-06-18
|
|
|
|
* Description : database album interface.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
|
|
|
|
* Copyright (C) 2006-2007 by Gilles Caulier <caulier dot gilles at gmail dot com>
|
|
|
|
* Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it
|
|
|
|
* and/or modify it under the terms of the GNU General
|
|
|
|
* Public License as published by the Free Software Foundation;
|
|
|
|
* either version 2, or (at your option)
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* ============================================================ */
|
|
|
|
|
|
|
|
/** @file albumdb.cpp */
|
|
|
|
|
|
|
|
// C Ansi includes.
|
|
|
|
|
|
|
|
extern "C"
|
|
|
|
{
|
|
|
|
#include "sqlite3.h"
|
|
|
|
#include <sys/time.h>
|
|
|
|
}
|
|
|
|
|
|
|
|
// C++ includes.
|
|
|
|
|
|
|
|
#include <cstdio>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <ctime>
|
|
|
|
|
|
|
|
// TQt includes.
|
|
|
|
|
|
|
|
#include <tqfile.h>
|
|
|
|
#include <tqfileinfo.h>
|
|
|
|
#include <tqdir.h>
|
|
|
|
|
|
|
|
// KDE includes.
|
|
|
|
|
|
|
|
#include <klocale.h>
|
|
|
|
|
|
|
|
// Local includes.
|
|
|
|
|
|
|
|
#include "ddebug.h"
|
|
|
|
#include "albummanager.h"
|
|
|
|
#include "album.h"
|
|
|
|
#include "albumdb.h"
|
|
|
|
#include "albumsettings.h"
|
|
|
|
|
|
|
|
namespace Digikam
|
|
|
|
{
|
|
|
|
|
|
|
|
typedef struct sqlite3_stmt sqlite3_stmt;
|
|
|
|
typedef struct sqlite3 sqleet3; // hehe.
|
|
|
|
|
|
|
|
class AlbumDBPriv
|
|
|
|
{
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
AlbumDBPriv()
|
|
|
|
{
|
|
|
|
valid = false;
|
|
|
|
dataBase = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool valid;
|
|
|
|
|
|
|
|
sqleet3 *dataBase;
|
|
|
|
|
|
|
|
IntList recentlyAssignedTags;
|
|
|
|
};
|
|
|
|
|
|
|
|
AlbumDB::AlbumDB()
|
|
|
|
{
|
|
|
|
d = new AlbumDBPriv;
|
|
|
|
}
|
|
|
|
|
|
|
|
AlbumDB::~AlbumDB()
|
|
|
|
{
|
|
|
|
if (d->dataBase)
|
|
|
|
{
|
|
|
|
sqlite3_close(d->dataBase);
|
|
|
|
}
|
|
|
|
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AlbumDB::isValid() const
|
|
|
|
{
|
|
|
|
return d->valid;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumDB::setDBPath(const TQString& path)
|
|
|
|
{
|
|
|
|
if (d->dataBase)
|
|
|
|
{
|
|
|
|
sqlite3_close(d->dataBase);
|
|
|
|
d->dataBase = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->valid = false;
|
|
|
|
|
|
|
|
sqlite3_open(TQFile::encodeName(path), &d->dataBase);
|
|
|
|
if (d->dataBase == 0)
|
|
|
|
{
|
|
|
|
DWarning() << "Cannot open database: "
|
|
|
|
<< sqlite3_errmsg(d->dataBase)
|
|
|
|
<< endl;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
initDB();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumDB::initDB()
|
|
|
|
{
|
|
|
|
d->valid = false;
|
|
|
|
|
|
|
|
// Check if we have the required tables
|
|
|
|
|
|
|
|
TQStringList values;
|
|
|
|
|
|
|
|
if (!execSql( TQString("SELECT name FROM sqlite_master"
|
|
|
|
" WHERE type='table'"
|
|
|
|
" ORDER BY name;"),
|
|
|
|
&values ))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!values.contains("Albums"))
|
|
|
|
{
|
|
|
|
if (!execSql( TQString("CREATE TABLE Albums\n"
|
|
|
|
" (id INTEGER PRIMARY KEY,\n"
|
|
|
|
" url TEXT NOT NULL UNITQUE,\n"
|
|
|
|
" date DATE NOT NULL,\n"
|
|
|
|
" caption TEXT,\n"
|
|
|
|
" collection TEXT,\n"
|
|
|
|
" icon INTEGER);") ))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!execSql( TQString("CREATE TABLE Tags\n"
|
|
|
|
" (id INTEGER PRIMARY KEY,\n"
|
|
|
|
" pid INTEGER,\n"
|
|
|
|
" name TEXT NOT NULL,\n"
|
|
|
|
" icon INTEGER,\n"
|
|
|
|
" iconkde TEXT,\n"
|
|
|
|
" UNITQUE (name, pid));") ))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!execSql( TQString("CREATE TABLE TagsTree\n"
|
|
|
|
" (id INTEGER NOT NULL,\n"
|
|
|
|
" pid INTEGER NOT NULL,\n"
|
|
|
|
" UNITQUE (id, pid));") ))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!execSql( TQString("CREATE TABLE Images\n"
|
|
|
|
" (id INTEGER PRIMARY KEY,\n"
|
|
|
|
" name TEXT NOT NULL,\n"
|
|
|
|
" dirid INTEGER NOT NULL,\n"
|
|
|
|
" caption TEXT,\n"
|
|
|
|
" datetime DATETIME,\n"
|
|
|
|
" UNITQUE (name, dirid));") ))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!execSql( TQString("CREATE TABLE ImageTags\n"
|
|
|
|
" (imageid INTEGER NOT NULL,\n"
|
|
|
|
" tagid INTEGER NOT NULL,\n"
|
|
|
|
" UNITQUE (imageid, tagid));") ))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!execSql( TQString("CREATE TABLE ImageProperties\n"
|
|
|
|
" (imageid INTEGER NOT NULL,\n"
|
|
|
|
" property TEXT NOT NULL,\n"
|
|
|
|
" value TEXT NOT NULL,\n"
|
|
|
|
" UNITQUE (imageid, property));") ))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !execSql( TQString( "CREATE TABLE Searches \n"
|
|
|
|
" (id INTEGER PRIMARY KEY, \n"
|
|
|
|
" name TEXT NOT NULL UNITQUE, \n"
|
|
|
|
" url TEXT NOT NULL);" ) ) )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!execSql( TQString("CREATE TABLE Settings \n"
|
|
|
|
"(keyword TEXT NOT NULL UNITQUE,\n"
|
|
|
|
" value TEXT);") ))
|
|
|
|
return;
|
|
|
|
else
|
|
|
|
setSetting("DBVersion","1");
|
|
|
|
|
|
|
|
// TODO: see which more indices are needed
|
|
|
|
// create indices
|
|
|
|
execSql("CREATE INDEX dir_index ON Images (dirid);");
|
|
|
|
execSql("CREATE INDEX tag_index ON ImageTags (tagid);");
|
|
|
|
|
|
|
|
// create triggers
|
|
|
|
|
|
|
|
// trigger: delete from Images/ImageTags/ImageProperties
|
|
|
|
// if Album has been deleted
|
|
|
|
execSql("CREATE TRIGGER delete_album DELETE ON Albums\n"
|
|
|
|
"BEGIN\n"
|
|
|
|
" DELETE FROM ImageTags\n"
|
|
|
|
" WHERE imageid IN (SELECT id FROM Images WHERE dirid=OLD.id);\n"
|
|
|
|
" DELETE From ImageProperties\n"
|
|
|
|
" WHERE imageid IN (SELECT id FROM Images WHERE dirid=OLD.id);\n"
|
|
|
|
" DELETE FROM Images\n"
|
|
|
|
" WHERE dirid = OLD.id;\n"
|
|
|
|
"END;");
|
|
|
|
|
|
|
|
// trigger: delete from ImageTags/ImageProperties
|
|
|
|
// if Image has been deleted
|
|
|
|
execSql("CREATE TRIGGER delete_image DELETE ON Images\n"
|
|
|
|
"BEGIN\n"
|
|
|
|
" DELETE FROM ImageTags\n"
|
|
|
|
" WHERE imageid=OLD.id;\n"
|
|
|
|
" DELETE From ImageProperties\n "
|
|
|
|
" WHERE imageid=OLD.id;\n"
|
|
|
|
" UPDATE Albums SET icon=null \n "
|
|
|
|
" WHERE icon=OLD.id;\n"
|
|
|
|
" UPDATE Tags SET icon=null \n "
|
|
|
|
" WHERE icon=OLD.id;\n"
|
|
|
|
"END;");
|
|
|
|
|
|
|
|
// trigger: delete from ImageTags if Tag has been deleted
|
|
|
|
execSql("CREATE TRIGGER delete_tag DELETE ON Tags\n"
|
|
|
|
"BEGIN\n"
|
|
|
|
" DELETE FROM ImageTags WHERE tagid=OLD.id;\n"
|
|
|
|
"END;");
|
|
|
|
|
|
|
|
// trigger: insert into TagsTree if Tag has been added
|
|
|
|
execSql("CREATE TRIGGER insert_tagstree AFTER INSERT ON Tags\n"
|
|
|
|
"BEGIN\n"
|
|
|
|
" INSERT INTO TagsTree\n"
|
|
|
|
" SELECT NEW.id, NEW.pid\n"
|
|
|
|
" UNION\n"
|
|
|
|
" SELECT NEW.id, pid FROM TagsTree WHERE id=NEW.pid;\n"
|
|
|
|
"END;");
|
|
|
|
|
|
|
|
// trigger: delete from TagsTree if Tag has been deleted
|
|
|
|
execSql("CREATE TRIGGER delete_tagstree DELETE ON Tags\n"
|
|
|
|
"BEGIN\n"
|
|
|
|
" DELETE FROM Tags\n"
|
|
|
|
" WHERE id IN (SELECT id FROM TagsTree WHERE pid=OLD.id);\n"
|
|
|
|
" DELETE FROM TagsTree\n"
|
|
|
|
" WHERE id IN (SELECT id FROM TagsTree WHERE pid=OLD.id);\n"
|
|
|
|
" DELETE FROM TagsTree\n"
|
|
|
|
" WHERE id=OLD.id;\n"
|
|
|
|
"END;");
|
|
|
|
|
|
|
|
// trigger: delete from TagsTree if Tag has been deleted
|
|
|
|
execSql("CREATE TRIGGER move_tagstree UPDATE OF pid ON Tags\n"
|
|
|
|
"BEGIN\n"
|
|
|
|
" DELETE FROM TagsTree\n"
|
|
|
|
" WHERE\n"
|
|
|
|
" ((id = OLD.id)\n"
|
|
|
|
" OR\n"
|
|
|
|
" id IN (SELECT id FROM TagsTree WHERE pid=OLD.id))\n"
|
|
|
|
" AND\n"
|
|
|
|
" pid IN (SELECT pid FROM TagsTree WHERE id=OLD.id);\n"
|
|
|
|
" INSERT INTO TagsTree\n"
|
|
|
|
" SELECT NEW.id, NEW.pid\n"
|
|
|
|
" UNION\n"
|
|
|
|
" SELECT NEW.id, pid FROM TagsTree WHERE id=NEW.pid\n"
|
|
|
|
" UNION\n"
|
|
|
|
" SELECT id, NEW.pid FROM TagsTree WHERE pid=NEW.id\n"
|
|
|
|
" UNION\n"
|
|
|
|
" SELECT A.id, B.pid FROM TagsTree A, TagsTree B\n"
|
|
|
|
" WHERE\n"
|
|
|
|
" A.pid = NEW.id AND B.id = NEW.pid;\n"
|
|
|
|
"END;");
|
|
|
|
}
|
|
|
|
|
|
|
|
d->valid = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
AlbumInfo::List AlbumDB::scanAlbums()
|
|
|
|
{
|
|
|
|
AlbumInfo::List aList;
|
|
|
|
|
|
|
|
TQString basePath(AlbumManager::instance()->getLibraryPath());
|
|
|
|
|
|
|
|
TQStringList values;
|
|
|
|
execSql( "SELECT A.id, A.url, A.date, A.caption, A.collection, B.url, I.name \n "
|
|
|
|
"FROM Albums AS A \n "
|
|
|
|
" LEFT OUTER JOIN Images AS I ON A.icon=I.id \n"
|
|
|
|
" LEFT OUTER JOIN Albums AS B ON B.id=I.dirid;", &values);
|
|
|
|
|
|
|
|
TQString iconAlbumUrl, iconName;
|
|
|
|
|
|
|
|
for (TQStringList::iterator it = values.begin(); it != values.end();)
|
|
|
|
{
|
|
|
|
AlbumInfo info;
|
|
|
|
|
|
|
|
info.id = (*it).toInt();
|
|
|
|
++it;
|
|
|
|
info.url = *it;
|
|
|
|
++it;
|
|
|
|
info.date = TQDate::fromString(*it, Qt::ISODate);
|
|
|
|
++it;
|
|
|
|
info.caption = *it;
|
|
|
|
++it;
|
|
|
|
info.collection = *it;
|
|
|
|
++it;
|
|
|
|
iconAlbumUrl = *it;
|
|
|
|
++it;
|
|
|
|
iconName = *it;
|
|
|
|
++it;
|
|
|
|
|
|
|
|
if (!iconName.isEmpty())
|
|
|
|
{
|
|
|
|
info.icon = basePath + iconAlbumUrl + '/' + iconName;
|
|
|
|
}
|
|
|
|
|
|
|
|
aList.append(info);
|
|
|
|
}
|
|
|
|
|
|
|
|
return aList;
|
|
|
|
}
|
|
|
|
|
|
|
|
TagInfo::List AlbumDB::scanTags()
|
|
|
|
{
|
|
|
|
TagInfo::List tList;
|
|
|
|
|
|
|
|
TQString basePath(AlbumManager::instance()->getLibraryPath());
|
|
|
|
|
|
|
|
TQStringList values;
|
|
|
|
execSql( "SELECT T.id, T.pid, T.name, A.url, I.name, T.iconkde \n "
|
|
|
|
"FROM Tags AS T LEFT OUTER JOIN Images AS I ON I.id=T.icon \n "
|
|
|
|
" LEFT OUTER JOIN Albums AS A ON A.id=I.dirid; ", &values );
|
|
|
|
|
|
|
|
TQString iconName, iconKDE, albumURL;
|
|
|
|
|
|
|
|
for (TQStringList::iterator it = values.begin(); it != values.end();)
|
|
|
|
{
|
|
|
|
TagInfo info;
|
|
|
|
|
|
|
|
info.id = (*it).toInt();
|
|
|
|
++it;
|
|
|
|
info.pid = (*it).toInt();
|
|
|
|
++it;
|
|
|
|
info.name = *it;
|
|
|
|
++it;
|
|
|
|
albumURL = *it;
|
|
|
|
++it;
|
|
|
|
iconName = *it;
|
|
|
|
++it;
|
|
|
|
iconKDE = *it;
|
|
|
|
++it;
|
|
|
|
|
|
|
|
if ( albumURL.isEmpty() )
|
|
|
|
{
|
|
|
|
info.icon = iconKDE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
info.icon = basePath + albumURL + '/' + iconName;
|
|
|
|
}
|
|
|
|
|
|
|
|
tList.append(info);
|
|
|
|
}
|
|
|
|
|
|
|
|
return tList;
|
|
|
|
}
|
|
|
|
|
|
|
|
SearchInfo::List AlbumDB::scanSearches()
|
|
|
|
{
|
|
|
|
SearchInfo::List searchList;
|
|
|
|
|
|
|
|
TQStringList values;
|
|
|
|
execSql( "SELECT id, name, url FROM Searches;", &values);
|
|
|
|
|
|
|
|
for (TQStringList::iterator it = values.begin(); it != values.end();)
|
|
|
|
{
|
|
|
|
SearchInfo info;
|
|
|
|
|
|
|
|
info.id = (*it).toInt();
|
|
|
|
++it;
|
|
|
|
info.name = (*it);
|
|
|
|
++it;
|
|
|
|
info.url = (*it);
|
|
|
|
++it;
|
|
|
|
|
|
|
|
searchList.append(info);
|
|
|
|
}
|
|
|
|
|
|
|
|
return searchList;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumDB::beginTransaction()
|
|
|
|
{
|
|
|
|
execSql( "BEGIN TRANSACTION;" );
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumDB::commitTransaction()
|
|
|
|
{
|
|
|
|
execSql( "COMMIT TRANSACTION;" );
|
|
|
|
}
|
|
|
|
|
|
|
|
int AlbumDB::addAlbum(const TQString& url, const TQString& caption,
|
|
|
|
const TQDate& date, const TQString& collection)
|
|
|
|
{
|
|
|
|
if (!d->dataBase)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
execSql( TQString("REPLACE INTO Albums (url, date, caption, collection) "
|
|
|
|
"VALUES('%1', '%2', '%3', '%4');")
|
|
|
|
.tqarg(escapeString(url),
|
|
|
|
date.toString(Qt::ISODate),
|
|
|
|
escapeString(caption),
|
|
|
|
escapeString(collection)));
|
|
|
|
|
|
|
|
int id = sqlite3_last_insert_rowid(d->dataBase);
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumDB::setAlbumCaption(int albumID, const TQString& caption)
|
|
|
|
{
|
|
|
|
execSql( TQString("UPDATE Albums SET caption='%1' WHERE id=%2;")
|
|
|
|
.tqarg(escapeString(caption),
|
|
|
|
TQString::number(albumID) ));
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumDB::setAlbumCollection(int albumID, const TQString& collection)
|
|
|
|
{
|
|
|
|
execSql( TQString("UPDATE Albums SET collection='%1' WHERE id=%2;")
|
|
|
|
.tqarg(escapeString(collection),
|
|
|
|
TQString::number(albumID)) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumDB::setAlbumDate(int albumID, const TQDate& date)
|
|
|
|
{
|
|
|
|
execSql( TQString("UPDATE Albums SET date='%1' WHERE id=%2;")
|
|
|
|
.tqarg(date.toString(Qt::ISODate))
|
|
|
|
.tqarg(albumID) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumDB::setAlbumIcon(int albumID, TQ_LLONG iconID)
|
|
|
|
{
|
|
|
|
execSql( TQString("UPDATE Albums SET icon=%1 WHERE id=%2;")
|
|
|
|
.tqarg(iconID)
|
|
|
|
.tqarg(albumID) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TQString AlbumDB::getAlbumIcon(int albumID)
|
|
|
|
{
|
|
|
|
TQStringList values;
|
|
|
|
execSql( TQString("SELECT B.url, I.name \n "
|
|
|
|
"FROM Albums AS A \n "
|
|
|
|
" LEFT OUTER JOIN Images AS I ON I.id=A.icon \n "
|
|
|
|
" LEFT OUTER JOIN Albums AS B ON B.id=I.dirid \n "
|
|
|
|
"WHERE A.id=%1;")
|
|
|
|
.tqarg(albumID), &values );
|
|
|
|
if (values.isEmpty())
|
|
|
|
return TQString();
|
|
|
|
|
|
|
|
TQStringList::iterator it = values.begin();
|
|
|
|
TQString url = *it;
|
|
|
|
++it;
|
|
|
|
TQString icon = *it;
|
|
|
|
if (icon.isEmpty())
|
|
|
|
return TQString();
|
|
|
|
|
|
|
|
TQString basePath(AlbumManager::instance()->getLibraryPath());
|
|
|
|
basePath += url;
|
|
|
|
basePath += '/' + icon;
|
|
|
|
|
|
|
|
return basePath;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumDB::deleteAlbum(int albumID)
|
|
|
|
{
|
|
|
|
execSql( TQString("DELETE FROM Albums WHERE id=%1")
|
|
|
|
.tqarg(albumID) );
|
|
|
|
}
|
|
|
|
|
|
|
|
int AlbumDB::addTag(int parentTagID, const TQString& name, const TQString& iconKDE,
|
|
|
|
TQ_LLONG iconID)
|
|
|
|
{
|
|
|
|
if (!d->dataBase)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!execSql( TQString("INSERT INTO Tags (pid, name) "
|
|
|
|
"VALUES( %1, '%2')")
|
|
|
|
.tqarg(parentTagID)
|
|
|
|
.tqarg(escapeString(name))))
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int id = sqlite3_last_insert_rowid(d->dataBase);
|
|
|
|
|
|
|
|
if (!iconKDE.isEmpty())
|
|
|
|
{
|
|
|
|
execSql( TQString("UPDATE Tags SET iconkde='%1' WHERE id=%2;")
|
|
|
|
.tqarg(escapeString(iconKDE),
|
|
|
|
TQString::number(id)));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
execSql( TQString("UPDATE Tags SET icon=%1 WHERE id=%2;")
|
|
|
|
.tqarg(iconID)
|
|
|
|
.tqarg(id));
|
|
|
|
}
|
|
|
|
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumDB::deleteTag(int tagID)
|
|
|
|
{
|
|
|
|
execSql( TQString("DELETE FROM Tags WHERE id=%1")
|
|
|
|
.tqarg(tagID) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumDB::setTagIcon(int tagID, const TQString& iconKDE, TQ_LLONG iconID)
|
|
|
|
{
|
|
|
|
if (!iconKDE.isEmpty())
|
|
|
|
{
|
|
|
|
execSql( TQString("UPDATE Tags SET iconkde='%1', icon=0 WHERE id=%2;")
|
|
|
|
.tqarg(escapeString(iconKDE),
|
|
|
|
TQString::number(tagID)));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
execSql( TQString("UPDATE Tags SET icon=%1 WHERE id=%2;")
|
|
|
|
.tqarg(iconID)
|
|
|
|
.tqarg(tagID));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString AlbumDB::getTagIcon(int tagID)
|
|
|
|
{
|
|
|
|
TQStringList values;
|
|
|
|
execSql( TQString("SELECT A.url, I.name, T.iconkde \n "
|
|
|
|
"FROM Tags AS T \n "
|
|
|
|
" LEFT OUTER JOIN Images AS I ON I.id=T.icon \n "
|
|
|
|
" LEFT OUTER JOIN Albums AS A ON A.id=I.dirid \n "
|
|
|
|
"WHERE T.id=%1;")
|
|
|
|
.tqarg(tagID), &values );
|
|
|
|
|
|
|
|
if (values.isEmpty())
|
|
|
|
return TQString();
|
|
|
|
|
|
|
|
TQString basePath(AlbumManager::instance()->getLibraryPath());
|
|
|
|
|
|
|
|
TQString iconName, iconKDE, albumURL, icon;
|
|
|
|
|
|
|
|
TQStringList::iterator it = values.begin();
|
|
|
|
|
|
|
|
albumURL = *it;
|
|
|
|
++it;
|
|
|
|
iconName = *it;
|
|
|
|
++it;
|
|
|
|
iconKDE = *it;
|
|
|
|
++it;
|
|
|
|
|
|
|
|
if ( albumURL.isEmpty() )
|
|
|
|
{
|
|
|
|
icon = iconKDE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
icon = basePath + albumURL + '/' + iconName;
|
|
|
|
}
|
|
|
|
|
|
|
|
return icon;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumDB::setTagParentID(int tagID, int newParentTagID)
|
|
|
|
{
|
|
|
|
execSql( TQString("UPDATE Tags SET pid=%1 WHERE id=%2;")
|
|
|
|
.tqarg(newParentTagID)
|
|
|
|
.tqarg(tagID) );
|
|
|
|
}
|
|
|
|
|
|
|
|
int AlbumDB::addSearch(const TQString& name, const KURL& url)
|
|
|
|
{
|
|
|
|
if (!d->dataBase)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
TQString str("INSERT INTO Searches (name, url) \n"
|
|
|
|
"VALUES('$$@@$$', '$$##$$');");
|
|
|
|
str.replace("$$@@$$", escapeString(name));
|
|
|
|
str.replace("$$##$$", escapeString(url.url()));
|
|
|
|
|
|
|
|
if (!execSql(str))
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return sqlite3_last_insert_rowid(d->dataBase);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumDB::updateSearch(int searchID, const TQString& name,
|
|
|
|
const KURL& url)
|
|
|
|
{
|
|
|
|
TQString str = TQString("UPDATE Searches SET name='$$@@$$', url='$$##$$' \n"
|
|
|
|
"WHERE id=%1")
|
|
|
|
.tqarg(searchID);
|
|
|
|
str.replace("$$@@$$", escapeString(name));
|
|
|
|
str.replace("$$##$$", escapeString(url.url()));
|
|
|
|
|
|
|
|
execSql(str);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumDB::deleteSearch(int searchID)
|
|
|
|
{
|
|
|
|
execSql( TQString("DELETE FROM Searches WHERE id=%1")
|
|
|
|
.tqarg(searchID) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumDB::setSetting(const TQString& keyword,
|
|
|
|
const TQString& value )
|
|
|
|
{
|
|
|
|
execSql( TQString("REPLACE into Settings VALUES ('%1','%2');")
|
|
|
|
.tqarg(escapeString(keyword),
|
|
|
|
escapeString(value) ));
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString AlbumDB::getSetting(const TQString& keyword)
|
|
|
|
{
|
|
|
|
TQStringList values;
|
|
|
|
execSql( TQString("SELECT value FROM Settings "
|
|
|
|
"WHERE keyword='%1';")
|
|
|
|
.tqarg(escapeString(keyword)), &values );
|
|
|
|
|
|
|
|
if (values.isEmpty())
|
|
|
|
return TQString();
|
|
|
|
else
|
|
|
|
return values[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AlbumDB::execSql(const TQString& sql, TQStringList* const values,
|
|
|
|
const bool debug)
|
|
|
|
{
|
|
|
|
if ( debug )
|
|
|
|
DDebug() << "SQL-query: " << sql << endl;
|
|
|
|
|
|
|
|
if ( !d->dataBase )
|
|
|
|
{
|
|
|
|
DWarning() << k_funcinfo << "SQLite pointer == NULL"
|
|
|
|
<< endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* tail;
|
|
|
|
sqlite3_stmt* stmt;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
//compile SQL program to virtual machine
|
|
|
|
error = sqlite3_prepare(d->dataBase, sql.utf8(), -1, &stmt, &tail);
|
|
|
|
if ( error != SQLITE_OK )
|
|
|
|
{
|
|
|
|
DWarning() << k_funcinfo
|
|
|
|
<< "sqlite_compile error: "
|
|
|
|
<< sqlite3_errmsg(d->dataBase)
|
|
|
|
<< " on query: "
|
|
|
|
<< sql << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int cols = sqlite3_column_count(stmt);
|
|
|
|
|
|
|
|
while ( true )
|
|
|
|
{
|
|
|
|
error = sqlite3_step( stmt );
|
|
|
|
|
|
|
|
if ( error == SQLITE_DONE || error == SQLITE_ERROR )
|
|
|
|
break;
|
|
|
|
|
|
|
|
//iterate over columns
|
|
|
|
for ( int i = 0; values && i < cols; i++ )
|
|
|
|
{
|
|
|
|
*values << TQString::fromUtf8( (const char*)sqlite3_column_text( stmt, i ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sqlite3_finalize( stmt );
|
|
|
|
|
|
|
|
if ( error != SQLITE_DONE )
|
|
|
|
{
|
|
|
|
DWarning() << "sqlite_step error: "
|
|
|
|
<< sqlite3_errmsg( d->dataBase )
|
|
|
|
<< " on query: "
|
|
|
|
<< sql << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString AlbumDB::escapeString(TQString str) const
|
|
|
|
{
|
|
|
|
str.replace( "'", "''" );
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString AlbumDB::getItemCaption(TQ_LLONG imageID)
|
|
|
|
{
|
|
|
|
TQStringList values;
|
|
|
|
|
|
|
|
execSql( TQString("SELECT caption FROM Images "
|
|
|
|
"WHERE id=%1;")
|
|
|
|
.tqarg(imageID),
|
|
|
|
&values );
|
|
|
|
|
|
|
|
if (!values.isEmpty())
|
|
|
|
return values[0];
|
|
|
|
else
|
|
|
|
return TQString();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString AlbumDB::getItemCaption(int albumID, const TQString& name)
|
|
|
|
{
|
|
|
|
TQStringList values;
|
|
|
|
|
|
|
|
execSql( TQString("SELECT caption FROM Images "
|
|
|
|
"WHERE dirid=%1 AND name='%2';")
|
|
|
|
.tqarg(albumID)
|
|
|
|
.tqarg(escapeString(name)),
|
|
|
|
&values );
|
|
|
|
|
|
|
|
if (!values.isEmpty())
|
|
|
|
return values[0];
|
|
|
|
else
|
|
|
|
return TQString();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQDateTime AlbumDB::getItemDate(TQ_LLONG imageID)
|
|
|
|
{
|
|
|
|
TQStringList values;
|
|
|
|
|
|
|
|
execSql( TQString("SELECT datetime FROM Images "
|
|
|
|
"WHERE id=%1;")
|
|
|
|
.tqarg(imageID),
|
|
|
|
&values );
|
|
|
|
|
|
|
|
if (values.isEmpty())
|
|
|
|
return TQDateTime();
|
|
|
|
else
|
|
|
|
return TQDateTime::fromString(values[0], Qt::ISODate);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQDateTime AlbumDB::getItemDate(int albumID, const TQString& name)
|
|
|
|
{
|
|
|
|
TQStringList values;
|
|
|
|
|
|
|
|
execSql( TQString("SELECT datetime FROM Images "
|
|
|
|
"WHERE dirid=%1 AND name='%2';")
|
|
|
|
.tqarg(albumID)
|
|
|
|
.tqarg(escapeString(name)),
|
|
|
|
&values );
|
|
|
|
|
|
|
|
if (values.isEmpty())
|
|
|
|
return TQDateTime();
|
|
|
|
else
|
|
|
|
return TQDateTime::fromString(values[0], Qt::ISODate);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQ_LLONG AlbumDB::getImageId(int albumID, const TQString& name)
|
|
|
|
{
|
|
|
|
TQStringList values;
|
|
|
|
|
|
|
|
execSql( TQString("SELECT id FROM Images "
|
|
|
|
"WHERE dirid=%1 AND name='%2';")
|
|
|
|
.tqarg(albumID)
|
|
|
|
.tqarg(escapeString(name)),
|
|
|
|
&values );
|
|
|
|
|
|
|
|
if (values.isEmpty())
|
|
|
|
return -1;
|
|
|
|
else
|
|
|
|
return (values[0]).toLongLong();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQStringList AlbumDB::getItemTagNames(TQ_LLONG imageID)
|
|
|
|
{
|
|
|
|
TQStringList values;
|
|
|
|
|
|
|
|
execSql( TQString("SELECT name FROM Tags \n "
|
|
|
|
"WHERE id IN (SELECT tagid FROM ImageTags \n "
|
|
|
|
" WHERE imageid=%1) \n "
|
|
|
|
"ORDER BY name;")
|
|
|
|
.tqarg(imageID),
|
|
|
|
&values );
|
|
|
|
|
|
|
|
return values;
|
|
|
|
}
|
|
|
|
|
|
|
|
IntList AlbumDB::getItemTagIDs(TQ_LLONG imageID)
|
|
|
|
{
|
|
|
|
TQStringList values;
|
|
|
|
|
|
|
|
execSql( TQString("SELECT tagid FROM ImageTags \n "
|
|
|
|
"WHERE imageID=%1;")
|
|
|
|
.tqarg(imageID),
|
|
|
|
&values );
|
|
|
|
|
|
|
|
IntList ids;
|
|
|
|
|
|
|
|
if (values.isEmpty())
|
|
|
|
return ids;
|
|
|
|
|
|
|
|
for (TQStringList::iterator it=values.begin(); it != values.end(); ++it)
|
|
|
|
{
|
|
|
|
ids << (*it).toInt();
|
|
|
|
}
|
|
|
|
return ids;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AlbumDB::hasTags(const LLongList& imageIDList)
|
|
|
|
{
|
|
|
|
IntList ids;
|
|
|
|
|
|
|
|
if (imageIDList.isEmpty())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
TQStringList values;
|
|
|
|
|
|
|
|
TQString sql = TQString("SELECT count(tagid) FROM ImageTags "
|
|
|
|
"WHERE imageid=%1 ")
|
|
|
|
.tqarg(imageIDList.first());
|
|
|
|
|
|
|
|
LLongList::const_iterator iter = imageIDList.begin();
|
|
|
|
++iter;
|
|
|
|
|
|
|
|
while (iter != imageIDList.end())
|
|
|
|
{
|
|
|
|
sql += TQString(" OR imageid=%2 ")
|
|
|
|
.tqarg(*iter);
|
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
|
|
|
|
sql += TQString(";");
|
|
|
|
execSql( sql, &values );
|
|
|
|
|
|
|
|
if (values[0] == "0")
|
|
|
|
return false;
|
|
|
|
else
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
IntList AlbumDB::getItemCommonTagIDs(const LLongList& imageIDList)
|
|
|
|
{
|
|
|
|
IntList ids;
|
|
|
|
|
|
|
|
if (imageIDList.isEmpty())
|
|
|
|
return ids;
|
|
|
|
|
|
|
|
TQStringList values;
|
|
|
|
|
|
|
|
TQString sql = TQString("SELECT DISTINCT tagid FROM ImageTags "
|
|
|
|
"WHERE imageid=%1 ")
|
|
|
|
.tqarg(imageIDList.first());
|
|
|
|
|
|
|
|
LLongList::const_iterator iter = imageIDList.begin();
|
|
|
|
++iter;
|
|
|
|
|
|
|
|
while (iter != imageIDList.end())
|
|
|
|
{
|
|
|
|
sql += TQString(" OR imageid=%2 ")
|
|
|
|
.tqarg(*iter);
|
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
|
|
|
|
sql += TQString(";");
|
|
|
|
execSql( sql, &values );
|
|
|
|
|
|
|
|
if (values.isEmpty())
|
|
|
|
return ids;
|
|
|
|
|
|
|
|
for (TQStringList::iterator it=values.begin(); it != values.end(); ++it)
|
|
|
|
{
|
|
|
|
ids << (*it).toInt();
|
|
|
|
}
|
|
|
|
return ids;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumDB::setItemCaption(TQ_LLONG imageID,const TQString& caption)
|
|
|
|
{
|
|
|
|
TQStringList values;
|
|
|
|
|
|
|
|
execSql( TQString("UPDATE Images SET caption='%1' "
|
|
|
|
"WHERE id=%2;")
|
|
|
|
.tqarg(escapeString(caption),
|
|
|
|
TQString::number(imageID) ));
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumDB::setItemCaption(int albumID, const TQString& name, const TQString& caption)
|
|
|
|
{
|
|
|
|
TQStringList values;
|
|
|
|
|
|
|
|
execSql( TQString("UPDATE Images SET caption='%1' "
|
|
|
|
"WHERE dirid=%2 AND name='%3';")
|
|
|
|
.tqarg(escapeString(caption),
|
|
|
|
TQString::number(albumID),
|
|
|
|
escapeString(name)) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumDB::addItemTag(TQ_LLONG imageID, int tagID)
|
|
|
|
{
|
|
|
|
execSql( TQString("REPLACE INTO ImageTags (imageid, tagid) "
|
|
|
|
"VALUES(%1, %2);")
|
|
|
|
.tqarg(imageID)
|
|
|
|
.tqarg(tagID) );
|
|
|
|
|
|
|
|
if (!d->recentlyAssignedTags.contains(tagID))
|
|
|
|
{
|
|
|
|
d->recentlyAssignedTags.push_front(tagID);
|
|
|
|
if (d->recentlyAssignedTags.size() > 10)
|
|
|
|
d->recentlyAssignedTags.pop_back();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumDB::addItemTag(int albumID, const TQString& name, int tagID)
|
|
|
|
{
|
|
|
|
execSql( TQString("REPLACE INTO ImageTags (imageid, tagid) \n "
|
|
|
|
"(SELECT id, %1 FROM Images \n "
|
|
|
|
" WHERE dirid=%2 AND name='%3');")
|
|
|
|
.tqarg(tagID)
|
|
|
|
.tqarg(albumID)
|
|
|
|
.tqarg(escapeString(name)) );
|
|
|
|
}
|
|
|
|
|
|
|
|
IntList AlbumDB::getRecentlyAssignedTags() const
|
|
|
|
{
|
|
|
|
return d->recentlyAssignedTags;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumDB::removeItemTag(TQ_LLONG imageID, int tagID)
|
|
|
|
{
|
|
|
|
execSql( TQString("DELETE FROM ImageTags "
|
|
|
|
"WHERE imageID=%1 AND tagid=%2;")
|
|
|
|
.tqarg(imageID)
|
|
|
|
.tqarg(tagID) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumDB::removeItemAllTags(TQ_LLONG imageID)
|
|
|
|
{
|
|
|
|
execSql( TQString("DELETE FROM ImageTags "
|
|
|
|
"WHERE imageID=%1;")
|
|
|
|
.tqarg(imageID) );
|
|
|
|
}
|
|
|
|
|
|
|
|
TQStringList AlbumDB::getItemNamesInAlbum(int albumID, bool recurssive)
|
|
|
|
{
|
|
|
|
TQStringList values;
|
|
|
|
|
|
|
|
if (recurssive)
|
|
|
|
{
|
|
|
|
KURL url(getAlbumURL(albumID));
|
|
|
|
execSql( TQString("SELECT Images.name "
|
|
|
|
"FROM Images "
|
|
|
|
"WHERE Images.dirid "
|
|
|
|
"IN (SELECT DISTINCT id "
|
|
|
|
"FROM Albums "
|
|
|
|
"WHERE url='%1' OR url LIKE '\%%2\%')")
|
|
|
|
.tqarg(escapeString(url.path())).tqarg(escapeString(url.path(1))), &values);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
execSql( TQString("SELECT Images.name "
|
|
|
|
"FROM Images "
|
|
|
|
"WHERE Images.dirid=%1")
|
|
|
|
.tqarg(albumID), &values );
|
|
|
|
}
|
|
|
|
return values;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQStringList AlbumDB::getAllItemURLsWithoutDate()
|
|
|
|
{
|
|
|
|
TQStringList values;
|
|
|
|
execSql( TQString("SELECT Albums.url||'/'||Images.name "
|
|
|
|
"FROM Images, Albums "
|
|
|
|
"WHERE Images.dirid=Albums.Id "
|
|
|
|
"AND (Images.datetime is null or "
|
|
|
|
" Images.datetime == '');"),
|
|
|
|
&values );
|
|
|
|
|
|
|
|
TQString libraryPath = AlbumManager::instance()->getLibraryPath() + '/';
|
|
|
|
for (TQStringList::iterator it = values.begin(); it != values.end();
|
|
|
|
++it)
|
|
|
|
{
|
|
|
|
*it = libraryPath + *it;
|
|
|
|
}
|
|
|
|
|
|
|
|
return values;
|
|
|
|
}
|
|
|
|
|
|
|
|
int AlbumDB::getOrCreateAlbumId(const TQString& folder)
|
|
|
|
{
|
|
|
|
TQStringList values;
|
|
|
|
execSql( TQString("SELECT id FROM Albums WHERE url ='%1';")
|
|
|
|
.tqarg( escapeString(folder) ), &values);
|
|
|
|
|
|
|
|
int albumID;
|
|
|
|
if (values.isEmpty())
|
|
|
|
{
|
|
|
|
execSql( TQString ("INSERT INTO Albums (url, date) "
|
|
|
|
"VALUES ('%1','%2')")
|
|
|
|
.tqarg(escapeString(folder),
|
|
|
|
TQDateTime::tqcurrentDateTime().toString(Qt::ISODate)) );
|
|
|
|
albumID = sqlite3_last_insert_rowid(d->dataBase);
|
|
|
|
} else
|
|
|
|
albumID = values[0].toInt();
|
|
|
|
|
|
|
|
return albumID;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQ_LLONG AlbumDB::addItem(int albumID,
|
|
|
|
const TQString& name,
|
|
|
|
const TQDateTime& datetime,
|
|
|
|
const TQString& comment,
|
|
|
|
int rating,
|
|
|
|
const TQStringList &keywordsList)
|
|
|
|
{
|
|
|
|
execSql ( TQString ("REPLACE INTO Images "
|
|
|
|
"( caption , datetime, name, dirid ) "
|
|
|
|
" VALUES ('%1','%2','%3',%4) " )
|
|
|
|
.tqarg(escapeString(comment),
|
|
|
|
datetime.toString(Qt::ISODate),
|
|
|
|
escapeString(name),
|
|
|
|
TQString::number(albumID)) );
|
|
|
|
|
|
|
|
TQ_LLONG item = sqlite3_last_insert_rowid(d->dataBase);
|
|
|
|
|
|
|
|
// Set Rating value to item in database.
|
|
|
|
|
|
|
|
if ( item != -1 && rating != -1 )
|
|
|
|
setItemRating(item, rating);
|
|
|
|
|
|
|
|
// Set existing tags in database or create new tags if not exist.
|
|
|
|
|
|
|
|
if ( item != -1 && !keywordsList.isEmpty() )
|
|
|
|
{
|
|
|
|
IntList tagIDs = getTagsFromTagPaths(keywordsList);
|
|
|
|
for (IntList::iterator it = tagIDs.begin(); it != tagIDs.end(); ++it)
|
|
|
|
{
|
|
|
|
addItemTag(item, *it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
|
|
|
IntList AlbumDB::getTagsFromTagPaths(const TQStringList &keywordsList, bool create)
|
|
|
|
{
|
|
|
|
if (keywordsList.isEmpty())
|
|
|
|
return IntList();
|
|
|
|
|
|
|
|
IntList tagIDs;
|
|
|
|
|
|
|
|
TQStringList keywordsList2Create;
|
|
|
|
|
|
|
|
// Create a list of the tags currently in database
|
|
|
|
|
|
|
|
TagInfo::List currentTagsList;
|
|
|
|
|
|
|
|
TQStringList values;
|
|
|
|
execSql( "SELECT id, pid, name FROM Tags;", &values );
|
|
|
|
|
|
|
|
for (TQStringList::iterator it = values.begin(); it != values.end();)
|
|
|
|
{
|
|
|
|
TagInfo info;
|
|
|
|
|
|
|
|
info.id = (*it).toInt();
|
|
|
|
++it;
|
|
|
|
info.pid = (*it).toInt();
|
|
|
|
++it;
|
|
|
|
info.name = *it;
|
|
|
|
++it;
|
|
|
|
currentTagsList.append(info);
|
|
|
|
}
|
|
|
|
|
|
|
|
// For every tag in keywordsList, scan taglist to check if tag already exists.
|
|
|
|
|
|
|
|
for (TQStringList::const_iterator kwd = keywordsList.begin();
|
|
|
|
kwd != keywordsList.end(); ++kwd )
|
|
|
|
{
|
|
|
|
// split full tag "url" into list of single tag names
|
|
|
|
TQStringList tagHierarchy = TQStringList::split('/', *kwd);
|
|
|
|
if (tagHierarchy.isEmpty())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// last entry in list is the actual tag name
|
|
|
|
bool foundTag = false;
|
|
|
|
TQString tagName = tagHierarchy.back();
|
|
|
|
tagHierarchy.pop_back();
|
|
|
|
|
|
|
|
for (TagInfo::List::iterator tag = currentTagsList.begin();
|
|
|
|
tag != currentTagsList.end(); ++tag )
|
|
|
|
{
|
|
|
|
// There might be multiple tags with the same name, but in different
|
|
|
|
// hierarchies. We must check them all until we find the correct hierarchy
|
|
|
|
if ((*tag).name == tagName)
|
|
|
|
{
|
|
|
|
int parentID = (*tag).pid;
|
|
|
|
|
|
|
|
// Check hierarchy, from bottom to top
|
|
|
|
bool foundParentTag = true;
|
|
|
|
TQStringList::iterator parentTagName = tagHierarchy.end();
|
|
|
|
|
|
|
|
while (foundParentTag && parentTagName != tagHierarchy.begin())
|
|
|
|
{
|
|
|
|
--parentTagName;
|
|
|
|
|
|
|
|
foundParentTag = false;
|
|
|
|
|
|
|
|
for (TagInfo::List::iterator parentTag = currentTagsList.begin();
|
|
|
|
parentTag != currentTagsList.end(); ++parentTag )
|
|
|
|
{
|
|
|
|
// check if name is the same, and if ID is identical
|
|
|
|
// to the parent ID we got from the child tag
|
|
|
|
if ( (*parentTag).id == parentID &&
|
|
|
|
(*parentTag).name == (*parentTagName) )
|
|
|
|
{
|
|
|
|
parentID = (*parentTag).pid;
|
|
|
|
foundParentTag = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we traversed the list without a match,
|
|
|
|
// foundParentTag will be false, the while loop breaks.
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we managed to traverse the full hierarchy,
|
|
|
|
// we have our tag.
|
|
|
|
if (foundParentTag)
|
|
|
|
{
|
|
|
|
// add to result list
|
|
|
|
tagIDs.append((*tag).id);
|
|
|
|
foundTag = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!foundTag)
|
|
|
|
keywordsList2Create.append(*kwd);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If tags do not exist in database, create them.
|
|
|
|
|
|
|
|
if (create && !keywordsList2Create.isEmpty())
|
|
|
|
{
|
|
|
|
for (TQStringList::iterator kwd = keywordsList2Create.begin();
|
|
|
|
kwd != keywordsList2Create.end(); ++kwd )
|
|
|
|
{
|
|
|
|
// split full tag "url" into list of single tag names
|
|
|
|
TQStringList tagHierarchy = TQStringList::split('/', *kwd);
|
|
|
|
|
|
|
|
if (tagHierarchy.isEmpty())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
int parentTagID = 0;
|
|
|
|
int tagID = 0;
|
|
|
|
bool parentTagExisted = true;
|
|
|
|
|
|
|
|
// Traverse hierarchy from top to bottom
|
|
|
|
for (TQStringList::iterator tagName = tagHierarchy.begin();
|
|
|
|
tagName != tagHierarchy.end(); ++tagName)
|
|
|
|
{
|
|
|
|
tagID = 0;
|
|
|
|
|
|
|
|
// if the parent tag did not exist, we need not check if the child exists
|
|
|
|
if (parentTagExisted)
|
|
|
|
{
|
|
|
|
for (TagInfo::List::iterator tag = currentTagsList.begin();
|
|
|
|
tag != currentTagsList.end(); ++tag )
|
|
|
|
{
|
|
|
|
// find the tag with tag name according to tagHierarchy,
|
|
|
|
// and parent ID identical to the ID of the tag we found in
|
|
|
|
// the previous run.
|
|
|
|
if ((*tag).name == (*tagName) && (*tag).pid == parentTagID)
|
|
|
|
{
|
|
|
|
tagID = (*tag).id;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tagID != 0)
|
|
|
|
{
|
|
|
|
// tag already found in DB
|
|
|
|
parentTagID = tagID;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tag does not yet exist in DB, add it
|
|
|
|
tagID = addTag(parentTagID, (*tagName), TQString(), 0);
|
|
|
|
|
|
|
|
if (tagID == -1)
|
|
|
|
{
|
|
|
|
// Something is wrong in database. Abort.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// append to our list of existing tags (for following keywords)
|
|
|
|
TagInfo info;
|
|
|
|
info.id = tagID;
|
|
|
|
info.pid = parentTagID;
|
|
|
|
info.name = (*tagName);
|
|
|
|
currentTagsList.append(info);
|
|
|
|
|
|
|
|
parentTagID = tagID;
|
|
|
|
parentTagExisted = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// add to result list
|
|
|
|
tagIDs.append(tagID);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return tagIDs;
|
|
|
|
}
|
|
|
|
|
|
|
|
int AlbumDB::getItemAlbum(TQ_LLONG imageID)
|
|
|
|
{
|
|
|
|
TQStringList values;
|
|
|
|
|
|
|
|
execSql ( TQString ("SELECT dirid FROM Images "
|
|
|
|
"WHERE id=%1;")
|
|
|
|
.tqarg(imageID),
|
|
|
|
&values);
|
|
|
|
|
|
|
|
if (!values.isEmpty())
|
|
|
|
return values.first().toInt();
|
|
|
|
else
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString AlbumDB::getItemName(TQ_LLONG imageID)
|
|
|
|
{
|
|
|
|
TQStringList values;
|
|
|
|
|
|
|
|
execSql ( TQString ("SELECT name FROM Images "
|
|
|
|
"WHERE id=%1;")
|
|
|
|
.tqarg(imageID),
|
|
|
|
&values);
|
|
|
|
|
|
|
|
if (!values.isEmpty())
|
|
|
|
return values.first();
|
|
|
|
else
|
|
|
|
return TQString();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AlbumDB::setItemDate(TQ_LLONG imageID,
|
|
|
|
const TQDateTime& datetime)
|
|
|
|
{
|
|
|
|
execSql ( TQString ("UPDATE Images SET datetime='%1'"
|
|
|
|
"WHERE id=%2;")
|
|
|
|
.tqarg(datetime.toString(Qt::ISODate),
|
|
|
|
TQString::number(imageID)) );
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AlbumDB::setItemDate(int albumID, const TQString& name,
|
|
|
|
const TQDateTime& datetime)
|
|
|
|
{
|
|
|
|
execSql ( TQString ("UPDATE Images SET datetime='%1'"
|
|
|
|
"WHERE dirid=%2 AND name='%3';")
|
|
|
|
.tqarg(datetime.toString(Qt::ISODate),
|
|
|
|
TQString::number(albumID),
|
|
|
|
escapeString(name)) );
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumDB::setItemRating(TQ_LLONG imageID, int rating)
|
|
|
|
{
|
|
|
|
execSql ( TQString ("REPLACE INTO ImageProperties "
|
|
|
|
"(imageid, property, value) "
|
|
|
|
"VALUES(%1, '%2', '%3');")
|
|
|
|
.tqarg(imageID)
|
|
|
|
.tqarg("Rating")
|
|
|
|
.tqarg(rating) );
|
|
|
|
}
|
|
|
|
|
|
|
|
int AlbumDB::getItemRating(TQ_LLONG imageID)
|
|
|
|
{
|
|
|
|
TQStringList values;
|
|
|
|
|
|
|
|
execSql( TQString("SELECT value FROM ImageProperties "
|
|
|
|
"WHERE imageid=%1 and property='%2';")
|
|
|
|
.tqarg(imageID)
|
|
|
|
.tqarg("Rating"),
|
|
|
|
&values);
|
|
|
|
|
|
|
|
if (!values.isEmpty())
|
|
|
|
return values[0].toInt();
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQStringList AlbumDB::getItemURLsInAlbum(int albumID)
|
|
|
|
{
|
|
|
|
TQStringList values;
|
|
|
|
|
|
|
|
TQString basePath(AlbumManager::instance()->getLibraryPath());
|
|
|
|
|
|
|
|
AlbumSettings::ImageSortOrder order = AlbumSettings::instance()->getImageSortOrder();
|
|
|
|
|
|
|
|
TQString sqlString;
|
|
|
|
switch(order)
|
|
|
|
{
|
|
|
|
case AlbumSettings::ByIName:
|
|
|
|
sqlString = TQString("SELECT Albums.url||'/'||Images.name FROM Images, Albums "
|
|
|
|
"WHERE Albums.id=%1 AND Albums.id=Images.dirid "
|
|
|
|
"ORDER BY Images.name COLLATE NOCASE;")
|
|
|
|
.tqarg(albumID);
|
|
|
|
break;
|
|
|
|
case AlbumSettings::ByIPath:
|
|
|
|
// Dont collate on the path - this is to maintain the same behaviour
|
|
|
|
// that happens when sort order is "By Path"
|
|
|
|
sqlString = TQString("SELECT Albums.url||'/'||Images.name FROM Images, Albums "
|
|
|
|
"WHERE Albums.id=%1 AND Albums.id=Images.dirid "
|
|
|
|
"ORDER BY Albums.url,Images.name;")
|
|
|
|
.tqarg(albumID);
|
|
|
|
break;
|
|
|
|
case AlbumSettings::ByIDate:
|
|
|
|
sqlString = TQString("SELECT Albums.url||'/'||Images.name FROM Images, Albums "
|
|
|
|
"WHERE Albums.id=%1 AND Albums.id=Images.dirid "
|
|
|
|
"ORDER BY Images.datetime;")
|
|
|
|
.tqarg(albumID);
|
|
|
|
break;
|
|
|
|
case AlbumSettings::ByIRating:
|
|
|
|
sqlString = TQString("SELECT Albums.url||'/'||Images.name FROM Images, Albums, ImageProperties "
|
|
|
|
"WHERE Albums.id=%1 AND Albums.id=Images.dirid "
|
|
|
|
"AND Images.id = ImageProperties.imageid "
|
|
|
|
"AND ImageProperties.property='Rating' "
|
|
|
|
"ORDER BY ImageProperties.value DESC;")
|
|
|
|
.tqarg(albumID);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
sqlString = TQString("SELECT Albums.url||'/'||Images.name FROM Images, Albums "
|
|
|
|
"WHERE Albums.id=%1 AND Albums.id=Images.dirid;")
|
|
|
|
.tqarg(albumID);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
execSql( sqlString, &values );
|
|
|
|
|
|
|
|
for (TQStringList::iterator it = values.begin(); it != values.end(); ++it)
|
|
|
|
{
|
|
|
|
*it = basePath + *it;
|
|
|
|
}
|
|
|
|
|
|
|
|
return values;
|
|
|
|
}
|
|
|
|
|
|
|
|
LLongList AlbumDB::getItemIDsInAlbum(int albumID)
|
|
|
|
{
|
|
|
|
LLongList itemIDs;
|
|
|
|
|
|
|
|
TQStringList itemNames = getItemNamesInAlbum(albumID);
|
|
|
|
|
|
|
|
for (TQStringList::iterator it = itemNames.begin(); it != itemNames.end(); ++it)
|
|
|
|
{
|
|
|
|
TQ_LLONG id = getImageId(albumID, *it);
|
|
|
|
itemIDs.append(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
return itemIDs;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQStringList AlbumDB::getItemURLsInTag(int tagID, bool recursive)
|
|
|
|
{
|
|
|
|
TQStringList values;
|
|
|
|
|
|
|
|
TQString basePath(AlbumManager::instance()->getLibraryPath());
|
|
|
|
|
|
|
|
TQString imagesIdClause;
|
|
|
|
if (recursive)
|
|
|
|
imagesIdClause = TQString("SELECT imageid FROM ImageTags "
|
|
|
|
" WHERE tagid=%1 "
|
|
|
|
" OR tagid IN (SELECT id FROM TagsTree WHERE pid=%2)")
|
|
|
|
.tqarg(tagID).tqarg(tagID);
|
|
|
|
else
|
|
|
|
imagesIdClause = TQString("SELECT imageid FROM ImageTags WHERE tagid=%1").tqarg(tagID);
|
|
|
|
|
|
|
|
execSql( TQString("SELECT Albums.url||'/'||Images.name FROM Images, Albums "
|
|
|
|
"WHERE Images.id IN (%1) "
|
|
|
|
"AND Albums.id=Images.dirid;")
|
|
|
|
.tqarg(imagesIdClause), &values );
|
|
|
|
|
|
|
|
for (TQStringList::iterator it = values.begin(); it != values.end(); ++it)
|
|
|
|
{
|
|
|
|
*it = basePath + *it;
|
|
|
|
}
|
|
|
|
|
|
|
|
return values;
|
|
|
|
}
|
|
|
|
|
|
|
|
LLongList AlbumDB::getItemIDsInTag(int tagID, bool recursive)
|
|
|
|
{
|
|
|
|
LLongList itemIDs;
|
|
|
|
TQStringList values;
|
|
|
|
|
|
|
|
if (recursive)
|
|
|
|
execSql( TQString("SELECT imageid FROM ImageTags "
|
|
|
|
" WHERE tagid=%1 "
|
|
|
|
" OR tagid IN (SELECT id FROM TagsTree WHERE pid=%2)")
|
|
|
|
.tqarg(tagID).tqarg(tagID), &values );
|
|
|
|
else
|
|
|
|
execSql( TQString("SELECT imageid FROM ImageTags WHERE tagid=%1;")
|
|
|
|
.tqarg(tagID), &values );
|
|
|
|
|
|
|
|
for (TQStringList::iterator it = values.begin(); it != values.end(); ++it)
|
|
|
|
{
|
|
|
|
itemIDs << (*it).toLong();
|
|
|
|
}
|
|
|
|
|
|
|
|
return itemIDs;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString AlbumDB::getAlbumURL(int albumID)
|
|
|
|
{
|
|
|
|
TQStringList values;
|
|
|
|
execSql( TQString("SELECT url from Albums where id=%1")
|
|
|
|
.tqarg( albumID), &values);
|
|
|
|
return values[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
TQDate AlbumDB::getAlbumLowestDate(int albumID)
|
|
|
|
{
|
|
|
|
TQStringList values;
|
|
|
|
execSql( TQString("SELECT MIN(datetime) FROM Images "
|
|
|
|
"WHERE dirid=%1 GROUP BY dirid")
|
|
|
|
.tqarg( albumID ), &values);
|
|
|
|
TQDate itemDate = TQDate::fromString( values[0], Qt::ISODate );
|
|
|
|
return itemDate;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQDate AlbumDB::getAlbumHighestDate(int albumID)
|
|
|
|
{
|
|
|
|
TQStringList values;
|
|
|
|
execSql( TQString("SELECT MAX(datetime) FROM Images "
|
|
|
|
"WHERE dirid=%1 GROUP BY dirid")
|
|
|
|
.tqarg( albumID ), &values);
|
|
|
|
TQDate itemDate = TQDate::fromString( values[0], Qt::ISODate );
|
|
|
|
return itemDate;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQDate AlbumDB::getAlbumAverageDate(int albumID)
|
|
|
|
{
|
|
|
|
TQStringList values;
|
|
|
|
execSql( TQString("SELECT datetime FROM Images WHERE dirid=%1")
|
|
|
|
.tqarg( albumID ), &values);
|
|
|
|
|
|
|
|
int differenceInSecs = 0;
|
|
|
|
int amountOfImages = 0;
|
|
|
|
TQDateTime baseDateTime;
|
|
|
|
|
|
|
|
for (TQStringList::iterator it = values.begin(); it != values.end(); ++it)
|
|
|
|
{
|
|
|
|
TQDateTime itemDateTime = TQDateTime::fromString( *it, Qt::ISODate );
|
|
|
|
if (itemDateTime.isValid())
|
|
|
|
{
|
|
|
|
++amountOfImages;
|
|
|
|
if ( baseDateTime.isNull() )
|
|
|
|
baseDateTime=itemDateTime;
|
|
|
|
else
|
|
|
|
differenceInSecs += itemDateTime.secsTo( baseDateTime );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( amountOfImages > 0 )
|
|
|
|
{
|
|
|
|
TQDateTime averageDateTime;
|
|
|
|
averageDateTime.setTime_t( baseDateTime.toTime_t() -
|
|
|
|
(int)( differenceInSecs/amountOfImages ) );
|
|
|
|
return ( averageDateTime.date() );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return TQDate();
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumDB::deleteItem(int albumID, const TQString& file)
|
|
|
|
{
|
|
|
|
execSql( TQString("DELETE FROM Images "
|
|
|
|
"WHERE dirid=%1 AND name='%2';")
|
|
|
|
.tqarg(albumID)
|
|
|
|
.tqarg(escapeString(file)) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumDB::setAlbumURL(int albumID, const TQString& url)
|
|
|
|
{
|
|
|
|
TQString u = escapeString(url);
|
|
|
|
|
|
|
|
// first delete any stale albums left behind
|
|
|
|
execSql( TQString("DELETE FROM Albums WHERE url = '%1'")
|
|
|
|
.tqarg(u) );
|
|
|
|
|
|
|
|
// now update the album url
|
|
|
|
execSql( TQString("UPDATE Albums SET url = '%1' WHERE id = %2;")
|
|
|
|
.tqarg(u, TQString::number(albumID) ));
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumDB::setTagName(int tagID, const TQString& name)
|
|
|
|
{
|
|
|
|
execSql( TQString("UPDATE Tags SET name='%1' WHERE id=%2;")
|
|
|
|
.tqarg(escapeString(name), TQString::number(tagID) ));
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumDB::moveItem(int srcAlbumID, const TQString& srcName,
|
|
|
|
int dstAlbumID, const TQString& dstName)
|
|
|
|
{
|
|
|
|
|
|
|
|
// first delete any stale database entries if any
|
|
|
|
deleteItem(dstAlbumID, dstName);
|
|
|
|
|
|
|
|
execSql( TQString("UPDATE Images SET dirid=%1, name='%2' "
|
|
|
|
"WHERE dirid=%3 AND name='%4';")
|
|
|
|
.tqarg(TQString::number(dstAlbumID), escapeString(dstName),
|
|
|
|
TQString::number(srcAlbumID), escapeString(srcName)) );
|
|
|
|
}
|
|
|
|
|
|
|
|
int AlbumDB::copyItem(int srcAlbumID, const TQString& srcName,
|
|
|
|
int dstAlbumID, const TQString& dstName)
|
|
|
|
{
|
|
|
|
// check for src == dest
|
|
|
|
if (srcAlbumID == dstAlbumID && srcName == dstName)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
// find id of src image
|
|
|
|
TQStringList values;
|
|
|
|
execSql( TQString("SELECT id FROM Images "
|
|
|
|
"WHERE dirid=%1 AND name='%2';")
|
|
|
|
.tqarg(TQString::number(srcAlbumID), escapeString(srcName)),
|
|
|
|
&values);
|
|
|
|
|
|
|
|
if (values.isEmpty())
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
int srcId = values[0].toInt();
|
|
|
|
|
|
|
|
// first delete any stale database entries if any
|
|
|
|
deleteItem(dstAlbumID, dstName);
|
|
|
|
|
|
|
|
// copy entry in Images table
|
|
|
|
execSql( TQString("INSERT INTO Images (dirid, name, caption, datetime) "
|
|
|
|
"SELECT %1, '%2', caption, datetime FROM Images "
|
|
|
|
"WHERE id=%3;")
|
|
|
|
.tqarg(TQString::number(dstAlbumID), escapeString(dstName),
|
|
|
|
TQString::number(srcId)) );
|
|
|
|
|
|
|
|
int dstId = sqlite3_last_insert_rowid(d->dataBase);
|
|
|
|
|
|
|
|
// copy tags
|
|
|
|
execSql( TQString("INSERT INTO ImageTags (imageid, tagid) "
|
|
|
|
"SELECT %1, tagid FROM ImageTags "
|
|
|
|
"WHERE imageid=%2;")
|
|
|
|
.tqarg(TQString::number(dstId), TQString::number(srcId)) );
|
|
|
|
|
|
|
|
// copy properties (rating)
|
|
|
|
execSql( TQString("INSERT INTO ImageProperties (imageid, property, value) "
|
|
|
|
"SELECT %1, property, value FROM ImageProperties "
|
|
|
|
"WHERE imageid=%2;")
|
|
|
|
.tqarg(TQString::number(dstId), TQString::number(srcId)) );
|
|
|
|
|
|
|
|
return dstId;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQ_LLONG AlbumDB::lastInsertedRow()
|
|
|
|
{
|
|
|
|
return sqlite3_last_insert_rowid(d->dataBase);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Digikam
|
|
|
|
|