]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/dolphinmainwindow.cpp
fix possible crash when selecting "New Tab" from the tab context menu of an inactive tab
[dolphin.git] / src / dolphinmainwindow.cpp
index d19f8eb1d556e7a10399213ae6da0ef38ed9af2b..b165e1cb30d038892a03f6eeffaf4dd73d0b35aa 100644 (file)
@@ -180,10 +180,9 @@ void DolphinMainWindow::changeUrl(const KUrl& url)
         updateEditActions();
         updateViewActions();
         updateGoActions();
-        const QString caption = url.fileName();
-        setCaption(caption);
+        setCaption(url.fileName());
         if (m_viewTab.count() > 1) {
-            m_tabBar->setTabText(m_tabIndex, caption);
+            m_tabBar->setTabText(m_tabIndex, tabName(url));
         }
         emit urlChanged(url);
     }
@@ -267,10 +266,11 @@ void DolphinMainWindow::openNewTab(const KUrl& url)
     if (m_viewTab.count() == 1) {
         // Only one view is open currently and hence no tab is shown at
         // all. Before creating a tab for 'url', provide a tab for the current URL.
-        m_tabBar->addTab(KIcon("folder"), m_activeViewContainer->url().fileName());
+        m_tabBar->addTab(KIcon("folder"), tabName(m_activeViewContainer->url()));
+        m_tabBar->blockSignals(false);
     }
 
-    m_tabBar->addTab(KIcon("folder"), url.fileName());
+    m_tabBar->addTab(KIcon("folder"), tabName(url));
 
     ViewTab viewTab;
     viewTab.splitter = new QSplitter(this);
@@ -675,24 +675,102 @@ void DolphinMainWindow::setActiveTab(int index)
     // hide current tab content
     m_viewTab[m_tabIndex].isPrimaryViewActive = m_viewTab[m_tabIndex].primaryView->isActive();
     QSplitter* splitter = m_viewTab[m_tabIndex].splitter;
-    m_centralWidgetLayout->removeWidget(splitter);
     splitter->hide();
+    m_centralWidgetLayout->removeWidget(splitter);
 
     // show active tab content
     m_tabIndex = index;
 
     ViewTab& viewTab = m_viewTab[index];
     m_centralWidgetLayout->addWidget(viewTab.splitter);
-    viewTab.splitter->show();
     viewTab.primaryView->show();
     if (viewTab.secondaryView != 0) {
         viewTab.secondaryView->show();
     }
+    viewTab.splitter->show();
 
     setActiveViewContainer(viewTab.isPrimaryViewActive ? viewTab.primaryView :
                                                          viewTab.secondaryView);
 }
 
+void DolphinMainWindow::closeTab()
+{
+    closeTab(m_tabBar->currentIndex());
+}
+
+void DolphinMainWindow::closeTab(int index)
+{
+    Q_ASSERT(index >= 0);
+    Q_ASSERT(index < m_viewTab.count());
+    if (m_viewTab.count() == 1) {
+          // the last tab may never get closed
+        return;
+    }
+
+    if (index == m_tabIndex) {
+        // The tab that should be closed is the active tab. Activate the
+        // previous tab before closing the tab.
+        setActiveTab((index > 0) ? index - 1 : 1);
+    }
+
+    // delete tab
+    m_viewTab[index].primaryView->deleteLater();
+    if (m_viewTab[index].secondaryView != 0) {
+        m_viewTab[index].secondaryView->deleteLater();
+    }
+    m_viewTab[index].splitter->deleteLater();
+    m_viewTab.erase(m_viewTab.begin() + index);
+
+    m_tabBar->blockSignals(true);
+    m_tabBar->removeTab(index);
+
+    if (m_tabIndex > index) {
+        m_tabIndex--;
+        Q_ASSERT(m_tabIndex >= 0);
+    }
+
+    // if only one tab is left, also remove the tab entry so that
+    // closing the last tab is not possible
+    if (m_viewTab.count() == 1) {
+        m_tabBar->removeTab(0);
+    } else {
+        m_tabBar->blockSignals(false);
+    }
+}
+
+void DolphinMainWindow::openTabContextMenu(int index, const QPoint& pos)
+{
+    KMenu menu(this);
+
+    QAction* newTabAction = menu.addAction(KIcon("tab-new"), i18nc("@action:inmenu", "New Tab"));
+    newTabAction->setShortcut(actionCollection()->action("new_tab")->shortcut());
+
+    QAction* closeOtherTabsAction = menu.addAction(KIcon("tab-close"), i18nc("@action:inmenu", "Close Other Tabs"));
+
+    QAction* closeTabAction = menu.addAction(KIcon("tab-close"), i18nc("@action:inmenu", "Close Tab"));
+    closeTabAction->setShortcut(actionCollection()->action("close_tab")->shortcut());
+
+    QAction* selectedAction = menu.exec(pos);
+    if (selectedAction == newTabAction) {
+        const ViewTab& tab = m_viewTab[index];
+        Q_ASSERT(tab.primaryView != 0);
+        const KUrl url = (tab.secondaryView != 0) && tab.secondaryView->isActive() ?
+                         tab.secondaryView->url() : tab.primaryView->url();
+        openNewTab(url);
+        m_tabBar->setCurrentIndex(m_viewTab.count() - 1);
+    } else if (selectedAction == closeOtherTabsAction) {
+        const int count = m_tabBar->count();
+        for (int i = 0; i < index; ++i) {
+            closeTab(0);
+        }
+        for (int i = index + 1; i < count; ++i) {
+            closeTab(1);
+        }
+    } else if (selectedAction == closeTabAction) {
+        closeTab(index);
+    }
+}
+
 void DolphinMainWindow::init()
 {
     DolphinSettings& settings = DolphinSettings::instance();
@@ -728,9 +806,14 @@ void DolphinMainWindow::init()
     m_actionHandler->setCurrentView(view);
 
     m_tabBar = new KTabBar(this);
-    m_tabBar->setHoverCloseButton(true);
+    m_tabBar->setCloseButtonEnabled(true);
     connect(m_tabBar, SIGNAL(currentChanged(int)),
             this, SLOT(setActiveTab(int)));
+    connect(m_tabBar, SIGNAL(closeRequest(int)),
+            this, SLOT(closeTab(int)));
+    connect(m_tabBar, SIGNAL(contextMenu(int, const QPoint&)),
+            this, SLOT(openTabContextMenu(int, const QPoint&)));
+    m_tabBar->blockSignals(true);  // signals get unblocked after at least 2 tabs are open
 
     QWidget* centralWidget = new QWidget(this);
     m_centralWidgetLayout = new QVBoxLayout(centralWidget);
@@ -795,10 +878,9 @@ void DolphinMainWindow::setActiveViewContainer(DolphinViewContainer* viewContain
     updateGoActions();
 
     const KUrl& url = m_activeViewContainer->url();
-    const QString caption = url.fileName();
-    setCaption(caption);
+    setCaption(url.fileName());
     if (m_viewTab.count() > 1) {
-        m_tabBar->setTabText(m_tabIndex, caption);
+        m_tabBar->setTabText(m_tabIndex, tabName(url));
     }
 
     emit urlChanged(url);
@@ -826,6 +908,11 @@ void DolphinMainWindow::setupActions()
     newTab->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_N);
     connect(newTab, SIGNAL(triggered()), this, SLOT(openNewTab()));
 
+    QAction* closeTab = new QAction(KIcon("tab-close"), i18nc("@action:inmenu File", "Close Tab"), this);
+    closeTab->setShortcut(Qt::CTRL | Qt::Key_W);
+    connect(closeTab, SIGNAL(triggered()), this, SLOT(closeTab()));
+    actionCollection()->addAction("close_tab", closeTab);
+
     KAction* properties = actionCollection()->addAction("properties");
     properties->setText(i18nc("@action:inmenu File", "Properties"));
     properties->setShortcut(Qt::ALT | Qt::Key_Return);
@@ -1114,6 +1201,11 @@ void DolphinMainWindow::updateSplitAction()
     }
 }
 
+QString DolphinMainWindow::tabName(const KUrl& url) const
+{
+    return url.equals(KUrl("file:///")) ? "/" : url.fileName();
+}
+
 DolphinMainWindow::UndoUiInterface::UndoUiInterface(DolphinMainWindow* mainWin) :
     KonqFileUndoManager::UiInterface(mainWin),
     m_mainWin(mainWin)