diff --git a/src/allimagesmodel.h b/src/allimagesmodel.h index f343fac..5af8d3c 100644 --- a/src/allimagesmodel.h +++ b/src/allimagesmodel.h @@ -1,46 +1,46 @@ /* * Copyright (C) 2015 Vishesh Handa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef KOKO_ALLIMAGESMODEL_H #define KOKO_ALLIMAGESMODEL_H #include class AllImagesModel : public QAbstractListModel { Q_OBJECT public: explicit AllImagesModel(QObject* parent = 0); enum Roles { FilePathRole = Qt::UserRole + 1 }; - virtual QHash roleNames() const; - virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; - virtual int rowCount(const QModelIndex& parent = QModelIndex()) const; + QHash roleNames() const override; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + int rowCount(const QModelIndex& parent = QModelIndex()) const override; private Q_SLOTS: void slotPopulate(); private: QStringList m_images; }; #endif diff --git a/src/exiv2extractor.cpp b/src/exiv2extractor.cpp index 151b1ec..7c3d8a6 100644 --- a/src/exiv2extractor.cpp +++ b/src/exiv2extractor.cpp @@ -1,242 +1,242 @@ /* Copyright (C) 2012-15 Vishesh Handa This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "exiv2extractor.h" #include #include Exiv2Extractor::Exiv2Extractor() : m_latitude(0) , m_longitude(0) , m_error(true) { } static QDateTime dateTimeFromString(const QString& dateString) { QDateTime dateTime; if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, QStringLiteral("yyyy-MM-dd")); dateTime.setTimeSpec(Qt::UTC); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, QStringLiteral("dd-MM-yyyy")); dateTime.setTimeSpec(Qt::UTC); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, QStringLiteral("yyyy-MM")); dateTime.setTimeSpec(Qt::UTC); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, QStringLiteral("MM-yyyy")); dateTime.setTimeSpec(Qt::UTC); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, QStringLiteral("yyyy.MM.dd")); dateTime.setTimeSpec(Qt::UTC); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, QStringLiteral("dd.MM.yyyy")); dateTime.setTimeSpec(Qt::UTC); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, QStringLiteral("dd MMMM yyyy")); dateTime.setTimeSpec(Qt::UTC); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, QStringLiteral("MM.yyyy")); dateTime.setTimeSpec(Qt::UTC); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, QStringLiteral("yyyy.MM")); dateTime.setTimeSpec(Qt::UTC); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, QStringLiteral("yyyy")); dateTime.setTimeSpec(Qt::UTC); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, QStringLiteral("yy")); dateTime.setTimeSpec(Qt::UTC); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, Qt::ISODate); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, QStringLiteral("dddd d MMM yyyy h':'mm':'ss AP")); dateTime.setTimeSpec(Qt::LocalTime); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, QStringLiteral("yyyy:MM:dd hh:mm:ss")); dateTime.setTimeSpec(Qt::LocalTime); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, Qt::SystemLocaleDate); dateTime.setTimeSpec(Qt::UTC); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, Qt::SystemLocaleShortDate); dateTime.setTimeSpec(Qt::UTC); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, Qt::SystemLocaleLongDate); dateTime.setTimeSpec(Qt::UTC); } if (!dateTime.isValid()) { qWarning() << "Could not determine correct datetime format from:" << dateString; return QDateTime(); } return dateTime; } static QDateTime toDateTime(const Exiv2::Value& value) { if (value.typeId() == Exiv2::asciiString) { QDateTime val = dateTimeFromString(value.toString().c_str()); if (val.isValid()) { // Datetime is stored in exif as local time. - val.setUtcOffset(0); + val.setOffsetFromUtc(0); return val; } } return QDateTime(); } void Exiv2Extractor::extract(const QString& filePath) { QByteArray arr = QFile::encodeName(filePath); std::string fileString(arr.data(), arr.length()); Exiv2::LogMsg::setLevel(Exiv2::LogMsg::mute); #if EXIV2_TEST_VERSION(0, 27, 99) Exiv2::Image::UniquePtr image; #else Exiv2::Image::AutoPtr image; #endif try { image = Exiv2::ImageFactory::open(fileString); } catch (const std::exception&) { return; } if (!image.get()) { return; } if (!image->good()) { return; } try { image->readMetadata(); } catch (const std::exception&) { return; } const Exiv2::ExifData& data = image->exifData(); Exiv2::ExifData::const_iterator it = data.findKey(Exiv2::ExifKey("Exif.Photo.DateTimeOriginal")); if (it != data.end()) { m_dateTime = toDateTime(it->value()); } if (m_dateTime.isNull()) { it = data.findKey(Exiv2::ExifKey("Exif.Image.DateTime")); if (it != data.end()) { m_dateTime = toDateTime(it->value()); } } m_latitude = fetchGpsDouble(data, "Exif.GPSInfo.GPSLatitude"); m_longitude = fetchGpsDouble(data, "Exif.GPSInfo.GPSLongitude"); QByteArray latRef = fetchByteArray(data, "Exif.GPSInfo.GPSLatitudeRef"); if (!latRef.isEmpty() && latRef[0] == 'S') m_latitude *= -1; QByteArray longRef = fetchByteArray(data, "Exif.GPSInfo.GPSLongitudeRef"); if (!longRef.isEmpty() && longRef[0] == 'W') m_longitude *= -1; m_error = false; } double Exiv2Extractor::fetchGpsDouble(const Exiv2::ExifData& data, const char* name) { Exiv2::ExifData::const_iterator it = data.findKey(Exiv2::ExifKey(name)); if (it != data.end() && it->count() == 3) { double n = 0.0; double d = 0.0; n = (*it).toRational(0).first; d = (*it).toRational(0).second; if (d == 0) { return 0.0; } double deg = n / d; n = (*it).toRational(1).first; d = (*it).toRational(1).second; if (d == 0) { return deg; } double min = n / d; if (min != -1.0) { deg += min / 60.0; } n = (*it).toRational(2).first; d = (*it).toRational(2).second; if (d == 0) { return deg; } double sec = n / d; if (sec != -1.0) { deg += sec / 3600.0; } return deg; } return 0.0; } QByteArray Exiv2Extractor::fetchByteArray(const Exiv2::ExifData& data, const char* name) { Exiv2::ExifData::const_iterator it = data.findKey(Exiv2::ExifKey(name)); if (it != data.end()) { std::string str = it->value().toString(); return QByteArray(str.c_str(), str.size()); } return QByteArray(); } bool Exiv2Extractor::error() const { return m_error; } diff --git a/src/filesystemtracker.cpp b/src/filesystemtracker.cpp index 36bb8f6..30094f3 100644 --- a/src/filesystemtracker.cpp +++ b/src/filesystemtracker.cpp @@ -1,235 +1,235 @@ /* * Copyright (C) 2017 Atul Sharma * Copyright (C) 2014 Vishesh Handa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "filesystemtracker.h" #include "filesystemimagefetcher.h" #include #include #include #include #include #include #include #include #include #include FileSystemTracker::FileSystemTracker(QObject* parent) : QObject(parent) { QObject::connect(KDirWatch::self(), &KDirWatch::dirty, this, &FileSystemTracker::setSubFolder); org::kde::KDirNotify *kdirnotify = new org::kde::KDirNotify(QString(), QString(), QDBusConnection::sessionBus(), this); connect(kdirnotify, &org::kde::KDirNotify::FilesRemoved, this, [this](const QStringList &files) { for (const QString & filePath : files) { removeFile(filePath); } }); connect(kdirnotify, &org::kde::KDirNotify::FilesAdded, this, &FileSystemTracker::setSubFolder); connect(kdirnotify, &org::kde::KDirNotify::FileRenamedWithLocalPath, - this, [this](const QString &src, const QString &dst, const QString &dstPath) { + this, [this](const QString &src, const QString &dst, const QString &) { removeFile(src); slotNewFiles({dst}); }); // // Real time updates // QDBusConnection con = QDBusConnection::sessionBus(); con.connect(QString(), QLatin1String("/files"), QLatin1String("org.kde"), QLatin1String("changed"), this, SLOT(slotNewFiles(QStringList))); connect( this, &FileSystemTracker::subFolderChanged, this, &FileSystemTracker::reindexSubFolder); } void FileSystemTracker::setupDb() { static QString dir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/koko/"; QDir().mkpath(dir); QSqlDatabase db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), QStringLiteral("fstracker")); db.setDatabaseName(dir + "/fstracker.sqlite3"); if (!db.open()) { qWarning() << "Failed to open db" << db.lastError().text(); return; } if (db.tables().contains("files")) { return; } QSqlQuery query(db); bool ret = query.exec(QLatin1String("CREATE TABLE files(" "id INTEGER PRIMARY KEY, " "url TEXT NOT NULL UNIQUE)")); if (!ret) { qWarning() << "Could not create files table" << query.lastError().text(); return; } ret = query.exec(QLatin1String("CREATE INDEX fileUrl_index ON files (url)")); if (!ret) { qWarning() << "Could not create tags index" << query.lastError().text(); return; } // // WAL Journaling mode has much lower io writes than the traditional journal // based indexing. // ret = query.exec(QLatin1String("PRAGMA journal_mode = WAL")); if (!ret) { qWarning() << "Could not set WAL journaling mode" << query.lastError().text(); return; } } FileSystemTracker::~FileSystemTracker() { QSqlDatabase::removeDatabase(QStringLiteral("fstracker")); } void FileSystemTracker::slotImageResult(const QString& filePath) { QSqlQuery query(QSqlDatabase::database("fstracker")); query.prepare("SELECT id from files where url = ?"); query.addBindValue(filePath); if (!query.exec()) { qDebug() << query.lastError(); return; } if (!query.next()) { QSqlQuery query(QSqlDatabase::database("fstracker")); query.prepare("INSERT into files(url) VALUES (?)"); query.addBindValue(filePath); if (!query.exec()) { qDebug() << query.lastError(); return; } qDebug() << "ADDED" << filePath; emit imageAdded(filePath); } m_filePaths << filePath; } void FileSystemTracker::slotFetchFinished() { QSqlQuery query(QSqlDatabase::database("fstracker")); query.prepare("SELECT url from files"); if (!query.exec()) { qDebug() << query.lastError(); return; } while (query.next()) { QString filePath = query.value(0).toString(); if (filePath.contains(m_subFolder) && !m_filePaths.contains(filePath)) { removeFile(filePath); } } QSqlDatabase::database("fstracker").commit(); m_filePaths.clear(); emit initialScanComplete(); } void FileSystemTracker::removeFile(const QString &filePath) { qDebug() << "REMOVED" << filePath; emit imageRemoved(filePath); QSqlQuery query(QSqlDatabase::database("fstracker")); query.prepare("DELETE from files where url = ?"); query.addBindValue(filePath); if (!query.exec()) { qWarning() << query.lastError(); } } void FileSystemTracker::slotNewFiles(const QStringList& files) { if (!m_filePaths.isEmpty()) { // A scan is already going on. No point interrupting it. return; } QMimeDatabase db; for (const QString& file: files) { QMimeType mimetype = db.mimeTypeForFile(file); if (mimetype.name().startsWith("image/")) { slotImageResult(file); } } m_filePaths.clear(); } void FileSystemTracker::setFolder(const QString &folder) { if (m_folder == folder) { return; } KDirWatch::self()->removeDir(m_folder); m_folder = folder; KDirWatch::self()->addDir(m_folder, KDirWatch::WatchSubDirs); } QString FileSystemTracker::folder() const { return m_folder; } void FileSystemTracker::setSubFolder(const QString& folder) { if(QFileInfo(folder).isDir()) { m_subFolder = folder; emit subFolderChanged(); } } void FileSystemTracker::reindexSubFolder() { FileSystemImageFetcher* fetcher = new FileSystemImageFetcher(m_subFolder); connect(fetcher, &FileSystemImageFetcher::imageResult, this, &FileSystemTracker::slotImageResult, Qt::QueuedConnection); connect(fetcher, &FileSystemImageFetcher::finished, this, &FileSystemTracker::slotFetchFinished, Qt::QueuedConnection); fetcher->fetch(); QSqlDatabase::database("fstracker").transaction(); } diff --git a/src/imagefoldermodel.h b/src/imagefoldermodel.h index 852b989..bd3cef8 100644 --- a/src/imagefoldermodel.h +++ b/src/imagefoldermodel.h @@ -1,80 +1,80 @@ /* * Copyright 2017 by Marco Martin * Copyright (C) 2017 Atul Sharma * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library 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 Library General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef IMAGEFOLDERMODEL_H #define IMAGEFOLDERMODEL_H #include #include #include class QTimer; /** * This class provides a QML binding to KDirModel * Provides an easy way to navigate a filesystem from within QML * * @author Marco Martin */ class ImageFolderModel : public KDirModel { Q_OBJECT /** * @property string The url we want to browse. it may be an absolute path or a correct url of any protocol KIO supports */ Q_PROPERTY(QString url READ url WRITE setUrl NOTIFY urlChanged) /** * @property count Total number of rows */ Q_PROPERTY(int count READ count NOTIFY countChanged) public: ImageFolderModel(QObject* parent=0); virtual ~ImageFolderModel(); QHash roleNames() const override; void setUrl(QString& url); QString url() const; - QVariant data(const QModelIndex &index, int role) const; + QVariant data(const QModelIndex &index, int role) const override; int count() const {return rowCount();} Q_INVOKABLE int indexForUrl(const QString &url) const; Q_INVOKABLE QVariantMap get(int index) const; /** * Helper method to empty the trash */ Q_INVOKABLE void emptyTrash(); Q_SIGNALS: void countChanged(); void urlChanged(); private: QStringList m_mimeTypes; QString m_imagePath; }; #endif // IMAGEFOLDERMODEL_H diff --git a/src/imagelistmodel.h b/src/imagelistmodel.h index 9e0a85c..eeea919 100644 --- a/src/imagelistmodel.h +++ b/src/imagelistmodel.h @@ -1,79 +1,79 @@ /* * Copyright 2017 by Atul Sharma * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library 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 Library General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef IMAGELISTMODEL_H #define IMAGELISTMODEL_H #include #include "types.h" class ImageListModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(Types::LocationGroup locationGroup READ locationGroup WRITE setLocationGroup NOTIFY locationGroupChanged) Q_PROPERTY(Types::TimeGroup timeGroup READ timeGroup WRITE setTimeGroup NOTIFY timeGroupChanged) Q_PROPERTY(Types::QueryType queryType READ queryType WRITE setQueryType) Q_PROPERTY(QByteArray query READ query WRITE setQuery NOTIFY queryChanged) public: explicit ImageListModel(QObject* parent = 0); ~ImageListModel(); - virtual QHash< int, QByteArray > roleNames() const; - virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; - virtual int rowCount(const QModelIndex& parent = QModelIndex()) const; + QHash< int, QByteArray > roleNames() const override; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + int rowCount(const QModelIndex& parent = QModelIndex()) const override; Types::LocationGroup locationGroup() const; void setLocationGroup(const Types::LocationGroup &group); Types::TimeGroup timeGroup() const; void setTimeGroup(const Types::TimeGroup &group); Types::QueryType queryType() const; void setQueryType( const Types::QueryType &type); QByteArray query() const; void setQuery(const QByteArray &statement); Q_INVOKABLE QByteArray queryForIndex(const int &index); void slotLocationGroupChanged(); void slotTimeGroupChanged(); void slotResetModel(); Q_SIGNALS: void imageListChanged(); void locationGroupChanged(); void timeGroupChanged(); void queryChanged(); private: QStringList m_images; Types::LocationGroup m_locationGroup; Types::TimeGroup m_timeGroup; Types::QueryType m_queryType; QByteArray m_query; QList< QPair > m_times; QList< QPair > m_locations; }; #endif diff --git a/src/imagelocationmodel.h b/src/imagelocationmodel.h index 4ebbc20..0847bfe 100644 --- a/src/imagelocationmodel.h +++ b/src/imagelocationmodel.h @@ -1,55 +1,55 @@ /* * Copyright (C) 2017 Atul Sharma * Copyright (C) 2014 Vishesh Handa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef IMAGELOCATIONMODEL_H #define IMAGELOCATIONMODEL_H #include #include #include #include "types.h" class ImageLocationModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(Types::LocationGroup group READ group WRITE setGroup NOTIFY groupChanged) public: explicit ImageLocationModel(QObject* parent = 0); - virtual QHash< int, QByteArray > roleNames() const; - virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; - virtual int rowCount(const QModelIndex& parent = QModelIndex()) const; + QHash< int, QByteArray > roleNames() const override; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + int rowCount(const QModelIndex& parent = QModelIndex()) const override; Types::LocationGroup group() const; void setGroup(Types::LocationGroup group); signals: void groupChanged(); private slots: void slotPopulate(); private: Types::LocationGroup m_group; QList > m_locations; }; #endif // IMAGELOCATIONMODEL_H diff --git a/src/imageprocessorrunnable.cpp b/src/imageprocessorrunnable.cpp index 2cc318d..4f28037 100644 --- a/src/imageprocessorrunnable.cpp +++ b/src/imageprocessorrunnable.cpp @@ -1,74 +1,74 @@ /* * Copyright (C) 2015 Vishesh Handa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "imageprocessorrunnable.h" #include #include "reversegeocoder.h" #include "imagestorage.h" #include "exiv2extractor.h" using namespace Koko; ImageProcessorRunnable::ImageProcessorRunnable(QString& filePath, ReverseGeoCoder* geoCoder) : QObject() , m_path(filePath) , m_geoCoder(geoCoder) { } void ImageProcessorRunnable::run() { ImageInfo ii; ii.path = m_path; Exiv2Extractor extractor; extractor.extract(m_path); if (extractor.error()) { emit finished(); return; } double latitude = extractor.gpsLatitude(); double longitude = extractor.gpsLongitude(); if (latitude != 0.0 && longitude != 0.0) { if (!m_geoCoder->initialized()) { m_geoCoder->init(); } QVariantMap map = m_geoCoder->lookup(latitude, longitude); QGeoAddress addr; addr.setCountry(map.value("country").toString()); addr.setState(map.value("admin1").toString()); addr.setCity(map.value("admin2").toString()); ii.location.setAddress(addr); } ii.dateTime = extractor.dateTime(); if (ii.dateTime.isNull()) { - ii.dateTime = QFileInfo(m_path).created(); + ii.dateTime = QFileInfo(m_path).birthTime(); } QMetaObject::invokeMethod(ImageStorage::instance(), "addImage", Qt::AutoConnection, Q_ARG(const ImageInfo&, ii)); emit finished(); } diff --git a/src/imageprocessorrunnable.h b/src/imageprocessorrunnable.h index 44c2d27..3a71e53 100644 --- a/src/imageprocessorrunnable.h +++ b/src/imageprocessorrunnable.h @@ -1,46 +1,46 @@ /* * Copyright (C) 2015 Vishesh Handa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef KOKO_IMAGEPROCESSORRUNNABLE_H #define KOKO_IMAGEPROCESSORRUNNABLE_H #include #include namespace Koko { class ReverseGeoCoder; class ImageProcessorRunnable : public QObject, public QRunnable { Q_OBJECT public: ImageProcessorRunnable(QString& filePath, ReverseGeoCoder* coder); - virtual void run(); + void run() override; signals: void finished(); private: QString m_path; ReverseGeoCoder* m_geoCoder; }; } #endif // KOKO_IMAGEPROCESSORRUNNABLE_H diff --git a/src/imagestorage.cpp b/src/imagestorage.cpp index 07d7f78..e5c6a26 100644 --- a/src/imagestorage.cpp +++ b/src/imagestorage.cpp @@ -1,591 +1,591 @@ /* * Copyright (C) 2017 Atul Sharma * Copyright (C) 2014 Vishesh Handa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "imagestorage.h" #include #include #include #include #include #include #include #include #include #include ImageStorage::ImageStorage(QObject* parent) : QObject(parent) { QString dir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/koko"; QDir().mkpath(dir); QSqlDatabase db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE")); db.setDatabaseName(dir + "/imageData.sqlite3"); if (!db.open()) { qDebug() << "Failed to open db" << db.lastError().text(); return; } if (db.tables().contains("files")) { db.transaction(); return; } QSqlQuery query(db); query.exec("CREATE TABLE locations (id INTEGER PRIMARY KEY, country TEXT, state TEXT, city TEXT" " , UNIQUE(country, state, city) ON CONFLICT REPLACE" ")"); query.exec("CREATE TABLE files (url TEXT NOT NULL UNIQUE PRIMARY KEY," " location INTEGER," " dateTime STRING NOT NULL," " FOREIGN KEY(location) REFERENCES locations(id)" " )"); db.transaction(); } ImageStorage::~ImageStorage() { QString name; { QSqlDatabase db = QSqlDatabase::database(); db.commit(); name = db.connectionName(); } QSqlDatabase::removeDatabase(name); } ImageStorage* ImageStorage::instance() { static ImageStorage storage; return &storage; } void ImageStorage::addImage(const ImageInfo& ii) { QMutexLocker lock(&m_mutex); QGeoAddress addr = ii.location.address(); if (!addr.country().isEmpty()) { int locId = -1; if (!addr.city().isEmpty()) { QSqlQuery query; query.prepare("SELECT id FROM LOCATIONS WHERE country = ? AND state = ? AND city = ?"); query.addBindValue(addr.country()); query.addBindValue(addr.state()); query.addBindValue(addr.city()); if (!query.exec()) { qDebug() << "LOC SELECT" << query.lastError(); } if (query.next()) { locId = query.value(0).toInt(); } } else { QSqlQuery query; query.prepare("SELECT id FROM LOCATIONS WHERE country = ? AND state = ?"); query.addBindValue(addr.country()); query.addBindValue(addr.state()); if (!query.exec()) { qDebug() << "LOC SELECT" << query.lastError(); } if (query.next()) { locId = query.value(0).toInt(); } } if (locId == -1) { QSqlQuery query; query.prepare("INSERT INTO LOCATIONS(country, state, city) VALUES (?, ?, ?)"); query.addBindValue(addr.country()); query.addBindValue(addr.state()); query.addBindValue(addr.city()); if (!query.exec()) { qDebug() << "LOC INSERT" << query.lastError(); } locId = query.lastInsertId().toInt(); } QSqlQuery query; query.prepare("INSERT INTO FILES(url, location, dateTime) VALUES(?, ?, ?)"); query.addBindValue(ii.path); query.addBindValue(locId); query.addBindValue(ii.dateTime.toString(Qt::ISODate)); if (!query.exec()) { qDebug() << "FILE LOC INSERT" << query.lastError(); } } else { QSqlQuery query; query.prepare("INSERT INTO FILES(url, dateTime) VALUES(?, ?)"); query.addBindValue(ii.path); query.addBindValue(ii.dateTime.toString(Qt::ISODate)); if (!query.exec()) { qDebug() << "FILE INSERT" << query.lastError(); } } } void ImageStorage::removeImage(const QString& filePath) { QMutexLocker lock(&m_mutex); QSqlQuery query; query.prepare("DELETE FROM FILES WHERE URL = ?"); query.addBindValue(filePath); if (!query.exec()) { qDebug() << "FILE del" << query.lastError(); } QSqlQuery query2; query2.prepare("DELETE FROM LOCATIONS WHERE id NOT IN (SELECT DISTINCT location FROM files WHERE location IS NOT NULL)"); if (!query2.exec()) { qDebug() << "Loc del" << query2.lastError(); } } void ImageStorage::commit() { { QMutexLocker lock(&m_mutex); QSqlDatabase db = QSqlDatabase::database(); db.commit(); db.transaction(); } emit storageModified(); } QList > ImageStorage::locations(Types::LocationGroup loca) { QMutexLocker lock(&m_mutex); QList< QPair > list; if (loca == Types::LocationGroup::Country) { QSqlQuery query; query.prepare("SELECT DISTINCT country from locations"); if (!query.exec()) { qDebug() << loca << query.lastError(); return list; } while (query.next()) { QString val = query.value(0).toString(); list << qMakePair(val.toUtf8(), val); } return list; } else if (loca == Types::LocationGroup::State) { QSqlQuery query; query.prepare("SELECT DISTINCT country, state from locations"); if (!query.exec()) { qDebug() << loca << query.lastError(); return list; } QStringList groups; while (query.next()) { QString country = query.value(0).toString(); QString state = query.value(1).toString(); QString display = state + ", " + country; QByteArray key; QDataStream stream(&key, QIODevice::WriteOnly); stream << country << state; list << qMakePair(key, display); } return list; } else if (loca == Types::LocationGroup::City) { QSqlQuery query; query.prepare("SELECT DISTINCT country, state, city from locations"); if (!query.exec()) { qDebug() << loca << query.lastError(); return list; } while (query.next()) { QString country = query.value(0).toString(); QString state = query.value(1).toString(); QString city = query.value(2).toString(); QString display; if (!city.isEmpty()) { display = city + ", " + state + ", " + country; } else { display = state + ", " + country; } QByteArray key; QDataStream stream(&key, QIODevice::WriteOnly); stream << country << state << city; list << qMakePair(key, display); } return list; } return list; } QStringList ImageStorage::imagesForLocation(const QByteArray& name, Types::LocationGroup loc) { QMutexLocker lock(&m_mutex); QSqlQuery query; if (loc == Types::LocationGroup::Country) { query.prepare("SELECT DISTINCT url from files, locations where country = ? AND files.location = locations.id"); query.addBindValue(QString::fromUtf8(name)); } else if (loc == Types::LocationGroup::State) { QDataStream st(name); QString country; QString state; st >> country >> state; query.prepare("SELECT DISTINCT url from files, locations where country = ? AND state = ? AND files.location = locations.id"); query.addBindValue(country); query.addBindValue(state); } else if (loc == Types::LocationGroup::City) { QDataStream st(name); QString country; QString state; QString city; st >> country >> state >> city; query.prepare("SELECT DISTINCT url from files, locations where country = ? AND state = ? AND files.location = locations.id"); query.addBindValue(country); query.addBindValue(state); } if (!query.exec()) { qDebug() << loc << query.lastError(); return QStringList(); } QStringList files; while (query.next()) { files << QString( "file://" + query.value(0).toString()); } return files; } QString ImageStorage::imageForLocation(const QByteArray& name, Types::LocationGroup loc) { QMutexLocker lock(&m_mutex); QSqlQuery query; if (loc == Types::LocationGroup::Country) { query.prepare("SELECT DISTINCT url from files, locations where country = ? AND files.location = locations.id"); query.addBindValue(QString::fromUtf8(name)); } else if (loc == Types::LocationGroup::State) { QDataStream st(name); QString country; QString state; st >> country >> state; query.prepare("SELECT DISTINCT url from files, locations where country = ? AND state = ? AND files.location = locations.id"); query.addBindValue(country); query.addBindValue(state); } else if (loc == Types::LocationGroup::City) { QDataStream st(name); QString country; QString state; QString city; st >> country >> state >> city; query.prepare("SELECT DISTINCT url from files, locations where country = ? AND state = ? AND files.location = locations.id"); query.addBindValue(country); query.addBindValue(state); } if (!query.exec()) { qDebug() << loc << query.lastError(); return QString(); } if (query.next()) { return QString( "file://" + query.value(0).toString()); } return QString(); } QList > ImageStorage::timeTypes(Types::TimeGroup group) { QMutexLocker lock(&m_mutex); QList< QPair > list; QSqlQuery query; if (group == Types::TimeGroup::Year) { query.prepare("SELECT DISTINCT strftime('%Y', dateTime) from files"); if (!query.exec()) { qDebug() << group << query.lastError(); return list; } while (query.next()) { QString val = query.value(0).toString(); list << qMakePair(val.toUtf8(), val); } return list; } else if (group == Types::TimeGroup::Month) { query.prepare("SELECT DISTINCT strftime('%Y', dateTime), strftime('%m', dateTime) from files"); if (!query.exec()) { qDebug() << group << query.lastError(); return list; } QStringList groups; while (query.next()) { QString year = query.value(0).toString(); QString month = query.value(1).toString(); - QString display = QDate::longMonthName(month.toInt()) + ", " + year; + QString display = QLocale().monthName(month.toInt(), QLocale::LongFormat) + ", " + year; QByteArray key; QDataStream stream(&key, QIODevice::WriteOnly); stream << year << month; list << qMakePair(key, display); } return list; } else if (group == Types::TimeGroup::Week) { query.prepare("SELECT DISTINCT strftime('%Y', dateTime), strftime('%m', dateTime), strftime('%W', dateTime) from files"); if (!query.exec()) { qDebug() << group << query.lastError(); return list; } while (query.next()) { QString year = query.value(0).toString(); QString month = query.value(1).toString(); QString week = query.value(2).toString(); - QString display = "Week " + week + ", " + QDate::longMonthName(month.toInt()) + ", " + year; + QString display = "Week " + week + ", " + QLocale().monthName(month.toInt(), QLocale::LongFormat) + ", " + year; QByteArray key; QDataStream stream(&key, QIODevice::WriteOnly); stream << year << week; list << qMakePair(key, display); } return list; } else if (group == Types::TimeGroup::Day) { query.prepare("SELECT DISTINCT date(dateTime) from files"); if (!query.exec()) { qDebug() << group << query.lastError(); return list; } while (query.next()) { QDate date = query.value(0).toDate(); QString display = date.toString(Qt::SystemLocaleLongDate); QByteArray key = date.toString(Qt::ISODate).toUtf8(); list << qMakePair(key, display); } return list; } Q_ASSERT(0); return list; } QStringList ImageStorage::imagesForTime(const QByteArray& name, Types::TimeGroup group) { QMutexLocker lock(&m_mutex); QSqlQuery query; if (group == Types::TimeGroup::Year) { query.prepare("SELECT DISTINCT url from files where strftime('%Y', dateTime) = ?"); query.addBindValue(QString::fromUtf8(name)); } else if (group == Types::TimeGroup::Month) { QDataStream stream(name); QString year; QString month; stream >> year >> month; query.prepare("SELECT DISTINCT url from files where strftime('%Y', dateTime) = ? AND strftime('%m', dateTime) = ?"); query.addBindValue(year); query.addBindValue(month); } else if (group == Types::TimeGroup::Week) { QDataStream stream(name); QString year; QString week; stream >> year >> week; query.prepare("SELECT DISTINCT url from files where strftime('%Y', dateTime) = ? AND strftime('%W', dateTime) = ?"); query.addBindValue(year); query.addBindValue(week); } else if (group == Types::TimeGroup::Day) { QDate date = QDate::fromString(QString::fromUtf8(name), Qt::ISODate); query.prepare("SELECT DISTINCT url from files where date(dateTime) = ?"); query.addBindValue(date); } if (!query.exec()) { qDebug() << group << query.lastError(); return QStringList(); } QStringList files; while (query.next()) { files << QString( "file://" + query.value(0).toString()); } Q_ASSERT(!files.isEmpty()); return files; } QString ImageStorage::imageForTime(const QByteArray& name, Types::TimeGroup group) { QMutexLocker lock(&m_mutex); Q_ASSERT(!name.isEmpty()); QSqlQuery query; if (group == Types::TimeGroup::Year) { query.prepare("SELECT DISTINCT url from files where strftime('%Y', dateTime) = ? LIMIT 1"); query.addBindValue(QString::fromUtf8(name)); } else if (group == Types::TimeGroup::Month) { QDataStream stream(name); QString year; QString month; stream >> year >> month; query.prepare("SELECT DISTINCT url from files where strftime('%Y', dateTime) = ? AND strftime('%m', dateTime) = ? LIMIT 1"); query.addBindValue(year); query.addBindValue(month); } else if (group == Types::TimeGroup::Week) { QDataStream stream(name); QString year; QString week; stream >> year >> week; query.prepare("SELECT DISTINCT url from files where strftime('%Y', dateTime) = ? AND strftime('%W', dateTime) = ? LIMIT 1"); query.addBindValue(year); query.addBindValue(week); } else if (group == Types::TimeGroup::Day) { QDate date = QDate::fromString(QString::fromUtf8(name), Qt::ISODate); query.prepare("SELECT DISTINCT url from files where date(dateTime) = ? LIMIT 1"); query.addBindValue(date); } if (!query.exec()) { qDebug() << group << query.lastError(); return QString(); } if (query.next()) { return QString( "file://" + query.value(0).toString()); } Q_ASSERT(0); return QString(); } QDate ImageStorage::dateForKey(const QByteArray& key, Types::TimeGroup group) { if (group == Types::TimeGroup::Year) { return QDate(key.toInt(), 1, 1); } else if (group == Types::TimeGroup::Month) { QDataStream stream(key); QString year; QString month; stream >> year >> month; return QDate(year.toInt(), month.toInt(), 1); } else if (group == Types::TimeGroup::Week) { QDataStream stream(key); QString year; QString week; stream >> year >> week; int month = week.toInt() / 4; int day = week.toInt() % 4; return QDate(year.toInt(), month, day); } else if (group == Types::TimeGroup::Day) { return QDate::fromString(QString::fromUtf8(key), Qt::ISODate); } Q_ASSERT(0); return QDate(); } void ImageStorage::reset() { QString dir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/koko"; QDir(dir).removeRecursively(); } QStringList ImageStorage::allImages(int size, int offset) { QMutexLocker lock(&m_mutex); QSqlQuery query; if (size == -1) { query.prepare("SELECT DISTINCT url from files ORDER BY dateTime DESC"); } else { query.prepare("SELECT DISTINCT url from files ORDER BY dateTime DESC LIMIT ? OFFSET ?"); query.addBindValue(size); query.addBindValue(offset); } if (!query.exec()) { qDebug() << query.lastError(); return QStringList(); } QStringList imageList; while (query.next()) imageList << query.value(0).toString(); return imageList; } diff --git a/src/imagetimemodel.h b/src/imagetimemodel.h index 4a523ce..609eb92 100644 --- a/src/imagetimemodel.h +++ b/src/imagetimemodel.h @@ -1,54 +1,54 @@ /* * Copyright (C) 2017 Atul Sharma * Copyright (C) 2014 Vishesh Handa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef IMAGETIMEMODEL_H #define IMAGETIMEMODEL_H #include #include #include "types.h" class ImageTimeModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(Types::TimeGroup group READ group WRITE setGroup NOTIFY groupChanged) public: explicit ImageTimeModel(QObject* parent = 0); - virtual QHash< int, QByteArray > roleNames() const; - virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; - virtual int rowCount(const QModelIndex& parent = QModelIndex()) const; + QHash< int, QByteArray > roleNames() const override; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + int rowCount(const QModelIndex& parent = QModelIndex()) const override; Types::TimeGroup group() const; void setGroup(Types::TimeGroup group); signals: void groupChanged(); private slots: void slotPopulate(); private: Types::TimeGroup m_group; QList< QPair > m_times; }; #endif diff --git a/src/qmlplugins.cpp b/src/qmlplugins.cpp index 56a8e3b..89796a4 100644 --- a/src/qmlplugins.cpp +++ b/src/qmlplugins.cpp @@ -1,56 +1,60 @@ /* * Copyright (C) 2014 Vishesh Handa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * */ #include "qmlplugins.h" #include "tagmodel.h" #include "imagelocationmodel.h" #include "imagetimemodel.h" #include "imagefoldermodel.h" #include "sortmodel.h" #include "allimagesmodel.h" #include "imagelistmodel.h" #include "notificationmanager.h" #include "types.h" #include "roles.h" #include "imagedocument.h" #include void QmlPlugins::initializeEngine(QQmlEngine *, const char *) { } void QmlPlugins::registerTypes(const char *uri) { +#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) qmlRegisterType (); +#else + qmlRegisterAnonymousType(uri, 0); +#endif qmlRegisterType (uri, 0, 1, "TagModel"); qmlRegisterType (uri, 0, 1, "ImageLocationModel"); qmlRegisterType (uri, 0, 1, "ImageTimeModel"); qmlRegisterType (uri, 0, 1, "ImageFolderModel"); qmlRegisterType (uri, 0, 1, "AllImagesModel"); qmlRegisterType (uri, 0, 1, "SortModel"); qmlRegisterType (uri, 0, 1, "ImageListModel"); qmlRegisterType (uri, 0, 1, "ImageDocument"); qmlRegisterType (uri, 0, 1, "NotificationManager"); qmlRegisterUncreatableType(uri, 0, 1, "Types", "Cannot instantiate the Types class"); qmlRegisterUncreatableType(uri, 0, 1, "Roles", "Cannot instantiate the Roles class"); } diff --git a/src/qmlplugins.h b/src/qmlplugins.h index 173bc92..5f0d6bb 100644 --- a/src/qmlplugins.h +++ b/src/qmlplugins.h @@ -1,37 +1,37 @@ /* * Copyright (C) 2013 Vishesh Handa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * */ #ifndef _QML_PLUGINS_H #define _QML_PLUGINS_H #include class QmlPlugins : public QQmlExtensionPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") public: - virtual void initializeEngine(QQmlEngine *engine, const char *uri); - virtual void registerTypes(const char *uri); + void initializeEngine(QQmlEngine *engine, const char *uri) override; + void registerTypes(const char *uri) override; }; #endif diff --git a/src/sortmodel.cpp b/src/sortmodel.cpp index 5070ee8..f12d3b0 100644 --- a/src/sortmodel.cpp +++ b/src/sortmodel.cpp @@ -1,330 +1,330 @@ /* * Copyright (C) 2017 Atul Sharma * Copyright (C) 2014 Vishesh Handa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "sortmodel.h" #include "types.h" #include "roles.h" #include #include #include #include #include using namespace Jungle; SortModel::SortModel(QObject* parent) : QSortFilterProxyModel(parent), m_screenshotSize(256, 256), m_containImages(false) { setSortLocaleAware(true); sort(0); m_selectionModel = new QItemSelectionModel(this); m_previewTimer = new QTimer(this); m_previewTimer->setSingleShot(true); connect(m_previewTimer, &QTimer::timeout, this, &SortModel::delayedPreview); connect(this, &SortModel::rowsInserted, this, [this] (const QModelIndex &parent, int first, int last) { Q_UNUSED(parent) for (int i = first; i <= last; i++) { if (Types::Image == data(index(i, 0, QModelIndex()), Roles::ItemTypeRole).toInt() && m_containImages == false) { setContainImages(true); break; } } }); connect(this, &SortModel::sourceModelChanged, this, [this] () { if (!sourceModel()) { return; } for (int i = 0; i <= sourceModel()->rowCount(); i++) { if (Types::Image == sourceModel()->data(sourceModel()->index(i, 0, QModelIndex()), Roles::ItemTypeRole).toInt() && m_containImages == false) { setContainImages(true); break; } } }); //using the same cache of the engine, they index both by url m_imageCache = new KImageCache(QStringLiteral("org.kde.koko"), 10485760); } SortModel::~SortModel() { delete m_imageCache; } void SortModel::setContainImages(bool value) { m_containImages = value; emit containImagesChanged(); } QByteArray SortModel::sortRoleName() const { int role = sortRole(); return roleNames().value(role); } void SortModel::setSortRoleName(const QByteArray& name) { if (!sourceModel()) { m_sortRoleName = name; return; } const QHash roles = sourceModel()->roleNames(); for (auto it = roles.begin(); it != roles.end(); it++) { if (it.value() == name) { setSortRole(it.key()); return; } } qDebug() << "Sort role" << name << "not found"; } QHash SortModel::roleNames() const { QHash hash = sourceModel()->roleNames(); hash.insert( Roles::SelectedRole, "selected"); hash.insert( Roles::Thumbnail, "thumbnail"); hash.insert( Roles::SourceIndex, "sourceIndex"); return hash; } QVariant SortModel::data(const QModelIndex& index, int role) const { if( !index.isValid()) { return QVariant(); } switch( role) { case Roles::SelectedRole: { return m_selectionModel->isSelected(index); } - + case Roles::Thumbnail: { QUrl thumbnailSource(QString( /*"file://" + */data( index, Roles::ImageUrlRole).toString())); KFileItem item( thumbnailSource, QString() ); QImage preview = QImage(m_screenshotSize, QImage::Format_ARGB32_Premultiplied); if (m_imageCache->findImage(item.url().toString(), &preview)) { return preview; } m_previewTimer->start(100); const_cast(this)->m_filesToPreview[item.url()] = QPersistentModelIndex(index); } - + case Roles::SourceIndex: { return mapToSource(index).row(); } } return QSortFilterProxyModel::data(index, role); } bool SortModel::lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const { if(sourceModel()) { if( (sourceModel()->data(source_left, Roles::ItemTypeRole) == Types::Folder && sourceModel()-> data(source_right, Roles::ItemTypeRole) == Types::Folder ) || (sourceModel()->data(source_left, Roles::ItemTypeRole) != Types::Folder && sourceModel()-> data(source_right, Roles::ItemTypeRole) != Types::Folder)) { return QSortFilterProxyModel::lessThan(source_left, source_right); } else if( sourceModel()->data(source_left, Roles::ItemTypeRole) == Types::Folder && sourceModel()->data(source_right, Roles::ItemTypeRole) != Types::Folder) { return true; } else { return false; } } return false; } void SortModel::setSourceModel(QAbstractItemModel* sourceModel) { QSortFilterProxyModel::setSourceModel(sourceModel); if (!m_sortRoleName.isEmpty()) { setSortRoleName(m_sortRoleName); m_sortRoleName.clear(); } } bool SortModel::containImages() { return m_containImages; } bool SortModel::hasSelectedImages() { return m_selectionModel->hasSelection(); } void SortModel::setSelected(int indexValue) { if( indexValue < 0) return; QModelIndex index = QSortFilterProxyModel::index( indexValue, 0); m_selectionModel->select( index, QItemSelectionModel::Select ); emit dataChanged( index, index); emit selectedImagesChanged(); } void SortModel::toggleSelected(int indexValue ) { if( indexValue < 0) return; QModelIndex index = QSortFilterProxyModel::index( indexValue, 0); m_selectionModel->select( index, QItemSelectionModel::Toggle ); emit dataChanged( index, index); emit selectedImagesChanged(); } void SortModel::clearSelections() { if(m_selectionModel->hasSelection()) { QModelIndexList selectedIndex = m_selectionModel->selectedIndexes(); m_selectionModel->clear(); foreach(QModelIndex indexValue, selectedIndex) { emit dataChanged( indexValue, indexValue); } } emit selectedImagesChanged(); } void SortModel::selectAll() { QModelIndexList indexList; for( int row=0; rowhasSelection()) { m_selectionModel->clear(); } foreach(QModelIndex index, indexList) { if( Types::Image == data(index, Roles::ItemTypeRole)) m_selectionModel->select( index, QItemSelectionModel::Select); } emit dataChanged( index( 0, 0, QModelIndex()), index( rowCount()-1, 0, QModelIndex()) ); emit selectedImagesChanged(); } void SortModel::deleteSelection() { QList filesToDelete; foreach(QModelIndex index, m_selectionModel->selectedIndexes()) { filesToDelete << data( index, Roles::ImageUrlRole).toUrl(); } auto trashJob = KIO::trash(filesToDelete); trashJob->exec(); } int SortModel::proxyIndex(const int& indexValue) { if( sourceModel() ) { return mapFromSource( sourceModel()->index( indexValue, 0, QModelIndex())).row(); } return -1; } int SortModel::sourceIndex(const int& indexValue) { return mapToSource( index(indexValue, 0, QModelIndex())).row(); } QJsonArray SortModel::selectedImages() { QJsonArray arr; foreach( QModelIndex index, m_selectionModel->selectedIndexes()) { arr.push_back( QJsonValue (data( index, Roles::ImageUrlRole).toString())); } return arr; } void SortModel::delayedPreview() { QHash::const_iterator i = m_filesToPreview.constBegin(); KFileItemList list; while (i != m_filesToPreview.constEnd()) { QUrl file = i.key(); QPersistentModelIndex index = i.value(); if (!m_previewJobs.contains(file) && file.isValid()) { list.append(KFileItem(file, QString(), 0)); m_previewJobs.insert(file, QPersistentModelIndex(index)); } ++i; } if (list.size() > 0) { KIO::PreviewJob* job = KIO::filePreview(list, m_screenshotSize); job->setIgnoreMaximumSize(true); // qDebug() << "Created job" << job; connect(job, &KIO::PreviewJob::gotPreview, this, &SortModel::showPreview); connect(job, &KIO::PreviewJob::failed, this, &SortModel::previewFailed); } m_filesToPreview.clear(); } void SortModel::showPreview(const KFileItem &item, const QPixmap &preview) { QPersistentModelIndex index = m_previewJobs.value(item.url()); m_previewJobs.remove(item.url()); if (!index.isValid()) { return; } m_imageCache->insertImage(item.url().toString(), preview.toImage()); //qDebug() << "preview size:" << preview.size(); emit dataChanged(index, index); } void SortModel::previewFailed(const KFileItem &item) { m_previewJobs.remove(item.url()); } diff --git a/src/sortmodel.h b/src/sortmodel.h index 24c12a9..8fefbab 100644 --- a/src/sortmodel.h +++ b/src/sortmodel.h @@ -1,88 +1,88 @@ /* * Copyright (C) 2017 Atul Sharma * Copyright (C) 2014 Vishesh Handa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef JUNGLE_SORTMODEL_H #define JUNGLE_SORTMODEL_H #include #include #include #include #include #include #include #include namespace Jungle { class SortModel : public QSortFilterProxyModel { Q_OBJECT Q_PROPERTY(QByteArray sortRoleName READ sortRoleName WRITE setSortRoleName) Q_PROPERTY(bool containImages READ containImages WRITE setContainImages NOTIFY containImagesChanged) Q_PROPERTY(bool hasSelectedImages READ hasSelectedImages NOTIFY selectedImagesChanged) public: explicit SortModel(QObject* parent = 0); virtual ~SortModel(); QByteArray sortRoleName() const; void setSortRoleName(const QByteArray& name); - QHash roleNames() const; - QVariant data(const QModelIndex & index, int role) const; + QHash roleNames() const override; + QVariant data(const QModelIndex & index, int role) const override; bool lessThan(const QModelIndex & source_left, const QModelIndex & source_right) const override; - virtual void setSourceModel(QAbstractItemModel* sourceModel); + void setSourceModel(QAbstractItemModel* sourceModel) override; bool containImages(); bool hasSelectedImages(); Q_INVOKABLE void setSelected( int indexValue); Q_INVOKABLE void toggleSelected( int indexValue); Q_INVOKABLE void clearSelections(); Q_INVOKABLE void selectAll(); Q_INVOKABLE void deleteSelection(); Q_INVOKABLE int proxyIndex(const int &indexValue); Q_INVOKABLE int sourceIndex(const int &indexValue); Q_INVOKABLE QJsonArray selectedImages(); protected Q_SLOTS: void setContainImages(bool); void showPreview(const KFileItem &item, const QPixmap &preview); void previewFailed(const KFileItem &item); void delayedPreview(); signals: void containImagesChanged(); void selectedImagesChanged(); private: QByteArray m_sortRoleName; QItemSelectionModel *m_selectionModel; QTimer *m_previewTimer; QHash m_filesToPreview; QSize m_screenshotSize; QHash m_previewJobs; KImageCache* m_imageCache; bool m_containImages; }; } #endif // JUNGLE_SORTMODEL_H diff --git a/src/tagmodel.h b/src/tagmodel.h index ff16f8a..ea3fc26 100644 --- a/src/tagmodel.h +++ b/src/tagmodel.h @@ -1,62 +1,62 @@ /* * Copyright (C) 2014 Vishesh Handa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef TAGMODEL_H #define TAGMODEL_H #include class TagModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(QStringList tags READ tags WRITE setTags NOTIFY tagsChanged) Q_PROPERTY(QStringList colors READ colors NOTIFY colorsChanged) public: explicit TagModel(QObject* parent = 0); enum Roles { ColorRole = Qt::UserRole + 1 }; - virtual QHash roleNames() const; - virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; - virtual int rowCount(const QModelIndex& parent = QModelIndex()) const; + QHash roleNames() const override; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + int rowCount(const QModelIndex& parent = QModelIndex()) const override; signals: void tagsChanged(); void colorsChanged(); public slots: - virtual bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()); + bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()) override; QStringList tags() const; void setTags(const QStringList& tags); void addTag(const QString& tag); /** * Return the colors of all the tags */ QStringList colors() const; private: QStringList m_tags; }; #endif // TAGMODEL_H