Korvo
Korvo

Reputation: 9753

SpellChecker (speller) on webkit

I believe that there is no native functions in QtWebKit to use SpellChecker.

Is there any way to get the fields (<textarea>, <input> and <tagName contenteditable=true>) of the current page and highlight specific words (add underline only words possibly wrong)?

[edit]

I need to add "visual effect" (underline) to the Words and not the dom elements, for example if I have a html like this:

<textarea>Helllo world!</textarea>

only the word "Helllo" will be underlined, example: enter image description here

Thank you.

Upvotes: 5

Views: 723

Answers (1)

phyatt
phyatt

Reputation: 19152

UPDATE:

No, as far as I can tell from poking and prodding at QtWebKit, you can't format the contents of a textarea.

Format text in a <textarea>?

You could maybe replace it with a div that looks and acts like a textarea, and then insert some tags around specific words.

But near as I can tell from working on this question, it isn't possible with QWebElement.

You could go and ask the trolls and see if they have any suggestions.

Here is the code that got the closest. When the webpage comes up, right click on different places on the page.

main.cpp

#include <QApplication>
#include "webview.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    WebView w;
    w.show();

    return a.exec();
}

webview.h

#ifndef WEBVIEW_H
#define WEBVIEW_H

#include <QWebView>
#include <QContextMenuEvent>


class WebView : public QWebView
{
    Q_OBJECT

public:
    explicit WebView(QWidget *parent = 0);
    ~WebView();

public slots:
    void contextMenuEvent(QContextMenuEvent *);

private:
};

#endif // WEBVIEW_H

webview.cpp

#include "webview.h"
#include <QWebFrame>
#include <QWebElement>
#include <QWebElementCollection>
#include <QDebug>

WebView::WebView(QWidget *parent) :
    QWebView(parent)
{
    this->setUrl(QUrl("http://www.w3schools.com/tags/tag_textarea.asp"));

    // right click on different parts of the web page
}

WebView::~WebView(){ }

void WebView::contextMenuEvent(QContextMenuEvent * cme)
{
    QPoint pos = cme->pos();

    QWebHitTestResult whtr = this->page()->frameAt(pos)->hitTestContent(pos);

    QWebElement we = whtr.element();

    if(we.isNull())
    {
        qDebug() << "WebElement is null.";
    }
    else
    {

        qDebug() << we.tagName() << "OuterXML <<<<<" << we.toOuterXml() << ">>>>>";
        qDebug() << we.tagName() << "InnerXML <<<<<" << we.toInnerXml() << ">>>>>";
        qDebug() << we.tagName() << "PlainText <<<<<" << we.toPlainText() << ">>>>>";


        // TODO: replace the lines below with a better way of extracting words from the DOM and the HTML tags
        // This current method modifies tags instead of just the text inside tags.
        QStringList list = we.toPlainText().split(' ');
        for(int i = 0; i < list.size(); i++)
        {
            // TODO: Insert dictionary logic here when examining words
            if(list.at(i).size() > 5)
            {
                list[i] = "<span class=\"sp\" style=\"border-bottom: 1px dotted red;\">" + list.at(i) + "</span>";
            }
        }
        qDebug() << list.join(" ");
        we.setInnerXml(list.join(" "));
        qDebug() << "-------------------------------------------";
    }
}

So after some additional research (after some changes to your question) here is the method I would look into:

When a right click is performed on the page, the QWidget (your QWebView) sends out a QContextMenuEvent.

http://qt-project.org/doc/qt-4.8/qcontextmenuevent.html#details

Get the position out of that event, and then drill down into your web page to find out what it was for:

Get the web frame at the click location...

QWebFrame * QWebPage::frameAt ( const QPoint & pos ) const

Do a hit test content at the location...

QWebHitTestResult QWebFrame::hitTestContent ( const QPoint & pos ) const

Query the element out of the hit test...

QWebElement QWebHitTestResult::element () const

Double check that the content is editable by the user...

bool QWebHitTestResult::isContentEditable () const

But that is about as far as I have gotten on this research project.

If you restyle the webelements on the page to have a span tag of your misspelled class, then you could look for those and then either create your own popup menu, or edit the contextMenu of the QWebView right then.

So, no, there is not a context menu for elements on the page, but you can simulate it, if you find the element that is clicked on, and then change the contextMenu for the QWidget.

http://qt-project.org/doc/qt-4.8/webkit-simpleselector.html

void Window::on_elementLineEdit_returnPressed()
{
    QWebFrame *frame = webView->page()->mainFrame();

    QWebElement document = frame->documentElement();
    QWebElementCollection elements = document.findAll(elementLineEdit->text());

    foreach (QWebElement element, elements)
        element.setAttribute("style", "background-color: #f0f090");
}

http://qt-project.org/doc/qt-4.8/mainwindows-menus.html

void MainWindow::contextMenuEvent(QContextMenuEvent *event)
{
    QMenu menu(this);
    menu.addAction(cutAct);
    menu.addAction(copyAct);
    menu.addAction(pasteAct);
    menu.exec(event->globalPos());
}

Again, I hope that helps.

As far as awesome examples of using QWebKit, there is this project:

How to create Web History for my Browser

https://code.google.com/p/arora/

I did a search on the repo for "spell" and "spellcheck" and nothing useful came up.

As far as tweaking the html on the fly, the Fancy Browser example shows how it's done:

http://qt-project.org/doc/qt-4.8/webkit-fancybrowser-mainwindow-cpp.html

void MainWindow::rotateImages(bool invert)
{
    QString code;
    if (invert)
        code = "$('img').each( function () { $(this).css('-webkit-transition', '-webkit-transform 2s'); $(this).css('-webkit-transform', 'rotate(180deg)') } )";
    else
        code = "$('img').each( function () { $(this).css('-webkit-transition', '-webkit-transform 2s'); $(this).css('-webkit-transform', 'rotate(0deg)') } )";
    view->page()->mainFrame()->evaluateJavaScript(code);
}

They just use jquery and run additional javascript on a loaded page.

So you could probably substitute "$('img').each( for "$('textarea').each( and act on the text of an area.

You could also run a regex on the page or use an html parser to find all the <textarea> blocks.

Hope that helps.

Upvotes: -2

Related Questions