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