Added enablePreview property to declarative Mode
[harmattan/cameraplus] / src / postcapturemodel.cpp
index 80d7f3a..f6d6a8b 100644 (file)
  */
 
 #include "postcapturemodel.h"
-#include <QSparqlConnection>
-#include <QSparqlQuery>
-#include <QSparqlResult>
-#include <QSparqlError>
-#include <QDeclarativeInfo>
+#include <QDir>
 #include <QDateTime>
-#include <QDBusConnection>
-#include <QStringList>
-#include <QDBusMetaType>
-#include <QDBusArgument>
-
-#define DRIVER "QTRACKER_DIRECT"
-#define QUERY "SELECT rdf:type(?urn) AS ?type nie:url(?urn) AS ?url nie:contentCreated(?urn) AS ?created nie:title(?urn) AS ?title nfo:fileName(?urn) AS ?filename nie:mimeType(?urn) AS ?mimetype tracker:available(?urn) AS ?available nfo:fileLastModified(?urn) as ?lastmod tracker:id(?urn) AS ?trackerid (EXISTS { ?urn nao:hasTag nao:predefined-tag-favorite }) AS ?favorite WHERE { ?urn nfo:equipment ?:equipment . {?urn a nfo:Video} UNION {?urn a nfo:Image}} ORDER BY DESC(?created)"
-
-#define UPDATE_QUERY "SELECT rdf:type(?urn) AS ?type nie:url(?urn) AS ?url nie:contentCreated(?urn) AS ?created nie:title(?urn) AS ?title nfo:fileName(?urn) AS ?filename nie:mimeType(?urn) AS ?mimetype tracker:available(?urn) AS ?available nfo:fileLastModified(?urn) as ?lastmod tracker:id(?urn) AS ?trackerid (EXISTS { ?urn nao:hasTag nao:predefined-tag-favorite }) AS ?favorite WHERE {?urn a nfo:Visual . FILTER (tracker:id(?urn) IN (%1)) }"
+#include <QUrl>
+#include <QStandardItem>
+#include <dirent.h>
+#include <sys/types.h>
+#if defined(QT4)
+#include <QDeclarativeInfo>
+#elif defined(QT5)
+#include <QQmlInfo>
+#endif
 
-#define TRACKER_SERVICE "org.freedesktop.Tracker1"
-#define TRACKER_RESOURCE_PATH "/org/freedesktop/Tracker1/Resources"
-#define TRACKER_RESOURCE_INTERFACE "org.freedesktop.Tracker1.Resources"
-#define TRACKER_RESOURCE_SIGNAL "GraphUpdated"
-#define PHOTO_CLASS "http://www.tracker-project.org/temp/nmm#Photo"
-#define VIDEO_CLASS "http://www.tracker-project.org/temp/nmm#Video"
-#define TRACKER_RESOURCE_SIGNAL_SIGNATURE "sa(iiii)a(iiii)"
+static QHash<QString, QString> m_mime;
 
-class Quad {
+class PostCaptureModelItem : public QStandardItem {
 public:
-  int graph;
-  int subject;
-  int predicate;
-  int object;
-};
-
-Q_DECLARE_METATYPE(Quad);
-Q_DECLARE_METATYPE(QList<Quad>);
-
-QDBusArgument& operator<<(QDBusArgument& argument, const Quad& t) {
-  argument.beginStructure();
-  argument << t.graph << t.subject << t.predicate << t.object;
-  argument.endStructure();
-  return argument;
-}
-
-const QDBusArgument& operator>>(const QDBusArgument& argument, Quad& t) {
-  argument.beginStructure();
-  argument >> t.graph >> t.subject >> t.predicate >> t.object;
-  argument.endStructure();
-  return argument;
-}
-
-PostCaptureModel::PostCaptureModel(QObject *parent) :
-  QAbstractListModel(parent),
-  m_connection(0),
-  m_connected(false) {
-
-  QHash<int, QByteArray> roles;
-  roles.insert(Item, "item");
-  setRoleNames(roles);
-
-  qDBusRegisterMetaType<Quad>();
-  qDBusRegisterMetaType<QList<Quad> >();
-}
-
-PostCaptureModel::~PostCaptureModel() {
-  qDeleteAll(m_items);
-  m_items.clear();
-
-  delete m_connection; m_connection = 0;
-}
-
-void PostCaptureModel::classBegin() {
-
-}
+  PostCaptureModelItem(const QString& path, const char *file) :
+    m_dir(path),
+    m_name(QString::fromLocal8Bit(file)),
+    m_info(0) {
 
-void PostCaptureModel::componentComplete() {
-
-}
-
-void PostCaptureModel::reload() {
-  delete m_connection; m_connection = 0;
-
-  if (!m_items.isEmpty()) {
-    beginRemoveRows(QModelIndex(), 0, m_items.size() - 1);
-    qDeleteAll(m_items);
-    m_items.clear();
-    endRemoveRows();
   }
 
-  m_connection = new QSparqlConnection(DRIVER, QSparqlConnectionOptions(), this);
-  if (!m_connection->isValid()) {
-    emit error(tr("Failed to create SPARQL connection"));
-    return;
+  ~PostCaptureModelItem() {
+    if (m_info) {
+      delete m_info;
+      m_info = 0;
+    }
   }
 
-  QString equipment = QString("urn:equipment:%1:%2:").arg(m_manufacturer).arg(m_model);
-
-  QSparqlQuery q(QUERY, QSparqlQuery::SelectStatement);
-  q.bindValue("equipment", equipment);
-  exec(q);
-
-  if (!m_connected) {
-    const char *slot = SLOT(graphUpdated(const QString&,
-                                        const QList<Quad>&,
-                                        const QList<Quad>&));
-    m_connected = QDBusConnection::sessionBus().connect(TRACKER_SERVICE, TRACKER_RESOURCE_PATH,
-                                                       TRACKER_RESOURCE_INTERFACE,
-                                                       TRACKER_RESOURCE_SIGNAL,
-                                                       TRACKER_RESOURCE_SIGNAL_SIGNATURE,
-                                                       this, slot);
+  int type() const {
+    return UserType;
   }
 
-  if (!m_connected) {
-    qmlInfo(this) << "Failed to connect to tracker " << TRACKER_RESOURCE_SIGNAL;
-  }
-}
+  const QFileInfo *info() const {
+    if (!m_info) {
+      m_info = new QFileInfo(path());
+    }
 
-void PostCaptureModel::exec(QSparqlQuery& query) {
-  if (!m_connection) {
-    qWarning() << "No connection to query";
-    return;
+    return m_info;
   }
 
-  QSparqlResult *result = m_connection->exec(query);
+  QString path() const {
+    return QString("%1%2%3").arg(m_dir).arg(QDir::separator()).arg(m_name);
+  }
 
-  if (result->hasError()) {
-    QSparqlError error = result->lastError();
-    qmlInfo(this) << "Error executing SPARQL query" << error.message();
+  QVariant data (int role = Qt::UserRole + 1) const {
+    switch (role) {
+    case PostCaptureModel::UrlRole:
+      return QUrl::fromLocalFile(path());
 
-    delete result;
+    case PostCaptureModel::TitleRole:
+      return info()->baseName();
 
-    emit PostCaptureModel::error(tr("Failed to query tracker"));
-  }
+    case PostCaptureModel::MimeTypeRole:
+      if (m_mime.contains(info()->completeSuffix())) {
+       return m_mime[info()->completeSuffix()];
+      }
 
-  if (result) {
-    QObject::connect(result, SIGNAL(dataReady(int)), this, SLOT(dataReady(int)));
-    QObject::connect(result, SIGNAL(finished()), result, SLOT(deleteLater()));
-  }
-}
+      return QString();
 
-int PostCaptureModel::rowCount(const QModelIndex& parent) const {
-  if (parent.isValid()) {
-    return 0;
-  }
+    case PostCaptureModel::CreatedRole:
+      return info()->created().toString();
 
-  return m_items.size();
-}
+    case PostCaptureModel::FileNameRole:
+      return info()->fileName();
 
-QVariant PostCaptureModel::data(const QModelIndex& index, int role) const {
-  if (!index.isValid() || index.row() < 0 || index.row() >= m_items.size()) {
-    return QVariant();
+    default:
+      return QVariant();
+    }
   }
 
-  if (role == Item) {
-    return QVariant::fromValue(dynamic_cast<QObject *>(m_items[index.row()]));
-  }
+private:
+  QString m_dir;
+  QString m_name;
+  mutable QFileInfo *m_info;
+};
 
-  return QVariant();
+static bool lessThan(const QStandardItem *a1, const QStandardItem *a2) {
+  // we sort descending
+  return dynamic_cast<const PostCaptureModelItem *>(a1)->info()->created() >
+    dynamic_cast<const PostCaptureModelItem *>(a2)->info()->created();
 }
 
-QString PostCaptureModel::manufacturer() const {
-  return m_manufacturer;
-}
+PostCaptureModel::PostCaptureModel(QObject *parent) :
+  QStandardItemModel(parent) {
 
-void PostCaptureModel::setManufacturer(const QString& manufacturer) {
-  if (m_manufacturer != manufacturer) {
-    m_manufacturer = manufacturer;
-    emit manufacturerChanged();
-  }
-}
+  QHash<int, QByteArray> roles;
+  roles.insert(UrlRole, "url");
+  roles.insert(TitleRole, "title");
+  roles.insert(MimeTypeRole, "mimeType");
+  roles.insert(CreatedRole, "created");
+  roles.insert(FileNameRole, "fileName");
 
-QString PostCaptureModel::model() const {
-  return m_model;
-}
+  setRoleNames(roles);
 
-void PostCaptureModel::setModel(const QString& model) {
-  if (m_model != model) {
-    m_model = model;
-    emit modelChanged();
+  if (m_mime.isEmpty()) {
+    m_mime.insert("jpg", "image/jpeg");
+    m_mime.insert("png", "image/png");
+    m_mime.insert("mp4", "video/mp4");
+    m_mime.insert("avi", "video/x-msvideo");
   }
 }
 
-void PostCaptureModel::dataReady(int totalCount) {
-  Q_UNUSED(totalCount);
-
-  QSparqlResult *result = dynamic_cast<QSparqlResult *>(sender());
-  if (!result) {
-    return;
-  }
+PostCaptureModel::~PostCaptureModel() {
 
-  while (result->next()) {
-    addRow(new PostCaptureModelItem(result->current(), this));
-  }
+}
 
-  result->previous();
+QString PostCaptureModel::imagePath() const {
+  return m_imagePath;
 }
 
-void PostCaptureModel::addRow(PostCaptureModelItem *item) {
-  if (m_hash.contains(item->trackerId())) {
-    m_hash[item->trackerId()]->update(item);
-    delete item;
-    return;
+void PostCaptureModel::setImagePath(const QString& path) {
+  if (m_imagePath != path) {
+    m_imagePath = path;
+    emit imagePathChanged();
   }
-
-  beginInsertRows(QModelIndex(), m_items.size(), m_items.size());
-  m_items << item;
-  m_hash.insert(item->trackerId(), item);
-
-  endInsertRows();
 }
 
-void PostCaptureModel::remove(QObject *item) {
-  PostCaptureModelItem *i = dynamic_cast<PostCaptureModelItem *>(item);
-  if (!i) {
-    qmlInfo(this) << "Invalid item to remove";
-    return;
-  }
+QString PostCaptureModel::videoPath() const {
+  return m_videoPath;
+}
 
-  int index = m_items.indexOf(i);
-  if (index == -1) {
-    qmlInfo(this) << "Item" << i->trackerId() << "not found in model";
-    return;
+void PostCaptureModel::setVideoPath(const QString& path) {
+  if (m_videoPath != path) {
+    m_videoPath = path;
+    emit videoPathChanged();
   }
-
-  beginRemoveRows(QModelIndex(), index, index);
-  m_items.takeAt(index);
-  m_hash.remove(i->trackerId());
-  endRemoveRows();
-
-  i->deleteLater();
 }
 
-void PostCaptureModel::graphUpdated(const QString& className, const QList<Quad>& deleted,
-                                   const QList<Quad>& inserted) {
-
-  // We will just assume tracker:available has changed and that's it.
-  // We are not really interested in the rest of properties.
+void PostCaptureModel::loadDir(const QDir& dir, QList<QStandardItem *>& out) {
+  QString path = dir.canonicalPath();
 
-  if (!(className == QLatin1String(PHOTO_CLASS) || className == QLatin1String(VIDEO_CLASS))) {
+  DIR *d = opendir(path.toLocal8Bit().constData());
+  if (!d) {
+    qmlInfo(this) << "Failed to open dir" << path;
     return;
   }
 
-  QList<int> items;
-
-  for (int x = 0; x < deleted.size(); x++) {
-    Quad q = deleted[x];
-    if (m_hash.contains(q.subject) && items.indexOf(q.subject) == -1) {
-      items << q.subject;
+  while (true) {
+    struct dirent *entry = readdir(d);
+    if (!entry) {
+      break;
     }
-  }
 
-  for (int x = 0; x < inserted.size(); x++) {
-    Quad q = inserted[x];
-    if (m_hash.contains(q.subject) && items.indexOf(q.subject) == -1) {
-      items << q.subject;
+    if (QLatin1String(".") == entry->d_name || QLatin1String("..") == entry->d_name) {
+      continue;
     }
-  }
 
-  for (int x = 0; x < items.size(); x++) {
-    QString query = QString(UPDATE_QUERY).arg(items[x]);
-    QSparqlQuery q(query, QSparqlQuery::SelectStatement);
-
-    exec(q);
-  }
-}
-
-PostCaptureModelItem::PostCaptureModelItem(const QSparqlResultRow& row, QObject *parent) :
-  QObject(parent) {
+    if (!(entry->d_type == DT_LNK || entry->d_type == DT_REG)) {
+      continue;
+    }
 
-  for (int x = 0; x < row.count(); x++) {
-    QSparqlBinding b = row.binding(x);
-    m_data.insert(b.name(), b.value());
+    out << new PostCaptureModelItem(path, entry->d_name);
   }
-}
 
-QString PostCaptureModelItem::type() const {
-  return value("type").toString();
+  closedir(d);
 }
 
-QUrl PostCaptureModelItem::url() const {
-  return value("url").toUrl();
-}
-
-QString PostCaptureModelItem::created() const {
-  return formatDateTime(value("created").toDateTime());
-}
+void PostCaptureModel::reload() {
+  QList<QStandardItem *> files;
 
-QString PostCaptureModelItem::title() const {
-  return value("title").toString();
-}
+  QDir images(m_imagePath);
+  QDir videos(m_videoPath);
 
-QString PostCaptureModelItem::fileName() const {
-  return value("filename").toString();
-}
+  loadDir(images, files);
 
-QString PostCaptureModelItem::mimeType() const {
-  return value("mimetype").toString();
-}
+  if (images.canonicalPath() != videos.canonicalPath()) {
+    loadDir(videos, files);
+  }
 
-bool PostCaptureModelItem::available() const {
-  return value("available", false).toBool();
-}
+  qSort(files.begin(), files.end(), lessThan);
 
-QString PostCaptureModelItem::lastModified() const {
-  return formatDateTime(value("lastmod").toDateTime());
+  invisibleRootItem()->appendRows(files);
 }
 
-unsigned PostCaptureModelItem::trackerId() const {
-  return value("trackerid").toUInt();
+void PostCaptureModel::clear() {
+  QStandardItemModel::clear();
 }
 
-bool PostCaptureModelItem::favorite() const {
-  return value("favorite", false).toBool();
-}
+void PostCaptureModel::remove(const QUrl& file) {
+  QString path(file.toLocalFile());
 
-void PostCaptureModelItem::setFavorite(bool add) {
-  if (favorite() != add) {
-    m_data["favorite"] = add;
+  int count = invisibleRootItem()->rowCount();
 
-    emit favoriteChanged();
+  for (int x = 0; x < count; x++) {
+    if (dynamic_cast<PostCaptureModelItem *>(invisibleRootItem()->child(x))->path() == path) {
+      invisibleRootItem()->removeRow(x);
+      return;
+    }
   }
 }
 
-QString PostCaptureModelItem::formatDateTime(const QDateTime& dt) const {
-  return dt.toString();
-}
-
-void PostCaptureModelItem::update(PostCaptureModelItem *other) {
-  // We will only update available, favorite and title:
-#if 0
-  qDebug() << "i" << trackerId() << other->trackerId()  << "\n"
-          << "a" << available() << other->available() << "\n"
-          << "t" << title() << other->title() << "\n"
-          << "f" << favorite() << other->favorite();
-#endif
-
-  if (available() != other->available()) {
-    m_data["available"] = other->available();
-    emit availableChanged();
-  }
-
-  if (title() != other->title()) {
-    m_data["title"] = other->title();
-    emit titleChanged();
-  }
-
-  if (favorite() != other->favorite()) {
-    m_data["favorite"] = other->favorite();
-    emit favoriteChanged();
-  }
+#if defined(QT5)
+QHash<int, QByteArray> PostCaptureModel::roleNames() const {
+  return m_roles;
 }
 
-QVariant PostCaptureModelItem::value(const QString& id, const QVariant& def) const {
-  return m_data.contains(id) ? m_data[id] : def;
+void PostCaptureModel::setRoleNames(const QHash<int, QByteArray>& roles) {
+  m_roles = roles;
 }
+#endif