From: Akos Polster Date: Sat, 24 Jul 2010 15:13:23 +0000 (+0200) Subject: Parse NCX directory for chapter titles. Show chapter titles for bookmarks. X-Git-Url: http://git.maemo.org/git/?p=dorian;a=commitdiff_plain;h=41c0fdd2d68424ab3a97f8de0b861e37bb2ccd20 Parse NCX directory for chapter titles. Show chapter titles for bookmarks. --- diff --git a/TODO.txt b/TODO.txt index ae2c05a..ee989e8 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,6 +1,6 @@ -To dos migrated to Maemo Garage: -https://garage.maemo.org/tracker/?group_id=1757 . Old to dos below are kept as -historical artifacts. +To do list migrated to Maemo Garage: +https://garage.maemo.org/tracker/?group_id=1757 . Old to do list below is kept as +historical artifact. To Do ----- diff --git a/book.cpp b/book.cpp index bd96c45..489e087 100644 --- a/book.cpp +++ b/book.cpp @@ -9,10 +9,11 @@ #include "book.h" #include "opshandler.h" -#include "opserrorhandler.h" +#include "xmlerrorhandler.h" #include "extractzip.h" #include "library.h" #include "containerhandler.h" +#include "ncxhandler.h" Book::Book() { @@ -77,7 +78,7 @@ void Book::fail(const QString &details, const QString &error) "

" + Qt::escape(error) + "

" + Qt::escape(details) + "

"; content["error"].href = errorPage; - content["error"].type = "text/html"; + content["error"].name = "Error"; } bool Book::extract() @@ -128,21 +129,37 @@ bool Book::parse() qDebug() << "Book::parse"; bool ret = false; - QFile bookFile(opsPath()); + QString opsFileName = opsPath(); + qDebug() << " Parsing OPS file" << opsFileName; + QFile opsFile(opsFileName); QXmlSimpleReader reader; - QXmlInputSource *source = new QXmlInputSource(&bookFile); + QXmlInputSource *source = new QXmlInputSource(&opsFile); OpsHandler *opsHandler = new OpsHandler(*this); - OpsErrorHandler *opsErrorHandler = new OpsErrorHandler(); + XmlErrorHandler *errorHandler = new XmlErrorHandler(); reader.setContentHandler(opsHandler); - reader.setErrorHandler(opsErrorHandler); - + reader.setErrorHandler(errorHandler); ret = reader.parse(source); - if (!ret) { - qCritical() << "*** Book::parse: XML parsing failed"; - } - + delete errorHandler; delete opsHandler; delete source; + + // If there is an "ncx" item in content, parse it: That's the real table of + // contents + if (content.contains("ncx")) { + QString ncxFileName = content["ncx"].href; + qDebug() << " Parsing NCX file" << ncxFileName; + QFile ncxFile(ncxFileName); + source = new QXmlInputSource(&ncxFile); + NcxHandler *ncxHandler = new NcxHandler(*this); + errorHandler = new XmlErrorHandler(); + reader.setContentHandler(ncxHandler); + reader.setErrorHandler(errorHandler); + ret = reader.parse(source); + delete ncxHandler; + delete errorHandler; + delete source; + } + return ret; } @@ -286,15 +303,16 @@ QString Book::opsPath() QXmlSimpleReader reader; QXmlInputSource *source = new QXmlInputSource(&container); ContainerHandler *containerHandler = new ContainerHandler(); - OpsErrorHandler *opsErrorHandler = new OpsErrorHandler(); + XmlErrorHandler *errorHandler = new XmlErrorHandler(); reader.setContentHandler(containerHandler); - reader.setErrorHandler(opsErrorHandler); + reader.setErrorHandler(errorHandler); if (reader.parse(source)) { ret = tmpDir() + "/" + containerHandler->rootFile; mRootPath = QFileInfo(ret).absoluteDir().absolutePath(); qDebug() << " OSP path" << ret; qDebug() << " Root dir" << mRootPath; } + delete errorHandler; delete containerHandler; delete source; return ret; diff --git a/book.h b/book.h index 974b7c7..6449112 100644 --- a/book.h +++ b/book.h @@ -16,7 +16,7 @@ public: struct ContentItem { QString href; - QString type; + QString name; }; /** Bookmark: a volume index and a relative position in volume. */ @@ -97,6 +97,9 @@ public: QString subject; //< Subject. QString source; //< Source. QString rights; //< Rights. + QString tocPath; //< Path to toc ncx. + QString coverPath; //< Path to cover html. + QString coverImagePath; //< Path to cover image. protected: /** Indicate failure by creating a single "error" content item. */ diff --git a/bookmarksdialog.cpp b/bookmarksdialog.cpp index 9594bbd..14b3b3e 100644 --- a/bookmarksdialog.cpp +++ b/bookmarksdialog.cpp @@ -15,7 +15,9 @@ BookmarksDialog::BookmarksDialog(Book *book_, QWidget *parent): list = new QListWidget(this); list->setSelectionMode(QAbstractItemView::SingleSelection); foreach (Book::Bookmark bookmark, book_->bookmarks()) { - list->addItem("Volume " + QString::number(bookmark.chapter + 1) + ", at " + + QString contentId = book_->toc[bookmark.chapter]; + QString contentTitle = book_->content[contentId].name; + list->addItem(contentTitle + ", at " + QString::number((int)(bookmark.pos * 100)) + "%"); } diff --git a/bookview.cpp b/bookview.cpp index d960e26..cea29f2 100644 --- a/bookview.cpp +++ b/bookview.cpp @@ -167,13 +167,11 @@ void BookView::onSettingsChanged(const QString &key) } else if (key == "font") { QString face = Settings::instance()->value("font").toString(); - qDebug() << "" << face; settings()->setFontFamily(QWebSettings::StandardFont, face); } else if (key == "scheme") { QWebFrame *frame = page()->mainFrame(); QString scheme = Settings::instance()->value("scheme").toString(); - qDebug() << "" << scheme; if ((scheme != "day") && (scheme != "night") && (scheme != "sand") && (scheme != "default")) { scheme = "default"; @@ -183,8 +181,6 @@ void BookView::onSettingsChanged(const QString &key) QString scriptText = script.readAll(); script.close(); QVariant ret = frame->evaluateJavaScript(scriptText); - qDebug() << "" << script.fileName() << ":" << scriptText; - qDebug() << "" << ret; } } diff --git a/dorian.pro b/dorian.pro index 217f457..0caa0af 100644 --- a/dorian.pro +++ b/dorian.pro @@ -37,9 +37,10 @@ HEADERS += \ settingswindow.h \ settings.h \ bookmarksdialog.h \ - opserrorhandler.h \ + xmlerrorhandler.h \ containerhandler.h \ - sortedlibrary.h + sortedlibrary.h \ + ncxhandler.h RESOURCES += \ dorian.qrc diff --git a/ncxhandler.h b/ncxhandler.h new file mode 100644 index 0000000..0f808cb --- /dev/null +++ b/ncxhandler.h @@ -0,0 +1,72 @@ +#ifndef NCXHANDLER_H +#define NCXHANDLER_H + +#include + +#include "book.h" + +/** XML content handler for NCX format. */ +class NcxHandler: public QXmlContentHandler +{ +public: + bool endDocument() {return true;} + bool endPrefixMapping(const QString &) {return true;} + QString errorString() const {return "";} + bool ignorableWhitespace(const QString &) {return true;} + bool processingInstruction(const QString &, const QString &) {return true;} + void setDocumentLocator(QXmlLocator *) {} + bool skippedEntity(const QString &) {return true;} + bool startDocument() {return true;} + bool startPrefixMapping(const QString &, const QString &) {return true;} + + NcxHandler(Book &b): book(b) + { + book.toc.clear(); + } + + bool characters(const QString &ch) + { + currentText += ch; + return true; + } + + bool endElement(const QString &namespaceUri, const QString &name, + const QString &qName) + { + (void)namespaceUri; + (void)qName; + if (name == "text") { + contentTitle = currentText; + } else if (name == "navPoint") { + Book::ContentItem item; + item.href = book.rootPath() + "/" + contentUrl; + item.name = contentTitle; + book.content[contentId] = item; + book.toc.append(contentId); + } + return true; + } + + bool startElement(const QString &namespaceUri, const QString &name, + const QString &qName, const QXmlAttributes &attrs) + { + (void)namespaceUri; + (void)qName; + currentText = ""; + if (name == "navPoint") { + contentId = attrs.value("id"); + } else if (name == "content") { + contentUrl = attrs.value("src"); + } + return true; + } + +private: + Book &book; + QString currentText; + QString contentId; + QString contentUrl; + QString contentTitle; +}; + +#endif // NCXHANDLER_H diff --git a/opserrorhandler.h b/opserrorhandler.h deleted file mode 100644 index f1a75f6..0000000 --- a/opserrorhandler.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef OPSERRORHANDLER_H -#define OPSERRORHANDLER_H - -#include -#include - -#include "book.h" - -/** - XML error handler for OPS format. - */ -class OpsErrorHandler: public QXmlErrorHandler -{ - bool error(const QXmlParseException &e) { - qDebug() << "OpsErrorHandler::error" << e.message() << "at line" - << e.lineNumber(); - return true; - } - virtual QString errorString() const {return QString();} - virtual bool fatalError(const QXmlParseException &e) { - qDebug() << "OpsErrorHandler::fatalError" << e.message() << "at line" - << e.lineNumber(); - return true; - } - virtual bool warning(const QXmlParseException &e) { - qDebug() << "OpsErrorHandler::warning" << e.message() << "at line" - << e.lineNumber(); - return true; - } -}; - -#endif // OPSERRORHANDLER_H diff --git a/opshandler.h b/opshandler.h index 6e1ee01..9b42c23 100644 --- a/opshandler.h +++ b/opshandler.h @@ -9,7 +9,7 @@ class OpsHandler: public QXmlContentHandler { public: - OpsHandler(Book &book): mBook(book) {} + OpsHandler(Book &b): book(b), partCount(0) {} bool endDocument() {return true;} bool endPrefixMapping(const QString &) {return true;} QString errorString() const {return "";} @@ -24,7 +24,7 @@ public: bool characters(const QString &ch) { - mCurrentText += ch; + currentText += ch; return true; } @@ -33,24 +33,24 @@ public: { (void)namespaceUri; (void)qName; - if (mCurrentText != "") { + if (currentText != "") { if (name == "title") { - mBook.title = mCurrentText; + book.title = currentText; } else if (name == "creator") { - mBook.creators.append(mCurrentText); + book.creators.append(currentText); } else if (name == "publisher") { - mBook.publisher = mCurrentText; + book.publisher = currentText; } else if (name == "subject") { - mBook.subject = mCurrentText; + book.subject = currentText; } else if (name == "source") { - mBook.source = mCurrentText; + book.source = currentText; } else if (name == "rights") { - mBook.rights = mCurrentText; + book.rights = currentText; } } return true; @@ -60,30 +60,27 @@ public: const QString &qName, const QXmlAttributes &attrs) { (void)namespaceUri; - (void)name; (void)qName; - (void)attrs; - mCurrentText = ""; + currentText = ""; if (name == "item") { Book::ContentItem item; - item.href = mBook.rootPath() + "/" + attrs.value("href"); - item.type = attrs.value("media-type"); + item.href = book.rootPath() + "/" + attrs.value("href"); + item.name = QString("Part %1").arg(partCount + 1); QString key = attrs.value("id"); - mBook.content[key] = item; - qDebug() << "OpsHandler::startElement: item" << key << "type" - << item.type << "href" << item.href; + book.content[key] = item; + partCount++; } else if (name == "itemref") { - mBook.toc.append(attrs.value("idref")); - qDebug() << "OpsHandler::startElement: itemref" << attrs.value("idref"); + book.toc.append(attrs.value("idref")); } return true; } private: - Book &mBook; - QString mCurrentText; + Book &book; + QString currentText; + int partCount; }; #endif // OPSHANDLER_H diff --git a/pkg/changelog b/pkg/changelog index d8e8981..4f46599 100644 --- a/pkg/changelog +++ b/pkg/changelog @@ -4,7 +4,9 @@ dorian (0.0.10-1) unstable; urgency=low * Show message if selected book is already in the library * Make library window full screen on Maemo * Show busy indicator while loading book - * Create Maemo Garage web pages + * Create Maemo Garage web page + * Read chapter titles from NCX directory + * Display chapter titles for bookmarks -- Akos Polster Fri, 16 Jul 2010 20:00:00 +0200 diff --git a/xmlerrorhandler.h b/xmlerrorhandler.h new file mode 100644 index 0000000..30082e7 --- /dev/null +++ b/xmlerrorhandler.h @@ -0,0 +1,28 @@ +#ifndef XMLERRORHANDLER_H +#define XMLERRORHANDLER_H + +#include +#include + +/** Generic XML error handler. */ +class XmlErrorHandler: public QXmlErrorHandler +{ + bool error(const QXmlParseException &e) { + qCritical() << "*** XmlErrorHandler::error" << e.message() << "at line" + << e.lineNumber(); + return true; + } + QString errorString() const {return QString();} + bool fatalError(const QXmlParseException &e) { + qCritical() << "*** XmlErrorHandler::fatalError" << e.message() + << "at line" << e.lineNumber(); + return true; + } + bool warning(const QXmlParseException &e) { + qWarning() << "XmlErrorHandler::warning" << e.message() << "at line" + << e.lineNumber(); + return true; + } +}; + +#endif // XMLERRORHANDLER_H