fb2read.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. #include <QtGui>
  2. #include <QTextEdit>
  3. #include <QtDebug>
  4. #include "fb2read.h"
  5. static QString Value(const QXmlAttributes &attributes, const QString &name)
  6. {
  7. int count = attributes.count();
  8. for (int i = 0; i < count; i++ ) {
  9. if (attributes.localName(i).compare(name, Qt::CaseInsensitive) == 0) {
  10. return attributes.value(i);
  11. }
  12. }
  13. return QString();
  14. }
  15. //---------------------------------------------------------------------------
  16. // Fb2Handler::ContentHandler
  17. //---------------------------------------------------------------------------
  18. Fb2Handler::ContentHandler::ContentHandler(Fb2Handler &owner)
  19. : m_owner(owner)
  20. , m_handler(NULL)
  21. {
  22. }
  23. Fb2Handler::ContentHandler::ContentHandler(ContentHandler &parent)
  24. : m_owner(parent.m_owner)
  25. , m_handler(NULL)
  26. {
  27. }
  28. Fb2Handler::ContentHandler::~ContentHandler()
  29. {
  30. if (m_handler) delete m_handler;
  31. }
  32. bool Fb2Handler::ContentHandler::doStart(const QString &name, const QXmlAttributes &attributes)
  33. {
  34. if (m_handler) return m_handler->doStart(name, attributes);
  35. m_handler = new ContentHandler(*this);
  36. }
  37. bool Fb2Handler::ContentHandler::doText(const QString &text)
  38. {
  39. if (m_handler) return m_handler->doText(text);
  40. return true;
  41. }
  42. bool Fb2Handler::ContentHandler::doEnd(const QString &name, bool & exit)
  43. {
  44. if (m_handler) {
  45. bool ok = m_handler->doEnd(name, exit);
  46. if (exit) {
  47. QTextCursor * cursor = getCursor();
  48. if (cursor) {
  49. QTextDocument * document = m_handler->getDocument();
  50. if (document) cursor->insertFragment(QTextDocumentFragment(document));
  51. }
  52. delete m_handler;
  53. m_handler = NULL;
  54. exit = false;
  55. }
  56. return ok;
  57. } else {
  58. exit = true;
  59. return true;
  60. }
  61. }
  62. //---------------------------------------------------------------------------
  63. // Fb2Handler::RootHandler
  64. //---------------------------------------------------------------------------
  65. Fb2Handler::RootHandler::KeywordHash::KeywordHash()
  66. {
  67. insert("stylesheet", Style);
  68. insert("description", Descr);
  69. insert("body", Body);
  70. insert("binary", Binary);
  71. }
  72. Fb2Handler::RootHandler::RootHandler(Fb2Handler & owner)
  73. : ContentHandler(owner)
  74. , m_document(owner.getDocument())
  75. , m_cursor(&m_document)
  76. {
  77. }
  78. Fb2Handler::RootHandler::Keyword Fb2Handler::RootHandler::toKeyword(const QString &name)
  79. {
  80. static KeywordHash map;
  81. KeywordHash::const_iterator i = map.find(name);
  82. return i == map.end() ? None : i.value();
  83. }
  84. bool Fb2Handler::RootHandler::doStart(const QString &name, const QXmlAttributes &attributes)
  85. {
  86. if (m_handler) return m_handler->doStart(name, attributes);
  87. switch (toKeyword(name)) {
  88. case Descr : return m_handler = new DescrHandler(*this);
  89. case Body : return m_handler = new BodyHandler(*this);
  90. case Binary : return m_handler = new BinaryHandler(*this, attributes);
  91. }
  92. qCritical() << QObject::tr("Unknown XML tag: %1").arg(name);
  93. return false;
  94. }
  95. //---------------------------------------------------------------------------
  96. // Fb2Handler::DescrHandler
  97. //---------------------------------------------------------------------------
  98. bool Fb2Handler::DescrHandler::doStart(const QString &name, const QXmlAttributes &attributes)
  99. {
  100. Q_UNUSED(name);
  101. Q_UNUSED(attributes);
  102. return true;
  103. }
  104. bool Fb2Handler::DescrHandler::doEnd(const QString &name, bool & exit)
  105. {
  106. Q_UNUSED(name);
  107. if (name == "description") exit = true;
  108. return true;
  109. }
  110. //---------------------------------------------------------------------------
  111. // Fb2Handler::BodyHandler
  112. //---------------------------------------------------------------------------
  113. Fb2Handler::BodyHandler::BodyHandler(ContentHandler &parent)
  114. : ContentHandler(parent)
  115. , m_document()
  116. , m_cursor(&m_document)
  117. {
  118. QTextBlockFormat blockFormat;
  119. blockFormat.setTopMargin(4);
  120. blockFormat.setBottomMargin(4);
  121. m_cursor.setBlockFormat(blockFormat);
  122. }
  123. Fb2Handler::BodyHandler::KeywordHash::KeywordHash()
  124. {
  125. insert("image", Image);
  126. insert("title", Title);
  127. insert("epigraph", Epigraph);
  128. insert("section", Section);
  129. insert("p", Paragraph);
  130. insert("poem", Poem);
  131. insert("stanza", Stanza);
  132. insert("v", Verse);
  133. }
  134. Fb2Handler::BodyHandler::Keyword Fb2Handler::BodyHandler::toKeyword(const QString &name)
  135. {
  136. static KeywordHash map;
  137. KeywordHash::const_iterator i = map.find(name);
  138. return i == map.end() ? None : i.value();
  139. }
  140. bool Fb2Handler::BodyHandler::doStart(const QString &name, const QXmlAttributes &attributes)
  141. {
  142. if (m_handler) return m_handler->doStart(name, attributes);
  143. switch (toKeyword(name)) {
  144. case Paragraph : m_handler = new TextHandler(*this, name); break;
  145. case Image : m_handler = new ImageHandler(*this, m_cursor, attributes); break;
  146. case Section : m_handler = new SectionHandler(*this, name, attributes); break;
  147. case Title : m_handler = new SectionHandler(*this, name, attributes); break;
  148. case Poem : m_handler = new SectionHandler(*this, name, attributes); break;
  149. case Stanza : m_handler = new SectionHandler(*this, name, attributes); break;
  150. default : m_handler = new TextHandler(*this, name); break;
  151. }
  152. return true;
  153. }
  154. bool Fb2Handler::BodyHandler::doText(const QString &text)
  155. {
  156. if (m_handler) return m_handler->doText(text);
  157. m_cursor.insertText(text);
  158. return true;
  159. }
  160. //---------------------------------------------------------------------------
  161. // Fb2Handler::SectionHandler
  162. //---------------------------------------------------------------------------
  163. Fb2Handler::SectionHandler::SectionHandler(ContentHandler &parent, const QString &name, const QXmlAttributes &attributes)
  164. : ContentHandler(parent)
  165. , m_document()
  166. , m_cursor(&m_document)
  167. , m_name(name)
  168. {
  169. QTextFrameFormat frameFormat;
  170. frameFormat.setBorder(1);
  171. frameFormat.setPadding(8);
  172. frameFormat.setTopMargin(4);
  173. frameFormat.setBottomMargin(4);
  174. m_cursor.insertFrame(frameFormat);
  175. QTextBlockFormat blockFormat;
  176. blockFormat.setTopMargin(4);
  177. blockFormat.setBottomMargin(4);
  178. m_cursor.setBlockFormat(blockFormat);
  179. }
  180. Fb2Handler::SectionHandler::KeywordHash::KeywordHash()
  181. {
  182. insert("image", Image);
  183. insert("section", Section);
  184. insert("title", Title);
  185. insert("p", Paragraph);
  186. insert("poem", Poem);
  187. insert("stanza", Stanza);
  188. insert("v", Verse);
  189. }
  190. Fb2Handler::SectionHandler::Keyword Fb2Handler::SectionHandler::toKeyword(const QString &name)
  191. {
  192. static KeywordHash map;
  193. KeywordHash::const_iterator i = map.find(name);
  194. return i == map.end() ? None : i.value();
  195. }
  196. bool Fb2Handler::SectionHandler::doStart(const QString &name, const QXmlAttributes &attributes)
  197. {
  198. if (m_handler) return m_handler->doStart(name, attributes);
  199. switch (toKeyword(name)) {
  200. case Paragraph : m_handler = new TextHandler(*this, name); break;
  201. case Image : m_handler = new ImageHandler(*this, m_cursor, attributes); break;
  202. case Section : m_handler = new SectionHandler(*this, name, attributes); break;
  203. case Title : m_handler = new SectionHandler(*this, name, attributes); break;
  204. case Poem : m_handler = new SectionHandler(*this, name, attributes); break;
  205. case Stanza : m_handler = new SectionHandler(*this, name, attributes); break;
  206. default : m_handler = new TextHandler(*this, name); break;
  207. }
  208. return true;
  209. }
  210. bool Fb2Handler::SectionHandler::doText(const QString &text)
  211. {
  212. if (m_handler) return m_handler->doText(text);
  213. m_cursor.insertText(text);
  214. return true;
  215. }
  216. //---------------------------------------------------------------------------
  217. // Fb2Handler::TextHandler
  218. //---------------------------------------------------------------------------
  219. Fb2Handler::TextHandler::TextHandler(ContentHandler &parent, const QString &name)
  220. : ContentHandler(parent)
  221. , m_document()
  222. , m_cursor(&m_document)
  223. , m_name(name)
  224. {
  225. QTextBlockFormat blockFormat;
  226. blockFormat.setTopMargin(4);
  227. blockFormat.setBottomMargin(4);
  228. m_cursor.setBlockFormat(blockFormat);
  229. }
  230. Fb2Handler::TextHandler::KeywordHash::KeywordHash()
  231. {
  232. insert("strong" , Strong);
  233. insert("emphasis" , Emphasis);
  234. insert("style" , Style);
  235. insert("a" , Anchor);
  236. insert("strikethrough" , Strikethrough);
  237. insert("sub" , Sub);
  238. insert("sup" , Sup);
  239. insert("code" , Code);
  240. insert("image" , Image);
  241. }
  242. Fb2Handler::TextHandler::Keyword Fb2Handler::TextHandler::toKeyword(const QString &name)
  243. {
  244. static KeywordHash map;
  245. KeywordHash::const_iterator i = map.find(name);
  246. return i == map.end() ? None : i.value();
  247. }
  248. bool Fb2Handler::TextHandler::doStart(const QString &name, const QXmlAttributes &attributes)
  249. {
  250. if (m_handler) return m_handler->doStart(name, attributes);
  251. switch (toKeyword(name)) {
  252. default : m_handler = new ContentHandler(*this); break;
  253. }
  254. return true;
  255. }
  256. bool Fb2Handler::TextHandler::doText(const QString &text)
  257. {
  258. if (m_handler) return m_handler->doText(text);
  259. m_cursor.insertText(text);
  260. return true;
  261. }
  262. //---------------------------------------------------------------------------
  263. // Fb2Handler::ImageHandler
  264. //---------------------------------------------------------------------------
  265. Fb2Handler::ImageHandler::ImageHandler(ContentHandler &parent, QTextCursor &cursor, const QXmlAttributes &attributes)
  266. : ContentHandler(parent)
  267. {
  268. QString image = Value(attributes, "href");
  269. while (image.left(1) == "#") image.remove(0, 1);
  270. if (!image.isEmpty()) cursor.insertImage(image);
  271. }
  272. bool Fb2Handler::ImageHandler::doStart(const QString &name, const QXmlAttributes &attributes)
  273. {
  274. Q_UNUSED(name);
  275. Q_UNUSED(attributes);
  276. return false;
  277. }
  278. //---------------------------------------------------------------------------
  279. // Fb2Handler::BinaryHandler
  280. //---------------------------------------------------------------------------
  281. Fb2Handler::BinaryHandler::BinaryHandler(ContentHandler &parent, const QXmlAttributes &attributes)
  282. : ContentHandler(parent), m_name(Value(attributes, "id"))
  283. {
  284. }
  285. bool Fb2Handler::BinaryHandler::doStart(const QString &name, const QXmlAttributes &attributes)
  286. {
  287. Q_UNUSED(name);
  288. Q_UNUSED(attributes);
  289. return false;
  290. }
  291. bool Fb2Handler::BinaryHandler::doText(const QString &text)
  292. {
  293. m_text += text;
  294. return true;
  295. }
  296. bool Fb2Handler::BinaryHandler::doEnd(const QString &name, bool & exit)
  297. {
  298. Q_UNUSED(name);
  299. QByteArray in; in.append(m_text);
  300. QImage img = QImage::fromData(QByteArray::fromBase64(in));
  301. if (!m_name.isEmpty()) m_owner.getDocument().addResource(QTextDocument::ImageResource, QUrl(m_name), img);
  302. exit = true;
  303. return true;
  304. }
  305. //---------------------------------------------------------------------------
  306. // Fb2Handler
  307. //---------------------------------------------------------------------------
  308. Fb2Handler::Fb2Handler(QTextDocument & document)
  309. : m_document(document)
  310. , m_handler(NULL)
  311. {
  312. document.clear();
  313. }
  314. Fb2Handler::~Fb2Handler()
  315. {
  316. if (m_handler) delete m_handler;
  317. }
  318. bool Fb2Handler::startElement(const QString & namespaceURI, const QString & localName, const QString &qName, const QXmlAttributes &attributes)
  319. {
  320. Q_UNUSED(namespaceURI);
  321. Q_UNUSED(localName);
  322. const QString name = qName.toLower();
  323. if (m_handler) return m_handler->doStart(name, attributes);
  324. if (name == "fictionbook") {
  325. m_handler = new RootHandler(*this);
  326. return true;
  327. } else {
  328. m_error = QObject::tr("The file is not an FB2 file.");
  329. return false;
  330. }
  331. }
  332. static bool isWhiteSpace(const QString &str)
  333. {
  334. return str.simplified().isEmpty();
  335. }
  336. bool Fb2Handler::characters(const QString &str)
  337. {
  338. QString s = str.simplified();
  339. if (s.isEmpty()) return true;
  340. if (isWhiteSpace(str.left(1))) s.prepend(" ");
  341. if (isWhiteSpace(str.right(1))) s.append(" ");
  342. return m_handler && m_handler->doText(s);
  343. }
  344. bool Fb2Handler::endElement(const QString & namespaceURI, const QString & localName, const QString &qName)
  345. {
  346. Q_UNUSED(namespaceURI);
  347. Q_UNUSED(localName);
  348. bool exit = false;
  349. return m_handler && m_handler->doEnd(qName.toLower(), exit);
  350. }
  351. bool Fb2Handler::fatalError(const QXmlParseException &exception)
  352. {
  353. qCritical() << QObject::tr("Parse error at line %1, column %2:\n%3")
  354. .arg(exception.lineNumber())
  355. .arg(exception.columnNumber())
  356. .arg(exception.message());
  357. return false;
  358. }
  359. QString Fb2Handler::errorString() const
  360. {
  361. return m_error;
  362. }
  363. /*
  364. QMessageBox::information(
  365. m_editor->window(),
  366. QObject::tr("fb2edit"),
  367. QObject::tr("%1=%2\n%1=%3")
  368. .arg(attributes.localName(i))
  369. .arg(attributes.value(i))
  370. .arg(image)
  371. );
  372. //! [2]
  373. QTextCursor cursor(editor->textCursor());
  374. cursor.movePosition(QTextCursor::Start);
  375. //! [2] //! [3]
  376. QTextFrame *topFrame = cursor.currentFrame();
  377. QTextFrameFormat topFrameFormat = topFrame->frameFormat();
  378. topFrameFormat.setPadding(16);
  379. topFrame->setFrameFormat(topFrameFormat);
  380. QTextCharFormat textFormat;
  381. QTextCharFormat boldFormat;
  382. boldFormat.setFontWeight(QFont::Bold);
  383. QTextFrameFormat referenceFrameFormat;
  384. referenceFrameFormat.setBorder(1);
  385. referenceFrameFormat.setPadding(8);
  386. referenceFrameFormat.setPosition(QTextFrameFormat::FloatRight);
  387. referenceFrameFormat.setWidth(QTextLength(QTextLength::PercentageLength, 40));
  388. cursor.insertFrame(referenceFrameFormat);
  389. cursor.insertText("A company", boldFormat);
  390. cursor.insertBlock();
  391. cursor.insertText("321 City Street");
  392. cursor.insertBlock();
  393. cursor.insertText("Industry Park");
  394. cursor.insertBlock();
  395. cursor.insertText("Another country");
  396. //! [3]
  397. //! [4]
  398. cursor.setPosition(topFrame->lastPosition());
  399. cursor.insertText(name, textFormat);
  400. QString line;
  401. foreach (line, address.split("\n")) {
  402. cursor.insertBlock();
  403. cursor.insertText(line);
  404. }
  405. //! [4] //! [5]
  406. cursor.insertBlock();
  407. cursor.insertBlock();
  408. QDate date = QDate::currentDate();
  409. cursor.insertText(tr("Date: %1").arg(date.toString("d MMMM yyyy")),
  410. textFormat);
  411. cursor.insertBlock();
  412. QTextFrameFormat bodyFrameFormat;
  413. bodyFrameFormat.setWidth(QTextLength(QTextLength::PercentageLength, 100));
  414. cursor.insertFrame(bodyFrameFormat);
  415. //! [5]
  416. //! [6]
  417. cursor.insertText(tr("I would like to place an order for the following "
  418. "items:"), textFormat);
  419. cursor.insertBlock();
  420. //! [6] //! [7]
  421. cursor.insertBlock();
  422. //! [7]
  423. //! [8]
  424. QTextTableFormat orderTableFormat;
  425. orderTableFormat.setAlignment(Qt::AlignHCenter);
  426. QTextTable *orderTable = cursor.insertTable(1, 2, orderTableFormat);
  427. QTextFrameFormat orderFrameFormat = cursor.currentFrame()->frameFormat();
  428. orderFrameFormat.setBorder(1);
  429. cursor.currentFrame()->setFrameFormat(orderFrameFormat);
  430. //! [8]
  431. //! [9]
  432. cursor = orderTable->cellAt(0, 0).firstCursorPosition();
  433. cursor.insertText(tr("Product"), boldFormat);
  434. cursor = orderTable->cellAt(0, 1).firstCursorPosition();
  435. cursor.insertText(tr("Quantity"), boldFormat);
  436. //! [9]
  437. //! [10]
  438. for (int i = 0; i < orderItems.count(); ++i) {
  439. QPair<QString,int> item = orderItems[i];
  440. int row = orderTable->rows();
  441. orderTable->insertRows(row, 1);
  442. cursor = orderTable->cellAt(row, 0).firstCursorPosition();
  443. cursor.insertText(item.first, textFormat);
  444. cursor = orderTable->cellAt(row, 1).firstCursorPosition();
  445. cursor.insertText(QString("%1").arg(item.second), textFormat);
  446. }
  447. //! [10]
  448. //! [11]
  449. cursor.setPosition(topFrame->lastPosition());
  450. cursor.insertBlock();
  451. //! [11] //! [12]
  452. cursor.insertText(tr("Please update my records to take account of the "
  453. "following privacy information:"));
  454. cursor.insertBlock();
  455. //! [12]
  456. //! [13]
  457. QTextTable *offersTable = cursor.insertTable(2, 2);
  458. cursor = offersTable->cellAt(0, 1).firstCursorPosition();
  459. cursor.insertText(tr("I want to receive more information about your "
  460. "company's products and special offers."), textFormat);
  461. cursor = offersTable->cellAt(1, 1).firstCursorPosition();
  462. cursor.insertText(tr("I do not want to receive any promotional information "
  463. "from your company."), textFormat);
  464. if (sendOffers)
  465. cursor = offersTable->cellAt(0, 0).firstCursorPosition();
  466. else
  467. cursor = offersTable->cellAt(1, 0).firstCursorPosition();
  468. cursor.insertText("X", boldFormat);
  469. //! [13]
  470. //! [14]
  471. cursor.setPosition(topFrame->lastPosition());
  472. cursor.insertBlock();
  473. cursor.insertText(tr("Sincerely,"), textFormat);
  474. cursor.insertBlock();
  475. cursor.insertBlock();
  476. cursor.insertBlock();
  477. cursor.insertText(name);
  478. printAction->setEnabled(true);
  479. }
  480. //! [14]
  481. */