1
0

fb2html.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. #include "fb2html.h"
  2. #include "fb2utils.h"
  3. #include "fb2text.hpp"
  4. //---------------------------------------------------------------------------
  5. // FbTextElement::Scheme
  6. //---------------------------------------------------------------------------
  7. FbTextElement::Scheme::Scheme()
  8. {
  9. m_types["BODY"]
  10. << Type("FB:DESCRIPTION", 1, 1)
  11. << Type("FB:BODY", 1, 1)
  12. ;
  13. m_types["FB:DESCRIPTION"]
  14. << Type("FB:TITLE-INFO", 1, 1)
  15. << Type("FB:SRC-TITLE-INFO", 0, 1)
  16. << Type("FB:DOCUMENT-INFO", 1, 1)
  17. << Type("FB:PUBLISH-INFO", 0, 1)
  18. << Type("FB:CUSTOM-INFO")
  19. ;
  20. m_types["FB:DOCUMENT-INFO"]
  21. << Type("FB:AUTHOR", 1, 1)
  22. << Type("FB:PROGRAM-USED", 0, 1)
  23. << Type("FB:DATE", 0, 1)
  24. ;
  25. m_types["FB:BODY"]
  26. << Type("IMG")
  27. << Type("FB:TITLE", 0, 1)
  28. << Type("FB:EPIGRAPH")
  29. << Type("FB:SECTION", 1, 0)
  30. ;
  31. m_types["FB:SECTION"]
  32. << Type("FB:TITLE", 1, 0)
  33. << Type("FB:EPIGRAPH")
  34. << Type("IMG")
  35. << Type("FB:ANNOTATION")
  36. << Type("FB:SECTION")
  37. ;
  38. m_types["FB:POEM"]
  39. << Type("FB:TITLE", 1, 0)
  40. << Type("FB:EPIGRAPH", 0, 0)
  41. << Type("FB:STANZA", 1, 0)
  42. ;
  43. m_types["FB:STANZA"]
  44. << Type("FB:TITLE", 1, 0)
  45. ;
  46. }
  47. const FbTextElement::TypeList * FbTextElement::Scheme::operator[](const QString &name) const
  48. {
  49. TypeMap::const_iterator it = m_types.find(name);
  50. if (it != m_types.end()) return &it.value();
  51. return 0;
  52. }
  53. //---------------------------------------------------------------------------
  54. // FbTextElement::Sublist
  55. //---------------------------------------------------------------------------
  56. FbTextElement::Sublist::Sublist(const TypeList &list, const QString &name)
  57. : m_list(list)
  58. , m_pos(list.begin())
  59. {
  60. TypeList::const_iterator empty = list.end();
  61. while (m_pos != list.end()) {
  62. if (m_pos->name() == name) break;
  63. m_pos++;
  64. }
  65. }
  66. FbTextElement::Sublist::operator bool() const
  67. {
  68. return m_pos != m_list.end();
  69. }
  70. bool FbTextElement::Sublist::operator!() const
  71. {
  72. return m_pos == m_list.end();
  73. }
  74. bool FbTextElement::Sublist::operator <(const FbTextElement &element) const
  75. {
  76. if (element.isNull()) return true;
  77. const QString name = element.nodeName();
  78. for (TypeList::const_iterator it = m_list.begin(); it != m_list.end(); it++) {
  79. if (it->name() == name) return m_pos < it;
  80. }
  81. return false;
  82. }
  83. //---------------------------------------------------------------------------
  84. // FbTextElement
  85. //---------------------------------------------------------------------------
  86. FbTextElement FbTextElement::operator[](const QString &name)
  87. {
  88. QString tagName = name.toUpper();
  89. FbTextElement child = firstChild();
  90. while (!child.isNull()) {
  91. if (child.tagName() == tagName) return child;
  92. child = child.nextSibling();
  93. }
  94. return insertInside(tagName, QString("<%1></%1>").arg(name));
  95. }
  96. QString FbTextElement::nodeName() const
  97. {
  98. QString n = tagName().toLower();
  99. return n.left(3) == "fb:" ? n.mid(3) : n;
  100. }
  101. void FbTextElement::getChildren(FbElementList &list)
  102. {
  103. FbTextElement child = firstChild();
  104. while (!child.isNull()) {
  105. QString tag = child.tagName();
  106. if (tag == "FB:DESCRIPTION") {
  107. // skip description
  108. } else if (tag.left(3) == "FB:") {
  109. list << child;
  110. } else if (tag == "IMG") {
  111. list << child;
  112. } else {
  113. child.getChildren(list);
  114. }
  115. child = child.nextSibling();
  116. }
  117. }
  118. int FbTextElement::childIndex() const
  119. {
  120. FbElementList list;
  121. parent().getChildren(list);
  122. int result = 0;
  123. FbElementList::const_iterator it;
  124. for (it = list.constBegin(); it != list.constEnd(); ++it) {
  125. if (*it == *this) return result;
  126. result++;
  127. }
  128. return -1;
  129. }
  130. bool FbTextElement::hasScheme() const
  131. {
  132. return subtypes();
  133. }
  134. const FbTextElement::TypeList * FbTextElement::subtypes() const
  135. {
  136. static Scheme scheme;
  137. return scheme[tagName()];
  138. }
  139. bool FbTextElement::hasSubtype(const QString &style) const
  140. {
  141. if (const TypeList * list = subtypes()) {
  142. for (TypeList::const_iterator item = list->begin(); item != list->end(); item++) {
  143. if (item->name() == style) return true;
  144. }
  145. }
  146. return false;
  147. }
  148. FbTextElement::TypeList::const_iterator FbTextElement::subtype(const TypeList &list, const QString &style)
  149. {
  150. for (TypeList::const_iterator item = list.begin(); item != list.end(); item++) {
  151. if (item->name() == style) return item;
  152. }
  153. return list.end();
  154. }
  155. FbTextElement FbTextElement::insertInside(const QString &style, const QString &html)
  156. {
  157. const TypeList * types = subtypes();
  158. if (!types) return FbTextElement();
  159. Sublist sublist(*types, style);
  160. if (sublist) {
  161. FbTextElement child = firstChild();
  162. if (sublist < child) {
  163. prependInside(html);
  164. return firstChild();
  165. }
  166. while (!child.isNull()) {
  167. FbTextElement subling = child.nextSibling();
  168. if (sublist < subling) {
  169. child.appendOutside(html);
  170. return child.nextSibling();
  171. }
  172. child = subling;
  173. }
  174. }
  175. appendInside(html);
  176. return lastChild();
  177. }
  178. QString FbTextElement::location()
  179. {
  180. return evaluateJavaScript("location(this)").toString();
  181. }
  182. void FbTextElement::select()
  183. {
  184. QString javascript = jScript("set_cursor.js");
  185. evaluateJavaScript(javascript);
  186. }
  187. bool FbTextElement::hasChild(const QString &style) const
  188. {
  189. FbTextElement child = firstChild();
  190. while (!child.isNull()) {
  191. if (child.tagName() == style) return true;
  192. child = child.nextSibling();
  193. }
  194. return false;
  195. }
  196. bool FbTextElement::isBody() const
  197. {
  198. return tagName() == "FB:BODY";
  199. }
  200. bool FbTextElement::isSection() const
  201. {
  202. return tagName() == "FB:SECTION";
  203. }
  204. bool FbTextElement::isTitle() const
  205. {
  206. return tagName() == "FB:TITLE";
  207. }
  208. bool FbTextElement::isStanza() const
  209. {
  210. return tagName() == "FB:STANZA";
  211. }
  212. bool FbTextElement::hasTitle() const
  213. {
  214. return hasChild("FB:TITLE");
  215. }
  216. int FbTextElement::index() const
  217. {
  218. int result = -1;
  219. FbTextElement prior = *this;
  220. while (!prior.isNull()) {
  221. prior = prior.previousSibling();
  222. result++;
  223. }
  224. return result;
  225. }
  226. FbTextElement FbTextElement::child(int index) const
  227. {
  228. FbTextElement result = firstChild();
  229. while (index > 0) {
  230. result = result.nextSibling();
  231. index--;
  232. }
  233. return index ? FbTextElement() : result;
  234. }
  235. //---------------------------------------------------------------------------
  236. // FbInsertCmd
  237. //---------------------------------------------------------------------------
  238. FbInsertCmd::FbInsertCmd(const FbTextElement &element)
  239. : QUndoCommand()
  240. , m_element(element)
  241. , m_parent(element.previousSibling())
  242. , m_inner(false)
  243. {
  244. if (m_parent.isNull()) {
  245. m_parent = m_element.parent();
  246. m_inner = true;
  247. }
  248. }
  249. void FbInsertCmd::redo()
  250. {
  251. if (m_inner) {
  252. m_parent.prependInside(m_element);
  253. } else {
  254. m_parent.appendOutside(m_element);
  255. }
  256. m_element.select();
  257. }
  258. void FbInsertCmd::undo()
  259. {
  260. m_element.takeFromDocument();
  261. }
  262. //---------------------------------------------------------------------------
  263. // FbReplaceCmd
  264. //---------------------------------------------------------------------------
  265. FbReplaceCmd::FbReplaceCmd(const FbTextElement &original, const FbTextElement &duplicate)
  266. : QUndoCommand()
  267. , m_original(original)
  268. , m_duplicate(duplicate)
  269. , m_update(false)
  270. {
  271. }
  272. void FbReplaceCmd::redo()
  273. {
  274. if (m_update) {
  275. m_original.prependOutside(m_duplicate);
  276. m_original.takeFromDocument();
  277. m_duplicate.select();
  278. } else {
  279. m_update = true;
  280. }
  281. }
  282. void FbReplaceCmd::undo()
  283. {
  284. m_duplicate.prependOutside(m_original);
  285. m_duplicate.takeFromDocument();
  286. m_original.select();
  287. }
  288. //---------------------------------------------------------------------------
  289. // FbDeleteCmd
  290. //---------------------------------------------------------------------------
  291. FbDeleteCmd::FbDeleteCmd(const FbTextElement &element)
  292. : QUndoCommand()
  293. , m_element(element)
  294. , m_parent(element.previousSibling())
  295. , m_inner(false)
  296. {
  297. if (m_parent.isNull()) {
  298. m_parent = element.parent();
  299. m_inner = true;
  300. }
  301. }
  302. void FbDeleteCmd::redo()
  303. {
  304. m_element.takeFromDocument();
  305. }
  306. void FbDeleteCmd::undo()
  307. {
  308. if (m_inner) {
  309. m_parent.prependInside(m_element);
  310. } else {
  311. m_parent.appendOutside(m_element);
  312. }
  313. m_element.select();
  314. }
  315. //---------------------------------------------------------------------------
  316. // FbMoveUpCmd
  317. //---------------------------------------------------------------------------
  318. FbMoveUpCmd::FbMoveUpCmd(const FbTextElement &element)
  319. : QUndoCommand()
  320. , m_element(element)
  321. {
  322. }
  323. void FbMoveUpCmd::redo()
  324. {
  325. FbTextElement subling = m_element.previousSibling();
  326. subling.prependOutside(m_element.takeFromDocument());
  327. }
  328. void FbMoveUpCmd::undo()
  329. {
  330. FbTextElement subling = m_element.nextSibling();
  331. subling.appendOutside(m_element.takeFromDocument());
  332. }
  333. //---------------------------------------------------------------------------
  334. // FbMoveLeftCmd
  335. //---------------------------------------------------------------------------
  336. FbMoveLeftCmd::FbMoveLeftCmd(const FbTextElement &element)
  337. : QUndoCommand()
  338. , m_element(element)
  339. , m_subling(element.previousSibling())
  340. , m_parent(element.parent())
  341. {
  342. }
  343. void FbMoveLeftCmd::redo()
  344. {
  345. m_parent.appendOutside(m_element.takeFromDocument());
  346. }
  347. void FbMoveLeftCmd::undo()
  348. {
  349. if (m_subling.isNull()) {
  350. m_parent.prependInside(m_element.takeFromDocument());
  351. } else {
  352. m_subling.appendOutside(m_element.takeFromDocument());
  353. }
  354. }
  355. //---------------------------------------------------------------------------
  356. // FbMoveRightCmd
  357. //---------------------------------------------------------------------------
  358. FbMoveRightCmd::FbMoveRightCmd(const FbTextElement &element)
  359. : QUndoCommand()
  360. , m_element(element)
  361. , m_subling(element.previousSibling())
  362. {
  363. }
  364. void FbMoveRightCmd::redo()
  365. {
  366. m_subling.appendInside(m_element.takeFromDocument());
  367. }
  368. void FbMoveRightCmd::undo()
  369. {
  370. m_subling.appendOutside(m_element.takeFromDocument());
  371. }