diff --git a/src/dolphinmainwindow.cpp b/src/dolphinmainwindow.cpp index 561c235b7..5183f993d 100644 --- a/src/dolphinmainwindow.cpp +++ b/src/dolphinmainwindow.cpp @@ -1,1505 +1,1520 @@ /*************************************************************************** * Copyright (C) 2006 by Peter Penz * * Copyright (C) 2006 by Stefan Monov * * Copyright (C) 2006 by Cvetoslav Ludmiloff * * * * 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 #include "dolphinmainwindow.h" -#include - #include "bookmarkssidebarpage.h" #include "dolphinapplication.h" #include "dolphinnewmenu.h" #include "dolphinsettings.h" #include "dolphinsettingsdialog.h" #include "dolphinstatusbar.h" #include "infosidebarpage.h" #include "metadataloader.h" #include "mainwindowadaptor.h" #include "treeviewsidebarpage.h" #include "urlnavigator.h" #include "viewpropertiesdialog.h" #include "viewproperties.h" #include "dolphin_generalsettings.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 DolphinMainWindow::DolphinMainWindow(int id) : KMainWindow(0), m_newMenu(0), m_splitter(0), m_activeView(0), m_id(id) { setObjectName("Dolphin"); m_view[PrimaryIdx] = 0; m_view[SecondaryIdx] = 0; new MainWindowAdaptor(this); QDBusConnection::sessionBus().registerObject(QString("/dolphin/MainWindow%1").arg(m_id), this); KonqUndoManager::incRef(); KonqUndoManager* undoManager = KonqUndoManager::self(); undoManager->setUiInterface(new UndoUiInterface(this)); connect(undoManager, SIGNAL(undoAvailable(bool)), this, SLOT(slotUndoAvailable(bool))); connect(undoManager, SIGNAL(undoTextChanged(const QString&)), this, SLOT(slotUndoTextChanged(const QString&))); } DolphinMainWindow::~DolphinMainWindow() { KonqUndoManager::decRef(); DolphinApplication::app()->removeMainWindow(this); } void DolphinMainWindow::setActiveView(DolphinView* view) { - assert((view == m_view[PrimaryIdx]) || (view == m_view[SecondaryIdx])); + Q_ASSERT((view == m_view[PrimaryIdx]) || (view == m_view[SecondaryIdx])); if (m_activeView == view) { return; } m_activeView = view; updateHistory(); updateEditActions(); updateViewActions(); updateGoActions(); setCaption(m_activeView->url().fileName()); emit activeViewChanged(); } void DolphinMainWindow::dropUrls(const KUrl::List& urls, const KUrl& destination) { Qt::DropAction action = Qt::CopyAction; Qt::KeyboardModifiers modifier = QApplication::keyboardModifiers(); const bool shiftPressed = modifier & Qt::ShiftModifier; const bool controlPressed = modifier & Qt::ControlModifier; if (shiftPressed && controlPressed) { // shortcut for 'Link Here' is used action = Qt::LinkAction; } else if (shiftPressed) { // shortcut for 'Move Here' is used action = Qt::MoveAction; } else if (controlPressed) { // shortcut for 'Copy Here' is used action = Qt::CopyAction; } else { // open a context menu which offers the following actions: // - Move Here // - Copy Here // - Link Here // - Cancel KMenu popup(this); QString seq = QKeySequence(Qt::ShiftModifier).toString(); seq.chop(1); // chop superfluous '+' QAction* moveAction = popup.addAction(KIcon("goto-page"), i18n("&Move Here") + '\t' + seq); seq = QKeySequence(Qt::ControlModifier).toString(); seq.chop(1); QAction* copyAction = popup.addAction(KIcon("edit-copy"), i18n("&Copy Here") + '\t' + seq); seq = QKeySequence(Qt::ControlModifier + Qt::ShiftModifier).toString(); seq.chop(1); QAction* linkAction = popup.addAction(KIcon("www"), i18n("&Link Here") + '\t' + seq); popup.addSeparator(); popup.addAction(KIcon("process-stop"), i18n("Cancel")); QAction* activatedAction = popup.exec(QCursor::pos()); if (activatedAction == moveAction) { action = Qt::MoveAction; } else if (activatedAction == copyAction) { action = Qt::CopyAction; } else if (activatedAction == linkAction) { action = Qt::LinkAction; } else { return; } } switch (action) { case Qt::MoveAction: moveUrls(urls, destination); break; case Qt::CopyAction: copyUrls(urls, destination); break; case Qt::LinkAction: linkUrls(urls, destination); break; default: break; } } +void DolphinMainWindow::rename(const KUrl& oldUrl, const KUrl& newUrl) +{ + KonqOperations::rename(this, oldUrl, newUrl); + m_undoCommandTypes.append(KonqUndoManager::RENAME); +} + 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; } 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(); } } m_activeView = isPrimaryViewActive ? m_view[PrimaryIdx] : m_view[SecondaryIdx]; - assert(m_activeView != 0); + Q_ASSERT(m_activeView != 0); updateViewActions(); emit activeViewChanged(); } void DolphinMainWindow::changeUrl(const QString& url) { if (activeView() != 0) { activeView()->setUrl(KUrl(url)); } } void DolphinMainWindow::slotViewModeChanged() { updateViewActions(); } void DolphinMainWindow::slotShowPreviewChanged() { // It is not enough to update the 'Show Preview' action, also // the 'Zoom In' and 'Zoom Out' actions must be adapted. updateViewActions(); } void DolphinMainWindow::slotShowHiddenFilesChanged() { KToggleAction* showHiddenFilesAction = static_cast(actionCollection()->action("show_hidden_files")); showHiddenFilesAction->setChecked(m_activeView->showHiddenFiles()); } void DolphinMainWindow::slotSortingChanged(DolphinView::Sorting sorting) { 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; case DolphinView::SortByPermissions: action = actionCollection()->action("by_permissions"); break; case DolphinView::SortByOwner: action = actionCollection()->action("by_owner"); break; case DolphinView::SortByGroup: action = actionCollection()->action("by_group"); break; default: break; } if (action != 0) { KToggleAction* toggleAction = static_cast(action); toggleAction->setChecked(true); } } void DolphinMainWindow::slotSortOrderChanged(Qt::SortOrder order) { KToggleAction* descending = static_cast(actionCollection()->action("descending")); const bool sortDescending = (order == Qt::Descending); descending->setChecked(sortDescending); } void DolphinMainWindow::slotAdditionalInfoChanged(KFileItemDelegate::AdditionalInformation info) { QAction* action = 0; switch (info) { case KFileItemDelegate::FriendlyMimeType: action = actionCollection()->action("show_mime_info"); break; case KFileItemDelegate::Size: action = actionCollection()->action("show_size_info"); break; case KFileItemDelegate::ModificationTime: action = actionCollection()->action("show_date_info"); break; case KFileItemDelegate::NoInformation: default: action = actionCollection()->action("clear_info"); break; } if (action != 0) { KToggleAction* toggleAction = static_cast(action); toggleAction->setChecked(true); QActionGroup* group = toggleAction->actionGroup(); Q_ASSERT(group != 0); group->setEnabled(m_activeView->mode() == DolphinView::IconsView); } } void DolphinMainWindow::slotSelectionChanged() { updateEditActions(); - assert(m_view[PrimaryIdx] != 0); + Q_ASSERT(m_view[PrimaryIdx] != 0); int selectedUrlsCount = m_view[PrimaryIdx]->selectedUrls().count(); if (m_view[SecondaryIdx] != 0) { selectedUrlsCount += m_view[SecondaryIdx]->selectedUrls().count(); } QAction* compareFilesAction = actionCollection()->action("compare_files"); compareFilesAction->setEnabled(selectedUrlsCount == 2); m_activeView->updateStatusBar(); emit selectionChanged(); } void DolphinMainWindow::slotHistoryChanged() { updateHistory(); } void DolphinMainWindow::slotUrlChanged(const KUrl& url) { updateEditActions(); updateViewActions(); updateGoActions(); setCaption(url.fileName()); } void DolphinMainWindow::updateFilterBarAction(bool show) { KToggleAction* showFilterBarAction = static_cast(actionCollection()->action("show_filter_bar")); showFilterBarAction->setChecked(show); } void DolphinMainWindow::openNewMainWindow() { DolphinApplication::app()->createMainWindow()->show(); } void DolphinMainWindow::closeEvent(QCloseEvent* event) { DolphinSettings& settings = DolphinSettings::instance(); GeneralSettings* generalSettings = settings.generalSettings(); generalSettings->setFirstRun(false); settings.save(); // 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::mainComponent().componentName()); filename.append("/panels_layout"); QFile file(filename); if (file.open(QIODevice::WriteOnly)) { QByteArray data = saveState(); file.write(data); file.close(); } KMainWindow::closeEvent(event); } void DolphinMainWindow::saveProperties(KConfig* config) { KConfigGroup primaryView = config->group("Primary view"); primaryView.writeEntry("Url", m_view[PrimaryIdx]->url().url()); primaryView.writeEntry("Editable Url", m_view[PrimaryIdx]->isUrlEditable()); if (m_view[SecondaryIdx] != 0) { KConfigGroup secondaryView = config->group("Secondary view"); secondaryView.writeEntry("Url", m_view[SecondaryIdx]->url().url()); secondaryView.writeEntry("Editable Url", m_view[SecondaryIdx]->isUrlEditable()); } } void DolphinMainWindow::readProperties(KConfig* config) { const KConfigGroup primaryView = config->group("Primary view"); m_view[PrimaryIdx]->setUrl(primaryView.readEntry("Url")); m_view[PrimaryIdx]->setUrlEditable(primaryView.readEntry("Editable Url", false)); if (config->hasGroup("Secondary view")) { const KConfigGroup secondaryView = config->group("Secondary view"); if (m_view[SecondaryIdx] == 0) { toggleSplitView(); } m_view[SecondaryIdx]->setUrl(secondaryView.readEntry("Url")); m_view[SecondaryIdx]->setUrlEditable(secondaryView.readEntry("Editable Url", false)); } else if (m_view[SecondaryIdx] != 0) { toggleSplitView(); } } void DolphinMainWindow::updateNewMenu() { m_newMenu->slotCheckUpToDate(); m_newMenu->setPopupFiles(activeView()->url()); } void DolphinMainWindow::rename() { clearStatusBar(); m_activeView->renameSelectedItems(); } void DolphinMainWindow::moveToTrash() { clearStatusBar(); const KUrl::List selectedUrls = m_activeView->selectedUrls(); KonqOperations::del(this, KonqOperations::TRASH, selectedUrls); - m_undoOperations.append(KonqOperations::TRASH); + m_undoCommandTypes.append(KonqUndoManager::TRASH); } void DolphinMainWindow::deleteItems() { clearStatusBar(); KUrl::List list = m_activeView->selectedUrls(); const uint itemCount = list.count(); - assert(itemCount >= 1); + Q_ASSERT(itemCount >= 1); 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()); } const bool del = KMessageBox::warningContinueCancel(this, text, QString(), KGuiItem(i18n("Delete"), KIcon("edit-delete")) ) == 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*))); } } void DolphinMainWindow::properties() { const KFileItemList list = m_activeView->selectedItems(); new KPropertiesDialog(list, this); } void DolphinMainWindow::quit() { close(); } void DolphinMainWindow::slotHandleJobError(KJob* job) { if (job->error() != 0) { DolphinStatusBar* statusBar = m_activeView->statusBar(); statusBar->setMessage(job->errorString(), DolphinStatusBar::Error); } } void DolphinMainWindow::slotDeleteFileFinished(KJob* job) { if (job->error() == 0) { DolphinStatusBar* statusBar = m_activeView->statusBar(); statusBar->setMessage(i18n("Delete operation completed."), DolphinStatusBar::OperationCompleted); } } void DolphinMainWindow::slotUndoAvailable(bool available) { QAction* undoAction = actionCollection()->action(KStandardAction::stdName(KStandardAction::Undo)); if (undoAction != 0) { undoAction->setEnabled(available); } - if (available && (m_undoOperations.count() > 0)) { - const KonqOperations::Operation op = m_undoOperations.takeFirst(); + if (available && (m_undoCommandTypes.count() > 0)) { + const KonqUndoManager::CommandType command = m_undoCommandTypes.takeFirst(); DolphinStatusBar* statusBar = m_activeView->statusBar(); - switch (op) { - case KonqOperations::COPY: + switch (command) { + case KonqUndoManager::COPY: statusBar->setMessage(i18n("Copy operation completed."), DolphinStatusBar::OperationCompleted); break; - case KonqOperations::MOVE: + case KonqUndoManager::MOVE: statusBar->setMessage(i18n("Move operation completed."), DolphinStatusBar::OperationCompleted); break; - case KonqOperations::LINK: + case KonqUndoManager::LINK: statusBar->setMessage(i18n("Link operation completed."), DolphinStatusBar::OperationCompleted); break; - case KonqOperations::TRASH: + case KonqUndoManager::TRASH: statusBar->setMessage(i18n("Move to trash operation completed."), DolphinStatusBar::OperationCompleted); break; + case KonqUndoManager::RENAME: + statusBar->setMessage(i18n("Renaming operation completed."), + DolphinStatusBar::OperationCompleted); + break; + + case KonqUndoManager::MKDIR: + statusBar->setMessage(i18n("Created directory."), + DolphinStatusBar::OperationCompleted); + break; + default: break; } } } void DolphinMainWindow::slotUndoTextChanged(const QString& text) { QAction* undoAction = actionCollection()->action(KStandardAction::stdName(KStandardAction::Undo)); if (undoAction != 0) { undoAction->setText(text); } } void DolphinMainWindow::undo() { clearStatusBar(); KonqUndoManager::self()->undo(); } void DolphinMainWindow::cut() { QClipboard* clipboard = QApplication::clipboard(); const QMimeData* currentMimeData = clipboard->mimeData(); const bool hadCutSelection = KonqMimeData::decodeIsCutSelection(currentMimeData); 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); if (hadCutSelection) { // If an old cut selection has been applied, the view must // be reloaded to get the original icons of the items without an // applied item effect. m_view[PrimaryIdx]->reload(); if (m_view[SecondaryIdx] != 0) { m_view[SecondaryIdx]->reload(); } } else { // apply an item effect for the icons of all cut items m_view[PrimaryIdx]->updateCutItems(); if (m_view[SecondaryIdx] != 0) { m_view[SecondaryIdx]->updateCutItems(); } } } 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); } 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); } } 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); pasteAction->setText(i18np("Paste One File", "Paste %1 Files", urls.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()); } } } void DolphinMainWindow::selectAll() { clearStatusBar(); m_activeView->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::sortByPermissions() { m_activeView->setSorting(DolphinView::SortByPermissions); } void DolphinMainWindow::sortByOwner() { m_activeView->setSorting(DolphinView::SortByOwner); } void DolphinMainWindow::sortByGroup() { m_activeView->setSorting(DolphinView::SortByGroup); } void DolphinMainWindow::toggleSortOrder() { const Qt::SortOrder order = (m_activeView->sortOrder() == Qt::Ascending) ? Qt::Descending : Qt::Ascending; m_activeView->setSortOrder(order); } void DolphinMainWindow::clearInfo() { m_activeView->setAdditionalInfo(KFileItemDelegate::NoInformation); } void DolphinMainWindow::showMimeInfo() { clearStatusBar(); m_activeView->setAdditionalInfo(KFileItemDelegate::FriendlyMimeType); } void DolphinMainWindow::showSizeInfo() { clearStatusBar(); m_activeView->setAdditionalInfo(KFileItemDelegate::Size); } void DolphinMainWindow::showDateInfo() { clearStatusBar(); m_activeView->setAdditionalInfo(KFileItemDelegate::ModificationTime); } void DolphinMainWindow::toggleSplitView() { if (m_view[SecondaryIdx] == 0) { const int newWidth = (m_view[PrimaryIdx]->width() - m_splitter->handleWidth()) / 2; // 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 { // 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]); } } emit activeViewChanged(); } void DolphinMainWindow::reloadView() { clearStatusBar(); m_activeView->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->showFilterBar(show); } void DolphinMainWindow::zoomIn() { m_activeView->zoomIn(); updateViewActions(); } void DolphinMainWindow::zoomOut() { m_activeView->zoomOut(); updateViewActions(); } void DolphinMainWindow::toggleEditLocation() { clearStatusBar(); KToggleAction* action = static_cast(actionCollection()->action("editable_location")); bool editOrBrowse = action->isChecked(); m_activeView->setUrlEditable(editOrBrowse); } void DolphinMainWindow::editLocation() { m_activeView->setUrlEditable(true); } void DolphinMainWindow::adjustViewProperties() { clearStatusBar(); ViewPropertiesDialog dlg(m_activeView); dlg.exec(); } void DolphinMainWindow::goBack() { clearStatusBar(); m_activeView->goBack(); } void DolphinMainWindow::goForward() { clearStatusBar(); m_activeView->goForward(); } void DolphinMainWindow::goUp() { clearStatusBar(); m_activeView->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()); } void DolphinMainWindow::compareFiles() { // The method is only invoked if exactly 2 files have // been selected. The selected files may be: // - both in the primary view // - 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_view[PrimaryIdx] != 0); KUrl urlA; KUrl urlB; KUrl::List urls = m_view[PrimaryIdx]->selectedUrls(); switch (urls.count()) { case 0: { - assert(m_view[SecondaryIdx] != 0); + Q_ASSERT(m_view[SecondaryIdx] != 0); urls = m_view[SecondaryIdx]->selectedUrls(); - assert(urls.count() == 2); + Q_ASSERT(urls.count() == 2); urlA = urls[0]; urlB = urls[1]; break; } case 1: { urlA = urls[0]; - assert(m_view[SecondaryIdx] != 0); + Q_ASSERT(m_view[SecondaryIdx] != 0); urls = m_view[SecondaryIdx]->selectedUrls(); - assert(urls.count() == 1); + Q_ASSERT(urls.count() == 1); urlB = urls[0]; 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); + Q_ASSERT(false); } } QString command("kompare -c \""); command.append(urlA.pathOrUrl()); command.append("\" \""); command.append(urlB.pathOrUrl()); command.append('\"'); KRun::runCommand(command, "Kompare", "kompare"); } void DolphinMainWindow::editSettings() { // TODO: make a static method for opening the settings dialog DolphinSettingsDialog dlg(this); dlg.exec(); } void DolphinMainWindow::init() { // 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(); 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); + Q_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:/"), "hdd-mount"); root.addBookmark(manager, i18n("Network"), KUrl("remote:/"), "network-local"); root.addBookmark(manager, i18n("Root"), KUrl("/"), "folder-red"); root.addBookmark(manager, i18n("Trash"), KUrl("trash:/"), "user-trash"); } setupActions(); const KUrl& homeUrl = settings.generalSettings()->homeUrl(); setCaption(homeUrl.fileName()); 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); setupDockWidgets(); setupGUI(Keys|Save|Create|ToolBar); createGUI(); stateChanged("new_file"); setAutoSaveSettings(); QClipboard* clipboard = QApplication::clipboard(); connect(clipboard, SIGNAL(dataChanged()), this, SLOT(updatePasteAction())); updatePasteAction(); updateGoActions(); loadSettings(); if (firstRun) { // assure a proper default size if Dolphin runs the first time resize(640, 480); } #ifdef HAVE_KMETADATA if (!DolphinApplication::app()->metadataLoader()->storageUp()) activeView()->statusBar()->setMessage(i18n("Failed to contact Nepomuk service, annotation and tagging are disabled."), DolphinStatusBar::Error); #endif } void DolphinMainWindow::loadSettings() { GeneralSettings* settings = DolphinSettings::instance().generalSettings(); KToggleAction* splitAction = static_cast(actionCollection()->action("split_view")); if (settings->splitView()) { splitAction->setChecked(true); toggleSplitView(); } updateViewActions(); // 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::mainComponent().componentName()); filename.append("/panels_layout"); QFile file(filename); if (file.open(QIODevice::ReadOnly)) { QByteArray data = file.readAll(); restoreState(data); file.close(); } } void DolphinMainWindow::setupActions() { // setup 'File' menu m_newMenu = new DolphinNewMenu(this); KMenu* menu = m_newMenu->menu(); menu->setTitle(i18n("Create New...")); menu->setIcon(SmallIcon("document-new")); connect(menu, SIGNAL(aboutToShow()), this, SLOT(updateNewMenu())); QAction* newWindow = actionCollection()->addAction("new_window"); newWindow->setIcon(KIcon("window-new")); newWindow->setText(i18n("New &Window")); newWindow->setShortcut(Qt::CTRL | Qt::Key_N); connect(newWindow, SIGNAL(triggered()), this, SLOT(openNewMainWindow())); 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("edit-trash")); moveToTrash->setShortcut(QKeySequence::Delete); connect(moveToTrash, SIGNAL(triggered()), this, SLOT(moveToTrash())); QAction* deleteAction = actionCollection()->addAction("delete"); deleteAction->setText(i18n("Delete")); deleteAction->setShortcut(Qt::SHIFT | Qt::Key_Delete); deleteAction->setIcon(KIcon("edit-delete")); connect(deleteAction, SIGNAL(triggered()), this, SLOT(deleteItems())); QAction* properties = actionCollection()->addAction("properties"); properties->setText(i18n("Properties")); properties->setShortcut(Qt::ALT | Qt::Key_Return); connect(properties, SIGNAL(triggered()), this, SLOT(properties())); KStandardAction::quit(this, SLOT(quit()), actionCollection()); // setup 'Edit' menu KStandardAction::undo(this, SLOT(undo()), actionCollection()); KStandardAction::cut(this, SLOT(cut()), actionCollection()); KStandardAction::copy(this, SLOT(copy()), actionCollection()); KStandardAction::paste(this, SLOT(paste()), actionCollection()); QAction* selectAll = actionCollection()->addAction("select_all"); selectAll->setText(i18n("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")); 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("fileview-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())); KToggleAction* sortByPermissions = actionCollection()->add("by_permissions"); sortByPermissions->setText(i18n("By Permissions")); connect(sortByPermissions, SIGNAL(triggered()), this, SLOT(sortByPermissions())); KToggleAction* sortByOwner = actionCollection()->add("by_owner"); sortByOwner->setText(i18n("By Owner")); connect(sortByOwner, SIGNAL(triggered()), this, SLOT(sortByOwner())); KToggleAction* sortByGroup = actionCollection()->add("by_group"); sortByGroup->setText(i18n("By Group")); connect(sortByGroup, SIGNAL(triggered()), this, SLOT(sortByGroup())); QActionGroup* sortGroup = new QActionGroup(this); sortGroup->addAction(sortByName); sortGroup->addAction(sortBySize); sortGroup->addAction(sortByDate); sortGroup->addAction(sortByPermissions); sortGroup->addAction(sortByOwner); sortGroup->addAction(sortByGroup); KToggleAction* sortDescending = actionCollection()->add("descending"); sortDescending->setText(i18n("Descending")); connect(sortDescending, SIGNAL(triggered()), this, SLOT(toggleSortOrder())); KToggleAction* clearInfo = actionCollection()->add("clear_info"); clearInfo->setText(i18n("No Information")); connect(clearInfo, SIGNAL(triggered()), this, SLOT(clearInfo())); KToggleAction* showMimeInfo = actionCollection()->add("show_mime_info"); showMimeInfo->setText(i18n("Type")); connect(showMimeInfo, SIGNAL(triggered()), this, SLOT(showMimeInfo())); KToggleAction* showSizeInfo = actionCollection()->add("show_size_info"); showSizeInfo->setText(i18n("Size")); connect(showSizeInfo, SIGNAL(triggered()), this, SLOT(showSizeInfo())); KToggleAction* showDateInfo = actionCollection()->add("show_date_info"); showDateInfo->setText(i18n("Date")); connect(showDateInfo, SIGNAL(triggered()), this, SLOT(showDateInfo())); QActionGroup* infoGroup = new QActionGroup(this); infoGroup->addAction(clearInfo); infoGroup->addAction(showMimeInfo); infoGroup->addAction(showSizeInfo); infoGroup->addAction(showDateInfo); KToggleAction* showPreview = actionCollection()->add("show_preview"); showPreview->setText(i18n("Preview")); showPreview->setIcon(KIcon("thumbnail-show")); 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_Period); connect(showHiddenFiles, SIGNAL(triggered()), this, SLOT(toggleShowHiddenFiles())); KToggleAction* split = actionCollection()->add("split_view"); split->setText(i18n("Split")); split->setShortcut(Qt::Key_F10); split->setIcon(KIcon("view-left-right")); connect(split, SIGNAL(triggered()), this, SLOT(toggleSplitView())); QAction* reload = actionCollection()->addAction("reload"); reload->setText(i18n("Reload")); reload->setShortcut(Qt::Key_F5); reload->setIcon(KIcon("view-refresh")); connect(reload, SIGNAL(triggered()), this, SLOT(reloadView())); QAction* stop = actionCollection()->addAction("stop"); stop->setText(i18n("Stop")); stop->setIcon(KIcon("process-stop")); connect(stop, SIGNAL(triggered()), this, SLOT(stopLoading())); // TODO: the URL navigator must emit a signal if the editable state has been // changed, so that the corresponding showFullLocation action is updated. Also // the naming "Show full Location" is currently confusing... KToggleAction* showFullLocation = actionCollection()->add("editable_location"); showFullLocation->setText(i18n("Show Full Location")); showFullLocation->setShortcut(Qt::CTRL | Qt::Key_L); connect(showFullLocation, SIGNAL(triggered()), this, SLOT(toggleEditLocation())); QAction* editLocation = actionCollection()->addAction("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())); // setup 'Go' menu KStandardAction::back(this, SLOT(goBack()), actionCollection()); 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("file-find")); 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())); QAction* compareFiles = actionCollection()->addAction("compare_files"); compareFiles->setText(i18n("Compare Files")); compareFiles->setIcon(KIcon("kompare")); compareFiles->setEnabled(false); connect(compareFiles, SIGNAL(triggered()), this, SLOT(compareFiles())); // setup 'Settings' menu KStandardAction::preferences(this, SLOT(editSettings()), actionCollection()); } void DolphinMainWindow::setupDockWidgets() { // TODO: there's a lot copy/paste code here. Provide a generic approach // after the dock concept has been finalized. // setup "Bookmarks" 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); // setup "Information" QDockWidget* infoDock = new QDockWidget(i18n("Information")); infoDock->setObjectName("infoDock"); infoDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); infoDock->setWidget(new InfoSidebarPage(this)); infoDock->toggleViewAction()->setText(i18n("Show Information Panel")); actionCollection()->addAction("show_info_panel", infoDock->toggleViewAction()); addDockWidget(Qt::RightDockWidgetArea, infoDock); // setup "Tree View" QDockWidget* treeViewDock = new QDockWidget(i18n("Folders")); // TODO: naming? treeViewDock->setObjectName("treeViewDock"); treeViewDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); treeViewDock->setWidget(new TreeViewSidebarPage(this)); treeViewDock->toggleViewAction()->setText(i18n("Show Folders Panel")); actionCollection()->addAction("show_folders_panel", treeViewDock->toggleViewAction()); addDockWidget(Qt::LeftDockWidgetArea, treeViewDock); const bool firstRun = DolphinSettings::instance().generalSettings()->firstRun(); if (firstRun) { infoDock->hide(); treeViewDock->hide(); } } void DolphinMainWindow::updateHistory() { int index = 0; const QLinkedList list = m_activeView->urlHistory(index); QAction* backAction = actionCollection()->action("go_back"); if (backAction != 0) { backAction->setEnabled(index < static_cast(list.count()) - 1); } QAction* forwardAction = actionCollection()->action("go_forward"); if (forwardAction != 0) { forwardAction->setEnabled(index > 0); } } void DolphinMainWindow::updateEditActions() { const KFileItemList list = m_activeView->selectedItems(); if (list.isEmpty()) { stateChanged("has_no_selection"); } else { stateChanged("has_selection"); QAction* renameAction = actionCollection()->action("rename"); if (renameAction != 0) { renameAction->setEnabled(list.count() >= 1); } 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; } QAction* moveToTrashAction = actionCollection()->action("move_to_trash"); moveToTrashAction->setEnabled(enableMoveToTrash); } updatePasteAction(); } void DolphinMainWindow::updateViewActions() { QAction* zoomInAction = actionCollection()->action(KStandardAction::stdName(KStandardAction::ZoomIn)); if (zoomInAction != 0) { zoomInAction->setEnabled(m_activeView->isZoomInPossible()); } QAction* zoomOutAction = actionCollection()->action(KStandardAction::stdName(KStandardAction::ZoomOut)); if (zoomOutAction != 0) { zoomOutAction->setEnabled(m_activeView->isZoomOutPossible()); } QAction* action = 0; switch (m_activeView->mode()) { case DolphinView::IconsView: action = actionCollection()->action("icons"); break; case DolphinView::DetailsView: action = actionCollection()->action("details"); break; default: break; } if (action != 0) { KToggleAction* toggleAction = static_cast(action); toggleAction->setChecked(true); } slotSortingChanged(m_activeView->sorting()); slotSortOrderChanged(m_activeView->sortOrder()); slotAdditionalInfoChanged(m_activeView->additionalInfo()); KToggleAction* showFilterBarAction = static_cast(actionCollection()->action("show_filter_bar")); showFilterBarAction->setChecked(m_activeView->isFilterBarVisible()); KToggleAction* showPreviewAction = static_cast(actionCollection()->action("show_preview")); showPreviewAction->setChecked(m_activeView->showPreview()); KToggleAction* showHiddenFilesAction = static_cast(actionCollection()->action("show_hidden_files")); showHiddenFilesAction->setChecked(m_activeView->showHiddenFiles()); KToggleAction* splitAction = static_cast(actionCollection()->action("split_view")); splitAction->setChecked(m_view[SecondaryIdx] != 0); KToggleAction* editableLocactionAction = static_cast(actionCollection()->action("editable_location")); editableLocactionAction->setChecked(m_activeView->isUrlEditable()); } void DolphinMainWindow::updateGoActions() { QAction* goUpAction = actionCollection()->action(KStandardAction::stdName(KStandardAction::Up)); const KUrl& currentUrl = m_activeView->url(); goUpAction->setEnabled(currentUrl.upUrl() != currentUrl); } void DolphinMainWindow::copyUrls(const KUrl::List& source, const KUrl& dest) { KonqOperations::copy(this, KonqOperations::COPY, source, dest); - m_undoOperations.append(KonqOperations::COPY); + m_undoCommandTypes.append(KonqUndoManager::COPY); } void DolphinMainWindow::moveUrls(const KUrl::List& source, const KUrl& dest) { KonqOperations::copy(this, KonqOperations::MOVE, source, dest); - m_undoOperations.append(KonqOperations::MOVE); + m_undoCommandTypes.append(KonqUndoManager::MOVE); } void DolphinMainWindow::linkUrls(const KUrl::List& source, const KUrl& dest) { KonqOperations::copy(this, KonqOperations::LINK, source, dest); - m_undoOperations.append(KonqOperations::LINK); + m_undoCommandTypes.append(KonqUndoManager::LINK); } void DolphinMainWindow::clearStatusBar() { m_activeView->statusBar()->clear(); } void DolphinMainWindow::connectViewSignals(int viewIndex) { DolphinView* view = m_view[viewIndex]; connect(view, SIGNAL(modeChanged()), this, SLOT(slotViewModeChanged())); connect(view, SIGNAL(showPreviewChanged()), this, SLOT(slotShowPreviewChanged())); 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(additionalInfoChanged(KFileItemDelegate::AdditionalInformation)), this, SLOT(slotAdditionalInfoChanged(KFileItemDelegate::AdditionalInformation))); 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())); } DolphinMainWindow::UndoUiInterface::UndoUiInterface(DolphinMainWindow* mainWin) : KonqUndoManager::UiInterface(mainWin), m_mainWin(mainWin) { - assert(m_mainWin != 0); + Q_ASSERT(m_mainWin != 0); } DolphinMainWindow::UndoUiInterface::~UndoUiInterface() { } void DolphinMainWindow::UndoUiInterface::jobError(KIO::Job* job) { DolphinStatusBar* statusBar = m_mainWin->activeView()->statusBar(); statusBar->setMessage(job->errorString(), DolphinStatusBar::Error); } #include "dolphinmainwindow.moc" diff --git a/src/dolphinmainwindow.h b/src/dolphinmainwindow.h index ff9fbf6a9..57d370890 100644 --- a/src/dolphinmainwindow.h +++ b/src/dolphinmainwindow.h @@ -1,437 +1,442 @@ /*************************************************************************** * Copyright (C) 2006 by Peter Penz * * Copyright (C) 2006 by Stefan Monov * * Copyright (C) 2006 by Cvetoslav Ludmiloff * * * * 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_MAINWINDOW_H_ #define _DOLPHIN_MAINWINDOW_H_ #include "dolphinview.h" #include #include -#include #include #include class KNewMenu; class KPrinter; class KUrl; class QLineEdit; class KFileIconView; class KHBox; class Q3IconViewItem; class QSplitter; class KAction; class UrlNavigator; class DolphinApplication; /** * @short Main window for Dolphin. * * Handles the menus, toolbars and Dolphin views. */ class DolphinMainWindow: public KMainWindow { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.dolphin.MainWindow") Q_PROPERTY(int id READ getId SCRIPTABLE true) friend class DolphinApplication; public: virtual ~DolphinMainWindow(); /** * Activates the given view, which means that * all menu actions are applied to this view. When * having a split view setup the nonactive view * is usually shown in darker colors. */ void setActiveView(DolphinView* view); /** * Returns the currently active view. See * DolphinMainWindow::setActiveView() for more details. */ DolphinView* activeView() const { return m_activeView; } /** - * Handles the dropping of Urls to the given + * Handles the dropping of URLs to the given * destination. A context menu with the options * 'Move Here', 'Copy Here', 'Link Here' and * 'Cancel' is offered to the user. - * @param urls List of Urls which have been + * @param urls List of URLs which have been * dropped. - * @param destination Destination Url, where the - * list or Urls should be moved, + * @param destination Destination URL, where the + * list or URLs should be moved, * copied or linked to. */ void dropUrls(const KUrl::List& urls, const KUrl& destination); + /** Renames the item represented by \a oldUrl to \a newUrl. */ + void rename(const KUrl& oldUrl, const KUrl& newUrl); + /** * Refreshs the views of the main window by recreating them dependent from * the given Dolphin settings. */ void refreshViews(); /** * Returns the 'Create New...' sub menu which also can be shared * with other menus (e. g. a context menu). */ KNewMenu* newMenu() const { return m_newMenu; } public slots: /** * Returns the main windows ID, mainly used throught DBus. */ int getId() const { return m_id; } /** * Changes the URL of the current active DolphinView to \a url. */ void changeUrl(const QString& url); /** Stores all settings and quits Dolphin. */ void quit(); signals: /** * Is send if the active view has been changed in * the split view mode. */ void activeViewChanged(); /** * Is send if the selection of the currently active view has * been changed. */ void selectionChanged(); protected: /** @see QMainWindow::closeEvent */ virtual void closeEvent(QCloseEvent* event); /** * This method is called when it is time for the app to save its * properties for session management purposes. */ void saveProperties(KConfig*); /** * This method is called when this app is restored. The KConfig * object points to the session management config file that was saved * with @ref saveProperties */ void readProperties(KConfig*); private slots: /** Updates the 'Create New...' sub menu. */ void updateNewMenu(); - /** Renames the selected item of the active view. */ + /** + * Let the user input a name for the selected item(s) and trigger + * a renaming afterwards. + */ void rename(); /** Moves the selected items of the active view to the trash. */ void moveToTrash(); /** Deletes the selected items of the active view. */ void deleteItems(); /** * Opens the properties window for the selected items of the * active view. The properties windows shows informations * like name, size and permissions. */ void properties(); /** * Shows the error information of the job \a job * in the status bar. */ void slotHandleJobError(KJob* job); /** * Indicates in the status bar that the delete operation * of the job \a job has been finished. */ void slotDeleteFileFinished(KJob* job); /** * Updates the state of the 'Undo' menu action dependent * from the parameter \a available. */ void slotUndoAvailable(bool available); /** Sets the text of the 'Undo' menu action to \a text. */ void slotUndoTextChanged(const QString& text); /** Performs the current undo operation. */ void undo(); /** * Copies all selected items to the clipboard and marks * the items as cutted. */ void cut(); /** Copies all selected items to the clipboard. */ void copy(); /** Pastes the clipboard data to the active view. */ void paste(); /** * Updates the text of the paste action dependent from * the number of items which are in the clipboard. */ void updatePasteAction(); /** Selects all items from the active view. */ void selectAll(); /** * Inverts the selection of all items of the active view: * Selected items get nonselected and nonselected items get * selected. */ void invertSelection(); /** The current active view is switched to the icons mode. */ void setIconsView(); /** The current active view is switched to the details mode. */ void setDetailsView(); /** The sorting of the current view should be done by the name. */ void sortByName(); /** The sorting of the current view should be done by the size. */ void sortBySize(); /** The sorting of the current view should be done by the date. */ void sortByDate(); /** The sorting of the current view should be done by the permissions. */ void sortByPermissions(); /** The sorting of the current view should be done by the owner. */ void sortByOwner(); /** The sorting of the current view should be done by the group. */ void sortByGroup(); /** Switches between an ascending and descending sorting order. */ void toggleSortOrder(); /** * Clears any additional information for an item except for the * name and the icon. */ void clearInfo(); /** Shows the MIME type as additional information for the item. */ void showMimeInfo(); /** Shows the size as additional information for the item. */ void showSizeInfo(); /** Shows the date as additional information for the item. */ void showDateInfo(); /** * Switches between one and two views: * If one view is visible, it will get split into two views. * If already two views are visible, the nonactivated view gets closed. */ void toggleSplitView(); /** Reloads the current active view. */ void reloadView(); /** Stops the loading process for the current active view. */ void stopLoading(); /** Switches between showing a preview of the file content and showing the icon. */ void togglePreview(); /** * Switches between showing and hiding of hidden marked files dependent * from the current state of the 'Show Hidden Files' menu toggle action. */ void toggleShowHiddenFiles(); /** * Switches between showing and hiding of the filter bar dependent * from the current state of the 'Show Filter Bar' menu toggle action. */ void showFilterBar(); /** Increases the size of the current set view mode. */ void zoomIn(); /** Decreases the size of the current set view mode. */ void zoomOut(); /** * Toggles between edit and brose mode of the navigation bar. */ void toggleEditLocation(); /** * Switches to the edit mode of the navigation bar. If the edit mode is * already active, it is assured that the navigation bar get focused. */ void editLocation(); /** * Opens the view properties dialog, which allows to modify the properties * of the currently active view. */ void adjustViewProperties(); - /** Goes back on step of the Url history. */ + /** Goes back on step of the URL history. */ void goBack(); - /** Goes forward one step of the Url history. */ + /** Goes forward one step of the URL history. */ void goForward(); - /** Goes up one hierarchy of the current Url. */ + /** Goes up one hierarchy of the current URL. */ void goUp(); - /** Goes to the home Url. */ + /** Goes to the home URL. */ void goHome(); /** Opens a terminal for the current shown directory. */ void openTerminal(); /** Opens KFind for the current shown directory. */ void findFile(); /** Opens Kompare for 2 selected files. */ void compareFiles(); /** Opens the settings dialog for Dolphin. */ void editSettings(); /** Updates the state of all 'View' menu actions. */ void slotViewModeChanged(); /** Updates the state of the 'Show preview' menu action. */ void slotShowPreviewChanged(); /** Updates the state of the 'Show hidden files' menu action. */ void slotShowHiddenFilesChanged(); /** Updates the state of the 'Sort by' actions. */ void slotSortingChanged(DolphinView::Sorting sorting); /** Updates the state of the 'Sort Ascending/Descending' action. */ void slotSortOrderChanged(Qt::SortOrder order); /** Updates the state of the 'Additional Information' actions. */ void slotAdditionalInfoChanged(KFileItemDelegate::AdditionalInformation info); /** Updates the state of the 'Edit' menu actions. */ void slotSelectionChanged(); /** * Updates the state of the 'Back' and 'Forward' menu * actions corresponding the the current history. */ void slotHistoryChanged(); /** * Updates the caption of the main window and the state - * of all menu actions which depend from a changed Url. + * of all menu actions which depend from a changed URL. */ void slotUrlChanged(const KUrl& url); /** Updates the state of the 'Show filter bar' menu action. */ void updateFilterBarAction(bool show); /** Open a new main window. */ void openNewMainWindow(); private: DolphinMainWindow(int id); void init(); void loadSettings(); void setupAccel(); void setupActions(); void setupDockWidgets(); void updateHistory(); void updateEditActions(); void updateViewActions(); void updateGoActions(); void copyUrls(const KUrl::List& source, const KUrl& dest); void moveUrls(const KUrl::List& source, const KUrl& dest); void linkUrls(const KUrl::List& source, const KUrl& dest); void clearStatusBar(); /** * Connects the signals from the created DolphinView with * the index \a viewIndex with the corresponding slots of * the DolphinMainWindow. This method must be invoked each * time a DolphinView has been created. */ void connectViewSignals(int viewIndex); private: /** * DolphinMainWindowsupports only one or two views, which * are handled internally as primary and secondary view. */ enum ViewIndex { PrimaryIdx = 0, SecondaryIdx = 1 }; /** * Implements a custom error handling for the undo manager. This * assures that all errors are shown in the status bar of Dolphin * instead as modal error dialog with an OK button. */ class UndoUiInterface : public KonqUndoManager::UiInterface { public: UndoUiInterface(DolphinMainWindow* mainWin); virtual ~UndoUiInterface(); virtual void jobError(KIO::Job* job); private: DolphinMainWindow* m_mainWin; }; KNewMenu* m_newMenu; QSplitter* m_splitter; DolphinView* m_activeView; int m_id; DolphinView* m_view[SecondaryIdx + 1]; /// remember pending undo operations until they are finished - QList m_undoOperations; + QList m_undoCommandTypes; }; #endif // _DOLPHIN_H_ diff --git a/src/dolphinview.cpp b/src/dolphinview.cpp index 6569530ce..3602d1563 100644 --- a/src/dolphinview.cpp +++ b/src/dolphinview.cpp @@ -1,1156 +1,1152 @@ /*************************************************************************** * Copyright (C) 2006 by Peter Penz * * Copyright (C) 2006 by Gregor Kališnik * * * * 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 "dolphinview.h" -#include - #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dolphincontroller.h" #include "dolphinstatusbar.h" #include "dolphinmainwindow.h" #include "dolphindirlister.h" #include "dolphinsortfilterproxymodel.h" #include "dolphindetailsview.h" #include "dolphiniconsview.h" #include "dolphincontextmenu.h" #include "filterbar.h" #include "renamedialog.h" #include "urlnavigator.h" #include "viewproperties.h" DolphinView::DolphinView(DolphinMainWindow* mainWindow, QWidget* parent, const KUrl& url, Mode mode, bool showHiddenFiles) : QWidget(parent), m_showProgress(false), m_mode(mode), m_iconSize(0), m_folderCount(0), m_fileCount(0), m_mainWindow(mainWindow), m_topLayout(0), m_urlNavigator(0), m_controller(0), m_iconsView(0), m_detailsView(0), m_fileItemDelegate(0), m_filterBar(0), m_statusBar(0), m_dirModel(0), m_dirLister(0), m_proxyModel(0) { hide(); setFocusPolicy(Qt::StrongFocus); m_topLayout = new QVBoxLayout(this); m_topLayout->setSpacing(0); m_topLayout->setMargin(0); connect(m_mainWindow, SIGNAL(activeViewChanged()), this, SLOT(updateActivationState())); m_urlNavigator = new UrlNavigator(url, this); m_urlNavigator->setShowHiddenFiles(showHiddenFiles); connect(m_urlNavigator, SIGNAL(urlChanged(const KUrl&)), this, SLOT(loadDirectory(const KUrl&))); connect(m_urlNavigator, SIGNAL(urlsDropped(const KUrl::List&, const KUrl&)), this, SLOT(dropUrls(const KUrl::List&, const KUrl&))); connect(m_urlNavigator, SIGNAL(activated()), this, SLOT(requestActivation())); connect(this, SIGNAL(contentsMoved(int, int)), m_urlNavigator, SLOT(storeContentsPosition(int, int))); m_statusBar = new DolphinStatusBar(this); m_dirLister = new DolphinDirLister(); m_dirLister->setAutoUpdate(true); m_dirLister->setMainWindow(this); m_dirLister->setShowingDotFiles(showHiddenFiles); m_dirLister->setDelayedMimeTypes(true); connect(m_dirLister, SIGNAL(clear()), this, SLOT(updateStatusBar())); connect(m_dirLister, SIGNAL(percent(int)), this, SLOT(updateProgress(int))); connect(m_dirLister, SIGNAL(deleteItem(KFileItem*)), this, SLOT(updateStatusBar())); connect(m_dirLister, SIGNAL(completed()), this, SLOT(updateItemCount())); connect(m_dirLister, SIGNAL(completed()), this, SLOT(updateCutItems())); connect(m_dirLister, SIGNAL(newItems(const KFileItemList&)), this, SLOT(generatePreviews(const KFileItemList&))); connect(m_dirLister, SIGNAL(infoMessage(const QString&)), this, SLOT(showInfoMessage(const QString&))); connect(m_dirLister, SIGNAL(errorMessage(const QString&)), this, SLOT(showErrorMessage(const QString&))); m_dirModel = new KDirModel(); m_dirModel->setDirLister(m_dirLister); m_dirModel->setDropsAllowed(KDirModel::DropOnDirectory); m_proxyModel = new DolphinSortFilterProxyModel(this); m_proxyModel->setSourceModel(m_dirModel); m_controller = new DolphinController(this); connect(m_controller, SIGNAL(requestContextMenu(const QPoint&)), this, SLOT(openContextMenu(const QPoint&))); connect(m_controller, SIGNAL(urlsDropped(const KUrl::List&, const QModelIndex&, QWidget*)), this, SLOT(dropUrls(const KUrl::List&, const QModelIndex&, QWidget*))); connect(m_controller, SIGNAL(sortingChanged(DolphinView::Sorting)), this, SLOT(updateSorting(DolphinView::Sorting))); connect(m_controller, SIGNAL(sortOrderChanged(Qt::SortOrder)), this, SLOT(updateSortOrder(Qt::SortOrder))); connect(m_controller, SIGNAL(itemTriggered(const QModelIndex&)), this, SLOT(triggerItem(const QModelIndex&))); connect(m_controller, SIGNAL(selectionChanged()), this, SLOT(emitSelectionChangedSignal())); connect(m_controller, SIGNAL(activated()), this, SLOT(requestActivation())); createView(); m_iconSize = K3Icon::SizeMedium; m_filterBar = new FilterBar(this); m_filterBar->hide(); connect(m_filterBar, SIGNAL(filterChanged(const QString&)), this, SLOT(changeNameFilter(const QString&))); connect(m_filterBar, SIGNAL(closeRequest()), this, SLOT(closeFilterBar())); m_topLayout->addWidget(m_urlNavigator); m_topLayout->addWidget(itemView()); m_topLayout->addWidget(m_filterBar); m_topLayout->addWidget(m_statusBar); loadDirectory(m_urlNavigator->url()); } DolphinView::~DolphinView() { delete m_dirLister; m_dirLister = 0; } void DolphinView::setUrl(const KUrl& url) { m_urlNavigator->setUrl(url); m_controller->setUrl(url); } const KUrl& DolphinView::url() const { return m_urlNavigator->url(); } bool DolphinView::isActive() const { return m_mainWindow->activeView() == this; } void DolphinView::setMode(Mode mode) { if (mode == m_mode) { return; // the wished mode is already set } m_mode = mode; ViewProperties props(m_urlNavigator->url()); props.setViewMode(m_mode); createView(); startDirLister(m_urlNavigator->url()); emit modeChanged(); } DolphinView::Mode DolphinView::mode() const { return m_mode; } void DolphinView::setShowPreview(bool show) { ViewProperties props(m_urlNavigator->url()); props.setShowPreview(show); m_controller->setShowPreview(show); emit showPreviewChanged(); reload(); } bool DolphinView::showPreview() const { return m_controller->showPreview(); } void DolphinView::setShowHiddenFiles(bool show) { if (m_dirLister->showingDotFiles() == show) { return; } ViewProperties props(m_urlNavigator->url()); props.setShowHiddenFiles(show); props.save(); m_dirLister->setShowingDotFiles(show); m_urlNavigator->setShowHiddenFiles(show); emit showHiddenFilesChanged(); reload(); } bool DolphinView::showHiddenFiles() const { return m_dirLister->showingDotFiles(); } void DolphinView::renameSelectedItems() { + DolphinView* view = mainWindow()->activeView(); const KUrl::List urls = selectedUrls(); if (urls.count() > 1) { // More than one item has been selected for renaming. Open // a rename dialog and rename all items afterwards. RenameDialog dialog(urls); if (dialog.exec() == QDialog::Rejected) { return; } - DolphinView* view = mainWindow()->activeView(); const QString& newName = dialog.newName(); if (newName.isEmpty()) { - view->statusBar()->setMessage(i18n("The new item name is invalid."), + view->statusBar()->setMessage(dialog.errorString(), DolphinStatusBar::Error); } else { // TODO: check how this can be integrated into KonqUndoManager/KonqOperations //UndoManager& undoMan = UndoManager::instance(); //undoMan.beginMacro(); - assert(newName.contains('#')); + Q_ASSERT(newName.contains('#')); const int urlsCount = urls.count(); // iterate through all selected items and rename them... const int replaceIndex = newName.indexOf('#'); - assert(replaceIndex >= 0); + Q_ASSERT(replaceIndex >= 0); for (int i = 0; i < urlsCount; ++i) { const KUrl& source = urls[i]; QString number; number.setNum(i + 1); QString name(newName); name.replace(replaceIndex, 1, number); if (source.fileName() != name) { KUrl dest(source.upUrl()); dest.addPath(name); const bool destExists = KIO::NetAccess::exists(dest, false, view); if (destExists) { view->statusBar()->setMessage(i18n("Renaming failed (item '%1' already exists).",name), DolphinStatusBar::Error); break; } else if (KIO::NetAccess::file_move(source, dest)) { // TODO: From the users point of view he executed one 'rename n files' operation, // but internally we store it as n 'rename 1 file' operations for the undo mechanism. //DolphinCommand command(DolphinCommand::Rename, source, dest); //undoMan.addCommand(command); } } } //undoMan.endMacro(); } } else { // Only one item has been selected for renaming. Use the custom // renaming mechanism from the views. - assert(urls.count() == 1); - // TODO: - /*if (m_mode == DetailsView) { - Q3ListViewItem* item = m_iconsView->firstChild(); - while (item != 0) { - if (item->isSelected()) { - m_iconsView->rename(item, DolphinDetailsView::NameColumn); - break; - } - item = item->nextSibling(); - } + Q_ASSERT(urls.count() == 1); + + // TODO: until KFileItemDelegate supports editing, use the the Dolphin + // rename dialog as temporary workaround: + RenameDialog dialog(urls); + if (dialog.exec() == QDialog::Rejected) { + return; + } + + const QString& newName = dialog.newName(); + if (newName.isEmpty()) { + view->statusBar()->setMessage(dialog.errorString(), + DolphinStatusBar::Error); } else { - KFileIconViewItem* item = static_cast(m_iconsView->firstItem()); - while (item != 0) { - if (item->isSelected()) { - item->rename(); - break; - } - item = static_cast(item->nextItem()); - } - }*/ + const KUrl& oldUrl = urls.first(); + KUrl newUrl = oldUrl.upUrl(); + newUrl.addPath(newName); + m_mainWindow->rename(oldUrl, newUrl); + } } } void DolphinView::selectAll() { selectAll(QItemSelectionModel::Select); } void DolphinView::invertSelection() { selectAll(QItemSelectionModel::Toggle); } DolphinStatusBar* DolphinView::statusBar() const { return m_statusBar; } int DolphinView::contentsX() const { return itemView()->horizontalScrollBar()->value(); } int DolphinView::contentsY() const { return itemView()->verticalScrollBar()->value(); } void DolphinView::refreshSettings() { startDirLister(m_urlNavigator->url()); } void DolphinView::emitRequestItemInfo(const KUrl& url) { emit requestItemInfo(url); } bool DolphinView::isFilterBarVisible() const { return m_filterBar->isVisible(); } bool DolphinView::isUrlEditable() const { return m_urlNavigator->isUrlEditable(); } void DolphinView::zoomIn() { m_controller->triggerZoomIn(); } void DolphinView::zoomOut() { m_controller->triggerZoomOut(); } bool DolphinView::isZoomInPossible() const { return m_controller->isZoomInPossible(); } bool DolphinView::isZoomOutPossible() const { return m_controller->isZoomOutPossible(); } void DolphinView::setSorting(Sorting sorting) { if (sorting != this->sorting()) { updateSorting(sorting); } } DolphinView::Sorting DolphinView::sorting() const { return m_proxyModel->sorting(); } void DolphinView::setSortOrder(Qt::SortOrder order) { if (sortOrder() != order) { updateSortOrder(order); } } Qt::SortOrder DolphinView::sortOrder() const { return m_proxyModel->sortOrder(); } void DolphinView::setAdditionalInfo(KFileItemDelegate::AdditionalInformation info) { ViewProperties props(m_urlNavigator->url()); props.setAdditionalInfo(info); m_fileItemDelegate->setAdditionalInformation(info); emit additionalInfoChanged(info); reload(); } KFileItemDelegate::AdditionalInformation DolphinView::additionalInfo() const { return m_fileItemDelegate->additionalInformation(); } void DolphinView::goBack() { m_urlNavigator->goBack(); } void DolphinView::goForward() { m_urlNavigator->goForward(); } void DolphinView::goUp() { m_urlNavigator->goUp(); } void DolphinView::goHome() { m_urlNavigator->goHome(); } void DolphinView::setUrlEditable(bool editable) { m_urlNavigator->editUrl(editable); } const QLinkedList DolphinView::urlHistory(int& index) const { return m_urlNavigator->history(index); } bool DolphinView::hasSelection() const { return itemView()->selectionModel()->hasSelection(); } KFileItemList DolphinView::selectedItems() const { const QAbstractItemView* view = itemView(); // Our view has a selection, we will map them back to the DirModel // and then fill the KFileItemList. Q_ASSERT((view != 0) && (view->selectionModel() != 0)); const QItemSelection selection = m_proxyModel->mapSelectionToSource(view->selectionModel()->selection()); KFileItemList itemList; const QModelIndexList indexList = selection.indexes(); QModelIndexList::const_iterator end = indexList.end(); for (QModelIndexList::const_iterator it = indexList.begin(); it != end; ++it) { Q_ASSERT((*it).isValid()); KFileItem* item = m_dirModel->itemForIndex(*it); if (item != 0) { itemList.append(item); } } return itemList; } KUrl::List DolphinView::selectedUrls() const { KUrl::List urls; const KFileItemList list = selectedItems(); KFileItemList::const_iterator it = list.begin(); const KFileItemList::const_iterator end = list.end(); while (it != end) { KFileItem* item = *it; urls.append(item->url()); ++it; } return urls; } KFileItem* DolphinView::fileItem(const QModelIndex index) const { const QModelIndex dirModelIndex = m_proxyModel->mapToSource(index); return m_dirModel->itemForIndex(dirModelIndex); } void DolphinView::rename(const KUrl& source, const QString& newName) { bool ok = false; if (newName.isEmpty() || (source.fileName() == newName)) { return; } KUrl dest(source.upUrl()); dest.addPath(newName); const bool destExists = KIO::NetAccess::exists(dest, false, mainWindow()->activeView()); if (destExists) { // the destination already exists, hence ask the user // how to proceed... KIO::RenameDialog renameDialog(this, i18n("File Already Exists"), source.path(), dest.path(), KIO::M_OVERWRITE); switch (renameDialog.exec()) { case KIO::R_OVERWRITE: // the destination should be overwritten ok = KIO::NetAccess::file_move(source, dest, -1, true); break; case KIO::R_RENAME: { // a new name for the destination has been used KUrl newDest(renameDialog.newDestUrl()); ok = KIO::NetAccess::file_move(source, newDest); break; } default: // the renaming operation has been canceled reload(); return; } } else { // no destination exists, hence just move the file to // do the renaming ok = KIO::NetAccess::file_move(source, dest); } const QString destFileName = dest.fileName(); if (ok) { m_statusBar->setMessage(i18n("Renamed file '%1' to '%2'.",source.fileName(), destFileName), DolphinStatusBar::OperationCompleted); KonqOperations::rename(this, source, destFileName); } else { m_statusBar->setMessage(i18n("Renaming of file '%1' to '%2' failed.",source.fileName(), destFileName), DolphinStatusBar::Error); reload(); } } void DolphinView::reload() { startDirLister(m_urlNavigator->url(), true); } void DolphinView::mouseReleaseEvent(QMouseEvent* event) { QWidget::mouseReleaseEvent(event); mainWindow()->setActiveView(this); } DolphinMainWindow* DolphinView::mainWindow() const { return m_mainWindow; } void DolphinView::loadDirectory(const KUrl& url) { const ViewProperties props(url); const Mode mode = props.viewMode(); if (m_mode != mode) { m_mode = mode; createView(); emit modeChanged(); } const bool showHiddenFiles = props.showHiddenFiles(); if (showHiddenFiles != m_dirLister->showingDotFiles()) { m_dirLister->setShowingDotFiles(showHiddenFiles); emit showHiddenFilesChanged(); } const DolphinView::Sorting sorting = props.sorting(); if (sorting != m_proxyModel->sorting()) { m_proxyModel->setSorting(sorting); emit sortingChanged(sorting); } const Qt::SortOrder sortOrder = props.sortOrder(); if (sortOrder != m_proxyModel->sortOrder()) { m_proxyModel->setSortOrder(sortOrder); emit sortOrderChanged(sortOrder); } KFileItemDelegate::AdditionalInformation info = props.additionalInfo(); if (info != m_fileItemDelegate->additionalInformation()) { m_fileItemDelegate->setAdditionalInformation(info); emit additionalInfoChanged(info); } const bool showPreview = props.showPreview(); if (showPreview != m_controller->showPreview()) { m_controller->setShowPreview(showPreview); emit showPreviewChanged(); } startDirLister(url); emit urlChanged(url); m_statusBar->clear(); } void DolphinView::triggerItem(const QModelIndex& index) { if (!isValidNameIndex(index)) { return; } const Qt::KeyboardModifiers modifier = QApplication::keyboardModifiers(); if ((modifier & Qt::ShiftModifier) || (modifier & Qt::ControlModifier)) { // items are selected by the user, hence don't trigger the // item specified by 'index' return; } KFileItem* item = m_dirModel->itemForIndex(m_proxyModel->mapToSource(index)); if (item == 0) { return; } // Prefer the local path over the URL. This assures that the // volume space information is correct. Assuming that the URL is media:/sda1, // and the local path is /windows/C: For the URL the space info is related // to the root partition (and hence wrong) and for the local path the space // info is related to the windows partition (-> correct). const QString localPath(item->localPath()); KUrl url; if (localPath.isEmpty()) { url = item->url(); } else { url = localPath; } if (item->isDir()) { setUrl(url); } else if (item->isFile()) { // allow to browse through ZIP and tar files KMimeType::Ptr mime = item->mimeTypePtr(); if (mime->is("application/x-zip")) { url.setProtocol("zip"); setUrl(url); } else if (mime->is("application/x-tar") || mime->is("application/x-tarz") || mime->is("application/x-tbz") || mime->is("application/x-tgz") || mime->is("application/x-tzo")) { url.setProtocol("tar"); setUrl(url); } else { item->run(); } } else { item->run(); } } void DolphinView::updateProgress(int percent) { if (m_showProgress) { m_statusBar->setProgress(percent); } } void DolphinView::updateItemCount() { if (m_showProgress) { m_statusBar->setProgressText(QString()); m_statusBar->setProgress(100); m_showProgress = false; } KFileItemList items(m_dirLister->items()); KFileItemList::const_iterator it = items.begin(); const KFileItemList::const_iterator end = items.end(); m_fileCount = 0; m_folderCount = 0; while (it != end) { KFileItem* item = *it; if (item->isDir()) { ++m_folderCount; } else { ++m_fileCount; } ++it; } updateStatusBar(); QTimer::singleShot(0, this, SLOT(restoreContentsPos())); } void DolphinView::generatePreviews(const KFileItemList& items) { if (m_controller->showPreview()) { KIO::PreviewJob* job = KIO::filePreview(items, 128); connect(job, SIGNAL(gotPreview(const KFileItem*, const QPixmap&)), this, SLOT(showPreview(const KFileItem*, const QPixmap&))); } const QMimeData* mimeData = QApplication::clipboard()->mimeData(); if (KonqMimeData::decodeIsCutSelection(mimeData)) { QTimer::singleShot(0, this, SLOT(applyCutEffect())); } } void DolphinView::showPreview(const KFileItem* item, const QPixmap& pixmap) { Q_ASSERT(item != 0); const QModelIndex idx = m_dirModel->indexForItem(*item); if (idx.isValid() && (idx.column() == 0)) { const QMimeData* mimeData = QApplication::clipboard()->mimeData(); if (KonqMimeData::decodeIsCutSelection(mimeData) && isCutItem(*item)) { KIconEffect iconEffect; QPixmap cutPixmap = iconEffect.apply(pixmap, K3Icon::Desktop, K3Icon::DisabledState); m_dirModel->setData(idx, cutPixmap, Qt::DecorationRole); } else { m_dirModel->setData(idx, pixmap, Qt::DecorationRole); } } } void DolphinView::restoreContentsPos() { int index = 0; const QLinkedList history = urlHistory(index); if (!history.isEmpty()) { QAbstractItemView* view = itemView(); // TODO: view->setCurrentItem(history[index].currentFileName()); QLinkedList::const_iterator it = history.begin(); it += index; view->horizontalScrollBar()->setValue((*it).contentsX()); view->verticalScrollBar()->setValue((*it).contentsY()); } } void DolphinView::showInfoMessage(const QString& msg) { m_statusBar->setMessage(msg, DolphinStatusBar::Information); } void DolphinView::showErrorMessage(const QString& msg) { m_statusBar->setMessage(msg, DolphinStatusBar::Error); } void DolphinView::emitSelectionChangedSignal() { emit selectionChanged(); } void DolphinView::closeFilterBar() { m_filterBar->hide(); emit showFilterBarChanged(false); } void DolphinView::startDirLister(const KUrl& url, bool reload) { if (!url.isValid()) { const QString location(url.pathOrUrl()); if (location.isEmpty()) { m_statusBar->setMessage(i18n("The location is empty."), DolphinStatusBar::Error); } else { m_statusBar->setMessage(i18n("The location '%1' is invalid.",location), DolphinStatusBar::Error); } return; } // Only show the directory loading progress if the status bar does // not contain another progress information. This means that // the directory loading progress information has the lowest priority. const QString progressText(m_statusBar->progressText()); m_showProgress = progressText.isEmpty() || (progressText == i18n("Loading directory...")); if (m_showProgress) { m_statusBar->setProgressText(i18n("Loading directory...")); m_statusBar->setProgress(0); } m_dirLister->stop(); m_dirLister->openUrl(url, false, reload); } QString DolphinView::defaultStatusBarText() const { return KIO::itemsSummaryString(m_fileCount + m_folderCount, m_fileCount, m_folderCount, 0, false); } QString DolphinView::selectionStatusBarText() const { QString text; const KFileItemList list = selectedItems(); if (list.isEmpty()) { // when an item is triggered, it is temporary selected but selectedItems() // will return an empty list return QString(); } int fileCount = 0; int folderCount = 0; KIO::filesize_t byteSize = 0; KFileItemList::const_iterator it = list.begin(); const KFileItemList::const_iterator end = list.end(); while (it != end){ KFileItem* item = *it; if (item->isDir()) { ++folderCount; } else { ++fileCount; byteSize += item->size(); } ++it; } if (folderCount > 0) { text = i18np("1 Folder selected", "%1 Folders selected", folderCount); if (fileCount > 0) { text += ", "; } } if (fileCount > 0) { const QString sizeText(KIO::convertSize(byteSize)); text += i18np("1 File selected (%2)", "%1 Files selected (%2)", fileCount, sizeText); } return text; } void DolphinView::showFilterBar(bool show) { - assert(m_filterBar != 0); + Q_ASSERT(m_filterBar != 0); if (show) { m_filterBar->show(); } else { m_filterBar->hide(); } } void DolphinView::updateStatusBar() { // As the item count information is less important // in comparison with other messages, it should only // be shown if: // - the status bar is empty or // - shows already the item count information or // - shows only a not very important information // - if any progress is given don't show the item count info at all const QString msg(m_statusBar->message()); const bool updateStatusBarMsg = (msg.isEmpty() || (msg == m_statusBar->defaultText()) || (m_statusBar->type() == DolphinStatusBar::Information)) && (m_statusBar->progress() == 100); const QString text(hasSelection() ? selectionStatusBarText() : defaultStatusBarText()); m_statusBar->setDefaultText(text); if (updateStatusBarMsg) { m_statusBar->setMessage(text, DolphinStatusBar::Default); } } void DolphinView::requestActivation() { m_mainWindow->setActiveView(this); } void DolphinView::updateCutItems() { const QMimeData* mimeData = QApplication::clipboard()->mimeData(); if (!KonqMimeData::decodeIsCutSelection(mimeData)) { return; } KFileItemList items(m_dirLister->items()); KFileItemList::const_iterator it = items.begin(); const KFileItemList::const_iterator end = items.end(); while (it != end) { KFileItem* item = *it; if (isCutItem(*item)) { QPixmap pixmap = item->pixmap(0); KIconEffect iconEffect; pixmap = iconEffect.apply(pixmap, K3Icon::Desktop, K3Icon::DisabledState); const QModelIndex idx = m_dirModel->indexForItem(*item); if (idx.isValid()) { m_dirModel->setData(idx, pixmap, Qt::DecorationRole); } } ++it; } } void DolphinView::changeNameFilter(const QString& nameFilter) { // The name filter of KDirLister does a 'hard' filtering, which // means that only the items are shown where the names match // exactly the filter. This is non-transparent for the user, which // just wants to have a 'soft' filtering: does the name contain // the filter string? QString adjustedFilter(nameFilter); adjustedFilter.insert(0, '*'); adjustedFilter.append('*'); // Use the ProxyModel to filter: // This code is #ifdefed as setNameFilter behaves // slightly different than the QSortFilterProxyModel // as it will not remove directories. I will ask // our beloved usability experts for input // -- z. #if 0 m_dirLister->setNameFilter(adjustedFilter); m_dirLister->emitChanges(); #else m_proxyModel->setFilterRegExp( nameFilter ); #endif } void DolphinView::openContextMenu(const QPoint& pos) { KFileItem* item = 0; const QModelIndex index = itemView()->indexAt(pos); if (isValidNameIndex(index)) { item = fileItem(index); } DolphinContextMenu contextMenu(this, item); contextMenu.open(); } void DolphinView::dropUrls(const KUrl::List& urls, const QModelIndex& index, QWidget* source) { KFileItem* directory = 0; if (isValidNameIndex(index)) { KFileItem* item = fileItem(index); - assert(item != 0); + Q_ASSERT(item != 0); if (item->isDir()) { // the URLs are dropped above a directory directory = item; } } if ((directory == 0) && (source == itemView())) { // The dropping is done into the same viewport where // the dragging has been started. Just ignore this... return; } const KUrl& destination = (directory == 0) ? url() : directory->url(); kDebug() << "DolphinView::dropUrls() - destination: " << destination.prettyUrl() << endl; dropUrls(urls, destination); } void DolphinView::dropUrls(const KUrl::List& urls, const KUrl& destination) { m_mainWindow->dropUrls(urls, destination); } void DolphinView::updateSorting(DolphinView::Sorting sorting) { ViewProperties props(url()); props.setSorting(sorting); m_proxyModel->setSorting(sorting); emit sortingChanged(sorting); } void DolphinView::updateSortOrder(Qt::SortOrder order) { ViewProperties props(url()); props.setSortOrder(order); m_proxyModel->setSortOrder(order); emit sortOrderChanged(order); } void DolphinView::emitContentsMoved() { emit contentsMoved(contentsX(), contentsY()); } void DolphinView::updateActivationState() { m_urlNavigator->setActive(isActive()); } void DolphinView::createView() { // delete current view QAbstractItemView* view = itemView(); if (view != 0) { m_topLayout->removeWidget(view); view->close(); view->deleteLater(); view = 0; m_iconsView = 0; m_detailsView = 0; m_fileItemDelegate = 0; } - assert(m_iconsView == 0); - assert(m_detailsView == 0); + Q_ASSERT(m_iconsView == 0); + Q_ASSERT(m_detailsView == 0); // ... and recreate it representing the current mode switch (m_mode) { case IconsView: m_iconsView = new DolphinIconsView(this, m_controller); view = m_iconsView; break; case DetailsView: m_detailsView = new DolphinDetailsView(this, m_controller); view = m_detailsView; break; } - assert(view != 0); + Q_ASSERT(view != 0); m_fileItemDelegate = new KFileItemDelegate(view); view->setItemDelegate(m_fileItemDelegate); view->setModel(m_proxyModel); view->setSelectionMode(QAbstractItemView::ExtendedSelection); new KMimeTypeResolver(view, m_dirModel); m_topLayout->insertWidget(1, view); connect(view->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), m_controller, SLOT(indicateSelectionChange())); connect(view->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(emitContentsMoved())); connect(view->horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(emitContentsMoved())); } void DolphinView::selectAll(QItemSelectionModel::SelectionFlags flags) { QItemSelectionModel* selectionModel = itemView()->selectionModel(); const QAbstractItemModel* itemModel = selectionModel->model(); const QModelIndex topLeft = itemModel->index(0, 0); const QModelIndex bottomRight = itemModel->index(itemModel->rowCount() - 1, itemModel->columnCount() - 1); QItemSelection selection(topLeft, bottomRight); selectionModel->select(selection, flags); } QAbstractItemView* DolphinView::itemView() const { Q_ASSERT((m_iconsView == 0) || (m_detailsView == 0)); if (m_detailsView != 0) { return m_detailsView; } return m_iconsView; } bool DolphinView::isValidNameIndex(const QModelIndex& index) const { return index.isValid() && (index.column() == KDirModel::Name); } bool DolphinView::isCutItem(const KFileItem& item) const { const QMimeData* mimeData = QApplication::clipboard()->mimeData(); const KUrl::List cutUrls = KUrl::List::fromMimeData(mimeData); const KUrl& itemUrl = item.url(); KUrl::List::const_iterator it = cutUrls.begin(); const KUrl::List::const_iterator end = cutUrls.end(); while (it != end){ if (*it == itemUrl) { return true; } ++it; } return false; } #include "dolphinview.moc" diff --git a/src/renamedialog.cpp b/src/renamedialog.cpp index 8aabb2f83..e68feff8d 100644 --- a/src/renamedialog.cpp +++ b/src/renamedialog.cpp @@ -1,99 +1,104 @@ /*************************************************************************** - * Copyright (C) 2006 by Peter Penz * - * peter.penz@gmx.at * + * Copyright (C) 2006 by Peter Penz (peter.penz@gmx.at) * * * * 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 "renamedialog.h" -#include -#include -#include -#include -//Added by qt3to4: -#include -#include + #include +#include + +#include +#include RenameDialog::RenameDialog(const KUrl::List& items) : KDialog() { setCaption(i18n("Rename Items")); setButtons(Ok|Cancel); setDefaultButton(Ok); setButtonGuiItem(Ok, KGuiItem(i18n("Rename"), "dialog-apply")); - QWidget *page = new QWidget(this); + QWidget* page = new QWidget(this); setMainWidget(page); - Q3VBoxLayout* topLayout = new Q3VBoxLayout(page, 0, spacingHint()); + QVBoxLayout* topLayout = new QVBoxLayout(page); topLayout->setMargin(KDialog::marginHint()); const int itemCount = items.count(); - QLabel* editLabel = new QLabel(i18n("Rename the %1 selected items to:",itemCount), + QLabel* editLabel = new QLabel(i18n("Rename the %1 selected items to:", itemCount), page); m_lineEdit = new KLineEdit(page); m_newName = i18n("New name #"); - assert(itemCount > 1); + + // TODO: reactivate assertion as soon as KFileItemDelegate supports renaming of + // single items + //Q_ASSERT(itemCount > 1); + QString postfix(items[0].prettyUrl().section('.',1)); if (postfix.length() > 0) { // The first item seems to have a postfix (e. g. 'jpg' or 'txt'). Now // check whether all other items have the same postfix. If this is the // case, add this postfix to the name suggestion. postfix.insert(0, '.'); for (int i = 1; i < itemCount; ++i) { if (!items[i].prettyUrl().contains(postfix)) { // at least one item does not have the same postfix postfix.truncate(0); break; } } } const int selectionLength = m_newName.length(); if (postfix.length() > 0) { m_newName.append(postfix); } m_lineEdit->setText(m_newName); m_lineEdit->setSelection(0, selectionLength - 1); m_lineEdit->setFocus(); QLabel* infoLabel = new QLabel(i18n("(# will be replaced by ascending numbers)"), page); topLayout->addWidget(editLabel); topLayout->addWidget(m_lineEdit); topLayout->addWidget(infoLabel); } RenameDialog::~RenameDialog() { } void RenameDialog::slotButtonClicked(int button) { if (button==Ok) { m_newName = m_lineEdit->text(); - if (m_newName.contains('#') != 1) { + if (m_newName.isEmpty()) { + m_errorString = i18n("The new name is empty. A name with at least one character must be entered."); + } + else if (m_newName.contains('#') != 1) { m_newName.truncate(0); + m_errorString = i18n("The name must contain exactly one # character."); } } KDialog::slotButtonClicked(button); } #include "renamedialog.moc" diff --git a/src/renamedialog.h b/src/renamedialog.h index 093484f2b..c08856f8c 100644 --- a/src/renamedialog.h +++ b/src/renamedialog.h @@ -1,67 +1,78 @@ /*************************************************************************** - * Copyright (C) 2006 by Peter Penz * - * peter.penz@gmx.at * + * Copyright (C) 2006 by Peter Penz (peter.penz@gmx.at) * * * * 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 RENAMEDIALOG_H #define RENAMEDIALOG_H #include #include -#include + +#include class KLineEdit; /** * @brief Dialog for renaming a variable number of files. * * The renaming is not done by the dialog, the invoker * must do this itself: * \code * RenameDialog dialog(...); * if (dialog.exec() == QDialog::Accepted) { * const QString& newName = dialog.newName(); - * // ... rename items corresponding to the new name + * if (newName.isEmpty()) { + * // an invalid name has been chosen, use + * // dialog.errorString() to tell the user about this + * } + * else { + * // rename items corresponding to the new name + * } * } * \endcode - * @author Peter Penz */ class RenameDialog : public KDialog { Q_OBJECT public: explicit RenameDialog(const KUrl::List& items); virtual ~RenameDialog(); /** * Returns the new name of the items. If the returned string is not empty, * then it is assured that the string contains exactly one character #, * which should be replaced by ascending numbers. An empty string indicates * that the user has removed the # character. */ const QString& newName() const { return m_newName; } + /** + * Returns the error string, if Dialog::newName() returned an empty string. + */ + const QString& errorString() const { return m_errorString; } + protected slots: virtual void slotButtonClicked(int button); private: KLineEdit* m_lineEdit; QString m_newName; + QString m_errorString; }; #endif