]> cloud.milkyroute.net Git - dolphin.git/commitdiff
Merge branch 'KDE/4.14'
authorEmmanuel Pescosta <emmanuelpescosta099@gmail.com>
Wed, 29 Oct 2014 11:20:10 +0000 (12:20 +0100)
committerEmmanuel Pescosta <emmanuelpescosta099@gmail.com>
Wed, 29 Oct 2014 11:20:10 +0000 (12:20 +0100)
21 files changed:
src/CMakeLists.txt
src/dolphin.appdata.xml
src/dolphinmainwindow.cpp
src/dolphinmainwindow.h
src/dolphinrecenttabsmenu.cpp
src/dolphinrecenttabsmenu.h
src/dolphintabbar.cpp [new file with mode: 0644]
src/dolphintabbar.h [new file with mode: 0644]
src/dolphintabpage.cpp
src/dolphintabpage.h
src/dolphintabwidget.cpp [new file with mode: 0644]
src/dolphintabwidget.h [new file with mode: 0644]
src/dolphinui.rc
src/main.cpp
src/panels/places/placesitem.cpp
src/panels/places/placesitem.h
src/panels/places/placesitemmodel.cpp
src/panels/places/placespanel.cpp
src/panels/terminal/terminalpanel.cpp
src/panels/terminal/terminalpanel.h
src/views/dolphinview.cpp

index 518c8b7d2f68e33dabc5df07be162095b9bd2c25..6f256a2f43c25bded169883313e3d07f51e67d08 100644 (file)
@@ -171,8 +171,10 @@ set(dolphin_SRCS
     dolphinmainwindow.cpp
     dolphinviewcontainer.cpp
     dolphincontextmenu.cpp
+    dolphintabbar.cpp
     dolphinrecenttabsmenu.cpp
     dolphintabpage.cpp
+    dolphintabwidget.cpp
     filterbar/filterbar.cpp
     main.cpp
     panels/information/filemetadataconfigurationdialog.cpp
index d9f6266641972d89047382c28476e118e68301e2..413cc984315bfd4083797053d4385bbe674d07fc 100644 (file)
@@ -16,6 +16,7 @@
   <name xml:lang="fr">Dolphin</name>
   <name xml:lang="ia">Dolphin</name>
   <name xml:lang="it">Dolphin</name>
+  <name xml:lang="ko">Dolphin</name>
   <name xml:lang="lt">Dolphin</name>
   <name xml:lang="nb">Dolphin</name>
   <name xml:lang="nds">Dolphin</name>
@@ -47,6 +48,7 @@
   <summary xml:lang="fr">Gestionnaire de fichier</summary>
   <summary xml:lang="ia">Gerente de File</summary>
   <summary xml:lang="it">Gestore file</summary>
+  <summary xml:lang="ko">파일 관리자</summary>
   <summary xml:lang="lt">Failų tvarkyklė</summary>
   <summary xml:lang="nb">Filbehandler</summary>
   <summary xml:lang="nds">Dateipleger</summary>
@@ -77,6 +79,7 @@
     <p xml:lang="fr">Dolphin est un gestionnaire de fichier léger. Il a été conçu en gardant à l'esprit la simplicité et l'aisance à l'usage, tout en permettant flexibilité et personnalisation. Cela signifie que vous pouvez gérer vos fichiers de la manière exacte que vous voulez.</p>
     <p xml:lang="ia">Dolphin es un gerente de file legier. Il ha essite designate con facilitate de uso e simplicitate in le mente, mentre il permitte ancora flexibilitate e personalisation. Isto significa que tu pote facer le gerente de file exactemente como tu lo vole.</p>
     <p xml:lang="it">Dolphin è un gestore file leggero. È stato progettato per essere facile da utilizzare e pensando alla semplicità, garantendo al contempo flessibilità e personalizzazione. Ciò significa che puoi gestire i tuoi file come meglio desideri.</p>
+    <p xml:lang="ko">Dolphin은 가벼운 파일 관리자입니다. 사용 편의성과 간단함을 위주로 설계되었으며, 유연성과 사용자 정의 가능성을 배제하지 않았습니다. 원하는 대로 파일을 관리할 수 있습니다.</p>
     <p xml:lang="nb">Dolphin er en lettvekts filbehandler. Den er laget for å være enkel og lett å bruke, samtidig som den er fleksibel og kan tilpasses. Det betyr at du kan utføre dine filbehandlingsoppgaver akkurat slik du vil gjøre det.</p>
     <p xml:lang="nds">Dolphin is en slank Dateipleger. Dat wöör buut mit de Idee vun't eenfache Bedenen vör Ogen, bides dat liekers flexibel un topassbor wesen schull. Du kannst Dien Dateien also jüst so plegen, as Du dat wullt.</p>
     <p xml:lang="nl">Dolphin is een lichtgewicht bestandsbeheerder. Het is ontworpen met gebruiksgemak en eenvoud in gedachte en staat toch flexibiliteit en aan te passen toe. Dit betekent dat u uw bestandsbeheer kunt doen precies op de manier zoals u dat wilt.</p>
     <p xml:lang="fr">Fonctionnalités :</p>
     <p xml:lang="ia">Characteristicas:</p>
     <p xml:lang="it">Funzionalità:</p>
+    <p xml:lang="ko">기능:</p>
     <p xml:lang="lt">Galimybės</p>
     <p xml:lang="nb">Egenskaper:</p>
     <p xml:lang="nds">Markmalen:</p>
     <p xml:lang="sv">Funktioner:</p>
     <p xml:lang="uk">Можливості:</p>
     <p xml:lang="x-test">xxFeatures:xx</p>
-    <p xml:lang="zh-TW">特色:</p>
+    <p xml:lang="zh-TW">功能:</p>
     <ul>
       <li>Navigation (or breadcrumb) bar for URLs, allowing you to quickly navigate through the hierarchy of files and folders.</li>
       <li xml:lang="ca">Barra de navegació (o fil d'Ariadna) per els URL, permetent una navegació ràpida per la jerarquia de fitxers i carpetes.</li>
       <li xml:lang="fr">Barre de navigation (ou fil d'Ariane) permettant de naviguer rapidement dans la hiérarchie de fichiers et de dossiers.</li>
       <li xml:lang="ia">Barra de navigation (o "breadcrumb") pro URLs, que il permitte te navigar rapidemente a transverso del hierarchia de files e dossieres.</li>
       <li xml:lang="it">La barra di navigazione per gli URL, che ti consente di navigare rapidamente attraverso la struttura di file e cartelle.</li>
+      <li xml:lang="ko">파일과 폴더 구조를 빠르게 탐색할 수 있도록 URL 탐색 표시줄을 사용할 수 있습니다.</li>
       <li xml:lang="nb">Navigasjonslinje (brødsmulelinje) for URL-er slik at du raskt kan navigere gjennom hierarkiet av filer og mapper.</li>
       <li xml:lang="nds">Steed- (oder Krömelspoor-)Balken för URLs, mit de Du Di fix dör de Hierarchie ut Dateien un Ornern bewegen kannst</li>
       <li xml:lang="nl">Navigatie- (of broodkruimel)balk voor URL's, waarmee u snel kunt navigeren door de hiërarchie van bestanden en mappen.</li>
       <li xml:lang="fr">Prend en charge plusieurs types de styles d'affichage et de propriété et vous permet de configurer l'affichage de la manière exacte que vous voulez.</li>
       <li xml:lang="ia">Il supporta multe differente typos de stilos de vista e proprietates e il permitte te configurar le vista exactemente como tu vole.</li>
       <li xml:lang="it">Supporta diversi stili di visualizzazione e proprietà e ti consente di configurare la vista come desideri.</li>
+      <li xml:lang="ko">여러 종류의 보기 형식을 지원하여 원하는 대로 항목을 볼 수 있습니다.</li>
       <li xml:lang="nb">Støtter flere forskjellige visningsstiler og kan sette opp visningen akkurat slik du vil ha den.</li>
       <li xml:lang="nds">Ünnerstütt en Reeg verscheden Ansichtstilen un -egenschappen un lett Di de Ansicht jüst so topassen, as Du dat bruukst.</li>
       <li xml:lang="nl">Ondersteunt een aantal verschillende soorten stijlen van weergave en eigenschappen en biedt u de mogelijkheid de weergave in te stellen precies zoals u dat wilt.</li>
       <li xml:lang="sv">Stöder flera olika sorters visningsstilar och egenskaper och låter dig anpassa visningen exakt som du vill ha den.</li>
       <li xml:lang="uk">Підтримка декількох різних типів та параметрів перегляду надає вам змогу налаштувати перегляд каталогів саме так, як вам це потрібно.</li>
       <li xml:lang="x-test">xxSupports several different kinds of view styles and properties and allows you to configure the view exactly how you want it.xx</li>
-      <li xml:lang="zh-TW">支援數個檢視模式,您也可以調整檢視模式的屬性。</li>
+      <li xml:lang="zh-TW">網址導覽列讓您可以快速瀏覽檔案與資料夾。</li>
       <li>Split view, allowing you to easily copy or move files between locations.</li>
       <li xml:lang="ar">العرض المقسوم، يسمح لك بنسخ ونقل الملفات بين مكانين بسهولة.</li>
       <li xml:lang="ca">Divisió de visualització, permetent copiar o moure fitxers fàcilment entre les ubicacions.</li>
       <li xml:lang="fr">Affichage divisé, permettant de facilement copier ou déplacer des fichiers dans les différents emplacements.</li>
       <li xml:lang="ia">Scinde vista,  il permitte te copiar o mover facilemente files inter locationes.</li>
       <li xml:lang="it">La vista divisa, che ti consente di copiare o spostare i file tra le diverse posizioni in maniera semplice.</li>
+      <li xml:lang="ko">화면을 나누어서 서로 다른 위치 간 파일을 쉽게 이동하거나 복사할 수 있도록 합니다.</li>
       <li xml:lang="nb">Delt visning, så du lett kan kopiere eller flytte filer mellom steder.</li>
       <li xml:lang="nds">Deelt Ansicht, mit De Du Dateien eenfach twischen Steden koperen oder bewegen kannst.</li>
       <li xml:lang="nl">Gesplitst beeld, waarmee u gemakkelijk bestanden kunt kopiëren of verplaatsen tussen locaties.</li>
       <li xml:lang="sv">Delad visning, som låter dig enkelt kopiera eller flytta filer mellan platser.</li>
       <li xml:lang="uk">За допомогою режиму двопанельного розділеного перегляду ви зможе без проблем копіювати або пересувати файли між каталогами.</li>
       <li xml:lang="x-test">xxSplit view, allowing you to easily copy or move files between locations.xx</li>
-      <li xml:lang="zh-TW">分割檢視讓您可以輕鬆複製或移動檔案。</li>
+      <li xml:lang="zh-TW">支援數個檢視模式,您也可以調整檢視模式的屬性。</li>
       <li>Additional information and shortcuts are available as dock-able panels, allowing you to move them around freely and display exactly what you want.</li>
       <li xml:lang="ar">تتوفر معلومات واختصارات إضافية كلوحات قابلة للرصف، مما يسمح لك بنقلها بحريّة وعرضها بالضبط كما تريد.</li>
       <li xml:lang="ca">Hi ha informació addicional i dreceres disponibles com a plafons acoblables, permetent moure'ls lliurement i mostrar exactament el què vulgueu.</li>
       <li xml:lang="fr">Des informations supplémentaires et des raccourcis sont disponible comme panneaux ancrable librement déplaçable et affichant exactement ce que vous voulez.</li>
       <li xml:lang="ia">Information additional e vias breve es disponibile como pannellos de basin (dock-panels), il permitte mover los liberemente e monstrar los exactemente como tu vole.</li>
       <li xml:lang="it">Informazioni aggiuntive e scorciatoie sono disponibili come pannelli agganciabili, che possono essere spostati liberamente e visualizzare esattamente ciò che desideri.</li>
+      <li xml:lang="ko">추가 정보 표시 창과 바로 가기는 도킹 가능한 패널 형태로 사용할 수 있으며, 원하는 곳으로 이동하여 표시할 수 있습니다.</li>
       <li xml:lang="nb">Mer informasjon og snarveier er tilgjengelige som dokkbare ruter, som du kan flytte fritt rundt og bruke til å vise akkurat hva du vil.</li>
       <li xml:lang="nds">Bito-Infos un Leestekens laat sik as Paneels andocken, Du kannst ehr verschuven un se jüst dat wiesen laten, wat Du weten wullt.</li>
       <li xml:lang="nl">Extra informatie en sneltoetsen zijn beschikbaar als vast te zetten panelen, die u vrij kunt verplaatsen en precies kunt tonen wat u wilt.</li>
       <li xml:lang="sv">Ytterligare information och genvägar är tillgängliga som dockningsbara paneler, vilket låter dig flytta omkring dem fritt och visa exakt vad du vill.</li>
       <li xml:lang="uk">За допомогою бічних пересувних панелей ви зможете отримувати додаткову інформацію та пересуватися каталогами. Ви можете розташувати ці панелі так, як вам це зручно, і наказати програмі показувати на них саме те, що вам потрібно.</li>
       <li xml:lang="x-test">xxAdditional information and shortcuts are available as dock-able panels, allowing you to move them around freely and display exactly what you want.xx</li>
-      <li xml:lang="zh-TW">額外資訊與嵌入式面板捷徑讓您可以輕易顯示您常用的項目。</li>
+      <li xml:lang="zh-TW">分割檢視讓您可以輕鬆複製或移動檔案。</li>
       <li>Multiple tab support</li>
       <li xml:lang="ar">دعم تعدّد الألسنة</li>
       <li xml:lang="ca">Implementació de pestanyes múltiples</li>
       <li xml:lang="fr">Prise en charge des onglets multiples</li>
       <li xml:lang="ia">Supporto de scheda multiple</li>
       <li xml:lang="it">Supporto di schede multiple</li>
+      <li xml:lang="ko">다중 탭 지원</li>
       <li xml:lang="lt">Daugelio kortelių palaikymas</li>
       <li xml:lang="nb">Støtte for flere faner</li>
       <li xml:lang="nds">Ünnerstütten för Paneels</li>
       <li xml:lang="sv">Stöd för flera flikar</li>
       <li xml:lang="uk">Підтримка роботи з вкладками.</li>
       <li xml:lang="x-test">xxMultiple tab supportxx</li>
-      <li xml:lang="zh-TW">支援多分頁</li>
+      <li xml:lang="zh-TW">額外資訊與嵌入式面板捷徑讓您可以輕易顯示您常用的項目。</li>
       <li>Informational dialogues are displayed in an unobtrusive way.</li>
       <li xml:lang="ar">حواريات المعلومات تُعرَض بطريقة غير مُزعجة.</li>
       <li xml:lang="ca">El diàlegs informatius es mostren de manera no molesta.</li>
       <li xml:lang="fr">Les dialogues d'information sont affiché de manière discrète.</li>
       <li xml:lang="ia">Dialogos de information es monstrate de modo non importun.</li>
       <li xml:lang="it">Le finestre informative sono visualizzate in modo molto discreto.</li>
+      <li xml:lang="ko">정보 대화 상자를 방해되지 않는 형태로 표시합니다.</li>
       <li xml:lang="nb">Informasjonsdialoger vises på en lite påtrengende måte.</li>
       <li xml:lang="nds">Informatschoondialogen kaamt Di nich in'n Weg.</li>
       <li xml:lang="nl">Informatiedialogen worden op een prettige manier getoond.</li>
       <li xml:lang="sv">Dialogrutor med information visas på ett diskret sätt.</li>
       <li xml:lang="uk">Показ інформаційних панелей у зручний спосіб, що не заважає роботі.</li>
       <li xml:lang="x-test">xxInformational dialogues are displayed in an unobtrusive way.xx</li>
-      <li xml:lang="zh-TW">以不唐突的方式顯示資訊對話框。</li>
+      <li xml:lang="zh-TW">支援多分頁</li>
       <li>Undo/redo support</li>
       <li xml:lang="ar">دعم التراجع والإعادة</li>
       <li xml:lang="ca">Implementació de desfer/refer</li>
       <li xml:lang="fr">Prise en charge d'annulation et recommencement</li>
       <li xml:lang="ia">Supporto de annulla/reface</li>
       <li xml:lang="it">Supporto di annulla/rifai</li>
+      <li xml:lang="ko">실행 취소/다시 실행 지원</li>
       <li xml:lang="nb">Støtte for angring/omgjøring</li>
       <li xml:lang="nds">Ünnerstütten för Torüchnehmen un Wedderherstellen</li>
       <li xml:lang="nl">Ondersteuning ongedaan maken/opnieuw</li>
       <li xml:lang="sv">Stöd för ångra och gör om</li>
       <li xml:lang="uk">Підтримка скасовування та повторення дій.</li>
       <li xml:lang="x-test">xxUndo/redo supportxx</li>
-      <li xml:lang="zh-TW">復原/重做功能</li>
+      <li xml:lang="zh-TW">以不唐突的方式顯示資訊對話框。</li>
       <li>Transparent network access through the KIO system.</li>
       <li xml:lang="ar">اتصال شبكيّ مباشر باستخدام نظام KIO.</li>
       <li xml:lang="ca">Accés transparent a la xarxa a través del sistema KIO.</li>
       <li xml:lang="fr">Accès au réseau transparent grâce au système des KIO.</li>
       <li xml:lang="ia">Accesso de rete transparente a transverso del systema KIO.</li>
       <li xml:lang="it">Accesso trasparente alla rete tramite il sistema KIO.</li>
+      <li xml:lang="ko">KIO 시스템을 통하여 네트워크 자원에 접근합니다.</li>
       <li xml:lang="nb">Gjennomsiktig nettverkstilgang via KIO-systemet.</li>
       <li xml:lang="nds">Direkt Nettwarktogriep över dat KDE-In-/Utgaav-(KIO-)Moduulsysteem</li>
       <li xml:lang="nl">Transparante toegang tot het netwerk via het KIO systeem.</li>
       <li xml:lang="sv">Transparent nätverksåtkomst via I/O-slavsystemet.</li>
       <li xml:lang="uk">Прозорий доступ до ресурсів у мережі за допомогою системи KIO.</li>
       <li xml:lang="x-test">xxTransparent network access through the KIO system.xx</li>
-      <li xml:lang="zh-TW">透過 KIO 系統無感地存取網路。</li>
+      <li xml:lang="zh-TW">復原支援</li>
     </ul>
   </description>
   <url type="homepage">http://dolphin.kde.org/</url>
index a4e43a98321fa30e1d1e650e65825292f7a322a2..95b08af96e1d8002aea3f5e490f773d77113e270 100644 (file)
@@ -26,6 +26,7 @@
 #include "dolphincontextmenu.h"
 #include "dolphinnewfilemenu.h"
 #include "dolphinrecenttabsmenu.h"
+#include "dolphintabwidget.h"
 #include "dolphinviewcontainer.h"
 #include "dolphintabpage.h"
 #include "panels/folders/folderspanel.h"
@@ -75,7 +76,6 @@
 #include <KStandardDirs>
 #include <kstatusbar.h>
 #include <KStandardAction>
-#include <ktabbar.h>
 #include <KToggleAction>
 #include <KUrlNavigator>
 #include <KUrl>
@@ -97,11 +97,8 @@ namespace {
 DolphinMainWindow::DolphinMainWindow() :
     KXmlGuiWindow(0),
     m_newFileMenu(0),
-    m_tabBar(0),
+    m_tabWidget(0),
     m_activeViewContainer(0),
-    m_centralWidgetLayout(0),
-    m_tabIndex(-1),
-    m_viewTab(),
     m_actionHandler(0),
     m_remoteEncoding(0),
     m_settingsDialog(),
@@ -134,6 +131,15 @@ DolphinMainWindow::DolphinMainWindow() :
 
     setAcceptDrops(true);
 
+    m_tabWidget = new DolphinTabWidget(this);
+    connect(m_tabWidget, SIGNAL(activeViewChanged(DolphinViewContainer*)),
+            this, SLOT(activeViewChanged(DolphinViewContainer*)));
+    connect(m_tabWidget, SIGNAL(tabCountChanged(int)),
+            this, SLOT(tabCountChanged(int)));
+    connect(m_tabWidget, SIGNAL(currentUrlChanged(KUrl)),
+            this, SLOT(setUrlAsCaption(KUrl)));
+    setCentralWidget(m_tabWidget);
+
     setupActions();
 
     m_actionHandler = new DolphinViewActionHandler(actionCollection(), this);
@@ -144,36 +150,6 @@ DolphinMainWindow::DolphinMainWindow() :
     connect(this, SIGNAL(urlChanged(KUrl)),
             m_remoteEncoding, SLOT(slotAboutToOpenUrl()));
 
-    m_tabBar = new KTabBar(this);
-    m_tabBar->setMovable(true);
-    m_tabBar->setTabsClosable(true);
-    connect(m_tabBar, SIGNAL(currentChanged(int)),
-            this, SLOT(setActiveTab(int)));
-    connect(m_tabBar, SIGNAL(tabCloseRequested(int)),
-            this, SLOT(closeTab(int)));
-    connect(m_tabBar, SIGNAL(contextMenu(int,QPoint)),
-            this, SLOT(openTabContextMenu(int,QPoint)));
-    connect(m_tabBar, SIGNAL(newTabRequest()),
-            this, SLOT(openNewTab()));
-    connect(m_tabBar, SIGNAL(testCanDecode(const QDragMoveEvent*,bool&)),
-            this, SLOT(slotTestCanDecode(const QDragMoveEvent*,bool&)));
-    connect(m_tabBar, SIGNAL(mouseMiddleClick(int)),
-            this, SLOT(closeTab(int)));
-    connect(m_tabBar, SIGNAL(tabMoved(int,int)),
-            this, SLOT(slotTabMoved(int,int)));
-    connect(m_tabBar, SIGNAL(receivedDropEvent(int,QDropEvent*)),
-            this, SLOT(tabDropEvent(int,QDropEvent*)));
-
-    m_tabBar->blockSignals(true);  // signals get unblocked after at least 2 tabs are open
-    m_tabBar->hide();
-
-    QWidget* centralWidget = new QWidget(this);
-    m_centralWidgetLayout = new QVBoxLayout(centralWidget);
-    m_centralWidgetLayout->setSpacing(0);
-    m_centralWidgetLayout->setMargin(0);
-    m_centralWidgetLayout->addWidget(m_tabBar);
-
-    setCentralWidget(centralWidget);
     setupDockWidgets();
 
     setupGUI(Keys | Save | Create | ToolBar);
@@ -206,48 +182,12 @@ DolphinMainWindow::~DolphinMainWindow()
 
 void DolphinMainWindow::openDirectories(const QList<KUrl>& dirs)
 {
-    const bool hasSplitView = GeneralSettings::splitView();
-
-    // Open each directory inside a new tab. If the "split view" option has been enabled,
-    // always show two directories within one tab.
-    QList<KUrl>::const_iterator it = dirs.constBegin();
-    while (it != dirs.constEnd()) {
-        const KUrl& primaryUrl = *(it++);
-        if (hasSplitView && (it != dirs.constEnd())) {
-            const KUrl& secondaryUrl = *(it++);
-            openNewTab(primaryUrl, secondaryUrl);
-        } else {
-            openNewTab(primaryUrl);
-        }
-    }
+    m_tabWidget->openDirectories(dirs);
 }
 
 void DolphinMainWindow::openFiles(const QList<KUrl>& files)
 {
-    if (files.isEmpty()) {
-        return;
-    }
-
-    // Get all distinct directories from 'files' and open a tab
-    // for each directory. If the "split view" option is enabled, two
-    // directories are shown inside one tab (see openDirectories()).
-    QList<KUrl> dirs;
-    foreach (const KUrl& url, files) {
-        const KUrl dir(url.directory());
-        if (!dirs.contains(dir)) {
-            dirs.append(dir);
-        }
-    }
-
-    openDirectories(dirs);
-
-    // Select the files. Although the files can be split between several
-    // tabs, there is no need to split 'files' accordingly, as
-    // the DolphinView will just ignore invalid selections.
-    foreach (DolphinTabPage* tabPage, m_viewTab) {
-        tabPage->markUrlsAsSelected(files);
-        tabPage->markUrlAsCurrent(files.first());
-    }
+    m_tabWidget->openFiles(files);
 }
 
 void DolphinMainWindow::showCommand(CommandType command)
@@ -293,21 +233,13 @@ void DolphinMainWindow::changeUrl(const KUrl& url)
         return;
     }
 
-    DolphinViewContainer* view = activeViewContainer();
-    if (view) {
-        view->setUrl(url);
-        updateEditActions();
-        updatePasteAction();
-        updateViewActions();
-        updateGoActions();
-        setUrlAsCaption(url);
-
-        const QString iconName = KMimeType::iconNameForUrl(url);
-        m_tabBar->setTabIcon(m_tabIndex, KIcon(iconName));
-        m_tabBar->setTabText(m_tabIndex, squeezedText(tabName(view->url())));
-
-        emit urlChanged(url);
-    }
+    m_activeViewContainer->setUrl(url);
+    updateEditActions();
+    updatePasteAction();
+    updateViewActions();
+    updateGoActions();
+
+    emit urlChanged(url);
 }
 
 void DolphinMainWindow::slotTerminalDirectoryChanged(const KUrl& url)
@@ -328,7 +260,7 @@ void DolphinMainWindow::slotSelectionChanged(const KFileItemList& selection)
 {
     updateEditActions();
 
-    const int selectedUrlsCount = m_viewTab.at(m_tabIndex)->selectedItemsCount();
+    const int selectedUrlsCount = m_tabWidget->currentTabPage()->selectedItemsCount();
 
     QAction* compareFilesAction = actionCollection()->action("compare_files");
     if (selectedUrlsCount == 2) {
@@ -374,84 +306,19 @@ void DolphinMainWindow::openNewMainWindow()
     KRun::run("dolphin %u", KUrl::List(), this);
 }
 
-void DolphinMainWindow::openNewTab()
+void DolphinMainWindow::openNewActivatedTab()
 {
-    const bool isUrlEditable =  m_activeViewContainer->urlNavigator()->isUrlEditable();
-
-    openNewTab(m_activeViewContainer->url());
-    m_tabBar->setCurrentIndex(m_viewTab.count() - 1);
-
-    // The URL navigator of the new tab should have the same editable state
-    // as the current tab
-    KUrlNavigator* navigator = m_activeViewContainer->urlNavigator();
-    navigator->setUrlEditable(isUrlEditable);
-
-    if (isUrlEditable) {
-        // If a new tab is opened and the URL is editable, assure that
-        // the user can edit the URL without manually setting the focus
-        navigator->setFocus();
-    }
+    m_tabWidget->openNewActivatedTab();
 }
 
 void DolphinMainWindow::openNewTab(const KUrl& primaryUrl, const KUrl& secondaryUrl)
 {
-    QWidget* focusWidget = QApplication::focusWidget();
-
-    DolphinTabPage* tabPage = new DolphinTabPage(primaryUrl, secondaryUrl, this);
-    m_viewTab.append(tabPage);
-
-    connect(tabPage, SIGNAL(activeViewChanged()),
-            this, SLOT(activeViewChanged()));
-
-    // The places-selector from the URL navigator should only be shown
-    // if the places dock is invisible
-    QDockWidget* placesDock = findChild<QDockWidget*>("placesDock");
-    const bool placesSelectorVisible = !placesDock || !placesDock->isVisible();
-    tabPage->setPlacesSelectorVisible(placesSelectorVisible);
-
-    tabPage->hide();
-
-    m_tabBar->addTab(KIcon(KMimeType::iconNameForUrl(primaryUrl)),
-                     squeezedText(tabName(primaryUrl)));
-
-    if (m_viewTab.count() > 1) {
-        actionCollection()->action("close_tab")->setEnabled(true);
-        actionCollection()->action("activate_prev_tab")->setEnabled(true);
-        actionCollection()->action("activate_next_tab")->setEnabled(true);
-        m_tabBar->show();
-        m_tabBar->blockSignals(false);
-    }
-
-    if (focusWidget) {
-        // The DolphinViewContainer grabbed the keyboard focus. As the tab is opened
-        // in background, assure that the previous focused widget gets the focus back.
-        focusWidget->setFocus();
-    }
+    m_tabWidget->openNewTab(primaryUrl, secondaryUrl);
 }
 
 void DolphinMainWindow::openNewActivatedTab(const KUrl& primaryUrl, const KUrl& secondaryUrl)
 {
-    openNewTab(primaryUrl, secondaryUrl);
-    setActiveTab(m_viewTab.count() - 1);
-}
-
-void DolphinMainWindow::activateNextTab()
-{
-    if (m_viewTab.count() >= 2) {
-        const int tabIndex = (m_tabBar->currentIndex() + 1) % m_tabBar->count();
-        setActiveTab(tabIndex);
-    }
-}
-
-void DolphinMainWindow::activatePrevTab()
-{
-    if (m_viewTab.count() >= 2) {
-        int tabIndex = m_tabBar->currentIndex() - 1;
-        if (tabIndex == -1) {
-            tabIndex = m_tabBar->count() - 1;
-        }
-        setActiveTab(tabIndex);
-    }
+    m_tabWidget->openNewActivatedTab(primaryUrl, secondaryUrl);
 }
 
 void DolphinMainWindow::openInNewTab()
@@ -490,12 +357,6 @@ void DolphinMainWindow::showEvent(QShowEvent* event)
 {
     KXmlGuiWindow::showEvent(event);
 
-    if (!m_activeViewContainer && m_viewTab.count() > 0) {
-        // If we have no active view container yet, we set the primary view container
-        // of the first tab as active view container.
-        setActiveTab(0);
-    }
-
     if (!event->spontaneous()) {
         m_activeViewContainer->view()->setFocus();
     }
@@ -511,7 +372,7 @@ void DolphinMainWindow::closeEvent(QCloseEvent* event)
         closedByUser = false;
     }
 
-    if (m_viewTab.count() > 1 && GeneralSettings::confirmClosingMultipleTabs() && closedByUser) {
+    if (m_tabWidget->count() > 1 && GeneralSettings::confirmClosingMultipleTabs() && closedByUser) {
         // Ask the user if he really wants to quit and close all tabs.
         // Open a confirmation dialog with 3 buttons:
         // KDialog::Yes    -> Quit
@@ -546,7 +407,7 @@ void DolphinMainWindow::closeEvent(QCloseEvent* event)
                 break;
             case KDialog::No:
                 // Close only the current tab
-                closeTab();
+                m_tabWidget->closeTab();
             default:
                 event->ignore();
                 return;
@@ -561,32 +422,12 @@ void DolphinMainWindow::closeEvent(QCloseEvent* event)
 
 void DolphinMainWindow::saveProperties(KConfigGroup& group)
 {
-    const int tabCount = m_viewTab.count();
-    group.writeEntry("Tab Count", tabCount);
-    group.writeEntry("Active Tab Index", m_tabBar->currentIndex());
-
-    for (int i = 0; i < tabCount; ++i) {
-        const DolphinTabPage* tabPage = m_viewTab.at(i);
-        group.writeEntry("Tab " % QString::number(i), tabPage->saveState());
-    }
+    m_tabWidget->saveProperties(group);
 }
 
 void DolphinMainWindow::readProperties(const KConfigGroup& group)
 {
-    const int tabCount = group.readEntry("Tab Count", 1);
-    for (int i = 0; i < tabCount; ++i) {
-        const QByteArray state = group.readEntry("Tab " % QString::number(i), QByteArray());
-        DolphinTabPage* tabPage = m_viewTab.at(i);
-        tabPage->restoreState(state);
-
-        // openNewTab() needs to be called only tabCount - 1 times
-        if (i != tabCount - 1) {
-            openNewTab();
-        }
-    }
-
-    const int index = group.readEntry("Active Tab Index", 0);
-    m_tabBar->setCurrentIndex(index);
+    m_tabWidget->readProperties(group);
 }
 
 void DolphinMainWindow::updateNewMenu()
@@ -690,7 +531,7 @@ void DolphinMainWindow::invertSelection()
 
 void DolphinMainWindow::toggleSplitView()
 {
-    DolphinTabPage* tabPage = m_viewTab.at(m_tabIndex);
+    DolphinTabPage* tabPage = m_tabWidget->currentTabPage();
     tabPage->setSplitViewEnabled(!tabPage->splitViewEnabled());
 
     updateViewActions();
@@ -755,14 +596,6 @@ void DolphinMainWindow::togglePanelLockState()
     GeneralSettings::setLockPanels(newLockState);
 }
 
-void DolphinMainWindow::slotPlacesPanelVisibilityChanged(bool visible)
-{
-    foreach (DolphinTabPage* tabPage, m_viewTab) {
-        // The Places selector in the location bar should be shown if and only if the Places panel is hidden.
-        tabPage->setPlacesSelectorVisible(!visible);
-    }
-}
-
 void DolphinMainWindow::goBack()
 {
     KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator();
@@ -828,7 +661,7 @@ void DolphinMainWindow::goHome(Qt::MouseButtons buttons)
 
 void DolphinMainWindow::compareFiles()
 {
-    const KFileItemList items = m_viewTab.at(m_tabIndex)->selectedItems();
+    const KFileItemList items = m_tabWidget->currentTabPage()->selectedItems();
     if (items.count() != 2) {
         // The action is disabled in this case, but it could have been triggered
         // via D-Bus, see https://bugs.kde.org/show_bug.cgi?id=325517
@@ -890,143 +723,6 @@ void DolphinMainWindow::editSettings()
     }
 }
 
-void DolphinMainWindow::setActiveTab(int index)
-{
-    Q_ASSERT(index >= 0);
-    Q_ASSERT(index < m_viewTab.count());
-    if (index == m_tabIndex) {
-        return;
-    }
-
-    m_tabBar->setCurrentIndex(index);
-
-    // hide current tab content
-    if (m_tabIndex >= 0) {
-        DolphinTabPage* hiddenTabPage = m_viewTab.at(m_tabIndex);
-        hiddenTabPage->hide();
-        m_centralWidgetLayout->removeWidget(hiddenTabPage);
-    }
-
-    // show active tab content
-    m_tabIndex = index;
-
-    DolphinTabPage* tabPage = m_viewTab.at(index);
-    m_centralWidgetLayout->addWidget(tabPage, 1);
-    tabPage->show();
-
-    setActiveViewContainer(tabPage->activeViewContainer());
-}
-
-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.
-        m_tabBar->setCurrentIndex((index > 0) ? index - 1 : 1);
-    }
-
-    DolphinTabPage* tabPage = m_viewTab.at(index);
-
-    if (tabPage->splitViewEnabled()) {
-        emit rememberClosedTab(tabPage->primaryViewContainer()->url(),
-                               tabPage->secondaryViewContainer()->url());
-    } else {
-        emit rememberClosedTab(tabPage->primaryViewContainer()->url(), KUrl());
-    }
-
-    // delete tab
-    m_viewTab.removeAt(index);
-    tabPage->deleteLater();
-
-    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() < 2) {
-        actionCollection()->action("close_tab")->setEnabled(false);
-        actionCollection()->action("activate_prev_tab")->setEnabled(false);
-        actionCollection()->action("activate_next_tab")->setEnabled(false);
-        m_tabBar->hide();
-    } 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* detachTabAction = menu.addAction(KIcon("tab-detach"), i18nc("@action:inmenu", "Detach Tab"));
-
-    QAction* closeOtherTabsAction = menu.addAction(KIcon("tab-close-other"), 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 KUrl url = m_viewTab.at(index)->activeViewContainer()->url();
-        openNewTab(url);
-        m_tabBar->setCurrentIndex(m_viewTab.count() - 1);
-    } else if (selectedAction == detachTabAction) {
-        const QString separator(QLatin1Char(' '));
-        QString command = QLatin1String("dolphin");
-
-        const DolphinTabPage* tabPage = m_viewTab.at(index);
-
-        command += separator + tabPage->primaryViewContainer()->url().url();
-        if (tabPage->splitViewEnabled()) {
-            command += separator + tabPage->secondaryViewContainer()->url().url();
-            command += separator + QLatin1String("-split");
-        }
-
-        KRun::runCommand(command, this);
-
-        closeTab(index);
-    } 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::slotTabMoved(int from, int to)
-{
-    m_viewTab.move(from, to);
-    m_tabIndex = m_tabBar->currentIndex();
-}
-
-void DolphinMainWindow::slotTestCanDecode(const QDragMoveEvent* event, bool& canDecode)
-{
-    canDecode = KUrl::List::canDecode(event->mimeData());
-}
-
 void DolphinMainWindow::handleUrl(const KUrl& url)
 {
     delete m_lastHandleUrlStatJob;
@@ -1060,20 +756,6 @@ void DolphinMainWindow::slotHandleUrlStatFinished(KJob* job)
     }
 }
 
-void DolphinMainWindow::tabDropEvent(int tab, QDropEvent* event)
-{
-    const KUrl::List urls = KUrl::List::fromMimeData(event->mimeData());
-    if (!urls.isEmpty() && tab != -1) {
-        const DolphinView* view = m_viewTab.at(tab)->activeViewContainer()->view();
-
-        QString error;
-        DragAndDropHelper::dropUrls(view->rootItem(), view->url(), event, error);
-        if (!error.isEmpty()) {
-            activeViewContainer()->showMessage(error, DolphinViewContainer::Error);
-        }
-    }
-}
-
 void DolphinMainWindow::slotWriteStateChanged(bool isFolderWritable)
 {
     newFileMenu()->setEnabled(isFolderWritable);
@@ -1233,30 +915,26 @@ void DolphinMainWindow::slotPlaceActivated(const KUrl& url)
     }
 }
 
-void DolphinMainWindow::activeViewChanged()
+void DolphinMainWindow::closedTabsCountChanged(unsigned int count)
 {
-    const DolphinTabPage* tabPage = m_viewTab.at(m_tabIndex);
-    setActiveViewContainer(tabPage->activeViewContainer());
+    actionCollection()->action("undo_close_tab")->setEnabled(count > 0);
 }
 
-void DolphinMainWindow::setActiveViewContainer(DolphinViewContainer* viewContainer)
+void DolphinMainWindow::activeViewChanged(DolphinViewContainer* viewContainer)
 {
+    DolphinViewContainer* oldViewContainer = m_activeViewContainer;
     Q_ASSERT(viewContainer);
-    Q_ASSERT((viewContainer == m_viewTab.at(m_tabIndex)->primaryViewContainer()) ||
-             (viewContainer == m_viewTab.at(m_tabIndex)->secondaryViewContainer()));
-    if (m_activeViewContainer == viewContainer) {
-        return;
-    }
 
-    if (m_activeViewContainer) {
+    m_activeViewContainer = viewContainer;
+
+    if (oldViewContainer) {
         // Disconnect all signals between the old view container (container,
         // view and url navigator) and main window.
-        m_activeViewContainer->disconnect(this);
-        m_activeViewContainer->view()->disconnect(this);
-        m_activeViewContainer->urlNavigator()->disconnect(this);
+        oldViewContainer->disconnect(this);
+        oldViewContainer->view()->disconnect(this);
+        oldViewContainer->urlNavigator()->disconnect(this);
     }
 
-    m_activeViewContainer = viewContainer;
     connectViewSignals(viewContainer);
 
     m_actionHandler->setCurrentView(viewContainer->view());
@@ -1267,14 +945,34 @@ void DolphinMainWindow::setActiveViewContainer(DolphinViewContainer* viewContain
     updateViewActions();
     updateGoActions();
 
-    const KUrl url = m_activeViewContainer->url();
-    setUrlAsCaption(url);
-    m_tabBar->setTabText(m_tabIndex, squeezedText(tabName(url)));
-    m_tabBar->setTabIcon(m_tabIndex, KIcon(KMimeType::iconNameForUrl(url)));
-
+    const KUrl url = viewContainer->url();
     emit urlChanged(url);
 }
 
+void DolphinMainWindow::tabCountChanged(int count)
+{
+    const bool enableTabActions = (count > 1);
+    actionCollection()->action("close_tab")->setEnabled(enableTabActions);
+    actionCollection()->action("activate_next_tab")->setEnabled(enableTabActions);
+    actionCollection()->action("activate_prev_tab")->setEnabled(enableTabActions);
+}
+
+void DolphinMainWindow::setUrlAsCaption(const KUrl& url)
+{
+    QString caption;
+    if (!url.isLocalFile()) {
+        caption.append(url.protocol() + " - ");
+        if (url.hasHost()) {
+            caption.append(url.host() + " - ");
+        }
+    }
+
+    const QString fileName = url.fileName().isEmpty() ? "/" : url.fileName();
+    caption.append(fileName);
+
+    setCaption(caption);
+}
+
 void DolphinMainWindow::setupActions()
 {
     // setup 'File' menu
@@ -1296,14 +994,14 @@ void DolphinMainWindow::setupActions()
     newTab->setIcon(KIcon("tab-new"));
     newTab->setText(i18nc("@action:inmenu File", "New Tab"));
     newTab->setShortcut(KShortcut(Qt::CTRL | Qt::Key_T, Qt::CTRL | Qt::SHIFT | Qt::Key_N));
-    connect(newTab, SIGNAL(triggered()), this, SLOT(openNewTab()));
+    connect(newTab, SIGNAL(triggered()), this, SLOT(openNewActivatedTab()));
 
     KAction* closeTab = actionCollection()->addAction("close_tab");
     closeTab->setIcon(KIcon("tab-close"));
     closeTab->setText(i18nc("@action:inmenu File", "Close Tab"));
     closeTab->setShortcut(Qt::CTRL | Qt::Key_W);
     closeTab->setEnabled(false);
-    connect(closeTab, SIGNAL(triggered()), this, SLOT(closeTab()));
+    connect(closeTab, SIGNAL(triggered()), m_tabWidget, SLOT(closeTab()));
 
     KStandardAction::quit(this, SLOT(quit()), actionCollection());
 
@@ -1375,10 +1073,19 @@ void DolphinMainWindow::setupActions()
 
     DolphinRecentTabsMenu* recentTabsMenu = new DolphinRecentTabsMenu(this);
     actionCollection()->addAction("closed_tabs", recentTabsMenu);
-    connect(this, SIGNAL(rememberClosedTab(KUrl,KUrl)),
-            recentTabsMenu, SLOT(rememberClosedTab(KUrl,KUrl)));
-    connect(recentTabsMenu, SIGNAL(restoreClosedTab(KUrl,KUrl)),
-            this, SLOT(openNewActivatedTab(KUrl,KUrl)));
+    connect(m_tabWidget, SIGNAL(rememberClosedTab(KUrl,QByteArray)),
+            recentTabsMenu, SLOT(rememberClosedTab(KUrl,QByteArray)));
+    connect(recentTabsMenu, SIGNAL(restoreClosedTab(QByteArray)),
+            m_tabWidget, SLOT(restoreClosedTab(QByteArray)));
+    connect(recentTabsMenu, SIGNAL(closedTabsCountChanged(uint)),
+            this, SLOT(closedTabsCountChanged(uint)));
+
+    KAction* undoCloseTab = actionCollection()->addAction("undo_close_tab");
+    undoCloseTab->setText(i18nc("@action:inmenu File", "Undo close tab"));
+    undoCloseTab->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_T);
+    undoCloseTab->setIcon(KIcon("edit-undo"));
+    undoCloseTab->setEnabled(false);
+    connect(undoCloseTab, SIGNAL(triggered()), recentTabsMenu, SLOT(undoCloseTab()));
 
     KAction* forwardAction = KStandardAction::forward(this, SLOT(goForward()), actionCollection());
     connect(forwardAction, SIGNAL(triggered(Qt::MouseButtons,Qt::KeyboardModifiers)), this, SLOT(goForward(Qt::MouseButtons)));
@@ -1427,14 +1134,14 @@ void DolphinMainWindow::setupActions()
     activateNextTab->setIconText(i18nc("@action:inmenu", "Next Tab"));
     activateNextTab->setText(i18nc("@action:inmenu", "Activate Next Tab"));
     activateNextTab->setEnabled(false);
-    connect(activateNextTab, SIGNAL(triggered()), SLOT(activateNextTab()));
+    connect(activateNextTab, SIGNAL(triggered()), m_tabWidget, SLOT(activateNextTab()));
     activateNextTab->setShortcuts(QApplication::isRightToLeft() ? prevTabKeys : nextTabKeys);
 
     KAction* activatePrevTab = actionCollection()->addAction("activate_prev_tab");
     activatePrevTab->setIconText(i18nc("@action:inmenu", "Previous Tab"));
     activatePrevTab->setText(i18nc("@action:inmenu", "Activate Previous Tab"));
     activatePrevTab->setEnabled(false);
-    connect(activatePrevTab, SIGNAL(triggered()), SLOT(activatePrevTab()));
+    connect(activatePrevTab, SIGNAL(triggered()), m_tabWidget, SLOT(activatePrevTab()));
     activatePrevTab->setShortcuts(QApplication::isRightToLeft() ? nextTabKeys : prevTabKeys);
 
     // for context menu
@@ -1563,10 +1270,12 @@ void DolphinMainWindow::setupDockWidgets()
     connect(this, SIGNAL(urlChanged(KUrl)),
             placesPanel, SLOT(setUrl(KUrl)));
     connect(placesDock, SIGNAL(visibilityChanged(bool)),
-            this, SLOT(slotPlacesPanelVisibilityChanged(bool)));
+            m_tabWidget, SLOT(slotPlacesPanelVisibilityChanged(bool)));
     connect(this, SIGNAL(settingsChanged()),
            placesPanel, SLOT(readSettings()));
 
+    m_tabWidget->slotPlacesPanelVisibilityChanged(placesPanel->isVisible());
+
     // Add actions into the "Panels" menu
     KActionMenu* panelsMenu = new KActionMenu(i18nc("@action:inmenu View", "Panels"), this);
     actionCollection()->addAction("panels", panelsMenu);
@@ -1689,15 +1398,13 @@ bool DolphinMainWindow::addActionToMenu(QAction* action, KMenu* menu)
 
 void DolphinMainWindow::refreshViews()
 {
-    foreach (DolphinTabPage* tabPage, m_viewTab) {
-        tabPage->refreshViews();
-    }
+    m_tabWidget->refreshViews();
 
     if (GeneralSettings::modifiedStartupSettings()) {
         // The startup settings have been changed by the user (see bug #254947).
         // Synchronize the split-view setting with the active view:
         const bool splitView = GeneralSettings::splitView();
-        m_viewTab.at(m_tabIndex)->setSplitViewEnabled(splitView);
+        m_tabWidget->currentTabPage()->setSplitViewEnabled(splitView);
         updateSplitAction();
     }
 
@@ -1748,7 +1455,7 @@ void DolphinMainWindow::connectViewSignals(DolphinViewContainer* container)
 void DolphinMainWindow::updateSplitAction()
 {
     QAction* splitAction = actionCollection()->action("split_view");
-    const DolphinTabPage* tabPage = m_viewTab.at(m_tabIndex);
+    const DolphinTabPage* tabPage = m_tabWidget->currentTabPage();
     if (tabPage->splitViewEnabled()) {
         if (tabPage->primaryViewActive()) {
             splitAction->setText(i18nc("@action:intoolbar Close left view", "Close"));
@@ -1766,24 +1473,6 @@ void DolphinMainWindow::updateSplitAction()
     }
 }
 
-QString DolphinMainWindow::tabName(const KUrl& url) const
-{
-    QString name;
-    if (url.equals(KUrl("file:///"))) {
-        name = '/';
-    } else {
-        name = url.fileName();
-        if (name.isEmpty()) {
-            name = url.protocol();
-        } else {
-            // Make sure that a '&' inside the directory name is displayed correctly
-            // and not misinterpreted as a keyboard shortcut in QTabBar::setTabText()
-            name.replace('&', "&&");
-        }
-    }
-    return name;
-}
-
 bool DolphinMainWindow::isKompareInstalled() const
 {
     static bool initialized = false;
@@ -1797,28 +1486,6 @@ bool DolphinMainWindow::isKompareInstalled() const
     return installed;
 }
 
-void DolphinMainWindow::setUrlAsCaption(const KUrl& url)
-{
-    QString caption;
-    if (!url.isLocalFile()) {
-        caption.append(url.protocol() + " - ");
-        if (url.hasHost()) {
-            caption.append(url.host() + " - ");
-        }
-    }
-
-    const QString fileName = url.fileName().isEmpty() ? "/" : url.fileName();
-    caption.append(fileName);
-
-    setCaption(caption);
-}
-
-QString DolphinMainWindow::squeezedText(const QString& text) const
-{
-    const QFontMetrics fm = fontMetrics();
-    return fm.elidedText(text, Qt::ElideMiddle, fm.maxWidth() * 10);
-}
-
 void DolphinMainWindow::createPanelAction(const KIcon& icon,
                                           const QKeySequence& shortcut,
                                           QAction* dockAction,
index 7c3bff47fdd288c9e56f9e58461385659fdc80fd..9d4c003af705965391299839438b292c4d2f3057 100644 (file)
@@ -40,17 +40,14 @@ class DolphinApplication;
 class DolphinSettingsDialog;
 class DolphinViewContainer;
 class DolphinRemoteEncoding;
-class DolphinTabPage;
+class DolphinTabWidget;
 class KAction;
 class KFileItem;
 class KFileItemList;
 class KJob;
 class KNewFileMenu;
-class KTabBar;
 class KUrl;
-class QSplitter;
 class QToolButton;
-class QVBoxLayout;
 
 /**
  * @short Main window for Dolphin.
@@ -149,11 +146,6 @@ signals:
      */
     void settingsChanged();
 
-    /**
-     * Is emitted when a tab has been closed.
-     */
-    void rememberClosedTab(const KUrl& primaryUrl, const KUrl& secondaryUrl);
-
 protected:
     /** @see QWidget::showEvent() */
     virtual void showEvent(QShowEvent* event);
@@ -262,13 +254,6 @@ private slots:
      */
     void togglePanelLockState();
 
-    /**
-     * Is invoked if the Places panel got visible/invisible and takes care
-     * that the places-selector of all views is only shown if the Places panel
-     * is invisible.
-     */
-    void slotPlacesPanelVisibilityChanged(bool visible);
-
     /** Goes back one step of the URL history. */
     void goBack();
 
@@ -343,8 +328,11 @@ private slots:
     /** Open a new main window. */
     void openNewMainWindow();
 
-    /** Opens a new view with the current URL that is part of a tab. */
-    void openNewTab();
+    /**
+     * Opens a new view with the current URL that is part of a tab and
+     * activates it.
+     */
+    void openNewActivatedTab();
 
     /**
      * Opens a new tab in the background showing the URL \a primaryUrl and the
@@ -358,10 +346,6 @@ private slots:
      */
     void openNewActivatedTab(const KUrl& primaryUrl, const KUrl& secondaryUrl = KUrl());
 
-    void activateNextTab();
-
-    void activatePrevTab();
-
     /**
      * Opens the selected folder in a new tab.
      */
@@ -378,39 +362,6 @@ private slots:
      */
     void showCommand(CommandType command);
 
-    /**
-     * Activates the tab with the index \a index, which means that the current view
-     * is replaced by the view of the given tab.
-     */
-    void setActiveTab(int index);
-
-    /** Closes the currently active tab. */
-    void closeTab();
-
-    /**
-     * Closes the tab with the index \a index and activates the tab with index - 1.
-     */
-    void closeTab(int index);
-
-    /**
-     * Opens a context menu for the tab with the index \a index
-     * on the position \a pos.
-     */
-    void openTabContextMenu(int index, const QPoint& pos);
-
-    /**
-     * Is connected to the QTabBar signal tabMoved(int from, int to).
-     * Reorders the list of tabs after a tab was moved in the tab bar
-     * and sets m_tabIndex to the new index of the current tab.
-     */
-    void slotTabMoved(int from, int to);
-
-    /**
-     * Is connected to the KTabBar signal testCanDecode() and adjusts
-     * the output parameter \a accept.
-     */
-    void slotTestCanDecode(const QDragMoveEvent* event, bool& accept);
-
     /**
      * If the URL can be listed, open it in the current view, otherwise
      * run it through KRun.
@@ -423,12 +374,6 @@ private slots:
      */
     void slotHandleUrlStatFinished(KJob* job);
 
-    /**
-     * Is connected to the KTabBar signal receivedDropEvent.
-     * Allows dragging and dropping files onto tabs.
-     */
-    void tabDropEvent(int tab, QDropEvent* event);
-
     /**
      * Is invoked when the write state of a folder has been changed and
      * enables/disables the "Create New..." menu entry.
@@ -466,17 +411,31 @@ private slots:
      */
     void slotPlaceActivated(const KUrl& url);
 
-    void activeViewChanged();
+    /**
+     * Is called if the another view has been activated by changing the current
+     * tab or activating another view in split-view mode.
+     *
+     * Activates the given view, which means that all menu actions are applied
+     * to this view. When having a split view setup, the nonactive view is
+     * usually shown in darker colors.
+     */
+    void activeViewChanged(DolphinViewContainer* viewContainer);
+
+    void closedTabsCountChanged(unsigned int count);
 
-private:
     /**
-     * Activates the given view, which means that
-     * all menu actions are applied to this view. When
-     * having a split view setup, the nonactive view
-     * is usually shown in darker colors.
+     * Is called if a new tab has been opened or a tab has been closed to
+     * enable/disable the tab actions.
+     */
+    void tabCountChanged(int count);
+
+    /**
+     * Sets the window caption to url.fileName() if this is non-empty,
+     * "/" if the URL is "file:///", and url.protocol() otherwise.
      */
-    void setActiveViewContainer(DolphinViewContainer* view);
+    void setUrlAsCaption(const KUrl& url);
 
+private:
     void setupActions();
     void setupDockWidgets();
     void updateEditActions();
@@ -509,20 +468,8 @@ private:
      */
     void updateSplitAction();
 
-    /** Returns the name of the tab for the URL \a url. */
-    QString tabName(const KUrl& url) const;
-
-
     bool isKompareInstalled() const;
 
-    /**
-     * Sets the window caption to url.fileName() if this is non-empty,
-     * "/" if the URL is "file:///", and url.protocol() otherwise.
-     */
-    void setUrlAsCaption(const KUrl& url);
-
-    QString squeezedText(const QString& text) const;
-
     /**
      * Creates an action for showing/hiding a panel, that is accessible
      * in "Configure toolbars..." and "Configure shortcuts...". This is necessary
@@ -549,14 +496,10 @@ private:
     };
 
     KNewFileMenu* m_newFileMenu;
-    KTabBar* m_tabBar;
+    DolphinTabWidget* m_tabWidget;
     DolphinViewContainer* m_activeViewContainer;
-    QVBoxLayout* m_centralWidgetLayout;
     int m_id;
 
-    int m_tabIndex;
-    QList<DolphinTabPage*> m_viewTab;
-
     DolphinViewActionHandler* m_actionHandler;
     DolphinRemoteEncoding* m_remoteEncoding;
     QWeakPointer<DolphinSettingsDialog> m_settingsDialog;
index a39f9945bf681516238af00b0b1618476ccecccb..fa3eaf166d4db726b21c3c786e44d4825b7c04c1 100644 (file)
@@ -40,19 +40,14 @@ DolphinRecentTabsMenu::DolphinRecentTabsMenu(QObject* parent) :
             this, SLOT(handleAction(QAction*)));
 }
 
-void DolphinRecentTabsMenu::rememberClosedTab(const KUrl& primaryUrl, const KUrl& secondaryUrl)
+void DolphinRecentTabsMenu::rememberClosedTab(const KUrl& url, const QByteArray& state)
 {
     QAction* action = new QAction(menu());
-    action->setText(primaryUrl.path());
-
-    const QString iconName = KMimeType::iconNameForUrl(primaryUrl);
+    action->setText(url.path());
+    action->setData(state);
+    const QString iconName = KMimeType::iconNameForUrl(url);
     action->setIcon(KIcon(iconName));
 
-    KUrl::List urls;
-    urls << primaryUrl;
-    urls << secondaryUrl;
-    action->setData(QVariant::fromValue(urls));
-
     // Add the closed tab menu entry after the separator and
     // "Empty Recently Closed Tabs" entry
     if (menu()->actions().size() == 2) {
@@ -60,7 +55,7 @@ void DolphinRecentTabsMenu::rememberClosedTab(const KUrl& primaryUrl, const KUrl
     } else {
         insertAction(menu()->actions().at(2), action);
     }
-
+    emit closedTabsCountChanged(menu()->actions().size() - 2);
     // Assure that only up to 6 closed tabs are shown in the menu.
     // 8 because of clear action + separator + 6 closed tabs
     if (menu()->actions().size() > 8) {
@@ -70,6 +65,12 @@ void DolphinRecentTabsMenu::rememberClosedTab(const KUrl& primaryUrl, const KUrl
     KAcceleratorManager::manage(menu());
 }
 
+void DolphinRecentTabsMenu::undoCloseTab()
+{
+    Q_ASSERT(menu()->actions().size() > 2);
+    handleAction(menu()->actions().at(2));
+}
+
 void DolphinRecentTabsMenu::handleAction(QAction* action)
 {
     if (action == m_clearListAction) {
@@ -80,14 +81,14 @@ void DolphinRecentTabsMenu::handleAction(QAction* action)
         for (int i = 2; i < count; ++i) {
             removeAction(actions.at(i));
         }
+        emit closedTabsCountChanged(0);
     } else {
-        const KUrl::List urls = action->data().value<KUrl::List>();
-        if (urls.count() == 2) {
-            emit restoreClosedTab(urls.first(), urls.last());
-        }
+        const QByteArray state = action->data().value<QByteArray>();
         removeAction(action);
         delete action;
         action = 0;
+        emit restoreClosedTab(state);
+        emit closedTabsCountChanged(menu()->actions().size() - 2);
     }
 
     if (menu()->actions().count() <= 2) {
index 34d41530b6b4096d60829b2a4e6115a19c6a577d..910e564a19bb7f2850feec88cffaef89583fa99c 100644 (file)
@@ -34,10 +34,12 @@ public:
     explicit DolphinRecentTabsMenu(QObject* parent);
 
 public slots:
-    void rememberClosedTab(const KUrl& primaryUrl, const KUrl& secondaryUrl);
+    void rememberClosedTab(const KUrl& url, const QByteArray& state);
+    void undoCloseTab();
 
 signals:
-    void restoreClosedTab(const KUrl& primaryUrl, const KUrl& secondaryUrl);
+    void restoreClosedTab(const QByteArray& state);
+    void closedTabsCountChanged(unsigned int count);
 
 private slots:
     void handleAction(QAction* action);
diff --git a/src/dolphintabbar.cpp b/src/dolphintabbar.cpp
new file mode 100644 (file)
index 0000000..78bd5ed
--- /dev/null
@@ -0,0 +1,174 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Emmanuel Pescosta <emmanuelpescosta099@gmail.com> *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA            *
+ ***************************************************************************/
+
+#include "dolphintabbar.h"
+
+#include <QTimer>
+#include <QDragEnterEvent>
+#include <KLocalizedString>
+#include <KMenu>
+#include <KIcon>
+#include <KUrl>
+
+DolphinTabBar::DolphinTabBar(QWidget* parent) :
+    QTabBar(parent),
+    m_autoActivationIndex(-1)
+{
+    setAcceptDrops(true);
+    setSelectionBehaviorOnRemove(QTabBar::SelectPreviousTab);
+    setMovable(true);
+    setTabsClosable(true);
+
+    m_autoActivationTimer = new QTimer(this);
+    m_autoActivationTimer->setSingleShot(true);
+    m_autoActivationTimer->setInterval(800);
+    connect(m_autoActivationTimer, SIGNAL(timeout()),
+            this, SLOT(slotAutoActivationTimeout()));
+}
+
+void DolphinTabBar::dragEnterEvent(QDragEnterEvent* event)
+{
+    const QMimeData* mimeData = event->mimeData();
+    const int index = tabAt(event->pos());
+
+    if (KUrl::List::canDecode(mimeData)) {
+        event->acceptProposedAction();
+        updateAutoActivationTimer(index);
+    }
+
+    QTabBar::dragEnterEvent(event);
+}
+
+void DolphinTabBar::dragLeaveEvent(QDragLeaveEvent* event)
+{
+    updateAutoActivationTimer(-1);
+
+    QTabBar::dragLeaveEvent(event);
+}
+
+void DolphinTabBar::dragMoveEvent(QDragMoveEvent* event)
+{
+    const QMimeData* mimeData = event->mimeData();
+    const int index = tabAt(event->pos());
+
+    if (KUrl::List::canDecode(mimeData)) {
+        updateAutoActivationTimer(index);
+    }
+
+    QTabBar::dragMoveEvent(event);
+}
+
+void DolphinTabBar::dropEvent(QDropEvent* event)
+{
+    // Disable the auto activation timer
+    updateAutoActivationTimer(-1);
+
+    const QMimeData* mimeData = event->mimeData();
+    const int index = tabAt(event->pos());
+
+    if (index >= 0 && KUrl::List::canDecode(mimeData)) {
+        emit tabDropEvent(index, event);
+    }
+
+    QTabBar::dropEvent(event);
+}
+
+void DolphinTabBar::mousePressEvent(QMouseEvent* event)
+{
+    const int index = tabAt(event->pos());
+
+    if (index >= 0 && event->button() == Qt::MiddleButton) {
+        // Mouse middle click on a tab closes this tab.
+        emit tabCloseRequested(index);
+        return;
+    }
+
+    QTabBar::mousePressEvent(event);
+}
+
+void DolphinTabBar::mouseDoubleClickEvent(QMouseEvent* event)
+{
+    const int index = tabAt(event->pos());
+
+    if (index < 0) {
+        // Double click on the empty tabbar area opens a new activated tab
+        // with the url from the current tab.
+        emit openNewActivatedTab(currentIndex());
+        return;
+    }
+
+    QTabBar::mouseDoubleClickEvent(event);
+}
+
+void DolphinTabBar::contextMenuEvent(QContextMenuEvent* event)
+{
+    const int index = tabAt(event->pos());
+
+    if (index >= 0) {
+        // Tab context menu
+        KMenu menu(this);
+
+        QAction* newTabAction = menu.addAction(KIcon("tab-new"), i18nc("@action:inmenu", "New Tab"));
+        QAction* detachTabAction = menu.addAction(KIcon("tab-detach"), i18nc("@action:inmenu", "Detach Tab"));
+        QAction* closeOtherTabsAction = menu.addAction(KIcon("tab-close-other"), i18nc("@action:inmenu", "Close Other Tabs"));
+        QAction* closeTabAction = menu.addAction(KIcon("tab-close"), i18nc("@action:inmenu", "Close Tab"));
+
+        QAction* selectedAction = menu.exec(event->globalPos());
+        if (selectedAction == newTabAction) {
+            emit openNewActivatedTab(index);
+        } else if (selectedAction == detachTabAction) {
+            emit tabDetachRequested(index);
+        } else if (selectedAction == closeOtherTabsAction) {
+            const int tabCount = count();
+            for (int i = 0; i < index; i++) {
+                emit tabCloseRequested(0);
+            }
+            for (int i = index + 1; i < tabCount; i++) {
+                emit tabCloseRequested(1);
+            }
+        } else if (selectedAction == closeTabAction) {
+            emit tabCloseRequested(index);
+        }
+
+        return;
+    }
+
+    QTabBar::contextMenuEvent(event);
+}
+
+void DolphinTabBar::slotAutoActivationTimeout()
+{
+    if (m_autoActivationIndex >= 0) {
+        setCurrentIndex(m_autoActivationIndex);
+        updateAutoActivationTimer(-1);
+    }
+}
+
+void DolphinTabBar::updateAutoActivationTimer(const int index)
+{
+    if (m_autoActivationIndex != index) {
+        m_autoActivationIndex = index;
+
+        if (m_autoActivationIndex < 0) {
+            m_autoActivationTimer->stop();
+        } else {
+            m_autoActivationTimer->start();
+        }
+    }
+}
diff --git a/src/dolphintabbar.h b/src/dolphintabbar.h
new file mode 100644 (file)
index 0000000..d2b2e9e
--- /dev/null
@@ -0,0 +1,65 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Emmanuel Pescosta <emmanuelpescosta099@gmail.com> *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA            *
+ ***************************************************************************/
+
+#ifndef DOLPHIN_TAB_BAR_H
+#define DOLPHIN_TAB_BAR_H
+
+#include <QTabBar>
+
+class DolphinTabBar : public QTabBar
+{
+    Q_OBJECT
+
+public:
+    explicit DolphinTabBar(QWidget* parent);
+
+signals:
+    void openNewActivatedTab(int index);
+    void tabDropEvent(int index, QDropEvent* event);
+    void tabDetachRequested(int index);
+
+protected:
+    virtual void dragEnterEvent(QDragEnterEvent* event);
+    virtual void dragLeaveEvent(QDragLeaveEvent* event);
+    virtual void dragMoveEvent(QDragMoveEvent* event);
+    virtual void dropEvent(QDropEvent* event);
+    virtual void mousePressEvent(QMouseEvent* event);
+    virtual void mouseDoubleClickEvent(QMouseEvent* event);
+
+    /**
+     * Opens a context menu for the tab on the \a event position.
+     */
+    virtual void contextMenuEvent(QContextMenuEvent* event);
+
+private slots:
+    void slotAutoActivationTimeout();
+
+private:
+    /**
+     * If \a index is a valid index (>= 0), store the index and start the timer
+     * (if the interval >= 0 ms). If the index is not valid (< 0), stop the timer.
+     */
+    void updateAutoActivationTimer(const int index);
+
+private:
+    QTimer* m_autoActivationTimer;
+    int m_autoActivationIndex;
+};
+
+#endif // DOLPHIN_TAB_BAR_H
index 4c49869f77e07d4341b76d450f827ae73199b108..f7000ea668d3f008bac9f0011bb0703f1d2e2e79 100644 (file)
@@ -41,6 +41,8 @@ DolphinTabPage::DolphinTabPage(const KUrl& primaryUrl, const KUrl& secondaryUrl,
     m_primaryViewContainer = createViewContainer(primaryUrl);
     connect(m_primaryViewContainer->view(), SIGNAL(urlChanged(KUrl)),
             this, SIGNAL(activeViewUrlChanged(KUrl)));
+    connect(m_primaryViewContainer->view(), SIGNAL(redirection(KUrl,KUrl)),
+            this, SLOT(slotViewUrlRedirection(KUrl,KUrl)));
 
     m_splitter->addWidget(m_primaryViewContainer);
     m_primaryViewContainer->show();
@@ -169,14 +171,18 @@ QByteArray DolphinTabPage::saveState() const
     QByteArray state;
     QDataStream stream(&state, QIODevice::WriteOnly);
 
+    stream << quint32(2); // Tab state version
+
     stream << m_splitViewEnabled;
 
     stream << m_primaryViewContainer->url();
     stream << m_primaryViewContainer->urlNavigator()->isUrlEditable();
+    m_primaryViewContainer->view()->saveState(stream);
 
     if (m_splitViewEnabled) {
         stream << m_secondaryViewContainer->url();
         stream << m_secondaryViewContainer->urlNavigator()->isUrlEditable();
+        m_secondaryViewContainer->view()->saveState(stream);
     }
 
     stream << m_primaryViewActive;
@@ -194,6 +200,58 @@ void DolphinTabPage::restoreState(const QByteArray& state)
     QByteArray sd = state;
     QDataStream stream(&sd, QIODevice::ReadOnly);
 
+    // Read the version number of the tab state and check if the version is supported.
+    quint32 version = 0;
+    stream >> version;
+    if (version != 2) {
+        // The version of the tab state isn't supported, we can't restore it.
+        return;
+    }
+
+    bool isSplitViewEnabled = false;
+    stream >> isSplitViewEnabled;
+    setSplitViewEnabled(isSplitViewEnabled);
+
+    KUrl primaryUrl;
+    stream >> primaryUrl;
+    m_primaryViewContainer->setUrl(primaryUrl);
+    bool primaryUrlEditable;
+    stream >> primaryUrlEditable;
+    m_primaryViewContainer->urlNavigator()->setUrlEditable(primaryUrlEditable);
+    m_primaryViewContainer->view()->restoreState(stream);
+
+    if (isSplitViewEnabled) {
+        KUrl secondaryUrl;
+        stream >> secondaryUrl;
+        m_secondaryViewContainer->setUrl(secondaryUrl);
+        bool secondaryUrlEditable;
+        stream >> secondaryUrlEditable;
+        m_secondaryViewContainer->urlNavigator()->setUrlEditable(secondaryUrlEditable);
+        m_secondaryViewContainer->view()->restoreState(stream);
+    }
+
+    stream >> m_primaryViewActive;
+    if (m_primaryViewActive) {
+        m_primaryViewContainer->setActive(true);
+    } else {
+        Q_ASSERT(m_splitViewEnabled);
+        m_secondaryViewContainer->setActive(true);
+    }
+
+    QByteArray splitterState;
+    stream >> splitterState;
+    m_splitter->restoreState(splitterState);
+}
+
+void DolphinTabPage::restoreStateV1(const QByteArray& state)
+{
+    if (state.isEmpty()) {
+        return;
+    }
+
+    QByteArray sd = state;
+    QDataStream stream(&sd, QIODevice::ReadOnly);
+
     bool isSplitViewEnabled = false;
     stream >> isSplitViewEnabled;
     setSplitViewEnabled(isSplitViewEnabled);
@@ -245,12 +303,23 @@ void DolphinTabPage::slotViewActivated()
     if (newActiveView != oldActiveView) {
         disconnect(oldActiveView, SIGNAL(urlChanged(KUrl)),
                    this, SIGNAL(activeViewUrlChanged(KUrl)));
+        disconnect(oldActiveView, SIGNAL(redirection(KUrl,KUrl)),
+                   this, SLOT(slotViewUrlRedirection(KUrl,KUrl)));
         connect(newActiveView, SIGNAL(urlChanged(KUrl)),
                 this, SIGNAL(activeViewUrlChanged(KUrl)));
+        connect(newActiveView, SIGNAL(redirection(KUrl,KUrl)),
+                this, SLOT(slotViewUrlRedirection(KUrl,KUrl)));
     }
 
     emit activeViewUrlChanged(activeViewContainer()->url());
-    emit activeViewChanged();
+    emit activeViewChanged(activeViewContainer());
+}
+
+void DolphinTabPage::slotViewUrlRedirection(const KUrl& oldUrl, const KUrl& newUrl)
+{
+    Q_UNUSED(oldUrl);
+
+    emit activeViewUrlChanged(newUrl);
 }
 
 DolphinViewContainer* DolphinTabPage::createViewContainer(const KUrl& url) const
index 95c02ed0a1ef8759d6a9d1ebee6e0c4b29f254a4..2a406f4a9a065687eff0d07ff6d15de421d752af 100644 (file)
@@ -120,8 +120,17 @@ public:
      */
     void restoreState(const QByteArray& state);
 
+    /**
+     * Restores all tab related properties (urls, splitter layout, ...) from
+     * the given \a state.
+     *
+     * @deprecated The first tab state version has no version number, we keep
+     *             this method to restore old states (<= Dolphin 4.14.x).
+     */
+    void restoreStateV1(const QByteArray& state);
+
 signals:
-    void activeViewChanged();
+    void activeViewChanged(DolphinViewContainer* viewContainer);
     void activeViewUrlChanged(const KUrl& url);
 
 private slots:
@@ -133,6 +142,13 @@ private slots:
      */
     void slotViewActivated();
 
+    /**
+     * Handles the view url redirection event.
+     *
+     * It emits the activeViewUrlChanged signal with the url \a newUrl.
+     */
+    void slotViewUrlRedirection(const KUrl& oldUrl, const KUrl& newUrl);
+
 private:
     /**
      * Creates a new view container and does the default initialization.
diff --git a/src/dolphintabwidget.cpp b/src/dolphintabwidget.cpp
new file mode 100644 (file)
index 0000000..c6607e5
--- /dev/null
@@ -0,0 +1,361 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Emmanuel Pescosta <emmanuelpescosta099@gmail.com> *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA            *
+ ***************************************************************************/
+
+#include "dolphintabwidget.h"
+
+#include "dolphintabbar.h"
+#include "dolphintabpage.h"
+#include "dolphinviewcontainer.h"
+#include "dolphin_generalsettings.h"
+#include "views/draganddrophelper.h"
+
+#include <QApplication>
+#include <KConfigGroup>
+#include <KIcon>
+#include <KRun>
+
+DolphinTabWidget::DolphinTabWidget(QWidget* parent) :
+    QTabWidget(parent),
+    m_placesSelectorVisible(true)
+{
+    connect(this, SIGNAL(tabCloseRequested(int)),
+            this, SLOT(closeTab(int)));
+    connect(this, SIGNAL(currentChanged(int)),
+            this, SLOT(currentTabChanged(int)));
+
+    DolphinTabBar* tabBar = new DolphinTabBar(this);
+    connect(tabBar, SIGNAL(openNewActivatedTab(int)),
+            this, SLOT(openNewActivatedTab(int)));
+    connect(tabBar, SIGNAL(tabDropEvent(int,QDropEvent*)),
+            this, SLOT(tabDropEvent(int,QDropEvent*)));
+    connect(tabBar, SIGNAL(tabDetachRequested(int)),
+            this, SLOT(detachTab(int)));
+    tabBar->hide();
+
+    setTabBar(tabBar);
+    setDocumentMode(true);
+    setElideMode(Qt::ElideRight);
+    setUsesScrollButtons(true);
+}
+
+DolphinTabPage* DolphinTabWidget::currentTabPage() const
+{
+    return tabPageAt(currentIndex());
+}
+
+DolphinTabPage* DolphinTabWidget::tabPageAt(const int index) const
+{
+    return static_cast<DolphinTabPage*>(widget(index));
+}
+
+void DolphinTabWidget::saveProperties(KConfigGroup& group) const
+{
+    const int tabCount = count();
+    group.writeEntry("Tab Count", tabCount);
+    group.writeEntry("Active Tab Index", currentIndex());
+
+    for (int i = 0; i < tabCount; ++i) {
+        const DolphinTabPage* tabPage = tabPageAt(i);
+        group.writeEntry("Tab Data " % QString::number(i), tabPage->saveState());
+    }
+}
+
+void DolphinTabWidget::readProperties(const KConfigGroup& group)
+{
+    const int tabCount = group.readEntry("Tab Count", 0);
+    for (int i = 0; i < tabCount; ++i) {
+        if (i >= count()) {
+            openNewActivatedTab();
+        }
+        if (group.hasKey("Tab Data " % QString::number(i))) {
+            // Tab state created with Dolphin > 4.14.x
+            const QByteArray state = group.readEntry("Tab Data " % QString::number(i), QByteArray());
+            tabPageAt(i)->restoreState(state);
+        } else {
+            // Tab state created with Dolphin <= 4.14.x
+            const QByteArray state = group.readEntry("Tab " % QString::number(i), QByteArray());
+            tabPageAt(i)->restoreStateV1(state);
+        }
+    }
+
+    const int index = group.readEntry("Active Tab Index", 0);
+    setCurrentIndex(index);
+}
+
+void DolphinTabWidget::refreshViews()
+{
+    const int tabCount = count();
+    for (int i = 0; i < tabCount; ++i) {
+        tabPageAt(i)->refreshViews();
+    }
+}
+
+void DolphinTabWidget::openNewActivatedTab()
+{
+    const DolphinViewContainer* oldActiveViewContainer = currentTabPage()->activeViewContainer();
+    Q_ASSERT(oldActiveViewContainer);
+
+    const bool isUrlEditable = oldActiveViewContainer->urlNavigator()->isUrlEditable();
+
+    openNewActivatedTab(oldActiveViewContainer->url());
+
+    DolphinViewContainer* newActiveViewContainer = currentTabPage()->activeViewContainer();
+    Q_ASSERT(newActiveViewContainer);
+
+    // The URL navigator of the new tab should have the same editable state
+    // as the current tab
+    KUrlNavigator* navigator = newActiveViewContainer->urlNavigator();
+    navigator->setUrlEditable(isUrlEditable);
+
+    if (isUrlEditable) {
+        // If a new tab is opened and the URL is editable, assure that
+        // the user can edit the URL without manually setting the focus
+        navigator->setFocus();
+    }
+}
+
+void DolphinTabWidget::openNewActivatedTab(const KUrl& primaryUrl, const KUrl& secondaryUrl)
+{
+    openNewTab(primaryUrl, secondaryUrl);
+    setCurrentIndex(count() - 1);
+}
+
+void DolphinTabWidget::openNewTab(const KUrl& primaryUrl, const KUrl& secondaryUrl)
+{
+    QWidget* focusWidget = QApplication::focusWidget();
+
+    DolphinTabPage* tabPage = new DolphinTabPage(primaryUrl, secondaryUrl, this);
+    tabPage->setPlacesSelectorVisible(m_placesSelectorVisible);
+    connect(tabPage, SIGNAL(activeViewChanged(DolphinViewContainer*)),
+            this, SIGNAL(activeViewChanged(DolphinViewContainer*)));
+    connect(tabPage, SIGNAL(activeViewUrlChanged(KUrl)),
+            this, SLOT(tabUrlChanged(KUrl)));
+    addTab(tabPage, KIcon(KMimeType::iconNameForUrl(primaryUrl)), tabName(primaryUrl));
+
+    if (focusWidget) {
+        // The DolphinViewContainer grabbed the keyboard focus. As the tab is opened
+        // in background, assure that the previous focused widget gets the focus back.
+        focusWidget->setFocus();
+    }
+}
+
+void DolphinTabWidget::openDirectories(const QList<KUrl>& dirs)
+{
+    const bool hasSplitView = GeneralSettings::splitView();
+
+    // Open each directory inside a new tab. If the "split view" option has been enabled,
+    // always show two directories within one tab.
+    QList<KUrl>::const_iterator it = dirs.constBegin();
+    while (it != dirs.constEnd()) {
+        const KUrl& primaryUrl = *(it++);
+        if (hasSplitView && (it != dirs.constEnd())) {
+            const KUrl& secondaryUrl = *(it++);
+            openNewTab(primaryUrl, secondaryUrl);
+        } else {
+            openNewTab(primaryUrl);
+        }
+    }
+}
+
+void DolphinTabWidget::openFiles(const QList<KUrl>& files)
+{
+    if (files.isEmpty()) {
+        return;
+    }
+
+    // Get all distinct directories from 'files' and open a tab
+    // for each directory. If the "split view" option is enabled, two
+    // directories are shown inside one tab (see openDirectories()).
+    QList<KUrl> dirs;
+    foreach (const KUrl& url, files) {
+        const KUrl dir(url.directory());
+        if (!dirs.contains(dir)) {
+            dirs.append(dir);
+        }
+    }
+
+    const int oldTabCount = count();
+    openDirectories(dirs);
+    const int tabCount = count();
+
+    // Select the files. Although the files can be split between several
+    // tabs, there is no need to split 'files' accordingly, as
+    // the DolphinView will just ignore invalid selections.
+    for (int i = oldTabCount; i < tabCount; ++i) {
+        DolphinTabPage* tabPage = tabPageAt(i);
+        tabPage->markUrlsAsSelected(files);
+        tabPage->markUrlAsCurrent(files.first());
+    }
+}
+
+void DolphinTabWidget::closeTab()
+{
+    closeTab(currentIndex());
+}
+
+void DolphinTabWidget::closeTab(const int index)
+{
+    Q_ASSERT(index >= 0);
+    Q_ASSERT(index < count());
+
+    if (count() < 2) {
+        // Never close the last tab.
+        return;
+    }
+
+    DolphinTabPage* tabPage = tabPageAt(index);
+    emit rememberClosedTab(tabPage->activeViewContainer()->url(), tabPage->saveState());
+
+    removeTab(index);
+    tabPage->deleteLater();
+}
+
+void DolphinTabWidget::activateNextTab()
+{
+    const int index = currentIndex() + 1;
+    setCurrentIndex(index < count() ? index : 0);
+}
+
+void DolphinTabWidget::activatePrevTab()
+{
+    const int index = currentIndex() - 1;
+    setCurrentIndex(index >= 0 ? index : (count() - 1));
+}
+
+void DolphinTabWidget::slotPlacesPanelVisibilityChanged(bool visible)
+{
+    // The places-selector from the URL navigator should only be shown
+    // if the places dock is invisible
+    m_placesSelectorVisible = !visible;
+
+    const int tabCount = count();
+    for (int i = 0; i < tabCount; ++i) {
+        DolphinTabPage* tabPage = tabPageAt(i);
+        tabPage->setPlacesSelectorVisible(m_placesSelectorVisible);
+    }
+}
+
+void DolphinTabWidget::restoreClosedTab(const QByteArray& state)
+{
+    openNewActivatedTab();
+    currentTabPage()->restoreState(state);
+}
+
+void DolphinTabWidget::detachTab(int index)
+{
+    Q_ASSERT(index >= 0);
+
+    const QString separator(QLatin1Char(' '));
+    QString command = QLatin1String("dolphin");
+
+    const DolphinTabPage* tabPage = tabPageAt(index);
+    command += separator + tabPage->primaryViewContainer()->url().url();
+    if (tabPage->splitViewEnabled()) {
+        command += separator + tabPage->secondaryViewContainer()->url().url();
+        command += separator + QLatin1String("-split");
+    }
+
+    KRun::runCommand(command, this);
+
+    closeTab(index);
+}
+
+void DolphinTabWidget::openNewActivatedTab(int index)
+{
+    Q_ASSERT(index >= 0);
+    const DolphinTabPage* tabPage = tabPageAt(index);
+    openNewActivatedTab(tabPage->activeViewContainer()->url());
+}
+
+void DolphinTabWidget::tabDropEvent(int index, QDropEvent* event)
+{
+    if (index >= 0) {
+        const DolphinView* view = tabPageAt(index)->activeViewContainer()->view();
+
+        QString error;
+        DragAndDropHelper::dropUrls(view->rootItem(), view->url(), event, error);
+        if (!error.isEmpty()) {
+            currentTabPage()->activeViewContainer()->showMessage(error, DolphinViewContainer::Error);
+        }
+    }
+}
+
+void DolphinTabWidget::tabUrlChanged(const KUrl& url)
+{
+    const int index = indexOf(qobject_cast<QWidget*>(sender()));
+    if (index >= 0) {
+        tabBar()->setTabText(index, tabName(url));
+        tabBar()->setTabIcon(index, KIcon(KMimeType::iconNameForUrl(url)));
+
+        // Emit the currentUrlChanged signal if the url of the current tab has been changed.
+        if (index == currentIndex()) {
+            emit currentUrlChanged(url);
+        }
+    }
+}
+
+void DolphinTabWidget::currentTabChanged(int index)
+{
+    DolphinViewContainer* viewContainer = tabPageAt(index)->activeViewContainer();
+    emit activeViewChanged(viewContainer);
+    emit currentUrlChanged(viewContainer->url());
+    viewContainer->view()->setFocus();
+}
+
+void DolphinTabWidget::tabInserted(int index)
+{
+    QTabWidget::tabInserted(index);
+
+    if (count() > 1) {
+        tabBar()->show();
+    }
+
+    emit tabCountChanged(count());
+}
+
+void DolphinTabWidget::tabRemoved(int index)
+{
+    QTabWidget::tabRemoved(index);
+
+    // If only one tab is left, then remove the tab entry so that
+    // closing the last tab is not possible.
+    if (count() < 2) {
+        tabBar()->hide();
+    }
+
+    emit tabCountChanged(count());
+}
+
+QString DolphinTabWidget::tabName(const KUrl& url) const
+{
+    QString name;
+    if (url.equals(KUrl("file:///"))) {
+        name = '/';
+    } else {
+        name = url.fileName();
+        if (name.isEmpty()) {
+            name = url.protocol();
+        } else {
+            // Make sure that a '&' inside the directory name is displayed correctly
+            // and not misinterpreted as a keyboard shortcut in QTabBar::setTabText()
+            name.replace('&', "&&");
+        }
+    }
+    return name;
+}
diff --git a/src/dolphintabwidget.h b/src/dolphintabwidget.h
new file mode 100644 (file)
index 0000000..98bcd98
--- /dev/null
@@ -0,0 +1,190 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Emmanuel Pescosta <emmanuelpescosta099@gmail.com> *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA            *
+ ***************************************************************************/
+
+#ifndef DOLPHIN_TAB_WIDGET_H
+#define DOLPHIN_TAB_WIDGET_H
+
+#include <QTabWidget>
+#include <KUrl>
+
+class DolphinViewContainer;
+class DolphinTabPage;
+class KConfigGroup;
+
+class DolphinTabWidget : public QTabWidget
+{
+    Q_OBJECT
+
+public:
+    explicit DolphinTabWidget(QWidget* parent);
+
+    /**
+     * @return Tab page at the current index (can be 0 if tabs count is smaller than 1)
+     */
+    DolphinTabPage* currentTabPage() const;
+
+    /**
+     * @return Tab page at the given \a index (can be 0 if the index is out-of-range)
+     */
+    DolphinTabPage* tabPageAt(const int index) const;
+
+    void saveProperties(KConfigGroup& group) const;
+    void readProperties(const KConfigGroup& group);
+
+    /**
+     * Refreshes the views of the main window by recreating them according to
+     * the given Dolphin settings.
+     */
+    void refreshViews();
+
+signals:
+    /**
+     * Is emitted when the active view has been changed, by changing the current
+     * tab or by activating another view when split view is enabled in the current
+     * tab.
+     */
+    void activeViewChanged(DolphinViewContainer* viewContainer);
+
+    /**
+     * Is emitted when the number of open tabs has changed (e.g. by opening or
+     * closing a tab)
+     */
+    void tabCountChanged(int count);
+
+    /**
+     * Is emitted when a tab has been closed.
+     */
+    void rememberClosedTab(const KUrl& url, const QByteArray& state);
+
+    /**
+     * Is emitted when the url of the current tab has been changed. This signal
+     * is also emitted when the active view has been changed.
+     */
+    void currentUrlChanged(const KUrl& url);
+
+public slots:
+    /**
+     * Opens a new view with the current URL that is part of a tab and activates
+     * the tab.
+     */
+    void openNewActivatedTab();
+
+    /**
+     * Opens a new tab showing the  URL \a primaryUrl and the optional URL
+     * \a secondaryUrl and activates the tab.
+     */
+    void openNewActivatedTab(const KUrl& primaryUrl, const KUrl& secondaryUrl = KUrl());
+
+    /**
+     * Opens a new tab in the background showing the URL \a primaryUrl and the
+     * optional URL \a secondaryUrl.
+     */
+    void openNewTab(const KUrl& primaryUrl, const KUrl& secondaryUrl = KUrl());
+
+    /**
+     * Opens each directory in \p dirs in a separate tab. If the "split view"
+     * option is enabled, 2 directories are collected within one tab.
+     */
+    void openDirectories(const QList<KUrl>& dirs);
+
+    /**
+     * Opens the directory which contains the files \p files
+     * and selects all files (implements the --select option
+     * of Dolphin).
+     */
+    void openFiles(const QList<KUrl>& files);
+
+    /**
+     * Closes the currently active tab.
+     */
+    void closeTab();
+
+    /**
+     * Closes the tab with the index \a index and activates the tab with index - 1.
+     */
+    void closeTab(const int index);
+
+    /**
+     * Activates the next tab in the tab bar.
+     * If the current active tab is the last tab, it activates the first tab.
+     */
+    void activateNextTab();
+
+    /**
+     * Activates the previous tab in the tab bar.
+     * If the current active tab is the first tab, it activates the last tab.
+     */
+    void activatePrevTab();
+
+    /**
+     * Is invoked if the Places panel got visible/invisible and takes care
+     * that the places-selector of all views is only shown if the Places panel
+     * is invisible.
+     */
+    void slotPlacesPanelVisibilityChanged(bool visible);
+
+    /**
+     * Is called when the user wants to reopen a previously closed tab from
+     * the recent tabs menu.
+     */
+    void restoreClosedTab(const QByteArray& state);
+
+private slots:
+    /**
+     * Opens the tab with the index \a index in a new Dolphin instance and closes
+     * this tab.
+     */
+    void detachTab(int index);
+
+    /**
+     * Opens a new tab showing the url from tab at the given \a index and
+     * activates the tab.
+     */
+    void openNewActivatedTab(int index);
+
+    /**
+     * Is connected to the KTabBar signal receivedDropEvent.
+     * Allows dragging and dropping files onto tabs.
+     */
+    void tabDropEvent(int tab, QDropEvent* event);
+
+    /**
+     * The active view url of a tab has been changed so update the text and the
+     * icon of the corresponding tab.
+     */
+    void tabUrlChanged(const KUrl& url);
+
+    void currentTabChanged(int index);
+
+protected:
+    virtual void tabInserted(int index);
+    virtual void tabRemoved(int index);
+
+private:
+    /**
+     * Returns the name of the tab for the URL \a url.
+     */
+    QString tabName(const KUrl& url) const;
+
+private:
+    /** Caches the (negated) places panel visibility */
+    bool m_placesSelectorVisible;
+};
+
+#endif
\ No newline at end of file
index 52826bb43a1a7556ddca433262caaab8b0235924..f197af402e1ece48e68378e14ce654ca8e81cfa0 100644 (file)
@@ -6,6 +6,7 @@
             <Action name="new_window" />
             <Action name="new_tab" />
             <Action name="close_tab" />
+           <Action name="undo_close_tab" />
             <Separator/>
             <Action name="rename" />
             <Action name="move_to_trash" />
index a8e785a0d2ddbd3451a6bbb93a5230bb36dbabd4..3ce3204e9b95909954f2b235a41e4fa82e52d7b0 100644 (file)
@@ -36,10 +36,13 @@ KDE_EXPORT int kdemain(int argc, char **argv)
                      KDE_VERSION_STRING,
                      ki18nc("@title", "File Manager"),
                      KAboutData::License_GPL,
-                     ki18nc("@info:credit", "(C) 2006-2014 Peter Penz and Frank Reininghaus"));
+                     ki18nc("@info:credit", "(C) 2006-2014 Peter Penz, Frank Reininghaus, and Emmanuel Pescosta"));
     about.setHomepage("http://dolphin.kde.org");
+    about.addAuthor(ki18nc("@info:credit", "Emmanuel Pescosta"),
+                    ki18nc("@info:credit", "Maintainer (since 2014) and developer"),
+                    "emmanuelpescosta099@gmail.com");
     about.addAuthor(ki18nc("@info:credit", "Frank Reininghaus"),
-                    ki18nc("@info:credit", "Maintainer (since 2012) and developer"),
+                    ki18nc("@info:credit", "Maintainer (2012-2014) and developer"),
                     "frank78ac@googlemail.com");
     about.addAuthor(ki18nc("@info:credit", "Peter Penz"),
                     ki18nc("@info:credit", "Maintainer and developer (2006-2012)"),
@@ -50,9 +53,6 @@ KDE_EXPORT int kdemain(int argc, char **argv)
     about.addAuthor(ki18nc("@info:credit", "David Faure"),
                     ki18nc("@info:credit", "Developer"),
                     "faure@kde.org");
-    about.addAuthor(ki18nc("@info:credit", "Emmanuel Pescosta"),
-                    ki18nc("@info:credit", "Developer"),
-                    "emmanuelpescosta099@gmail.com");
     about.addAuthor(ki18nc("@info:credit", "Aaron J. Seigo"),
                     ki18nc("@info:credit", "Developer"),
                     "aseigo@kde.org");
index 539b9263daa660d1aeebb4991bcbf040d4623020..173da29c5e5443156e3b6a1456d081b874ed4cee 100644 (file)
@@ -144,20 +144,20 @@ void PlacesItem::setBookmark(const KBookmark& bookmark)
     const GroupType type = groupType();
     if (icon().isEmpty()) {
         switch (type) {
-        case RecentlyAccessedType: setIcon("chronometer"); break;
-        case SearchForType:        setIcon("nepomuk"); break;
+        case RecentlySavedType: setIcon("chronometer"); break;
+        case SearchForType:     setIcon("nepomuk"); break;
         case PlacesType:
-        default:                   setIcon("folder");
+        default:                setIcon("folder");
         }
 
     }
 
     switch (type) {
-    case PlacesType:           setGroup(i18nc("@item", "Places")); break;
-    case RecentlyAccessedType: setGroup(i18nc("@item", "Recently Accessed")); break;
-    case SearchForType:        setGroup(i18nc("@item", "Search For")); break;
-    case DevicesType:          setGroup(i18nc("@item", "Devices")); break;
-    default:                   Q_ASSERT(false); break;
+    case PlacesType:        setGroup(i18nc("@item", "Places")); break;
+    case RecentlySavedType: setGroup(i18nc("@item", "Recently Saved")); break;
+    case SearchForType:     setGroup(i18nc("@item", "Search For")); break;
+    case DevicesType:       setGroup(i18nc("@item", "Devices")); break;
+    default:                Q_ASSERT(false); break;
     }
 
     setHidden(bookmark.metaDataItem("IsHidden") == QLatin1String("true"));
@@ -173,7 +173,7 @@ PlacesItem::GroupType PlacesItem::groupType() const
     if (udi().isEmpty()) {
         const QString protocol = url().protocol();
         if (protocol == QLatin1String("timeline")) {
-            return RecentlyAccessedType;
+            return RecentlySavedType;
         }
 
         if (protocol.contains(QLatin1String("search"))) {
index 297f12d9123e6eb50df787f21c649e15102c3ae9..4c636ec63412e088d37103c22835fa823fd9b140 100644 (file)
@@ -44,7 +44,7 @@ public:
     {
         PlacesType,
         SearchForType,
-        RecentlyAccessedType,
+        RecentlySavedType,
         DevicesType
     };
 
index 2ac2169586a7eaf757bf1c3673a4c113460c60a2..6accdc837070e7f8d350ee85b3588b1756d28de4 100644 (file)
@@ -58,7 +58,7 @@
 
 namespace {
     // As long as KFilePlacesView from kdelibs is available in parallel, the
-    // system-bookmarks for "Recently Accessed" and "Search For" should be
+    // system-bookmarks for "Recently Saved" and "Search For" should be
     // shown only inside the Places Panel. This is necessary as the stored
     // URLs needs to get translated to a Baloo-search-URL on-the-fly to
     // be independent from changes in the Baloo-search-URL-syntax.
@@ -313,7 +313,8 @@ void PlacesItemModel::requestEject(int index)
         Solid::OpticalDrive* drive = item->device().parent().as<Solid::OpticalDrive>();
         if (drive) {
             connect(drive, SIGNAL(ejectDone(Solid::ErrorType,QVariant,QString)),
-                    this, SLOT(slotStorageTeardownDone(Solid::ErrorType,QVariant)));
+                    this, SLOT(slotStorageTeardownDone(Solid::ErrorType,QVariant)),
+                    Qt::UniqueConnection);
             drive->eject();
         } else {
             const QString label = item->text();
@@ -330,7 +331,8 @@ void PlacesItemModel::requestTeardown(int index)
         Solid::StorageAccess* access = item->device().as<Solid::StorageAccess>();
         if (access) {
             connect(access, SIGNAL(teardownDone(Solid::ErrorType,QVariant,QString)),
-                    this, SLOT(slotStorageTeardownDone(Solid::ErrorType,QVariant)));
+                    this, SLOT(slotStorageTeardownDone(Solid::ErrorType,QVariant)),
+                    Qt::UniqueConnection);
             access->teardown();
         }
     }
@@ -359,7 +361,8 @@ void PlacesItemModel::requestStorageSetup(int index)
         m_storageSetupInProgress[access] = index;
 
         connect(access, SIGNAL(setupDone(Solid::ErrorType,QVariant,QString)),
-                this, SLOT(slotStorageSetupDone(Solid::ErrorType,QVariant,QString)));
+                this, SLOT(slotStorageSetupDone(Solid::ErrorType,QVariant,QString)),
+                Qt::UniqueConnection);
 
         access->setup();
     }
@@ -599,6 +602,7 @@ void PlacesItemModel::slotStorageSetupDone(Solid::ErrorType error,
 {
     Q_UNUSED(udi);
 
+    Q_ASSERT(!m_storageSetupInProgress.isEmpty());
     const int index = m_storageSetupInProgress.take(sender());
     const PlacesItem*  item = placesItem(index);
     if (!item) {
@@ -738,7 +742,7 @@ void PlacesItemModel::loadBookmarks()
     // items should always be collected in one group so the items are collected first
     // in separate lists before inserting them.
     QList<PlacesItem*> placesItems;
-    QList<PlacesItem*> recentlyAccessedItems;
+    QList<PlacesItem*> recentlySavedItems;
     QList<PlacesItem*> searchForItems;
     QList<PlacesItem*> devicesItems;
 
@@ -763,11 +767,11 @@ void PlacesItemModel::loadBookmarks()
                 }
 
                 switch (item->groupType()) {
-                case PlacesItem::PlacesType:           placesItems.append(item); break;
-                case PlacesItem::RecentlyAccessedType: recentlyAccessedItems.append(item); break;
-                case PlacesItem::SearchForType:        searchForItems.append(item); break;
+                case PlacesItem::PlacesType:        placesItems.append(item); break;
+                case PlacesItem::RecentlySavedType: recentlySavedItems.append(item); break;
+                case PlacesItem::SearchForType:     searchForItems.append(item); break;
                 case PlacesItem::DevicesType:
-                default:                               Q_ASSERT(false); break;
+                default:                            Q_ASSERT(false); break;
                 }
             }
         }
@@ -782,11 +786,11 @@ void PlacesItemModel::loadBookmarks()
             if (missingSystemBookmarks.contains(data.url)) {
                 PlacesItem* item = createSystemPlacesItem(data);
                 switch (item->groupType()) {
-                case PlacesItem::PlacesType:           placesItems.append(item); break;
-                case PlacesItem::RecentlyAccessedType: recentlyAccessedItems.append(item); break;
-                case PlacesItem::SearchForType:        searchForItems.append(item); break;
+                case PlacesItem::PlacesType:        placesItems.append(item); break;
+                case PlacesItem::RecentlySavedType: recentlySavedItems.append(item); break;
+                case PlacesItem::SearchForType:     searchForItems.append(item); break;
                 case PlacesItem::DevicesType:
-                default:                               Q_ASSERT(false); break;
+                default:                            Q_ASSERT(false); break;
                 }
             }
         }
@@ -800,7 +804,7 @@ void PlacesItemModel::loadBookmarks()
 
     QList<PlacesItem*> items;
     items.append(placesItems);
-    items.append(recentlyAccessedItems);
+    items.append(recentlySavedItems);
     items.append(searchForItems);
     items.append(devicesItems);
 
@@ -845,7 +849,7 @@ PlacesItem* PlacesItemModel::createSystemPlacesItem(const SystemBookmarkData& da
     const QString protocol = data.url.protocol();
     if (protocol == QLatin1String("timeline") || protocol == QLatin1String("search")) {
         // As long as the KFilePlacesView from kdelibs is available, the system-bookmarks
-        // for "Recently Accessed" and "Search For" should be a setting available only
+        // for "Recently Saved" and "Search For" should be a setting available only
         // in the Places Panel (see description of AppNamePrefix for more details).
         const QString appName = KGlobal::mainComponent().componentName() + AppNamePrefix;
         bookmark.setMetaDataItem("OnlyInApp", appName);
@@ -854,11 +858,11 @@ PlacesItem* PlacesItemModel::createSystemPlacesItem(const SystemBookmarkData& da
     PlacesItem* item = new PlacesItem(bookmark);
     item->setSystemItem(true);
 
-    // Create default view-properties for all "Search For" and "Recently Accessed" bookmarks
+    // Create default view-properties for all "Search For" and "Recently Saved" bookmarks
     // in case if the user has not already created custom view-properties for a corresponding
     // query yet.
     const bool createDefaultViewProperties = (item->groupType() == PlacesItem::SearchForType ||
-                                              item->groupType() == PlacesItem::RecentlyAccessedType) &&
+                                              item->groupType() == PlacesItem::RecentlySavedType) &&
                                               !GeneralSettings::self()->globalViewProps();
     if (createDefaultViewProperties) {
         ViewProperties props(convertedUrl(data.url));
index f19fa1e259f7e6fa203ffa8419f7c18038a77418..720e07ce37e91067b319c108580847b24aaf30af 100644 (file)
@@ -335,7 +335,7 @@ void PlacesPanel::slotItemDropEvent(int index, QGraphicsSceneDragDropEvent* even
 
     const PlacesItem* destItem = m_model->placesItem(index);
     const PlacesItem::GroupType group = destItem->groupType();
-    if (group == PlacesItem::SearchForType || group == PlacesItem::RecentlyAccessedType) {
+    if (group == PlacesItem::SearchForType || group == PlacesItem::RecentlySavedType) {
         return;
     }
 
index 1e5a33617ddb6e1895b5206e31932f2151f11ffd..f827503a2b592520d81f41dc58a9b8f690c8dc51 100644 (file)
@@ -42,7 +42,8 @@ TerminalPanel::TerminalPanel(QWidget* parent) :
     m_terminal(0),
     m_terminalWidget(0),
     m_konsolePart(0),
-    m_konsolePartCurrentDirectory()
+    m_konsolePartCurrentDirectory(),
+    m_sendCdToTerminalHistory()
 {
     m_layout = new QVBoxLayout(this);
     m_layout->setMargin(0);
@@ -161,7 +162,12 @@ void TerminalPanel::sendCdToTerminal(const QString& dir)
     }
 
     m_terminal->sendInput(" cd " + KShell::quoteArg(dir) + '\n');
-    m_konsolePartCurrentDirectory = dir;
+
+    // We want to ignore the currentDirectoryChanged(QString) signal, which we will receive after
+    // the directory change, because this directory change is not caused by a "cd" command that the
+    // user entered in the panel. Therefore, we have to remember 'dir'. Note that it could also be
+    // a symbolic link -> remember the 'canonical' path.
+    m_sendCdToTerminalHistory.enqueue(QDir(dir).canonicalPath());
 
     if (m_clearTerminal) {
         m_terminal->sendInput(" clear\n");
@@ -182,16 +188,17 @@ void TerminalPanel::slotMostLocalUrlResult(KJob* job)
 
 void TerminalPanel::slotKonsolePartCurrentDirectoryChanged(const QString& dir)
 {
-    m_konsolePartCurrentDirectory = dir;
-
-    // Only change the view URL if 'dir' is different from the current view URL.
-    // Note that the current view URL could also be a symbolic link to 'dir'
-    // -> use QDir::canonicalPath() to check that.
-    const KUrl oldUrl(url());
-    const KUrl newUrl(dir);
-    if (newUrl != oldUrl && dir != QDir(oldUrl.path()).canonicalPath()) {
-        emit changeUrl(newUrl);
+    m_konsolePartCurrentDirectory = QDir(dir).canonicalPath();
+
+    // Only emit a changeUrl signal if the directory change was caused by the user inside the
+    // terminal, and not by sendCdToTerminal(QString).
+    while (!m_sendCdToTerminalHistory.empty()) {
+        if (m_konsolePartCurrentDirectory == m_sendCdToTerminalHistory.dequeue()) {
+            return;
+        }
     }
+
+    emit changeUrl(dir);
 }
 
 #include "terminalpanel.moc"
index 374476e1c054c023737b7b3b4a159fbbad707b83..b65239baf3de021309120d5af63258fb5d55f96c 100644 (file)
@@ -22,6 +22,8 @@
 
 #include <panels/panel.h>
 
+#include <QQueue>
+
 class TerminalInterfaceV2;
 class QVBoxLayout;
 class QWidget;
@@ -82,6 +84,7 @@ private:
     QWidget* m_terminalWidget;
     KParts::ReadOnlyPart* m_konsolePart;
     QString m_konsolePartCurrentDirectory;
+    QQueue<QString> m_sendCdToTerminalHistory;
 };
 
 #endif // TERMINALPANEL_H
index 02b8815e07a8e7377991d600fc8ba41e4cc89f05..1de973bd5489704dd5cfcad1681f3c732502e8c5 100644 (file)
@@ -1167,6 +1167,14 @@ bool DolphinView::itemsExpandable() const
 
 void DolphinView::restoreState(QDataStream& stream)
 {
+    // Read the version number of the view state and check if the version is supported.
+    quint32 version = 0;
+    stream >> version;
+    if (version != 1) {
+        // The version of the view state isn't supported, we can't restore it.
+        return;
+    }
+
     // Restore the current item that had the keyboard focus
     stream >> m_currentItemUrl;
 
@@ -1181,6 +1189,8 @@ void DolphinView::restoreState(QDataStream& stream)
 
 void DolphinView::saveState(QDataStream& stream)
 {
+    stream << quint32(1); // View state version
+
     // Save the current item that has the keyboard focus
     const int currentIndex = m_container->controller()->selectionManager()->currentItem();
     if (currentIndex != -1) {