|
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 connect(urlEdit, SIGNAL(returnPressed()), |
|
302 SLOT(changeLocation())); |
|
303 bar->addAction("Go back", page, SLOT(goBack())); |
|
304 bar->addAction("Stop", page, SLOT(stop())); |
|
305 bar->addAction("Go forward", page, SLOT(goForward())); |
|
306 bar->addWidget(urlEdit); |
|
307 |
|
308 hoverLabel = new HoverLabel(this); |
|
309 hoverLabel->hide(); |
|
310 |
|
311 page->open(url); |
|
312 |
|
313 info->raise(); |
|
314 } |
|
315 protected slots: |
|
316 void changeLocation() |
|
317 { |
|
318 QUrl url(urlEdit->text()); |
|
319 page->open(url); |
|
320 } |
|
321 void loadFinished() |
|
322 { |
|
323 urlEdit->setText(page->url().toString()); |
|
324 } |
|
325 void showLinkHover(const QString &link, const QString &toolTip) |
|
326 { |
|
327 //statusBar()->showMessage(link); |
|
328 hoverLabel->setHoverLink(link); |
|
329 #ifndef QT_NO_TOOLTIP |
|
330 if (!toolTip.isEmpty()) |
|
331 QToolTip::showText(QCursor::pos(), toolTip); |
|
332 #endif |
|
333 } |
|
334 protected: |
|
335 void resizeEvent(QResizeEvent *) { |
|
336 QSize hoverSize = hoverLabel->sizeHint(); |
|
337 hoverLabel->setGeometry(0, height()-hoverSize.height(), |
|
338 300, hoverSize.height()); |
|
339 } |
|
340 private: |
|
341 QWebPage *page; |
|
342 QLineEdit *urlEdit; |
|
343 HoverLabel *hoverLabel; |
|
344 }; |
|
345 |
|
346 #include "main.moc" |
|
347 |
|
348 int main(int argc, char **argv) |
|
349 { |
|
350 QString url = QString("%1/%2").arg(QDir::homePath()).arg(QLatin1String("index.html")); |
|
351 QApplication app(argc, argv); |
|
352 |
|
353 QWebSettings settings = QWebSettings::global(); |
|
354 settings.setAttribute(QWebSettings::PluginsEnabled); |
|
355 QWebSettings::setGlobal(settings); |
|
356 |
|
357 const QStringList args = app.arguments(); |
|
358 if (args.count() > 1) |
|
359 url = args.at(1); |
|
360 |
|
361 QUrl qurl(url); |
|
362 if (qurl.scheme().isEmpty()) |
|
363 qurl = QUrl::fromLocalFile(QFileInfo(url).absoluteFilePath()); |
|
364 MainWindow window(qurl); |
|
365 window.show(); |
|
366 |
|
367 return app.exec(); |
|
368 } |