X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/7e311509a4ac89ebe95f3d81928fe78a9f398aa9..8eb9b508ca87fb1d634d8b8ba62c054ed04466d2:/src/views/dolphinview.cpp diff --git a/src/views/dolphinview.cpp b/src/views/dolphinview.cpp index 2c2dbc231..a4e97bf6e 100644 --- a/src/views/dolphinview.cpp +++ b/src/views/dolphinview.cpp @@ -29,26 +29,27 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include -#include -#include +#include +#include #include "additionalinfoaccessor.h" +#include "dolphindirlister.h" #include "dolphinmodel.h" #include "dolphincolumnviewcontainer.h" #include "dolphinviewcontroller.h" @@ -67,9 +68,7 @@ #include "zoomlevelinfo.h" #include "dolphindetailsviewexpander.h" -DolphinView::DolphinView(QWidget* parent, - const KUrl& url, - DolphinSortFilterProxyModel* proxyModel) : +DolphinView::DolphinView(const KUrl& url, QWidget* parent) : QWidget(parent), m_active(true), m_showPreview(false), @@ -77,13 +76,14 @@ DolphinView::DolphinView(QWidget* parent, m_tabsForFiles(false), m_isContextMenuOpen(false), m_assureVisibleCurrentIndex(false), + m_expanderActive(false), + m_isFolderWritable(true), m_mode(DolphinView::IconsView), m_topLayout(0), m_dolphinViewController(0), m_viewModeController(0), - m_viewAccessor(proxyModel), + m_viewAccessor(), m_selectionChangedTimer(0), - m_rootUrl(), m_activeItemUrl(), m_restoredContentsPosition(), m_createdItemUrl(), @@ -125,15 +125,7 @@ DolphinView::DolphinView(QWidget* parent, connect(m_dolphinViewController, SIGNAL(viewportEntered()), this, SLOT(clearHoverInformation())); connect(m_dolphinViewController, SIGNAL(urlChangeRequested(KUrl)), - m_viewModeController, SLOT(setUrl(KUrl))); - - KDirLister* dirLister = m_viewAccessor.dirLister(); - connect(dirLister, SIGNAL(redirection(KUrl,KUrl)), - this, SLOT(slotRedirection(KUrl,KUrl))); - connect(dirLister, SIGNAL(completed()), - this, SLOT(slotDirListerCompleted())); - connect(dirLister, SIGNAL(refreshItems(const QList>&)), - this, SLOT(slotRefreshItems())); + this, SLOT(slotUrlChangeRequested(KUrl))); // When a new item has been created by the "Create New..." menu, the item should // get selected and it must be assured that the item will get visible. As the @@ -179,9 +171,7 @@ void DolphinView::setActive(bool active) m_active = active; QColor color = KColorScheme(QPalette::Active, KColorScheme::View).background().color(); - if (active) { - emitSelectionChangedSignal(); - } else { + if (!active) { color.setAlpha(150); } @@ -195,6 +185,8 @@ void DolphinView::setActive(bool active) if (active) { m_viewAccessor.itemView()->setFocus(); emit activated(); + emitSelectionChangedSignal(); + emit writeStateChanged(m_isFolderWritable); } m_viewModeController->indicateActivationChange(active); @@ -218,6 +210,7 @@ void DolphinView::setMode(Mode mode) // be restored after reloading the directory m_selectedItems = selectedItems(); + const bool hasFocus = m_viewAccessor.itemView()->hasFocus(); deleteView(); const KUrl viewPropsUrl = rootUrl(); @@ -225,6 +218,10 @@ void DolphinView::setMode(Mode mode) props.setViewMode(m_mode); createView(); + if (hasFocus) { + m_viewAccessor.itemView()->setFocus(); + } + // the file item delegate has been recreated, apply the current // additional information manually const KFileItemDelegate::InformationList infoList = props.additionalInfo(); @@ -279,6 +276,11 @@ bool DolphinView::supportsCategorizedSorting() const return m_viewAccessor.supportsCategorizedSorting(); } +KFileItem DolphinView::rootItem() const +{ + return m_viewAccessor.dirLister()->rootItem(); +} + KFileItemList DolphinView::items() const { return m_viewAccessor.dirLister()->items(); @@ -444,6 +446,11 @@ void DolphinView::setNameFilter(const QString& nameFilter) m_viewModeController->setNameFilter(nameFilter); } +QString DolphinView::nameFilter() const +{ + return m_viewModeController->nameFilter(); +} + void DolphinView::calculateItemCount(int& fileCount, int& folderCount, KIO::filesize_t& totalFileSize) const @@ -528,30 +535,25 @@ void DolphinView::setUrl(const KUrl& url) return; } - // The selection model might change in the case of the column view. Disconnect - // from the current selection model and reconnect later after the URL switch. const bool hadSelection = hasSelection(); - QAbstractItemView* view = m_viewAccessor.itemView(); - disconnect(view->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), - this, SLOT(slotSelectionChanged(QItemSelection, QItemSelection))); + + // The selection model and directory lister might change in the case of the column view: + disconnectViewAccessor(); m_newFileNames.clear(); m_viewModeController->setUrl(url); // emits urlChanged, which we forward m_viewAccessor.prepareUrlChange(url); applyViewProperties(); - loadDirectory(url); // When changing the URL there is no need to keep the version // data of the previous URL. m_viewAccessor.dirModel()->clearVersionData(); - emit startedPathLoading(url); + // Reconnect to the (probably) new selection model and directory lister + connectViewAccessor(); + loadDirectory(url); - // Reconnect to the (probably) new selection model - view = m_viewAccessor.itemView(); - connect(view->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), - this, SLOT(slotSelectionChanged(QItemSelection, QItemSelection))); if (hadSelection || hasSelection()) { emitSelectionChangedSignal(); } @@ -564,15 +566,23 @@ void DolphinView::selectAll() void DolphinView::invertSelection() { - QItemSelectionModel* selectionModel = m_viewAccessor.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); + // Implementation note: Using selectionModel->select(selection, QItemSelectionModel::Toggle) does not + // work, as QItemSelectionModel::hasSelection() provides invalid values in this case. This might be a Qt-issue - + // when changing the implementation with an updated Qt-version don't forget to run the Dolphin-unit-tests that + // verify this usecase. + const KFileItemList selItems = selectedItems(); + clearSelection(); + + QItemSelection invertedSelection; + foreach (const KFileItem& item, items()) { + if (!selItems.contains(item)) { + const QModelIndex index = m_viewAccessor.proxyModel()->mapFromSource(m_viewAccessor.dirModel()->indexForItem(item)); + invertedSelection.select(index, index); + } + } - const QItemSelection selection(topLeft, bottomRight); - selectionModel->select(selection, QItemSelectionModel::Toggle); + QItemSelectionModel* selectionModel = m_viewAccessor.itemView()->selectionModel(); + selectionModel->select(invertedSelection, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Current); } void DolphinView::clearSelection() @@ -904,13 +914,18 @@ bool DolphinView::itemsExpandable() const void DolphinView::restoreState(QDataStream& stream) { - // current item + // Restore the URL of the current item that had the keyboard focus stream >> m_activeItemUrl; - // view position + // Restore the root URL + KUrl rootUrl; + stream >> rootUrl; + m_viewAccessor.setRootUrl(rootUrl); + + // Restore the view position stream >> m_restoredContentsPosition; - // expanded folders (only relevant for the details view - will be ignored by the view in other view modes) + // Restore expanded folders (only relevant for the details view - will be ignored by the view in other view modes) QSet urlsToExpand; stream >> urlsToExpand; const DolphinDetailsViewExpander* expander = m_viewAccessor.setExpandedUrls(urlsToExpand); @@ -925,7 +940,7 @@ void DolphinView::restoreState(QDataStream& stream) void DolphinView::saveState(QDataStream& stream) { - // current item + // Save the URL of the current item that has the keyboard focus KFileItem currentItem; const QAbstractItemView* view = m_viewAccessor.itemView(); @@ -935,19 +950,22 @@ void DolphinView::saveState(QDataStream& stream) currentItem = m_viewAccessor.dirModel()->itemForIndex(dirModelIndex); } - KUrl currentUrl; + KUrl currentItemUrl; if (!currentItem.isNull()) { - currentUrl = currentItem.url(); + currentItemUrl = currentItem.url(); } - stream << currentUrl; + stream << currentItemUrl; - // view position + // Save the root URL + stream << m_viewAccessor.rootUrl(); + + // Save view position const int x = view->horizontalScrollBar()->value(); const int y = view->verticalScrollBar()->value(); stream << QPoint(x, y); - // expanded folders (only relevant for the details view - the set will be empty in other view modes) + // Save expanded folders (only relevant for the details view - the set will be empty in other view modes) stream << m_viewAccessor.expandedUrls(); } @@ -977,6 +995,34 @@ void DolphinView::selectAndScrollToCreatedItem() m_createdItemUrl = KUrl(); } +void DolphinView::slotRedirection(const KUrl& oldUrl, const KUrl& newUrl) +{ + if (oldUrl.equals(url(), KUrl::CompareWithoutTrailingSlash)) { + emit redirection(oldUrl, newUrl); + m_viewModeController->redirectToUrl(newUrl); // #186947 + } +} + +void DolphinView::restoreContentsPosition() +{ + if (!m_restoredContentsPosition.isNull()) { + const int x = m_restoredContentsPosition.x(); + const int y = m_restoredContentsPosition.y(); + m_restoredContentsPosition = QPoint(); + + QAbstractItemView* view = m_viewAccessor.itemView(); + Q_ASSERT(view != 0); + view->horizontalScrollBar()->setValue(x); + view->verticalScrollBar()->setValue(y); + } +} + +void DolphinView::slotUrlChangeRequested(const KUrl& url) +{ + m_viewModeController->setUrl(url); + updateWritableState(); +} + void DolphinView::showHoverInformation(const KFileItem& item) { emit requestItemInfo(item); @@ -996,6 +1042,18 @@ void DolphinView::slotDeleteFileFinished(KJob* job) } } +void DolphinView::slotDirListerStarted(const KUrl& url) +{ + // Disable the writestate temporary until it can be determined in a fast way + // in DolphinView::slotDirListerCompleted() + if (m_isFolderWritable) { + m_isFolderWritable = false; + emit writeStateChanged(m_isFolderWritable); + } + + emit startedPathLoading(url); +} + void DolphinView::slotDirListerCompleted() { if (!m_expanderActive) { @@ -1020,6 +1078,8 @@ void DolphinView::slotDirListerCompleted() m_newFileNames.clear(); } + + updateWritableState(); } void DolphinView::slotLoadingCompleted() @@ -1048,7 +1108,7 @@ void DolphinView::slotLoadingCompleted() foreach(const KFileItem& item, m_selectedItems) { url = item.url().upUrl(); if (baseUrl.equals(url, KUrl::CompareWithoutTrailingSlash)) { - QModelIndex index = m_viewAccessor.proxyModel()->mapFromSource(m_viewAccessor.dirModel()->indexForItem(item)); + const QModelIndex index = m_viewAccessor.proxyModel()->mapFromSource(m_viewAccessor.dirModel()->indexForItem(item)); newSelection.select(index, index); } } @@ -1106,6 +1166,7 @@ void DolphinView::applyViewProperties() if (m_viewAccessor.itemView() == 0) { createView(); } + Q_ASSERT(m_viewAccessor.itemView() != 0); Q_ASSERT(m_viewAccessor.itemDelegate() != 0); @@ -1177,8 +1238,7 @@ void DolphinView::createView() const int zoomLevel = ZoomLevelInfo::zoomLevelForIconSize(view->iconSize()); m_viewModeController->setZoomLevel(zoomLevel); - connect(view->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), - this, SLOT(slotSelectionChanged(QItemSelection, QItemSelection))); + connectViewAccessor(); setFocusProxy(m_viewAccessor.layoutTarget()); m_topLayout->insertWidget(1, m_viewAccessor.layoutTarget()); @@ -1191,18 +1251,17 @@ void DolphinView::deleteView() m_dolphinViewController->setItemView(0); if (view != 0) { - if (view->selectionModel() != 0) { - disconnect(view->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), - this, SLOT(slotSelectionChanged(QItemSelection, QItemSelection))); + disconnectViewAccessor(); + + if (hasFocus()) { + // It's important to set the keyboard focus to the parent + // before deleting the view: Otherwise when having a split + // view the other view will get the focus and will request + // an activation (see DolphinView::eventFilter()). + setFocusProxy(0); + setFocus(); } - // It's important to set the keyboard focus to the parent - // before deleting the view: Otherwise when having a split - // view the other view will get the focus and will request - // an activation (see DolphinView::eventFilter()). - setFocusProxy(0); - setFocus(); - m_viewModeController->disconnect(view); m_viewAccessor.deleteView(); @@ -1281,17 +1340,95 @@ QItemSelection DolphinView::childrenMatchingPattern(const QModelIndex& parent, c return matchingIndexes; } -DolphinView::ViewAccessor::ViewAccessor(DolphinSortFilterProxyModel* proxyModel) : +void DolphinView::connectViewAccessor() +{ + KDirLister* dirLister = m_viewAccessor.dirLister(); + connect(dirLister, SIGNAL(redirection(KUrl,KUrl)), this, SLOT(slotRedirection(KUrl,KUrl))); + connect(dirLister, SIGNAL(started(KUrl)), this, SLOT(slotDirListerStarted(KUrl))); + connect(dirLister, SIGNAL(completed()), this, SLOT(slotDirListerCompleted())); + connect(dirLister, SIGNAL(refreshItems(const QList>&)), + this, SLOT(slotRefreshItems())); + + connect(dirLister, SIGNAL(clear()), this, SIGNAL(itemCountChanged())); + connect(dirLister, SIGNAL(newItems(KFileItemList)), this, SIGNAL(itemCountChanged())); + connect(dirLister, SIGNAL(infoMessage(const QString&)), this, SIGNAL(infoMessage(const QString&))); + connect(dirLister, SIGNAL(errorMessage(const QString&)), this, SIGNAL(infoMessage(const QString&))); + connect(dirLister, SIGNAL(percent(int)), this, SIGNAL(pathLoadingProgress(int))); + connect(dirLister, SIGNAL(urlIsFileError(const KUrl&)), this, SIGNAL(urlIsFileError(const KUrl&))); + connect(dirLister, SIGNAL(itemsDeleted(const KFileItemList&)), this, SIGNAL(itemCountChanged())); + + QAbstractItemView* view = m_viewAccessor.itemView(); + connect(view->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), + this, SLOT(slotSelectionChanged(QItemSelection, QItemSelection))); +} + +void DolphinView::disconnectViewAccessor() +{ + KDirLister* dirLister = m_viewAccessor.dirLister(); + disconnect(dirLister, SIGNAL(redirection(KUrl,KUrl)), this, SLOT(slotRedirection(KUrl,KUrl))); + disconnect(dirLister, SIGNAL(started(KUrl)), this, SLOT(slotDirListerStarted(KUrl))); + disconnect(dirLister, SIGNAL(completed()), this, SLOT(slotDirListerCompleted())); + disconnect(dirLister, SIGNAL(refreshItems(const QList>&)), + this, SLOT(slotRefreshItems())); + + disconnect(dirLister, SIGNAL(clear()), this, SIGNAL(itemCountChanged())); + disconnect(dirLister, SIGNAL(newItems(KFileItemList)), this, SIGNAL(itemCountChanged())); + disconnect(dirLister, SIGNAL(infoMessage(const QString&)), this, SIGNAL(infoMessage(const QString&))); + disconnect(dirLister, SIGNAL(errorMessage(const QString&)), this, SIGNAL(errorMessage(const QString&))); + disconnect(dirLister, SIGNAL(percent(int)), this, SIGNAL(pathLoadingProgress(int))); + disconnect(dirLister, SIGNAL(urlIsFileError(const KUrl&)), this, SIGNAL(urlIsFileError(const KUrl&))); + disconnect(dirLister, SIGNAL(itemsDeleted(const KFileItemList&)), this, SIGNAL(itemCountChanged())); + + QAbstractItemView* view = m_viewAccessor.itemView(); + disconnect(view->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), + this, SLOT(slotSelectionChanged(QItemSelection, QItemSelection))); +} + +void DolphinView::updateWritableState() +{ + const bool wasFolderWritable = m_isFolderWritable; + m_isFolderWritable = true; + + const KFileItem item = m_viewAccessor.dirLister()->rootItem(); + if (!item.isNull()) { + KFileItemListProperties capabilities(KFileItemList() << item); + m_isFolderWritable = capabilities.supportsWriting(); + } + if (m_isFolderWritable != wasFolderWritable) { + emit writeStateChanged(m_isFolderWritable); + } +} + +DolphinView::ViewAccessor::ViewAccessor() : + m_rootUrl(), m_iconsView(0), m_detailsView(0), m_columnsContainer(0), - m_proxyModel(proxyModel), + m_dolphinModel(0), + m_proxyModel(0), m_dragSource(0) { + DolphinDirLister* dirLister = new DolphinDirLister(); + dirLister->setAutoUpdate(true); + dirLister->setDelayedMimeTypes(true); + + m_dolphinModel = new DolphinModel(); + m_dolphinModel->setDirLister(dirLister); // m_dolphinModel takes ownership of dirLister + m_dolphinModel->setDropsAllowed(DolphinModel::DropOnDirectory); + + m_proxyModel = new DolphinSortFilterProxyModel(); + m_proxyModel->setSourceModel(m_dolphinModel); + m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); } DolphinView::ViewAccessor::~ViewAccessor() { + delete m_proxyModel; + m_proxyModel = 0; + + delete m_dolphinModel; + m_dolphinModel = 0; + delete m_dragSource; m_dragSource = 0; } @@ -1322,6 +1459,12 @@ void DolphinView::ViewAccessor::createView(QWidget* parent, m_columnsContainer = new DolphinColumnViewContainer(parent, dolphinViewController, viewModeController); + if (!m_rootUrl.isEmpty() && m_rootUrl.isParentOf(viewModeController->url())) { + // The column-view must show several columns starting with m_rootUrl as + // first column and viewModeController->url() as last column. + m_columnsContainer->showColumn(m_rootUrl); + m_columnsContainer->showColumn(viewModeController->url()); + } break; default: @@ -1365,7 +1508,6 @@ void DolphinView::ViewAccessor::deleteView() } } - void DolphinView::ViewAccessor::prepareUrlChange(const KUrl& url) { if (m_columnsContainer != 0) { @@ -1403,9 +1545,14 @@ QWidget* DolphinView::ViewAccessor::layoutTarget() const return itemView(); } +void DolphinView::ViewAccessor::setRootUrl(const KUrl& rootUrl) +{ + m_rootUrl = rootUrl; +} + KUrl DolphinView::ViewAccessor::rootUrl() const { - return (m_columnsContainer != 0) ? m_columnsContainer->rootUrl() : KUrl(); + return (m_columnsContainer != 0) ? m_columnsContainer->rootUrl() : m_rootUrl; } bool DolphinView::ViewAccessor::supportsCategorizedSorting() const @@ -1418,7 +1565,6 @@ bool DolphinView::ViewAccessor::itemsExpandable() const return (m_detailsView != 0) && m_detailsView->itemsExpandable(); } - QSet DolphinView::ViewAccessor::expandedUrls() const { if (m_detailsView != 0) { @@ -1469,26 +1615,4 @@ KDirLister* DolphinView::ViewAccessor::dirLister() const return dirModel()->dirLister(); } -void DolphinView::slotRedirection(const KUrl& oldUrl, const KUrl& newUrl) -{ - if (oldUrl.equals(url(), KUrl::CompareWithoutTrailingSlash)) { - emit redirection(oldUrl, newUrl); - m_viewModeController->redirectToUrl(newUrl); // #186947 - } -} - -void DolphinView::restoreContentsPosition() -{ - if (!m_restoredContentsPosition.isNull()) { - const int x = m_restoredContentsPosition.x(); - const int y = m_restoredContentsPosition.y(); - m_restoredContentsPosition = QPoint(); - - QAbstractItemView* view = m_viewAccessor.itemView(); - Q_ASSERT(view != 0); - view->horizontalScrollBar()->setValue(x); - view->verticalScrollBar()->setValue(y); - } -} - #include "dolphinview.moc"