X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/98a4aa10ef09087ce6498d09461036cb0ab9cb4d..09bf5b66dc5136885c36e6b702047d56b627770d:/src/views/dolphinview.cpp diff --git a/src/views/dolphinview.cpp b/src/views/dolphinview.cpp index ff5c2988a..20bc9f522 100644 --- a/src/views/dolphinview.cpp +++ b/src/views/dolphinview.cpp @@ -33,6 +33,8 @@ #include #include +#include +#include #include #include #include @@ -73,7 +75,7 @@ #include "zoomlevelinfo.h" #ifdef HAVE_NEPOMUK - #include + #include #endif namespace { @@ -98,9 +100,11 @@ DolphinView::DolphinView(const KUrl& url, QWidget* parent) : m_toolTipManager(0), m_selectionChangedTimer(0), m_currentItemUrl(), + m_scrollToCurrentItem(false), m_restoredContentsPosition(), - m_createdItemUrl(), m_selectedUrls(), + m_clearSelectionBeforeSelectingNewItems(false), + m_markFirstNewlySelectedItemAsCurrent(false), m_versionControlObserver(0) { m_topLayout = new QVBoxLayout(this); @@ -122,7 +126,6 @@ DolphinView::DolphinView(const KUrl& url, QWidget* parent) : m_model = new KFileItemModel(this); m_view = new DolphinItemListView(); m_view->setEnabledSelectionToggles(GeneralSettings::showSelectionToggle()); - m_view->setEnlargeSmallPreviews(GeneralSettings::enlargeSmallPreviews()); m_view->setVisibleRoles(QList() << "text"); applyModeToView(); @@ -130,6 +133,10 @@ DolphinView::DolphinView(const KUrl& url, QWidget* parent) : const int delay = GeneralSettings::autoExpandFolders() ? 750 : -1; controller->setAutoActivationDelay(delay); + // The EnlargeSmallPreviews setting can only be changed after the model + // has been set in the view by KItemListController. + m_view->setEnlargeSmallPreviews(GeneralSettings::enlargeSmallPreviews()); + m_container = new KItemListContainer(controller, this); m_container->installEventFilter(this); setFocusProxy(m_container); @@ -151,6 +158,7 @@ DolphinView::DolphinView(const KUrl& url, QWidget* parent) : connect(m_model, SIGNAL(directoryLoadingStarted()), this, SLOT(slotDirectoryLoadingStarted())); connect(m_model, SIGNAL(directoryLoadingCompleted()), this, SLOT(slotDirectoryLoadingCompleted())); + connect(m_model, SIGNAL(directoryLoadingCanceled()), this, SIGNAL(directoryLoadingCanceled())); connect(m_model, SIGNAL(directoryLoadingProgress(int)), this, SIGNAL(directoryLoadingProgress(int))); connect(m_model, SIGNAL(directorySortingProgress(int)), this, SIGNAL(directorySortingProgress(int))); connect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet)), @@ -160,6 +168,7 @@ DolphinView::DolphinView(const KUrl& url, QWidget* parent) : connect(m_model, SIGNAL(infoMessage(QString)), this, SIGNAL(infoMessage(QString))); connect(m_model, SIGNAL(errorMessage(QString)), this, SIGNAL(errorMessage(QString))); connect(m_model, SIGNAL(directoryRedirection(KUrl,KUrl)), this, SLOT(slotDirectoryRedirection(KUrl,KUrl))); + connect(m_model, SIGNAL(urlIsFileError(KUrl)), this, SIGNAL(urlIsFileError(KUrl))); m_view->installEventFilter(this); connect(m_view, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder)), @@ -169,9 +178,7 @@ DolphinView::DolphinView(const KUrl& url, QWidget* parent) : connect(m_view, SIGNAL(visibleRolesChanged(QList,QList)), this, SLOT(slotVisibleRolesChangedByHeader(QList,QList))); connect(m_view, SIGNAL(roleEditingCanceled(int,QByteArray,QVariant)), - this, SLOT(slotRoleEditingCanceled(int,QByteArray,QVariant))); - connect(m_view, SIGNAL(roleEditingFinished(int,QByteArray,QVariant)), - this, SLOT(slotRoleEditingFinished(int,QByteArray,QVariant))); + this, SLOT(slotRoleEditingCanceled())); connect(m_view->header(), SIGNAL(columnWidthChanged(QByteArray,qreal,qreal)), this, SLOT(slotHeaderColumnWidthChanged(QByteArray,qreal,qreal))); @@ -241,9 +248,12 @@ void DolphinView::setMode(Mode mode) if (mode != m_mode) { ViewProperties props(viewPropertiesUrl()); props.setViewMode(mode); - props.save(); - applyViewProperties(); + // We pass the new ViewProperties to applyViewProperties, rather than + // storing them on disk and letting applyViewProperties() read them + // from there, to prevent that changing the view mode fails if the + // .directory file is not writable (see bug 318534). + applyViewProperties(props); } } @@ -339,10 +349,12 @@ int DolphinView::itemsCount() const KFileItemList DolphinView::selectedItems() const { const KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager(); - const QSet selectedIndexes = selectionManager->selectedItems(); + QList selectedIndexes = selectionManager->selectedItems().toList(); + + qSort(selectedIndexes); KFileItemList selectedItems; - QSetIterator it(selectedIndexes); + QListIterator it(selectedIndexes); while (it.hasNext()) { const int index = it.next(); selectedItems.append(m_model->fileItem(index)); @@ -364,6 +376,7 @@ void DolphinView::markUrlsAsSelected(const QList& urls) void DolphinView::markUrlAsCurrent(const KUrl& url) { m_currentItemUrl = url; + m_scrollToCurrentItem = true; } void DolphinView::selectItems(const QRegExp& pattern, bool enabled) @@ -510,6 +523,16 @@ QString DolphinView::nameFilter() const return m_model->nameFilter(); } +void DolphinView::setMimeTypeFilters(const QStringList& filters) +{ + return m_model->setMimeTypeFilters(filters); +} + +QStringList DolphinView::mimeTypeFilters() const +{ + return m_model->mimeTypeFilters(); +} + QString DolphinView::statusBarText() const { QString summary; @@ -585,11 +608,16 @@ void DolphinView::setUrl(const KUrl& url) return; } + clearSelection(); + emit urlAboutToBeChanged(url); m_url = url; hideToolTip(); + disconnect(m_view, SIGNAL(roleEditingFinished(int,QByteArray,QVariant)), + this, SLOT(slotRoleEditingFinished(int,QByteArray,QVariant))); + // It is important to clear the items from the model before // applying the view properties, otherwise expensive operations // might be done on the existing items although they get cleared @@ -615,31 +643,35 @@ void DolphinView::invertSelection() void DolphinView::clearSelection() { + m_selectedUrls.clear(); m_container->controller()->selectionManager()->clearSelection(); } void DolphinView::renameSelectedItems() { const KFileItemList items = selectedItems(); - if (items.isEmpty()) { - return; - } - - if (items.count() == 1) { - const int index = m_model->index(items.first()); - m_view->editRole(index, "text"); - } else { - RenameDialog* dialog = new RenameDialog(this, items); - dialog->setAttribute(Qt::WA_DeleteOnClose); - dialog->show(); - dialog->raise(); - dialog->activateWindow(); - } - - // Assure that the current index remains visible when KFileItemModel - // will notify the view about changed items (which might result in - // a changed sorting). - m_assureVisibleCurrentIndex = true; + if (items.isEmpty()) { + return; + } + + if (items.count() == 1 && GeneralSettings::renameInline()) { + const int index = m_model->index(items.first()); + m_view->editRole(index, "text"); + + connect(m_view, SIGNAL(roleEditingFinished(int,QByteArray,QVariant)), + this, SLOT(slotRoleEditingFinished(int,QByteArray,QVariant))); + } else { + RenameDialog* dialog = new RenameDialog(this, items); + dialog->setAttribute(Qt::WA_DeleteOnClose); + dialog->show(); + dialog->raise(); + dialog->activateWindow(); + } + + // Assure that the current index remains visible when KFileItemModel + // will notify the view about changed items (which might result in + // a changed sorting). + m_assureVisibleCurrentIndex = true; } void DolphinView::trashSelectedItems() @@ -743,6 +775,20 @@ void DolphinView::hideEvent(QHideEvent* event) QWidget::hideEvent(event); } +bool DolphinView::event(QEvent* event) +{ + /* See Bug 297355 + * Dolphin leaves file preview tooltips open even when is not visible. + * + * Hide tool-tip when Dolphin loses focus. + */ + if (event->type() == QEvent::WindowDeactivate) { + hideToolTip(); + } + + return QWidget::event(event); +} + void DolphinView::activate() { setActive(true); @@ -760,33 +806,56 @@ void DolphinView::slotItemsActivated(const QSet& indexes) { Q_ASSERT(indexes.count() >= 2); + if (indexes.count() > 5) { + QString question = i18np("Are you sure you want to open 1 item?", "Are you sure you want to open %1 items?", indexes.count()); + const int answer = KMessageBox::warningYesNo(this, question); + if (answer != KMessageBox::Yes) { + return; + } + } + KFileItemList items; + items.reserve(indexes.count()); QSetIterator it(indexes); while (it.hasNext()) { const int index = it.next(); - items.append(m_model->fileItem(index)); - } + KFileItem item = m_model->fileItem(index); + const KUrl& url = openItemAsFolderUrl(item); - foreach (const KFileItem& item, items) { - if (item.isDir()) { - emit tabRequested(item.url()); + if (!url.isEmpty()) { // Open folders in new tabs + emit tabRequested(url); } else { - emit itemActivated(item); + items.append(item); } } + + if (items.count() == 1) { + emit itemActivated(items.first()); + } else if (items.count() > 1) { + emit itemsActivated(items); + } } void DolphinView::slotItemMiddleClicked(int index) { - const KFileItem item = m_model->fileItem(index); - if (item.isDir() || isTabsForFilesEnabled()) { + const KFileItem& item = m_model->fileItem(index); + const KUrl& url = openItemAsFolderUrl(item); + if (!url.isEmpty()) { + emit tabRequested(url); + } else if (isTabsForFilesEnabled()) { emit tabRequested(item.url()); } } void DolphinView::slotItemContextMenuRequested(int index, const QPointF& pos) { + // Force emit of a selection changed signal before we request the + // context menu, to update the edit-actions first. (See Bug 294013) + if (m_selectionChangedTimer->isActive()) { + emitSelectionChangedSignal(); + } + const KFileItem item = m_model->fileItem(index); emit requestContextMenu(pos.toPoint(), item, url(), QList()); } @@ -808,10 +877,10 @@ void DolphinView::slotHeaderContextMenuRequested(const QPointF& pos) bool nepomukRunning = false; bool indexingEnabled = false; #ifdef HAVE_NEPOMUK - nepomukRunning = (Nepomuk::ResourceManager::instance()->initialized()); + nepomukRunning = (Nepomuk2::ResourceManager::instance()->initialized()); if (nepomukRunning) { KConfig config("nepomukserverrc"); - indexingEnabled = config.group("Service-nepomukfileindexer").readEntry("autostart", false); + indexingEnabled = config.group("Service-nepomukfileindexer").readEntry("autostart", true); } #endif @@ -976,15 +1045,19 @@ void DolphinView::slotItemDropEvent(int index, QGraphicsSceneDragDropEvent* even event->buttons(), event->modifiers()); - const QString error = DragAndDropHelper::dropUrls(destItem, destUrl, &dropEvent); + QString error; + KonqOperations* op = DragAndDropHelper::dropUrls(destItem, destUrl, &dropEvent, error); if (!error.isEmpty()) { - emit errorMessage(error); + emit infoMessage(error); } - if (destUrl == url()) { + if (op && destUrl == url()) { // Mark the dropped urls as selected. - markPastedUrlsAsSelected(event->mimeData()); + m_clearSelectionBeforeSelectingNewItems = true; + connect(op, SIGNAL(aboutToCreate(KUrl::List)), this, SLOT(slotAboutToCreate(KUrl::List))); } + + setActive(true); } void DolphinView::slotModelChanged(KItemModelBase* current, KItemModelBase* previous) @@ -1019,6 +1092,17 @@ void DolphinView::slotMouseButtonPressed(int itemIndex, Qt::MouseButtons buttons } } +void DolphinView::slotAboutToCreate(const KUrl::List& urls) +{ + if (!urls.isEmpty()) { + if (m_markFirstNewlySelectedItemAsCurrent) { + markUrlAsCurrent(urls.first()); + m_markFirstNewlySelectedItemAsCurrent = false; + } + m_selectedUrls << KDirModel::simplifiedUrlList(urls); + } +} + void DolphinView::slotSelectionChanged(const QSet& current, const QSet& previous) { const int currentCount = current.count(); @@ -1141,27 +1225,56 @@ QString DolphinView::viewPropertiesContext() const return m_viewPropertiesContext; } -void DolphinView::observeCreatedItem(const KUrl& url) +KUrl DolphinView::openItemAsFolderUrl(const KFileItem& item, const bool browseThroughArchives) { - m_createdItemUrl = url; - connect(m_model, SIGNAL(directoryLoadingCompleted()), - this, SLOT(selectAndScrollToCreatedItem())); + if (item.isNull()) { + return KUrl(); + } + + KUrl url = item.targetUrl(); + + if (item.isDir()) { + return url; + } + + if (item.isMimeTypeKnown()) { + const QString& mimetype = item.mimetype(); + + if (browseThroughArchives && item.isFile() && url.isLocalFile()) { + // Generic mechanism for redirecting to tar:// when clicking on a tar file, + // zip:// when clicking on a zip file, etc. + // The .protocol file specifies the mimetype that the kioslave handles. + // Note that we don't use mimetype inheritance since we don't want to + // open OpenDocument files as zip folders... + const QString& protocol = KProtocolManager::protocolForArchiveMimetype(mimetype); + if (!protocol.isEmpty()) { + url.setProtocol(protocol); + return url; + } + } + + if (mimetype == QLatin1String("application/x-desktop")) { + // Redirect to the URL in Type=Link desktop files, unless it is a http(s) URL. + KDesktopFile desktopFile(url.toLocalFile()); + if (desktopFile.hasLinkType()) { + const QString linkUrl = desktopFile.readUrl(); + if (!linkUrl.startsWith(QLatin1String("http"))) { + return linkUrl; + } + } + } + } + + return KUrl(); } -void DolphinView::selectAndScrollToCreatedItem() +void DolphinView::observeCreatedItem(const KUrl& url) { - KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager(); - const int index = m_model->index(m_createdItemUrl); - if (index != -1) { - selectionManager->setCurrentItem(index); - selectionManager->clearSelection(); - selectionManager->setSelected(index); - m_view->scrollToItem(index); + if (m_active) { + clearSelection(); + markUrlAsCurrent(url); + markUrlsAsSelected(QList() << url); } - - disconnect(m_model, SIGNAL(directoryLoadingCompleted()), - this, SLOT(selectAndScrollToCreatedItem())); - m_createdItemUrl = KUrl(); } void DolphinView::slotDirectoryRedirection(const KUrl& oldUrl, const KUrl& newUrl) @@ -1179,10 +1292,17 @@ void DolphinView::updateViewState() const int currentIndex = m_model->index(m_currentItemUrl); if (currentIndex != -1) { selectionManager->setCurrentItem(currentIndex); + + // scroll to current item and reset the state + if (m_scrollToCurrentItem) { + m_view->scrollToItem(currentIndex); + m_scrollToCurrentItem = false; + } + + m_currentItemUrl = KUrl(); } else { selectionManager->setCurrentItem(0); } - m_currentItemUrl = KUrl(); } if (!m_restoredContentsPosition.isNull()) { @@ -1195,20 +1315,27 @@ void DolphinView::updateViewState() } if (!m_selectedUrls.isEmpty()) { - clearSelection(); - KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager(); + + if (m_clearSelectionBeforeSelectingNewItems) { + selectionManager->clearSelection(); + m_clearSelectionBeforeSelectingNewItems = false; + } + QSet selectedItems = selectionManager->selectedItems(); - foreach (const KUrl& url, m_selectedUrls) { - const int index = m_model->index(url); + QList::iterator it = m_selectedUrls.begin(); + while (it != m_selectedUrls.end()) { + const int index = m_model->index(*it); if (index >= 0) { selectedItems.insert(index); + it = m_selectedUrls.erase(it); + } else { + ++it; } } selectionManager->setSelectedItems(selectedItems); - m_selectedUrls.clear(); } } @@ -1254,6 +1381,16 @@ void DolphinView::slotDeleteFileFinished(KJob* job) } } +void DolphinView::slotRenamingFailed(const KUrl& oldUrl, const KUrl& newUrl) +{ + const int index = m_model->index(newUrl); + if (index >= 0) { + QHash data; + data.insert("text", oldUrl.fileName()); + m_model->setData(index, data); + } +} + void DolphinView::slotDirectoryLoadingStarted() { // Disable the writestate temporary until it can be determined in a fast way @@ -1320,30 +1457,46 @@ void DolphinView::slotVisibleRolesChangedByHeader(const QList& curre emit visibleRolesChanged(m_visibleRoles, previousVisibleRoles); } -void DolphinView::slotRoleEditingCanceled(int index, const QByteArray& role, const QVariant& value) +void DolphinView::slotRoleEditingCanceled() { - Q_UNUSED(index); - Q_UNUSED(role); - Q_UNUSED(value); - setFocus(); + disconnect(m_view, SIGNAL(roleEditingFinished(int,QByteArray,QVariant)), + this, SLOT(slotRoleEditingFinished(int,QByteArray,QVariant))); } void DolphinView::slotRoleEditingFinished(int index, const QByteArray& role, const QVariant& value) { + disconnect(m_view, SIGNAL(roleEditingFinished(int,QByteArray,QVariant)), + this, SLOT(slotRoleEditingFinished(int,QByteArray,QVariant))); + + if (index < 0 || index >= m_model->count()) { + return; + } + if (role == "text") { const KFileItem oldItem = m_model->fileItem(index); const QString newName = value.toString(); if (!newName.isEmpty() && newName != oldItem.text() && newName != QLatin1String(".") && newName != QLatin1String("..")) { const KUrl oldUrl = oldItem.url(); - QHash data; - data.insert(role, value); - m_model->setData(index, data); + const KUrl newUrl(url().path(KUrl::AddTrailingSlash) + newName); + const bool newNameExistsAlready = (m_model->index(newUrl) >= 0); + if (!newNameExistsAlready) { + // Only change the data in the model if no item with the new name + // is in the model yet. If there is an item with the new name + // already, calling KonqOperations::rename() will open a dialog + // asking for a new name, and KFileItemModel will update the + // data when the dir lister signals that the file name has changed. + QHash data; + data.insert(role, value); + m_model->setData(index, data); + } - KonqOperations::rename(this, oldUrl, newName); + KonqOperations* op = KonqOperations::renameV2(this, oldUrl, newName); + if (op) { + connect(op, SIGNAL(renamingFailed(KUrl,KUrl)), SLOT(slotRenamingFailed(KUrl,KUrl))); + } } } - setFocus(); } void DolphinView::loadDirectory(const KUrl& url, bool reload) @@ -1367,9 +1520,13 @@ void DolphinView::loadDirectory(const KUrl& url, bool reload) void DolphinView::applyViewProperties() { - m_view->beginTransaction(); - const ViewProperties props(viewPropertiesUrl()); + applyViewProperties(props); +} + +void DolphinView::applyViewProperties(const ViewProperties& props) +{ + m_view->beginTransaction(); const Mode mode = props.viewMode(); if (m_mode != mode) { @@ -1473,8 +1630,12 @@ void DolphinView::applyModeToView() void DolphinView::pasteToUrl(const KUrl& url) { - markPastedUrlsAsSelected(QApplication::clipboard()->mimeData()); - KonqOperations::doPaste(this, url); + KonqOperations* op = KonqOperations::doPasteV2(this, url); + if (op) { + m_clearSelectionBeforeSelectingNewItems = true; + m_markFirstNewlySelectedItemAsCurrent = true; + connect(op, SIGNAL(aboutToCreate(KUrl::List)), this, SLOT(slotAboutToCreate(KUrl::List))); + } } KUrl::List DolphinView::simplifiedSelectedUrls() const @@ -1482,7 +1643,7 @@ KUrl::List DolphinView::simplifiedSelectedUrls() const KUrl::List urls; const KFileItemList items = selectedItems(); - foreach (const KFileItem &item, items) { + foreach (const KFileItem& item, items) { urls.append(item.url()); } @@ -1502,17 +1663,6 @@ QMimeData* DolphinView::selectionMimeData() const return m_model->createMimeData(selectedIndexes); } -void DolphinView::markPastedUrlsAsSelected(const QMimeData* mimeData) -{ - const KUrl::List sourceUrls = KUrl::List::fromMimeData(mimeData); - KUrl::List destUrls; - foreach (const KUrl& source, sourceUrls) { - KUrl destination(url().url() + "/" + source.fileName()); - destUrls << destination; - } - markUrlsAsSelected(destUrls); -} - void DolphinView::updateWritableState() { const bool wasFolderWritable = m_isFolderWritable;