X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/07e07fd522cc278dffccc3b8b6faded0f6f5df20..11289b4fc3efbc074b668d4516cd896f8ade9761:/src/dolphinmainwindow.cpp diff --git a/src/dolphinmainwindow.cpp b/src/dolphinmainwindow.cpp index de81af06d..cf2064482 100644 --- a/src/dolphinmainwindow.cpp +++ b/src/dolphinmainwindow.cpp @@ -20,260 +20,269 @@ ***************************************************************************/ #include "dolphinmainwindow.h" +#include "dolphinviewactionhandler.h" -#include +#include #include "dolphinapplication.h" +#include "dolphinfileplacesview.h" +#include "dolphinnewmenu.h" #include "dolphinsettings.h" #include "dolphinsettingsdialog.h" #include "dolphinstatusbar.h" -#include "dolphinapplication.h" -#include "urlnavigator.h" -#include "dolphinsettings.h" -#include "bookmarkssidebarpage.h" +#include "dolphinviewcontainer.h" #include "infosidebarpage.h" -#include "generalsettings.h" -#include "viewpropertiesdialog.h" +#include "metadatawidget.h" +#include "mainwindowadaptor.h" +#include "treeviewsidebarpage.h" #include "viewproperties.h" +#ifndef Q_OS_WIN +#include "terminalsidebarpage.h" +#endif + +#include "dolphin_generalsettings.h" +#include "dolphin_iconsmodesettings.h" +#include "draganddrophelper.h" + #include #include -#include #include #include #include #include +#include #include #include #include #include -#include #include #include +#include #include +#include #include +#include #include -#include -#include #include -#include #include #include #include #include #include +#include +#include +#include #include +#include -#include // TODO -#include +#include +#include #include +#include #include #include -DolphinMainWindow::DolphinMainWindow() : - KMainWindow(0), - m_splitter(0), - m_activeView(0) +DolphinMainWindow::DolphinMainWindow(int id) : + KXmlGuiWindow(0), + m_newMenu(0), + m_showMenuBar(0), + m_tabBar(0), + m_activeViewContainer(0), + m_centralWidgetLayout(0), + m_id(id), + m_tabIndex(0), + m_viewTab(), + m_actionHandler(0) { - setObjectName("Dolphin"); - m_view[PrimaryIdx] = 0; - m_view[SecondaryIdx] = 0; + setObjectName("Dolphin#"); - KonqUndoManager::incRef(); + m_viewTab.append(ViewTab()); - connect(KonqUndoManager::self(), SIGNAL(undoAvailable(bool)), + new MainWindowAdaptor(this); + QDBusConnection::sessionBus().registerObject(QString("/dolphin/MainWindow%1").arg(m_id), this); + + KIO::FileUndoManager* undoManager = KIO::FileUndoManager::self(); + undoManager->setUiInterface(new UndoUiInterface()); + + connect(undoManager, SIGNAL(undoAvailable(bool)), this, SLOT(slotUndoAvailable(bool))); - connect(KonqUndoManager::self(), SIGNAL(undoTextChanged(const QString&)), + connect(undoManager, SIGNAL(undoTextChanged(const QString&)), this, SLOT(slotUndoTextChanged(const QString&))); + connect(undoManager, SIGNAL(jobRecordingStarted(CommandType)), + this, SLOT(clearStatusBar())); + connect(undoManager, SIGNAL(jobRecordingFinished(CommandType)), + this, SLOT(showCommand(CommandType))); + connect(DolphinSettings::instance().placesModel(), SIGNAL(errorMessage(const QString&)), + this, SLOT(showErrorMessage(const QString&))); + connect(&DragAndDropHelper::instance(), SIGNAL(errorMessage(const QString&)), + this, SLOT(showErrorMessage(const QString&))); } DolphinMainWindow::~DolphinMainWindow() { - KonqUndoManager::decRef(); - - qDeleteAll(m_fileGroupActions); - m_fileGroupActions.clear(); - DolphinApplication::app()->removeMainWindow(this); } -void DolphinMainWindow::setActiveView(DolphinView* view) +void DolphinMainWindow::toggleViews() { - assert((view == m_view[PrimaryIdx]) || (view == m_view[SecondaryIdx])); - if (m_activeView == view) { + if (m_viewTab[m_tabIndex].primaryView == 0) { return; } - m_activeView = view; + // move secondary view from the last position of the splitter + // to the first position + m_viewTab[m_tabIndex].splitter->insertWidget(0, m_viewTab[m_tabIndex].secondaryView); - updateHistory(); - updateEditActions(); - updateViewActions(); - updateGoActions(); - - setCaption(m_activeView->url().fileName()); - - emit activeViewChanged(); + DolphinViewContainer* container = m_viewTab[m_tabIndex].primaryView; + m_viewTab[m_tabIndex].primaryView = m_viewTab[m_tabIndex].secondaryView; + m_viewTab[m_tabIndex].secondaryView = container; } -void DolphinMainWindow::dropUrls(const KUrl::List& urls, - const KUrl& destination) +void DolphinMainWindow::showCommand(CommandType command) { - m_dropDestination = destination; - m_droppedUrls = urls; - - /* KDE4-TODO - const ButtonState keyboardState = KApplication::keyboardMouseState(); - const bool shiftPressed = (keyboardState & ShiftButton) > 0; - const bool controlPressed = (keyboardState & ControlButton) > 0; - - - - if (shiftPressed && controlPressed) { - // shortcut for 'Linke Here' is used - selectedIndex = 2; - } - else if (controlPressed) { - // shortcut for 'Copy Here' is used - selectedIndex = 1; - } - else if (shiftPressed) { - // shortcut for 'Move Here' is used - selectedIndex = 0; - } - else*/ { - // no shortcut is used, hence open a popup menu - KMenu popup(this); - - QAction* moveAction = popup.addAction(SmallIcon("goto"), i18n("&Move Here")); - connect(moveAction, SIGNAL(triggered()), this, SLOT(moveDroppedItems())); - - QAction* copyAction = popup.addAction(SmallIcon("editcopy"), i18n( "&Copy Here" )); - connect(copyAction, SIGNAL(triggered()), this, SLOT(copyDroppedItems())); - - QAction* linkAction = popup.addAction(i18n("&Link Here")); - connect(linkAction, SIGNAL(triggered()), this, SLOT(linkDroppedItems())); + DolphinStatusBar* statusBar = m_activeViewContainer->statusBar(); + switch (command) { + case KIO::FileUndoManager::Copy: + statusBar->setMessage(i18nc("@info:status", "Copy operation completed."), + DolphinStatusBar::OperationCompleted); + break; + case KIO::FileUndoManager::Move: + statusBar->setMessage(i18nc("@info:status", "Move operation completed."), + DolphinStatusBar::OperationCompleted); + break; + case KIO::FileUndoManager::Link: + statusBar->setMessage(i18nc("@info:status", "Link operation completed."), + DolphinStatusBar::OperationCompleted); + break; + case KIO::FileUndoManager::Trash: + statusBar->setMessage(i18nc("@info:status", "Move to trash operation completed."), + DolphinStatusBar::OperationCompleted); + break; + case KIO::FileUndoManager::Rename: + statusBar->setMessage(i18nc("@info:status", "Renaming operation completed."), + DolphinStatusBar::OperationCompleted); + break; - QAction* cancelAction = popup.addAction(SmallIcon("stop"), i18n("Cancel")); - popup.insertSeparator(cancelAction); + case KIO::FileUndoManager::Mkdir: + statusBar->setMessage(i18nc("@info:status", "Created folder."), + DolphinStatusBar::OperationCompleted); + break; - popup.exec(QCursor::pos()); + default: + break; } - - m_droppedUrls.clear(); } void DolphinMainWindow::refreshViews() { - const bool split = DolphinSettings::instance().generalSettings()->splitView(); - const bool isPrimaryViewActive = (m_activeView == m_view[PrimaryIdx]); - KUrl url; - for (int i = PrimaryIdx; i <= SecondaryIdx; ++i) { - if (m_view[i] != 0) { - url = m_view[i]->url(); - - // delete view instance... - m_view[i]->close(); - m_view[i]->deleteLater(); - m_view[i] = 0; - } + Q_ASSERT(m_viewTab[m_tabIndex].primaryView != 0); + + // remember the current active view, as because of + // the refreshing the active view might change to + // the secondary view + DolphinViewContainer* activeViewContainer = m_activeViewContainer; - if (split || (i == PrimaryIdx)) { - // ... and recreate it - ViewProperties props(url); - m_view[i] = new DolphinView(this, - m_splitter, - url, - props.viewMode(), - props.showHiddenFiles()); - connectViewSignals(i); - m_view[i]->show(); + const int tabCount = m_viewTab.count(); + for (int i = 0; i < tabCount; ++i) { + m_viewTab[i].primaryView->refresh(); + if (m_viewTab[i].secondaryView != 0) { + m_viewTab[i].secondaryView->refresh(); } } - m_activeView = isPrimaryViewActive ? m_view[PrimaryIdx] : m_view[SecondaryIdx]; - assert(m_activeView != 0); - - updateViewActions(); - emit activeViewChanged(); + setActiveViewContainer(activeViewContainer); } -void DolphinMainWindow::slotViewModeChanged() +void DolphinMainWindow::pasteIntoFolder() { - updateViewActions(); + m_activeViewContainer->view()->pasteIntoFolder(); } -void DolphinMainWindow::slotShowHiddenFilesChanged() +void DolphinMainWindow::changeUrl(const KUrl& url) { - KToggleAction* showHiddenFilesAction = - static_cast(actionCollection()->action("show_hidden_files")); - showHiddenFilesAction->setChecked(m_activeView->showHiddenFiles()); + if (!KProtocolManager::supportsListing(url)) { + // The URL navigator only checks for validity, not + // if the URL can be listed. An error message is + // shown due to DolphinViewContainer::restoreView(). + return; + } + + DolphinViewContainer* view = activeViewContainer(); + if (view != 0) { + view->setUrl(url); + updateEditActions(); + updateViewActions(); + updateGoActions(); + setCaption(url.fileName()); + if (m_viewTab.count() > 1) { + m_tabBar->setTabText(m_tabIndex, tabName(url)); + } + emit urlChanged(url); + } } -void DolphinMainWindow::slotSortingChanged(DolphinView::Sorting sorting) +void DolphinMainWindow::changeSelection(const KFileItemList& selection) { - QAction* action = 0; - switch (sorting) { - case DolphinView::SortByName: - action = actionCollection()->action("by_name"); - break; - case DolphinView::SortBySize: - action = actionCollection()->action("by_size"); - break; - case DolphinView::SortByDate: - action = actionCollection()->action("by_date"); - break; - default: - break; - } - - if (action != 0) { - KToggleAction* toggleAction = static_cast(action); - toggleAction->setChecked(true); - } + activeViewContainer()->view()->changeSelection(selection); } -void DolphinMainWindow::slotSortOrderChanged(Qt::SortOrder order) +void DolphinMainWindow::slotEditableStateChanged(bool editable) { - KToggleAction* descending = static_cast(actionCollection()->action("descending")); - const bool sortDescending = (order == Qt::Descending); - descending->setChecked(sortDescending); + KToggleAction* editableLocationAction = + static_cast(actionCollection()->action("editable_location")); + editableLocationAction->setChecked(editable); } -void DolphinMainWindow::slotSelectionChanged() +void DolphinMainWindow::slotSelectionChanged(const KFileItemList& selection) { updateEditActions(); - assert(m_view[PrimaryIdx] != 0); - int selectedUrlsCount = m_view[PrimaryIdx]->selectedUrls().count(); - if (m_view[SecondaryIdx] != 0) { - selectedUrlsCount += m_view[SecondaryIdx]->selectedUrls().count(); + Q_ASSERT(m_viewTab[m_tabIndex].primaryView != 0); + int selectedUrlsCount = m_viewTab[m_tabIndex].primaryView->view()->selectedItemsCount(); + if (m_viewTab[m_tabIndex].secondaryView != 0) { + selectedUrlsCount += m_viewTab[m_tabIndex].secondaryView->view()->selectedItemsCount(); } QAction* compareFilesAction = actionCollection()->action("compare_files"); - compareFilesAction->setEnabled(selectedUrlsCount == 2); + if (selectedUrlsCount == 2) { + compareFilesAction->setEnabled(isKompareInstalled()); + } else { + compareFilesAction->setEnabled(false); + } - m_activeView->updateStatusBar(); + const bool activeViewHasSelection = (activeViewContainer()->view()->selectedItemsCount() > 0); + actionCollection()->action("quick_view")->setEnabled(activeViewHasSelection); - emit selectionChanged(); + m_activeViewContainer->updateStatusBar(); + + emit selectionChanged(selection); } -void DolphinMainWindow::slotHistoryChanged() +void DolphinMainWindow::slotRequestItemInfo(const KFileItem& item) { - updateHistory(); + emit requestItemInfo(item); } -void DolphinMainWindow::slotUrlChanged(const KUrl& url) +void DolphinMainWindow::updateHistory() { - updateEditActions(); - updateGoActions(); - setCaption(url.fileName()); + const KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator(); + const int index = urlNavigator->historyIndex(); + + QAction* backAction = actionCollection()->action("go_back"); + if (backAction != 0) { + backAction->setEnabled(index < urlNavigator->historySize() - 1); + } + + QAction* forwardAction = actionCollection()->action("go_forward"); + if (forwardAction != 0) { + forwardAction->setEnabled(index > 0); + } } void DolphinMainWindow::updateFilterBarAction(bool show) { - KToggleAction* showFilterBarAction = - static_cast(actionCollection()->action("show_filter_bar")); + QAction* showFilterBarAction = actionCollection()->action("show_filter_bar"); showFilterBarAction->setChecked(show); } @@ -282,293 +291,150 @@ void DolphinMainWindow::openNewMainWindow() DolphinApplication::app()->createMainWindow()->show(); } -void DolphinMainWindow::moveDroppedItems() -{ - moveUrls(m_droppedUrls, m_dropDestination); -} - -void DolphinMainWindow::copyDroppedItems() +void DolphinMainWindow::openNewTab() { - copyUrls(m_droppedUrls, m_dropDestination); + openNewTab(m_activeViewContainer->url()); + m_tabBar->setCurrentIndex(m_viewTab.count() - 1); } -void DolphinMainWindow::linkDroppedItems() +void DolphinMainWindow::openNewTab(const KUrl& url) { - KonqOperations::copy(this, KonqOperations::LINK, m_droppedUrls, m_dropDestination); - m_undoOperations.append(KonqOperations::LINK); -} + if (m_viewTab.count() == 1) { + // Only one view is open currently and hence no tab is shown at + // all. Before creating a tab for 'url', provide a tab for the current URL. + m_tabBar->addTab(KIcon("folder"), tabName(m_activeViewContainer->url())); + m_tabBar->blockSignals(false); + } -void DolphinMainWindow::closeEvent(QCloseEvent* event) -{ - DolphinSettings& settings = DolphinSettings::instance(); - GeneralSettings* generalSettings = settings.generalSettings(); - generalSettings->setFirstRun(false); + m_tabBar->addTab(KIcon("folder"), tabName(url)); - settings.save(); + ViewTab viewTab; + viewTab.splitter = new QSplitter(this); + viewTab.primaryView = new DolphinViewContainer(this, viewTab.splitter, url); + connectViewSignals(viewTab.primaryView); + viewTab.primaryView->view()->reload(); - // TODO: I assume there will be a generic way in KDE 4 to store the docks - // of the main window. In the meantime they are stored manually: - QString filename = KStandardDirs::locateLocal("data", KGlobal::instance()->instanceName()); - filename.append("/panels_layout"); - QFile file(filename); - if (file.open(QIODevice::WriteOnly)) { - QByteArray data = saveState(); - file.write(data); - file.close(); - } + m_viewTab.append(viewTab); - KMainWindow::closeEvent(event); + actionCollection()->action("close_tab")->setEnabled(true); } -void DolphinMainWindow::saveProperties(KConfig* config) +void DolphinMainWindow::activateNextTab() { - config->setGroup("Primary view"); - config->writeEntry("Url", m_view[PrimaryIdx]->url().url()); - config->writeEntry("Editable Url", m_view[PrimaryIdx]->isUrlEditable()); - if (m_view[SecondaryIdx] != 0) { - config->setGroup("Secondary view"); - config->writeEntry("Url", m_view[SecondaryIdx]->url().url()); - config->writeEntry("Editable Url", m_view[SecondaryIdx]->isUrlEditable()); + if (m_viewTab.count() == 1 || m_tabBar->count() < 2) { + return; } -} -void DolphinMainWindow::readProperties(KConfig* config) -{ - config->setGroup("Primary view"); - m_view[PrimaryIdx]->setUrl(config->readEntry("Url")); - m_view[PrimaryIdx]->setUrlEditable(config->readEntry("Editable Url", false)); - if (config->hasGroup("Secondary view")) { - config->setGroup("Secondary view"); - if (m_view[SecondaryIdx] == 0) { - toggleSplitView(); - } - m_view[SecondaryIdx]->setUrl(config->readEntry("Url")); - m_view[SecondaryIdx]->setUrlEditable(config->readEntry("Editable Url", false)); - } - else if (m_view[SecondaryIdx] != 0) { - toggleSplitView(); - } + const int tabIndex = (m_tabBar->currentIndex() + 1) % m_tabBar->count(); + m_tabBar->setCurrentIndex(tabIndex); } -void DolphinMainWindow::createFolder() +void DolphinMainWindow::activatePrevTab() { - // Parts of the following code have been taken - // from the class KonqPopupMenu located in - // libqonq/konq_popupmenu.h of Konqueror. - // (Copyright (C) 2000 David Faure , - // Copyright (C) 2001 Holger Freyther ) - - clearStatusBar(); - - DolphinStatusBar* statusBar = m_activeView->statusBar(); - const KUrl baseUrl(m_activeView->url()); - - QString name(i18n("New Folder")); - baseUrl.path(KUrl::AddTrailingSlash); - - - if (baseUrl.isLocalFile() && QFileInfo(baseUrl.path(KUrl::AddTrailingSlash) + name).exists()) { - name = KIO::RenameDialog::suggestName(baseUrl, i18n("New Folder")); - } - - bool ok = false; - name = KInputDialog::getText(i18n("New Folder"), - i18n("Enter folder name:" ), - name, - &ok, - this); - - if (!ok) { - // the user has pressed 'Cancel' + if (m_viewTab.count() == 1 || m_tabBar->count() < 2) { return; } - assert(!name.isEmpty()); - - KUrl url; - if ((name[0] == '/') || (name[0] == '~')) { - url.setPath(KShell::tildeExpand(name)); - } - else { - name = KIO::encodeFileName(name); - url = baseUrl; - url.addPath(name); - } - - KonqOperations::mkdir(this, url); - - // TODO: is there a possability to check whether the mkdir operation - // has been successful? - //if (ok) { - statusBar->setMessage(i18n("Created folder %1.",url.path()), - DolphinStatusBar::OperationCompleted); - //} - //else { - // // Creating of the folder has been failed. Check whether the creating - // // has been failed because a folder with the same name exists... - // if (KIO::NetAccess::exists(url, true, this)) { - // statusBar->setMessage(i18n("A folder named %1 already exists.",url.path()), - // DolphinStatusBar::Error); - // } - // else { - // statusBar->setMessage(i18n("Creating of folder %1 failed.",url.path()), - // DolphinStatusBar::Error); - // } -} - -void DolphinMainWindow::createFile() -{ - // Parts of the following code have been taken - // from the class KonqPopupMenu located in - // libqonq/konq_popupmenu.h of Konqueror. - // (Copyright (C) 2000 David Faure , - // Copyright (C) 2001 Holger Freyther ) - - clearStatusBar(); - - // TODO: const Entry& entry = m_createFileTemplates[QString(sender->name())]; - // should be enough. Anyway: the implementation of [] does a linear search internally too. - KSortableList::ConstIterator it = m_createFileTemplates.begin(); - KSortableList::ConstIterator end = m_createFileTemplates.end(); - - const QString senderName(sender()->objectName()); - bool found = false; - CreateFileEntry entry; - while (!found && (it != end)) { - if ((*it).key() == senderName) { - entry = (*it).value(); - found = true; - } - else { - ++it; - } + int tabIndex = m_tabBar->currentIndex() - 1; + if (tabIndex == -1) { + tabIndex = m_tabBar->count() - 1; } + m_tabBar->setCurrentIndex(tabIndex); +} - DolphinStatusBar* statusBar = m_activeView->statusBar(); - if (!found || !QFile::exists(entry.templatePath)) { - statusBar->setMessage(i18n("Could not create file."), DolphinStatusBar::Error); - return; +void DolphinMainWindow::openInNewTab() +{ + const KFileItemList list = m_activeViewContainer->view()->selectedItems(); + if ((list.count() == 1) && list[0].isDir()) { + openNewTab(m_activeViewContainer->view()->selectedUrls()[0]); + m_tabBar->setCurrentIndex(m_viewTab.count() - 1); } +} - // Get the source path of the template which should be copied. - // The source path is part of the Url entry of the desktop file. - const int pos = entry.templatePath.lastIndexOf('/'); - QString sourcePath(entry.templatePath.left(pos + 1)); - sourcePath += KDesktopFile(entry.templatePath, true).readPathEntry("Url"); - - QString name(i18n(entry.name.toAscii())); - // Most entry names end with "..." (e. g. "HTML File..."), which is ok for - // menus but no good choice for a new file name -> remove the dots... - name.replace("...", QString::null); - - // add the file extension to the name - name.append(sourcePath.right(sourcePath.length() - sourcePath.lastIndexOf('.'))); - - // Check whether a file with the current name already exists. If yes suggest automatically - // a unique file name (e. g. "HTML File" will be replaced by "HTML File_1"). - const KUrl viewUrl(m_activeView->url()); - const bool fileExists = viewUrl.isLocalFile() && - QFileInfo(viewUrl.path(KUrl::AddTrailingSlash) + KIO::encodeFileName(name)).exists(); - if (fileExists) { - name = KIO::RenameDialog::suggestName(viewUrl, name); +void DolphinMainWindow::openInNewWindow() +{ + const KFileItemList list = m_activeViewContainer->view()->selectedItems(); + if ((list.count() == 1) && list[0].isDir()) { + DolphinMainWindow* window = DolphinApplication::app()->createMainWindow(); + window->changeUrl(m_activeViewContainer->view()->selectedUrls()[0]); + window->show(); } +} - // let the user change the suggested file name - bool ok = false; - name = KInputDialog::getText(entry.name, - entry.comment, - name, - &ok, - this); - if (!ok) { - // the user has pressed 'Cancel' +void DolphinMainWindow::toggleActiveView() +{ + if (m_viewTab[m_tabIndex].secondaryView == 0) { + // only one view is available return; } - // before copying the template to the destination path check whether a file - // with the given name already exists - const QString destPath(viewUrl.pathOrUrl() + "/" + KIO::encodeFileName(name)); - const KUrl destUrl(destPath); - if (KIO::NetAccess::exists(destUrl, false, this)) { - statusBar->setMessage(i18n("A file named %1 already exists.",name), - DolphinStatusBar::Error); - return; - } + Q_ASSERT(m_activeViewContainer != 0); + Q_ASSERT(m_viewTab[m_tabIndex].primaryView != 0); - // copy the template to the destination path - const KUrl sourceUrl(sourcePath); - KIO::CopyJob* job = KIO::copyAs(sourceUrl, destUrl); - job->setDefaultPermissions(true); - if (KIO::NetAccess::synchronousRun(job, this)) { - statusBar->setMessage(i18n("Created file %1.",name), - DolphinStatusBar::OperationCompleted); + DolphinViewContainer* left = m_viewTab[m_tabIndex].primaryView; + DolphinViewContainer* right = m_viewTab[m_tabIndex].secondaryView; + setActiveViewContainer(m_activeViewContainer == right ? left : right); +} - KUrl::List list; - list.append(sourceUrl); +void DolphinMainWindow::closeEvent(QCloseEvent* event) +{ + DolphinSettings& settings = DolphinSettings::instance(); + GeneralSettings* generalSettings = settings.generalSettings(); + generalSettings->setFirstRun(false); - // TODO: use the KonqUndoManager/KonqOperations instead. - //DolphinCommand command(DolphinCommand::CreateFile, list, destUrl); - //UndoManager::instance().addCommand(command); + settings.save(); - } - else { - statusBar->setMessage(i18n("Creating of file %1 failed.",name), - DolphinStatusBar::Error); - } + KXmlGuiWindow::closeEvent(event); } -void DolphinMainWindow::rename() +void DolphinMainWindow::saveProperties(KConfigGroup& group) { - clearStatusBar(); - m_activeView->renameSelectedItems(); -} + // TODO: remember tabs + DolphinViewContainer* cont = m_viewTab[m_tabIndex].primaryView; + group.writeEntry("Primary Url", cont->url().url()); + group.writeEntry("Primary Editable Url", cont->isUrlEditable()); -void DolphinMainWindow::moveToTrash() -{ - clearStatusBar(); - const KUrl::List selectedUrls = m_activeView->selectedUrls(); - // TODO: per default a message box is opened which asks whether the item - // should really be moved to the trash. This does not make sense, as the - // action can be undone anyway by the user. - KonqOperations::del(this, KonqOperations::TRASH, selectedUrls); - m_undoOperations.append(KonqOperations::TRASH); + cont = m_viewTab[m_tabIndex].secondaryView; + if (cont != 0) { + group.writeEntry("Secondary Url", cont->url().url()); + group.writeEntry("Secondary Editable Url", cont->isUrlEditable()); + } } -void DolphinMainWindow::deleteItems() +void DolphinMainWindow::readProperties(const KConfigGroup& group) { - clearStatusBar(); + // TODO: read tabs + DolphinViewContainer* cont = m_viewTab[m_tabIndex].primaryView; - KUrl::List list = m_activeView->selectedUrls(); - const uint itemCount = list.count(); - assert(itemCount >= 1); + cont->setUrl(group.readEntry("Primary Url")); + bool editable = group.readEntry("Primary Editable Url", false); + cont->urlNavigator()->setUrlEditable(editable); - QString text; - if (itemCount > 1) { - text = i18n("Do you really want to delete the %1 selected items?",itemCount); - } - else { - const KUrl& url = list.first(); - text = i18n("Do you really want to delete '%1'?",url.fileName()); - } + cont = m_viewTab[m_tabIndex].secondaryView; + const QString secondaryUrl = group.readEntry("Secondary Url"); + if (!secondaryUrl.isEmpty()) { + if (cont == 0) { + // a secondary view should be shown, but no one is available + // currently -> create a new view + toggleSplitView(); + cont = m_viewTab[m_tabIndex].secondaryView; + Q_ASSERT(cont != 0); + } - const bool del = KMessageBox::warningContinueCancel(this, - text, - QString::null, - KGuiItem(i18n("Delete"), KIcon("editdelete")) - ) == KMessageBox::Continue; - if (del) { - KIO::Job* job = KIO::del(list); - connect(job, SIGNAL(result(KJob*)), - this, SLOT(slotHandleJobError(KJob*))); - connect(job, SIGNAL(result(KJob*)), - this, SLOT(slotDeleteFileFinished(KJob*))); + cont->setUrl(secondaryUrl); + bool editable = group.readEntry("Secondary Editable Url", false); + cont->urlNavigator()->setUrlEditable(editable); + } else if (cont != 0) { + // no secondary view should be shown, but the default setting shows + // one already -> close the view + toggleSplitView(); } } -void DolphinMainWindow::properties() +void DolphinMainWindow::updateNewMenu() { - const KFileItemList list = m_activeView->selectedItems(); - new KPropertiesDialog(list, this); + m_newMenu->slotCheckUpToDate(); + m_newMenu->setPopupFiles(activeViewContainer()->url()); } void DolphinMainWindow::quit() @@ -576,366 +442,183 @@ void DolphinMainWindow::quit() close(); } -void DolphinMainWindow::slotHandleJobError(KJob* job) +void DolphinMainWindow::showErrorMessage(const QString& message) { - if (job->error() != 0) { - m_activeView->statusBar()->setMessage(job->errorString(), - DolphinStatusBar::Error); - } -} - -void DolphinMainWindow::slotDeleteFileFinished(KJob* job) -{ - if (job->error() == 0) { - m_activeView->statusBar()->setMessage(i18n("Delete operation completed."), - DolphinStatusBar::OperationCompleted); - - // TODO: In opposite to the 'Move to Trash' operation in the class KFileIconView - // no rearranging of the item position is done when a file has been deleted. - // This is bypassed by reloading the view, but it might be worth to investigate - // deeper for the root of this issue. - m_activeView->reload(); + if (!message.isEmpty()) { + DolphinStatusBar* statusBar = m_activeViewContainer->statusBar(); + statusBar->setMessage(message, DolphinStatusBar::Error); } } void DolphinMainWindow::slotUndoAvailable(bool available) { - QAction* undoAction = actionCollection()->action(KStandardAction::stdName(KStandardAction::Undo)); + QAction* undoAction = actionCollection()->action(KStandardAction::name(KStandardAction::Undo)); if (undoAction != 0) { undoAction->setEnabled(available); } - - if (available && (m_undoOperations.count() > 0)) { - const KonqOperations::Operation op = m_undoOperations.takeFirst(); - DolphinStatusBar* statusBar = m_activeView->statusBar(); - switch (op) { - case KonqOperations::COPY: - statusBar->setMessage(i18n("Copy operation completed."), - DolphinStatusBar::OperationCompleted); - break; - case KonqOperations::MOVE: - statusBar->setMessage(i18n("Move operation completed."), - DolphinStatusBar::OperationCompleted); - break; - case KonqOperations::LINK: - statusBar->setMessage(i18n("Link operation completed."), - DolphinStatusBar::OperationCompleted); - break; - case KonqOperations::TRASH: - statusBar->setMessage(i18n("Move to trash operation completed."), - DolphinStatusBar::OperationCompleted); - break; - default: - break; - } - - } } void DolphinMainWindow::slotUndoTextChanged(const QString& text) { - QAction* undoAction = actionCollection()->action(KStandardAction::stdName(KStandardAction::Undo)); + QAction* undoAction = actionCollection()->action(KStandardAction::name(KStandardAction::Undo)); if (undoAction != 0) { undoAction->setText(text); } } +void DolphinMainWindow::undo() +{ + clearStatusBar(); + KIO::FileUndoManager::self()->uiInterface()->setParentWidget(this); + KIO::FileUndoManager::self()->undo(); +} + void DolphinMainWindow::cut() { - QMimeData* mimeData = new QMimeData(); - const KUrl::List kdeUrls = m_activeView->selectedUrls(); - const KUrl::List mostLocalUrls; - KonqMimeData::populateMimeData(mimeData, kdeUrls, mostLocalUrls, true); - QApplication::clipboard()->setMimeData(mimeData); + m_activeViewContainer->view()->cutSelectedItems(); } void DolphinMainWindow::copy() { - QMimeData* mimeData = new QMimeData(); - const KUrl::List kdeUrls = m_activeView->selectedUrls(); - const KUrl::List mostLocalUrls; - KonqMimeData::populateMimeData(mimeData, kdeUrls, mostLocalUrls, false); - - QApplication::clipboard()->setMimeData(mimeData); + m_activeViewContainer->view()->copySelectedItems(); } void DolphinMainWindow::paste() { - QClipboard* clipboard = QApplication::clipboard(); - const QMimeData* mimeData = clipboard->mimeData(); - - clearStatusBar(); - - const KUrl::List sourceUrls = KUrl::List::fromMimeData(mimeData); - - // per default the pasting is done into the current Url of the view - KUrl destUrl(m_activeView->url()); - - // check whether the pasting should be done into a selected directory - KUrl::List selectedUrls = m_activeView->selectedUrls(); - if (selectedUrls.count() == 1) { - const KFileItem fileItem(S_IFDIR, - KFileItem::Unknown, - selectedUrls.first(), - true); - if (fileItem.isDir()) { - // only one item is selected which is a directory, hence paste - // into this directory - destUrl = selectedUrls.first(); - } - } - - if (KonqMimeData::decodeIsCutSelection(mimeData)) { - moveUrls(sourceUrls, destUrl); - clipboard->clear(); - } - else { - copyUrls(sourceUrls, destUrl); - } + m_activeViewContainer->view()->paste(); } void DolphinMainWindow::updatePasteAction() { - QAction* pasteAction = actionCollection()->action(KStandardAction::stdName(KStandardAction::Paste)); - if (pasteAction == 0) { - return; - } - - QString text(i18n("Paste")); - QClipboard* clipboard = QApplication::clipboard(); - const QMimeData* mimeData = clipboard->mimeData(); - - KUrl::List urls = KUrl::List::fromMimeData(mimeData); - if (!urls.isEmpty()) { - pasteAction->setEnabled(true); - - const int count = urls.count(); - if (count == 1) { - pasteAction->setText(i18n("Paste 1 File")); - } - else { - pasteAction->setText(i18n("Paste %1 Files").arg(count)); - } - } - else { - pasteAction->setEnabled(false); - pasteAction->setText(i18n("Paste")); - } - - if (pasteAction->isEnabled()) { - KUrl::List urls = m_activeView->selectedUrls(); - const uint count = urls.count(); - if (count > 1) { - // pasting should not be allowed when more than one file - // is selected - pasteAction->setEnabled(false); - } - else if (count == 1) { - // Only one file is selected. Pasting is only allowed if this - // file is a directory. - // TODO: this doesn't work with remote protocols; instead we need a - // m_activeView->selectedFileItems() to get the real KFileItems - const KFileItem fileItem(S_IFDIR, - KFileItem::Unknown, - urls.first(), - true); - pasteAction->setEnabled(fileItem.isDir()); - } - } + QAction* pasteAction = actionCollection()->action(KStandardAction::name(KStandardAction::Paste)); + QPair pasteInfo = m_activeViewContainer->view()->pasteInfo(); + pasteAction->setEnabled(pasteInfo.first); + pasteAction->setText(pasteInfo.second); } void DolphinMainWindow::selectAll() { clearStatusBar(); - m_activeView->selectAll(); + + // if the URL navigator is editable and focused, select the whole + // URL instead of all items of the view + + KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator(); + QLineEdit* lineEdit = urlNavigator->editor()->lineEdit(); + const bool selectUrl = urlNavigator->isUrlEditable() && + lineEdit->hasFocus(); + if (selectUrl) { + lineEdit->selectAll(); + } else { + m_activeViewContainer->view()->selectAll(); + } } void DolphinMainWindow::invertSelection() { clearStatusBar(); - m_activeView->invertSelection(); -} -void DolphinMainWindow::setIconsView() -{ - m_activeView->setMode(DolphinView::IconsView); -} - -void DolphinMainWindow::setDetailsView() -{ - m_activeView->setMode(DolphinView::DetailsView); -} - -void DolphinMainWindow::sortByName() -{ - m_activeView->setSorting(DolphinView::SortByName); -} - -void DolphinMainWindow::sortBySize() -{ - m_activeView->setSorting(DolphinView::SortBySize); -} - -void DolphinMainWindow::sortByDate() -{ - m_activeView->setSorting(DolphinView::SortByDate); -} - -void DolphinMainWindow::toggleSortOrder() -{ - const Qt::SortOrder order = (m_activeView->sortOrder() == Qt::Ascending) ? - Qt::Descending : - Qt::Ascending; - m_activeView->setSortOrder(order); + m_activeViewContainer->view()->invertSelection(); } void DolphinMainWindow::toggleSplitView() { - if (m_view[SecondaryIdx] == 0) { - const int newWidth = (m_view[PrimaryIdx]->width() - m_splitter->handleWidth()) / 2; + if (m_viewTab[m_tabIndex].secondaryView == 0) { // create a secondary view - m_view[SecondaryIdx] = new DolphinView(this, - 0, - m_view[PrimaryIdx]->url(), - m_view[PrimaryIdx]->mode(), - m_view[PrimaryIdx]->showHiddenFiles()); - connectViewSignals(SecondaryIdx); - m_splitter->addWidget(m_view[SecondaryIdx]); - m_splitter->setSizes(QList() << newWidth << newWidth); - m_view[SecondaryIdx]->show(); - } - else { + QSplitter* splitter = m_viewTab[m_tabIndex].splitter; + const int newWidth = (m_viewTab[m_tabIndex].primaryView->width() - splitter->handleWidth()) / 2; + + const DolphinView* view = m_viewTab[m_tabIndex].primaryView->view(); + m_viewTab[m_tabIndex].secondaryView = new DolphinViewContainer(this, 0, view->rootUrl()); + connectViewSignals(m_viewTab[m_tabIndex].secondaryView); + splitter->addWidget(m_viewTab[m_tabIndex].secondaryView); + splitter->setSizes(QList() << newWidth << newWidth); + m_viewTab[m_tabIndex].secondaryView->view()->reload(); + m_viewTab[m_tabIndex].secondaryView->setActive(false); + m_viewTab[m_tabIndex].secondaryView->show(); + + setActiveViewContainer(m_viewTab[m_tabIndex].secondaryView); + } else if (m_activeViewContainer == m_viewTab[m_tabIndex].secondaryView) { // remove secondary view - if (m_activeView == m_view[PrimaryIdx]) { - m_view[SecondaryIdx]->close(); - m_view[SecondaryIdx]->deleteLater(); - m_view[SecondaryIdx] = 0; - setActiveView(m_view[PrimaryIdx]); - } - else { - // The secondary view is active, hence from the 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_view[PrimaryIdx]->close(); - delete m_view[PrimaryIdx]; - m_view[PrimaryIdx] = m_view[SecondaryIdx]; - m_view[SecondaryIdx] = 0; - setActiveView(m_view[PrimaryIdx]); - } + m_viewTab[m_tabIndex].secondaryView->close(); + m_viewTab[m_tabIndex].secondaryView->deleteLater(); + m_viewTab[m_tabIndex].secondaryView = 0; + + 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); } + + updateViewActions(); } void DolphinMainWindow::reloadView() { clearStatusBar(); - m_activeView->reload(); + m_activeViewContainer->view()->reload(); } void DolphinMainWindow::stopLoading() { } -void DolphinMainWindow::togglePreview() -{ - clearStatusBar(); - - const KToggleAction* showPreviewAction = - static_cast(actionCollection()->action("show_preview")); - const bool show = showPreviewAction->isChecked(); - m_activeView->setShowPreview(show); -} - -void DolphinMainWindow::toggleShowHiddenFiles() -{ - clearStatusBar(); - - const KToggleAction* showHiddenFilesAction = - static_cast(actionCollection()->action("show_hidden_files")); - const bool show = showHiddenFilesAction->isChecked(); - m_activeView->setShowHiddenFiles(show); -} - -void DolphinMainWindow::showFilterBar() -{ - const KToggleAction* showFilterBarAction = - static_cast(actionCollection()->action("show_filter_bar")); - const bool show = showFilterBarAction->isChecked(); - m_activeView->slotShowFilterBar(show); -} - -void DolphinMainWindow::zoomIn() -{ - m_activeView->zoomIn(); - updateViewActions(); -} - -void DolphinMainWindow::zoomOut() +void DolphinMainWindow::toggleFilterBarVisibility(bool show) { - m_activeView->zoomOut(); - updateViewActions(); + m_activeViewContainer->showFilterBar(show); } void DolphinMainWindow::toggleEditLocation() { clearStatusBar(); - KToggleAction* action = static_cast(actionCollection()->action("editable_location")); - - bool editOrBrowse = action->isChecked(); -// action->setChecked(action->setChecked); - m_activeView->setUrlEditable(editOrBrowse); + QAction* action = actionCollection()->action("editable_location"); + KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator(); + urlNavigator->setUrlEditable(action->isChecked()); } -void DolphinMainWindow::editLocation() +void DolphinMainWindow::replaceLocation() { - KToggleAction* action = static_cast(actionCollection()->action("editable_location")); - action->setChecked(true); - m_activeView->setUrlEditable(true); -} + KUrlNavigator* navigator = m_activeViewContainer->urlNavigator(); + navigator->setUrlEditable(true); + navigator->setFocus(); -void DolphinMainWindow::adjustViewProperties() -{ - clearStatusBar(); - ViewPropertiesDialog dlg(m_activeView); - dlg.exec(); + // select the whole text of the combo box editor + QLineEdit* lineEdit = navigator->editor()->lineEdit(); + const QString text = lineEdit->text(); + lineEdit->setSelection(0, text.length()); } void DolphinMainWindow::goBack() { clearStatusBar(); - m_activeView->goBack(); + m_activeViewContainer->urlNavigator()->goBack(); } void DolphinMainWindow::goForward() { clearStatusBar(); - m_activeView->goForward(); + m_activeViewContainer->urlNavigator()->goForward(); } void DolphinMainWindow::goUp() { clearStatusBar(); - m_activeView->goUp(); + m_activeViewContainer->urlNavigator()->goUp(); } void DolphinMainWindow::goHome() { clearStatusBar(); - m_activeView->goHome(); -} - -void DolphinMainWindow::openTerminal() -{ - QString command("konsole --workdir \""); - command.append(m_activeView->url().path()); - command.append('\"'); - - KRun::runCommand(command, "Konsole", "konsole"); -} - -void DolphinMainWindow::findFile() -{ - KRun::run("kfind", m_activeView->url()); + m_activeViewContainer->urlNavigator()->goHome(); } void DolphinMainWindow::compareFiles() @@ -946,42 +629,42 @@ void DolphinMainWindow::compareFiles() // - both in the secondary view // - one in the primary view and the other in the secondary // view - assert(m_view[PrimaryIdx] != 0); + Q_ASSERT(m_viewTab[m_tabIndex].primaryView != 0); KUrl urlA; KUrl urlB; - KUrl::List urls = m_view[PrimaryIdx]->selectedUrls(); + KUrl::List urls = m_viewTab[m_tabIndex].primaryView->view()->selectedUrls(); switch (urls.count()) { - case 0: { - assert(m_view[SecondaryIdx] != 0); - urls = m_view[SecondaryIdx]->selectedUrls(); - assert(urls.count() == 2); - urlA = urls[0]; - urlB = urls[1]; - break; - } + case 0: { + Q_ASSERT(m_viewTab[m_tabIndex].secondaryView != 0); + urls = m_viewTab[m_tabIndex].secondaryView->view()->selectedUrls(); + Q_ASSERT(urls.count() == 2); + urlA = urls[0]; + urlB = urls[1]; + break; + } - case 1: { - urlA = urls[0]; - assert(m_view[SecondaryIdx] != 0); - urls = m_view[SecondaryIdx]->selectedUrls(); - assert(urls.count() == 1); - urlB = urls[0]; - break; - } + case 1: { + urlA = urls[0]; + Q_ASSERT(m_viewTab[m_tabIndex].secondaryView != 0); + urls = m_viewTab[m_tabIndex].secondaryView->view()->selectedUrls(); + Q_ASSERT(urls.count() == 1); + urlB = urls[0]; + break; + } - case 2: { - urlA = urls[0]; - urlB = urls[1]; - break; - } + case 2: { + urlA = urls[0]; + urlB = urls[1]; + break; + } - default: { - // may not happen: compareFiles may only get invoked if 2 - // files are selected - assert(false); - } + default: { + // may not happen: compareFiles may only get invoked if 2 + // files are selected + Q_ASSERT(false); + } } QString command("kompare -c \""); @@ -989,64 +672,218 @@ void DolphinMainWindow::compareFiles() command.append("\" \""); command.append(urlB.pathOrUrl()); command.append('\"'); - KRun::runCommand(command, "Kompare", "kompare"); + KRun::runCommand(command, "Kompare", "kompare", this); +} + +void DolphinMainWindow::quickView() +{ + const KUrl::List urls = activeViewContainer()->view()->selectedUrls(); + Q_ASSERT(urls.count() > 0); + + QDBusMessage msg = QDBusMessage::createMethodCall("org.kde.plasma", "/Previewer", "", "openFile"); + foreach (const KUrl& url, urls) { + msg.setArguments(QList() << url.prettyUrl()); + QDBusConnection::sessionBus().send(msg); + } +} +void DolphinMainWindow::toggleShowMenuBar() +{ + const bool visible = menuBar()->isVisible(); + menuBar()->setVisible(!visible); } void DolphinMainWindow::editSettings() { - // TODO: make a static method for opening the settings dialog - DolphinSettingsDialog dlg(this); - dlg.exec(); + DolphinSettingsDialog dialog(this); + dialog.exec(); +} + +void DolphinMainWindow::setActiveTab(int index) +{ + Q_ASSERT(index >= 0); + Q_ASSERT(index < m_viewTab.count()); + if (index == m_tabIndex) { + return; + } + + // hide current tab content + m_viewTab[m_tabIndex].isPrimaryViewActive = m_viewTab[m_tabIndex].primaryView->isActive(); + 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); + viewTab.primaryView->show(); + if (viewTab.secondaryView != 0) { + viewTab.secondaryView->show(); + } + viewTab.splitter->show(); + + setActiveViewContainer(viewTab.isPrimaryViewActive ? viewTab.primaryView : + viewTab.secondaryView); +} + +void DolphinMainWindow::closeTab() +{ + closeTab(m_tabBar->currentIndex()); +} + +void DolphinMainWindow::closeTab(int index) +{ + Q_ASSERT(index >= 0); + Q_ASSERT(index < m_viewTab.count()); + if (m_viewTab.count() == 1) { + // the last tab may never get closed + return; + } + + if (index == m_tabIndex) { + // The tab that should be closed is the active tab. Activate the + // previous tab before closing the tab. + m_tabBar->setCurrentIndex((index > 0) ? index - 1 : 1); + } + + // delete tab + m_viewTab[index].primaryView->deleteLater(); + if (m_viewTab[index].secondaryView != 0) { + m_viewTab[index].secondaryView->deleteLater(); + } + m_viewTab[index].splitter->deleteLater(); + m_viewTab.erase(m_viewTab.begin() + index); + + m_tabBar->blockSignals(true); + m_tabBar->removeTab(index); + + if (m_tabIndex > index) { + m_tabIndex--; + Q_ASSERT(m_tabIndex >= 0); + } + + // if only one tab is left, also remove the tab entry so that + // closing the last tab is not possible + if (m_viewTab.count() == 1) { + m_tabBar->removeTab(0); + actionCollection()->action("close_tab")->setEnabled(false); + } else { + m_tabBar->blockSignals(false); + } +} + +void DolphinMainWindow::openTabContextMenu(int index, const QPoint& pos) +{ + KMenu menu(this); + + QAction* newTabAction = menu.addAction(KIcon("tab-new"), i18nc("@action:inmenu", "New Tab")); + newTabAction->setShortcut(actionCollection()->action("new_tab")->shortcut()); + + QAction* closeOtherTabsAction = menu.addAction(KIcon("tab-close-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 ViewTab& tab = m_viewTab[index]; + Q_ASSERT(tab.primaryView != 0); + const KUrl url = (tab.secondaryView != 0) && tab.secondaryView->isActive() ? + tab.secondaryView->url() : tab.primaryView->url(); + openNewTab(url); + m_tabBar->setCurrentIndex(m_viewTab.count() - 1); + } else if (selectedAction == closeOtherTabsAction) { + const int count = m_tabBar->count(); + for (int i = 0; i < index; ++i) { + closeTab(0); + } + for (int i = index + 1; i < count; ++i) { + closeTab(1); + } + } else if (selectedAction == closeTabAction) { + closeTab(index); + } +} + +void DolphinMainWindow::handlePlacesClick(const KUrl& url, Qt::MouseButtons buttons) +{ + if (buttons & Qt::MidButton) { + openNewTab(url); + m_tabBar->setCurrentIndex(m_viewTab.count() - 1); + } else { + changeUrl(url); + } +} + +void DolphinMainWindow::slotTestCanDecode(const QDragMoveEvent* event, bool& canDecode) +{ + canDecode = KUrl::List::canDecode(event->mimeData()); } void DolphinMainWindow::init() { + DolphinSettings& settings = DolphinSettings::instance(); + // Check whether Dolphin runs the first time. If yes then // a proper default window size is given at the end of DolphinMainWindow::init(). - GeneralSettings* generalSettings = DolphinSettings::instance().generalSettings(); + GeneralSettings* generalSettings = settings.generalSettings(); const bool firstRun = generalSettings->firstRun(); + if (firstRun) { + generalSettings->setViewPropsTimestamp(QDateTime::currentDateTime()); + } setAcceptDrops(true); - m_splitter = new QSplitter(this); - - DolphinSettings& settings = DolphinSettings::instance(); - - KBookmarkManager* manager = settings.bookmarkManager(); - assert(manager != 0); - KBookmarkGroup root = manager->root(); - if (root.first().isNull()) { - root.addBookmark(manager, i18n("Home"), settings.generalSettings()->homeUrl(), "folder_home"); - root.addBookmark(manager, i18n("Storage Media"), KUrl("media:/"), "blockdevice"); - root.addBookmark(manager, i18n("Network"), KUrl("remote:/"), "network_local"); - root.addBookmark(manager, i18n("Root"), KUrl("/"), "folder_red"); - root.addBookmark(manager, i18n("Trash"), KUrl("trash:/"), "trashcan_full"); - } + m_viewTab[m_tabIndex].splitter = new QSplitter(this); setupActions(); - const KUrl& homeUrl = root.first().url(); + const KUrl& homeUrl = generalSettings->homeUrl(); setCaption(homeUrl.fileName()); + m_actionHandler = new DolphinViewActionHandler(actionCollection(), this); + connect(m_actionHandler, SIGNAL(actionBeingHandled()), SLOT(clearStatusBar())); ViewProperties props(homeUrl); - m_view[PrimaryIdx] = new DolphinView(this, - m_splitter, - homeUrl, - props.viewMode(), - props.showHiddenFiles()); - connectViewSignals(PrimaryIdx); - m_view[PrimaryIdx]->show(); - - m_activeView = m_view[PrimaryIdx]; - - setCentralWidget(m_splitter); + m_viewTab[m_tabIndex].primaryView = new DolphinViewContainer(this, + m_viewTab[m_tabIndex].splitter, + homeUrl); + + m_activeViewContainer = m_viewTab[m_tabIndex].primaryView; + connectViewSignals(m_activeViewContainer); + DolphinView* view = m_activeViewContainer->view(); + view->reload(); + m_activeViewContainer->show(); + m_actionHandler->setCurrentView(view); + + m_tabBar = new KTabBar(this); + m_tabBar->setCloseButtonEnabled(true); + connect(m_tabBar, SIGNAL(currentChanged(int)), + this, SLOT(setActiveTab(int))); + connect(m_tabBar, SIGNAL(closeRequest(int)), + this, SLOT(closeTab(int))); + connect(m_tabBar, SIGNAL(contextMenu(int, const QPoint&)), + this, SLOT(openTabContextMenu(int, const QPoint&))); + connect(m_tabBar, SIGNAL(newTabRequest()), + this, SLOT(openNewTab())); + connect(m_tabBar, SIGNAL(testCanDecode(const QDragMoveEvent*, bool&)), + this, SLOT(slotTestCanDecode(const QDragMoveEvent*, bool&))); + m_tabBar->blockSignals(true); // signals get unblocked after at least 2 tabs are open + + 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(m_viewTab[m_tabIndex].splitter); + + setCentralWidget(centralWidget); setupDockWidgets(); + emit urlChanged(homeUrl); - setupGUI(Keys|Save|Create|ToolBar); - createGUI(); + setupGUI(Keys | Save | Create | ToolBar); stateChanged("new_file"); - setAutoSaveSettings(); QClipboard* clipboard = QApplication::clipboard(); connect(clipboard, SIGNAL(dataChanged()), @@ -1054,486 +891,424 @@ void DolphinMainWindow::init() updatePasteAction(); updateGoActions(); - setupCreateNewMenuActions(); + if (generalSettings->splitView()) { + toggleSplitView(); + } + updateViewActions(); - loadSettings(); + QAction* showFilterBarAction = actionCollection()->action("show_filter_bar"); + showFilterBarAction->setChecked(generalSettings->filterBar()); if (firstRun) { // assure a proper default size if Dolphin runs the first time - resize(640, 480); + resize(750, 500); } + + m_showMenuBar->setChecked(!menuBar()->isHidden()); // workaround for bug #171080 } -void DolphinMainWindow::loadSettings() +void DolphinMainWindow::setActiveViewContainer(DolphinViewContainer* viewContainer) { - GeneralSettings* settings = DolphinSettings::instance().generalSettings(); - - KToggleAction* splitAction = static_cast(actionCollection()->action("split_view")); - if (settings->splitView()) { - splitAction->setChecked(true); - toggleSplitView(); + Q_ASSERT(viewContainer != 0); + Q_ASSERT((viewContainer == m_viewTab[m_tabIndex].primaryView) || + (viewContainer == m_viewTab[m_tabIndex].secondaryView)); + 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(), SIGNAL(activated()), this, SLOT(toggleActiveView())); + m_activeViewContainer->setActive(true); + connect(m_activeViewContainer->view(), SIGNAL(activated()), this, SLOT(toggleActiveView())); + + m_actionHandler->setCurrentView(viewContainer->view()); + + updateHistory(); + updateEditActions(); updateViewActions(); + updateGoActions(); - // TODO: I assume there will be a generic way in KDE 4 to restore the docks - // of the main window. In the meantime they are restored manually (see also - // DolphinMainWindow::closeEvent() for more details): - QString filename = KStandardDirs::locateLocal("data", KGlobal::instance()->instanceName()); - filename.append("/panels_layout"); - QFile file(filename); - if (file.open(QIODevice::ReadOnly)) { - QByteArray data = file.readAll(); - restoreState(data); - file.close(); + const KUrl& url = m_activeViewContainer->url(); + setCaption(url.fileName()); + if (m_viewTab.count() > 1) { + m_tabBar->setTabText(m_tabIndex, tabName(url)); } + + emit urlChanged(url); } void DolphinMainWindow::setupActions() { // setup 'File' menu - QAction *action = actionCollection()->addAction("new_window"); - action->setIcon(KIcon("window_new")); - action->setText(i18n("New &Window")); - connect(action, SIGNAL(triggered()), this, SLOT(openNewMainWindow())); - - QAction* createFolder = actionCollection()->addAction("create_folder"); - createFolder->setText(i18n("Folder...")); - createFolder->setIcon(KIcon("folder")); - createFolder->setShortcut(Qt::Key_N); - connect(createFolder, SIGNAL(triggered()), this, SLOT(createFolder())); - - QAction* rename = actionCollection()->addAction("rename"); - rename->setText(i18n("Rename")); - rename->setShortcut(Qt::Key_F2); - connect(rename, SIGNAL(triggered()), this, SLOT(rename())); - - QAction* moveToTrash = actionCollection()->addAction("move_to_trash"); - moveToTrash->setText(i18n("Move to Trash")); - moveToTrash->setIcon(KIcon("edittrash")); - moveToTrash->setShortcut(QKeySequence::Delete); - connect(moveToTrash, SIGNAL(triggered()), this, SLOT(moveToTrash())); - - QAction* deleteAction = actionCollection()->addAction("delete"); - deleteAction->setText(i18n("Delete")); - deleteAction->setShortcut(Qt::ALT | Qt::Key_Delete); - deleteAction->setIcon(KIcon("editdelete")); - connect(deleteAction, SIGNAL(triggered()), this, SLOT(deleteItems())); - - QAction* properties = actionCollection()->addAction("properties"); - properties->setText(i18n("Propert&ies")); - properties->setShortcut(Qt::Key_Alt | Qt::Key_Return); - connect(properties, SIGNAL(triggered()), this, SLOT(properties())); + m_newMenu = new DolphinNewMenu(this, this); + KMenu* menu = m_newMenu->menu(); + menu->setTitle(i18nc("@title:menu Create new folder, file, link, etc.", "Create New")); + menu->setIcon(KIcon("document-new")); + connect(menu, SIGNAL(aboutToShow()), + this, SLOT(updateNewMenu())); + + KAction* newWindow = actionCollection()->addAction("new_window"); + newWindow->setIcon(KIcon("window-new")); + newWindow->setText(i18nc("@action:inmenu File", "New &Window")); + newWindow->setShortcut(Qt::CTRL | Qt::Key_N); + connect(newWindow, SIGNAL(triggered()), this, SLOT(openNewMainWindow())); + + KAction* newTab = actionCollection()->addAction("new_tab"); + newTab->setIcon(KIcon("tab-new")); + newTab->setText(i18nc("@action:inmenu File", "New Tab")); + newTab->setShortcut(KShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_N, Qt::CTRL | Qt::Key_T)); + connect(newTab, SIGNAL(triggered()), this, SLOT(openNewTab())); + + QAction* closeTab = new QAction(KIcon("tab-close"), i18nc("@action:inmenu File", "Close Tab"), this); + closeTab->setShortcut(Qt::CTRL | Qt::Key_W); + closeTab->setEnabled(false); + connect(closeTab, SIGNAL(triggered()), this, SLOT(closeTab())); + actionCollection()->addAction("close_tab", closeTab); KStandardAction::quit(this, SLOT(quit()), actionCollection()); // setup 'Edit' menu - KStandardAction::undo(KonqUndoManager::self(), + KStandardAction::undo(this, SLOT(undo()), actionCollection()); - KStandardAction::cut(this, SLOT(cut()), actionCollection()); + // need to remove shift+del from cut action, else the shortcut for deletejob + // doesn't work + KAction* cut = KStandardAction::cut(this, SLOT(cut()), actionCollection()); + KShortcut cutShortcut = cut->shortcut(); + cutShortcut.remove(Qt::SHIFT + Qt::Key_Delete, KShortcut::KeepEmpty); + cut->setShortcut(cutShortcut); KStandardAction::copy(this, SLOT(copy()), actionCollection()); KStandardAction::paste(this, SLOT(paste()), actionCollection()); - QAction* selectAll = actionCollection()->addAction("select_all"); - selectAll->setText(i18n("Select All")); + KAction* selectAll = actionCollection()->addAction("select_all"); + selectAll->setText(i18nc("@action:inmenu Edit", "Select All")); selectAll->setShortcut(Qt::CTRL + Qt::Key_A); connect(selectAll, SIGNAL(triggered()), this, SLOT(selectAll())); - QAction* invertSelection = actionCollection()->addAction("invert_selection"); - invertSelection->setText(i18n("Invert Selection")); + KAction* invertSelection = actionCollection()->addAction("invert_selection"); + invertSelection->setText(i18nc("@action:inmenu Edit", "Invert Selection")); invertSelection->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_A); connect(invertSelection, SIGNAL(triggered()), this, SLOT(invertSelection())); // setup 'View' menu - KStandardAction::zoomIn(this, - SLOT(zoomIn()), - actionCollection()); - - KStandardAction::zoomOut(this, - SLOT(zoomOut()), - actionCollection()); - - KToggleAction* iconsView = actionCollection()->add("icons"); - iconsView->setText(i18n("Icons")); - iconsView->setShortcut(Qt::CTRL | Qt::Key_1); - iconsView->setIcon(KIcon("view_icon")); - connect(iconsView, SIGNAL(triggered()), this, SLOT(setIconsView())); - - KToggleAction* detailsView = actionCollection()->add("details"); - detailsView->setText(i18n("Details")); - detailsView->setShortcut(Qt::CTRL | Qt::Key_2); - detailsView->setIcon(KIcon("view_text")); - connect(detailsView, SIGNAL(triggered()), this, SLOT(setDetailsView())); - - QActionGroup* viewModeGroup = new QActionGroup(this); - viewModeGroup->addAction(iconsView); - viewModeGroup->addAction(detailsView); - - KToggleAction* sortByName = actionCollection()->add("by_name"); - sortByName->setText(i18n("By Name")); - connect(sortByName, SIGNAL(triggered()), this, SLOT(sortByName())); - - KToggleAction* sortBySize = actionCollection()->add("by_size"); - sortBySize->setText(i18n("By Size")); - connect(sortBySize, SIGNAL(triggered()), this, SLOT(sortBySize())); - - KToggleAction* sortByDate = actionCollection()->add("by_date"); - sortByDate->setText(i18n("By Date")); - connect(sortByDate, SIGNAL(triggered()), this, SLOT(sortByDate())); - - QActionGroup* sortGroup = new QActionGroup(this); - sortGroup->addAction(sortByName); - sortGroup->addAction(sortBySize); - sortGroup->addAction(sortByDate); - - KToggleAction* sortDescending = actionCollection()->add("descending"); - sortDescending->setText(i18n("Descending")); - connect(sortDescending, SIGNAL(triggered()), this, SLOT(toggleSortOrder())); - - KToggleAction* showPreview = actionCollection()->add("show_preview"); - showPreview->setText(i18n("Show Preview")); - connect(showPreview, SIGNAL(triggered()), this, SLOT(togglePreview())); - - KToggleAction* showHiddenFiles = actionCollection()->add("show_hidden_files"); - showHiddenFiles->setText(i18n("Show Hidden Files")); - //showHiddenFiles->setShortcut(Qt::ALT | Qt::Key_ KDE4-TODO: what Qt-Key represents '.'? - connect(showHiddenFiles, SIGNAL(triggered()), this, SLOT(toggleShowHiddenFiles())); - - KToggleAction* split = actionCollection()->add("split_view"); - split->setText(i18n("Split View")); - split->setShortcut(Qt::Key_F10); - split->setIcon(KIcon("view_left_right")); + // (note that most of it is set up in DolphinViewActionHandler) + + KAction* split = actionCollection()->addAction("split_view"); + split->setShortcut(Qt::Key_F3); + updateSplitAction(); connect(split, SIGNAL(triggered()), this, SLOT(toggleSplitView())); - QAction* reload = actionCollection()->addAction("reload"); - reload->setText(i18n("Reload")); + KAction* reload = actionCollection()->addAction("reload"); + reload->setText(i18nc("@action:inmenu View", "Reload")); reload->setShortcut(Qt::Key_F5); - reload->setIcon(KIcon("reload")); + reload->setIcon(KIcon("view-refresh")); connect(reload, SIGNAL(triggered()), this, SLOT(reloadView())); - QAction* stop = actionCollection()->addAction("stop"); - stop->setText(i18n("Stop")); - stop->setIcon(KIcon("stop")); + KAction* stop = actionCollection()->addAction("stop"); + stop->setText(i18nc("@action:inmenu View", "Stop")); + stop->setIcon(KIcon("process-stop")); connect(stop, SIGNAL(triggered()), this, SLOT(stopLoading())); KToggleAction* showFullLocation = actionCollection()->add("editable_location"); - showFullLocation->setText(i18n("Show Full Location")); + showFullLocation->setText(i18nc("@action:inmenu Navigation Bar", "Editable Location")); showFullLocation->setShortcut(Qt::CTRL | Qt::Key_L); connect(showFullLocation, SIGNAL(triggered()), this, SLOT(toggleEditLocation())); - KToggleAction* editLocation = actionCollection()->add("edit_location"); - editLocation->setText(i18n("Edit Location")); - editLocation->setShortcut(Qt::Key_F6); - connect(editLocation, SIGNAL(triggered()), this, SLOT(editLocation())); - - QAction* adjustViewProps = actionCollection()->addAction("view_properties"); - adjustViewProps->setText(i18n("Adjust View Properties...")); - connect(adjustViewProps, SIGNAL(triggered()), this, SLOT(adjustViewProperties())); + KAction* replaceLocation = actionCollection()->addAction("replace_location"); + replaceLocation->setText(i18nc("@action:inmenu Navigation Bar", "Replace Location")); + replaceLocation->setShortcut(Qt::Key_F6); + connect(replaceLocation, SIGNAL(triggered()), this, SLOT(replaceLocation())); // setup 'Go' menu - KStandardAction::back(this, SLOT(goBack()), actionCollection()); + KAction* backAction = KStandardAction::back(this, SLOT(goBack()), actionCollection()); + KShortcut backShortcut = backAction->shortcut(); + backShortcut.setAlternate(Qt::Key_Backspace); + backAction->setShortcut(backShortcut); + KStandardAction::forward(this, SLOT(goForward()), actionCollection()); KStandardAction::up(this, SLOT(goUp()), actionCollection()); KStandardAction::home(this, SLOT(goHome()), actionCollection()); // setup 'Tools' menu - QAction* openTerminal = actionCollection()->addAction("open_terminal"); - openTerminal->setText(i18n("Open Terminal")); - openTerminal->setShortcut(Qt::Key_F4); - openTerminal->setIcon(KIcon("konsole")); - connect(openTerminal, SIGNAL(triggered()), this, SLOT(openTerminal())); - - QAction* findFile = actionCollection()->addAction("find_file"); - findFile->setText(i18n("Find File...")); - findFile->setShortcut(Qt::Key_F); - findFile->setIcon(KIcon("filefind")); - connect(findFile, SIGNAL(triggered()), this, SLOT(findFile())); - KToggleAction* showFilterBar = actionCollection()->add("show_filter_bar"); - showFilterBar->setText(i18n("Show Filter Bar")); - showFilterBar->setShortcut(Qt::Key_Slash); - connect(showFilterBar, SIGNAL(triggered()), this, SLOT(showFilterBar())); + showFilterBar->setText(i18nc("@action:inmenu Tools", "Show Filter Bar")); + showFilterBar->setShortcut(Qt::CTRL | Qt::Key_I); + connect(showFilterBar, SIGNAL(triggered(bool)), this, SLOT(toggleFilterBarVisibility(bool))); - QAction* compareFiles = actionCollection()->addAction("compare_files"); - compareFiles->setText(i18n("Compare Files")); + KAction* compareFiles = actionCollection()->addAction("compare_files"); + compareFiles->setText(i18nc("@action:inmenu Tools", "Compare Files")); compareFiles->setIcon(KIcon("kompare")); compareFiles->setEnabled(false); connect(compareFiles, SIGNAL(triggered()), this, SLOT(compareFiles())); + KAction* quickView = actionCollection()->addAction("quick_view"); + quickView->setText(i18nc("@action:inmenu Tools", "Quick View")); + quickView->setIcon(KIcon("view-preview")); + quickView->setShortcut(Qt::CTRL + Qt::Key_Return); + quickView->setEnabled(false); + connect(quickView, SIGNAL(triggered()), this, SLOT(quickView())); + // setup 'Settings' menu + m_showMenuBar = KStandardAction::showMenubar(this, SLOT(toggleShowMenuBar()), actionCollection()); KStandardAction::preferences(this, SLOT(editSettings()), actionCollection()); + + // not in menu actions + KAction* activateNextTab = actionCollection()->addAction("activatenexttab"); + activateNextTab->setText(i18nc("@action:inmenu", "Activate Next Tab")); + connect(activateNextTab, SIGNAL(triggered()), SLOT(activateNextTab())); + activateNextTab->setShortcuts(QApplication::isRightToLeft() ? KStandardShortcut::tabPrev() : + KStandardShortcut::tabNext()); + + KAction* activatePrevTab = actionCollection()->addAction("activateprevtab"); + activatePrevTab->setText(i18nc("@action:inmenu", "Activate Previous Tab")); + connect(activatePrevTab, SIGNAL(triggered()), SLOT(activatePrevTab())); + activatePrevTab->setShortcuts(QApplication::isRightToLeft() ? KStandardShortcut::tabNext() : + KStandardShortcut::tabPrev()); + + // for context menu + KAction* openInNewTab = actionCollection()->addAction("open_in_new_tab"); + openInNewTab->setText(i18nc("@action:inmenu", "Open in New Tab")); + openInNewTab->setIcon(KIcon("tab-new")); + connect(openInNewTab, SIGNAL(triggered()), this, SLOT(openInNewTab())); + + KAction* openInNewWindow = actionCollection()->addAction("open_in_new_window"); + openInNewWindow->setText(i18nc("@action:inmenu", "Open in New Window")); + openInNewWindow->setIcon(KIcon("window-new")); + connect(openInNewWindow, SIGNAL(triggered()), this, SLOT(openInNewWindow())); } void DolphinMainWindow::setupDockWidgets() { - QDockWidget* shortcutsDock = new QDockWidget(i18n("Bookmarks")); - shortcutsDock->setObjectName("bookmarksDock"); - shortcutsDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); - shortcutsDock->setWidget(new BookmarksSidebarPage(this)); - - shortcutsDock->toggleViewAction()->setText(i18n("Show Bookmarks Panel")); - actionCollection()->addAction("show_bookmarks_panel", shortcutsDock->toggleViewAction()); - - addDockWidget(Qt::LeftDockWidgetArea, shortcutsDock); - - QDockWidget* infoDock = new QDockWidget(i18n("Information")); + // setup "Information" + QDockWidget* infoDock = new QDockWidget(i18nc("@title:window", "Information")); infoDock->setObjectName("infoDock"); infoDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); - infoDock->setWidget(new InfoSidebarPage(this)); + SidebarPage* infoWidget = new InfoSidebarPage(infoDock); + infoDock->setWidget(infoWidget); - infoDock->toggleViewAction()->setText(i18n("Show Information Panel")); + infoDock->toggleViewAction()->setText(i18nc("@title:window", "Information")); + infoDock->toggleViewAction()->setShortcut(Qt::Key_F11); actionCollection()->addAction("show_info_panel", infoDock->toggleViewAction()); addDockWidget(Qt::RightDockWidgetArea, infoDock); -} - -void DolphinMainWindow::setupCreateNewMenuActions() -{ - // Parts of the following code have been taken - // from the class KNewMenu located in - // libqonq/knewmenu.h of Konqueror. - // Copyright (C) 1998, 1999 David Faure - // 2003 Sven Leiber - - QStringList files = actionCollection()->instance()->dirs()->findAllResources("templates"); - for (QStringList::Iterator it = files.begin() ; it != files.end(); ++it) { - if ((*it)[0] != '.' ) { - KSimpleConfig config(*it, true); - config.setDesktopGroup(); - - // tricky solution to ensure that TextFile is at the beginning - // because this filetype is the most used (according kde-core discussion) - const QString name(config.readEntry("Name")); - QString key(name); - - const QString path(config.readPathEntry("Url")); - if (!path.endsWith("emptydir")) { - if (path.endsWith("TextFile.txt")) { - key = "1" + key; - } - else if (!KDesktopFile::isDesktopFile(path)) { - key = "2" + key; - } - else if (path.endsWith("Url.desktop")){ - key = "3" + key; - } - else if (path.endsWith("Program.desktop")){ - key = "4" + key; - } - else { - key = "5"; - } - - const QString icon(config.readEntry("Icon")); - const QString comment(config.readEntry("Comment")); - const QString type(config.readEntry("Type")); - - const QString filePath(*it); - - - if (type == "Link") { - CreateFileEntry entry; - entry.name = name; - entry.icon = icon; - entry.comment = comment; - entry.templatePath = filePath; - m_createFileTemplates.insert(key, entry); - } - } - } - } - m_createFileTemplates.sort(); - - unplugActionList("create_actions"); - KSortableList::ConstIterator it = m_createFileTemplates.begin(); - KSortableList::ConstIterator end = m_createFileTemplates.end(); - /* KDE4-TODO: don't port this code; use KNewMenu instead - while (it != end) { - CreateFileEntry entry = (*it).value(); - KAction* action = new KAction(entry.name); - action->setIcon(entry.icon); - action->setName((*it).index()); - connect(action, SIGNAL(activated()), - this, SLOT(createFile())); - - const QChar section = ((*it).index()[0]); - switch (section) { - case '1': - case '2': { - m_fileGroupActions.append(action); - break; - } - - case '3': - case '4': { - // TODO: not used yet. See documentation of DolphinMainWindow::linkGroupActions() - // and DolphinMainWindow::linkToDeviceActions() in the header file for details. - //m_linkGroupActions.append(action); - break; - } - - case '5': { - // TODO: not used yet. See documentation of DolphinMainWindow::linkGroupActions() - // and DolphinMainWindow::linkToDeviceActions() in the header file for details. - //m_linkToDeviceActions.append(action); - break; - } - default: - break; - } - ++it; + connect(this, SIGNAL(urlChanged(KUrl)), + infoWidget, SLOT(setUrl(KUrl))); + connect(this, SIGNAL(selectionChanged(KFileItemList)), + infoWidget, SLOT(setSelection(KFileItemList))); + connect(this, SIGNAL(requestItemInfo(KFileItem)), + infoWidget, SLOT(requestDelayedItemInfo(KFileItem))); + + // setup "Tree View" + QDockWidget* treeViewDock = new QDockWidget(i18nc("@title:window", "Folders")); + treeViewDock->setObjectName("treeViewDock"); + treeViewDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); + TreeViewSidebarPage* treeWidget = new TreeViewSidebarPage(treeViewDock); + treeViewDock->setWidget(treeWidget); + + treeViewDock->toggleViewAction()->setText(i18nc("@title:window", "Folders")); + treeViewDock->toggleViewAction()->setShortcut(Qt::Key_F7); + actionCollection()->addAction("show_folders_panel", treeViewDock->toggleViewAction()); + + addDockWidget(Qt::LeftDockWidgetArea, treeViewDock); + connect(this, SIGNAL(urlChanged(KUrl)), + treeWidget, SLOT(setUrl(KUrl))); + connect(treeWidget, SIGNAL(changeUrl(KUrl, Qt::MouseButtons)), + this, SLOT(handlePlacesClick(KUrl, Qt::MouseButtons))); + connect(treeWidget, SIGNAL(changeSelection(KFileItemList)), + this, SLOT(changeSelection(KFileItemList))); + + // setup "Terminal" +#ifndef Q_OS_WIN + QDockWidget* terminalDock = new QDockWidget(i18nc("@title:window Shell terminal", "Terminal")); + terminalDock->setObjectName("terminalDock"); + terminalDock->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea); + SidebarPage* terminalWidget = new TerminalSidebarPage(terminalDock); + terminalDock->setWidget(terminalWidget); + + connect(terminalWidget, SIGNAL(hideTerminalSidebarPage()), terminalDock, SLOT(hide())); + + terminalDock->toggleViewAction()->setText(i18nc("@title:window Shell terminal", "Terminal")); + terminalDock->toggleViewAction()->setShortcut(Qt::Key_F4); + actionCollection()->addAction("show_terminal_panel", terminalDock->toggleViewAction()); + + addDockWidget(Qt::BottomDockWidgetArea, terminalDock); + connect(this, SIGNAL(urlChanged(KUrl)), + terminalWidget, SLOT(setUrl(KUrl))); +#endif + + const bool firstRun = DolphinSettings::instance().generalSettings()->firstRun(); + if (firstRun) { + treeViewDock->hide(); +#ifndef Q_OS_WIN + terminalDock->hide(); +#endif } - plugActionList("create_file_group", m_fileGroupActions); - //plugActionList("create_link_group", m_linkGroupActions); - //plugActionList("link_to_device", m_linkToDeviceActions);*/ -} + QDockWidget* placesDock = new QDockWidget(i18nc("@title:window", "Places")); + placesDock->setObjectName("placesDock"); + placesDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); -void DolphinMainWindow::updateHistory() -{ - int index = 0; - const Q3ValueList list = m_activeView->urlHistory(index); + DolphinFilePlacesView* placesView = new DolphinFilePlacesView(placesDock); + placesDock->setWidget(placesView); + placesView->setModel(DolphinSettings::instance().placesModel()); + placesView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - QAction* backAction = actionCollection()->action("go_back"); - if (backAction != 0) { - backAction->setEnabled(index < static_cast(list.count()) - 1); - } + placesDock->toggleViewAction()->setText(i18nc("@title:window", "Places")); + placesDock->toggleViewAction()->setShortcut(Qt::Key_F9); + actionCollection()->addAction("show_places_panel", placesDock->toggleViewAction()); - QAction* forwardAction = actionCollection()->action("go_forward"); - if (forwardAction != 0) { - forwardAction->setEnabled(index > 0); - } + addDockWidget(Qt::LeftDockWidgetArea, placesDock); + connect(placesView, SIGNAL(urlChanged(KUrl, Qt::MouseButtons)), + this, SLOT(handlePlacesClick(KUrl, Qt::MouseButtons))); + connect(this, SIGNAL(urlChanged(KUrl)), + placesView, SLOT(setUrl(KUrl))); } void DolphinMainWindow::updateEditActions() { - const KFileItemList list = m_activeView->selectedItems(); + const KFileItemList list = m_activeViewContainer->view()->selectedItems(); if (list.isEmpty()) { stateChanged("has_no_selection"); - } - else { + } else { stateChanged("has_selection"); - QAction* renameAction = actionCollection()->action("rename"); - if (renameAction != 0) { - renameAction->setEnabled(list.count() >= 1); - } + KActionCollection* col = actionCollection(); + QAction* renameAction = col->action("rename"); + QAction* moveToTrashAction = col->action("move_to_trash"); + QAction* deleteAction = col->action("delete"); + QAction* cutAction = col->action(KStandardAction::name(KStandardAction::Cut)); + QAction* deleteWithTrashShortcut = col->action("delete_shortcut"); // see DolphinViewActionHandler - bool enableMoveToTrash = true; - - KFileItemList::const_iterator it = list.begin(); - const KFileItemList::const_iterator end = list.end(); - while (it != end) { - KFileItem* item = *it; - const KUrl& url = item->url(); - // only enable the 'Move to Trash' action for local files - if (!url.isLocalFile()) { - enableMoveToTrash = false; - } - ++it; - } + KonqFileItemCapabilities capabilities(list); + const bool enableMoveToTrash = capabilities.isLocal() && capabilities.supportsMoving(); - QAction* moveToTrashAction = actionCollection()->action("move_to_trash"); + renameAction->setEnabled(capabilities.supportsMoving()); moveToTrashAction->setEnabled(enableMoveToTrash); + deleteAction->setEnabled(capabilities.supportsDeleting()); + deleteWithTrashShortcut->setEnabled(capabilities.supportsDeleting() && !enableMoveToTrash); + cutAction->setEnabled(capabilities.supportsMoving()); } updatePasteAction(); } void DolphinMainWindow::updateViewActions() { - QAction* zoomInAction = actionCollection()->action(KStandardAction::stdName(KStandardAction::ZoomIn)); - if (zoomInAction != 0) { - zoomInAction->setEnabled(m_activeView->isZoomInPossible()); - } + m_actionHandler->updateViewActions(); - QAction* zoomOutAction = actionCollection()->action(KStandardAction::stdName(KStandardAction::ZoomOut)); - if (zoomOutAction != 0) { - zoomOutAction->setEnabled(m_activeView->isZoomOutPossible()); - } + QAction* showFilterBarAction = actionCollection()->action("show_filter_bar"); + showFilterBarAction->setChecked(m_activeViewContainer->isFilterBarVisible()); - QAction* action = 0; - switch (m_activeView->mode()) { - case DolphinView::IconsView: - action = actionCollection()->action("icons"); - break; - case DolphinView::DetailsView: - action = actionCollection()->action("details"); - break; - //case DolphinView::PreviewsView: - // action = actionCollection()->action("previews"); - // break; - default: - break; - } + updateSplitAction(); - if (action != 0) { - KToggleAction* toggleAction = static_cast(action); - toggleAction->setChecked(true); - } + QAction* editableLocactionAction = actionCollection()->action("editable_location"); + const KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator(); + editableLocactionAction->setChecked(urlNavigator->isUrlEditable()); +} - slotSortingChanged(m_activeView->sorting()); - slotSortOrderChanged(m_activeView->sortOrder()); +void DolphinMainWindow::updateGoActions() +{ + QAction* goUpAction = actionCollection()->action(KStandardAction::name(KStandardAction::Up)); + const KUrl& currentUrl = m_activeViewContainer->url(); + goUpAction->setEnabled(currentUrl.upUrl() != currentUrl); +} - KToggleAction* showFilterBarAction = - static_cast(actionCollection()->action("show_filter_bar")); - showFilterBarAction->setChecked(m_activeView->isFilterBarVisible()); +void DolphinMainWindow::clearStatusBar() +{ + m_activeViewContainer->statusBar()->clear(); +} - KToggleAction* showHiddenFilesAction = - static_cast(actionCollection()->action("show_hidden_files")); - showHiddenFilesAction->setChecked(m_activeView->showHiddenFiles()); +void DolphinMainWindow::connectViewSignals(DolphinViewContainer* container) +{ + connect(container, SIGNAL(showFilterBarChanged(bool)), + this, SLOT(updateFilterBarAction(bool))); - KToggleAction* splitAction = static_cast(actionCollection()->action("split_view")); - splitAction->setChecked(m_view[SecondaryIdx] != 0); + DolphinView* view = container->view(); + connect(view, SIGNAL(selectionChanged(KFileItemList)), + this, SLOT(slotSelectionChanged(KFileItemList))); + connect(view, SIGNAL(requestItemInfo(KFileItem)), + this, SLOT(slotRequestItemInfo(KFileItem))); + connect(view, SIGNAL(activated()), + this, SLOT(toggleActiveView())); + connect(view, SIGNAL(tabRequested(const KUrl&)), + this, SLOT(openNewTab(const KUrl&))); + + const KUrlNavigator* navigator = container->urlNavigator(); + connect(navigator, SIGNAL(urlChanged(const KUrl&)), + this, SLOT(changeUrl(const KUrl&))); + connect(navigator, SIGNAL(historyChanged()), + this, SLOT(updateHistory())); + connect(navigator, SIGNAL(editableStateChanged(bool)), + this, SLOT(slotEditableStateChanged(bool))); } -void DolphinMainWindow::updateGoActions() +void DolphinMainWindow::updateSplitAction() { - QAction* goUpAction = actionCollection()->action(KStandardAction::stdName(KStandardAction::Up)); - const KUrl& currentUrl = m_activeView->url(); - goUpAction->setEnabled(currentUrl.upUrl() != currentUrl); + QAction* splitAction = actionCollection()->action("split_view"); + if (m_viewTab[m_tabIndex].secondaryView != 0) { + if (m_activeViewContainer == m_viewTab[m_tabIndex].secondaryView) { + splitAction->setText(i18nc("@action:intoolbar Close right view", "Close")); + splitAction->setIcon(KIcon("view-right-close")); + } else { + splitAction->setText(i18nc("@action:intoolbar Close left view", "Close")); + splitAction->setIcon(KIcon("view-left-close")); + } + } else { + splitAction->setText(i18nc("@action:intoolbar Split view", "Split")); + splitAction->setIcon(KIcon("view-right-new")); + } } -void DolphinMainWindow::copyUrls(const KUrl::List& source, const KUrl& dest) +QString DolphinMainWindow::tabName(const KUrl& url) const { - KonqOperations::copy(this, KonqOperations::COPY, source, dest); - m_undoOperations.append(KonqOperations::COPY); + QString name; + if (url.equals(KUrl("file:///"))) { + name = "/"; + } else { + name = url.fileName(); + if (name.isEmpty()) { + name = url.protocol(); + } + } + return name; } -void DolphinMainWindow::moveUrls(const KUrl::List& source, const KUrl& dest) +bool DolphinMainWindow::isKompareInstalled() const { - KonqOperations::copy(this, KonqOperations::MOVE, source, dest); - m_undoOperations.append(KonqOperations::MOVE); + static bool initialized = false; + static bool installed = false; + if (!initialized) { + // TODO: maybe replace this approach later by using a menu + // plugin like kdiff3plugin.cpp + installed = !KGlobal::dirs()->findExe("kompare").isEmpty(); + initialized = true; + } + return installed; } -void DolphinMainWindow::clearStatusBar() +DolphinMainWindow::UndoUiInterface::UndoUiInterface() : + KIO::FileUndoManager::UiInterface() { - m_activeView->statusBar()->clear(); } -void DolphinMainWindow::connectViewSignals(int viewIndex) +DolphinMainWindow::UndoUiInterface::~UndoUiInterface() { - DolphinView* view = m_view[viewIndex]; - connect(view, SIGNAL(modeChanged()), - this, SLOT(slotViewModeChanged())); - connect(view, SIGNAL(showHiddenFilesChanged()), - this, SLOT(slotShowHiddenFilesChanged())); - connect(view, SIGNAL(sortingChanged(DolphinView::Sorting)), - this, SLOT(slotSortingChanged(DolphinView::Sorting))); - connect(view, SIGNAL(sortOrderChanged(Qt::SortOrder)), - this, SLOT(slotSortOrderChanged(Qt::SortOrder))); - connect(view, SIGNAL(selectionChanged()), - this, SLOT(slotSelectionChanged())); - connect(view, SIGNAL(showFilterBarChanged(bool)), - this, SLOT(updateFilterBarAction(bool))); - - const UrlNavigator* navigator = view->urlNavigator(); - connect(navigator, SIGNAL(urlChanged(const KUrl&)), - this, SLOT(slotUrlChanged(const KUrl&))); - connect(navigator, SIGNAL(historyChanged()), - this, SLOT(slotHistoryChanged())); +} +void DolphinMainWindow::UndoUiInterface::jobError(KIO::Job* job) +{ + DolphinMainWindow* mainWin= qobject_cast(parentWidget()); + if (mainWin) { + DolphinStatusBar* statusBar = mainWin->activeViewContainer()->statusBar(); + statusBar->setMessage(job->errorString(), DolphinStatusBar::Error); + } else { + KIO::FileUndoManager::UiInterface::jobError(job); + } } #include "dolphinmainwindow.moc"