f639685edbc48be976e5b8a2321311db2f0adb84
[WebKit-https.git] / WebKit / qt / QtLauncher / main.cpp
1 /*
2  * Copyright (C) 2006 George Staikos <staikos@kde.org>
3  * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
4  * Copyright (C) 2006 Zack Rusin <zack@kde.org>
5  * Copyright (C) 2006 Simon Hausmann <hausmann@kde.org>
6  *
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
22  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 #include <qwebpage.h>
31 #include <qwebframe.h>
32 #include <qwebsettings.h>
33
34 #include <QtGui>
35 #include <QDebug>
36
37
38
39 class InfoWidget :public QProgressBar {
40     Q_OBJECT
41 public:
42     InfoWidget(QWidget *parent)
43         : QProgressBar(parent), m_progress(0)
44     {
45         setMinimum(0);
46         setMaximum(100);
47     }
48     QSize sizeHint() const
49     {
50         QSize size(100, 20);
51         return size;
52     }
53 public slots:
54     void startLoad()
55     {
56         setValue(m_progress);
57         show();
58     }
59     void changeLoad(int change)
60     {
61         m_progress = change;
62         setValue(change);
63     }
64     void endLoad()
65     {
66         QTimer::singleShot(1000, this, SLOT(hide()));
67         m_progress = 0;
68     }
69
70 protected:
71     int m_progress;
72 };
73
74 class HoverLabel : public QWidget {
75     Q_OBJECT
76 public:
77     HoverLabel(QWidget *parent=0)
78         : QWidget(parent),
79           m_animating(false),
80           m_percent(0)
81     {
82         m_timer.setInterval(1000/30);
83         m_hideTimer.setInterval(500);
84         m_hideTimer.setSingleShot(true);
85         connect(&m_timer, SIGNAL(timeout()),
86                 this, SLOT(update()));
87         connect(&m_hideTimer, SIGNAL(timeout()),
88                 this, SLOT(hide()));
89     }
90
91 public slots:
92     void setHoverLink(const QString &link) {
93         m_link = link;
94         if (m_link.isEmpty()) {
95             m_hideTimer.start();
96         } else {
97             m_hideTimer.stop();
98             m_oldSize = m_newSize;
99             m_newSize = sizeForFont();
100             resetAnimation();
101             updateSize();
102             show();
103             repaint();
104         }
105     }
106     QSize sizeForFont() const {
107         QFont f = font();
108         QFontMetrics fm(f);
109         return QSize(fm.width(m_link) + 10, fm.height() + 6);
110     }
111     QSize sizeHint() const {
112         if (!m_animating)
113             return sizeForFont();
114         else
115             return (m_newSize.width() > m_oldSize.width()) ? m_newSize : m_oldSize;
116     }
117     void updateSize() {
118         QRect r = geometry();
119         QSize newSize = sizeHint();
120         r = QRect(r.x(), r.y(), newSize.width(), newSize.height());
121         setGeometry(r);
122     }
123     void resetAnimation() {
124         m_animating = true;
125         m_percent = 0;
126         if (!m_timer.isActive())
127             m_timer.start();
128     }
129 protected:
130     void paintEvent(QPaintEvent *e) {
131         QPainter p(this);
132         p.setClipRect(e->rect());
133         p.setPen(QPen(Qt::black, 1));
134         QLinearGradient gradient(rect().topLeft(), rect().bottomLeft());
135         gradient.setColorAt(0, QColor(255, 255, 255, 220));
136         gradient.setColorAt(1, QColor(193, 193, 193, 220));
137         p.setBrush(QBrush(gradient));
138         QSize size;
139         {
140             //draw a nicely rounded corner rectangle. to avoid unwanted
141             // borders we move the coordinates outsize the our clip region
142             size = interpolate(m_oldSize, m_newSize, m_percent);
143             QRect r(-1, 0, size.width(), size.height()+2);
144             const int roundness = 20;
145             QPainterPath path;
146             path.moveTo(r.x(), r.y());
147             path.lineTo(r.topRight().x()-roundness, r.topRight().y());
148             path.cubicTo(r.topRight().x(), r.topRight().y(),
149                          r.topRight().x(), r.topRight().y(),
150                          r.topRight().x(), r.topRight().y() + roundness);
151             path.lineTo(r.bottomRight());
152             path.lineTo(r.bottomLeft());
153             path.closeSubpath();
154             p.setRenderHint(QPainter::Antialiasing);
155             p.drawPath(path);
156         }
157         if (m_animating) {
158             if (qFuzzyCompare(m_percent, 1)) {
159                 m_animating = false;
160                 m_percent = 0;
161                 m_timer.stop();
162             } else {
163                 m_percent += 0.1;
164                 if (m_percent >= 0.99) {
165                     m_percent = 1;
166                 }
167             }
168         }
169
170         QString txt;
171         QFontMetrics fm(fontMetrics());
172         txt = fm.elidedText(m_link, Qt::ElideRight, size.width()-5);
173         p.drawText(5, height()-6, txt);
174     }
175
176 private:
177     QSize interpolate(const QSize &src, const QSize &dst, qreal percent) {
178         int widthDiff  = int((dst.width() - src.width())  * percent);
179         int heightDiff = int((dst.height() - src.height()) * percent);
180         return QSize(src.width()  + widthDiff,
181                      src.height() + heightDiff);
182     }
183     QString m_link;
184     bool    m_animating;
185     QTimer  m_timer;
186     QTimer  m_hideTimer;
187     QSize   m_oldSize;
188     QSize   m_newSize;
189     qreal   m_percent;
190 };
191
192 class SearchEdit;
193
194 class ClearButton : public QPushButton {
195     Q_OBJECT
196 public:
197     ClearButton(QWidget *w)
198         : QPushButton(w)
199     {
200         setMinimumSize(24, 24);
201         setFixedSize(24, 24);
202         setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
203     }
204     void paintEvent(QPaintEvent *event)
205     {
206         Q_UNUSED(event);
207         QPainter painter(this);
208         int height = parentWidget()->geometry().height();
209         int width = height; //parentWidget()->geometry().width();
210
211         painter.setRenderHint(QPainter::Antialiasing, true);
212         painter.setPen(Qt::lightGray);
213         painter.setBrush(isDown() ?
214                          QColor(140, 140, 190) :
215                          underMouse() ? QColor(220, 220, 255) : QColor(200, 200, 230)
216             );
217         painter.drawEllipse(4, 4, width - 8, height - 8);
218         painter.setPen(Qt::white);
219         int border = 8;
220         painter.drawLine(border, border, width - border, height - border);
221         painter.drawLine(border, height - border, width - border, border);
222     }
223 };
224
225 class SearchEdit : public QLineEdit
226 {
227     Q_OBJECT
228 public:
229     SearchEdit(const QString &str, QWidget *parent = 0)
230         : QLineEdit(str, parent)
231     {
232         setMinimumSize(QSize(400, 24));
233         setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
234
235         setStyleSheet(":enabled { padding-right: 27px }");
236         clearButton = new ClearButton(this);
237         clearButton->setGeometry(QRect(geometry().right() - 27,
238                                        geometry().top() - 2,
239                                        geometry().right(), geometry().bottom()));
240         clearButton->setVisible(true);
241 #ifndef QT_NO_CURSOR
242         clearButton->setCursor(Qt::ArrowCursor);
243 #endif
244 #ifndef QT_NO_TOOLTIP
245         clearButton->setToolTip("Clear");
246 #endif
247         connect(clearButton, SIGNAL(clicked()), this, SLOT(clear()));
248     }
249     ~SearchEdit() { }
250 protected:
251     virtual void paintEvent(QPaintEvent *e) {
252         QLineEdit::paintEvent(e);
253         if(text().isEmpty())
254             clearButton->setVisible(false);
255         else
256             clearButton->setVisible(true);
257     }
258     virtual void resizeEvent(QResizeEvent *) {
259         clearButton->setParent(this);
260         clearButton->setGeometry(QRect(width()-27,
261                                        0,
262                                        24, 24));
263     }
264     virtual void moveEvent(QMoveEvent *) {
265         clearButton->setParent(this);
266         clearButton->setGeometry(QRect(width()-27, 1,
267                                        24, 24));
268     }
269
270     QPushButton *clearButton;
271 };
272
273 class MainWindow : public QMainWindow
274 {
275     Q_OBJECT
276 public:
277     MainWindow(const QUrl &url)
278     {
279         page = new QWebPage(this);
280         InfoWidget *info = new InfoWidget(page);
281         info->setGeometry(20, 20, info->sizeHint().width(),
282                           info->sizeHint().height());
283         connect(page, SIGNAL(loadStarted(QWebFrame*)),
284                 info, SLOT(startLoad()));
285         connect(page, SIGNAL(loadProgressChanged(int)),
286                 info, SLOT(changeLoad(int)));
287         connect(page, SIGNAL(loadFinished(QWebFrame*)),
288                 info, SLOT(endLoad()));
289         connect(page, SIGNAL(loadFinished(QWebFrame*)),
290                 this, SLOT(loadFinished()));
291         connect(page, SIGNAL(titleChanged(const QString&)),
292                 this, SLOT(setWindowTitle(const QString&)));
293         connect(page, SIGNAL(hoveringOverLink(const QString&, const QString&)),
294                 this, SLOT(showLinkHover(const QString&, const QString&)));
295
296
297         setCentralWidget(page);
298
299         QToolBar *bar = addToolBar("Navigation");
300         urlEdit = new SearchEdit(url.toString());
301         urlEdit->setSizePolicy(QSizePolicy::Expanding, urlEdit->sizePolicy().verticalPolicy());
302         connect(urlEdit, SIGNAL(returnPressed()),
303                 SLOT(changeLocation()));
304         bar->addAction(page->webAction(QWebPage::GoBack));
305         bar->addAction(page->webAction(QWebPage::Stop));
306         bar->addAction(page->webAction(QWebPage::GoForward));
307         bar->addSeparator();
308         bar->addAction(page->webAction(QWebPage::Cut));
309         bar->addAction(page->webAction(QWebPage::Copy));
310         bar->addAction(page->webAction(QWebPage::Paste));
311         bar->addSeparator();
312         bar->addAction(page->webAction(QWebPage::Undo));
313         bar->addAction(page->webAction(QWebPage::Redo));
314
315         addToolBarBreak();
316         bar = addToolBar("Location");
317         bar->addWidget(new QLabel(tr("Location:")));
318         bar->addWidget(urlEdit);
319
320         hoverLabel = new HoverLabel(this);
321         hoverLabel->hide();
322
323         page->open(url);
324
325         info->raise();
326     }
327 protected slots:
328     void changeLocation()
329     {
330         QUrl url(urlEdit->text());
331         page->open(url);
332     }
333     void loadFinished()
334     {
335         urlEdit->setText(page->url().toString());
336     }
337     void showLinkHover(const QString &link, const QString &toolTip)
338     {
339         //statusBar()->showMessage(link);
340         hoverLabel->setHoverLink(link);
341 #ifndef QT_NO_TOOLTIP
342         if (!toolTip.isEmpty())
343             QToolTip::showText(QCursor::pos(), toolTip);
344 #endif
345     }
346 protected:
347     void resizeEvent(QResizeEvent *) {
348         QSize hoverSize = hoverLabel->sizeHint();
349         hoverLabel->setGeometry(0, height()-hoverSize.height(),
350                                 300, hoverSize.height());
351     }
352 private:
353     QWebPage *page;
354     QLineEdit *urlEdit;
355     HoverLabel *hoverLabel;
356 };
357
358 #include "main.moc"
359
360 int main(int argc, char **argv)
361 {
362     QString url = QString("%1/%2").arg(QDir::homePath()).arg(QLatin1String("index.html"));
363     QApplication app(argc, argv);
364
365     QWebSettings settings = QWebSettings::global();
366     settings.setAttribute(QWebSettings::PluginsEnabled);
367     QWebSettings::setGlobal(settings);
368
369     const QStringList args = app.arguments();
370     if (args.count() > 1)
371         url = args.at(1);
372
373     QUrl qurl(url);
374     if (qurl.scheme().isEmpty())
375         qurl = QUrl::fromLocalFile(QFileInfo(url).absoluteFilePath());
376     MainWindow window(qurl);
377     window.show();
378
379     return app.exec();
380 }