1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the demonstration applications of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL21$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** $QT_END_LICENSE$
31 **
32 ****************************************************************************/
33
34 #include "tabwidget.h"
35
36 #include "browserapplication.h"
37 #include "browsermainwindow.h"
38 #include "history.h"
39 #include "urllineedit.h"
40 #include "webview.h"
41
42 #include <QtCore/QMimeData>
43 #include <QtGui/QClipboard>
44 #include <QtWidgets/QCompleter>
45 #include <QtWidgets/QListView>
46 #include <QtWidgets/QMenu>
47 #include <QtWidgets/QMessageBox>
48 #include <QtGui/QDrag>
49 #include <QtGui/QMouseEvent>
50 #include <QtWidgets/QStackedWidget>
51 #include <QtWidgets/QStyle>
52 #include <QtWidgets/QToolButton>
53
54 #include <QtCore/QDebug>
55
TabBar(QWidget * parent)56 TabBar::TabBar(QWidget *parent)
57 : QTabBar(parent)
58 {
59 setContextMenuPolicy(Qt::CustomContextMenu);
60 setAcceptDrops(true);
61 connect(this, SIGNAL(customContextMenuRequested(QPoint)),
62 this, SLOT(contextMenuRequested(QPoint)));
63
64 QString ctrl = QLatin1String("Ctrl+%1");
65 for (int i = 1; i <= 10; ++i) {
66 int key = i;
67 if (key == 10)
68 key = 0;
69 QShortcut *shortCut = new QShortcut(ctrl.arg(key), this);
70 m_tabShortcuts.append(shortCut);
71 connect(shortCut, SIGNAL(activated()), this, SLOT(selectTabAction()));
72 }
73 setTabsClosable(true);
74 connect(this, SIGNAL(tabCloseRequested(int)),
75 this, SIGNAL(closeTab(int)));
76 setSelectionBehaviorOnRemove(QTabBar::SelectPreviousTab);
77 setMovable(true);
78 }
79
selectTabAction()80 void TabBar::selectTabAction()
81 {
82 if (QShortcut *shortCut = qobject_cast<QShortcut*>(sender())) {
83 int index = m_tabShortcuts.indexOf(shortCut);
84 if (index == 0)
85 index = 10;
86 setCurrentIndex(index);
87 }
88 }
89
contextMenuRequested(const QPoint & position)90 void TabBar::contextMenuRequested(const QPoint &position)
91 {
92 QMenu menu;
93 menu.addAction(tr("New &Tab"), this, SIGNAL(newTab()), QKeySequence::AddTab);
94 int index = tabAt(position);
95 if (-1 != index) {
96 QAction *action = menu.addAction(tr("Clone Tab"),
97 this, SLOT(cloneTab()));
98 action->setData(index);
99
100 menu.addSeparator();
101
102 action = menu.addAction(tr("&Close Tab"),
103 this, SLOT(closeTab()), QKeySequence::Close);
104 action->setData(index);
105
106 action = menu.addAction(tr("Close &Other Tabs"),
107 this, SLOT(closeOtherTabs()));
108 action->setData(index);
109
110 menu.addSeparator();
111
112 action = menu.addAction(tr("Reload Tab"),
113 this, SLOT(reloadTab()), QKeySequence::Refresh);
114 action->setData(index);
115 } else {
116 menu.addSeparator();
117 }
118 menu.addAction(tr("Reload All Tabs"), this, SIGNAL(reloadAllTabs()));
119 menu.exec(QCursor::pos());
120 }
121
cloneTab()122 void TabBar::cloneTab()
123 {
124 if (QAction *action = qobject_cast<QAction*>(sender())) {
125 int index = action->data().toInt();
126 emit cloneTab(index);
127 }
128 }
129
closeTab()130 void TabBar::closeTab()
131 {
132 if (QAction *action = qobject_cast<QAction*>(sender())) {
133 int index = action->data().toInt();
134 emit closeTab(index);
135 }
136 }
137
closeOtherTabs()138 void TabBar::closeOtherTabs()
139 {
140 if (QAction *action = qobject_cast<QAction*>(sender())) {
141 int index = action->data().toInt();
142 emit closeOtherTabs(index);
143 }
144 }
145
mousePressEvent(QMouseEvent * event)146 void TabBar::mousePressEvent(QMouseEvent *event)
147 {
148 if (event->button() == Qt::LeftButton)
149 m_dragStartPos = event->pos();
150 QTabBar::mousePressEvent(event);
151 }
152
mouseMoveEvent(QMouseEvent * event)153 void TabBar::mouseMoveEvent(QMouseEvent *event)
154 {
155 if (event->buttons() == Qt::LeftButton) {
156 int diffX = event->pos().x() - m_dragStartPos.x();
157 int diffY = event->pos().y() - m_dragStartPos.y();
158 if ((event->pos() - m_dragStartPos).manhattanLength() > QApplication::startDragDistance()
159 && diffX < 3 && diffX > -3
160 && diffY < -10) {
161 QDrag *drag = new QDrag(this);
162 QMimeData *mimeData = new QMimeData;
163 QList<QUrl> urls;
164 int index = tabAt(event->pos());
165 QUrl url = tabData(index).toUrl();
166 urls.append(url);
167 mimeData->setUrls(urls);
168 mimeData->setText(tabText(index));
169 mimeData->setData(QLatin1String("action"), "tab-reordering");
170 drag->setMimeData(mimeData);
171 drag->exec();
172 }
173 }
174 QTabBar::mouseMoveEvent(event);
175 }
176
177 // When index is -1 index chooses the current tab
reloadTab(int index)178 void TabWidget::reloadTab(int index)
179 {
180 if (index < 0)
181 index = currentIndex();
182 if (index < 0 || index >= count())
183 return;
184
185 QWidget *widget = this->widget(index);
186 if (WebView *tab = qobject_cast<WebView*>(widget))
187 tab->reload();
188 }
189
reloadTab()190 void TabBar::reloadTab()
191 {
192 if (QAction *action = qobject_cast<QAction*>(sender())) {
193 int index = action->data().toInt();
194 emit reloadTab(index);
195 }
196 }
197
TabWidget(QWidget * parent)198 TabWidget::TabWidget(QWidget *parent)
199 : QTabWidget(parent)
200 , m_recentlyClosedTabsAction(0)
201 , m_newTabAction(0)
202 , m_closeTabAction(0)
203 , m_nextTabAction(0)
204 , m_previousTabAction(0)
205 , m_recentlyClosedTabsMenu(0)
206 , m_lineEditCompleter(0)
207 , m_lineEdits(0)
208 , m_tabBar(new TabBar(this))
209 {
210 setElideMode(Qt::ElideRight);
211
212 connect(m_tabBar, SIGNAL(newTab()), this, SLOT(newTab()));
213 connect(m_tabBar, SIGNAL(closeTab(int)), this, SLOT(closeTab(int)));
214 connect(m_tabBar, SIGNAL(cloneTab(int)), this, SLOT(cloneTab(int)));
215 connect(m_tabBar, SIGNAL(closeOtherTabs(int)), this, SLOT(closeOtherTabs(int)));
216 connect(m_tabBar, SIGNAL(reloadTab(int)), this, SLOT(reloadTab(int)));
217 connect(m_tabBar, SIGNAL(reloadAllTabs()), this, SLOT(reloadAllTabs()));
218 connect(m_tabBar, SIGNAL(tabMoved(int,int)), this, SLOT(moveTab(int,int)));
219 setTabBar(m_tabBar);
220 setDocumentMode(true);
221
222 // Actions
223 m_newTabAction = new QAction(QIcon(QLatin1String(":addtab.png")), tr("New &Tab"), this);
224 m_newTabAction->setShortcuts(QKeySequence::AddTab);
225 m_newTabAction->setIconVisibleInMenu(false);
226 connect(m_newTabAction, SIGNAL(triggered()), this, SLOT(newTab()));
227
228 m_closeTabAction = new QAction(QIcon(QLatin1String(":closetab.png")), tr("&Close Tab"), this);
229 m_closeTabAction->setShortcuts(QKeySequence::Close);
230 m_closeTabAction->setIconVisibleInMenu(false);
231 connect(m_closeTabAction, SIGNAL(triggered()), this, SLOT(closeTab()));
232
233 m_nextTabAction = new QAction(tr("Show Next Tab"), this);
234 QList<QKeySequence> shortcuts;
235 shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_BraceRight));
236 shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_PageDown));
237 shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_BracketRight));
238 shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_Less));
239 m_nextTabAction->setShortcuts(shortcuts);
240 connect(m_nextTabAction, SIGNAL(triggered()), this, SLOT(nextTab()));
241
242 m_previousTabAction = new QAction(tr("Show Previous Tab"), this);
243 shortcuts.clear();
244 shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_BraceLeft));
245 shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_PageUp));
246 shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_BracketLeft));
247 shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_Greater));
248 m_previousTabAction->setShortcuts(shortcuts);
249 connect(m_previousTabAction, SIGNAL(triggered()), this, SLOT(previousTab()));
250
251 m_recentlyClosedTabsMenu = new QMenu(this);
252 connect(m_recentlyClosedTabsMenu, SIGNAL(aboutToShow()),
253 this, SLOT(aboutToShowRecentTabsMenu()));
254 connect(m_recentlyClosedTabsMenu, SIGNAL(triggered(QAction*)),
255 this, SLOT(aboutToShowRecentTriggeredAction(QAction*)));
256 m_recentlyClosedTabsAction = new QAction(tr("Recently Closed Tabs"), this);
257 m_recentlyClosedTabsAction->setMenu(m_recentlyClosedTabsMenu);
258 m_recentlyClosedTabsAction->setEnabled(false);
259
260 connect(this, SIGNAL(currentChanged(int)),
261 this, SLOT(currentChanged(int)));
262
263 m_lineEdits = new QStackedWidget(this);
264 }
265
clear()266 void TabWidget::clear()
267 {
268 // clear the recently closed tabs
269 m_recentlyClosedTabs.clear();
270 // clear the line edit history
271 for (int i = 0; i < m_lineEdits->count(); ++i) {
272 QLineEdit *qLineEdit = lineEdit(i);
273 qLineEdit->setText(qLineEdit->text());
274 }
275 }
276
moveTab(int fromIndex,int toIndex)277 void TabWidget::moveTab(int fromIndex, int toIndex)
278 {
279 QWidget *lineEdit = m_lineEdits->widget(fromIndex);
280 m_lineEdits->removeWidget(lineEdit);
281 m_lineEdits->insertWidget(toIndex, lineEdit);
282 }
283
addWebAction(QAction * action,QWebPage::WebAction webAction)284 void TabWidget::addWebAction(QAction *action, QWebPage::WebAction webAction)
285 {
286 if (!action)
287 return;
288 m_actions.append(new WebActionMapper(action, webAction, this));
289 }
290
currentChanged(int index)291 void TabWidget::currentChanged(int index)
292 {
293 WebView *webView = this->webView(index);
294 if (!webView)
295 return;
296
297 Q_ASSERT(m_lineEdits->count() == count());
298
299 WebView *oldWebView = this->webView(m_lineEdits->currentIndex());
300 if (oldWebView) {
301 disconnect(oldWebView, SIGNAL(statusBarMessage(QString)),
302 this, SIGNAL(showStatusBarMessage(QString)));
303 disconnect(oldWebView->page(), SIGNAL(linkHovered(QString,QString,QString)),
304 this, SIGNAL(linkHovered(QString)));
305 disconnect(oldWebView, SIGNAL(loadProgress(int)),
306 this, SIGNAL(loadProgress(int)));
307 }
308
309 connect(webView, SIGNAL(statusBarMessage(QString)),
310 this, SIGNAL(showStatusBarMessage(QString)));
311 connect(webView->page(), SIGNAL(linkHovered(QString,QString,QString)),
312 this, SIGNAL(linkHovered(QString)));
313 connect(webView, SIGNAL(loadProgress(int)),
314 this, SIGNAL(loadProgress(int)));
315
316 for (int i = 0; i < m_actions.count(); ++i) {
317 WebActionMapper *mapper = m_actions[i];
318 mapper->updateCurrent(webView->page());
319 }
320 emit setCurrentTitle(webView->title());
321 m_lineEdits->setCurrentIndex(index);
322 emit loadProgress(webView->progress());
323 emit showStatusBarMessage(webView->lastStatusBarText());
324 if (webView->url().isEmpty())
325 m_lineEdits->currentWidget()->setFocus();
326 else
327 webView->setFocus();
328 }
329
newTabAction() const330 QAction *TabWidget::newTabAction() const
331 {
332 return m_newTabAction;
333 }
334
closeTabAction() const335 QAction *TabWidget::closeTabAction() const
336 {
337 return m_closeTabAction;
338 }
339
recentlyClosedTabsAction() const340 QAction *TabWidget::recentlyClosedTabsAction() const
341 {
342 return m_recentlyClosedTabsAction;
343 }
344
nextTabAction() const345 QAction *TabWidget::nextTabAction() const
346 {
347 return m_nextTabAction;
348 }
349
previousTabAction() const350 QAction *TabWidget::previousTabAction() const
351 {
352 return m_previousTabAction;
353 }
354
lineEditStack() const355 QWidget *TabWidget::lineEditStack() const
356 {
357 return m_lineEdits;
358 }
359
currentLineEdit() const360 QLineEdit *TabWidget::currentLineEdit() const
361 {
362 return lineEdit(m_lineEdits->currentIndex());
363 }
364
currentWebView() const365 WebView *TabWidget::currentWebView() const
366 {
367 return webView(currentIndex());
368 }
369
lineEdit(int index) const370 QLineEdit *TabWidget::lineEdit(int index) const
371 {
372 UrlLineEdit *urlLineEdit = qobject_cast<UrlLineEdit*>(m_lineEdits->widget(index));
373 if (urlLineEdit)
374 return urlLineEdit->lineEdit();
375 return 0;
376 }
377
webView(int index) const378 WebView *TabWidget::webView(int index) const
379 {
380 QWidget *widget = this->widget(index);
381 if (WebView *webView = qobject_cast<WebView*>(widget)) {
382 return webView;
383 } else {
384 // optimization to delay creating the first webview
385 if (count() == 1) {
386 TabWidget *that = const_cast<TabWidget*>(this);
387 that->setUpdatesEnabled(false);
388 that->newTab();
389 that->closeTab(0);
390 that->setUpdatesEnabled(true);
391 return currentWebView();
392 }
393 }
394 return 0;
395 }
396
webViewIndex(WebView * webView) const397 int TabWidget::webViewIndex(WebView *webView) const
398 {
399 int index = indexOf(webView);
400 return index;
401 }
402
newTab(bool makeCurrent)403 WebView *TabWidget::newTab(bool makeCurrent)
404 {
405 // line edit
406 UrlLineEdit *urlLineEdit = new UrlLineEdit;
407 QLineEdit *lineEdit = urlLineEdit->lineEdit();
408 if (!m_lineEditCompleter && count() > 0) {
409 HistoryCompletionModel *completionModel = new HistoryCompletionModel(this);
410 completionModel->setSourceModel(BrowserApplication::historyManager()->historyFilterModel());
411 m_lineEditCompleter = new QCompleter(completionModel, this);
412 // Should this be in Qt by default?
413 QAbstractItemView *popup = m_lineEditCompleter->popup();
414 QListView *listView = qobject_cast<QListView*>(popup);
415 if (listView)
416 listView->setUniformItemSizes(true);
417 }
418 lineEdit->setCompleter(m_lineEditCompleter);
419 connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(lineEditReturnPressed()));
420 m_lineEdits->addWidget(urlLineEdit);
421 m_lineEdits->setSizePolicy(lineEdit->sizePolicy());
422
423 // optimization to delay creating the more expensive WebView, history, etc
424 if (count() == 0) {
425 QWidget *emptyWidget = new QWidget;
426 QPalette p = emptyWidget->palette();
427 p.setColor(QPalette::Window, palette().color(QPalette::Base));
428 emptyWidget->setPalette(p);
429 emptyWidget->setAutoFillBackground(true);
430 disconnect(this, SIGNAL(currentChanged(int)),
431 this, SLOT(currentChanged(int)));
432 addTab(emptyWidget, tr("(Untitled)"));
433 connect(this, SIGNAL(currentChanged(int)),
434 this, SLOT(currentChanged(int)));
435 return 0;
436 }
437
438 // webview
439 WebView *webView = new WebView;
440 urlLineEdit->setWebView(webView);
441 connect(webView, SIGNAL(loadStarted()),
442 this, SLOT(webViewLoadStarted()));
443 connect(webView, SIGNAL(loadFinished(bool)),
444 this, SLOT(webViewIconChanged()));
445 connect(webView, SIGNAL(iconChanged()),
446 this, SLOT(webViewIconChanged()));
447 connect(webView, SIGNAL(titleChanged(QString)),
448 this, SLOT(webViewTitleChanged(QString)));
449 connect(webView, SIGNAL(urlChanged(QUrl)),
450 this, SLOT(webViewUrlChanged(QUrl)));
451 connect(webView->page(), SIGNAL(windowCloseRequested()),
452 this, SLOT(windowCloseRequested()));
453 connect(webView->page(), SIGNAL(geometryChangeRequested(QRect)),
454 this, SIGNAL(geometryChangeRequested(QRect)));
455 connect(webView->page(), SIGNAL(printRequested(QWebFrame*)),
456 this, SIGNAL(printRequested(QWebFrame*)));
457 connect(webView->page(), SIGNAL(menuBarVisibilityChangeRequested(bool)),
458 this, SIGNAL(menuBarVisibilityChangeRequested(bool)));
459 connect(webView->page(), SIGNAL(statusBarVisibilityChangeRequested(bool)),
460 this, SIGNAL(statusBarVisibilityChangeRequested(bool)));
461 connect(webView->page(), SIGNAL(toolBarVisibilityChangeRequested(bool)),
462 this, SIGNAL(toolBarVisibilityChangeRequested(bool)));
463 addTab(webView, tr("(Untitled)"));
464 if (makeCurrent)
465 setCurrentWidget(webView);
466
467 // webview actions
468 for (int i = 0; i < m_actions.count(); ++i) {
469 WebActionMapper *mapper = m_actions[i];
470 mapper->addChild(webView->page()->action(mapper->webAction()));
471 }
472
473 if (count() == 1)
474 currentChanged(currentIndex());
475 emit tabsChanged();
476 return webView;
477 }
478
reloadAllTabs()479 void TabWidget::reloadAllTabs()
480 {
481 for (int i = 0; i < count(); ++i) {
482 QWidget *tabWidget = widget(i);
483 if (WebView *tab = qobject_cast<WebView*>(tabWidget)) {
484 tab->reload();
485 }
486 }
487 }
488
lineEditReturnPressed()489 void TabWidget::lineEditReturnPressed()
490 {
491 if (QLineEdit *lineEdit = qobject_cast<QLineEdit*>(sender())) {
492 emit loadPage(lineEdit->text());
493 if (m_lineEdits->currentWidget() == lineEdit)
494 currentWebView()->setFocus();
495 }
496 }
497
windowCloseRequested()498 void TabWidget::windowCloseRequested()
499 {
500 WebPage *webPage = qobject_cast<WebPage*>(sender());
501 WebView *webView = qobject_cast<WebView*>(webPage->view());
502 int index = webViewIndex(webView);
503 if (index >= 0) {
504 if (count() == 1)
505 webView->webPage()->mainWindow()->close();
506 else
507 closeTab(index);
508 }
509 }
510
closeOtherTabs(int index)511 void TabWidget::closeOtherTabs(int index)
512 {
513 if (-1 == index)
514 return;
515 for (int i = count() - 1; i > index; --i)
516 closeTab(i);
517 for (int i = index - 1; i >= 0; --i)
518 closeTab(i);
519 }
520
521 // When index is -1 index chooses the current tab
cloneTab(int index)522 void TabWidget::cloneTab(int index)
523 {
524 if (index < 0)
525 index = currentIndex();
526 if (index < 0 || index >= count())
527 return;
528 WebView *tab = newTab(false);
529 tab->setUrl(webView(index)->url());
530 }
531
532 // When index is -1 index chooses the current tab
closeTab(int index)533 void TabWidget::closeTab(int index)
534 {
535 if (index < 0)
536 index = currentIndex();
537 if (index < 0 || index >= count())
538 return;
539
540 bool hasFocus = false;
541 if (WebView *tab = webView(index)) {
542 if (tab->isModified()) {
543 QMessageBox closeConfirmation(tab);
544 closeConfirmation.setWindowFlags(Qt::Sheet);
545 closeConfirmation.setWindowTitle(tr("Do you really want to close this page?"));
546 closeConfirmation.setInformativeText(tr("You have modified this page and when closing it you would lose the modification.\n"
547 "Do you really want to close this page?\n"));
548 closeConfirmation.setIcon(QMessageBox::Question);
549 closeConfirmation.addButton(QMessageBox::Yes);
550 closeConfirmation.addButton(QMessageBox::No);
551 closeConfirmation.setEscapeButton(QMessageBox::No);
552 if (closeConfirmation.exec() == QMessageBox::No)
553 return;
554 }
555 hasFocus = tab->hasFocus();
556
557 QWebSettings *globalSettings = QWebSettings::globalSettings();
558 if (!globalSettings->testAttribute(QWebSettings::PrivateBrowsingEnabled)) {
559 m_recentlyClosedTabsAction->setEnabled(true);
560 m_recentlyClosedTabs.prepend(tab->url());
561 if (m_recentlyClosedTabs.size() >= TabWidget::m_recentlyClosedTabsSize)
562 m_recentlyClosedTabs.removeLast();
563 }
564 }
565 QWidget *lineEdit = m_lineEdits->widget(index);
566 m_lineEdits->removeWidget(lineEdit);
567 lineEdit->deleteLater();
568 QWidget *webView = widget(index);
569 removeTab(index);
570 webView->deleteLater();
571 emit tabsChanged();
572 if (hasFocus && count() > 0)
573 currentWebView()->setFocus();
574 if (count() == 0)
575 emit lastTabClosed();
576 }
577
webViewLoadStarted()578 void TabWidget::webViewLoadStarted()
579 {
580 WebView *webView = qobject_cast<WebView*>(sender());
581 int index = webViewIndex(webView);
582 if (-1 != index) {
583 QIcon icon(QLatin1String(":loading.gif"));
584 setTabIcon(index, icon);
585 }
586 }
587
webViewIconChanged()588 void TabWidget::webViewIconChanged()
589 {
590 WebView *webView = qobject_cast<WebView*>(sender());
591 int index = webViewIndex(webView);
592 if (-1 != index) {
593 QIcon icon = BrowserApplication::instance()->icon(webView->url());
594 setTabIcon(index, icon);
595 }
596 }
597
webViewTitleChanged(const QString & title)598 void TabWidget::webViewTitleChanged(const QString &title)
599 {
600 WebView *webView = qobject_cast<WebView*>(sender());
601 int index = webViewIndex(webView);
602 if (-1 != index) {
603 setTabText(index, title);
604 }
605 if (currentIndex() == index)
606 emit setCurrentTitle(title);
607 BrowserApplication::historyManager()->updateHistoryItem(webView->url(), title);
608 }
609
webViewUrlChanged(const QUrl & url)610 void TabWidget::webViewUrlChanged(const QUrl &url)
611 {
612 WebView *webView = qobject_cast<WebView*>(sender());
613 int index = webViewIndex(webView);
614 if (-1 != index) {
615 m_tabBar->setTabData(index, url);
616 }
617 emit tabsChanged();
618 }
619
aboutToShowRecentTabsMenu()620 void TabWidget::aboutToShowRecentTabsMenu()
621 {
622 m_recentlyClosedTabsMenu->clear();
623 for (int i = 0; i < m_recentlyClosedTabs.count(); ++i) {
624 QAction *action = new QAction(m_recentlyClosedTabsMenu);
625 action->setData(m_recentlyClosedTabs.at(i));
626 QIcon icon = BrowserApplication::instance()->icon(m_recentlyClosedTabs.at(i));
627 action->setIcon(icon);
628 action->setText(m_recentlyClosedTabs.at(i).toString());
629 m_recentlyClosedTabsMenu->addAction(action);
630 }
631 }
632
aboutToShowRecentTriggeredAction(QAction * action)633 void TabWidget::aboutToShowRecentTriggeredAction(QAction *action)
634 {
635 QUrl url = action->data().toUrl();
636 loadUrlInCurrentTab(url);
637 }
638
mouseDoubleClickEvent(QMouseEvent * event)639 void TabWidget::mouseDoubleClickEvent(QMouseEvent *event)
640 {
641 if (!childAt(event->pos())
642 // Remove the line below when QTabWidget does not have a one pixel frame
643 && event->pos().y() < (tabBar()->y() + tabBar()->height())) {
644 newTab();
645 return;
646 }
647 QTabWidget::mouseDoubleClickEvent(event);
648 }
649
contextMenuEvent(QContextMenuEvent * event)650 void TabWidget::contextMenuEvent(QContextMenuEvent *event)
651 {
652 if (!childAt(event->pos())) {
653 m_tabBar->contextMenuRequested(event->pos());
654 return;
655 }
656 QTabWidget::contextMenuEvent(event);
657 }
658
mouseReleaseEvent(QMouseEvent * event)659 void TabWidget::mouseReleaseEvent(QMouseEvent *event)
660 {
661 #ifndef QT_NO_CLIPBOARD
662 if (event->button() == Qt::MidButton && !childAt(event->pos())
663 // Remove the line below when QTabWidget does not have a one pixel frame
664 && event->pos().y() < (tabBar()->y() + tabBar()->height())) {
665 QUrl url(QApplication::clipboard()->text(QClipboard::Selection));
666 if (!url.isEmpty() && url.isValid() && !url.scheme().isEmpty()) {
667 WebView *webView = newTab();
668 webView->setUrl(url);
669 }
670 }
671 #endif
672 }
673
loadUrlInCurrentTab(const QUrl & url)674 void TabWidget::loadUrlInCurrentTab(const QUrl &url)
675 {
676 WebView *webView = currentWebView();
677 if (webView) {
678 webView->loadUrl(url);
679 webView->setFocus();
680 }
681 }
682
nextTab()683 void TabWidget::nextTab()
684 {
685 int next = currentIndex() + 1;
686 if (next == count())
687 next = 0;
688 setCurrentIndex(next);
689 }
690
previousTab()691 void TabWidget::previousTab()
692 {
693 int next = currentIndex() - 1;
694 if (next < 0)
695 next = count() - 1;
696 setCurrentIndex(next);
697 }
698
699 static const qint32 TabWidgetMagic = 0xaa;
700
saveState() const701 QByteArray TabWidget::saveState() const
702 {
703 int version = 1;
704 QByteArray data;
705 QDataStream stream(&data, QIODevice::WriteOnly);
706
707 stream << qint32(TabWidgetMagic);
708 stream << qint32(version);
709
710 QStringList tabs;
711 for (int i = 0; i < count(); ++i) {
712 if (WebView *tab = qobject_cast<WebView*>(widget(i))) {
713 tabs.append(tab->url().toString());
714 } else {
715 tabs.append(QString());
716 }
717 }
718 stream << tabs;
719 stream << currentIndex();
720 return data;
721 }
722
restoreState(const QByteArray & state)723 bool TabWidget::restoreState(const QByteArray &state)
724 {
725 int version = 1;
726 QByteArray sd = state;
727 QDataStream stream(&sd, QIODevice::ReadOnly);
728 if (stream.atEnd())
729 return false;
730
731 qint32 marker;
732 qint32 v;
733 stream >> marker;
734 stream >> v;
735 if (marker != TabWidgetMagic || v != version)
736 return false;
737
738 QStringList openTabs;
739 stream >> openTabs;
740
741 for (int i = 0; i < openTabs.count(); ++i) {
742 if (i != 0)
743 newTab();
744 loadPage(openTabs.at(i));
745 }
746
747 int currentTab;
748 stream >> currentTab;
749 setCurrentIndex(currentTab);
750
751 return true;
752 }
753
WebActionMapper(QAction * root,QWebPage::WebAction webAction,QObject * parent)754 WebActionMapper::WebActionMapper(QAction *root, QWebPage::WebAction webAction, QObject *parent)
755 : QObject(parent)
756 , m_currentParent(0)
757 , m_root(root)
758 , m_webAction(webAction)
759 {
760 if (!m_root)
761 return;
762 connect(m_root, SIGNAL(triggered()), this, SLOT(rootTriggered()));
763 connect(root, SIGNAL(destroyed(QObject*)), this, SLOT(rootDestroyed()));
764 root->setEnabled(false);
765 }
766
rootDestroyed()767 void WebActionMapper::rootDestroyed()
768 {
769 m_root = 0;
770 }
771
currentDestroyed()772 void WebActionMapper::currentDestroyed()
773 {
774 updateCurrent(0);
775 }
776
addChild(QAction * action)777 void WebActionMapper::addChild(QAction *action)
778 {
779 if (!action)
780 return;
781 connect(action, SIGNAL(changed()), this, SLOT(childChanged()));
782 }
783
webAction() const784 QWebPage::WebAction WebActionMapper::webAction() const
785 {
786 return m_webAction;
787 }
788
rootTriggered()789 void WebActionMapper::rootTriggered()
790 {
791 if (m_currentParent) {
792 QAction *gotoAction = m_currentParent->action(m_webAction);
793 gotoAction->trigger();
794 }
795 }
796
childChanged()797 void WebActionMapper::childChanged()
798 {
799 if (QAction *source = qobject_cast<QAction*>(sender())) {
800 if (m_root
801 && m_currentParent
802 && source->parent() == m_currentParent) {
803 m_root->setChecked(source->isChecked());
804 m_root->setEnabled(source->isEnabled());
805 }
806 }
807 }
808
updateCurrent(QWebPage * currentParent)809 void WebActionMapper::updateCurrent(QWebPage *currentParent)
810 {
811 if (m_currentParent)
812 disconnect(m_currentParent, SIGNAL(destroyed(QObject*)),
813 this, SLOT(currentDestroyed()));
814
815 m_currentParent = currentParent;
816 if (!m_root)
817 return;
818 if (!m_currentParent) {
819 m_root->setEnabled(false);
820 m_root->setChecked(false);
821 return;
822 }
823 QAction *source = m_currentParent->action(m_webAction);
824 m_root->setChecked(source->isChecked());
825 m_root->setEnabled(source->isEnabled());
826 connect(m_currentParent, SIGNAL(destroyed(QObject*)),
827 this, SLOT(currentDestroyed()));
828 }
829
830