xref: /OK3568_Linux_fs/app/forlinx/flapp/src/plugins/allwinner/browser/tabwidget.cpp (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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