dolphinviewactionhandler.cpp
dolphinviewautoscroller.cpp
dolphinremoteencoding.cpp
+ dolphindetailsviewexpander.cpp
draganddrophelper.cpp
folderexpander.cpp
renamedialog.cpp
m_controller(controller),
m_extensionsFactory(0),
m_expandableFoldersAction(0),
+ m_expandedUrls(),
m_font(),
m_decorationSize(),
m_band()
connect(m_expandableFoldersAction, SIGNAL(toggled(bool)),
this, SLOT(setFoldersExpandable(bool)));
+ connect(this, SIGNAL(expanded(const QModelIndex&)), this, SLOT(slotExpanded(const QModelIndex&)));
+ connect(this, SIGNAL(collapsed(const QModelIndex&)), this, SLOT(slotCollapsed(const QModelIndex&)));
+
updateDecorationSize(view->showPreview());
m_extensionsFactory = new ViewExtensionsFactory(this, controller);
{
}
+QSet<KUrl> DolphinDetailsView::expandedUrls() const
+{
+ return m_expandedUrls;
+}
+
bool DolphinDetailsView::event(QEvent* event)
{
if (event->type() == QEvent::Polish) {
setItemsExpandable(expandable);
}
+void DolphinDetailsView::slotExpanded(const QModelIndex& index)
+{
+ KFileItem item = m_controller->itemForIndex(index);
+ if (!item.isNull()) {
+ m_expandedUrls.insert(item.url());
+ }
+}
+
+void DolphinDetailsView::slotCollapsed(const QModelIndex& index)
+{
+ KFileItem item = m_controller->itemForIndex(index);
+ if (!item.isNull()) {
+ m_expandedUrls.remove(item.url());
+ }
+}
+
+void DolphinDetailsView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
+{
+ removeExpandedIndexes(parent, start, end);
+ QTreeView::rowsAboutToBeRemoved(parent, start, end);
+}
+
+void DolphinDetailsView::removeExpandedIndexes(const QModelIndex& parent, int start, int end)
+{
+ if (m_expandedUrls.isEmpty()) {
+ return;
+ }
+
+ for (int row = start; row <= end; row++) {
+ const QModelIndex index = model()->index(row, 0, parent);
+ if (isExpanded(index)) {
+ slotCollapsed(index);
+ removeExpandedIndexes(index, 0, model()->rowCount(index) - 1);
+ }
+ }
+}
+
void DolphinDetailsView::updateDecorationSize(bool showPreview)
{
DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings();
DolphinSortFilterProxyModel* model);
virtual ~DolphinDetailsView();
+ /**
+ * Returns a set containing the URLs of all expanded items.
+ */
+ QSet<KUrl> expandedUrls() const;
+
protected:
virtual bool event(QEvent* event);
virtual QStyleOptionViewItem viewOptions() const;
*/
void setFoldersExpandable(bool expandable);
+ /**
+ * These slots update the list of expanded items.
+ */
+ void slotExpanded(const QModelIndex& index);
+ void slotCollapsed(const QModelIndex& index);
+
+protected slots:
+
+ virtual void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
+
private:
+ /**
+ * Removes the URLs corresponding to the children of \a index in the rows
+ * between \a start and \a end inclusive from the set of expanded URLs.
+ */
+ void removeExpandedIndexes(const QModelIndex& parent, int start, int end);
+
/**
* Updates the size of the decoration dependent on the
* icon size of the DetailsModeSettings. The controller
ViewExtensionsFactory* m_extensionsFactory;
QAction* m_expandableFoldersAction;
+ // A set containing the URLs of all currently expanded folders.
+ // We cannot use a QSet<QModelIndex> because a QModelIndex is not guaranteed to remain valid over time.
+ // Also a QSet<QPersistentModelIndex> does not work as expected because it is not guaranteed that
+ // subsequent expand/collapse events of the same file item will yield the same QPersistentModelIndex.
+ QSet<KUrl> m_expandedUrls;
+
QFont m_font;
QSize m_decorationSize;
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2009 by Frank Reininghaus (frank78ac@googlemail.com) *
+ * *
+ * 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 "dolphindetailsviewexpander.h"
+
+#include "dolphindetailsview.h"
+#include "dolphinmodel.h"
+#include "dolphinsortfilterproxymodel.h"
+
+#include <kdirlister.h>
+#include <kdirmodel.h>
+
+DolphinDetailsViewExpander::DolphinDetailsViewExpander(DolphinDetailsView* parent,
+ const QSet<KUrl>& urlsToExpand) :
+ QObject(parent),
+ m_detailsView(parent),
+ m_dirLister(0),
+ m_dolphinModel(0),
+ m_proxyModel(0)
+{
+ Q_ASSERT(parent != 0);
+
+ m_proxyModel = qobject_cast<const DolphinSortFilterProxyModel*>(parent->model());
+ Q_ASSERT(m_proxyModel != 0);
+
+ m_dolphinModel = qobject_cast<const DolphinModel*>(m_proxyModel->sourceModel());
+ Q_ASSERT(m_dolphinModel != 0);
+
+ m_dirLister = m_dolphinModel->dirLister();
+ Q_ASSERT(m_dirLister != 0);
+
+ if(!urlsToExpand.isEmpty()) {
+ // The URLs must be sorted. E.g. /home/user/ cannot be expanded before /home/
+ // because it is not known to the dir model before.
+ m_urlsToExpand = urlsToExpand.toList();
+ qSort(m_urlsToExpand);
+
+ // The dir lister must have completed the folder listing before a subfolder can be expanded.
+ connect(m_dirLister, SIGNAL(completed()), this, SLOT(slotDirListerCompleted()));
+ }
+ else {
+ // There is nothing to expand - destroy this object
+ deleteLater();
+ }
+}
+
+DolphinDetailsViewExpander::~DolphinDetailsViewExpander()
+{
+}
+
+void DolphinDetailsViewExpander::stop()
+{
+ disconnect(m_dirLister, SIGNAL(completed()), this, SLOT(slotDirListerCompleted()));
+ deleteLater();
+}
+
+void DolphinDetailsViewExpander::slotDirListerCompleted()
+{
+ QModelIndex dirIndex;
+
+ while(!m_urlsToExpand.isEmpty() && !dirIndex.isValid()) {
+ const KUrl url = m_urlsToExpand.takeFirst();
+ dirIndex = m_dolphinModel->indexForUrl(url);
+ }
+
+ if(dirIndex.isValid()) {
+ // A valid model index was found. Note that only one item is expanded in each call of this slot
+ // because expanding any item will trigger KDirLister::openUrl(...) via KDirModel::fetchMore(...),
+ // and we can only continue when the dir lister is done.
+ const QModelIndex proxyIndex = m_proxyModel->mapFromSource(dirIndex);
+ m_detailsView->expand(proxyIndex);
+ }
+
+ if(m_urlsToExpand.isEmpty()) {
+ emit completed();
+ stop();
+ }
+}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2009 by Frank Reininghaus (frank78ac@googlemail.com) *
+ * *
+ * 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 DOLPHINDETAILSVIEWEXPANDER_H
+#define DOLPHINDETAILSVIEWEXPANDER_H
+
+#include <QObject>
+#include <QSet>
+#include <QList>
+
+class DolphinDetailsView;
+class KUrl;
+class KDirLister;
+class DolphinModel;
+class DolphinSortFilterProxyModel;
+
+/**
+ * @brief Expands a given set of subfolders in collaboration with the dir lister and the dir model.
+ *
+ * Note that only one subfolder can be expanded at a time. Each expansion triggers KDirLister::openUrl(...),
+ * and further expansions can only be done the next time the dir lister emits its completed() signal.
+ */
+class DolphinDetailsViewExpander : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit DolphinDetailsViewExpander(DolphinDetailsView* parent,
+ const QSet<KUrl>& urlsToExpand);
+
+ virtual ~DolphinDetailsViewExpander();
+
+ /**
+ * Stops the expansion and deletes the object via deleteLater().
+ */
+ void stop();
+
+private slots:
+ /**
+ * This slot is invoked every time the dir lister has completed a listing.
+ * It expands the first URL from the list m_urlsToExpand that can be found in the dir model.
+ * If the list is empty, stop() is called.
+ */
+ void slotDirListerCompleted();
+
+signals:
+ /**
+ * Is emitted when the expander has finished expanding URLs in the details view.
+ */
+ void completed();
+
+private:
+ QList<KUrl> m_urlsToExpand;
+
+ DolphinDetailsView* m_detailsView;
+ const KDirLister* m_dirLister;
+ const DolphinModel* m_dolphinModel;
+ const DolphinSortFilterProxyModel* m_proxyModel;
+};
+
+#endif
////
+void DolphinPartBrowserExtension::restoreState(QDataStream &stream)
+{
+ KParts::BrowserExtension::restoreState(stream);
+ m_part->view()->restoreState(stream);
+}
+
+void DolphinPartBrowserExtension::saveState(QDataStream &stream)
+{
+ KParts::BrowserExtension::saveState(stream);
+ m_part->view()->saveState(stream);
+}
+
void DolphinPartBrowserExtension::cut()
{
m_part->view()->cutSelectedItems();
DolphinPartBrowserExtension( DolphinPart* part )
: KParts::BrowserExtension( part ), m_part(part) {}
+ virtual void restoreState(QDataStream &stream);
+ virtual void saveState(QDataStream &stream);
+
public Q_SLOTS:
void cut();
void copy();
#include "settings/dolphinsettings.h"
#include "viewproperties.h"
#include "zoomlevelinfo.h"
+#include "dolphindetailsviewexpander.h"
/**
* Helper function for sorting items with qSort() in
m_selectionChangedTimer(0),
m_rootUrl(),
m_activeItemUrl(),
+ m_restoredContentsPosition(),
m_createdItemUrl(),
m_selectedItems(),
m_newFileNames()
m_loadingDirectory = false;
}
+void DolphinView::setRestoredContentsPosition(const QPoint& pos)
+{
+ // TODO: This function is called by DolphinViewContainer.
+ // If it makes use of DolphinView::restoreState(...) to restore the
+ // view state in KDE 4.5, this function can be removed.
+ m_restoredContentsPosition = pos;
+}
+
QPoint DolphinView::contentsPosition() const
{
+ // TODO: If DolphinViewContainer uses DolphinView::saveState(...) to save the
+ // view state in KDE 4.5, this code can be moved to DolphinView::saveState.
QAbstractItemView* view = m_viewAccessor.itemView();
Q_ASSERT(view != 0);
const int x = view->horizontalScrollBar()->value();
void DolphinView::activateItem(const KUrl& url)
{
+ // TODO: If DolphinViewContainer uses DolphinView::restoreState(...) to restore the
+ // view state in KDE 4.5, this function can be removed.
m_activeItemUrl = url;
}
return m_viewAccessor.itemsExpandable();
}
+void DolphinView::restoreState(QDataStream &stream)
+{
+ // current item
+ stream >> m_activeItemUrl;
+
+ // view position
+ stream >> m_restoredContentsPosition;
+
+ // expanded folders (only relevant for the details view - will be ignored by the view in other view modes)
+ QSet<KUrl> urlsToExpand;
+ stream >> urlsToExpand;
+ const DolphinDetailsViewExpander* expander = m_viewAccessor.setExpandedUrls(urlsToExpand);
+
+ if (expander) {
+ m_expanderActive = true;
+ connect (expander, SIGNAL(completed()), this, SLOT(slotLoadingCompleted()));
+ }
+ else {
+ m_expanderActive = false;
+ }
+}
+
+void DolphinView::saveState(QDataStream &stream)
+{
+ // current item
+ KFileItem currentItem;
+ const QAbstractItemView* view = m_viewAccessor.itemView();
+
+ if(view) {
+ const QModelIndex proxyIndex = view->currentIndex();
+ const QModelIndex dirModelIndex = m_viewAccessor.proxyModel()->mapToSource(proxyIndex);
+ currentItem = m_viewAccessor.dirModel()->itemForIndex(dirModelIndex);
+ }
+
+ KUrl currentUrl;
+ if (!currentItem.isNull())
+ currentUrl = currentItem.url();
+
+ stream << currentUrl;
+
+ // view position
+ stream << contentsPosition();
+
+ // expanded folders (only relevant for the details view - the set will be empty in other view modes)
+ stream << m_viewAccessor.expandedUrls();
+}
+
void DolphinView::observeCreatedItem(const KUrl& url)
{
m_createdItemUrl = url;
void DolphinView::emitContentsMoved()
{
+ // TODO: If DolphinViewContainer uses DolphinView::saveState(...) to save the
+ // view state in KDE 4.5, the contentsMoved signal might not be needed anymore,
+ // depending on how the implementation is done.
+ // In that case, the code in contentsPosition() can be moved to saveState().
+
// only emit the contents moved signal if no directory loading is ongoing
// (this would reset the contents position always to (0, 0))
if (!m_loadingDirectory) {
void DolphinView::slotDirListerCompleted()
{
- if (!m_activeItemUrl.isEmpty()) {
- // assure that the current item remains visible
- const QModelIndex dirIndex = m_viewAccessor.dirModel()->indexForUrl(m_activeItemUrl);
- if (dirIndex.isValid()) {
- const QModelIndex proxyIndex = m_viewAccessor.proxyModel()->mapFromSource(dirIndex);
- QAbstractItemView* view = m_viewAccessor.itemView();
- const bool clearSelection = !hasSelection();
- view->setCurrentIndex(proxyIndex);
- if (clearSelection) {
- view->clearSelection();
- }
- m_activeItemUrl.clear();
- }
+ if (!m_expanderActive) {
+ slotLoadingCompleted();
}
if (!m_newFileNames.isEmpty()) {
}
}
+void DolphinView::slotLoadingCompleted()
+{
+ m_expanderActive = false;
+ m_loadingDirectory = false;
+
+ if (!m_activeItemUrl.isEmpty()) {
+ // assure that the current item remains visible
+ const QModelIndex dirIndex = m_viewAccessor.dirModel()->indexForUrl(m_activeItemUrl);
+ if (dirIndex.isValid()) {
+ const QModelIndex proxyIndex = m_viewAccessor.proxyModel()->mapFromSource(dirIndex);
+ QAbstractItemView* view = m_viewAccessor.itemView();
+ const bool clearSelection = !hasSelection();
+ view->setCurrentIndex(proxyIndex);
+ if (clearSelection) {
+ view->clearSelection();
+ }
+ m_activeItemUrl.clear();
+ }
+ }
+
+ // Restore the contents position. This has to be done using a Qt::QueuedConnection
+ // because the view might not be in its final state yet.
+ QMetaObject::invokeMethod(this, "restoreContentsPosition", Qt::QueuedConnection);
+}
+
void DolphinView::slotRefreshItems()
{
if (m_assureVisibleCurrentIndex) {
}
m_loadingDirectory = true;
+ m_expanderActive = false;
if (reload) {
m_selectedItems = selectedItems();
if (m_columnsContainer != 0) {
m_columnsContainer->showColumn(url);
}
+
+ if(!m_detailsViewExpander.isNull()) {
+ // Stop expanding items in the current folder
+ m_detailsViewExpander->stop();
+ }
}
QAbstractItemView* DolphinView::ViewAccessor::itemView() const
return (m_detailsView != 0) && m_detailsView->itemsExpandable();
}
+
+QSet<KUrl> DolphinView::ViewAccessor::expandedUrls() const
+{
+ if(m_detailsView != 0) {
+ return m_detailsView->expandedUrls();
+ }
+ else {
+ return QSet<KUrl>();
+ }
+}
+
+const DolphinDetailsViewExpander* DolphinView::ViewAccessor::setExpandedUrls(const QSet<KUrl>& urlsToExpand)
+{
+ if((m_detailsView != 0) && m_detailsView->itemsExpandable() && !urlsToExpand.isEmpty()) {
+ m_detailsViewExpander = new DolphinDetailsViewExpander(m_detailsView, urlsToExpand);
+ return m_detailsViewExpander;
+ }
+ else {
+ return 0;
+ }
+}
+
bool DolphinView::ViewAccessor::reloadOnAdditionalInfoChange() const
{
// the details view requires no reloading of the directory, as it maps
m_controller->redirectToUrl(newUrl); // #186947
}
+void DolphinView::restoreContentsPosition()
+{
+ if (!m_restoredContentsPosition.isNull()) {
+ setContentsPosition(m_restoredContentsPosition.x(), m_restoredContentsPosition.y());
+ m_restoredContentsPosition = QPoint();
+ }
+}
+
#include "dolphinview.moc"
class KDirLister;
class KUrl;
class ViewProperties;
+class DolphinDetailsViewExpander;
/**
* @short Represents a view for the directory content.
*/
void setContentsPosition(int x, int y);
+ /**
+ * Sets the upper left position of the view content
+ * to (x,y) after the directory loading is finished.
+ * This is useful when going back or forward in history.
+ */
+ void setRestoredContentsPosition(const QPoint& pos);
+
/** Returns the upper left position of the view content. */
QPoint contentsPosition() const;
*/
bool itemsExpandable() const;
+ /**
+ * Restores the view state (current item, contents position, details view expansion state)
+ */
+ void restoreState(QDataStream &stream);
+
+ /**
+ * Saves the view state (current item, contents position, details view expansion state)
+ */
+ void saveState(QDataStream &stream);
+
+
public slots:
/**
* Changes the directory to \a url. If the current directory is equal to
*/
void slotDirListerCompleted();
+ /**
+ * Invoked when the loading of the directory is finished.
+ * Restores the active item and the scroll position if possible.
+ */
+ void slotLoadingCompleted();
+
/**
* Is invoked when the KDirLister indicates refreshed items.
*/
*/
void slotRedirection(const KUrl& oldUrl, const KUrl& newUrl);
+ /**
+ * Restores the contents position, if history information about the old position is available.
+ */
+ void restoreContentsPosition();
+
private:
void loadDirectory(const KUrl& url, bool reload = false);
bool supportsCategorizedSorting() const;
bool itemsExpandable() const;
+ QSet<KUrl> expandedUrls() const;
+ const DolphinDetailsViewExpander* setExpandedUrls(const QSet<KUrl>& urlsToExpand);
/**
* Returns true, if a reloading of the items is required
DolphinColumnViewContainer* m_columnsContainer;
DolphinSortFilterProxyModel* m_proxyModel;
QAbstractItemView* m_dragSource;
+ QPointer<DolphinDetailsViewExpander> m_detailsViewExpander;
};
bool m_active : 1;
bool m_isContextMenuOpen : 1; // TODO: workaround for Qt-issue 207192
bool m_ignoreViewProperties : 1;
bool m_assureVisibleCurrentIndex : 1;
+ bool m_expanderActive : 1;
Mode m_mode;
KUrl m_rootUrl;
KUrl m_activeItemUrl;
+ QPoint m_restoredContentsPosition;
KUrl m_createdItemUrl; // URL for a new item that got created by the "Create New..." menu
KFileItemList m_selectedItems; // this is used for making the View to remember selections after F5
} else {
updateStatusBar();
}
- QMetaObject::invokeMethod(this, "restoreContentsPos", Qt::QueuedConnection);
// Enable the 'File'->'Create New...' menu only if the directory
// supports writing.
void DolphinViewContainer::saveContentsPos(int x, int y)
{
+ // TODO: If DolphinViewContainer uses DolphinView::saveState(...) to save the
+ // view state in KDE 4.5, this funciton can be removed.
m_urlNavigator->savePosition(x, y);
}
-void DolphinViewContainer::restoreContentsPos()
-{
- if (!url().isEmpty()) {
- const QPoint pos = m_urlNavigator->savedPosition();
- m_view->setContentsPosition(pos.x(), pos.y());
- }
-}
-
void DolphinViewContainer::activate()
{
setActive(true);
// the previous directory as active item:
const KUrl url = m_urlNavigator->historyUrl(index - 1);
m_view->activateItem(url);
+ QPoint pos = m_urlNavigator->savedPosition();
+ m_view->setRestoredContentsPosition(pos);
}
}
*/
void saveContentsPos(int x, int y);
- /**
- * Restores the contents position of the view, if the view
- * is part of the history.
- */
- void restoreContentsPos();
-
/**
* Marks the view container as active
* (see DolphinViewContainer::setActive()).