Add a mechanism to store and retrieve preferences for the Web Inspector.
[WebKit-https.git] / WebKit / qt / QtLauncher / main.cpp
1 /*
2  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
3  * Copyright (C) 2006 George Staikos <staikos@kde.org>
4  * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
5  * Copyright (C) 2006 Zack Rusin <zack@kde.org>
6  * Copyright (C) 2006 Simon Hausmann <hausmann@kde.org>
7  *
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
20  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
27  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include <qwebpage.h>
33 #include <qwebview.h>
34 #include <qwebframe.h>
35 #include <qwebsettings.h>
36
37 #include <QtGui>
38 #include <QDebug>
39 #if QT_VERSION >= 0x040400 && !defined(QT_NO_PRINTER)
40 #include <QPrintPreviewDialog>
41 #endif
42
43 #include <QtUiTools/QUiLoader>
44
45 class WebPage : public QWebPage
46 {
47 public:
48     WebPage(QWidget *parent) : QWebPage(parent) {}
49
50     virtual QWebPage *createWindow(QWebPage::WebWindowType);
51     virtual QObject* createPlugin(const QString&, const QUrl&, const QStringList&, const QStringList&);
52 };
53
54 class MainWindow : public QMainWindow
55 {
56     Q_OBJECT
57 public:
58     MainWindow(const QString& url = QString()): currentZoom(100) {
59         view = new QWebView(this);
60         setCentralWidget(view);
61
62         view->setPage(new WebPage(view));
63
64         connect(view, SIGNAL(loadFinished(bool)),
65                 this, SLOT(loadFinished()));
66         connect(view, SIGNAL(titleChanged(const QString&)),
67                 this, SLOT(setWindowTitle(const QString&)));
68         connect(view->page(), SIGNAL(linkHovered(const QString&, const QString&, const QString &)),
69                 this, SLOT(showLinkHover(const QString&, const QString&)));
70         connect(view->page(), SIGNAL(windowCloseRequested()), this, SLOT(deleteLater()));
71
72         setupUI();
73
74         QUrl qurl = guessUrlFromString(url);
75         if (qurl.isValid()) {
76             urlEdit->setText(qurl.toString());
77             view->load(qurl);
78
79             // the zoom values are chosen to be like in Mozilla Firefox 3
80             zoomLevels << 30 << 50 << 67 << 80 << 90;
81             zoomLevels << 100;
82             zoomLevels << 110 << 120 << 133 << 150 << 170 << 200 << 240 << 300;
83         }
84     }
85
86     QWebPage *webPage() const {
87         return view->page();
88     }
89
90 protected slots:
91
92     void changeLocation() {
93         QUrl url = guessUrlFromString(urlEdit->text());
94         urlEdit->setText(url.toString());
95         view->load(url);
96         view->setFocus(Qt::OtherFocusReason);
97     }
98
99     void loadFinished() {
100         urlEdit->setText(view->url().toString());
101
102         QUrl::FormattingOptions opts;
103         opts |= QUrl::RemoveScheme;
104         opts |= QUrl::RemoveUserInfo;
105         opts |= QUrl::StripTrailingSlash;
106         QString s = view->url().toString(opts);
107         s = s.mid(2);
108         if (s.isEmpty())
109             return;
110
111         if (!urlList.contains(s))
112             urlList += s;
113         urlModel.setStringList(urlList);
114     }
115
116     void showLinkHover(const QString &link, const QString &toolTip) {
117         statusBar()->showMessage(link);
118 #ifndef QT_NO_TOOLTIP
119         if (!toolTip.isEmpty())
120             QToolTip::showText(QCursor::pos(), toolTip);
121 #endif
122     }
123
124     void newWindow() {
125         MainWindow *mw = new MainWindow;
126         mw->show();
127     }
128
129     void zoomIn() {
130         int i = zoomLevels.indexOf(currentZoom);
131         Q_ASSERT(i >= 0);
132         if (i < zoomLevels.count() - 1)
133             currentZoom = zoomLevels[i + 1];
134
135         view->setZoomFactor(qreal(currentZoom)/100.0);
136     }
137
138     void zoomOut() {
139         int i = zoomLevels.indexOf(currentZoom);
140         Q_ASSERT(i >= 0);
141         if (i > 0)
142             currentZoom = zoomLevels[i - 1];
143
144         view->setZoomFactor(qreal(currentZoom)/100.0);
145     }
146
147     void resetZoom()
148     {
149        currentZoom = 100;
150        view->setZoomFactor(1.0);
151     }
152
153     void toggleZoomTextOnly(bool b)
154     {
155         view->page()->settings()->setAttribute(QWebSettings::ZoomTextOnly, b);
156     }
157
158     void print() {
159 #if QT_VERSION >= 0x040400 && !defined(QT_NO_PRINTER)
160         QPrintPreviewDialog dlg(this);
161         connect(&dlg, SIGNAL(paintRequested(QPrinter *)),
162                 view, SLOT(print(QPrinter *)));
163         dlg.exec();
164 #endif
165     }
166
167     void setEditable(bool on) {
168         view->page()->setEditable(on);
169         formatMenuAction->setVisible(on);
170     }
171
172     void dumpHtml() {
173         qDebug() << "HTML: " << view->page()->mainFrame()->toHtml();
174     }
175 private:
176
177     QVector<int> zoomLevels;
178     int currentZoom;
179
180     // create the status bar, tool bar & menu
181     void setupUI() {
182         progress = new QProgressBar(this);
183         progress->setRange(0, 100);
184         progress->setMinimumSize(100, 20);
185         progress->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
186         progress->hide();
187         statusBar()->addPermanentWidget(progress);
188
189         connect(view, SIGNAL(loadProgress(int)), progress, SLOT(show()));
190         connect(view, SIGNAL(loadProgress(int)), progress, SLOT(setValue(int)));
191         connect(view, SIGNAL(loadFinished(bool)), progress, SLOT(hide()));
192
193         urlEdit = new QLineEdit(this);
194         urlEdit->setSizePolicy(QSizePolicy::Expanding, urlEdit->sizePolicy().verticalPolicy());
195         connect(urlEdit, SIGNAL(returnPressed()),
196                 SLOT(changeLocation()));
197         QCompleter *completer = new QCompleter(this);
198         urlEdit->setCompleter(completer);
199         completer->setModel(&urlModel);
200
201         QToolBar *bar = addToolBar("Navigation");
202         bar->addAction(view->pageAction(QWebPage::Back));
203         bar->addAction(view->pageAction(QWebPage::Forward));
204         bar->addAction(view->pageAction(QWebPage::Reload));
205         bar->addAction(view->pageAction(QWebPage::Stop));
206         bar->addWidget(urlEdit);
207
208         QMenu *fileMenu = menuBar()->addMenu("&File");
209         QAction *newWindow = fileMenu->addAction("New Window", this, SLOT(newWindow()));
210 #if QT_VERSION >= 0x040400
211         fileMenu->addAction(tr("Print"), this, SLOT(print()));
212 #endif
213         fileMenu->addAction("Close", this, SLOT(close()));
214
215         QMenu *editMenu = menuBar()->addMenu("&Edit");
216         editMenu->addAction(view->pageAction(QWebPage::Undo));
217         editMenu->addAction(view->pageAction(QWebPage::Redo));
218         editMenu->addSeparator();
219         editMenu->addAction(view->pageAction(QWebPage::Cut));
220         editMenu->addAction(view->pageAction(QWebPage::Copy));
221         editMenu->addAction(view->pageAction(QWebPage::Paste));
222         editMenu->addSeparator();
223         QAction *setEditable = editMenu->addAction("Set Editable", this, SLOT(setEditable(bool)));
224         setEditable->setCheckable(true);
225
226         QMenu *viewMenu = menuBar()->addMenu("&View");
227         viewMenu->addAction(view->pageAction(QWebPage::Stop));
228         viewMenu->addAction(view->pageAction(QWebPage::Reload));
229         viewMenu->addSeparator();
230         QAction *zoomIn = viewMenu->addAction("Zoom &In", this, SLOT(zoomIn()));
231         QAction *zoomOut = viewMenu->addAction("Zoom &Out", this, SLOT(zoomOut()));
232         QAction *resetZoom = viewMenu->addAction("Reset Zoom", this, SLOT(resetZoom()));
233         QAction *zoomTextOnly = viewMenu->addAction("Zoom Text Only", this, SLOT(toggleZoomTextOnly(bool)));
234         zoomTextOnly->setCheckable(true);
235         zoomTextOnly->setChecked(false);
236         viewMenu->addSeparator();
237         viewMenu->addAction("Dump HTML", this, SLOT(dumpHtml()));
238
239         QMenu *formatMenu = new QMenu("F&ormat");
240         formatMenuAction = menuBar()->addMenu(formatMenu);
241         formatMenuAction->setVisible(false);
242         formatMenu->addAction(view->pageAction(QWebPage::ToggleBold));
243         formatMenu->addAction(view->pageAction(QWebPage::ToggleItalic));
244         formatMenu->addAction(view->pageAction(QWebPage::ToggleUnderline));
245         QMenu *writingMenu = formatMenu->addMenu(tr("Writing Direction"));
246         writingMenu->addAction(view->pageAction(QWebPage::SetTextDirectionDefault));
247         writingMenu->addAction(view->pageAction(QWebPage::SetTextDirectionLeftToRight));
248         writingMenu->addAction(view->pageAction(QWebPage::SetTextDirectionRightToLeft));
249
250         newWindow->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_N));
251         view->pageAction(QWebPage::Back)->setShortcut(QKeySequence::Back);
252         view->pageAction(QWebPage::Stop)->setShortcut(Qt::Key_Escape);
253         view->pageAction(QWebPage::Forward)->setShortcut(QKeySequence::Forward);
254         view->pageAction(QWebPage::Reload)->setShortcut(QKeySequence::Refresh);
255         view->pageAction(QWebPage::Undo)->setShortcut(QKeySequence::Undo);
256         view->pageAction(QWebPage::Redo)->setShortcut(QKeySequence::Redo);
257         view->pageAction(QWebPage::Cut)->setShortcut(QKeySequence::Cut);
258         view->pageAction(QWebPage::Copy)->setShortcut(QKeySequence::Copy);
259         view->pageAction(QWebPage::Paste)->setShortcut(QKeySequence::Paste);
260         zoomIn->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Plus));
261         zoomOut->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Minus));
262         resetZoom->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_0));
263         view->pageAction(QWebPage::ToggleBold)->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_B));
264         view->pageAction(QWebPage::ToggleItalic)->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_I));
265         view->pageAction(QWebPage::ToggleUnderline)->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_U));
266     }
267
268     QUrl guessUrlFromString(const QString &string) {
269         QString urlStr = string.trimmed();
270         QRegExp test(QLatin1String("^[a-zA-Z]+\\:.*"));
271
272         // Check if it looks like a qualified URL. Try parsing it and see.
273         bool hasSchema = test.exactMatch(urlStr);
274         if (hasSchema) {
275             QUrl url(urlStr, QUrl::TolerantMode);
276             if (url.isValid())
277                 return url;
278         }
279
280         // Might be a file.
281         if (QFile::exists(urlStr))
282             return QUrl::fromLocalFile(urlStr);
283
284         // Might be a shorturl - try to detect the schema.
285         if (!hasSchema) {
286             int dotIndex = urlStr.indexOf(QLatin1Char('.'));
287             if (dotIndex != -1) {
288                 QString prefix = urlStr.left(dotIndex).toLower();
289                 QString schema = (prefix == QLatin1String("ftp")) ? prefix : QLatin1String("http");
290                 QUrl url(schema + QLatin1String("://") + urlStr, QUrl::TolerantMode);
291                 if (url.isValid())
292                     return url;
293             }
294         }
295
296         // Fall back to QUrl's own tolerant parser.
297         return QUrl(string, QUrl::TolerantMode);
298     }
299
300     QWebView *view;
301     QLineEdit *urlEdit;
302     QProgressBar *progress;
303
304     QAction *formatMenuAction;
305
306     QStringList urlList;
307     QStringListModel urlModel;
308 };
309
310 QWebPage *WebPage::createWindow(QWebPage::WebWindowType)
311 {
312     MainWindow *mw = new MainWindow;
313     return mw->webPage();
314 }
315
316 QObject *WebPage::createPlugin(const QString &classId, const QUrl &url, const QStringList &paramNames, const QStringList &paramValues)
317 {
318     Q_UNUSED(url);
319     Q_UNUSED(paramNames);
320     Q_UNUSED(paramValues);
321     QUiLoader loader;
322     return loader.createWidget(classId, view());
323 }
324
325 #include "main.moc"
326
327 int main(int argc, char **argv)
328 {
329     QApplication app(argc, argv);
330     QString url = QString("%1/%2").arg(QDir::homePath()).arg(QLatin1String("index.html"));
331
332     QWebSettings::setMaximumPagesInCache(4);
333
334     app.setApplicationName("QtLauncher");
335 #if QT_VERSION >= 0x040400
336     app.setApplicationVersion("0.1");
337 #endif
338
339     QWebSettings::setObjectCacheCapacities((16*1024*1024) / 8, (16*1024*1024) / 8, 16*1024*1024);
340
341     QWebSettings::globalSettings()->setAttribute(QWebSettings::PluginsEnabled, true);
342     QWebSettings::globalSettings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
343
344     const QStringList args = app.arguments();
345     if (args.count() > 1)
346         url = args.at(1);
347
348     MainWindow window(url);
349     window.show();
350
351     return app.exec();
352 }
353