vtableofcontent.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. #include "vtableofcontent.h"
  2. #include "vconstants.h"
  3. #include <QXmlStreamReader>
  4. #include <QDebug>
  5. VTableOfContent::VTableOfContent()
  6. : m_file(NULL), m_type(VTableOfContentType::Anchor)
  7. {
  8. }
  9. VTableOfContent::VTableOfContent(const VFile *p_file)
  10. : m_file(p_file), m_type(VTableOfContentType::Anchor)
  11. {
  12. }
  13. void VTableOfContent::update(const VFile *p_file,
  14. const QVector<VTableOfContentItem> &p_table,
  15. VTableOfContentType p_type)
  16. {
  17. m_file = p_file;
  18. m_table = p_table;
  19. m_type = p_type;
  20. }
  21. static bool parseTocUl(QXmlStreamReader &p_xml,
  22. QVector<VTableOfContentItem> &p_table,
  23. int p_level);
  24. static bool parseTocLi(QXmlStreamReader &p_xml,
  25. QVector<VTableOfContentItem> &p_table,
  26. int p_level)
  27. {
  28. Q_ASSERT(p_xml.isStartElement() && p_xml.name() == "li");
  29. if (p_xml.readNextStartElement()) {
  30. if (p_xml.name() == "a") {
  31. QString anchor = p_xml.attributes().value("href").toString().mid(1);
  32. QString name;
  33. if (p_xml.readNext()) {
  34. if (p_xml.tokenString() == "Characters") {
  35. name = p_xml.text().toString();
  36. } else if (!p_xml.isEndElement()) {
  37. qWarning() << "TOC HTML <a> should be ended by </a>" << p_xml.name();
  38. return false;
  39. }
  40. VTableOfContentItem header(name, p_level, anchor, p_table.size());
  41. p_table.append(header);
  42. } else {
  43. // Error
  44. return false;
  45. }
  46. } else if (p_xml.name() == "ul") {
  47. // Such as header 3 under header 1 directly
  48. VTableOfContentItem header(c_emptyHeaderName, p_level, "", p_table.size());
  49. p_table.append(header);
  50. parseTocUl(p_xml, p_table, p_level + 1);
  51. } else {
  52. qWarning() << "TOC HTML <li> should contain <a> or <ul>" << p_xml.name();
  53. return false;
  54. }
  55. }
  56. while (p_xml.readNext()) {
  57. if (p_xml.isEndElement()) {
  58. if (p_xml.name() == "li") {
  59. return true;
  60. }
  61. continue;
  62. }
  63. if (p_xml.name() == "ul") {
  64. // Nested unordered list
  65. if (!parseTocUl(p_xml, p_table, p_level + 1)) {
  66. return false;
  67. }
  68. } else {
  69. return false;
  70. }
  71. }
  72. return true;
  73. }
  74. static bool parseTocUl(QXmlStreamReader &p_xml,
  75. QVector<VTableOfContentItem> &p_table,
  76. int p_level)
  77. {
  78. bool ret = true;
  79. Q_ASSERT(p_xml.isStartElement() && p_xml.name() == "ul");
  80. while (p_xml.readNextStartElement()) {
  81. if (p_xml.name() == "li") {
  82. if (!parseTocLi(p_xml, p_table, p_level)) {
  83. ret = false;
  84. break;
  85. }
  86. } else {
  87. qWarning() << "TOC HTML <ul> should contain <li>" << p_xml.name();
  88. ret = false;
  89. break;
  90. }
  91. }
  92. return ret;
  93. }
  94. bool VTableOfContent::parseTableFromHtml(const QString &p_html)
  95. {
  96. bool ret = true;
  97. m_table.clear();
  98. if (!p_html.isEmpty()) {
  99. QXmlStreamReader xml(p_html);
  100. if (xml.readNextStartElement()) {
  101. if (xml.name() == "ul") {
  102. ret = parseTocUl(xml, m_table, 1);
  103. } else {
  104. qWarning() << "TOC HTML does not start with <ul>" << p_html;
  105. ret = false;
  106. }
  107. }
  108. if (xml.hasError()) {
  109. qWarning() << "fail to parse TOC in HTML" << p_html;
  110. ret = false;
  111. }
  112. }
  113. return ret;
  114. }
  115. int VTableOfContent::indexOfItemByAnchor(const QString &p_anchor) const
  116. {
  117. if (p_anchor.isEmpty()
  118. || isEmpty()
  119. || m_type != VTableOfContentType::Anchor) {
  120. return -1;
  121. }
  122. for (int i = 0; i < m_table.size(); ++i) {
  123. if (m_table[i].m_anchor == p_anchor) {
  124. return i;
  125. }
  126. }
  127. return -1;
  128. }
  129. int VTableOfContent::indexOfItemByBlockNumber(int p_blockNumber) const
  130. {
  131. if (p_blockNumber == -1
  132. || isEmpty()
  133. || m_type != VTableOfContentType::BlockNumber) {
  134. return -1;
  135. }
  136. for (int i = m_table.size() - 1; i >= 0; --i) {
  137. if (!m_table[i].isEmpty()
  138. && m_table[i].m_blockNumber <= p_blockNumber) {
  139. return i;
  140. }
  141. }
  142. return -1;
  143. }
  144. bool VTableOfContent::operator==(const VTableOfContent &p_outline) const
  145. {
  146. return m_file == p_outline.getFile()
  147. && m_type == p_outline.getType()
  148. && m_table == p_outline.getTable();
  149. }