123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611 |
- #include <QtGui>
- #include <QtDebug>
- #include "fb2page.hpp"
- #include "fb2save.hpp"
- #include "fb2text.hpp"
- #include "fb2utils.h"
- #include "fb2html.h"
- #include <QAbstractNetworkCache>
- #include <QBuffer>
- #include <QComboBox>
- #include <QDateTime>
- #include <QFileDialog>
- #include <QGridLayout>
- #include <QLabel>
- #include <QList>
- #include <QNetworkReply>
- #include <QNetworkRequest>
- #include <QScopedPointer>
- #include <QTextCodec>
- #include <QWebFrame>
- #include <QWebPage>
- #include <QtDebug>
- #define XMLAutoFormatting
- //#define ImgTypePrint
- //---------------------------------------------------------------------------
- // FbSaveDialog
- //---------------------------------------------------------------------------
- FbSaveDialog::FbSaveDialog(QWidget *parent, Qt::WindowFlags f)
- : QFileDialog(parent, f)
- {
- init();
- }
- FbSaveDialog::FbSaveDialog(QWidget *parent, const QString &caption, const QString &directory, const QString &filter)
- : QFileDialog(parent, caption, directory, filter)
- {
- init();
- }
- void FbSaveDialog::init()
- {
- QMap<QString, QString> codecMap;
- for (const int &mib: QTextCodec::availableMibs()) {
- QTextCodec *codec = QTextCodec::codecForMib(mib);
- QString sortKey = codec->name().toUpper();
- int rank;
- if (sortKey.startsWith("UTF-8")) {
- rank = 1;
- } else if (sortKey.startsWith("KOI8")) {
- rank = 2;
- } else if (sortKey.startsWith("WINDOWS")) {
- rank = 3;
- } else {
- rank = 4;
- }
- sortKey.prepend(QChar('0' + rank));
- codecMap.insert(sortKey, codec->name());
- }
- setAcceptMode(AcceptSave);
- setOption(DontConfirmOverwrite, false);
- setDefaultSuffix("fb2");
- QStringList filters;
- filters << tr("Fiction book files (*.fb2)");
- filters << tr("Any files (*.*)");
- setNameFilters(filters);
- combo = new QComboBox(this);
- for (const QString &codec: codecMap) {
- combo->addItem(codec);
- }
- combo->setCurrentIndex(0);
- label = new QLabel(this);
- label->setText(tr("&Encoding"));
- label->setBuddy(combo);
- layout()->addWidget(label);
- layout()->addWidget(combo);
- }
- QString FbSaveDialog::fileName() const
- {
- for (const QString &filename: selectedFiles()) {
- return filename;
- }
- return QString();
- }
- QString FbSaveDialog::codec() const
- {
- return combo->currentText();
- }
- //---------------------------------------------------------------------------
- // FbHtmlHandler
- //---------------------------------------------------------------------------
- QString FbHtmlHandler::local(const QString &name)
- {
- return name.mid(name.lastIndexOf(":"));
- }
- void FbHtmlHandler::onAttr(const QString &name, const QString &value)
- {
- m_atts.append(name, local(name), value);
- }
- void FbHtmlHandler::onNew(const QString &name)
- {
- startElement("", local(name), name, m_atts);
- m_atts.clear();
- }
- void FbHtmlHandler::onTxt(const QString &text)
- {
- m_lastTextLength = text.length();
- characters(text);
- }
- void FbHtmlHandler::onCom(const QString &text)
- {
- comment(text);
- }
- void FbHtmlHandler::onEnd(const QString &name)
- {
- endElement("", local(name), name);
- }
- //---------------------------------------------------------------------------
- // FbSaveWriter
- //---------------------------------------------------------------------------
- FbSaveWriter::FbSaveWriter(FbTextEdit &view, QByteArray *array)
- : QXmlStreamWriter(array)
- , m_view(view)
- , m_string(0)
- , m_anchor(0)
- , m_focus(0)
- {
- if (QWebFrame * frame = m_view.page()->mainFrame()) {
- m_style = frame->findFirstElement("html>head>style#origin").toPlainText();
- }
- #ifdef XMLAutoFormatting
- setAutoFormatting(true);
- #endif
- }
- FbSaveWriter::FbSaveWriter(FbTextEdit &view, QIODevice *device)
- : QXmlStreamWriter(device)
- , m_view(view)
- , m_string(0)
- , m_anchor(0)
- , m_focus(0)
- {
- #ifdef XMLAutoFormatting
- setAutoFormatting(true);
- #endif
- }
- FbSaveWriter::FbSaveWriter(FbTextEdit &view, QString *string)
- : QXmlStreamWriter(string)
- , m_view(view)
- , m_string(string)
- , m_anchor(0)
- , m_focus(0)
- {
- #ifdef XMLAutoFormatting
- setAutoFormatting(true);
- #endif
- }
- void FbSaveWriter::writeComment(const QString &ch)
- {
- writeLineEnd();
- QXmlStreamWriter::writeComment(ch);
- }
- void FbSaveWriter::writeStartDocument()
- {
- if (device()) {
- QXmlStreamWriter::writeStartDocument();
- } else if (m_string) {
- m_string->append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
- }
- }
- void FbSaveWriter::writeStartElement(const QString &name, int level)
- {
- #ifndef XMLAutoFormatting
- Q_UNUSED(level)
- if (level) writeLineEnd();
- for (int i = 1; i < level; ++i) writeCharacters(" ");
- #endif
- QXmlStreamWriter::writeStartElement(name);
- }
- void FbSaveWriter::writeEndElement(int level)
- {
- #ifndef XMLAutoFormatting
- Q_UNUSED(level)
- if (level) writeLineEnd();
- for (int i = 1; i < level; ++i) writeCharacters(" ");
- #endif
- QXmlStreamWriter::writeEndElement();
- }
- void FbSaveWriter::writeLineEnd()
- {
- #ifndef XMLAutoFormatting
- writeCharacters("\n");
- #endif
- }
- QByteArray FbSaveWriter::downloadFile(const QUrl &url)
- {
- QNetworkRequest request(url);
- QNetworkAccessManager * network = m_view.page()->networkAccessManager();
- QScopedPointer<QNetworkReply> reply(network->get(request));
- if (reply.isNull()) return QByteArray();
- QEventLoop loop;
- QObject::connect(reply.data(), SIGNAL(finished()), &loop, SLOT(quit()));
- loop.exec();
- return reply->readAll();
- }
- QString FbSaveWriter::append(const QString &name)
- {
- if (m_names.indexOf(name) < 0) {
- m_names.append(name);
- }
- return name;
- }
- QString FbSaveWriter::filename(const QString &path)
- {
- FbStore *store = m_view.store();
- if (!store) return QString();
- if (path.left(1) == "#") {
- QString name = path.mid(1);
- if (store->exists(name)) {
- return append(name);
- } else {
- return QString();
- }
- } else {
- QUrl url = path;
- QByteArray data = downloadFile(url);
- if (data.size() == 0) return QString();
- QString name = store->add(url.path(), data);
- return append(name);
- }
- }
- void FbSaveWriter::writeStyle()
- {
- if (m_style.isEmpty()) return;
- const QString postfix = "\n ";
- writeStartElement("stylesheet", 2);
- writeAttribute("type", "text/css");
- writeCharacters(postfix);
- QStringList list = m_style.split("}", Qt::SkipEmptyParts);
- QString line;
- for (const QString &str: list) {
- line = str.simplified();
- if (line.isEmpty()) continue;
- writeCharacters(" " + line + "}" + postfix);
- }
- QXmlStreamWriter::writeEndElement();
- }
- void FbSaveWriter::writeFiles()
- {
- FbStore *store = m_view.store();
- if (!store) return;
- QStringListIterator it(m_names);
- while (it.hasNext()) {
- QString name = it.next();
- if (name.isEmpty()) continue;
- FbBinary * file = store->get(name);
- if (!file) continue;
- writeStartElement("binary", 2);
- writeAttribute("id", name);
- QByteArray array = file->data();
- QString data = array.toBase64();
- writeContentType(name, array);
- writeLineEnd();
- int pos = 0;
- while (true) {
- QString text = data.mid(pos, 76);
- if (text.isEmpty()) break;
- writeCharacters(text);
- writeLineEnd();
- pos += 76;
- }
- writeCharacters(" ");
- QXmlStreamWriter::writeEndElement();
- }
- }
- void FbSaveWriter::writeContentType(const QString &name, QByteArray &data)
- {
- QBuffer buffer(&data);
- buffer.open(QIODevice::ReadOnly);
- QString type = QImageReader::imageFormat(&buffer);
- #ifdef ImgTypePrint
- qCritical()<<"Img type: "<< type;
- #endif
- if (type.isEmpty()) {
- qCritical() << QObject::tr("Unknown image format: %1").arg(name);
- return;
- }
- type.prepend("image/");
- writeAttribute("content-type", type);
- }
- void FbSaveWriter::setAnchor(int offset)
- {
- if (m_string) m_anchor = m_string->length() + offset;
- }
- void FbSaveWriter::setFocus(int offset)
- {
- if (m_string) m_focus = m_string->length() + offset;
- }
- //---------------------------------------------------------------------------
- // FbSaveHandler::TextHandler
- //---------------------------------------------------------------------------
- FB2_BEGIN_KEYHASH(FbSaveHandler::TextHandler)
- FB2_KEY( Origin , "table" );
- FB2_KEY( Origin , "td" );
- FB2_KEY( Origin , "th" );
- FB2_KEY( Origin , "tr" );
- FB2_KEY( Origin , "a" );
- FB2_KEY( Image , "img" );
- FB2_KEY( Parag , "p" );
- FB2_KEY( Strong , "b" );
- FB2_KEY( Emphas , "i" );
- FB2_KEY( Span , "span" );
- FB2_KEY( Strike , "strike" );
- FB2_KEY( Sub , "sub" );
- FB2_KEY( Sup , "sup" );
- FB2_KEY( Code , "tt" );
- FB2_END_KEYHASH
- FbSaveHandler::TextHandler::TextHandler(FbSaveWriter &writer, const QString &name, const QXmlStreamAttributes &atts, const QString &tag)
- : NodeHandler(name)
- , m_writer(writer)
- , m_tag(tag)
- , m_level(1)
- , m_hasChild(false)
- {
- if (tag.isEmpty()) return;
- m_writer.writeStartElement(m_tag, m_level);
- writeAtts(atts);
- }
- FbSaveHandler::TextHandler::TextHandler(TextHandler *parent, const QString &name, const QXmlStreamAttributes &atts, const QString &tag)
- : NodeHandler(name)
- , m_writer(parent->m_writer)
- , m_tag(tag)
- , m_level(parent->nextLevel())
- , m_hasChild(false)
- {
- if (tag.isEmpty()) return;
- m_writer.writeStartElement(m_tag, m_level);
- writeAtts(atts);
- }
- void FbSaveHandler::TextHandler::writeAtts(const QXmlStreamAttributes &atts)
- {
- for (const auto& attr : atts) {
- QString name = attr.qualifiedName().toString();
- QString value = attr.value().toString();
- if (m_tag == "image") {
- if (name == "src") {
- name = "l:href";
- value = m_writer.filename(value).prepend('#');
- }
- } else if (m_tag == "a") {
- if (name == "href") name = "l:href";
- }
- m_writer.writeAttribute(name, value);
- }
- }
- FbXmlHandler::NodeHandler * FbSaveHandler::TextHandler::NewTag(const QString &name, const QXmlStreamAttributes &atts)
- {
- m_hasChild = true;
- QString tag = QString();
- switch (toKeyword(name)) {
- case Origin : tag = name; break;
- case Parag : return new ParagHandler(this, name, atts);
- case Span : return new SpanHandler(this, name, atts);
- case Image : tag = "image" ; break;
- case Strong : tag = "strong" ; break;
- case Emphas : tag = "emphasis" ; break;
- case Strike : tag = "strikethrough" ; break;
- case Code : tag = "code" ; break;
- case Sub : tag = "sub" ; break;
- case Sup : tag = "sup" ; break;
- default: if (name.left(3) == "fb:") tag = name.mid(3);
- }
- return new TextHandler(this, name, atts, tag);
- }
- void FbSaveHandler::TextHandler::TxtTag(const QString &text)
- {
- m_writer.writeCharacters(text);
- }
- void FbSaveHandler::TextHandler::EndTag(const QString &name)
- {
- Q_UNUSED(name);
- if (m_tag.isEmpty()) return;
- m_writer.writeEndElement(m_hasChild ? m_level : 0);
- }
- int FbSaveHandler::TextHandler::nextLevel() const
- {
- return m_level ? m_level + 1 : 0;
- }
- //---------------------------------------------------------------------------
- // FbSaveHandler::RootHandler
- //---------------------------------------------------------------------------
- FbSaveHandler::RootHandler::RootHandler(FbSaveWriter &writer, const QString &name)
- : NodeHandler(name)
- , m_writer(writer)
- {
- }
- FbXmlHandler::NodeHandler * FbSaveHandler::RootHandler::NewTag(const QString &name, const QXmlStreamAttributes &atts)
- {
- Q_UNUSED(atts);
- return name == "body" ? new BodyHandler(m_writer, name) : NULL;
- }
- //---------------------------------------------------------------------------
- // FbSaveHandler::BodyHandler
- //---------------------------------------------------------------------------
- FbSaveHandler::BodyHandler::BodyHandler(FbSaveWriter &writer, const QString &name)
- : TextHandler(writer, name, QXmlStreamAttributes(), "FictionBook")
- {
- m_writer.writeAttribute("xmlns", "http://www.gribuser.ru/xml/fictionbook/2.0");
- m_writer.writeAttribute("xmlns:l", "http://www.w3.org/1999/xlink");
- m_writer.writeStyle();
- }
- void FbSaveHandler::BodyHandler::EndTag(const QString &name)
- {
- m_writer.writeFiles();
- TextHandler::EndTag(name);
- }
- //---------------------------------------------------------------------------
- // FbSaveHandler::SpanHandler
- //---------------------------------------------------------------------------
- FbSaveHandler::SpanHandler::SpanHandler(TextHandler *parent, const QString &name, const QXmlStreamAttributes &atts)
- : TextHandler(parent, name, atts, Value(atts, "class") == "Apple-style-span" ? "" : "style")
- {
- }
- //---------------------------------------------------------------------------
- // FbSaveHandler::ParagHandler
- //---------------------------------------------------------------------------
- FbSaveHandler::ParagHandler::ParagHandler(TextHandler *parent, const QString &name, const QXmlStreamAttributes &atts)
- : TextHandler(parent, name, atts, "")
- , m_parent(parent->tag())
- , m_empty(true)
- {
- for (const auto& attr : atts) {
- QString qName = attr.qualifiedName().toString();
- QString value = attr.value().toString();
- if (qName == "fb:class") {
- m_class = value;
- } else {
- m_atts.append(qName, value);
- }
- }
- }
- FbXmlHandler::NodeHandler * FbSaveHandler::ParagHandler::NewTag(const QString &name, const QXmlStreamAttributes &atts)
- {
- if (m_empty && name != "br") start();
- return TextHandler::NewTag(name, atts);
- }
- void FbSaveHandler::ParagHandler::TxtTag(const QString &text)
- {
- if (m_empty) {
- if (isWhiteSpace(text)) return;
- start();
- }
- TextHandler::TxtTag(text);
- }
- void FbSaveHandler::ParagHandler::EndTag(const QString &name)
- {
- Q_UNUSED(name);
- if (m_empty) m_writer.writeStartElement("empty-line", m_level);
- m_writer.writeEndElement(0);
- }
- void FbSaveHandler::ParagHandler::start()
- {
- if (!m_empty) return;
- QString tag = "p";
- if (m_class.isEmpty()) {
- if (m_parent == "stanza") tag = "v";
- } else {
- tag = m_class;
- }
- m_writer.writeStartElement(tag, m_level);
- writeAtts(m_atts);
- m_empty = false;
- }
- //---------------------------------------------------------------------------
- // FbSaveHandler
- //---------------------------------------------------------------------------
- FbSaveHandler::FbSaveHandler(FbSaveWriter &writer)
- : FbHtmlHandler()
- , m_writer(writer)
- {
- }
- bool FbSaveHandler::comment(const QString& ch)
- {
- m_writer.writeComment(ch);
- return true;
- }
- void FbSaveHandler::onAnchor(int offset)
- {
- m_writer.setAnchor(offset - m_lastTextLength);
- }
- void FbSaveHandler::onFocus(int offset)
- {
- m_writer.setFocus(offset - m_lastTextLength);
- }
- FbXmlHandler::NodeHandler * FbSaveHandler::CreateRoot(const QString &name, const QXmlStreamAttributes &atts)
- {
- Q_UNUSED(atts);
- if (name == "html") return new RootHandler(m_writer, name);
- m_error = QObject::tr("The tag <html> was not found.");
- return 0;
- }
- void FbSaveHandler::setDocumentInfo(QWebFrame * frame)
- {
- QString info1 = qApp->applicationName() += QString(" ") += qApp->applicationVersion();
- QDateTime now = QDateTime::currentDateTime();
- QString info2 = now.toString("dd MMM yyyy");
- QString value = now.toString("yyyy-MM-dd hh:mm:ss");
- FbTextElement parent = frame->documentElement().findFirst("BODY");
- parent = parent["FB:DESCRIPTION"];
- parent = parent["FB:DOCUMENT-INFO"];
- FbTextElement child1 = parent["FB:PROGRAM-USED"];
- child1.setInnerXml(info1);
- FbTextElement child2 = parent["FB:DATE"];
- child2.setInnerXml(info2);
- child2.setAttribute("value", value);
- }
- bool FbSaveHandler::save()
- {
- FbTextPage *page = m_writer.view().page();
- if (!page) return false;
- QWebFrame *frame = page->mainFrame();
- if (!frame) return false;
- m_writer.writeStartDocument();
- if (page->isModified()) setDocumentInfo(frame);
- QString javascript = jScript("export.js");
- frame->addToJavaScriptWindowObject("handler", this);
- frame->evaluateJavaScript(javascript);
- m_writer.writeEndDocument();
- return true;
- }
|