diff options
Diffstat (limited to 'notebookmodel.cc')
-rw-r--r-- | notebookmodel.cc | 323 |
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 ¬ebooks = _notebooks[penName]; + const QString ¬ebookName = 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 ¬ebooks = _notebooks[penName]; + const QString ¬ebookName = 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 ¬ebooks = _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 ¬ebooks = _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 ¬ebook) const +{ + return QDir(_dataDir.filePath("%1.pen/%2.afd").arg(pen, notebook)); +} + +QIcon NotebookModel::getNotebookIcon(const QString &pen, const QString ¬ebook) 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 ¬ebook) 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(); + } +} |