aboutsummaryrefslogtreecommitdiff
path: root/notebookmodel.cc
diff options
context:
space:
mode:
Diffstat (limited to 'notebookmodel.cc')
-rw-r--r--notebookmodel.cc323
1 files changed, 323 insertions, 0 deletions
diff --git a/notebookmodel.cc b/notebookmodel.cc
new file mode 100644
index 0000000..1d8228c
--- /dev/null
+++ b/notebookmodel.cc
@@ -0,0 +1,323 @@
+#include <QtCore/QDebug>
+#include <QtGui/QApplication>
+#include <QtGui/QIcon>
+#include <QtGui/QDesktopServices>
+#include <QtGui/QStyle>
+#include "notebookmodel.h"
+
+#define NUM_COLUMNS 3
+#define PEN_INDEX_ID 0xFFFFFFFFU
+
+NotebookModel::NotebookModel(QObject *parent) :
+ QAbstractItemModel(parent),
+ _dataDir(QDesktopServices::storageLocation(QDesktopServices::DataLocation)),
+ _watcher()
+{
+ if (!_dataDir.exists()) {
+ if (!_dataDir.mkpath(".")) {
+ qWarning() << "Cannot create my data directory:" << _dataDir.absolutePath();
+ }
+ }
+ _watcher.addPath(_dataDir.absolutePath());
+ connect(&_watcher, SIGNAL(directoryChanged(QString)), SLOT(handleChangedDirectory(QString)));
+ refresh();
+}
+
+QString NotebookModel::penDirectory(const QString &name) const
+{
+ return _dataDir.filePath(name + ".pen");
+}
+
+QString NotebookModel::notebookDirectory(const QString &penName, const QString &nbName) const
+{
+ return _dataDir.filePath(penName + ".pen" + "/" + nbName + ".afd");
+}
+
+QString NotebookModel::notebookDirectory(const QModelIndex &index) const
+{
+ if (!index.isValid()) return QString();
+ quint32 id = index.internalId();
+ if (id != PEN_INDEX_ID) {
+ const QString &penName = _pens[id];
+ const QStringList &notebooks = _notebooks[penName];
+ const QString &notebookName = notebooks.at(index.row());
+ return notebookDirectory(penName, notebookName);
+ }
+ return QString();
+}
+
+QVariant NotebookModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid()) return QVariant();
+ quint32 id = index.internalId();
+ if (id == PEN_INDEX_ID) {
+ int penIndex = index.row();
+ if (penIndex < 0 || penIndex >= _pens.size()) return QVariant();
+ switch (role) {
+ case Qt::DisplayRole:
+ switch (index.column()) {
+ case 0:
+ return _pens[penIndex];
+ }
+ break;
+ }
+ } else {
+ const QString &penName = _pens[id];
+ const QStringList &notebooks = _notebooks[penName];
+ const QString &notebookName = notebooks.at(index.row());
+ switch (role) {
+ case Qt::DisplayRole:
+ switch (index.column()) {
+ case 0:
+ return notebooks.at(index.row());
+ case 1:
+ return 0;
+ }
+ break;
+ case Qt::DecorationRole:
+ switch (index.column()) {
+ case 0:
+ return getNotebookIcon(penName, notebookName);
+ case 1:
+ return QVariant();
+ case 2:
+ if (isNotebookLocked(penName, notebookName)) {
+ return QApplication::style()->standardIcon(QStyle::SP_BrowserReload);
+ }
+ }
+ case Qt::TextAlignmentRole:
+ switch (index.column()) {
+ case 0:
+ return Qt::AlignLeft;
+ case 1:
+ case 2:
+ return Qt::AlignCenter;
+ }
+ }
+ }
+ return QVariant();
+}
+
+Qt::ItemFlags NotebookModel::flags(const QModelIndex &index) const
+{
+ switch (index.column()) {
+ case 0:
+ return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
+ default:
+ return Qt::ItemIsSelectable;
+ }
+}
+
+QModelIndex NotebookModel::index(int row, int column, const QModelIndex &parent) const
+{
+ if (parent.isValid()) {
+ quint32 id = parent.internalId();
+ if (id == PEN_INDEX_ID) {
+ // Pen index
+ const quint32 penIndex = parent.row();
+ const QString &penName = _pens.at(penIndex);
+ const QStringList &notebooks = _notebooks[penName];
+ if (row >= 0 && row < notebooks.size() && column >= 0 && column < NUM_COLUMNS) {
+ return createIndex(row, column, penIndex);
+ } else {
+ return QModelIndex();
+ }
+ } else {
+ // Notebook index
+ return QModelIndex(); // Nothing inside notebooks
+ }
+ } else if (row >= 0 && row < _pens.size() && column >= 0 && column < NUM_COLUMNS) {
+ return createIndex(row, column, PEN_INDEX_ID);
+ } else {
+ return QModelIndex();
+ }
+}
+
+QModelIndex NotebookModel::parent(const QModelIndex &child) const
+{
+ if (child.isValid()) {
+ quint32 id = child.internalId();
+ if (id == PEN_INDEX_ID) {
+ return QModelIndex(); // Pens have no parent
+ } else {
+ return createIndex(id, 0, PEN_INDEX_ID);
+ }
+ } else {
+ return QModelIndex();
+ }
+}
+
+int NotebookModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid()) {
+ quint32 id = parent.internalId();
+ if (id == PEN_INDEX_ID) {
+ const quint32 penIndex = parent.row();
+ const QString &penName = _pens.at(penIndex);
+ const QStringList &notebooks = _notebooks[penName];
+ return notebooks.size();
+ } else {
+ return 0; // Nothing inside notebooks
+ }
+ } else {
+ return _pens.size();
+ }
+}
+
+int NotebookModel::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return NUM_COLUMNS;
+}
+
+void NotebookModel::refresh()
+{
+ QStringList pens = _dataDir.entryList(QStringList("*.pen"), QDir::Dirs, QDir::Name);
+ for (int i = 0; i < pens.size(); i++) {
+ pens[i].chop(4);
+ }
+
+ int i = 0, j = 0;
+ while (i < _pens.size() && j < pens.size()) {
+ int comp = QString::compare(_pens[i], pens[j], Qt::CaseInsensitive);
+ if (comp == 0) {
+ ++i;
+ ++j;
+ } else if (comp > 0) { /* _pens[i] > pens[j] */
+ beginInsertRows(QModelIndex(), i, i);
+ _pens.insert(i, pens[j]);
+ endInsertRows();
+ ++i;
+ ++j;
+ } else { /* _pens[i] < pens[j] */
+ beginRemoveRows(QModelIndex(), i, i);
+ _notebooks.remove(_pens[i]);
+ _pens.removeAt(i);
+ endRemoveRows();
+ }
+ }
+ if (i < _pens.size()) {
+ Q_ASSERT(j == pens.size());
+ beginRemoveRows(QModelIndex(), i, _pens.size() - 1);
+ while (i < _pens.size()) {
+ _notebooks.remove(_pens[i]);
+ _pens.removeAt(i);
+ }
+ endRemoveRows();
+ } else if (j < pens.size()) {
+ Q_ASSERT(i == _pens.size());
+ beginInsertRows(QModelIndex(), i, i + (pens.size() - j));
+ _pens.append(pens.mid(j));
+ endInsertRows();
+ }
+
+ foreach (const QString &pen, _pens) {
+ refreshPen(pen);
+ }
+}
+
+void NotebookModel::refreshPen(const QString &name)
+{
+ QDir penDir(penDirectory(name));
+ if (!penDir.exists()) {
+ return;
+ }
+
+ _watcher.addPath(penDir.canonicalPath());
+
+ QStringList &curNotebooks = _notebooks[name];
+ QStringList diskNotebooks = penDir.entryList(QStringList("*.afd"), QDir::Dirs, QDir::Name);
+ for (int i = 0; i < diskNotebooks.size(); i++) {
+ diskNotebooks[i].chop(4);
+ }
+
+ QModelIndex penIndex = index(indexOfPen(name), 0, QModelIndex());
+
+ int i = 0, j = 0;
+ while (i < curNotebooks.size() && j < diskNotebooks.size()) {
+ int comp = QString::compare(curNotebooks[i], diskNotebooks[j], Qt::CaseInsensitive);
+ if (comp == 0) {
+ ++i;
+ ++j;
+ } else if (comp > 0) { /* _pens[i] > pens[j] */
+ beginInsertRows(penIndex, i, i);
+ curNotebooks.insert(i, diskNotebooks[j]);
+ endInsertRows();
+ ++i;
+ ++j;
+ } else { /* _pens[i] < pens[j] */
+ beginRemoveRows(penIndex, i, i);
+ curNotebooks.removeAt(i);
+ endRemoveRows();
+ }
+ }
+ if (i < curNotebooks.size()) {
+ Q_ASSERT(j == diskNotebooks.size());
+ beginRemoveRows(penIndex, i, curNotebooks.size() - 1);
+ curNotebooks.erase(curNotebooks.begin() + i, curNotebooks.end());
+ endRemoveRows();
+ } else if (j < diskNotebooks.size()) {
+ Q_ASSERT(i == curNotebooks.size());
+ beginInsertRows(penIndex, i, i + (diskNotebooks.size() - j));
+ curNotebooks.append(diskNotebooks.mid(j));
+ endInsertRows();
+ }
+
+ qDebug() << "Found" << curNotebooks.size() << "notebook for pen" << name;
+}
+
+int NotebookModel::indexOfPen(const QString &name)
+{
+ QStringList::const_iterator it = qBinaryFind(_pens, name);
+ if (it == _pens.end()) {
+ return -1;
+ } else {
+ return it - _pens.begin();
+ }
+}
+
+QDir NotebookModel::notebookDir(const QString &pen, const QString &notebook) const
+{
+ return QDir(_dataDir.filePath("%1.pen/%2.afd").arg(pen, notebook));
+}
+
+QIcon NotebookModel::getNotebookIcon(const QString &pen, const QString &notebook) const
+{
+ static QStringList candidates;
+ if (candidates.isEmpty()) {
+ candidates << "userdata/icon/Notebook.png"
+ << "userdata/icon/active_64x64.png"
+ << "userdata/icon/active_32x32.png"
+ << "userdata/icon/active_16x16.png";
+ }
+ QIcon icon;
+
+ QDir dir = notebookDir(pen, notebook);
+ if (dir.exists()) {
+ foreach (const QString &candidate, candidates) {
+ if (dir.exists(candidate)) {
+ icon.addFile(dir.filePath(candidate));
+ }
+ }
+ }
+
+ return icon;
+}
+
+bool NotebookModel::isNotebookLocked(const QString &pen, const QString &notebook) const
+{
+ QDir dir = notebookDir(pen, notebook);
+ if (dir.exists(".sync.lck")) {
+ return true; // TODO check if stale
+ } else {
+ return false;
+ }
+}
+
+void NotebookModel::handleChangedDirectory(const QString &path)
+{
+ qDebug() << "changed" << path;
+ if (path == _dataDir.absolutePath()) {
+ refresh();
+ }
+}