diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3eb529b0d9..62f8e8c4a2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -150,7 +150,9 @@ set(dolphin_SRCS dolphinmainwindow.cpp dolphinviewcontainer.cpp dolphincontextmenu.cpp + dolphintabbar.cpp dolphinrecenttabsmenu.cpp + dolphintabpage.cpp filterbar/filterbar.cpp main.cpp panels/information/filemetadataconfigurationdialog.cpp diff --git a/src/dolphin.appdata.xml b/src/dolphin.appdata.xml index 712376ae6b..c4bf53cd2a 100644 --- a/src/dolphin.appdata.xml +++ b/src/dolphin.appdata.xml @@ -4,39 +4,54 @@ CC0-1.0 GPL-2.0+ Dolphin + دولفين Dolphin Dolphin Dolphin Dolphin Dolphin Dolphin + Dolphin Dolphin Dolphin Dolphin Dolphin Dolphin + Dolphin Dolphin + Делфин + Dolphin + Делфин + Dolphin Dolphin Dolphin xxDolphinxx File Manager + مدير ملفات Gestor de fitxers Správce souborů Filhåndtering Dateiverwaltung Tiedostonhallinta Gerente de File + Failų tvarkyklė Dateipleger Bestandsbeheerder Zarządzanie plikami Gestor de Ficheiros Gerenciador de arquivos + Gestionar de fișiere Správca súborov + Менаџер фајлова + Menadžer fajlova + Менаџер фајлова + Menadžer fajlova Filhanterare Програма для керування файлами xxFile Managerxx

Dolphin is a lightweight file manager. It has been designed with ease of use and simplicity in mind, while still allowing flexibility and customisation. This means that you can do your file management exactly the way you want to do it.

+

دولفين هو مدير ملفات خفيف. صُمِّم دولفين مع أخذ سهولة الاستخدام والبساطة بعين الاعتبار، مع السماح بالمرونة والتخصيص. يعني هذا أنه يمكنك إدارة ملفاتك كما تريد تماماً.

El Dolphin és un gestor de fitxers lleuger. S'ha dissenyat pensant en facilitar el seu ús i que sigui simple, permetent la flexibilitat i la personalització. Això vol dir que podeu fer la gestió dels vostres fitxers de la manera exacta com ho vulgueu fer.

Dolphin er letvægtsfilhåndtering. Den er blevet designet med henblik på brugervenlighed og simpelhed, mens fleksibilitet og tilpasning stadig er muligt. Det betyder at du klare din filhåndtering nøjagtig på den måde du vil gøre det.

Dolphin on kevyt tiedostonhallinta. Se on suunniteltu helppokäyttöiseksi ja yksinkertaiseksi, mutta silti joustavaksi ja mukautettavaksi. Voit siis hallita tiedostojasi juuri niin kuin haluat.

@@ -47,22 +62,33 @@

O Dolphin é um gestor de ficheiros leve. Foi desenhado com a facilidade de uso e simplicidade em mente, permitindo à mesma a flexibilidade e personalização. Isto significa que poderá fazer a sua gestão de ficheiros exactamente da forma que deseja.

Dolphin é um gerenciador de arquivos leve e fácil de usar. Foi projetado para ser simples e ao mesmo tempo manter a flexibilidade e personalização. Isso significa que você poderá gerenciar seus arquivos da forma que desejar.

Dolphin je odľahčený správca súborov. Bol navrhnutý na jednoduché použitie a jednoduchosť, ale s možnosťami flexibility a prispôsobenia. To znamená, že môžete vykonávať správu súborov presne tak, ako chcete.

+

Делфин је лагани менаџер фајлова. Пројектован је да буде лак за употребу и једноставан, а да ипак омогућава флексибилност и прилагођавање. То значи да ће моћи да баратате фајловима тачно онако како бисте желели.

+

Dolphin je lagani menadžer fajlova. Projektovan je da bude lak za upotrebu i jednostavan, a da ipak omogućava fleksibilnost i prilagođavanje. To znači da će moći da baratate fajlovima tačno onako kako biste želeli.

+

Делфин је лагани менаџер фајлова. Пројектован је да буде лак за употребу и једноставан, а да ипак омогућава флексибилност и прилагођавање. То значи да ће моћи да баратате фајловима тачно онако како бисте желели.

+

Dolphin je lagani menadžer fajlova. Projektovan je da bude lak za upotrebu i jednostavan, a da ipak omogućava fleksibilnost i prilagođavanje. To znači da će moći da baratate fajlovima tačno onako kako biste želeli.

Dolphin är en lättviktig filhanterare. Den har konstruerats med användbarhet och enkelhet i åtanke, men ändå tillåta flexibilitet och anpassning. Det betyder att du kan hantera filer exakt på det sätt som du vill göra det.

Dolphin — невибаглива до ресурсів програма для керування файлами. Її створено простою у користуванні і гнучкою у налаштовуванні. Це означає, що ви можете зробити керування файлами саме таким, як вам потрібно.

xxDolphin is a lightweight file manager. It has been designed with ease of use and simplicity in mind, while still allowing flexibility and customisation. This means that you can do your file management exactly the way you want to do it.xx

Features:

+

المزايا:

Característiques:

Vlastnosti:

Funktioner:

Funktionen:

Ominaisuudet:

Characteristicas:

+

Galimybės

Markmalen:

Mogelijkheden:

Możliwości:

Características:

Funcionalidades:

+

Caracteristici:

Funkcie:

+

Могућности:

+

Mogućnosti:

+

Могућности:

+

Mogućnosti:

Funktioner:

Можливості:

xxFeatures:xx

@@ -77,10 +103,15 @@
  • Barra de navegação dos URL's, que lhe permite navegar rapidamente pela hierarquia de ficheiros e pastas.
  • Barra de navegação de URLs, permitindo-lhe navegar rapidamente pela hierarquia de arquivos e pastas.
  • Navigačná lišta pre URL, umožňujúca vám rýchlu navigáciu cez hierarchiu súborov a priečinkov.
  • +
  • Навигациона трака (или мрвице) за УРЛ‑ове, преко које се можете брзо кретати кроз стабло фајлова и фасцикли.
  • +
  • Navigaciona traka (ili mrvice) za URL‑ove, preko koje se možete brzo kretati kroz stablo fajlova i fascikli.
  • +
  • Навигациона трака (или мрвице) за УРЛ‑ове, преко које се можете брзо кретати кроз стабло фајлова и фасцикли.
  • +
  • Navigaciona traka (ili mrvice) za URL‑ove, preko koje se možete brzo kretati kroz stablo fajlova i fascikli.
  • Navigeringsrad (eller länkstig) för webbadresser, som låter dig snabbt navigera igenom hierarkin av filer och kataloger.
  • Панель навігації (звичайний режим і режим послідовної навігації) для адрес надає вам змогу швидко пересуватися ієрархією файлів та каталогів.
  • xxNavigation (or breadcrumb) bar for URLs, allowing you to quickly navigate through the hierarchy of files and folders.xx
  • Supports several different kinds of view styles and properties and allows you to configure the view exactly how you want it.
  • +
  • يدعم العديد من الأنواع المختلفة من الخصائص وأنماط العرض ويسمك لك بضبط العرض كما تريد تماماً.
  • Accepta diferents classes diverses d'estils de visualització i propietats i us permet configurar la visualització exactament com la vulgueu.
  • Understøtter flere forskellige slags visninger og egenskaber og lader dig konfigurere visningen nøjagtig som du vil have den.
  • Il supporta multe differente typos de stilos de vista e proprietates e il permitte te configurar le vista exactemente como tu vole.
  • @@ -90,10 +121,15 @@
  • Suposta diferentes tipos de vistas e propriedades e permite-lhe configurar cada vista exactamente como a deseja.
  • Suporte a diferentes tipos de visualização, permitindo-lhe configurar cada modo de exibição da forma que desejar.
  • Podporuje niekoľko rôznych typov štýlov zobrazenia a vlastností a umožňuje vám nastaviť pohľad presne tak, ako chcete.
  • +
  • Неколико начина приказа, са својствима које можете подесити по жељи.
  • +
  • Nekoliko načina prikaza, sa svojstvima koje možete podesiti po želji.
  • +
  • Неколико начина приказа, са својствима које можете подесити по жељи.
  • +
  • Nekoliko načina prikaza, sa svojstvima koje možete podesiti po želji.
  • Stöder flera olika sorters visningsstilar och egenskaper och låter dig anpassa visningen exakt som du vill ha den.
  • Підтримка декількох різних типів та параметрів перегляду надає вам змогу налаштувати перегляд каталогів саме так, як вам це потрібно.
  • xxSupports several different kinds of view styles and properties and allows you to configure the view exactly how you want it.xx
  • Split view, allowing you to easily copy or move files between locations.
  • +
  • العرض المقسوم، يسمح لك بنسخ ونقل الملفات بين مكانين بسهولة.
  • Divisió de visualització, permetent copiar o moure fitxers fàcilment entre les ubicacions.
  • Opdelt visning lader dig kopiere filer mellem placeringer på en nem måde.
  • Scinde vista, il permitte te copiar o mover facilemente files inter locationes.
  • @@ -103,10 +139,15 @@
  • Uma vista dividida, que lhe permite facilmente copiar ou mover os ficheiros entre locais.
  • Um modo de exibição dividido, permitindo-lhe copiar ou mover arquivos facilmente entre locais.
  • Rozdelený pohľad, umožňuje vám jednoducho kopírovať alebo presúvať súbory medzi umiestneniami.
  • +
  • Подељени приказ, за лако копирање и премештање фајлова између локација.
  • +
  • Podeljeni prikaz, za lako kopiranje i premeštanje fajlova između lokacija.
  • +
  • Подељени приказ, за лако копирање и премештање фајлова између локација.
  • +
  • Podeljeni prikaz, za lako kopiranje i premeštanje fajlova između lokacija.
  • Delad visning, som låter dig enkelt kopiera eller flytta filer mellan platser.
  • За допомогою режиму двопанельного розділеного перегляду ви зможе без проблем копіювати або пересувати файли між каталогами.
  • xxSplit view, allowing you to easily copy or move files between locations.xx
  • Additional information and shortcuts are available as dock-able panels, allowing you to move them around freely and display exactly what you want.
  • +
  • تتوفر معلومات واختصارات إضافية كألواح قابلة للتركيب، مما يسمح لك بنقلها بحريّة وعرضها بالضبط كما تريد.
  • Hi ha informació addicional i dreceres disponibles com a plafons acoblables, permetent moure'ls lliurement i mostrar exactament el què vulgueu.
  • Yderligere information og genveje er tilgængelige som dokbare paneler, som lader dig flytte dem frit omkring og vise nøjagtigt det du vil have.
  • 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.
  • @@ -116,20 +157,31 @@
  • Estão disponíveis informações e atalhos adicionais como painéis acopláveis, permitindo-lhe movê-los à vontade e apresentar como desejar.
  • As informações e atalhos adicionais estão disponíveis na forma de painéis acopláveis, permitindo-lhe movê-los à vontade e apresentar como desejar.
  • Dodatočné informácie a skratky sú dostupné ako dokovateľné panely, umožňujúce vám ich voľný presun a zobrazenie presne tak, ako chcete.
  • +
  • Допунски подаци и пречице доступни су као усидриви панели, које можете поставити где вам одговара и подесити да приказују тачно оно што желите.
  • +
  • Dopunski podaci i prečice dostupni su kao usidrivi paneli, koje možete postaviti gde vam odgovara i podesiti da prikazuju tačno ono što želite.
  • +
  • Допунски подаци и пречице доступни су као усидриви панели, које можете поставити где вам одговара и подесити да приказују тачно оно што желите.
  • +
  • Dopunski podaci i prečice dostupni su kao usidrivi paneli, koje možete postaviti gde vam odgovara i podesiti da prikazuju tačno ono što želite.
  • 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.
  • За допомогою бічних пересувних панелей ви зможете отримувати додаткову інформацію та пересуватися каталогами. Ви можете розташувати ці панелі так, як вам це зручно, і наказати програмі показувати на них саме те, що вам потрібно.
  • xxAdditional information and shortcuts are available as dock-able panels, allowing you to move them around freely and display exactly what you want.xx
  • Multiple tab support
  • +
  • دعم تعدّد الألسنة
  • Implementació de pestanyes múltiples
  • Understøttelse af flere faneblade
  • Useiden välilehtien tuki
  • Supporto de scheda multiple
  • +
  • Daugelio kortelių palaikymas
  • Ünnerstütten för Paneels
  • Ondersteuning voor meerdere tabbladen
  • Obsługa wielu kart
  • Suporte para várias páginas
  • Suporte a várias abas
  • +
  • Suport pentru file multiple
  • Podpora viacerých kariet
  • +
  • Вишеструки језичци.
  • +
  • Višestruki jezičci.
  • +
  • Вишеструки језичци.
  • +
  • Višestruki jezičci.
  • Stöd för flera flikar
  • Підтримка роботи з вкладками.
  • xxMultiple tab supportxx
  • @@ -143,6 +195,10 @@
  • As janelas informativas são apresentadas de forma não-intrusiva.
  • As janelas informativas são apresentadas de forma não-intrusiva.
  • Informačné dialógy sú zobrazené nevtieravým spôsobom.
  • +
  • Информативни дијалози који се ненаметљиво појављују.
  • +
  • Informativni dijalozi koji se nenametljivo pojavljuju.
  • +
  • Информативни дијалози који се ненаметљиво појављују.
  • +
  • Informativni dijalozi koji se nenametljivo pojavljuju.
  • Dialogrutor med information visas på ett diskret sätt.
  • Показ інформаційних панелей у зручний спосіб, що не заважає роботі.
  • xxInformational dialogues are displayed in an unobtrusive way.xx
  • @@ -156,11 +212,17 @@
  • Obsługa cofnij/ponów
  • Suporte para desfazer/refazer
  • Suporte para desfazer/refazer
  • +
  • Suport pentru desfacere/refacere
  • Podpora Späť/Znova
  • +
  • Опозивање и понављање.
  • +
  • Opozivanje i ponavljanje.
  • +
  • Опозивање и понављање.
  • +
  • Opozivanje i ponavljanje.
  • Stöd för ångra och gör om
  • Підтримка скасовування та повторення дій.
  • xxUndo/redo supportxx
  • Transparent network access through the KIO system.
  • +
  • اتصال شبكيّ مباشر باستخدام نظام KIO.
  • Accés transparent a la xarxa a través del sistema KIO.
  • Transparent netværksadgang igennem KIO-systemet
  • Accesso de rete transparente a transverso del systema KIO.
  • @@ -169,7 +231,12 @@
  • Przezroczysty dostęp do sieci przez system KIO.
  • Acesso transparente à rede através do sistema KIO.
  • Acesso transparente à rede através do sistema KIO.
  • +
  • Acces transparent la rețea prin sistemul KIO.
  • Transparentný prístup na sieť cez KIO systém.
  • +
  • Прозиран мрежни приступ кроз систем К‑У/И.
  • +
  • Proziran mrežni pristup kroz sistem K‑U/I.
  • +
  • Прозиран мрежни приступ кроз систем К‑У/И.
  • +
  • Proziran mrežni pristup kroz sistem K‑U/I.
  • Transparent nätverksåtkomst via I/O-slavsystemet.
  • Прозорий доступ до ресурсів у мережі за допомогою системи KIO.
  • xxTransparent network access through the KIO system.xx
  • diff --git a/src/dolphinapplication.cpp b/src/dolphinapplication.cpp index 200824e0c2..4576318bbd 100644 --- a/src/dolphinapplication.cpp +++ b/src/dolphinapplication.cpp @@ -35,7 +35,6 @@ DolphinApplication::DolphinApplication() : m_mainWindow = new DolphinMainWindow(); m_mainWindow->setAttribute(Qt::WA_DeleteOnClose); - m_mainWindow->show(); KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); @@ -72,6 +71,9 @@ DolphinApplication::DolphinApplication() : } else { m_mainWindow->openDirectories(urls); } + } else { + const KUrl homeUrl(GeneralSettings::homeUrl()); + m_mainWindow->openNewActivatedTab(homeUrl); } if (resetSplitSettings) { @@ -79,6 +81,8 @@ DolphinApplication::DolphinApplication() : } args->clear(); + + m_mainWindow->show(); } DolphinApplication::~DolphinApplication() diff --git a/src/dolphinmainwindow.cpp b/src/dolphinmainwindow.cpp index 75cc12f460..3b084ac8b4 100644 --- a/src/dolphinmainwindow.cpp +++ b/src/dolphinmainwindow.cpp @@ -26,7 +26,9 @@ #include "dolphincontextmenu.h" #include "dolphinnewfilemenu.h" #include "dolphinrecenttabsmenu.h" +#include "dolphintabbar.h" #include "dolphinviewcontainer.h" +#include "dolphintabpage.h" #include "panels/folders/folderspanel.h" #include "panels/places/placespanel.h" #include "panels/information/informationpanel.h" @@ -75,10 +77,8 @@ #include #include #include -#include #include #include -#include #include #include @@ -103,7 +103,7 @@ DolphinMainWindow::DolphinMainWindow() : m_tabBar(0), m_activeViewContainer(0), m_centralWidgetLayout(0), - m_tabIndex(0), + m_tabIndex(-1), m_viewTab(), m_actionHandler(0), m_remoteEncoding(0), @@ -114,10 +114,6 @@ DolphinMainWindow::DolphinMainWindow() : { setObjectName("Dolphin#"); - m_viewTab.append(ViewTab()); - ViewTab& viewTab = m_viewTab[m_tabIndex]; - viewTab.wasActive = true; // The first opened tab is automatically active - connect(&DolphinNewFileMenuObserver::instance(), &DolphinNewFileMenuObserver::errorMessage, this, &DolphinMainWindow::showErrorMessage); @@ -141,61 +137,41 @@ DolphinMainWindow::DolphinMainWindow() : setAcceptDrops(true); - viewTab.splitter = new QSplitter(this); - viewTab.splitter->setChildrenCollapsible(false); - setupActions(); - const KUrl homeUrl(generalSettings->homeUrl()); - setUrlAsCaption(homeUrl); m_actionHandler = new DolphinViewActionHandler(actionCollection(), this); connect(m_actionHandler, &DolphinViewActionHandler::actionBeingHandled, this, &DolphinMainWindow::clearStatusBar); connect(m_actionHandler, &DolphinViewActionHandler::createDirectory, this, &DolphinMainWindow::createDirectory); - viewTab.primaryView = createViewContainer(homeUrl, viewTab.splitter); - - m_activeViewContainer = viewTab.primaryView; - connectViewSignals(m_activeViewContainer); - DolphinView* view = m_activeViewContainer->view(); - m_activeViewContainer->show(); - m_actionHandler->setCurrentView(view); - m_remoteEncoding = new DolphinRemoteEncoding(this, m_actionHandler); connect(this, &DolphinMainWindow::urlChanged, m_remoteEncoding, &DolphinRemoteEncoding::slotAboutToOpenUrl); - m_tabBar = new KTabBar(this); - m_tabBar->setMovable(true); - m_tabBar->setTabsClosable(true); - connect(m_tabBar, &KTabBar::currentChanged, - this, &DolphinMainWindow::setActiveTab); - connect(m_tabBar, &KTabBar::tabCloseRequested, - this, static_cast(&DolphinMainWindow::closeTab)); - connect(m_tabBar, &KTabBar::contextMenu, - this, &DolphinMainWindow::openTabContextMenu); - connect(m_tabBar, &KTabBar::newTabRequest, - this, static_cast(&DolphinMainWindow::openNewTab)); - connect(m_tabBar, &KTabBar::testCanDecode, - this, &DolphinMainWindow::slotTestCanDecode); - connect(m_tabBar, &KTabBar::mouseMiddleClick, - this, static_cast(&DolphinMainWindow::closeTab)); - connect(m_tabBar, &KTabBar::tabMoved, - this, &DolphinMainWindow::slotTabMoved); - connect(m_tabBar, &KTabBar::receivedDropEvent, - this, &DolphinMainWindow::tabDropEvent); + m_tabBar = new DolphinTabBar(this); + connect(m_tabBar, SIGNAL(currentChanged(int)), + this, SLOT(setActiveTab(int))); + connect(m_tabBar, SIGNAL(tabCloseRequested(int)), + this, SLOT(closeTab(int))); + connect(m_tabBar, SIGNAL(openNewActivatedTab(int)), + this, SLOT(openNewActivatedTab(int))); + connect(m_tabBar, SIGNAL(tabMoved(int,int)), + this, SLOT(slotTabMoved(int,int))); + connect(m_tabBar, SIGNAL(tabDropEvent(int,QDropEvent*)), + this, SLOT(tabDropEvent(int,QDropEvent*))); + connect(m_tabBar, SIGNAL(tabDetachRequested(int)), + this, SLOT(detachTab(int))); 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); - m_centralWidgetLayout->addWidget(viewTab.splitter, 1); setCentralWidget(centralWidget); setupDockWidgets(); - emit urlChanged(homeUrl); setupGUI(Keys | Save | Create | ToolBar); stateChanged("new_file"); @@ -204,14 +180,6 @@ DolphinMainWindow::DolphinMainWindow() : connect(clipboard, &QClipboard::dataChanged, this, &DolphinMainWindow::updatePasteAction); - if (generalSettings->splitView()) { - toggleSplitView(); - } - updateEditActions(); - updatePasteAction(); - updateViewActions(); - updateGoActions(); - QAction* showFilterBarAction = actionCollection()->action("show_filter_bar"); showFilterBarAction->setChecked(generalSettings->filterBar()); @@ -235,37 +203,20 @@ DolphinMainWindow::~DolphinMainWindow() void DolphinMainWindow::openDirectories(const QList& dirs) { - if (dirs.isEmpty()) { - return; - } - - if (dirs.count() == 1) { - m_activeViewContainer->setUrl(dirs.first()); - return; - } - - const int oldOpenTabsCount = m_viewTab.count(); - 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::const_iterator it = dirs.constBegin(); while (it != dirs.constEnd()) { - openNewTab(*it); - ++it; - + const KUrl& primaryUrl = *(it++); if (hasSplitView && (it != dirs.constEnd())) { - const int tabIndex = m_viewTab.count() - 1; - m_viewTab[tabIndex].secondaryView->setUrl(*it); - ++it; + const KUrl& secondaryUrl = *(it++); + openNewTab(primaryUrl, secondaryUrl); + } else { + openNewTab(primaryUrl); } } - - // Remove the previously opened tabs - for (int i = 0; i < oldOpenTabsCount; ++i) { - closeTab(0); - } } void DolphinMainWindow::openFiles(const QList& files) @@ -290,14 +241,9 @@ void DolphinMainWindow::openFiles(const QList& files) // 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. - const int tabCount = m_viewTab.count(); - for (int i = 0; i < tabCount; ++i) { - m_viewTab[i].primaryView->view()->markUrlsAsSelected(files); - m_viewTab[i].primaryView->view()->markUrlAsCurrent(files.at(0)); - if (m_viewTab[i].secondaryView) { - m_viewTab[i].secondaryView->view()->markUrlsAsSelected(files); - m_viewTab[i].secondaryView->view()->markUrlAsCurrent(files.at(0)); - } + foreach (DolphinTabPage* tabPage, m_viewTab) { + tabPage->markUrlsAsSelected(files); + tabPage->markUrlAsCurrent(files.first()); } } @@ -352,11 +298,11 @@ void DolphinMainWindow::changeUrl(const KUrl& url) updateViewActions(); updateGoActions(); setUrlAsCaption(url); - if (m_viewTab.count() > 1) { - m_tabBar->setTabText(m_tabIndex, squeezedText(tabName(m_activeViewContainer->url()))); - } + const QString iconName = KIO::iconNameForUrl(url); m_tabBar->setTabIcon(m_tabIndex, QIcon::fromTheme(iconName)); + m_tabBar->setTabText(m_tabIndex, squeezedText(tabName(view->url()))); + emit urlChanged(url); } } @@ -379,11 +325,7 @@ void DolphinMainWindow::slotSelectionChanged(const KFileItemList& selection) { updateEditActions(); - Q_ASSERT(m_viewTab[m_tabIndex].primaryView); - int selectedUrlsCount = m_viewTab[m_tabIndex].primaryView->view()->selectedItemsCount(); - if (m_viewTab[m_tabIndex].secondaryView) { - selectedUrlsCount += m_viewTab[m_tabIndex].secondaryView->view()->selectedItemsCount(); - } + const int selectedUrlsCount = m_viewTab.at(m_tabIndex)->selectedItemsCount(); QAction* compareFilesAction = actionCollection()->action("compare_files"); if (selectedUrlsCount == 2) { @@ -448,41 +390,41 @@ void DolphinMainWindow::openNewTab() } } -void DolphinMainWindow::openNewTab(const KUrl& url) +void DolphinMainWindow::openNewTab(const KUrl& primaryUrl, const KUrl& secondaryUrl) { QWidget* focusWidget = QApplication::focusWidget(); - if (m_viewTab.count() == 1) { - // Only one view is open currently and hence no tab is shown at - // all. Before creating a tab for 'url', provide a tab for the current URL. - const KUrl currentUrl = m_activeViewContainer->url(); - m_tabBar->addTab(QIcon::fromTheme(KIO::iconNameForUrl(currentUrl)), - squeezedText(tabName(currentUrl))); - m_tabBar->blockSignals(false); + 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("placesDock"); + const bool placesSelectorVisible = !placesDock || !placesDock->isVisible(); + tabPage->setPlacesSelectorVisible(placesSelectorVisible); + + DolphinViewContainer* primaryContainer = tabPage->primaryViewContainer(); + connectViewSignals(primaryContainer); + + if (tabPage->splitViewEnabled()) { + DolphinViewContainer* secondaryContainer = tabPage->secondaryViewContainer(); + connectViewSignals(secondaryContainer); } - m_tabBar->addTab(QIcon::fromTheme(KIO::iconNameForUrl(url)), - squeezedText(tabName(url))); + tabPage->hide(); - ViewTab viewTab; - viewTab.splitter = new QSplitter(this); - viewTab.splitter->setChildrenCollapsible(false); - viewTab.primaryView = createViewContainer(url, viewTab.splitter); - viewTab.primaryView->setActive(false); - connectViewSignals(viewTab.primaryView); + m_tabBar->addTab(QIcon::fromTheme(KIO::iconNameForUrl(primaryUrl)), + squeezedText(tabName(primaryUrl))); - m_viewTab.append(viewTab); - - actionCollection()->action("close_tab")->setEnabled(true); - actionCollection()->action("activate_prev_tab")->setEnabled(true); - actionCollection()->action("activate_next_tab")->setEnabled(true); - - // Provide a split view, if the startup settings are set this way - if (GeneralSettings::splitView()) { - const int newTabIndex = m_viewTab.count() - 1; - createSecondaryView(newTabIndex); - m_viewTab[newTabIndex].secondaryView->setActive(true); - m_viewTab[newTabIndex].isPrimaryViewActive = false; + 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) { @@ -492,17 +434,24 @@ void DolphinMainWindow::openNewTab(const KUrl& url) } } -void DolphinMainWindow::openNewActivatedTab(const KUrl& url) +void DolphinMainWindow::openNewActivatedTab(const KUrl& primaryUrl, const KUrl& secondaryUrl) { - openNewTab(url); - m_tabBar->setCurrentIndex(m_viewTab.count() - 1); + openNewTab(primaryUrl, secondaryUrl); + setActiveTab(m_viewTab.count() - 1); +} + +void DolphinMainWindow::openNewActivatedTab(int index) +{ + Q_ASSERT(index >= 0); + const DolphinTabPage* tabPage = m_viewTab.at(index); + openNewActivatedTab(tabPage->activeViewContainer()->url()); } void DolphinMainWindow::activateNextTab() { if (m_viewTab.count() >= 2) { const int tabIndex = (m_tabBar->currentIndex() + 1) % m_tabBar->count(); - m_tabBar->setCurrentIndex(tabIndex); + setActiveTab(tabIndex); } } @@ -513,7 +462,7 @@ void DolphinMainWindow::activatePrevTab() if (tabIndex == -1) { tabIndex = m_tabBar->count() - 1; } - m_tabBar->setCurrentIndex(tabIndex); + setActiveTab(tabIndex); } } @@ -549,24 +498,16 @@ void DolphinMainWindow::openInNewWindow() } } -void DolphinMainWindow::toggleActiveView() -{ - if (!m_viewTab[m_tabIndex].secondaryView) { - // only one view is available - return; - } - - Q_ASSERT(m_activeViewContainer); - Q_ASSERT(m_viewTab[m_tabIndex].primaryView); - - DolphinViewContainer* left = m_viewTab[m_tabIndex].primaryView; - DolphinViewContainer* right = m_viewTab[m_tabIndex].secondaryView; - setActiveViewContainer(m_activeViewContainer == right ? left : right); -} - 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(); } @@ -638,17 +579,8 @@ void DolphinMainWindow::saveProperties(KConfigGroup& group) group.writeEntry("Active Tab Index", m_tabBar->currentIndex()); for (int i = 0; i < tabCount; ++i) { - const DolphinViewContainer* cont = m_viewTab[i].primaryView; - group.writeEntry(tabProperty("Primary URL", i), cont->url().url()); - group.writeEntry(tabProperty("Primary Editable", i), - cont->urlNavigator()->isUrlEditable()); - - cont = m_viewTab[i].secondaryView; - if (cont) { - group.writeEntry(tabProperty("Secondary URL", i), cont->url().url()); - group.writeEntry(tabProperty("Secondary Editable", i), - cont->urlNavigator()->isUrlEditable()); - } + const DolphinTabPage* tabPage = m_viewTab.at(i); + group.writeEntry("Tab " % QString::number(i), tabPage->saveState()); } } @@ -656,38 +588,9 @@ void DolphinMainWindow::readProperties(const KConfigGroup& group) { const int tabCount = group.readEntry("Tab Count", 1); for (int i = 0; i < tabCount; ++i) { - DolphinViewContainer* cont = m_viewTab[i].primaryView; - - cont->setUrl(group.readEntry(tabProperty("Primary URL", i))); - const bool editable = group.readEntry(tabProperty("Primary Editable", i), false); - cont->urlNavigator()->setUrlEditable(editable); - - cont = m_viewTab[i].secondaryView; - const QString secondaryUrl = group.readEntry(tabProperty("Secondary URL", i)); - if (!secondaryUrl.isEmpty()) { - if (!cont) { - // a secondary view should be shown, but no one is available - // currently -> create a new view - toggleSplitView(); - cont = m_viewTab[i].secondaryView; - Q_ASSERT(cont); - } - - // The right view must be activated before the URL is set. Changing - // the URL in the right view will emit the right URL navigator's - // urlChanged(KUrl) signal, which is connected to the changeUrl(KUrl) - // slot. That slot will change the URL in the left view if it is still - // active. See https://bugs.kde.org/show_bug.cgi?id=330047. - setActiveViewContainer(cont); - - cont->setUrl(secondaryUrl); - const bool editable = group.readEntry(tabProperty("Secondary Editable", i), false); - cont->urlNavigator()->setUrlEditable(editable); - } else if (cont) { - // no secondary view should be shown, but the default setting shows - // one already -> close the view - toggleSplitView(); - } + 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) { @@ -800,28 +703,11 @@ void DolphinMainWindow::invertSelection() void DolphinMainWindow::toggleSplitView() { - if (!m_viewTab[m_tabIndex].secondaryView) { - createSecondaryView(m_tabIndex); - setActiveViewContainer(m_viewTab[m_tabIndex].secondaryView); - } else if (m_activeViewContainer == m_viewTab[m_tabIndex].secondaryView) { - // remove secondary view - m_viewTab[m_tabIndex].secondaryView->close(); - m_viewTab[m_tabIndex].secondaryView->deleteLater(); - m_viewTab[m_tabIndex].secondaryView = 0; + DolphinTabPage* tabPage = m_viewTab.at(m_tabIndex); + tabPage->setSplitViewEnabled(!tabPage->splitViewEnabled()); - setActiveViewContainer(m_viewTab[m_tabIndex].primaryView); - } else { - // The primary view is active and should be closed. Hence from a users point of view - // the content of the secondary view should be moved to the primary view. - // From an implementation point of view it is more efficient to close - // the primary view and exchange the internal pointers afterwards. - - m_viewTab[m_tabIndex].primaryView->close(); - m_viewTab[m_tabIndex].primaryView->deleteLater(); - m_viewTab[m_tabIndex].primaryView = m_viewTab[m_tabIndex].secondaryView; - m_viewTab[m_tabIndex].secondaryView = 0; - - setActiveViewContainer(m_viewTab[m_tabIndex].primaryView); + if (tabPage->splitViewEnabled()) { + connectViewSignals(tabPage->secondaryViewContainer()); } updateViewActions(); @@ -888,14 +774,8 @@ void DolphinMainWindow::togglePanelLockState() void DolphinMainWindow::slotPlacesPanelVisibilityChanged(bool visible) { - const int tabCount = m_viewTab.count(); - for (int i = 0; i < tabCount; ++i) { - ViewTab& tab = m_viewTab[i]; - Q_ASSERT(tab.primaryView); - tab.primaryView->urlNavigator()->setPlacesSelectorVisible(!visible); - if (tab.secondaryView) { - tab.secondaryView->urlNavigator()->setPlacesSelectorVisible(!visible); - } + foreach (DolphinTabPage* tabPage, m_viewTab) { + tabPage->setPlacesSelectorVisible(visible); } } @@ -964,15 +844,7 @@ void DolphinMainWindow::goHome(Qt::MouseButtons buttons) void DolphinMainWindow::compareFiles() { - const DolphinViewContainer* primaryViewContainer = m_viewTab[m_tabIndex].primaryView; - Q_ASSERT(primaryViewContainer); - KFileItemList items = primaryViewContainer->view()->selectedItems(); - - const DolphinViewContainer* secondaryViewContainer = m_viewTab[m_tabIndex].secondaryView; - if (secondaryViewContainer) { - items.append(secondaryViewContainer->view()->selectedItems()); - } - + const KFileItemList items = m_viewTab.at(m_tabIndex)->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 @@ -1042,42 +914,23 @@ void DolphinMainWindow::setActiveTab(int index) return; } + m_tabBar->setCurrentIndex(index); + // hide current tab content - ViewTab& hiddenTab = m_viewTab[m_tabIndex]; - hiddenTab.isPrimaryViewActive = hiddenTab.primaryView->isActive(); - hiddenTab.primaryView->setActive(false); - if (hiddenTab.secondaryView) { - hiddenTab.secondaryView->setActive(false); + if (m_tabIndex >= 0) { + DolphinTabPage* hiddenTabPage = m_viewTab.at(m_tabIndex); + hiddenTabPage->hide(); + m_centralWidgetLayout->removeWidget(hiddenTabPage); } - QSplitter* splitter = m_viewTab[m_tabIndex].splitter; - splitter->hide(); - m_centralWidgetLayout->removeWidget(splitter); // show active tab content m_tabIndex = index; - ViewTab& viewTab = m_viewTab[index]; - m_centralWidgetLayout->addWidget(viewTab.splitter, 1); - viewTab.primaryView->show(); - if (viewTab.secondaryView) { - viewTab.secondaryView->show(); - } - viewTab.splitter->show(); + DolphinTabPage* tabPage = m_viewTab.at(index); + m_centralWidgetLayout->addWidget(tabPage, 1); + tabPage->show(); - if (!viewTab.wasActive) { - viewTab.wasActive = true; - - // If the tab has not been activated yet the size of the KItemListView is - // undefined and results in an unwanted animation. To prevent this a - // reloading of the directory gets triggered. - viewTab.primaryView->view()->reload(); - if (viewTab.secondaryView) { - viewTab.secondaryView->view()->reload(); - } - } - - setActiveViewContainer(viewTab.isPrimaryViewActive ? viewTab.primaryView : - viewTab.secondaryView); + setActiveViewContainer(tabPage->activeViewContainer()); } void DolphinMainWindow::closeTab() @@ -1100,17 +953,18 @@ void DolphinMainWindow::closeTab(int index) m_tabBar->setCurrentIndex((index > 0) ? index - 1 : 1); } - const KUrl primaryUrl(m_viewTab[index].primaryView->url()); - const KUrl secondaryUrl(m_viewTab[index].secondaryView ? m_viewTab[index].secondaryView->url() : KUrl()); - emit rememberClosedTab(primaryUrl, secondaryUrl); + 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[index].primaryView->deleteLater(); - if (m_viewTab[index].secondaryView) { - m_viewTab[index].secondaryView->deleteLater(); - } - m_viewTab[index].splitter->deleteLater(); - m_viewTab.erase(m_viewTab.begin() + index); + m_viewTab.removeAt(index); + tabPage->deleteLater(); m_tabBar->blockSignals(true); m_tabBar->removeTab(index); @@ -1122,64 +976,33 @@ void DolphinMainWindow::closeTab(int index) // if only one tab is left, also remove the tab entry so that // closing the last tab is not possible - if (m_viewTab.count() == 1) { - m_tabBar->removeTab(0); + 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) +void DolphinMainWindow::detachTab(int index) { - KMenu menu(this); + Q_ASSERT(index >= 0); - QAction* newTabAction = menu.addAction(QIcon::fromTheme("tab-new"), i18nc("@action:inmenu", "New Tab")); - newTabAction->setShortcut(actionCollection()->action("new_tab")->shortcut()); + const QString separator(QLatin1Char(' ')); + QString command = QLatin1String("dolphin"); - QAction* detachTabAction = menu.addAction(QIcon::fromTheme("tab-detach"), i18nc("@action:inmenu", "Detach Tab")); - - QAction* closeOtherTabsAction = menu.addAction(QIcon::fromTheme("tab-close-other"), i18nc("@action:inmenu", "Close Other Tabs")); - - QAction* closeTabAction = menu.addAction(QIcon::fromTheme("tab-close"), i18nc("@action:inmenu", "Close Tab")); - closeTabAction->setShortcut(actionCollection()->action("close_tab")->shortcut()); - QAction* selectedAction = menu.exec(pos); - if (selectedAction == newTabAction) { - const ViewTab& tab = m_viewTab[index]; - Q_ASSERT(tab.primaryView); - const KUrl url = tab.secondaryView && tab.secondaryView->isActive() ? - tab.secondaryView->url() : tab.primaryView->url(); - openNewTab(url); - m_tabBar->setCurrentIndex(m_viewTab.count() - 1); - } else if (selectedAction == detachTabAction) { - const QString separator(QLatin1Char(' ')); - QString command = QLatin1String("dolphin"); - - const ViewTab& tab = m_viewTab[index]; - Q_ASSERT(tab.primaryView); - - command += separator + tab.primaryView->url().url(); - if (tab.secondaryView) { - command += separator + tab.secondaryView->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); + 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); } void DolphinMainWindow::slotTabMoved(int from, int to) @@ -1188,11 +1011,6 @@ void DolphinMainWindow::slotTabMoved(int from, int 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; @@ -1230,9 +1048,8 @@ void DolphinMainWindow::tabDropEvent(int tab, QDropEvent* event) { const KUrl::List urls = KUrl::List::fromMimeData(event->mimeData()); if (!urls.isEmpty() && tab != -1) { - const ViewTab& viewTab = m_viewTab[tab]; - const DolphinView* view = viewTab.isPrimaryViewActive ? viewTab.primaryView->view() - : viewTab.secondaryView->view(); + const DolphinView* view = m_viewTab.at(tab)->activeViewContainer()->view(); + QString error; DragAndDropHelper::dropUrls(view->rootItem(), view->url(), event, error); if (!error.isEmpty()) { @@ -1401,37 +1218,22 @@ void DolphinMainWindow::slotPlaceActivated(const KUrl& url) } } -void DolphinMainWindow::restoreClosedTab(const KUrl& primaryUrl, const KUrl& secondaryUrl) +void DolphinMainWindow::activeViewChanged() { - openNewActivatedTab(primaryUrl); - - if (!secondaryUrl.isEmpty() && secondaryUrl.isValid()) { - const int index = m_tabBar->currentIndex(); - createSecondaryView(index); - setActiveViewContainer(m_viewTab[index].secondaryView); - m_viewTab[index].secondaryView->setUrl(secondaryUrl); - } + const DolphinTabPage* tabPage = m_viewTab.at(m_tabIndex); + setActiveViewContainer(tabPage->activeViewContainer()); } void DolphinMainWindow::setActiveViewContainer(DolphinViewContainer* viewContainer) { Q_ASSERT(viewContainer); - Q_ASSERT((viewContainer == m_viewTab[m_tabIndex].primaryView) || - (viewContainer == m_viewTab[m_tabIndex].secondaryView)); + Q_ASSERT((viewContainer == m_viewTab.at(m_tabIndex)->primaryViewContainer()) || + (viewContainer == m_viewTab.at(m_tabIndex)->secondaryViewContainer())); if (m_activeViewContainer == viewContainer) { return; } - m_activeViewContainer->setActive(false); m_activeViewContainer = viewContainer; - - // Activating the view container might trigger a recursive setActiveViewContainer() call - // inside DolphinMainWindow::toggleActiveView() when having a split view. Temporary - // disconnect the activated() signal in this case: - disconnect(m_activeViewContainer->view(), &DolphinView::activated, this, &DolphinMainWindow::toggleActiveView); - m_activeViewContainer->setActive(true); - connect(m_activeViewContainer->view(), &DolphinView::activated, this, &DolphinMainWindow::toggleActiveView); - m_actionHandler->setCurrentView(viewContainer->view()); updateHistory(); @@ -1442,26 +1244,12 @@ void DolphinMainWindow::setActiveViewContainer(DolphinViewContainer* viewContain const KUrl url = m_activeViewContainer->url(); setUrlAsCaption(url); - if (m_viewTab.count() > 1) { - m_tabBar->setTabText(m_tabIndex, tabName(url)); - m_tabBar->setTabIcon(m_tabIndex, QIcon::fromTheme(KIO::iconNameForUrl(url))); - } + m_tabBar->setTabText(m_tabIndex, squeezedText(tabName(url))); + m_tabBar->setTabIcon(m_tabIndex, QIcon::fromTheme(KIO::iconNameForUrl(url))); emit urlChanged(url); } -DolphinViewContainer* DolphinMainWindow::createViewContainer(const KUrl& url, QWidget* parent) -{ - DolphinViewContainer* container = new DolphinViewContainer(url, parent); - - // The places-selector from the URL navigator should only be shown - // if the places dock is invisible - QDockWidget* placesDock = findChild("placesDock"); - container->urlNavigator()->setPlacesSelectorVisible(!placesDock || !placesDock->isVisible()); - - return container; -} - void DolphinMainWindow::setupActions() { // setup 'File' menu @@ -1529,7 +1317,6 @@ void DolphinMainWindow::setupActions() QAction* split = actionCollection()->addAction("split_view"); split->setShortcut(Qt::Key_F3); - updateSplitAction(); connect(split, &QAction::triggered, this, &DolphinMainWindow::toggleSplitView); QAction* reload = actionCollection()->addAction("reload"); @@ -1565,7 +1352,7 @@ void DolphinMainWindow::setupActions() connect(this, SIGNAL(rememberClosedTab(KUrl,KUrl)), recentTabsMenu, SLOT(rememberClosedTab(KUrl,KUrl))); connect(recentTabsMenu, SIGNAL(restoreClosedTab(KUrl,KUrl)), - this, SLOT(restoreClosedTab(KUrl,KUrl))); + this, SLOT(openNewActivatedTab(KUrl,KUrl))); KStandardAction::forward(this, SLOT(goForward()), actionCollection()); KStandardAction::up(this, SLOT(goUp()), actionCollection()); @@ -1686,8 +1473,8 @@ void DolphinMainWindow::setupDockWidgets() foldersPanel, &FoldersPanel::setUrl); connect(foldersPanel, &FoldersPanel::folderActivated, this, &DolphinMainWindow::changeUrl); - connect(foldersPanel, &FoldersPanel::folderMiddleClicked, - this, static_cast(&DolphinMainWindow::openNewTab)); + connect(foldersPanel, SIGNAL(folderMiddleClicked(KUrl)), + this, SLOT(openNewTab(KUrl))); connect(foldersPanel, &FoldersPanel::errorMessage, this, &DolphinMainWindow::slotPanelErrorMessage); @@ -1738,8 +1525,8 @@ void DolphinMainWindow::setupDockWidgets() addDockWidget(Qt::LeftDockWidgetArea, placesDock); connect(placesPanel, &PlacesPanel::placeActivated, this, &DolphinMainWindow::slotPlaceActivated); - connect(placesPanel, &PlacesPanel::placeMiddleClicked, - this, static_cast(&DolphinMainWindow::openNewTab)); + connect(placesPanel, SIGNAL(placeMiddleClicked(KUrl)), + this, SLOT(openNewTab(KUrl))); connect(placesPanel, &PlacesPanel::errorMessage, this, &DolphinMainWindow::slotPanelErrorMessage); connect(this, &DolphinMainWindow::urlChanged, @@ -1871,33 +1658,16 @@ bool DolphinMainWindow::addActionToMenu(QAction* action, KMenu* menu) void DolphinMainWindow::refreshViews() { - Q_ASSERT(m_viewTab[m_tabIndex].primaryView); - - // remember the current active view, as because of - // the refreshing the active view might change to - // the secondary view - DolphinViewContainer* activeViewContainer = m_activeViewContainer; - - const int tabCount = m_viewTab.count(); - for (int i = 0; i < tabCount; ++i) { - m_viewTab[i].primaryView->readSettings(); - if (m_viewTab[i].secondaryView) { - m_viewTab[i].secondaryView->readSettings(); - } + foreach (DolphinTabPage* tabPage, m_viewTab) { + tabPage->refreshViews(); } - setActiveViewContainer(activeViewContainer); - 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(); - const ViewTab& activeTab = m_viewTab[m_tabIndex]; - const bool toggle = ( splitView && !activeTab.secondaryView) - || (!splitView && activeTab.secondaryView); - if (toggle) { - toggleSplitView(); - } + m_viewTab.at(m_tabIndex)->setSplitViewEnabled(splitView); + updateSplitAction(); } emit settingsChanged(); @@ -1915,15 +1685,13 @@ void DolphinMainWindow::connectViewSignals(DolphinViewContainer* container) connect(container, &DolphinViewContainer::writeStateChanged, this, &DolphinMainWindow::slotWriteStateChanged); - DolphinView* view = container->view(); + const DolphinView* view = container->view(); connect(view, &DolphinView::selectionChanged, this, &DolphinMainWindow::slotSelectionChanged); connect(view, &DolphinView::requestItemInfo, this, &DolphinMainWindow::slotRequestItemInfo); - connect(view, &DolphinView::activated, - this, &DolphinMainWindow::toggleActiveView); - connect(view, &DolphinView::tabRequested, - this, static_cast(&DolphinMainWindow::openNewTab)); + connect(view, SIGNAL(tabRequested(KUrl)), + this, SLOT(openNewTab(KUrl))); connect(view, &DolphinView::requestContextMenu, this, &DolphinMainWindow::openContextMenu); connect(view, &DolphinView::directoryLoadingStarted, @@ -1942,22 +1710,23 @@ void DolphinMainWindow::connectViewSignals(DolphinViewContainer* container) this, &DolphinMainWindow::updateHistory); connect(navigator, &KUrlNavigator::editableStateChanged, this, &DolphinMainWindow::slotEditableStateChanged); - connect(navigator, &KUrlNavigator::tabRequested, - this, static_cast(&DolphinMainWindow::openNewTab)); + connect(navigator, SIGNAL(tabRequested(KUrl)), + this, SLOT(openNewTab(KUrl))); } void DolphinMainWindow::updateSplitAction() { QAction* splitAction = actionCollection()->action("split_view"); - if (m_viewTab[m_tabIndex].secondaryView) { - if (m_activeViewContainer == m_viewTab[m_tabIndex].secondaryView) { - splitAction->setText(i18nc("@action:intoolbar Close right view", "Close")); - splitAction->setToolTip(i18nc("@info", "Close right view")); - splitAction->setIcon(QIcon::fromTheme("view-right-close")); - } else { + const DolphinTabPage* tabPage = m_viewTab.at(m_tabIndex); + if (tabPage->splitViewEnabled()) { + if (tabPage->primaryViewActive()) { splitAction->setText(i18nc("@action:intoolbar Close left view", "Close")); splitAction->setToolTip(i18nc("@info", "Close left view")); - splitAction->setIcon(QIcon::fromTheme("view-left-close")); + splitAction->setIcon(KIcon("view-left-close")); + } else { + splitAction->setText(i18nc("@action:intoolbar Close right view", "Close")); + splitAction->setToolTip(i18nc("@info", "Close right view")); + splitAction->setIcon(KIcon("view-right-close")); } } else { splitAction->setText(i18nc("@action:intoolbar Split view", "Split")); @@ -1997,35 +1766,6 @@ bool DolphinMainWindow::isKompareInstalled() const return installed; } -void DolphinMainWindow::createSecondaryView(int tabIndex) -{ - ViewTab& viewTab = m_viewTab[tabIndex]; - - QSplitter* splitter = viewTab.splitter; - const int newWidth = (viewTab.primaryView->width() - splitter->handleWidth()) / 2; - - const DolphinView* view = viewTab.primaryView->view(); - // The final parent of the new view container will be set by adding it - // to the splitter. However, we must make sure that the DolphinMainWindow - // is a parent of the view container already when it is constructed - // because this enables the container's KFileItemModel to assign its - // dir lister to the right main window. The dir lister can then cache - // authentication data. - viewTab.secondaryView = createViewContainer(view->url(), this); - splitter->addWidget(viewTab.secondaryView); - splitter->setSizes(QList() << newWidth << newWidth); - - connectViewSignals(viewTab.secondaryView); - viewTab.secondaryView->setActive(false); - viewTab.secondaryView->resize(newWidth, viewTab.primaryView->height()); - viewTab.secondaryView->show(); -} - -QString DolphinMainWindow::tabProperty(const QString& property, int tabIndex) const -{ - return "Tab " + QString::number(tabIndex) + ' ' + property; -} - void DolphinMainWindow::setUrlAsCaption(const KUrl& url) { QString caption; diff --git a/src/dolphinmainwindow.h b/src/dolphinmainwindow.h index 4fe13d29fd..4816837fc5 100644 --- a/src/dolphinmainwindow.h +++ b/src/dolphinmainwindow.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -38,15 +39,15 @@ typedef KIO::FileUndoManager::CommandType CommandType; class DolphinViewActionHandler; class DolphinApplication; class DolphinSettingsDialog; +class DolphinTabBar; class DolphinViewContainer; class DolphinRemoteEncoding; +class DolphinTabPage; class KAction; class KFileItem; class KFileItemList; class KJob; class KNewFileMenu; -class KTabBar; -class KUrl; class QSplitter; class QToolButton; class QVBoxLayout; @@ -89,13 +90,6 @@ public: */ void openFiles(const QList& files); - /** - * Returns true, if the main window contains two instances - * of a view container. The active view constainer can be - * accessed by DolphinMainWindow::activeViewContainer(). - */ - bool isSplit() const; - /** * Returns the 'Create New...' sub menu which also can be shared * with other menus (e. g. a context menu). @@ -354,15 +348,22 @@ private slots: void openNewTab(); /** - * Opens a new tab in the background showing the URL \a url. + * Opens a new tab in the background showing the URL \a primaryUrl and the + * optional URL \a secondaryUrl. */ - void openNewTab(const KUrl& url); + void openNewTab(const KUrl& primaryUrl, const KUrl& secondaryUrl = KUrl()); /** - * Opens a new tab showing the URL \a url and activates - * the tab. + * Opens a new tab showing the URL \a primaryUrl and the optional URL + * \a secondaryUrl and activates the tab. */ - void openNewActivatedTab(const KUrl& url); + void openNewActivatedTab(const KUrl& primaryUrl, const KUrl& secondaryUrl = KUrl()); + + /** + * Opens a new tab showing the url from tab at the given \a index and + * activates the tab. + */ + void openNewActivatedTab(int index); void activateNextTab(); @@ -378,9 +379,6 @@ private slots: */ void openInNewWindow(); - /** Toggles the active view if two views are shown within the main window. */ - void toggleActiveView(); - /** * Indicates in the statusbar that the execution of the command \a command * has been finished. @@ -402,10 +400,10 @@ private slots: void closeTab(int index); /** - * Opens a context menu for the tab with the index \a index - * on the position \a pos. + * Opens the tab with the index \a index in a new Dolphin instance and closes + * this tab. */ - void openTabContextMenu(int index, const QPoint& pos); + void detachTab(int index); /** * Is connected to the QTabBar signal tabMoved(int from, int to). @@ -414,12 +412,6 @@ private slots: */ 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. @@ -475,11 +467,7 @@ private slots: */ void slotPlaceActivated(const KUrl& url); - /** - * Is called when the user wants to reopen a previously closed \a tab from - * the recent tabs menu. - */ - void restoreClosedTab(const KUrl& primaryUrl, const KUrl& secondaryUrl); + void activeViewChanged(); private: /** @@ -490,11 +478,6 @@ private: */ void setActiveViewContainer(DolphinViewContainer* view); - /** - * Creates a view container and does a default initialization. - */ - DolphinViewContainer* createViewContainer(const KUrl& url, QWidget* parent); - void setupActions(); void setupDockWidgets(); void updateEditActions(); @@ -530,17 +513,9 @@ private: /** Returns the name of the tab for the URL \a url. */ QString tabName(const KUrl& url) const; + bool isKompareInstalled() const; - void createSecondaryView(int tabIndex); - - /** - * Helper method for saveProperties() and readProperties(): Returns - * the property string for a tab with the index \a tabIndex and - * the property \a property. - */ - QString tabProperty(const QString& property, int tabIndex) const; - /** * Sets the window caption to url.fileName() if this is non-empty, * "/" if the URL is "file:///", and url.protocol() otherwise. @@ -575,23 +550,13 @@ private: }; KNewFileMenu* m_newFileMenu; - KTabBar* m_tabBar; + DolphinTabBar* m_tabBar; DolphinViewContainer* m_activeViewContainer; QVBoxLayout* m_centralWidgetLayout; int m_id; - // Members for the tab-handling: - struct ViewTab - { - ViewTab() : isPrimaryViewActive(true), wasActive(false), primaryView(0), secondaryView(0), splitter(0) {} - bool isPrimaryViewActive; - bool wasActive; - DolphinViewContainer* primaryView; - DolphinViewContainer* secondaryView; - QSplitter* splitter; - }; int m_tabIndex; - QList m_viewTab; + QList m_viewTab; DolphinViewActionHandler* m_actionHandler; DolphinRemoteEncoding* m_remoteEncoding; @@ -609,11 +574,6 @@ inline DolphinViewContainer* DolphinMainWindow::activeViewContainer() const return m_activeViewContainer; } -inline bool DolphinMainWindow::isSplit() const -{ - return m_viewTab[m_tabIndex].secondaryView != 0; -} - inline KNewFileMenu* DolphinMainWindow::newFileMenu() const { return m_newFileMenu; diff --git a/src/dolphintabbar.cpp b/src/dolphintabbar.cpp new file mode 100644 index 0000000000..78bd5edcb9 --- /dev/null +++ b/src/dolphintabbar.cpp @@ -0,0 +1,174 @@ +/*************************************************************************** + * Copyright (C) 2014 by Emmanuel Pescosta * + * * + * 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 +#include +#include +#include +#include +#include + +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 index 0000000000..d2b2e9e575 --- /dev/null +++ b/src/dolphintabbar.h @@ -0,0 +1,65 @@ +/*************************************************************************** + * Copyright (C) 2014 by Emmanuel Pescosta * + * * + * 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 + +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 diff --git a/src/dolphintabpage.cpp b/src/dolphintabpage.cpp new file mode 100644 index 0000000000..c8e4263359 --- /dev/null +++ b/src/dolphintabpage.cpp @@ -0,0 +1,258 @@ +/*************************************************************************** + * Copyright (C) 2014 by Emmanuel Pescosta * + * * + * 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 "dolphintabpage.h" + +#include "dolphinviewcontainer.h" +#include "dolphin_generalsettings.h" + +#include + +DolphinTabPage::DolphinTabPage(const KUrl& primaryUrl, const KUrl& secondaryUrl, QWidget* parent) : + QWidget(parent), + m_primaryViewActive(true), + m_splitViewEnabled(false) +{ + QVBoxLayout* layout = new QVBoxLayout(this); + layout->setSpacing(0); + layout->setMargin(0); + + m_splitter = new QSplitter(Qt::Horizontal, this); + m_splitter->setChildrenCollapsible(false); + layout->addWidget(m_splitter); + + // Create a new primary view + m_primaryViewContainer = createViewContainer(primaryUrl); + connect(m_primaryViewContainer->view(), SIGNAL(urlChanged(KUrl)), + this, SIGNAL(activeViewUrlChanged(KUrl))); + + m_splitter->addWidget(m_primaryViewContainer); + m_primaryViewContainer->show(); + + if (secondaryUrl.isValid() || GeneralSettings::splitView()) { + // Provide a secondary view, if the given secondary url is valid or if the + // startup settings are set this way (use the url of the primary view). + m_splitViewEnabled = true; + const KUrl& url = secondaryUrl.isValid() ? secondaryUrl : primaryUrl; + m_secondaryViewContainer = createViewContainer(url); + m_splitter->addWidget(m_secondaryViewContainer); + m_secondaryViewContainer->show(); + } + + m_primaryViewContainer->setActive(true); +} + +bool DolphinTabPage::primaryViewActive() const +{ + return m_primaryViewActive; +} + +bool DolphinTabPage::splitViewEnabled() const +{ + return m_splitViewEnabled; +} + +void DolphinTabPage::setSplitViewEnabled(bool enabled) +{ + if (m_splitViewEnabled != enabled) { + m_splitViewEnabled = enabled; + + if (enabled) { + const KUrl& url = m_primaryViewContainer->url(); + m_secondaryViewContainer = createViewContainer(url); + m_splitter->addWidget(m_secondaryViewContainer); + m_secondaryViewContainer->show(); + m_secondaryViewContainer->setActive(true); + } else { + // Close the view which is active. + DolphinViewContainer* view = activeViewContainer(); + if (m_primaryViewActive) { + // If the primary view is active, we have to swap the pointers + // because the secondary view will be the new primary view. + qSwap(m_primaryViewContainer, m_secondaryViewContainer); + } + m_primaryViewContainer->setActive(true); + view->close(); + view->deleteLater(); + } + } +} + +DolphinViewContainer* DolphinTabPage::primaryViewContainer() const +{ + return m_primaryViewContainer; +} + +DolphinViewContainer* DolphinTabPage::secondaryViewContainer() const +{ + return m_secondaryViewContainer; +} + +DolphinViewContainer* DolphinTabPage::activeViewContainer() const +{ + return m_primaryViewActive ? m_primaryViewContainer : + m_secondaryViewContainer; +} + +KFileItemList DolphinTabPage::selectedItems() const +{ + KFileItemList items = m_primaryViewContainer->view()->selectedItems(); + if (m_splitViewEnabled) { + items += m_secondaryViewContainer->view()->selectedItems(); + } + return items; +} + +int DolphinTabPage::selectedItemsCount() const +{ + int selectedItemsCount = m_primaryViewContainer->view()->selectedItemsCount(); + if (m_splitViewEnabled) { + selectedItemsCount += m_secondaryViewContainer->view()->selectedItemsCount(); + } + return selectedItemsCount; +} + +void DolphinTabPage::markUrlsAsSelected(const QList& urls) +{ + m_primaryViewContainer->view()->markUrlsAsSelected(urls); + if (m_splitViewEnabled) { + m_secondaryViewContainer->view()->markUrlsAsSelected(urls); + } +} + +void DolphinTabPage::markUrlAsCurrent(const KUrl& url) +{ + m_primaryViewContainer->view()->markUrlAsCurrent(url); + if (m_splitViewEnabled) { + m_secondaryViewContainer->view()->markUrlAsCurrent(url); + } +} + +void DolphinTabPage::setPlacesSelectorVisible(bool visible) +{ + m_primaryViewContainer->urlNavigator()->setPlacesSelectorVisible(visible); + if (m_splitViewEnabled) { + m_secondaryViewContainer->urlNavigator()->setPlacesSelectorVisible(visible); + } +} + +void DolphinTabPage::refreshViews() +{ + m_primaryViewContainer->readSettings(); + if (m_splitViewEnabled) { + m_secondaryViewContainer->readSettings(); + } +} + +QByteArray DolphinTabPage::saveState() const +{ + QByteArray state; + QDataStream stream(&state, QIODevice::WriteOnly); + + stream << m_splitViewEnabled; + + stream << m_primaryViewContainer->url(); + stream << m_primaryViewContainer->urlNavigator()->isUrlEditable(); + + if (m_splitViewEnabled) { + stream << m_secondaryViewContainer->url(); + stream << m_secondaryViewContainer->urlNavigator()->isUrlEditable(); + } + + stream << m_primaryViewActive; + stream << m_splitter->saveState(); + + return state; +} + +void DolphinTabPage::restoreState(const QByteArray& state) +{ + QByteArray sd = state; + QDataStream stream(&sd, QIODevice::ReadOnly); + + bool isSplitViewEnabled = false; + stream >> isSplitViewEnabled; + setSplitViewEnabled(isSplitViewEnabled); + + KUrl primaryUrl; + stream >> primaryUrl; + m_primaryViewContainer->setUrl(primaryUrl); + bool primaryUrlEditable; + stream >> primaryUrlEditable; + m_primaryViewContainer->urlNavigator()->setUrlEditable(primaryUrlEditable); + + if (isSplitViewEnabled) { + KUrl secondaryUrl; + stream >> secondaryUrl; + m_secondaryViewContainer->setUrl(secondaryUrl); + bool secondaryUrlEditable; + stream >> secondaryUrlEditable; + m_secondaryViewContainer->urlNavigator()->setUrlEditable(secondaryUrlEditable); + } + + 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::slotViewActivated() +{ + const DolphinView* oldActiveView = activeViewContainer()->view(); + + // Set the view, which was active before, to inactive + // and update the active view type. + if (m_splitViewEnabled) { + activeViewContainer()->setActive(false); + m_primaryViewActive = !m_primaryViewActive; + } else { + m_primaryViewActive = true; + } + + const DolphinView* newActiveView = activeViewContainer()->view(); + + if (newActiveView != oldActiveView) { + disconnect(oldActiveView, SIGNAL(urlChanged(KUrl)), + this, SIGNAL(activeViewUrlChanged(KUrl))); + connect(newActiveView, SIGNAL(urlChanged(KUrl)), + this, SIGNAL(activeViewUrlChanged(KUrl))); + } + + emit activeViewUrlChanged(activeViewContainer()->url()); + emit activeViewChanged(); +} + +DolphinViewContainer* DolphinTabPage::createViewContainer(const KUrl& url) const +{ + DolphinViewContainer* container = new DolphinViewContainer(url, m_splitter); + container->setActive(false); + + const DolphinView* view = container->view(); + connect(view, SIGNAL(activated()), + this, SLOT(slotViewActivated())); + + return container; +} diff --git a/src/dolphintabpage.h b/src/dolphintabpage.h new file mode 100644 index 0000000000..95c02ed0a1 --- /dev/null +++ b/src/dolphintabpage.h @@ -0,0 +1,152 @@ +/*************************************************************************** + * Copyright (C) 2014 by Emmanuel Pescosta * + * * + * 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_PAGE_H +#define DOLPHIN_TAB_PAGE_H + +#include +#include +#include + +class QSplitter; +class DolphinViewContainer; +class KFileItemList; + +class DolphinTabPage : public QWidget +{ + Q_OBJECT + +public: + explicit DolphinTabPage(const KUrl& primaryUrl, const KUrl& secondaryUrl = KUrl(), QWidget* parent = 0); + + /** + * @return True if primary view is the active view in this tab. + */ + bool primaryViewActive() const; + + /** + * @return True if split view is enabled. + */ + bool splitViewEnabled() const; + + /** + * Enables or disables the split view mode. + * + * If \a enabled is true, it creates a secondary view with the url of the primary view. + */ + void setSplitViewEnabled(bool enabled); + + /** + * @return The primary view containter. + */ + DolphinViewContainer* primaryViewContainer() const; + + /** + * @return The secondary view containter, can be 0 if split view is disabled. + */ + DolphinViewContainer* secondaryViewContainer() const; + + /** + * @return DolphinViewContainer of the active view + */ + DolphinViewContainer* activeViewContainer() const; + + /** + * Returns the selected items. The list is empty if no item has been + * selected. + */ + KFileItemList selectedItems() const; + + /** + * Returns the number of selected items (this is faster than + * invoking selectedItems().count()). + */ + int selectedItemsCount() const; + + /** + * Marks the items indicated by \p urls to get selected after the + * directory DolphinView::url() has been loaded. Note that nothing + * gets selected if no loading of a directory has been triggered + * by DolphinView::setUrl() or DolphinView::reload(). + */ + void markUrlsAsSelected(const QList& urls); + + /** + * Marks the item indicated by \p url to be scrolled to and as the + * current item after directory DolphinView::url() has been loaded. + */ + void markUrlAsCurrent(const KUrl& url); + + /** + * Sets the places selector visible, if \a visible is true. + * The places selector allows to select the places provided + * by the places model passed in the constructor. Per default + * the places selector is visible. + */ + void setPlacesSelectorVisible(bool visible); + + /** + * Refreshes the views of the main window by recreating them according to + * the given Dolphin settings. + */ + void refreshViews(); + + /** + * Saves all tab related properties (urls, splitter layout, ...). + * + * @return A byte-array which contains all properties. + */ + QByteArray saveState() const; + + /** + * Restores all tab related properties (urls, splitter layout, ...) from + * the given \a state. + */ + void restoreState(const QByteArray& state); + +signals: + void activeViewChanged(); + void activeViewUrlChanged(const KUrl& url); + +private slots: + /** + * Handles the view activated event. + * + * It sets the previous active view to inactive, updates the current + * active view type and triggers the activeViewChanged event. + */ + void slotViewActivated(); + +private: + /** + * Creates a new view container and does the default initialization. + */ + DolphinViewContainer* createViewContainer(const KUrl& url) const; + +private: + QSplitter* m_splitter; + + QPointer m_primaryViewContainer; + QPointer m_secondaryViewContainer; + + bool m_primaryViewActive; + bool m_splitViewEnabled; +}; + +#endif // DOLPHIN_TAB_PAGE_H diff --git a/src/dolphinviewcontainer.cpp b/src/dolphinviewcontainer.cpp index c1677dc430..87a2ceb4d2 100644 --- a/src/dolphinviewcontainer.cpp +++ b/src/dolphinviewcontainer.cpp @@ -143,6 +143,8 @@ DolphinViewContainer::DolphinViewContainer(const KUrl& url, QWidget* parent) : this, &DolphinViewContainer::showErrorMessage); connect(m_view, &DolphinView::urlIsFileError, this, &DolphinViewContainer::slotUrlIsFileError); + connect(m_view, &DolphinView::activated, + this, &DolphinViewContainer::activate); connect(m_urlNavigator, &KUrlNavigator::urlAboutToBeChanged, this, &DolphinViewContainer::slotUrlNavigatorLocationAboutToBeChanged);