QWebkit: How to tell when netscape plugin is not available?



  • Hello,

    I am writing a custom browser in my QT application using webkit. This browser accesses webpages that have pdf files embeded in them using @<embed>...</embed>@

    Also it accesses pages that use flash.

    I have two issues:

    If a plugin is not available when accessing a page that needs a plugin, I want to handle the situation gracefully (besides just showing that silly plugin icon).... To do this, I need to catch a signal or some other way get notified that QWebkit is loading content that needs a plugin, but that plugin was not found. I have yet found a way to get notified of this.

    Under Linux, QWebkit will not load the pdf viewer plugin (I know the plugin is installed because Firefox will load it just fine). Under windows the plugin loads fine.



  • did you ever get this working? if so, how?



  • [quote author="jimrising" date="1282079940"]did you ever get this working? if so, how?[/quote]

    Yes, I derived off of QWebPluginFactory to create my own plugin that simply hands the pdf off to the operating system to load the pdf:

    @WebPluginFactory::WebPluginFactory(QObject *parent, QNetworkAccessManager *accessManager) : QWebPluginFactory(parent)
    {
    m_networkAccessManager = accessManager;
    }

    QObject *WebPluginFactory::create(const QString &mimeType, const QUrl &url, const QStringList &argumentNames, const QStringList &argumentValues) const
    {
    if(mimeType == "application/pdf")
    return new PdfWebPlugin(url, m_networkAccessManager);

        return NULL;
    

    }

    QListQWebPluginFactory::Plugin WebPluginFactory::plugins() const
    {
    return QListQWebPluginFactory::Plugin() << PdfWebPlugin::pluginInfo();
    }@

    @PdfWebPlugin::PdfWebPlugin(const QUrl &pdfUrl, QNetworkAccessManager networkAccessManager, QWidget parent/ = 0/) : QWidget(parent), m_ui(new Ui::PdfWebPlugin)
    {
    m_ui->setupUi(this);

        m_ui->msgLbl->setText("Downloading PDF...");
        m_ui->msgSubLbl->setVisible(false);
    
        m_ui->loadingLbl->setMovie(new QMovie(":/ehr/images/loading.gif"));
        m_ui->loadingLbl->resize(QSize(16, 16));
        m_ui->loadingLbl->movie()->start();
        m_ui->actionBtn->setText("Cancel");
    
        QNetworkRequest request(pdfUrl);
    
        m_downloadReply = networkAccessManager->get(request);
        connect(m_downloadReply, SIGNAL(finished()), this, SLOT(pdfDownloadFinished()));
        connect(m_ui->actionBtn, SIGNAL(clicked()), this, SLOT(cancelDownload()));
    

    }

    PdfWebPlugin::~PdfWebPlugin()
    {
    delete m_ui;
    }

    void PdfWebPlugin::cancelDownload()
    {
    disconnect(m_ui->actionBtn, SIGNAL(clicked()), this, SLOT(cancelDownload()));

        if(m_downloadReply->isRunning())
                m_downloadReply->abort();
        m_ui->msgLbl->setText("PDF download canceled");
        m_ui->loadingLbl->movie()->stop();
        m_ui->loadingLbl->setVisible(false);
        m_ui->actionBtn->setVisible(false);
    
        m_downloadReply->deleteLater();
        m_downloadReply = 0;
    

    }

    void PdfWebPlugin::pdfDownloadFinished()
    {
    disconnect(m_ui->actionBtn, SIGNAL(clicked()), this, SLOT(cancelDownload()));

        openPdf();
    
        m_ui->loadingLbl->movie()->stop();
        m_ui->loadingLbl->setVisible(false);
        m_ui->msgLbl->setText("Sending to PDF viewer...");
        m_ui->msgSubLbl->setText("Click Open to resend document to Print Preview");
        m_ui->msgSubLbl->setVisible(true);
        m_ui->actionBtn->setText("Open");
        EVAL&#40;connect(m_ui->actionBtn, SIGNAL(clicked(&#41;), this, SLOT(openPdf())));
    

    }

    void PdfWebPlugin::openPdf()
    {
    if(!m_pdfFile.exists() && m_downloadReply && m_downloadReply->isFinished() && m_downloadReply->error() == QNetworkReply::NoError)
    {
    m_pdfFile.setFileTemplate(QDir::toNativeSeparators(QDir::tempPath() + "/ehr_temp.XXXXXX.pdf"));
    m_pdfFile.setAutoRemove(false);
    m_pdfFile.open();
    m_pdfFile.write(m_downloadReply->readAll());
    m_pdfFile.close();
    m_downloadReply->deleteLater();
    m_downloadReply = 0;
    }

        if(m_pdfFile.exists())
                QDesktopServices::openUrl(QUrl("file:" + m_pdfFile.fileName()));
    

    }

    /static/
    QWebPluginFactory::Plugin PdfWebPlugin::pluginInfo()
    {
    QWebPluginFactory::Plugin pdfPlugin;
    pdfPlugin.description = tr("Uses the OS's local pdf viewer to open pdf files");
    // // And there mime types
    QWebPluginFactory::MimeType pdfMime;
    pdfMime.description = tr("");
    pdfMime.fileExtensions.append("pdf");
    pdfMime.name = "application/pdf";

        pdfPlugin.mimeTypes.append(pdfMime);
        pdfPlugin.name = tr("External PDF viewer plugin");
    
        return pdfPlugin;
    

    }
    @

    Obviously we're missing the UI part of the code... but you can get general idea.



  • Thanks so much for sharing this information however my qt knowlege is not extensive enough to fill in the blanks.

    Would it be possible for you to supply the source code files, or paster the full source code here. or even explain the missing steps. As im not sure what must go in the .h and the cpp. the ui does not make much sense.

    Any help would be greatly appreciated.

    Regards


  • Moderators

    ShapeShifter: You might want to grab a good book on Qt then. The code is really straight forward and simple, a few days of study should enable you to do it yourself.



  • Thanks for the reply. However im not in general that stupid.

    In general i know what im doing. I have written a testing program or 5 that uses mysql network elements and even audio. so overall i do grasp the concepts. you are right the code is straight forward. i grasp the concept. however the problem i have is implementing it.

    So let me rephrase this another way. And tell you step by step what i did, and perhaps you might be willing to help me change what i need to to get it working.

    When trying to implement the above code in QTcreator .

    1. Add new file to project.
    2. Select QT Designer FORM CLass (The one that creates a blank ui aswell ass the cpp and .h
    3. I select Widget From The menu (Blank)
    4. Click Next - For the classname on the next wizard i typed in "PdfWebPlugin" in that exact case.
      The wizard made the pdfwebplugin.h + pdfwebplugin.cpp and pdfwebplugin.ui
    5. Next then finish

    What I did from here is copy the second slot of code from the above post to "pdfwebplugin.cpp"
    i also commented out some of the ui items as for the time being ill only create the action btn
    for all i know this is my problem. but let have a look at it.

    So My entire Code Looks like this

    code below line for pdfwebplugin.cpp

    @
    #include "pdfwebplugin.h"
    #include "ui_pdfwebplugin.h"

    PdfWebPlugin::PdfWebPlugin(const QUrl &pdfUrl, QNetworkAccessManager *networkAccessManager, QWidget *parent) :
    QWidget(parent),
    m_ui(new Ui::PdfWebPlugin)
    {
    m_ui->setupUi(this);
    //m_ui->msgLbl->setText("Downloading PDF...");
    //m_ui->msgSubLbl->setVisible(false);

            //m_ui->loadingLbl->setMovie(new QMovie(":/ehr/images/loading.gif"));
            //m_ui->loadingLbl->resize(QSize(16, 16));
            //m_ui->loadingLbl->movie()->start();
            m_ui->actionBtn->setText("Cancel");
    
            QNetworkRequest request(pdfUrl);
    
            m_downloadReply = networkAccessManager->get(request);
            connect(m_downloadReply, SIGNAL(finished()), this, SLOT(pdfDownloadFinished()));
            connect(m_ui->actionBtn, SIGNAL(clicked()), this, SLOT(cancelDownload()));
    

    }

    PdfWebPlugin::~PdfWebPlugin()
    {
    delete m_ui;
    }

    /*void PdfWebPlugin::changeEvent(QEvent e)
    {
    QWidget::changeEvent(e);
    switch (e->type()) {
    case QEvent::LanguageChange:
    ui->retranslateUi(this);
    break;
    default:
    break;
    }
    }
    /

    void PdfWebPlugin::cancelDownload()
    {
    disconnect(m_ui->actionBtn, SIGNAL(clicked()), this, SLOT(cancelDownload()));

        if(m_downloadReply->isRunning())
                m_downloadReply->abort();
        //m_ui->msgLbl->setText("PDF download canceled");
        //m_ui->loadingLbl->movie()->stop();
        //m_ui->loadingLbl->setVisible(false);
        m_ui->actionBtn->setVisible(false);
    
        m_downloadReply->deleteLater();
        m_downloadReply = 0;
    

    }

    void PdfWebPlugin::pdfDownloadFinished()
    {
    disconnect(m_ui->actionBtn, SIGNAL(clicked()), this, SLOT(cancelDownload()));

        openPdf();
    
        //m_ui->loadingLbl->movie()->stop();
        //m_ui->loadingLbl->setVisible(false);
        //m_ui->msgLbl->setText("Sending to PDF viewer...");
        //m_ui->msgSubLbl->setText("Click Open to resend document to Print Preview");
        //m_ui->msgSubLbl->setVisible(true);
        m_ui->actionBtn->setText("Open");
        EVAL&#40;connect(m_ui->actionBtn, SIGNAL(clicked(&#41;), this, SLOT(openPdf())));
    

    }

    void PdfWebPlugin::openPdf()
    {
    if(!m_pdfFile.exists() && m_downloadReply && m_downloadReply->isFinished() && m_downloadReply->error() == QNetworkReply::NoError)
    {
    m_pdfFile.setFileTemplate(QDir::toNativeSeparators(QDir::tempPath() + "/ehr_temp.XXXXXX.pdf"));
    m_pdfFile.setAutoRemove(false);
    m_pdfFile.open();
    m_pdfFile.write(m_downloadReply->readAll());
    m_pdfFile.close();
    m_downloadReply->deleteLater();
    m_downloadReply = 0;
    }

        if(m_pdfFile.exists())
                QDesktopServices::openUrl(QUrl("file:" + m_pdfFile.fileName()));
    

    }

    /static/
    QWebPluginFactory::Plugin PdfWebPlugin::pluginInfo()
    {
    QWebPluginFactory::Plugin pdfPlugin;
    pdfPlugin.description = tr("Uses the OS's local pdf viewer to open pdf files");
    // // And there mime types
    QWebPluginFactory::MimeType pdfMime;
    pdfMime.description = tr("");
    pdfMime.fileExtensions.append("pdf");
    pdfMime.name = "application/pdf";

        pdfPlugin.mimeTypes.append(pdfMime);
        pdfPlugin.name = tr("External PDF viewer plugin");
    
        return pdfPlugin;
    

    }
    @

    More on next post



  • Now the above code created alot of little errors about naespacing and i know that is beciase the required includes are missing.,

    so i added the following to the pdfwebplugin.h
    i also added the private slots

    @
    #ifndef PDFWEBPLUGIN_H
    #define PDFWEBPLUGIN_H

    #include <QWidget>
    #include <QNetworkRequest>
    #include <QtWebKit/QtWebKit>
    #include <QtGui>
    #include <QUrl>
    #include <QDir>
    //#include <QtNetwork>

    namespace Ui {
    class PdfWebPlugin;
    }

    class PdfWebPlugin : public QWidget {
    Q_OBJECT
    public:
    PdfWebPlugin(QWidget *parent = 0);
    ~PdfWebPlugin();

    private slots:
    void openPdf();
    void pdfDownloadFinished();
    void cancelDownload();

    protected:
    void changeEvent(QEvent *e);

    private:
    Ui::PdfWebPlugin *m_ui;
    };

    #endif // PDFWEBPLUGIN_H
    @
    And my ui file is one push btn called "actionBtn"

    So with that i get the following errors
    @
    pdfwebplugin.cpp:4: error: prototype for ‘PdfWebPlugin::PdfWebPlugin(const QUrl&, QNetworkAccessManager*, QWidget*)’ does not match any in class ‘PdfWebPlugin’
    pdfwebplugin.h:17: error: candidates are: PdfWebPlugin::PdfWebPlugin(const PdfWebPlugin&)
    pdfwebplugin.h:20: error: PdfWebPlugin::PdfWebPlugin(QWidget*)
    pdfwebplugin.cpp:46: error: ‘m_downloadReply’ was not declared in this scope
    pdfwebplugin.cpp:53: error: ‘m_downloadReply’ was not declared in this scope
    pdfwebplugin.cpp:70: error: ‘EVAL’ was not declared in this scope
    pdfwebplugin.cpp:75: error: ‘m_pdfFile’ was not declared in this scope
    pdfwebplugin.cpp:75: error: ‘m_downloadReply’ was not declared in this scope
    pdfwebplugin.cpp:86: error: ‘m_pdfFile’ was not declared in this scope
    pdfwebplugin.cpp:91: error: no ‘QWebPluginFactory::Plugin PdfWebPlugin::pluginInfo()’ member function declared in class ‘PdfWebPlugin’
    @

    And i dont know where the code from the above post slot one goes. main.cpp the the form with the qtwebform.

    @
    WebPluginFactory::WebPluginFactory(QObject *parent, QNetworkAccessManager *accessManager) : QWebPluginFactory(parent)
    {
    m_networkAccessManager = accessManager;
    }

    QObject *WebPluginFactory::create(const QString &mimeType, const QUrl &url, const QStringList &argumentNames, const QStringList &argumentValues) const
    {
    if(mimeType == "application/pdf")
    return new PdfWebPlugin(url, m_networkAccessManager);

        return NULL;
    

    }

    QListQWebPluginFactory::Plugin WebPluginFactory::plugins() const
    {
    return QListQWebPluginFactory::Plugin() << PdfWebPlugin::pluginInfo();
    }
    @

    So perhaps with this could somone please help.


  • Moderators

    ShapeShifter: I did not want to imply that you are stupid. I hope that is not how my comment came across!

    It is just that I am convinced a good Qt book would provide you with the Qt specifics required to implement the blanks. You seem to agree that you are missing those.

    You mention problems due to namespacing... I do not see you use namespaces, so I don't think you are interpreting the compiler output correctly. The error messages you provided are all due to mismatching information in the .cpp and .h file. Just make sure the member variables and methods are defined as declared.



  • I didn't say you called me stupid. i know you didn't. I was trying to explain that im not one of those programmers that would like everything handed to them on a platter. i have tried to decipher the code.

    The problem is that when i ask a question after spending DAYS searching. To get given no advise other than buy a book and spend a few days learning and then it will be easy kinda makes a person feel stupid, as if everyone should know how this works. AS from the link below you can see that i have been trying for ages. post on different forum.

    "http://www.qtforum.org/article/32029/webkit-to-open-pdf-documents.html":http://www.qtforum.org/article/32029/webkit-to-open-pdf-documents.html

    I my help there was kinda unhelpfull if you would like to read it there. And after that wonderfull bit of help i stop learning QT and didnt try again for a month or 2. now after getting a better grasp of QT and writing a few aplications and more learning i want to try do the same thing again (my first project ever). And the only thing i can remotely find out helpfull is the above code.

    But i dont know how to implement it.

    [quote author="Tobias Hunger" date="1284203751"]
    You mention problems due to namespacing... I do not see you use namespaces, so I don't think you are interpreting the compiler output correctly. The error messages you provided are all due to mismatching information in the .cpp and .h file. Just make sure the member variables and methods are defined as declared. [/quote]

    Well i cant see the mismatch info. i have patsted all the information in the post above. would you perhaps tell me what is mismatching. if i could see it myself i wouldnt need to have asked for the source code to start off. Im sure it is something simple but untill someone is willing to tell me what it is i wont be able to learn.

    Im also unfortunalty one of thoose ppl that learn by doing.


  • Moderators

    So let's go through the error messages you have given:

    @pdfwebplugin.cpp:4: error: prototype for ‘PdfWebPlugin::PdfWebPlugin(const QUrl&, QNetworkAccessManager*, QWidget*)’ does not match any in class ‘PdfWebPlugin’
    pdfwebplugin.h:17: error: candidates are: PdfWebPlugin::PdfWebPlugin(const PdfWebPlugin&)
    pdfwebplugin.h:20: error: PdfWebPlugin::PdfWebPlugin(QWidget*)@

    In pdfwebplugin.cpp line 4 you are defining a PdfWebPlugin constructor with the following signature:

    @PdfWebPlugin::PdfWebPlugin(const QUrl&, QNetworkAccessManager*, QWidget*)@

    which was not declared to exist in that class.

    The file pdfwebplugin.h has two candidates you could be trying to use in lines 17 and 20. The one in line 17 is the default copy constructor that is implicitly defined by the class definition (which you should actually disable since QObjects can not get copied).

    @pdfwebplugin.cpp:46: error: ‘m_downloadReply’ was not declared in this scope
    pdfwebplugin.cpp:53: error: ‘m_downloadReply’ was not declared in this scope
    pdfwebplugin.cpp:75: error: ‘m_pdfFile’ was not declared in this scope
    pdfwebplugin.cpp:75: error: ‘m_downloadReply’ was not declared in this scope
    pdfwebplugin.cpp:86: error: ‘m_pdfFile’ was not declared in this scope@

    You are using m_downloadReply and m_pdfFile. Those were never declared. I guess those are supposed to be member variables: Those need to be defined in the header file (usually in the private section of the class).

    @pdfwebplugin.cpp:70: error: ‘EVAL’ was not declared in this scope@

    EVAL is not a keyword in C++, so the compiler expects you to define this before using it. Actually you are probably ok when you just remove it altogether.

    @pdfwebplugin.cpp:91: error: no ‘QWebPluginFactory::Plugin PdfWebPlugin::pluginInfo()’ member function declared in class ‘PdfWebPlugin’@

    You are using a method pluginInfo() which is not declared in the class PdfWebPlugin. Again you need to add the definition to the header of the class.

    All these are very basic issues which any introductory book on C++ would teach you about. Most Qt books also cover the bare essentials of C++ programming. I really advice taking the time to study the language you are going to use for a bit. C++ is a very complex language, trying to meddle through without the basics will just leave you frustrated. If a book is not your way to learn, then listen in on lectures at a university near you (most have introductory courses on C++) or find yourself a friendly C++ developer nearby and convince her/him to do some pair programming sessions with you.

    Forums might be a ok way to get help on a specific topic (there are better IMHO), but they are poor for teaching the basics. I doubt that you will manage to get into shape to tackle even simple projects in C++/Qt that way. Of course you may always prove me wrong:-)



  • You will not beleive how much help that was, i have now fixed all but one errors. the one below.

    [quote]
    pdfwebplugin.cpp:91: error: no ‘QWebPluginFactory::Plugin PdfWebPlugin::pluginInfo()’ member function declared in class ‘PdfWebPlugin’

    You are using a method pluginInfo() which is not declared in the class PdfWebPlugin. Again you need to add the definition to the header of the class.
    [/quote]

    How would i declare the item. I cant fugure it out. i tried multiple ways and in different locations.

    Perhaps could you let me know where and how. it would be much appreciated..

    As for the undeclared variables i added this to private:

    @
    QNetworkReply *m_downloadReply;
    QTemporaryFile m_pdfFile;
    @

    I understand the need for a reference book. but I've tried reading these books and basic tutorials but unless i have a goal in mind, reading is just reading. stuff as complex at C++ (which to date is the hardest language I've ever learnt) is a mind overflow so nothing makes sense so you have to try and try again.

    I find it better to choose a project and work through all the function trying to reach that goal. by the end of the goal (the first one being the hardest) all the basics will be understood. so these couple of errors which you think are simple will eventually be simple for me as well. i have read all of this before but until you need to use the stuff it wont sink in. or at least in my case.

    Thanks very much for your help.
    and i hope you will help me with this one more error


  • Moderators

    Just replace

    @PdfWebPlugin(QWidget *parent = 0)@

    with

    @PdfWebPlugin(const QUrl &pdfUrl, QNetworkAccessManager *networkAccessManager, QWidget *parent)@

    You might want to add the "= 0" part to the parent again if you are OK with the PdfWebPlugin not having a parent.



  • i did do that one. the eroor im still getting is this one on line 91

    QWebPluginFactory::Plugin PdfWebPlugin::pluginInfo()



  • O please those are not Qt problems. You relay need to brush-up on Your C++ basics. As this compilation error clearly states You need to declare this method in the class header.

    @#ifndef PDFWEBPLUGIN_H
    #define PDFWEBPLUGIN_H

    #include <QWidget>
    #include <QNetworkRequest>
    #include <QtWebKit/QtWebKit>
    #include <QtGui>
    #include <QUrl>
    #include <QDir>
    //#include <QtNetwork>

    namespace Ui {
    class PdfWebPlugin;
    }

    class PdfWebPlugin : public QWidget {
    Q_OBJECT
    public:
    PdfWebPlugin(QWidget *parent = 0);
    ~PdfWebPlugin();

    private slots:
    void openPdf();
    void pdfDownloadFinished();
    void cancelDownload();

    protected:
    void changeEvent(QEvent *e);

    private:
    Ui::PdfWebPlugin *m_ui;
    };

    #endif // PDFWEBPLUGIN_H@
    As You can see Your header lacks it. "C++ Primer":http://www.amazon.com/Primer-3rd-Stanley-B-Lippman/dp/0201824701


  • Moderators

    I already told you how to fix the issue. This is not leading anywhere... and you even claimed you had this bug fixed before when you said you where only seeing the constructor one:-(

    And we got pretty far off-topic, too.



  • I did not claim that one was fixed, but never mind. ill keep trying until i get it.
    Eventually ill stumble on the correct syntax to declare a method.

    Sorry i asked for help for something as simple as declaring a method.
    I really didn't think people would have a problem showing me how to do this simple things.
    but live and learn.
    and sorry i ask in a QT forum as someone said this is a c++ question.


  • Moderators

    ShapeShifter: Nobody minds you asking basic C++ questions. I (and others) even took the time to answer them, even though those questions are covered by any introduction text to C++, some of which were even recommended here. We provided way more interaction here as you had in the other forum thread you mentioned (which did provide an answer which I found genuinely helpful by the way).

    I am new to this whole forum thing (which I am doing almost exclusively in my spare time, I am not paid to answer questions here!) and this forum is new, too. So I am seriously interested in understanding your expectations.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.