diff --git a/src/lay/lay/layGSIHelpProvider.cc b/src/lay/lay/layGSIHelpProvider.cc index b8e33266b..08637a407 100644 --- a/src/lay/lay/layGSIHelpProvider.cc +++ b/src/lay/lay/layGSIHelpProvider.cc @@ -1186,6 +1186,10 @@ GSIHelpProvider::produce_class_doc (const std::string &cls) const os << "

" << tl::to_string (QObject::tr ("Detailed description")) << "

" << std::endl; + std::string prev_title; + + os << ""; + for (std::multimap >::const_iterator i = mm.begin (); i != mm.end (); ++i, ++n) { const gsi::MethodBase::MethodSynonym &syn = i->second.first->begin_synonyms () [i->second.second]; @@ -1195,14 +1199,23 @@ GSIHelpProvider::produce_class_doc (const std::string &cls) const os << "" << "first) << "\"/>" << "first) << "\" name=\"" << escape_xml (cls) << "#" << escape_xml (i->first) << "\"/>" << std::endl; - - os << "

"; + + os << "

"; + } + os << "
"; + if (i->first != prev_title) { + os << "

" << escape_xml (i->first) << "

" << std::endl; + prev_title = i->first; + } + os << "
"; + + os << "

" << tl::to_string (QObject::tr ("Signature")) << ": "; std::string attr = method_attributes (i->second.first, method_doc); if (! attr.empty ()) { os << "[" << escape_xml (attr) << "] "; } - os << method_return (i->second.first, method_doc, true) << " " << escape_xml (i->first) << method_arguments (i->second.first, cls_obj, method_doc, true, ""); - os << "" << std::endl; + os << method_return (i->second.first, method_doc, true) << " " << escape_xml (i->first) << " " << method_arguments (i->second.first, cls_obj, method_doc, true, ""); + os << "

" << std::endl; + + os << "
"; os << "

" << tl::to_string (QObject::tr ("Description")) << ": " << replace_references (escape_xml (method_doc.brief_doc), cls_obj) << "

" << std::endl; @@ -1237,8 +1250,13 @@ GSIHelpProvider::produce_class_doc (const std::string &cls) const } } + os << "
"; + os << "
"; + os << "" << std::endl; return os.str (); diff --git a/src/lay/lay/layHelpSource.cc b/src/lay/lay/layHelpSource.cc index a5d7803ff..59304dddb 100644 --- a/src/lay/lay/layHelpSource.cc +++ b/src/lay/lay/layHelpSource.cc @@ -195,6 +195,7 @@ static QString class_doc_element = QString::fromUtf8 ("class_doc"); static QString doc_element = QString::fromUtf8 ("doc"); static QString h2_element = QString::fromUtf8 ("h2"); static QString h2_index_element = QString::fromUtf8 ("h2-index"); +static QString h3_element = QString::fromUtf8 ("h3"); static QString href_attribute = QString::fromUtf8 ("href"); static QString name_attribute = QString::fromUtf8 ("name"); static QString title_attribute = QString::fromUtf8 ("title"); @@ -541,10 +542,19 @@ HelpSource::get_css (const std::string &u) std::string HelpSource::get (const std::string &u) { - return process (get_dom (u), u); + BrowserOutline ol; + return process (get_dom (u), u, ol); } -std::string +BrowserOutline +HelpSource::get_outline (const std::string &u) +{ + BrowserOutline ol; + process (get_dom (u), u, ol); + return ol; +} + +std::string HelpSource::next_topic (const std::string &url) { std::string u = tl::to_string (QUrl::fromEncoded (url.c_str ()).path ()); @@ -724,7 +734,7 @@ HelpSource::parent_of (const std::string &path) } std::string -HelpSource::process (const QDomDocument &doc, const std::string &path) +HelpSource::process (const QDomDocument &doc, const std::string &path, BrowserOutline &ol) { QBuffer output; output.open (QIODevice::WriteOnly); @@ -733,7 +743,7 @@ HelpSource::process (const QDomDocument &doc, const std::string &path) QXmlStreamWriter writer (&output); writer.writeStartDocument (QString::fromUtf8 ("1.0")); - process (doc.documentElement (), path, writer); + process (doc.documentElement (), path, writer, ol); writer.writeEndDocument (); output.close (); @@ -742,7 +752,7 @@ HelpSource::process (const QDomDocument &doc, const std::string &path) } void -HelpSource::process_child_nodes (const QDomElement &element, const std::string &path, QXmlStreamWriter &writer) +HelpSource::process_child_nodes (const QDomElement &element, const std::string &path, QXmlStreamWriter &writer, BrowserOutline &ol) { if (element.isNull ()) { return; @@ -750,7 +760,7 @@ HelpSource::process_child_nodes (const QDomElement &element, const std::string & for (QDomNode n = element.firstChild (); ! n.isNull (); n = n.nextSibling ()) { if (n.isElement ()) { - process (n.toElement (), path, writer); + process (n.toElement (), path, writer, ol); } else if (n.isComment ()) { // ignore } else if (n.isCDATASection ()) { @@ -762,7 +772,7 @@ HelpSource::process_child_nodes (const QDomElement &element, const std::string & } void -HelpSource::writeElement (const QDomElement &element, const std::string &path, QXmlStreamWriter &writer) +HelpSource::writeElement (const QDomElement &element, const std::string &path, QXmlStreamWriter &writer, BrowserOutline &ol) { // simply pass all other elements writer.writeStartElement (element.nodeName ()); @@ -778,13 +788,26 @@ HelpSource::writeElement (const QDomElement &element, const std::string &path, Q } } - process_child_nodes (element, path, writer); + process_child_nodes (element, path, writer, ol); writer.writeEndElement (); } +static void +add_outline_at_level (int i, BrowserOutline &ol, const BrowserOutline &child) +{ + if (i == 0) { + ol.add_child (child); + } else if (ol.begin () != ol.end ()) { + add_outline_at_level (i - 1, *(--ol.end ()), child); + } else { + ol.add_child (BrowserOutline (tl::to_string (QObject::tr ("(empty")), std::string ())); + add_outline_at_level (i - 1, *(--ol.end ()), child); + } +} + void -HelpSource::process (const QDomElement &element, const std::string &path, QXmlStreamWriter &writer) +HelpSource::process (const QDomElement &element, const std::string &path, QXmlStreamWriter &writer, BrowserOutline &ol) { if (element.localName () == keyword_element) { @@ -805,7 +828,7 @@ HelpSource::process (const QDomElement &element, const std::string &path, QXmlSt writer.writeEndElement (); // replace .. by content - process_child_nodes (element, path, writer); + process_child_nodes (element, path, writer, ol); } else if (element.localName () == h2_index_element) { @@ -822,21 +845,36 @@ HelpSource::process (const QDomElement &element, const std::string &path, QXmlSt } writer.writeEndElement (); - } else if (element.localName () == h2_element) { + } else if (element.localName () == h2_element || element.localName () == h3_element) { - // replace "h2" by "

" + int level = (element.localName () == h2_element ? 1 : 2); + + QString name = element.localName () + QString::fromUtf8 ("-") + QString::number (element.lineNumber ()); + QString title = element.text (); + + std::string path_wo_anchor = path; + std::string::size_type n; + if ((n = path.rfind ("#")) != std::string::npos) { + path_wo_anchor = std::string (path, 0, n); + } + + add_outline_at_level (level, ol, BrowserOutline (tl::to_string (title), path_wo_anchor + "#" + tl::to_string (name))); + + // replace "h2"/"h3" by "

" writer.writeStartElement (QString::fromUtf8 ("a")); - writer.writeAttribute (QString::fromUtf8 ("name"), element.localName () + QString::fromUtf8 ("-") + QString::number (element.lineNumber ())); + writer.writeAttribute (QString::fromUtf8 ("name"), name); writer.writeEndElement (); writer.writeStartElement (element.localName ()); - process_child_nodes (element, path, writer); + process_child_nodes (element, path, writer, ol); writer.writeEndElement (); } else if (element.localName () == title_element) { + add_outline_at_level (0, ol, BrowserOutline (tl::to_string (element.text ()), path)); + // replace "title" by "h1" writer.writeStartElement (QString::fromUtf8 ("h1")); - process_child_nodes (element, path, writer); + process_child_nodes (element, path, writer, ol); writer.writeEndElement (); } else if (element.localName () == doc_element) { @@ -887,7 +925,7 @@ HelpSource::process (const QDomElement &element, const std::string &path, QXmlSt } } writer.writeEndElement (); - process_child_nodes (element, path, writer); + process_child_nodes (element, path, writer, ol); writer.writeEndElement (); writer.writeEndElement (); @@ -895,7 +933,7 @@ HelpSource::process (const QDomElement &element, const std::string &path, QXmlSt // replace "topics" by "ul" writer.writeStartElement (QString::fromUtf8 ("ul")); - process_child_nodes (element, path, writer); + process_child_nodes (element, path, writer, ol); writer.writeEndElement (); } else if (element.localName () == topic_ref_element) { @@ -929,7 +967,7 @@ HelpSource::process (const QDomElement &element, const std::string &path, QXmlSt if (new_el.hasAttribute (href_attribute)) { new_el.setAttribute (href_attribute, relative_url (path, new_el.attribute (href_attribute))); } - writeElement (new_el, path, writer); + writeElement (new_el, path, writer, ol); } else if (element.localName () == img_element) { @@ -937,7 +975,7 @@ HelpSource::process (const QDomElement &element, const std::string &path, QXmlSt if (new_el.hasAttribute (src_attribute)) { new_el.setAttribute (src_attribute, relative_url (path, new_el.attribute (src_attribute))); } - writeElement (new_el, path, writer); + writeElement (new_el, path, writer, ol); } else if (element.localName () == class_doc_element) { @@ -970,7 +1008,7 @@ HelpSource::process (const QDomElement &element, const std::string &path, QXmlSt } else { // simply pass all other elements - writeElement (element, path, writer); + writeElement (element, path, writer, ol); } } diff --git a/src/lay/lay/layHelpSource.h b/src/lay/lay/layHelpSource.h index 099f67c8d..67f8bb766 100644 --- a/src/lay/lay/layHelpSource.h +++ b/src/lay/lay/layHelpSource.h @@ -78,6 +78,7 @@ public: ~HelpSource(); virtual std::string get (const std::string &url); + virtual BrowserOutline get_outline (const std::string &url); virtual QImage get_image (const std::string &url); virtual std::string get_css (const std::string &url); @@ -163,11 +164,11 @@ private: QDomDocument produce_main_index (); void produce_index_file (const std::string &path); void initialize_index (); - std::string process (const QDomDocument &doc, const std::string &path); - void process_child_nodes (const QDomElement &element, const std::string &path, QXmlStreamWriter &writer); - void process (const QDomElement &element, const std::string &path, QXmlStreamWriter &writer); + std::string process (const QDomDocument &doc, const std::string &path, BrowserOutline &ol); + void process_child_nodes (const QDomElement &element, const std::string &path, QXmlStreamWriter &writer, BrowserOutline &old); + void process (const QDomElement &element, const std::string &path, QXmlStreamWriter &writer, BrowserOutline &ol); std::string read (const std::string &u); - void writeElement (const QDomElement &element, const std::string &path, QXmlStreamWriter &writer); + void writeElement (const QDomElement &element, const std::string &path, QXmlStreamWriter &writer, BrowserOutline &ol); void scan (const std::string &path, tl::AbsoluteProgress &progress); void scan_child_nodes (const QDomElement &element, const std::string &path, std::vector &subtopics, std::string &title, std::string §ion); void scan (const QDomElement &element, const std::string &path, std::vector &subtopics, std::string &title, std::string §ion); diff --git a/src/laybasic/laybasic/BrowserPanel.ui b/src/laybasic/laybasic/BrowserPanel.ui index 8b588cb12..af94c7c61 100644 --- a/src/laybasic/laybasic/BrowserPanel.ui +++ b/src/laybasic/laybasic/BrowserPanel.ui @@ -1,162 +1,257 @@ - + + BrowserPanel - - + + 0 0 - 482 - 414 + 826 + 580 - + Form - - + + 0 - + + 0 + + + 0 + + + 0 + + 2 - - - - TextLabel + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 6 + 20 + + + + + + + + Next Topic + + + ... + + + + :/next_topic.png:/next_topic.png + + + + 24 + 24 + + + + true - - - - - 7 - 0 + + + + + 0 + 50 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + + 0 + 0 + + + + + 0 + 0 + + + + false + + + true + + + false + + + + 1 + + + + + + + 4 + 0 + + + + + + + + + + + + 0 0 - - - - Previous Topic - - - ... - - - :/prev_topic.png - - - - 24 - 24 - - - - true - - - - - - - Next Topic - - - ... - - - :/next_topic.png - - - - 24 - 24 - - - - true - - - - - - + + + Back - + ... - - :/back.png + + + :/back.png:/back.png - + 24 24 - + true - - - - Forward - - - ... - - - :/forward.png - - - - 24 - 24 - - - - true - - - - - - + + + Home - + ... - - :/home.png + + + :/home.png:/home.png - + 24 24 - + true - + + + + Previous Topic + + + ... + + + + :/prev_topic.png:/prev_topic.png + + + + 24 + 24 + + + + true + + + + + + + Forward + + + ... + + + + :/forward.png:/forward.png + + + + 24 + 24 + + + + true + + + + - + Qt::Horizontal - + QSizePolicy::MinimumExpanding - + 20 20 @@ -164,15 +259,22 @@ - + + + + TextLabel + + + + - + Qt::Horizontal - + QSizePolicy::Fixed - + 6 20 @@ -180,25 +282,6 @@ - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 6 - 20 - - - - - - - @@ -213,10 +296,9 @@ back_pb forward_pb home_pb - browser - + diff --git a/src/laybasic/laybasic/layBrowserPanel.cc b/src/laybasic/laybasic/layBrowserPanel.cc index 6d3ac61b7..5b1df30fa 100644 --- a/src/laybasic/laybasic/layBrowserPanel.cc +++ b/src/laybasic/laybasic/layBrowserPanel.cc @@ -33,6 +33,8 @@ # include #endif +#include + namespace lay { @@ -80,6 +82,7 @@ BrowserPanel::init () connect (mp_ui->browser, SIGNAL (textChanged ()), this, SLOT (text_changed ())); connect (mp_ui->browser, SIGNAL (backwardAvailable (bool)), mp_ui->back_pb, SLOT (setEnabled (bool))); connect (mp_ui->browser, SIGNAL (forwardAvailable (bool)), mp_ui->forward_pb, SLOT (setEnabled (bool))); + connect (mp_ui->outline_tree, SIGNAL (itemActivated (QTreeWidgetItem *, int)), this, SLOT (outline_item_clicked (QTreeWidgetItem *))); mp_ui->searchEdit->hide (); @@ -117,6 +120,15 @@ BrowserPanel::text_changed () } } +void +BrowserPanel::outline_item_clicked (QTreeWidgetItem *item) +{ + QString url = item->data (0, Qt::UserRole).toString (); + if (! url.isEmpty ()) { + load (tl::to_string (url)); + } +} + void BrowserPanel::load (const std::string &s) { @@ -157,6 +169,17 @@ BrowserPanel::set_home (const std::string &url) { m_home = url; home (); + + // NOTE: we take this call as a hint that the panel is set up and about to be + // shown. We use this opportunity to resize the outline pane. + mp_ui->outline_tree->header ()->hide (); + QList sizes = mp_ui->splitter->sizes (); + if (sizes.size () >= 2) { + int size_outline = 150; + sizes[1] += sizes[0] - size_outline; + sizes[0] = size_outline; + } + mp_ui->splitter->setSizes (sizes); } void @@ -212,7 +235,7 @@ BrowserPanel::home () QSize BrowserPanel::sizeHint () const { - return QSize (600, 400); + return QSize (800, 600); } void @@ -266,6 +289,54 @@ BrowserPanel::set_label (const std::string &text) mp_ui->label->setVisible (! text.empty ()); } +static void +update_item_with_outline (const BrowserOutline &ol, QTreeWidgetItem *item) +{ + item->setData (0, Qt::UserRole, tl::to_qstring (ol.url ())); + item->setData (0, Qt::DisplayRole, tl::to_qstring (ol.title ())); + item->setData (0, Qt::ToolTipRole, tl::to_qstring (ol.title ())); + + int i = 0; + for (BrowserOutline::const_child_iterator c = ol.begin (); c != ol.end (); ++c, ++i) { + if (item->childCount () <= i) { + new QTreeWidgetItem (item); + } + update_item_with_outline (*c, item->child (i)); + } + + while (item->childCount () > i) { + delete item->child (i); + } +} + +void +BrowserPanel::set_outline (const BrowserOutline &ol) +{ + if (ol.begin () == ol.end ()) { + + mp_ui->outline_tree->hide (); + + } else { + + mp_ui->outline_tree->show (); + + int i = 0; + for (BrowserOutline::const_child_iterator c = ol.begin (); c != ol.end (); ++c, ++i) { + if (mp_ui->outline_tree->topLevelItemCount () <= i) { + new QTreeWidgetItem (mp_ui->outline_tree); + } + update_item_with_outline (*c, mp_ui->outline_tree->topLevelItem (i)); + } + + while (mp_ui->outline_tree->topLevelItemCount () > i) { + delete mp_ui->outline_tree->topLevelItem (i); + } + + mp_ui->outline_tree->expandAll (); + + } +} + QVariant BrowserPanel::loadResource (int type, const QUrl &url) { @@ -309,14 +380,17 @@ BrowserPanel::loadResource (int type, const QUrl &url) std::string u = tl::to_string (url.toString ()); std::string s; std::string nu, pu; + BrowserOutline ol; if (u == m_cached_url) { s = m_cached_text; nu = m_cached_next_url; pu = m_cached_prev_url; + ol = m_cached_outline; } else { s = mp_source->get (u); nu = mp_source->next_topic (u); pu = mp_source->prev_topic (u); + ol = mp_source->get_outline (u); } if (s.empty ()) { s = " "; // QTextBrowser needs at least something @@ -332,6 +406,7 @@ BrowserPanel::loadResource (int type, const QUrl &url) m_cached_url = u; m_cached_next_url = nu; m_cached_prev_url = pu; + m_cached_outline = ol; } ret = QVariant (tl::to_qstring (s)); @@ -346,6 +421,9 @@ BrowserPanel::loadResource (int type, const QUrl &url) mp_ui->next_topic_pb->setEnabled (! nu.empty ()); } + // push the outline + set_outline (ol); + END_PROTECTED QApplication::restoreOverrideCursor (); @@ -390,6 +468,12 @@ BrowserSource::get_image (const std::string & /*url*/) return QImage (); } +BrowserOutline +BrowserSource::get_outline (const std::string & /*url*/) +{ + return BrowserOutline (); +} + std::string BrowserSource::get (const std::string & /*url*/) { diff --git a/src/laybasic/laybasic/layBrowserPanel.h b/src/laybasic/laybasic/layBrowserPanel.h index b5c33015a..cdcfd7404 100644 --- a/src/laybasic/laybasic/layBrowserPanel.h +++ b/src/laybasic/laybasic/layBrowserPanel.h @@ -32,8 +32,11 @@ #include #include +#include #include +class QTreeWidgetItem; + namespace Ui { class BrowserPanel; @@ -44,6 +47,121 @@ namespace lay class BrowserPanel; +/** + * @brief Specifies the outline of the document + * + * The outline is a hierarchical tree of items. Each node has a title, a URL to navigate to and + * optional child items. + */ +class LAYBASIC_PUBLIC BrowserOutline +{ +public: + typedef std::list::const_iterator const_child_iterator; + typedef std::list::iterator child_iterator; + + /** + * @brief Default constructor: creates an empty browser outline + */ + BrowserOutline () + { + // .. nothing yet .. + } + + /** + * @brief Default constructor: creates a single entry with title and URL + */ + BrowserOutline (const std::string &title, const std::string &url) + : m_title (title), m_url (url) + { + // .. nothing yet .. + } + + /** + * @brief Gets the title + */ + const std::string &title () const + { + return m_title; + } + + /** + * @brief Sets the title + */ + void set_title (const std::string &t) + { + m_title = t; + } + + /** + * @brief Gets the URL + */ + const std::string &url () const + { + return m_url; + } + + /** + * @brief Sets the URL + */ + void set_url (const std::string &u) + { + m_url = u; + } + + /** + * @brief Returns the begin iterator for the children + */ + const_child_iterator begin () const + { + return m_children.begin (); + } + + /** + * @brief Returns the end iterator for the children + */ + const_child_iterator end () const + { + return m_children.end (); + } + + /** + * @brief Returns the non-const begin iterator for the children + */ + child_iterator begin () + { + return m_children.begin (); + } + + /** + * @brief Returns the non-const end iterator for the children + */ + child_iterator end () + { + return m_children.end (); + } + + /** + * @brief Adds a child entry at the end of the list + */ + void add_child (const BrowserOutline &ol) + { + m_children.push_back (ol); + } + + /** + * @brief Clears the child list of the node + */ + void clear_children () + { + m_children.clear (); + } + +private: + std::string m_title; + std::string m_url; + std::list m_children; +}; + /** * @brief The source for BrowserDialog's "int" URL's */ @@ -76,6 +194,16 @@ public: */ virtual std::string get (const std::string &url); + /** + * @brief Gets the outline object if the source provides one + * + * The outline is a dictionary of item and subitems, each with a title and a + * URL to navigate to if selected. + * + * If an empty outline is returned, no outline is shown. + */ + virtual BrowserOutline get_outline (const std::string &url); + /** * @brief Get the image for a given "int" URL in an image */ @@ -205,6 +333,11 @@ public: */ void set_label (const std::string &text); + /** + * @brief Sets the outline + */ + void set_outline (const BrowserOutline &ol); + /** * @brief Enables the search bx and sets the Url and query item name for the search */ @@ -255,6 +388,7 @@ public slots: protected slots: void search_edited (); void text_changed (); + void outline_item_clicked (QTreeWidgetItem *item); protected: virtual QVariant loadResource (int type, const QUrl &url); @@ -268,6 +402,7 @@ private: std::string m_cached_text; std::string m_cached_next_url; std::string m_cached_prev_url; + BrowserOutline m_cached_outline; Ui::BrowserPanel *mp_ui; bool m_schedule_back; tl::DeferredMethod m_back_dm;