From 41f9a9b0563c3bd523bd534b854e50161a2626b3 Mon Sep 17 00:00:00 2001 From: Javier Date: Sat, 13 Jun 2015 04:24:21 +0200 Subject: continue with paperreplay loading changes --- afdnotebook.cc | 6 ++ afdnotebook.h | 41 ++++++----- mainwindow.cc | 1 + mainwindow.ui | 30 ++++++++ notebookmodel.cc | 15 ++-- notebookmodel.h | 1 + notebookview.cc | 41 ++++++++--- notebookview.h | 9 ++- paperreplay.cc | 212 +++++++++++++++++++++++++++++++++++++++++++++++++++++ paperreplay.h | 47 ++++++++++++ replaydata.cc | 183 --------------------------------------------- replaydata.h | 53 -------------- scribiu.pro | 4 +- stfgraphicsitem.cc | 9 ++- 14 files changed, 373 insertions(+), 279 deletions(-) create mode 100644 paperreplay.cc create mode 100644 paperreplay.h delete mode 100644 replaydata.cc delete mode 100644 replaydata.h diff --git a/afdnotebook.cc b/afdnotebook.cc index 38f1fdc..e3b024a 100644 --- a/afdnotebook.cc +++ b/afdnotebook.cc @@ -49,6 +49,11 @@ QString AfdNotebook::title() const return _title; } +quint64 AfdNotebook::guid() const +{ + return _guid; +} + int AfdNotebook::numPages() const { return _pages.size(); @@ -232,6 +237,7 @@ bool AfdNotebook::parseMainInfo() } _title = info["title"]; + _guid = info["guid"].mid(3).toULongLong(0, 16); _firstPage = PageAddress(info["pagestart"]); _lastPage = PageAddress(info["pagestop"]); _pagesPerBook = info.value("segment-pages-per-book", "108").toUInt(); diff --git a/afdnotebook.h b/afdnotebook.h index 38f926f..737196e 100644 --- a/afdnotebook.h +++ b/afdnotebook.h @@ -15,10 +15,31 @@ public: AfdNotebook(QObject *parent = 0); ~AfdNotebook(); + struct PageAddress { + PageAddress(); + explicit PageAddress(uint shelf, uint segment, uint book, uint page); + explicit PageAddress(uint series, uint shelf, uint segment, uint book, uint page); + explicit PageAddress(quint64 addr); + explicit PageAddress(const QString &str); + + QString toString() const; + quint64 toUInt64() const; + + bool operator<(const PageAddress& o) const; + bool operator==(const PageAddress& o) const; + + uint series : 12; + uint shelf : 12; + uint segment : 16; + uint book : 12; + uint page : 12; + }; + bool open(const QString &path); void close(); QString title() const; + quint64 guid() const; int numPages() const; @@ -36,25 +57,6 @@ public: bool readStrokes(const QString &penSerial, int page, StfReader::StrokeHandler *handler); private: - struct PageAddress { - PageAddress(); - explicit PageAddress(uint shelf, uint segment, uint book, uint page); - explicit PageAddress(uint series, uint shelf, uint segment, uint book, uint page); - explicit PageAddress(quint64 addr); - explicit PageAddress(const QString &str); - - QString toString() const; - - bool operator<(const PageAddress& o) const; - bool operator==(const PageAddress& o) const; - - uint series : 12; - uint shelf : 12; - uint segment : 16; - uint book : 12; - uint page : 12; - }; - struct Gfx { QString basename; }; @@ -89,6 +91,7 @@ private: private: QDir _dir; QString _title; + quint64 _guid; PageAddress _firstPage, _lastPage; uint _pagesPerBook; QMap _gfx; diff --git a/mainwindow.cc b/mainwindow.cc index 793a722..c509d4e 100644 --- a/mainwindow.cc +++ b/mainwindow.cc @@ -39,6 +39,7 @@ void MainWindow::openNotebook(const QString &pen, const QString ¬ebook) qDebug() << "Opening notebook" << _curPenName << _curNotebookName << nbDir; + ui->notebookView->setPaperReplay(_notebooks->paperReplayDirectory(_curPenName)); ui->notebookView->setNotebook(nbDir); } diff --git a/mainwindow.ui b/mainwindow.ui index dceeadc..ac3dce3 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -192,6 +192,36 @@ + + + + + + + 30 + 30 + + + + ... + + + + + + + + + + Qt::Horizontal + + + + + + + + diff --git a/notebookmodel.cc b/notebookmodel.cc index 13e3b21..2b7c99f 100644 --- a/notebookmodel.cc +++ b/notebookmodel.cc @@ -3,7 +3,7 @@ #include #include #include -#include "replaydata.h" +#include "paperreplay.h" #include "notebookmodel.h" #define NUM_COLUMNS 3 @@ -47,6 +47,11 @@ QString NotebookModel::notebookDirectory(const QModelIndex &index) const return QString(); } +QString NotebookModel::paperReplayDirectory(const QString &name) const +{ + return _dataDir.filePath(name + ".pen" + "/"+ PAPER_REPLAY); +} + QVariant NotebookModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); @@ -231,6 +236,7 @@ void NotebookModel::refreshPen(const QString &name) for (int i = 0; i < diskNotebooks.size(); i++) { diskNotebooks[i].chop(4); } + if (penDir.exists(PAPER_REPLAY)) diskNotebooks.append(PAPER_REPLAY); QModelIndex penIndex = index(indexOfPen(name), 0, QModelIndex()); @@ -265,13 +271,6 @@ void NotebookModel::refreshPen(const QString &name) } qDebug() << "Found" << curNotebooks.size() << "notebooks for pen" << name; - - ReplayData replay; - if (replay.open(penDir.filePath("PaperReplay"))) { - qDebug() << "Paper replay opened"; - } else { - qDebug() << "No paper replay for pen" << name; - } } int NotebookModel::indexOfPen(const QString &name) diff --git a/notebookmodel.h b/notebookmodel.h index 83bb004..1f52088 100644 --- a/notebookmodel.h +++ b/notebookmodel.h @@ -14,6 +14,7 @@ public: QString penDirectory(const QString &name) const; QString notebookDirectory(const QString &penName, const QString &nbName) const; QString notebookDirectory(const QModelIndex &index) const; + QString paperReplayDirectory(const QString &name) const; QVariant data(const QModelIndex &index, int role) const; Qt::ItemFlags flags(const QModelIndex &index) const; diff --git a/notebookview.cc b/notebookview.cc index 2605792..aa37ac9 100644 --- a/notebookview.cc +++ b/notebookview.cc @@ -6,7 +6,7 @@ #define PAGE_SEPARATION 100 NotebookView::NotebookView(QWidget *parent) : - QGraphicsView(parent), _nb(new AfdNotebook(this)), + QGraphicsView(parent), _nb(new AfdNotebook(this)), _replay(new PaperReplay(this)), _zoom(100), _curPage(0) { setScene(new QGraphicsScene(this)); @@ -18,14 +18,11 @@ NotebookView::NotebookView(QWidget *parent) : void NotebookView::setNotebook(const QString &path) { removePages(); + + _nbPath = path; + if (!path.isEmpty()) { - if (_nb->open(path)) { - _nbPath = path; - if (_zoom > 100) { - _zoom = 100; - emit zoomChanged(); - } - createPages(); + if (createPages()) { emit pageNumbersChanged(); if (!_pages.isEmpty()) { _curPage = _pages.begin().key(); @@ -43,6 +40,17 @@ QString NotebookView::notebook() const return _nbPath; } +void NotebookView::setPaperReplay(const QString &path) +{ + _replayPath = path; + // TODO reload; for now, please set this before the notebook +} + +QString NotebookView::paperReplay() const +{ + return _replayPath; +} + QList NotebookView::pageNumbers() const { return _pages.keys(); @@ -132,16 +140,25 @@ void NotebookView::removePages() scene()->clear(); scene()->setSceneRect(QRectF()); _nb->close(); - _nbPath.clear(); + _replay->close(); _maxPageSize.setWidth(0); _maxPageSize.setHeight(0); + if (_zoom > 100) { + _zoom = 100; + emit zoomChanged(); + } resetTransform(); } -void NotebookView::createPages() +bool NotebookView::createPages() { + if (!_nb->open(_nbPath)) return false; + QStringList pens = _nb->penSerials(); - if (pens.isEmpty()) return; + if (pens.isEmpty()) return false; + + // Failure to open paperreplay data is not fatal + _replay->open(_replayPath, pens[0], _nb->guid()); QList pagesWithStrokes = _nb->pagesWithStrokes(pens.first()); Q_ASSERT(_pages.isEmpty()); @@ -173,6 +190,8 @@ void NotebookView::createPages() } scene()->setSceneRect(0, 0, _maxPageSize.width(), curY); + + return true; } void NotebookView::calculateScale() diff --git a/notebookview.h b/notebookview.h index e51afa3..567d5cf 100644 --- a/notebookview.h +++ b/notebookview.h @@ -4,12 +4,14 @@ #include #include #include "afdnotebook.h" +#include "paperreplay.h" #include "pageitem.h" class NotebookView : public QGraphicsView { Q_OBJECT Q_PROPERTY(QString notebook WRITE setNotebook READ notebook) + Q_PROPERTY(QString paperReplay WRITE setPaperReplay READ paperReplay) Q_PROPERTY(QList pageNumbers READ pageNumbers NOTIFY pageNumbersChanged) Q_PROPERTY(int curPage READ curPage WRITE setCurPage NOTIFY curPageChanged) Q_PROPERTY(int zoom READ zoom WRITE setZoom NOTIFY zoomChanged) @@ -20,6 +22,9 @@ public: void setNotebook(const QString &path); QString notebook() const; + void setPaperReplay(const QString &path); + QString paperReplay() const; + QList pageNumbers() const; int curPage() const; @@ -44,12 +49,14 @@ protected: private: void removePages(); - void createPages(); + bool createPages(); void calculateScale(); private: AfdNotebook *_nb; + PaperReplay *_replay; QString _nbPath; + QString _replayPath; QMap _pages; QSizeF _maxPageSize; int _zoom; diff --git a/paperreplay.cc b/paperreplay.cc new file mode 100644 index 0000000..8bfb20e --- /dev/null +++ b/paperreplay.cc @@ -0,0 +1,212 @@ +#include +#include +#include +#include "smartpen.h" +#include "paperreplay.h" + +namespace +{ +bool readUtfString(QDataStream &stream, QString &s) +{ + quint16 len; + stream >> len; + QByteArray buffer(len, Qt::Uninitialized); + if (stream.readRawData(buffer.data(), len) != len) { + return false; + } + s = QString::fromUtf8(buffer); + return true; +} +} + +PaperReplay::PaperReplay(QObject *parent) : + QObject(parent) +{ +} + +bool PaperReplay::open(const QString &path, const QString &penSerial, quint64 notebookGuid) +{ + _dir.setPath(path + QString("/userdata/%1/Paper Replay/99/%2/sessions") + .arg(penSerial) + .arg(qulonglong(notebookGuid), notebookGuid == 0 ? 1 : 16, 16, QLatin1Char('0'))); + if (!_dir.exists()) { + qDebug() << "Cannot open paper replay:" << _dir.absolutePath() << "does not exist"; + return false; + } + + QDirIterator iter(_dir.path(), QStringList("PRS-*"), QDir::Dirs | QDir::NoDotAndDotDot); + while (iter.hasNext()) { + QDir sessionDir(iter.next()); + bool ok; + quint64 sessionId = sessionDir.dirName().mid(4).toULongLong(&ok, 16); + if (!ok) { + qWarning() << "Invalid session identifier:" << sessionDir.dirName(); + } + Session &session = _sessions[sessionId]; + if (!parseSessionInfo(session, sessionDir.filePath("session.info"))) { + qWarning() << "Could not parse:" << sessionDir.absoluteFilePath("session.info"); + } + if (!parseSessionPages(session, sessionDir.filePath("session.pages"))) { + qWarning() << "Could not parse:" << sessionDir.absoluteFilePath("session.pages"); + } + } + + return true; +} + +void PaperReplay::close() +{ + _sessions.clear(); + _byPage.clear(); + _dir.setPath(QString()); +} + +QList PaperReplay::sessions() +{ + return _sessions.values(); +} + +QList PaperReplay::sessions(quint64 pageAddress) +{ + QList sessions; + QMultiMap::iterator it = _byPage.find(pageAddress); + while (it != _byPage.end() && it.key() == pageAddress) { + sessions.append(_sessions[it.value()]); + } + return sessions; +} + +bool PaperReplay::parseSessionInfo(Session &session, const QString &path) +{ + QFile f(path); + if (f.open(QIODevice::ReadOnly)) { + return parseSessionInfo(session, &f); + } else { + return false; + } +} + +bool PaperReplay::parseSessionInfo(Session &session, QIODevice *dev) +{ + unsigned char magic[2]; + if (dev->read(reinterpret_cast(magic), 2) != 2 || + magic[0] != 0xFA || magic[1] != 0xCE) { + qWarning() << "Invalid magic"; + return false; + } + + char version = 0; + if (!dev->getChar(&version)) { + qWarning() << "Short read while getting version number"; + return false; + } + + switch (version) { + case 3: + return parseSessionInfoV3(session, dev); + default: + qWarning() << "Unknown version:" << version; + return false; + } +} + +bool PaperReplay::parseSessionInfoV3(Session &session, QIODevice *dev) +{ + QDataStream s(dev); + if (s.skipRawData(5) != 5) return false; + + qint64 startTime, endTime, creationTime; + QString name; + + s >> startTime >> endTime >> creationTime; + if (!readUtfString(s, name)) { + return false; + } + + qDebug() << "Name:" << name << Smartpen::fromPenTime(startTime) << Smartpen::fromPenTime(endTime) << creationTime; + + quint16 num_clips; + s >> num_clips; + + for (uint i = 0; i < num_clips; ++i) { + QString file; + if (!readUtfString(s, file)) { + return false; + } + s >> startTime >> endTime; + qDebug() << " Clip:" << file << startTime << endTime; + qDebug() << " " << QDateTime::fromTime_t(startTime) << QDateTime::fromTime_t(endTime); + } + + quint16 num_strokes; + s >> num_strokes; + + for (uint i = 0; i < num_strokes; ++i) { + quint64 a, b, c; + quint32 d; + QString nbGuid; + quint8 f, g; + s >> a >> b >> c >> d; + if (!readUtfString(s, nbGuid)) { + return false; + } + s >> f >> g; + qDebug() << " Stroke:" << a << b << c << d << nbGuid << f << g; + } + + return true; +} + +bool PaperReplay::parseSessionPages(Session &session, const QString &path) +{ + QFile f(path); + if (f.open(QIODevice::ReadOnly)) { + return parseSessionPages(session, &f); + } else { + return false; + } +} + +bool PaperReplay::parseSessionPages(Session &session, QIODevice *dev) +{ + unsigned char magic[2]; + if (dev->read(reinterpret_cast(magic), 2) != 2 || + magic[0] != 0xCA || magic[1] != 0xBE) { + qWarning() << "Invalid magic"; + return false; + } + + char version = 0; + if (!dev->getChar(&version)) { + qWarning() << "Short read while getting version number"; + return false; + } + + switch (version) { + case 1: + return parseSessionPagesV1(session, dev); + default: + qWarning() << "Unknown version:" << version; + return false; + } +} + +bool PaperReplay::parseSessionPagesV1(Session &session, QIODevice *dev) +{ + QDataStream s(dev); + if (s.skipRawData(1) != 1) return false; + + quint16 num_pages = 0; + s >> num_pages; + session.pages.reserve(session.pages.size() + num_pages); + + for (uint i = 0; i < num_pages; ++i) { + quint64 address, unk; + s >> address >> unk; + + session.pages.append(address); + qDebug() << " Page:" << address << unk; + } + + return true; +} diff --git a/paperreplay.h b/paperreplay.h new file mode 100644 index 0000000..8ad7331 --- /dev/null +++ b/paperreplay.h @@ -0,0 +1,47 @@ +#ifndef PAPERREPLAY_H +#define PAPERREPLAY_H + +#include +#include +#include +#include +#include + +#define PAPER_REPLAY "Paper Replay" + +class PaperReplay : public QObject +{ + Q_OBJECT + +public: + explicit PaperReplay(QObject *parent = 0); + + bool open(const QString &path, const QString &penSerial, quint64 notebookGuid); + void close(); + + struct Session { + QDateTime start, end; + QString name; + QVector pages; + QString file; + }; + + QList sessions(); + QList sessions(quint64 pageAddress); + +private: + static bool parseSessionInfo(Session &session, const QString &path); + static bool parseSessionInfo(Session &session, QIODevice *dev); + static bool parseSessionInfoV3(Session &session, QIODevice *dev); + + static bool parseSessionPages(Session &session, const QString &path); + static bool parseSessionPages(Session &session, QIODevice *dev); + static bool parseSessionPagesV1(Session &session, QIODevice *dev); + +private: + QDir _dir; + QHash _sessions; + QMultiMap _byPage; +}; + +#endif // PAPERREPLAY_H diff --git a/replaydata.cc b/replaydata.cc deleted file mode 100644 index 021a79f..0000000 --- a/replaydata.cc +++ /dev/null @@ -1,183 +0,0 @@ -#include -#include -#include -#include "smartpen.h" -#include "replaydata.h" - -namespace -{ -bool readUtfString(QDataStream &stream, QString &s) -{ - quint16 len; - stream >> len; - QByteArray buffer(len, Qt::Uninitialized); - if (stream.readRawData(buffer.data(), len) != len) { - return false; - } - s = QString::fromUtf8(buffer); - return true; -} -} - -ReplayData::ReplayData(QObject *parent) : - QObject(parent) -{ -} - -bool ReplayData::open(const QString &path) -{ - _dir.setPath(path); - if (!_dir.exists()) { - return false; - } - - QDirIterator iter(_dir.path(), QStringList("session.info"), QDir::Files, QDirIterator::Subdirectories); - while (iter.hasNext()) { - QFileInfo finfo(iter.next()); - QDir sessionDir(finfo.path()); - Session session; - if (!parseSessionInfo(session, finfo.filePath())) { - qWarning() << "Could not parse:" << finfo.absoluteFilePath(); - } - if (!parseSessionPages(session, sessionDir.filePath("session.pages"))) { - qWarning() << "Could not parse:" << sessionDir.absoluteFilePath("session.pages"); - } - } - - return true; -} - -bool ReplayData::parseSessionInfo(Session &session, const QString &path) -{ - QFile f(path); - if (f.open(QIODevice::ReadOnly)) { - return parseSessionInfo(session, &f); - } else { - return false; - } -} - -bool ReplayData::parseSessionInfo(Session &session, QIODevice *dev) -{ - unsigned char magic[2]; - if (dev->read(reinterpret_cast(magic), 2) != 2 || - magic[0] != 0xFA || magic[1] != 0xCE) { - qWarning() << "Invalid magic"; - return false; - } - - char version = 0; - if (!dev->getChar(&version)) { - qWarning() << "Short read while getting version number"; - return false; - } - - switch (version) { - case 3: - return parseSessionInfoV3(session, dev); - default: - qWarning() << "Unknown version:" << version; - return false; - } -} - -bool ReplayData::parseSessionInfoV3(Session &session, QIODevice *dev) -{ - QDataStream s(dev); - if (s.skipRawData(5) != 5) return false; - - qint64 startTime, endTime, creationTime; - QString name; - - s >> startTime >> endTime >> creationTime; - if (!readUtfString(s, name)) { - return false; - } - - qDebug() << "Name:" << name << Smartpen::fromPenTime(startTime) << Smartpen::fromPenTime(endTime) << creationTime; - - quint16 num_clips; - s >> num_clips; - - for (uint i = 0; i < num_clips; ++i) { - QString file; - if (!readUtfString(s, file)) { - return false; - } - s >> startTime >> endTime; - qDebug() << " Clip:" << file << startTime << endTime; - qDebug() << " " << QDateTime::fromTime_t(startTime) << QDateTime::fromTime_t(endTime); - } - - quint16 num_strokes; - s >> num_strokes; - - for (uint i = 0; i < num_strokes; ++i) { - quint64 a, b, c; - quint32 d; - QString nbGuid; - quint8 f, g; - s >> a >> b >> c >> d; - if (!readUtfString(s, nbGuid)) { - return false; - } - s >> f >> g; - qDebug() << " Stroke:" << a << b << c << d << nbGuid << f << g; - } - - return true; -} - -bool ReplayData::parseSessionPages(Session &session, const QString &path) -{ - QFile f(path); - if (f.open(QIODevice::ReadOnly)) { - return parseSessionPages(session, &f); - } else { - return false; - } -} - -bool ReplayData::parseSessionPages(Session &session, QIODevice *dev) -{ - unsigned char magic[2]; - if (dev->read(reinterpret_cast(magic), 2) != 2 || - magic[0] != 0xCA || magic[1] != 0xBE) { - qWarning() << "Invalid magic"; - return false; - } - - char version = 0; - if (!dev->getChar(&version)) { - qWarning() << "Short read while getting version number"; - return false; - } - - switch (version) { - case 1: - return parseSessionPagesV1(session, dev); - default: - qWarning() << "Unknown version:" << version; - return false; - } -} - -bool ReplayData::parseSessionPagesV1(Session &session, QIODevice *dev) -{ - QDataStream s(dev); - if (s.skipRawData(1) != 1) return false; - - quint16 num_pages = 0; - s >> num_pages; - session.pages.reserve(session.pages.size() + num_pages); - - for (uint i = 0; i < num_pages; ++i) { - quint64 address, unk; - s >> address >> unk; - - session.pages.append(address); - qDebug() << " Page:" << address << unk; - } - - return true; -} diff --git a/replaydata.h b/replaydata.h deleted file mode 100644 index 39b1e0e..0000000 --- a/replaydata.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef REPLAYDATA_H -#define REPLAYDATA_H - -#include -#include -#include -#include -#include - -class ReplayData : public QObject -{ - Q_OBJECT - -public: - explicit ReplayData(QObject *parent = 0); - - bool open(const QString &path); - void close(); - - struct Session { - QDateTime start, end; - QString name; - QVector pages; - QString file; - }; - - QList sessions(quint64 penId, quint64 notebookId); - QList sessions(quint64 penId, quint64 notebookId, quint64 pageAddress); - -private: - struct NotebookData { - QHash sessions; - QMultiMap byPage; - }; - -private: - bool findSessions(); - - static bool parseSessionInfo(Session &session, const QString &path); - static bool parseSessionInfo(Session &session, QIODevice *dev); - static bool parseSessionInfoV3(Session &session, QIODevice *dev); - - static bool parseSessionPages(Session &session, const QString &path); - static bool parseSessionPages(Session &session, QIODevice *dev); - static bool parseSessionPagesV1(Session &session, QIODevice *dev); - -private: - QDir _dir; - QHash > _notebooks; // TODO Cache on demand - // /userdata/XXX-XXX-XXX-XX/Paper Replay/99/0bf11a726d11f3f3/sessions/PRS-21977890a4 -}; - -#endif // REPLAYDATA_H diff --git a/scribiu.pro b/scribiu.pro index 31d05ea..f50b75b 100644 --- a/scribiu.pro +++ b/scribiu.pro @@ -20,7 +20,7 @@ SOURCES += main.cc\ afdnotebook.cc \ pageitem.cc \ stfgraphicsitem.cc \ - replaydata.cc + paperreplay.cc HEADERS += mainwindow.h \ smartpenmanager.h \ @@ -32,6 +32,6 @@ HEADERS += mainwindow.h \ afdnotebook.h \ pageitem.h \ stfgraphicsitem.h \ - replaydata.h + paperreplay.h FORMS += mainwindow.ui diff --git a/stfgraphicsitem.cc b/stfgraphicsitem.cc index 865a029..414cf6c 100644 --- a/stfgraphicsitem.cc +++ b/stfgraphicsitem.cc @@ -1,3 +1,4 @@ +#include #include #include "stfreader.h" @@ -16,12 +17,16 @@ public: ~StfToGraphicsPathItems() { } - bool startStroke(const QPoint& p, int, quint64) { + bool startStroke(const QPoint& p, int force, quint64 time) { + Q_UNUSED(force); + Q_UNUSED(time); path = QPainterPath(QPointF(p)); return true; } - bool strokePoint(const QPoint& p, int, quint64) { + bool strokePoint(const QPoint& p, int force, quint64 time) { + Q_UNUSED(force); + Q_UNUSED(time); path.lineTo(QPointF(p)); return true; } -- cgit v1.2.3