2 Copyright (C) 2007 Trolltech ASA
3 Copyright (C) 2007 Staikos Computing Services Inc.
4 Copyright (C) 2007 Apple Inc.
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
21 This class provides all functionality needed for loading images, style sheets and html
22 pages from the web. It has a memory cache for these objects.
26 #include "qwebframe.h"
27 #include "qwebpage_p.h"
28 #include "qwebframe_p.h"
29 #include "qwebnetworkinterface.h"
30 #include "qwebpagehistory.h"
31 #include "qwebpagehistory_p.h"
32 #include "qwebsettings.h"
35 #include "ChromeClientQt.h"
36 #include "ContextMenuClientQt.h"
37 #include "DragClientQt.h"
38 #include "DragController.h"
40 #include "EditorClientQt.h"
43 #include "FrameLoader.h"
46 #include "IconDatabase.h"
47 #include "InspectorClientQt.h"
48 #include "FocusController.h"
50 #include "PlatformScrollBar.h"
51 #include "PlatformKeyboardEvent.h"
52 #include "ProgressTracker.h"
55 #include <QDragEnterEvent>
56 #include <QDragLeaveEvent>
57 #include <QDragMoveEvent>
59 #include <QFileDialog>
60 #include <QHttpRequestHeader>
61 #include <QInputDialog>
62 #include <QMessageBox>
63 #include <QNetworkProxy>
68 using namespace WebCore;
70 QWebPagePrivate::QWebPagePrivate(QWebPage *qq)
74 q->setMouseTracking(true);
75 q->setFocusPolicy(Qt::ClickFocus);
76 chromeClient = new ChromeClientQt(q);
77 contextMenuClient = new ContextMenuClientQt();
78 editorClient = new EditorClientQt(q);
79 page = new Page(chromeClient, contextMenuClient, editorClient,
80 new DragClientQt(q), new InspectorClientQt());
85 insideOpenCall = false;
88 QWebPagePrivate::~QWebPagePrivate()
94 QWebPage::NavigationRequestResponse QWebPagePrivate::navigationRequested(QWebFrame *frame, const QWebNetworkRequest &request, QWebPage::NavigationType type)
97 && frame == mainFrame)
98 return QWebPage::AcceptNavigationRequest;
99 return q->navigationRequested(frame, request, type);
102 void QWebPagePrivate::createMainFrame()
105 QWebFrameData frameData;
106 frameData.ownerElement = 0;
107 frameData.allowsScrolling = true;
108 frameData.marginWidth = 0;
109 frameData.marginHeight = 0;
110 mainFrame = q->createFrame(0, &frameData);
111 QObject::connect(mainFrame, SIGNAL(titleChanged(const QString&)),
112 q, SIGNAL(titleChanged(const QString&)));
113 QObject::connect(mainFrame, SIGNAL(hoveringOverLink(const QString&, const QString&)),
114 q, SIGNAL(hoveringOverLink(const QString&, const QString&)));
116 mainFrame->d->frameView->setFrameGeometry(q->geometry());
121 QWebPage::QWebPage(QWidget *parent)
123 , d(new QWebPagePrivate(this))
125 setSettings(QWebSettings::global());
126 QPalette pal = palette();
127 pal.setBrush(QPalette::Background, Qt::white);
129 setAttribute(Qt::WA_OpaquePaintEvent);
132 setAcceptDrops(true);
133 connect(this, SIGNAL(loadProgressChanged(int)), this, SLOT(onLoadProgressChanged(int)));
136 QWebPage::~QWebPage()
138 FrameLoader *loader = d->mainFrame->d->frame->loader();
140 loader->detachFromParent();
144 QWebFrame *QWebPage::createFrame(QWebFrame *parentFrame, QWebFrameData *frameData)
147 return new QWebFrame(parentFrame, frameData);
148 QWebFrame *f = new QWebFrame(this, frameData);
152 void QWebPage::open(const QUrl &url)
154 open(QWebNetworkRequest(url));
157 void QWebPage::open(const QWebNetworkRequest &req)
159 d->insideOpenCall = true;
161 QUrl url = req.url();
162 QHttpRequestHeader httpHeader = req.httpHeader();
163 QByteArray postData = req.postData();
165 WebCore::ResourceRequest request(KURL(url.toString()));
167 QString method = httpHeader.method();
168 if (!method.isEmpty())
169 request.setHTTPMethod(method);
171 QList<QPair<QString, QString> > values = httpHeader.values();
172 for (int i = 0; i < values.size(); ++i) {
173 const QPair<QString, QString> &val = values.at(i);
174 request.addHTTPHeaderField(val.first, val.second);
177 if (!postData.isEmpty()) {
178 WTF::RefPtr<WebCore::FormData> formData = new WebCore::FormData(postData.constData(), postData.size());
179 request.setHTTPBody(formData);
182 mainFrame()->d->frame->loader()->load(request);
183 d->insideOpenCall = false;
186 QUrl QWebPage::url() const
188 return QUrl((QString)mainFrame()->d->frame->loader()->url().url());
191 QString QWebPage::title() const
193 return mainFrame()->title();
196 QWebFrame *QWebPage::mainFrame() const
198 d->createMainFrame();
202 QSize QWebPage::sizeHint() const
204 return QSize(800, 600);
207 void QWebPage::stop()
209 FrameLoader *f = mainFrame()->d->frame->loader();
210 f->stopForUserCancel();
213 QWebPageHistory QWebPage::history() const
215 WebCore::BackForwardList *lst = d->page->backForwardList();
216 QWebPageHistoryPrivate *priv = new QWebPageHistoryPrivate(lst);
217 return QWebPageHistory(priv);
220 void QWebPage::goBack()
225 void QWebPage::goForward()
227 d->page->goForward();
230 void QWebPage::goToHistoryItem(const QWebHistoryItem &item)
232 d->page->goToItem(item.d->item, FrameLoadTypeIndexedBackForward);
235 void QWebPage::javaScriptConsoleMessage(const QString& message, unsigned int lineNumber, const QString& sourceID)
239 void QWebPage::javaScriptAlert(QWebFrame *frame, const QString& msg)
242 QMessageBox::information(this, title(), msg, QMessageBox::Ok);
245 bool QWebPage::javaScriptConfirm(QWebFrame *frame, const QString& msg)
248 return 0 == QMessageBox::information(this, title(), msg, QMessageBox::Yes, QMessageBox::No);
251 bool QWebPage::javaScriptPrompt(QWebFrame *frame, const QString& msg, const QString& defaultValue, QString* result)
255 #ifndef QT_NO_INPUTDIALOG
256 QString x = QInputDialog::getText(this, title(), msg, QLineEdit::Normal, defaultValue, &ok);
264 QWebPage *QWebPage::createWindow()
269 QWebPage *QWebPage::createModalDialog()
274 QObject *QWebPage::createPlugin(const QString &classid, const QUrl &url, const QStringList ¶mNames, const QStringList ¶mValues)
279 Q_UNUSED(paramValues)
283 QWebPage::NavigationRequestResponse QWebPage::navigationRequested(QWebFrame *frame, const QWebNetworkRequest &request, QWebPage::NavigationType type)
286 return AcceptNavigationRequest;
289 void QWebPage::setWindowGeometry(const QRect& geom)
294 bool QWebPage::canCut() const
296 return d->page->focusController()->focusedOrMainFrame()->editor()->canCut();
299 bool QWebPage::canCopy() const
301 return d->page->focusController()->focusedOrMainFrame()->editor()->canCopy();
304 bool QWebPage::canPaste() const
306 return d->page->focusController()->focusedOrMainFrame()->editor()->canPaste();
311 d->page->focusController()->focusedOrMainFrame()->editor()->cut();
314 void QWebPage::copy()
316 d->page->focusController()->focusedOrMainFrame()->editor()->copy();
319 void QWebPage::paste()
321 d->page->focusController()->focusedOrMainFrame()->editor()->paste();
325 Returns true if the page contains unsubmitted form data.
327 bool QWebPage::isModified() const
333 QUndoStack *QWebPage::undoStack()
336 d->undoStack = new QUndoStack(this);
341 static inline DragOperation dropActionToDragOp(Qt::DropActions actions)
344 if (actions & Qt::CopyAction)
345 result |= DragOperationCopy;
346 if (actions & Qt::MoveAction)
347 result |= DragOperationMove;
348 if (actions & Qt::LinkAction)
349 result |= DragOperationLink;
350 return (DragOperation)result;
353 static inline Qt::DropAction dragOpToDropAction(unsigned actions)
355 Qt::DropAction result = Qt::IgnoreAction;
356 if (actions & DragOperationCopy)
357 result = Qt::CopyAction;
358 else if (actions & DragOperationMove)
359 result = Qt::MoveAction;
360 else if (actions & DragOperationLink)
361 result = Qt::LinkAction;
365 void QWebPage::resizeEvent(QResizeEvent *e)
367 QWidget::resizeEvent(e);
368 if (mainFrame()->d->frame && mainFrame()->d->frameView) {
369 mainFrame()->d->frameView->setFrameGeometry(rect());
370 mainFrame()->d->frame->forceLayout();
371 mainFrame()->d->frame->view()->adjustViewSize();
375 void QWebPage::paintEvent(QPaintEvent *ev)
377 #ifdef QWEBKIT_TIME_RENDERING
384 QVector<QRect> vector = ev->region().rects();
385 if (!vector.isEmpty()) {
386 for (int i = 0; i < vector.size(); ++i) {
387 mainFrame()->render(&p, vector.at(i));
390 mainFrame()->render(&p, ev->rect());
393 #ifdef QWEBKIT_TIME_RENDERING
394 int elapsed = time.elapsed();
395 qDebug()<<"paint event on "<<ev->region()<<", took to render = "<<elapsed;
399 void QWebPage::mouseMoveEvent(QMouseEvent *ev)
401 mainFrame()->mouseMoveEvent(ev);
404 void QWebPage::mousePressEvent(QMouseEvent *ev)
406 mainFrame()->mousePressEvent(ev);
409 void QWebPage::mouseDoubleClickEvent(QMouseEvent *ev)
411 mainFrame()->mouseDoubleClickEvent(ev);
414 void QWebPage::mouseReleaseEvent(QMouseEvent *ev)
416 mainFrame()->mouseReleaseEvent(ev);
419 void QWebPage::wheelEvent(QWheelEvent *ev)
421 mainFrame()->wheelEvent(ev);
422 if (!ev->isAccepted())
423 QWidget::wheelEvent(ev);
426 void QWebPage::keyPressEvent(QKeyEvent *ev)
428 if (!mainFrame()->d->eventHandler)
431 bool handled = false;
432 QWebFrame *frame = mainFrame();
433 WebCore::Editor *editor = frame->d->frame->editor();
434 if (editor->canEdit()) {
435 const char *command = 0;
436 if (ev == QKeySequence::Cut) {
439 } else if (ev == QKeySequence::Copy) {
442 } else if (ev == QKeySequence::Paste) {
445 } else if (ev == QKeySequence::Undo) {
448 } else if (ev == QKeySequence::Redo) {
451 } else if(ev == QKeySequence::MoveToNextChar) {
452 command = "MoveForward";
453 } else if(ev == QKeySequence::MoveToPreviousChar) {
454 command = "MoveBackward";
455 } else if(ev == QKeySequence::MoveToNextWord) {
456 command = "MoveWordForward";
457 } else if(ev == QKeySequence::MoveToPreviousWord) {
458 command = "MoveWordBackward";
459 } else if(ev == QKeySequence::MoveToNextLine) {
460 command = "MoveDown";
461 } else if(ev == QKeySequence::MoveToPreviousLine) {
463 // } else if(ev == QKeySequence::MoveToNextPage) {
464 // } else if(ev == QKeySequence::MoveToPreviousPage) {
465 } else if(ev == QKeySequence::MoveToStartOfLine) {
466 command = "MoveToBeginningOfLine";
467 } else if(ev == QKeySequence::MoveToEndOfLine) {
468 command = "MoveToEndOfLine";
469 } else if(ev == QKeySequence::MoveToStartOfBlock) {
470 command = "MoveToBeginningOfParagraph";
471 } else if(ev == QKeySequence::MoveToEndOfBlock) {
472 command = "MoveToEndOfParagraph";
473 } else if(ev == QKeySequence::MoveToStartOfDocument) {
474 command = "MoveToBeginningOfDocument";
475 } else if(ev == QKeySequence::MoveToEndOfDocument) {
476 command = "MoveToEndOfDocument";
477 } else if(ev == QKeySequence::SelectNextChar) {
478 command = "MoveForwardAndModifySelection";
479 } else if(ev == QKeySequence::SelectPreviousChar) {
480 command = "MoveBackwardAndModifySelection";
481 } else if(ev == QKeySequence::SelectNextWord) {
482 command = "MoveWordForwardAndModifySelection";
483 } else if(ev == QKeySequence::SelectPreviousWord) {
484 command = "MoveWordBackwardAndModifySelection";
485 } else if(ev == QKeySequence::SelectNextLine) {
486 command = "MoveDownAndModifySelection";
487 } else if(ev == QKeySequence::SelectPreviousLine) {
488 command = "MoveUpAndModifySelection";
489 // } else if(ev == QKeySequence::SelectNextPage) {
490 // } else if(ev == QKeySequence::SelectPreviousPage) {
491 } else if(ev == QKeySequence::SelectStartOfLine) {
492 command = "MoveToBeginningOfLineAndModifySelection";
493 } else if(ev == QKeySequence::SelectEndOfLine) {
494 command = "MoveToEndOfLineAndModifySelection";
495 } else if(ev == QKeySequence::SelectStartOfBlock) {
496 command = "MoveToBeginningOfParagraphAndModifySelection";
497 } else if(ev == QKeySequence::SelectEndOfBlock) {
498 command = "MoveToEndOfParagraphAndModifySelection";
499 } else if(ev == QKeySequence::SelectStartOfDocument) {
500 command = "MoveToBeginningOfDocumentAndModifySelection";
501 } else if(ev == QKeySequence::SelectEndOfDocument) {
502 command = "MoveToEndOfDocumentAndModifySelection";
503 } else if(ev == QKeySequence::DeleteStartOfWord) {
504 command = "DeleteWordBackward";
505 } else if(ev == QKeySequence::DeleteEndOfWord) {
506 command = "DeleteWordForward";
507 // } else if(ev == QKeySequence::DeleteEndOfLine) {
510 editor->execCommand(command);
515 handled = frame->d->eventHandler->keyEvent(ev);
518 PlatformScrollbar *h, *v;
519 h = mainFrame()->d->horizontalScrollBar();
520 v = mainFrame()->d->verticalScrollBar();
522 if (ev == QKeySequence::MoveToNextPage) {
524 v->setValue(v->value() + height());
525 } else if (ev == QKeySequence::MoveToPreviousPage) {
527 v->setValue(v->value() - height());
532 v->setValue(v->value() - 10);
536 v->setValue(v->value() + 10);
540 h->setValue(h->value() - 10);
544 h->setValue(h->value() + 10);
553 ev->setAccepted(handled);
556 void QWebPage::keyReleaseEvent(QKeyEvent *ev)
558 if (ev->isAutoRepeat()) {
559 ev->setAccepted(true);
563 if (!mainFrame()->d->eventHandler)
566 bool handled = mainFrame()->d->eventHandler->keyEvent(ev);
567 ev->setAccepted(handled);
570 void QWebPage::focusInEvent(QFocusEvent *ev)
572 if (ev->reason() != Qt::PopupFocusReason)
573 mainFrame()->d->frame->page()->focusController()->setFocusedFrame(mainFrame()->d->frame);
574 QWidget::focusInEvent(ev);
577 void QWebPage::focusOutEvent(QFocusEvent *ev)
579 QWidget::focusOutEvent(ev);
580 if (ev->reason() != Qt::PopupFocusReason) {
581 mainFrame()->d->frame->selectionController()->clear();
582 mainFrame()->d->frame->setIsActive(false);
586 bool QWebPage::focusNextPrevChild(bool next)
592 void QWebPage::dragEnterEvent(QDragEnterEvent *ev)
594 #ifndef QT_NO_DRAGANDDROP
595 DragData dragData(ev->mimeData(), ev->pos(), QCursor::pos(),
596 dropActionToDragOp(ev->possibleActions()));
597 Qt::DropAction action = dragOpToDropAction(d->page->dragController()->dragEntered(&dragData));
598 ev->setDropAction(action);
603 void QWebPage::dragLeaveEvent(QDragLeaveEvent *ev)
605 #ifndef QT_NO_DRAGANDDROP
606 DragData dragData(0, IntPoint(), QCursor::pos(), DragOperationNone);
607 d->page->dragController()->dragExited(&dragData);
612 void QWebPage::dragMoveEvent(QDragMoveEvent *ev)
614 #ifndef QT_NO_DRAGANDDROP
615 DragData dragData(ev->mimeData(), ev->pos(), QCursor::pos(),
616 dropActionToDragOp(ev->possibleActions()));
617 Qt::DropAction action = dragOpToDropAction(d->page->dragController()->dragUpdated(&dragData));
618 ev->setDropAction(action);
623 void QWebPage::dropEvent(QDropEvent *ev)
625 #ifndef QT_NO_DRAGANDDROP
626 DragData dragData(ev->mimeData(), ev->pos(), QCursor::pos(),
627 dropActionToDragOp(ev->possibleActions()));
628 Qt::DropAction action = dragOpToDropAction(d->page->dragController()->performDrag(&dragData));
633 void QWebPage::setNetworkInterface(QWebNetworkInterface *interface)
635 d->networkInterface = interface;
638 QWebNetworkInterface *QWebPage::networkInterface() const
640 if (d->networkInterface)
641 return d->networkInterface;
643 return QWebNetworkInterface::defaultInterface();
646 QPixmap QWebPage::icon() const
648 Image* image = iconDatabase()->iconForPageURL(url().toString(), IntSize(16, 16));
649 if (!image || image->isNull()) {
650 image = iconDatabase()->defaultIcon(IntSize(16, 16));
657 QPixmap *icon = image->getPixmap();
664 void QWebPage::setSettings(const QWebSettings &settings)
666 WebCore::Settings *wSettings = d->page->settings();
668 wSettings->setStandardFontFamily(
669 settings.fontFamily(QWebSettings::StandardFont));
670 wSettings->setFixedFontFamily(
671 settings.fontFamily(QWebSettings::FixedFont));
672 wSettings->setSerifFontFamily(
673 settings.fontFamily(QWebSettings::SerifFont));
674 wSettings->setSansSerifFontFamily(
675 settings.fontFamily(QWebSettings::SansSerifFont));
676 wSettings->setCursiveFontFamily(
677 settings.fontFamily(QWebSettings::CursiveFont));
678 wSettings->setFantasyFontFamily(
679 settings.fontFamily(QWebSettings::FantasyFont));
681 wSettings->setMinimumFontSize(settings.minimumFontSize());
682 wSettings->setMinimumLogicalFontSize(settings.minimumLogicalFontSize());
683 wSettings->setDefaultFontSize(settings.defaultFontSize());
684 wSettings->setDefaultFixedFontSize(settings.defaultFixedFontSize());
686 wSettings->setLoadsImagesAutomatically(
687 settings.testAttribute(QWebSettings::AutoLoadImages));
688 wSettings->setJavaScriptEnabled(
689 settings.testAttribute(QWebSettings::JavascriptEnabled));
690 wSettings->setJavaScriptCanOpenWindowsAutomatically(
691 settings.testAttribute(QWebSettings::JavascriptCanOpenWindows));
692 wSettings->setJavaEnabled(
693 settings.testAttribute(QWebSettings::JavaEnabled));
694 wSettings->setPluginsEnabled(
695 settings.testAttribute(QWebSettings::PluginsEnabled));
696 wSettings->setPrivateBrowsingEnabled(
697 settings.testAttribute(QWebSettings::PrivateBrowsingEnabled));
699 wSettings->setUserStyleSheetLocation(KURL(settings.userStyleSheetLocation()));
701 // ### should be configurable
702 wSettings->setDefaultTextEncodingName("iso-8859-1");
703 wSettings->setDOMPasteAllowed(true);
706 QWebSettings QWebPage::settings() const
708 QWebSettings settings;
709 WebCore::Settings *wSettings = d->page->settings();
711 settings.setFontFamily(QWebSettings::StandardFont,
712 wSettings->standardFontFamily());
713 settings.setFontFamily(QWebSettings::FixedFont,
714 wSettings->fixedFontFamily());
715 settings.setFontFamily(QWebSettings::SerifFont,
716 wSettings->serifFontFamily());
717 settings.setFontFamily(QWebSettings::SansSerifFont,
718 wSettings->sansSerifFontFamily());
719 settings.setFontFamily(QWebSettings::CursiveFont,
720 wSettings->cursiveFontFamily());
721 settings.setFontFamily(QWebSettings::FantasyFont,
722 wSettings->fantasyFontFamily());
724 settings.setMinimumFontSize(wSettings->minimumFontSize());
725 settings.setMinimumLogicalFontSize(wSettings->minimumLogicalFontSize());
726 settings.setDefaultFontSize(wSettings->defaultFontSize());
727 settings.setDefaultFixedFontSize(wSettings->defaultFixedFontSize());
729 settings.setAttribute(QWebSettings::AutoLoadImages,
730 wSettings->loadsImagesAutomatically());
731 settings.setAttribute(QWebSettings::JavascriptEnabled,
732 wSettings->isJavaScriptEnabled());
733 settings.setAttribute(QWebSettings::JavascriptCanOpenWindows,
734 wSettings->JavaScriptCanOpenWindowsAutomatically());
735 settings.setAttribute(QWebSettings::JavaEnabled,
736 wSettings->isJavaEnabled());
737 settings.setAttribute(QWebSettings::PluginsEnabled,
738 wSettings->arePluginsEnabled());
739 settings.setAttribute(QWebSettings::PrivateBrowsingEnabled,
740 wSettings->privateBrowsingEnabled());
742 settings.setUserStyleSheetLocation(
743 wSettings->userStyleSheetLocation().url());
748 QString QWebPage::chooseFile(QWebFrame *parentFrame, const QString& oldFile)
751 #ifndef QT_NO_FILEDIALOG
752 return QFileDialog::getOpenFileName(this, QString::null, oldFile);
754 return QString::null;
758 #ifndef QT_NO_NETWORKPROXY
759 void QWebPage::setNetworkProxy(const QNetworkProxy& proxy)
761 d->networkProxy = proxy;
764 QNetworkProxy QWebPage::networkProxy() const
766 return d->networkProxy;
770 QString QWebPage::userAgentStringForUrl(const QUrl& forUrl) const {
772 return QLatin1String("Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/418.9.1 (KHTML, like Gecko) Safari/419.3 Qt");
776 void QWebPage::onLoadProgressChanged(int) {
777 d->m_totalBytes = d->page->progress()->totalPageAndResourceBytesToLoad();
778 d->m_bytesReceived = d->page->progress()->totalBytesReceived();
782 quint64 QWebPage::totalBytes() const {
783 return d->m_bytesReceived;
787 quint64 QWebPage::bytesReceived() const {
788 return d->m_totalBytes;