Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. no pictures in helpfile
Forum Updated to NodeBB v4.3 + New Features

no pictures in helpfile

Scheduled Pinned Locked Moved Solved General and Desktop
8 Posts 3 Posters 528 Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • D Offline
    D Offline
    django.Reinhard
    wrote on last edited by
    #1

    Hi,

    I'm currently trying to familiarize myself with the Qt help system. As I understand it, the help system is built on top of the qdoc system.

    So I have created some files for qdoc. The generation of the html files works and the files also look as expected.

    However, when I generate the help file and view it with QtAssistant, there is not a single image. I searched for additional information, but my uncle Ducky hardly finds any entries about qt-helpfiles.

    I vaguely remember reading somewhere that the images should be in the same directory as the html files, so I tried copying the images. Didn't make any difference, unfortunately.

    directory layout from QtCreator:

    Dirs.png

    My qdoc config file:

    project     = FalconView
    description = controlcenter for linuxcnc
    outputdir   = html
    headerdirs  = src
    sourcedirs  = src
    imagedirs   = src/images
    exampledirs = .
    version     = 0.1
    headers.fileextensions  = "*.h *.hpp"
    sources.fileextensions  = "*.cpp *.qdoc"
    qhp.FalconView.namespace     = de.schwarzrot.falconview.0.1
    qhp.FalconView.virtualFolder = FalconView
    qhp.FalconView.indexTitle    = User Guide
    

    the help project file:

    <?xml version="1.0" encoding="utf-8" ?>
    <QtHelpProject version="1.0">
        <namespace>de.schwarzrot.falconview.0.1</namespace>
        <virtualFolder>FalconView</virtualFolder>
        <filterSection>
            <filterAttribute>FalconView</filterAttribute>
            <filterAttribute>0.1</filterAttribute>
            <toc>
                <section title="User Guide" ref="index.html">
                    <section title="start the engine" ref="startup.html"/>
                    <section title="reference" ref="reference.html"/>
                    <section title="use case" ref="usage.html"/>
                </section>
            </toc>
            <keywords>
                <keyword name="fileManager" id="fileManager" ref="fileManager.html"/>
            </keywords>
            <files>
                <file>*.html</file>
            </files>
        </filterSection>
    </QtHelpProject>
    

    ... and here's how I build the help-file:

    #!/bin/bash
    project=FalconView
    
    qdoc ${project}.qdocconf
    cp ${project}.qhp html
    cd html
    cp -a images/* .
    qhelpgenerator ${project}.qhp
    mv ${project}.qch ..
    

    As mentioned - I tried with and without image copying.

    May be the biggest question for my understanding:
    Are the images put into the compressed helpfile, or do I have to provied them to the helpviewer, like any HTML-browser does?

    1 Reply Last reply
    0
    • sierdzioS Offline
      sierdzioS Offline
      sierdzio
      Moderators
      wrote on last edited by
      #2

      qdoc is an internal tool of Qt, do not use it for other projects. Use Doxygen instead.

      (Z(:^

      artwawA 1 Reply Last reply
      1
      • sierdzioS sierdzio

        qdoc is an internal tool of Qt, do not use it for other projects. Use Doxygen instead.

        artwawA Offline
        artwawA Offline
        artwaw
        wrote on last edited by
        #3

        @sierdzio said in no pictures in helpfile:

        qdoc is an internal tool of Qt

        That's new to me, it is not mentioned in the documentation or did I miss it through all the years?

        For more information please re-read.

        Kind Regards,
        Artur

        sierdzioS 1 Reply Last reply
        0
        • D Offline
          D Offline
          django.Reinhard
          wrote on last edited by
          #4

          Hi,

          thank you for your attention!

          @sierdzio said in no pictures in helpfile:

          qdoc is an internal tool of Qt, do not use it for other projects.

          Hm, my expectations are not very high, so qdoc works fine for me and I have no issues.

          Opposed to the helpengine.
          I tried to follow the Qt example "contextsensitivehelp", but it does not work at all for me. Documentation says, that I should test helpfile-creation by loading it in QtAssistant.

          Well, QtAssistant shows the pages, but without pictures. But when I use helpengine like Qt examples, I have no documents, no keywords, nothing.
          Even if I use the same url, that QtAssistant claims to use, I get no document in my app. But setup returns ok.

          So I don't know what's wrong.
          I'll gonna try to build my own help engine.

          1 Reply Last reply
          0
          • D Offline
            D Offline
            django.Reinhard
            wrote on last edited by
            #5

            @django-Reinhard said in no pictures in helpfile:

            I'll gonna try to build my own help engine.

            Done :)

            My uncle duck guided me to stackoverflow (last post), and with that info, it was straight forward. Qt already has all needed stuff - only had to assemble it new.

            According to my tests, I can answer my initial question:

            @django-Reinhard said in no pictures in helpfile:

            Are the images put into the compressed helpfile, or do I have to provied them to the helpviewer, like any HTML-browser does?

            Aperently not.

            Ok, what did I do?
            I have the qdoc-files in directory docs, which has a subdirectory images.
            qdoc then creates a directory 'html' with a subdirectory 'images' and copies all images to html/images.

            So I created a zip-file from the qdoc output - means all generated html-files and the image subdirectory.

            Base for help output is QTextBrowser. It already has complete functionality. Subclassing is anyway required to be able to override QTextBrowser::loadResource.

            So the minimal project with a working helpEngine looks like:

            MainWindow declaration:

            class MainWindow : public QMainWindow
            {
              Q_OBJECT
            public:
              explicit MainWindow(QWidget *parent = nullptr);
              virtual ~MainWindow();
            
              void createConnections();
              void loadPage(const QString& pgName);
              void loadPage(const QUrl& link);
            
            private:
              Ui::MainWindow* ui;
              HelpEngine*     he;
              QTextBrowser*   tb;
              };
            

            ... and MainWindow definition:

            MainWindow::MainWindow(QWidget *parent)
             : QMainWindow(parent)
             , ui(new Ui::MainWindow)
             , he(new HelpEngine(QApplication::applicationDirPath()
                               + "/../share/falconview/help/FalconView.qzh"
                               , this))
             , tb(new HTMLBrowser(*he, this)) {
              ui->setupUi(this);
              tb->setMinimumWidth(830);
            
              setCentralWidget(tb);
              createConnections();
              }
            
            
            MainWindow::~MainWindow() {
              }
            
            
            void MainWindow::createConnections() {
              connect(ui->actionExit,      &QAction::triggered, this, &QWidget::close);
              connect(ui->actionStartup,   &QAction::triggered, this, [=](){ loadPage("startup"); });
              connect(ui->actionReference, &QAction::triggered, this, [=](){ loadPage("reference"); });
              connect(ui->actionUsage,     &QAction::triggered, this, [=](){ loadPage("usage"); });
              }
            
            
            void MainWindow::loadPage(const QString &pgName) {
              qDebug() << "MW::loadPage(" << pgName << ")";
              tb->setSource(pgName + ".html");
              }
            
            
            void MainWindow::loadPage(const QUrl& link) {
              qDebug() << "MW::loadPage(" << link << ")";
              tb->setSource(link);
              }
            

            I renamed the zip-archive to *.qzh - shortcut for "Qt zipped helpfile" ;)

            For testing purpuse I added a menubar to mainwindow, and I used the menuentries to select pages from help-archive.

            HTMLBrowser is subclass of QTextBrowser:

            class HTMLBrowser : public QTextBrowser
            {
              Q_OBJECT
            public:
              explicit HTMLBrowser(HelpEngine& engine, QWidget* parent = nullptr);
              virtual ~HTMLBrowser();
            
              QVariant loadResource(int type, const QUrl &name);
            
            private:
              HelpEngine& engine;
              };
            

            Nothing special in implementation:

            HTMLBrowser::HTMLBrowser(HelpEngine& engine, QWidget* parent)
             : QTextBrowser(parent)
             , engine(engine) {
              }
            
            
            HTMLBrowser::~HTMLBrowser() {
              }
            
            
            QVariant HTMLBrowser::loadResource(int type, const QUrl& link) {
              qDebug() << "loadResource(" << type << "url:" << link;
            
              return engine.readFile(link.path());
              }
            

            ... and finally the "new" HelpEngine.
            First declaration:

            class HelpEngine : public QObject
            {
              Q_OBJECT
            public:
              explicit HelpEngine(const QString& helpFile, QObject *parent = nullptr);
            
              QVariant readFile(const QString& file);
              void     tellContent();
            
            protected:
              void     buildDir(const QVector<QZipReader::FileInfo> entries);
            
            private:
              QZipReader*        reader;
              QMap<QString, int> helpDir;
              };
            

            ... and here the implementation:

            HelpEngine::HelpEngine(const QString& helpFile, QObject *parent)
             : QObject(parent)
             , reader(new QZipReader(helpFile)) {
              buildDir(reader->fileInfoList());
              }
            
            
            void HelpEngine::buildDir(const QVector<QZipReader::FileInfo> entries) {
              int mx = entries.count();
            
              for (int i=0; i < mx; ++i) {
                  if (!entries[i].isFile) continue;
                  helpDir.insert(entries[i].filePath, i);
                  }
              }
            
            
            QVariant HelpEngine::readFile(const QString& file) {
              if (!helpDir.contains(file)) return QVariant();
              QByteArray ba = reader->fileData(file);
            
              return QVariant(ba);
              }
            
            
            void HelpEngine::tellContent() {
              for (const QZipReader::FileInfo& e : reader->fileInfoList()) {
                  qDebug() << "Helpfile-entry:" << e.filePath
                           << (e.isDir ? "Dir" : "")
                           << (e.isFile ? "File" : "")
                           << (e.isSymLink ? "SymLink" : "");
                  }
              }
            

            works like charming :)

            ... and in my humble opinion its fast enuf to use it without sqlite.
            Well, I have to find a solution for keywords and index, but I'm confident, that is feasible.

            Cheers

            1 Reply Last reply
            0
            • artwawA artwaw

              @sierdzio said in no pictures in helpfile:

              qdoc is an internal tool of Qt

              That's new to me, it is not mentioned in the documentation or did I miss it through all the years?

              sierdzioS Offline
              sierdzioS Offline
              sierdzio
              Moderators
              wrote on last edited by
              #6

              @artwaw said in no pictures in helpfile:

              @sierdzio said in no pictures in helpfile:

              qdoc is an internal tool of Qt

              That's new to me, it is not mentioned in the documentation or did I miss it through all the years?

              It's not mentioned in the docs, but it has been said repeatedly on the mailing list. I have no idea why the docs have never been updated with this info.

              (Z(:^

              artwawA 1 Reply Last reply
              1
              • sierdzioS sierdzio

                @artwaw said in no pictures in helpfile:

                @sierdzio said in no pictures in helpfile:

                qdoc is an internal tool of Qt

                That's new to me, it is not mentioned in the documentation or did I miss it through all the years?

                It's not mentioned in the docs, but it has been said repeatedly on the mailing list. I have no idea why the docs have never been updated with this info.

                artwawA Offline
                artwawA Offline
                artwaw
                wrote on last edited by
                #7

                @sierdzio Thank you!

                For more information please re-read.

                Kind Regards,
                Artur

                1 Reply Last reply
                0
                • D Offline
                  D Offline
                  django.Reinhard
                  wrote on last edited by
                  #8

                  Hi,

                  help from compressed archive works no matter, whether the *.html-files where built by qdoc, doxygen or are handwritten.
                  If firefox can display the page as local file, then it should be ready for help-browser as well.

                  New changes for index and keyword support: I added *.qhp to archive. That file already contains all necessary informations. So I did it like QHelpEngine: create Standard-widgets, which can be included in some page layout.

                  I created a help-"dialog" a dockable, which can be used floating or integrated into mainwindow.

                  HelpDialog::HelpDialog(QWidget* parent)
                   : QDockWidget(tr("Help"), parent)
                   , he(new HelpEngine(Core().helpFilename(), this))
                   , tb(new HTMLBrowser(*he))
                   , cw(static_cast<HelpContentWidget*>(he->contentWidget()))
                   , kw(static_cast<HelpKeywordWidget*>(he->keywordWidget())) {
                    setObjectName("HelpDialog");
                    tb->setMinimumWidth(830);
                    setMinimumWidth(1100);
                    QSplitter*  sh = new QSplitter(Qt::Horizontal, this);
                    QTabWidget* tw = new QTabWidget(sh);
                  
                    sh->addWidget(tw);
                    sh->addWidget(tb);
                    tw->addTab(cw, tr("Content"));
                    tw->addTab(kw, tr("Keywords"));
                    setWidget(sh);
                    connect(cw, &QTreeWidget::currentItemChanged, this, &HelpDialog::contentItemChanged);
                    connect(kw, &QListWidget::currentItemChanged, this, &HelpDialog::keywordItemChanged);
                    }
                  
                  
                  void HelpDialog::contentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *) {
                    const QString& page = current->data(1, Qt::DisplayRole).toString();
                  
                    tb->setSource(page);
                    }
                  
                  
                  void HelpDialog::keywordItemChanged(QListWidgetItem *current, QListWidgetItem *) {
                    const QString& page = current->toolTip();
                  
                    tb->setSource(page);
                    }
                  

                  FalconView_Help01.jpg

                  Here the sources. First the content-widget, a subclass of QTreeWidget:

                  class HelpContentWidget : public QTreeWidget
                  {
                    Q_OBJECT
                  public:
                    explicit HelpContentWidget(QWidget* parent = nullptr);
                    virtual ~HelpContentWidget();
                  
                    void setFolderIcon(const QIcon& ico);
                    void setHelpIcon(const QIcon& ico);
                    void parse(const QByteArray& ba);
                  
                  protected:
                    QTreeWidgetItem* createItem(const QDomElement& e, QTreeWidgetItem* parent);
                    QTreeWidgetItem* processElement(const QDomElement& e, QTreeWidgetItem* parent);
                    void processChildren(const QDomElement& e, QTreeWidgetItem* parentItem = nullptr);
                    void processAttributes(const QDomElement& e, QTreeWidgetItem* item);
                  
                  private:
                    int   level;
                    QIcon folderIcon;
                    QIcon helpIcon;
                    };
                  

                  ... and its implementation:

                  HelpContentWidget::HelpContentWidget(QWidget* parent)
                   : QTreeWidget(parent) {
                    header()->setStretchLastSection(true);
                    setHeaderLabel(tr("Title"));
                    }
                  
                  
                  HelpContentWidget::~HelpContentWidget() {
                    }
                  
                  
                  void HelpContentWidget::parse(const QByteArray& ba) {
                    QDomDocument doc;
                  
                    doc.setContent(ba);
                    QDomNodeList links = doc.elementsByTagName("toc");
                  
                    level = 0;
                    clear();
                    for (int i=0; i < links.count(); ++i) {
                        QDomNode link = links.item(i);
                  
                        qDebug() << "\n";
                        qDebug() << "check entry #" << i;
                        if (link.isElement()) {
                           QDomElement e = link.toElement();
                  
                           processChildren(e);
                           }
                        }
                    }
                  
                  
                  void HelpContentWidget::processAttributes(const QDomElement& e, QTreeWidgetItem* item) {
                    int mx = e.attributes().count();
                  
                    qDebug() << "processAttributes ...";
                    if (mx > 0) {
                       qDebug() << "element has" << mx << "attributes";
                       for (int i=0; i < mx; ++i) {
                           const QDomNode& n = e.attributes().item(i);
                  
                           qDebug() << "\tattribute:" << n.nodeName() << " => " << n.nodeValue();
                           if (n.nodeName() == "title")    item->setText(0, n.nodeValue());
                           else if (n.nodeName() == "ref") item->setText(1, n.nodeValue());
                           }
                       }
                    else qDebug() << "element has NO attributes";
                    }
                  
                  
                  void HelpContentWidget::processChildren(const QDomElement& e, QTreeWidgetItem* parent) {
                    qDebug() << "processChildren ... (level:" << level++ << ")";
                  
                    for (QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
                        if (n.isElement()) {
                           qDebug() << "child is Element";
                           processElement(n.toElement(), parent);
                           }
                        }
                    --level;
                    }
                  
                  
                  QTreeWidgetItem* HelpContentWidget::createItem(const QDomElement &e, QTreeWidgetItem *parent) {
                    QTreeWidgetItem* item;
                  
                    if (parent) item = new QTreeWidgetItem(parent);
                    else        item = new QTreeWidgetItem(this);
                    item->setIcon(0, folderIcon);
                    processAttributes(e, item);
                  
                    return item;
                    }
                  
                  
                  QTreeWidgetItem* HelpContentWidget::processElement(const QDomElement& e, QTreeWidgetItem* parent) {
                    qDebug() << "processElement - tag:" << e.tagName() << "text:" << e.text();
                    QTreeWidgetItem* item = nullptr;
                  
                    if (e.tagName() == "section") {
                       item = createItem(e, parent);
                  
                       processChildren(e, item);
                       }
                    return item;
                    }
                  
                  
                  void HelpContentWidget::setFolderIcon(const QIcon &ico) {
                    folderIcon = ico;
                    }
                  
                  
                  void HelpContentWidget::setHelpIcon(const QIcon &ico) {
                    helpIcon = ico;
                    }
                  

                  ... followed by the keywordWidget:

                  class HelpKeywordWidget : public QListWidget
                  {
                    Q_OBJECT
                  public:
                    explicit HelpKeywordWidget(QWidget* parent = nullptr);
                    virtual ~HelpKeywordWidget();
                  
                    void parse(const QByteArray& ba);
                    void setIcon(const QIcon& icon);
                  
                  protected:
                    void processChildren(const QDomElement& e);
                  
                  private:
                    QIcon icon;
                    };
                  

                  with this implementation:

                  HelpKeywordWidget::HelpKeywordWidget(QWidget* parent)
                   : QListWidget(parent) {
                    }
                  
                  
                  HelpKeywordWidget::~HelpKeywordWidget() {
                    }
                  
                  
                  void HelpKeywordWidget::parse(const QByteArray &ba) {
                    QDomDocument doc;
                  
                    doc.setContent(ba);
                    QDomNodeList links = doc.elementsByTagName("keywords");
                  
                    clear();
                    for (int i=0; i < links.count(); ++i) {
                        QDomNode link = links.item(i);
                  
                        qDebug() << "\n";
                        qDebug() << "check entry #" << i;
                        if (link.isElement()) {
                           QDomElement e = link.toElement();
                  
                           processChildren(e);
                           }
                        }
                    }
                  
                  
                  void HelpKeywordWidget::processChildren(const QDomElement& e) {
                    qDebug() << "processChildren ... ";
                  
                    for (QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
                        if (n.isElement()) {
                           qDebug() << "child is Element";
                           QDomElement      elem = n.toElement();
                           QListWidgetItem* item = new QListWidgetItem();
                           int              mx   = elem.attributes().count();
                  
                           item->setIcon(icon);
                           for (int i=0; i < mx; ++i) {
                               const QDomNode& n = elem.attributes().item(i);
                  
                               if (n.nodeName() == "name")     item->setText(n.nodeValue());
                               else if (n.nodeName() == "ref") item->setToolTip(n.nodeValue());
                               }
                           addItem(item);
                           }
                        else if (n.isEntity()) qDebug() << "child is Entity";
                        else if (n.isAttr())   qDebug() << "child is Attribute";
                        else if (n.isText())   qDebug() << "child is Text";
                        }
                    }
                  
                  
                  void HelpKeywordWidget::setIcon(const QIcon &icon) {
                    this->icon = icon;
                    }
                  

                  Creation of helpfile is done with a little bash-script:

                  #!/bin/bash
                  project=FalconView
                  
                  qdoc ${project}.qdocconf
                  cp ${project}.qhp html
                  cd html
                  zip -u9 ../FalconView.qzh *.html images/* FalconView.qhp
                  

                  I think that this solution can be used to create a helper solution for small applications with the least possible effort.

                  1 Reply Last reply
                  0

                  • Login

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • Users
                  • Groups
                  • Search
                  • Get Qt Extensions
                  • Unsolved