From 652d08c9242ed51d86dba3b2afda9d3b2e9a9cd7 Mon Sep 17 00:00:00 2001 From: Peter Penz Date: Sat, 24 Jul 2010 21:45:49 +0000 Subject: Sourcecode hierarchy cleanup: Create folder "views" and move view related sources to it svn path=/trunk/KDE/kdebase/apps/; revision=1154146 --- src/CMakeLists.txt | 36 +- src/additionalinfoaccessor.h | 2 +- src/dolphincategorydrawer.cpp | 378 ----- src/dolphincategorydrawer.h | 85 -- src/dolphincolumnview.cpp | 466 ------ src/dolphincolumnview.h | 170 --- src/dolphincolumnviewcontainer.cpp | 416 ------ src/dolphincolumnviewcontainer.h | 147 -- src/dolphincontextmenu.cpp | 4 +- src/dolphindetailsview.cpp | 1113 -------------- src/dolphindetailsview.h | 287 ---- src/dolphindetailsviewexpander.cpp | 87 -- src/dolphindetailsviewexpander.h | 77 - src/dolphinfileitemdelegate.cpp | 180 --- src/dolphinfileitemdelegate.h | 90 -- src/dolphiniconsview.cpp | 532 ------- src/dolphiniconsview.h | 122 -- src/dolphinmainwindow.h | 5 +- src/dolphinnewmenu.cpp | 2 +- src/dolphinpart.cpp | 2 +- src/dolphinsortfilterproxymodel.h | 2 +- src/dolphinview.cpp | 1569 -------------------- src/dolphinview.h | 818 ---------- src/dolphinviewactionhandler.cpp | 4 +- src/dolphinviewactionhandler.h | 2 +- src/dolphinviewautoscroller.cpp | 223 --- src/dolphinviewautoscroller.h | 79 - src/dolphinviewcontainer.cpp | 12 +- src/dolphinviewcontainer.h | 4 +- src/dolphinviewcontroller.cpp | 249 ---- src/dolphinviewcontroller.h | 314 ---- src/draganddrophelper.cpp | 5 +- src/filterbar.cpp | 90 -- src/filterbar.h | 65 - src/filterbar/filterbar.cpp | 90 ++ src/filterbar/filterbar.h | 65 + src/panels/folders/folderspanel.cpp | 3 +- src/panels/folders/paneltreeview.cpp | 3 +- src/selectionmanager.cpp | 186 --- src/selectionmanager.h | 74 - src/selectiontoggle.cpp | 233 --- src/selectiontoggle.h | 91 -- .../dolphin_directoryviewpropertysettings.kcfgc | 2 +- src/settings/startup/startupsettingspage.cpp | 3 +- src/settings/viewmodes/columnviewsettingspage.cpp | 3 +- src/settings/viewmodes/detailsviewsettingspage.cpp | 5 +- src/settings/viewmodes/iconsizegroupbox.cpp | 2 +- src/settings/viewmodes/iconsviewsettingspage.cpp | 3 +- src/settings/viewmodes/iconsviewsettingspage.h | 2 +- src/settings/viewpropertiesdialog.cpp | 2 +- src/statusbar/dolphinstatusbar.cpp | 4 +- src/viewextensionsfactory.cpp | 244 --- src/viewextensionsfactory.h | 105 -- src/viewmodecontroller.cpp | 88 -- src/viewmodecontroller.h | 124 -- src/viewproperties.h | 2 +- src/views/dolphincategorydrawer.cpp | 378 +++++ src/views/dolphincategorydrawer.h | 85 ++ src/views/dolphincolumnview.cpp | 466 ++++++ src/views/dolphincolumnview.h | 170 +++ src/views/dolphincolumnviewcontainer.cpp | 416 ++++++ src/views/dolphincolumnviewcontainer.h | 147 ++ src/views/dolphindetailsview.cpp | 1113 ++++++++++++++ src/views/dolphindetailsview.h | 287 ++++ src/views/dolphindetailsviewexpander.cpp | 87 ++ src/views/dolphindetailsviewexpander.h | 77 + src/views/dolphinfileitemdelegate.cpp | 180 +++ src/views/dolphinfileitemdelegate.h | 90 ++ src/views/dolphiniconsview.cpp | 532 +++++++ src/views/dolphiniconsview.h | 122 ++ src/views/dolphinview.cpp | 1569 ++++++++++++++++++++ src/views/dolphinview.h | 818 ++++++++++ src/views/dolphinviewautoscroller.cpp | 223 +++ src/views/dolphinviewautoscroller.h | 79 + src/views/dolphinviewcontroller.cpp | 249 ++++ src/views/dolphinviewcontroller.h | 314 ++++ src/views/selectionmanager.cpp | 186 +++ src/views/selectionmanager.h | 74 + src/views/selectiontoggle.cpp | 233 +++ src/views/selectiontoggle.h | 91 ++ src/views/viewextensionsfactory.cpp | 244 +++ src/views/viewextensionsfactory.h | 105 ++ src/views/viewmodecontroller.cpp | 88 ++ src/views/viewmodecontroller.h | 124 ++ src/views/zoomlevelinfo.cpp | 60 + src/views/zoomlevelinfo.h | 51 + src/zoomlevelinfo.cpp | 60 - src/zoomlevelinfo.h | 51 - 88 files changed, 8874 insertions(+), 8866 deletions(-) delete mode 100644 src/dolphincategorydrawer.cpp delete mode 100644 src/dolphincategorydrawer.h delete mode 100644 src/dolphincolumnview.cpp delete mode 100644 src/dolphincolumnview.h delete mode 100644 src/dolphincolumnviewcontainer.cpp delete mode 100644 src/dolphincolumnviewcontainer.h delete mode 100644 src/dolphindetailsview.cpp delete mode 100644 src/dolphindetailsview.h delete mode 100644 src/dolphindetailsviewexpander.cpp delete mode 100644 src/dolphindetailsviewexpander.h delete mode 100644 src/dolphinfileitemdelegate.cpp delete mode 100644 src/dolphinfileitemdelegate.h delete mode 100644 src/dolphiniconsview.cpp delete mode 100644 src/dolphiniconsview.h delete mode 100644 src/dolphinview.cpp delete mode 100644 src/dolphinview.h delete mode 100644 src/dolphinviewautoscroller.cpp delete mode 100644 src/dolphinviewautoscroller.h delete mode 100644 src/dolphinviewcontroller.cpp delete mode 100644 src/dolphinviewcontroller.h delete mode 100644 src/filterbar.cpp delete mode 100644 src/filterbar.h create mode 100644 src/filterbar/filterbar.cpp create mode 100644 src/filterbar/filterbar.h delete mode 100644 src/selectionmanager.cpp delete mode 100644 src/selectionmanager.h delete mode 100644 src/selectiontoggle.cpp delete mode 100644 src/selectiontoggle.h delete mode 100644 src/viewextensionsfactory.cpp delete mode 100644 src/viewextensionsfactory.h delete mode 100644 src/viewmodecontroller.cpp delete mode 100644 src/viewmodecontroller.h create mode 100644 src/views/dolphincategorydrawer.cpp create mode 100644 src/views/dolphincategorydrawer.h create mode 100644 src/views/dolphincolumnview.cpp create mode 100644 src/views/dolphincolumnview.h create mode 100644 src/views/dolphincolumnviewcontainer.cpp create mode 100644 src/views/dolphincolumnviewcontainer.h create mode 100644 src/views/dolphindetailsview.cpp create mode 100644 src/views/dolphindetailsview.h create mode 100644 src/views/dolphindetailsviewexpander.cpp create mode 100644 src/views/dolphindetailsviewexpander.h create mode 100644 src/views/dolphinfileitemdelegate.cpp create mode 100644 src/views/dolphinfileitemdelegate.h create mode 100644 src/views/dolphiniconsview.cpp create mode 100644 src/views/dolphiniconsview.h create mode 100644 src/views/dolphinview.cpp create mode 100644 src/views/dolphinview.h create mode 100644 src/views/dolphinviewautoscroller.cpp create mode 100644 src/views/dolphinviewautoscroller.h create mode 100644 src/views/dolphinviewcontroller.cpp create mode 100644 src/views/dolphinviewcontroller.h create mode 100644 src/views/selectionmanager.cpp create mode 100644 src/views/selectionmanager.h create mode 100644 src/views/selectiontoggle.cpp create mode 100644 src/views/selectiontoggle.h create mode 100644 src/views/viewextensionsfactory.cpp create mode 100644 src/views/viewextensionsfactory.h create mode 100644 src/views/viewmodecontroller.cpp create mode 100644 src/views/viewmodecontroller.h create mode 100644 src/views/zoomlevelinfo.cpp create mode 100644 src/views/zoomlevelinfo.h delete mode 100644 src/zoomlevelinfo.cpp delete mode 100644 src/zoomlevelinfo.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bba1bf957..4dc2476c7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -17,27 +17,15 @@ endif (Nepomuk_FOUND) set(dolphinprivate_LIB_SRCS additionalinfoaccessor.cpp - dolphindetailsview.cpp - dolphindetailsviewexpander.cpp - dolphiniconsview.cpp - dolphincolumnview.cpp - dolphincolumnviewcontainer.cpp dolphindirlister.cpp - dolphinfileitemdelegate.cpp dolphinmodel.cpp dolphinnewmenuobserver.cpp dolphinsortfilterproxymodel.cpp - dolphincategorydrawer.cpp - dolphinview.cpp dolphinviewactionhandler.cpp - dolphinviewautoscroller.cpp - dolphinviewcontroller.cpp dolphinremoteencoding.cpp draganddrophelper.cpp folderexpander.cpp renamedialog.cpp - selectiontoggle.cpp - selectionmanager.cpp settings/additionalinfodialog.cpp settings/applyviewpropsjob.cpp settings/dolphinsettings.cpp @@ -49,10 +37,22 @@ set(dolphinprivate_LIB_SRCS versioncontrol/pendingthreadsmaintainer.cpp versioncontrol/updateitemstatesthread.cpp versioncontrol/versioncontrolobserver.cpp - viewextensionsfactory.cpp - viewmodecontroller.cpp viewproperties.cpp - zoomlevelinfo.cpp + views/dolphincategorydrawer.cpp + views/dolphinview.cpp + views/dolphindetailsview.cpp + views/dolphindetailsviewexpander.cpp + views/dolphinfileitemdelegate.cpp + views/dolphiniconsview.cpp + views/dolphincolumnview.cpp + views/dolphincolumnviewcontainer.cpp + views/dolphinviewautoscroller.cpp + views/dolphinviewcontroller.cpp + views/selectiontoggle.cpp + views/selectionmanager.cpp + views/viewextensionsfactory.cpp + views/viewmodecontroller.cpp + views/zoomlevelinfo.cpp ) kde4_add_kcfg_files(dolphinprivate_LIB_SRCS @@ -101,7 +101,7 @@ set(dolphin_SRCS dolphinviewcontainer.cpp dolphindirlister.cpp dolphincontextmenu.cpp - filterbar.cpp + filterbar/filterbar.cpp main.cpp pixmapviewer.cpp panels/information/informationpanel.cpp @@ -135,7 +135,7 @@ set(dolphin_SRCS statusbar/dolphinstatusbar.cpp statusbar/statusbarspaceinfo.cpp statusbar/statusbarmessagelabel.cpp - zoomlevelinfo.cpp + views/zoomlevelinfo.cpp ) kde4_add_kcfg_files(dolphin_SRCS @@ -205,7 +205,7 @@ set(kcm_dolphinviewmodes_PART_SRCS settings/viewmodes/iconsizegroupbox.cpp settings/viewmodes/iconsviewsettingspage.cpp settings/viewmodes/viewsettingspagebase.cpp - zoomlevelinfo.cpp) + views/zoomlevelinfo.cpp) set(kcm_dolphinnavigation_PART_SRCS settings/kcm/kcmdolphinnavigation.cpp diff --git a/src/additionalinfoaccessor.h b/src/additionalinfoaccessor.h index 51319a11c..0a3d51459 100644 --- a/src/additionalinfoaccessor.h +++ b/src/additionalinfoaccessor.h @@ -20,9 +20,9 @@ #ifndef ADDITIONALINFOACCESSOR_H #define ADDITIONALINFOACCESSOR_H -#include #include #include +#include #include #include diff --git a/src/dolphincategorydrawer.cpp b/src/dolphincategorydrawer.cpp deleted file mode 100644 index 59743b7f5..000000000 --- a/src/dolphincategorydrawer.cpp +++ /dev/null @@ -1,378 +0,0 @@ -/* - * This file is part of the KDE project - * Copyright (C) 2007 Rafael Fernández López - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include "dolphincategorydrawer.h" - -#include - -#include -#include -#include -#include -#include - -#ifdef HAVE_NEPOMUK -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include "dolphinview.h" -#include "dolphinmodel.h" - -#define HORIZONTAL_HINT 3 - -DolphinCategoryDrawer::DolphinCategoryDrawer(KCategorizedView *view) - : KCategoryDrawerV3(view) - , hotSpotPressed(NoneHotSpot) - , selectAll(KIconLoader::global()->loadIcon("list-add", KIconLoader::Desktop, 16)) - , selectAllHovered(KIconLoader::global()->iconEffect()->apply(selectAll, KIconLoader::Desktop, KIconLoader::ActiveState)) - , selectAllDisabled(KIconLoader::global()->iconEffect()->apply(selectAll, KIconLoader::Desktop, KIconLoader::DisabledState)) - , unselectAll(KIconLoader::global()->loadIcon("list-remove", KIconLoader::Desktop, 16)) - , unselectAllHovered(KIconLoader::global()->iconEffect()->apply(unselectAll, KIconLoader::Desktop, KIconLoader::ActiveState)) - , unselectAllDisabled(KIconLoader::global()->iconEffect()->apply(unselectAll, KIconLoader::Desktop, KIconLoader::DisabledState)) -{ -} - -DolphinCategoryDrawer::~DolphinCategoryDrawer() -{ -} - -bool DolphinCategoryDrawer::allCategorySelected(const QString &category) const -{ - const QModelIndexList list = view()->block(category); - foreach (const QModelIndex &index, list) { - if (!view()->selectionModel()->isSelected(index)) { - return false; - } - } - return true; -} - -bool DolphinCategoryDrawer::someCategorySelected(const QString &category) const -{ - const QModelIndexList list = view()->block(category); - foreach (const QModelIndex &index, list) { - if (view()->selectionModel()->isSelected(index)) { - return true; - } - } - return false; -} - -void DolphinCategoryDrawer::drawCategory(const QModelIndex &index, int sortRole, - const QStyleOption &option, QPainter *painter) const -{ - Q_UNUSED(sortRole); - painter->setRenderHint(QPainter::Antialiasing); - - if (!index.isValid()) { - return; - } - - const QString category = index.model()->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); - const QRect optRect = option.rect; - QFont font(QApplication::font()); - font.setBold(true); - const QFontMetrics fontMetrics = QFontMetrics(font); - - QColor outlineColor = option.palette.text().color(); - outlineColor.setAlphaF(0.35); - - //BEGIN: top left corner - { - painter->save(); - painter->setPen(outlineColor); - const QPointF topLeft(optRect.topLeft()); - QRectF arc(topLeft, QSizeF(4, 4)); - arc.translate(0.5, 0.5); - painter->drawArc(arc, 1440, 1440); - painter->restore(); - } - //END: top left corner - - //BEGIN: left vertical line - { - QPoint start(optRect.topLeft()); - start.ry() += 3; - QPoint verticalGradBottom(optRect.topLeft()); - verticalGradBottom.ry() += fontMetrics.height() + 5; - QLinearGradient gradient(start, verticalGradBottom); - gradient.setColorAt(0, outlineColor); - gradient.setColorAt(1, Qt::transparent); - painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient); - } - //END: left vertical line - - //BEGIN: horizontal line - { - QPoint start(optRect.topLeft()); - start.rx() += 3; - QPoint horizontalGradTop(optRect.topLeft()); - horizontalGradTop.rx() += optRect.width() - 6; - painter->fillRect(QRect(start, QSize(optRect.width() - 6, 1)), outlineColor); - } - //END: horizontal line - - //BEGIN: top right corner - { - painter->save(); - painter->setPen(outlineColor); - QPointF topRight(optRect.topRight()); - topRight.rx() -= 4; - QRectF arc(topRight, QSizeF(4, 4)); - arc.translate(0.5, 0.5); - painter->drawArc(arc, 0, 1440); - painter->restore(); - } - //END: top right corner - - //BEGIN: right vertical line - { - QPoint start(optRect.topRight()); - start.ry() += 3; - QPoint verticalGradBottom(optRect.topRight()); - verticalGradBottom.ry() += fontMetrics.height() + 5; - QLinearGradient gradient(start, verticalGradBottom); - gradient.setColorAt(0, outlineColor); - gradient.setColorAt(1, Qt::transparent); - painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient); - } - //END: right vertical line - - const int iconSize = KIconLoader::global()->currentSize(KIconLoader::Small); - - //BEGIN: select/unselect all - { - if (this->category == category) { - QRect iconAllRect(option.rect); - iconAllRect.setTop(iconAllRect.top() + 4); - iconAllRect.setLeft(iconAllRect.right() - 16 - 7); - iconAllRect.setSize(QSize(iconSize, iconSize)); - if (!allCategorySelected(category)) { - if (iconAllRect.contains(pos)) { - painter->drawPixmap(iconAllRect, selectAllHovered); - } else { - painter->drawPixmap(iconAllRect, selectAll); - } - } else { - painter->drawPixmap(iconAllRect, selectAllDisabled); - } - QRect iconNoneRect(option.rect); - iconNoneRect.setTop(iconNoneRect.top() + 4); - iconNoneRect.setLeft(iconNoneRect.right() - 16 * 2 - 7 * 2); - iconNoneRect.setSize(QSize(iconSize, iconSize)); - if (someCategorySelected(category)) { - if (iconNoneRect.contains(pos)) { - painter->drawPixmap(iconNoneRect, unselectAllHovered); - } else { - painter->drawPixmap(iconNoneRect, unselectAll); - } - } else { - painter->drawPixmap(iconNoneRect, unselectAllDisabled); - } - } - } - //END: select/unselect all - - //BEGIN: category information - { - bool paintIcon; - QPixmap icon; - switch (index.column()) { - case KDirModel::Owner: { - paintIcon = true; - KUser user(category); - const QString faceIconPath = user.faceIconPath(); - if (faceIconPath.isEmpty()) { - icon = KIconLoader::global()->loadIcon("user-identity", KIconLoader::NoGroup, iconSize); - } else { - icon = QPixmap::fromImage(QImage(faceIconPath).scaledToHeight(iconSize, Qt::SmoothTransformation)); - } - } - break; - case KDirModel::Type: { - paintIcon = true; - const KCategorizedSortFilterProxyModel *proxyModel = static_cast(index.model()); - const DolphinModel *model = static_cast(proxyModel->sourceModel()); - KFileItem item = model->itemForIndex(proxyModel->mapToSource(index)); - // This is the only way of getting the icon right. Others will fail on corner - // cases like the item representing this group has been set a different icon, - // so the group icon drawn is that one particularly. This way assures the drawn - // icon is the one of the mimetype of the group itself. (ereslibre) - icon = KIconLoader::global()->loadMimeTypeIcon(item.mimeTypePtr()->iconName(), KIconLoader::NoGroup, iconSize); - } - break; - default: - paintIcon = false; - } - - if (paintIcon) { - QRect iconRect(option.rect); - iconRect.setTop(iconRect.top() + 4); - iconRect.setLeft(iconRect.left() + 7); - iconRect.setSize(QSize(iconSize, iconSize)); - - painter->drawPixmap(iconRect, icon); - } - - //BEGIN: text - { - QRect textRect(option.rect); - textRect.setTop(textRect.top() + 7); - textRect.setLeft(textRect.left() + 7 + (paintIcon ? (iconSize + 6) : 0)); - textRect.setHeight(qMax(fontMetrics.height(), iconSize)); - textRect.setRight(textRect.right() - 7); - textRect.setBottom(textRect.bottom() - 5); // only one pixel separation here (no gradient) - - painter->save(); - painter->setFont(font); - QColor penColor(option.palette.text().color()); - penColor.setAlphaF(0.6); - painter->setPen(penColor); - painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, category); - painter->restore(); - } - //END: text - } - //BEGIN: category information -} - -int DolphinCategoryDrawer::categoryHeight(const QModelIndex &index, const QStyleOption &) const -{ - int iconSize = KIconLoader::global()->currentSize(KIconLoader::Small); - QFont font(QApplication::font()); - font.setBold(true); - const QFontMetrics fontMetrics = QFontMetrics(font); - int heightWithoutIcon = fontMetrics.height() + (iconSize / 4) * 2 + 1; /* 1 pixel-width gradient */ - bool paintIcon; - - switch (index.column()) { - case KDirModel::Owner: - case KDirModel::Type: - paintIcon = true; - break; - default: - paintIcon = false; - } - - if (paintIcon) { - return qMax(heightWithoutIcon + 5, iconSize + 1 /* 1 pixel-width gradient */ - + 5 /* top and bottom separation */); - } - - return heightWithoutIcon + 5; -} - -void DolphinCategoryDrawer::mouseButtonPressed(const QModelIndex &index, const QRect &blockRect, QMouseEvent *event) -{ - if (!index.isValid()) { - event->ignore(); - return; - } - const QString category = index.model()->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); - int iconSize = KIconLoader::global()->currentSize(KIconLoader::Small); - if (this->category == category) { - QRect iconAllRect(blockRect); - iconAllRect.setTop(iconAllRect.top() + 4); - iconAllRect.setLeft(iconAllRect.right() - 16 - 7); - iconAllRect.setSize(QSize(iconSize, iconSize)); - if (iconAllRect.contains(pos)) { - event->accept(); - hotSpotPressed = SelectAllHotSpot; - categoryPressed = index; - return; - } - QRect iconNoneRect(blockRect); - iconNoneRect.setTop(iconNoneRect.top() + 4); - iconNoneRect.setLeft(iconNoneRect.right() - 16 * 2 - 7 * 2); - iconNoneRect.setSize(QSize(iconSize, iconSize)); - if (iconNoneRect.contains(pos)) { - event->accept(); - hotSpotPressed = UnselectAllHotSpot; - categoryPressed = index; - return; - } - } - event->ignore(); -} - -void DolphinCategoryDrawer::mouseButtonReleased(const QModelIndex &index, const QRect &blockRect, QMouseEvent *event) -{ - if (!index.isValid() || hotSpotPressed == NoneHotSpot || categoryPressed != index) { - event->ignore(); - return; - } - categoryPressed = QModelIndex(); - const QString category = index.model()->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); - int iconSize = KIconLoader::global()->currentSize(KIconLoader::Small); - if (this->category == category) { - QRect iconAllRect(blockRect); - iconAllRect.setTop(iconAllRect.top() + 4); - iconAllRect.setLeft(iconAllRect.right() - 16 - 7); - iconAllRect.setSize(QSize(iconSize, iconSize)); - if (iconAllRect.contains(pos)) { - if (hotSpotPressed == SelectAllHotSpot) { - event->accept(); - emit actionRequested(SelectAll, index); - } else { - event->ignore(); - hotSpotPressed = NoneHotSpot; - } - return; - } - QRect iconNoneRect(blockRect); - iconNoneRect.setTop(iconNoneRect.top() + 4); - iconNoneRect.setLeft(iconNoneRect.right() - 16 * 2 - 7 * 2); - iconNoneRect.setSize(QSize(iconSize, iconSize)); - if (iconNoneRect.contains(pos)) { - if (hotSpotPressed == UnselectAllHotSpot) { - event->accept(); - emit actionRequested(UnselectAll, index); - } else { - event->ignore(); - hotSpotPressed = NoneHotSpot; - } - return; - } - } - event->ignore(); -} - -void DolphinCategoryDrawer::mouseMoved(const QModelIndex &index, const QRect &, QMouseEvent *event) -{ - event->ignore(); - if (!index.isValid()) { - return; - } - pos = event->pos(); - category = index.model()->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); -} - -void DolphinCategoryDrawer::mouseLeft(const QModelIndex &, const QRect &) -{ - pos = QPoint(); - category = QString(); -} diff --git a/src/dolphincategorydrawer.h b/src/dolphincategorydrawer.h deleted file mode 100644 index d9849727e..000000000 --- a/src/dolphincategorydrawer.h +++ /dev/null @@ -1,85 +0,0 @@ -/* This file is part of the KDE project - * Copyright (C) 2007 Rafael Fernández López - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. -*/ - -#ifndef DOLPHINCATEGORYDRAWER_H -#define DOLPHINCATEGORYDRAWER_H - -#include - -#include -#include - -#include - -class LIBDOLPHINPRIVATE_EXPORT DolphinCategoryDrawer - : public KCategoryDrawerV3 -{ -public: - using KCategoryDrawerV2::mouseButtonPressed; - using KCategoryDrawerV2::mouseButtonReleased; - - enum Action { - SelectAll = 0, - UnselectAll - }; - - DolphinCategoryDrawer(KCategorizedView *view); - - virtual ~DolphinCategoryDrawer(); - - bool allCategorySelected(const QString &category) const; - - bool someCategorySelected(const QString &category) const; - - virtual void drawCategory(const QModelIndex &index, int sortRole, - const QStyleOption &option, QPainter *painter) const; - - virtual int categoryHeight(const QModelIndex &index, const QStyleOption &option) const; - -protected: - virtual void mouseButtonPressed(const QModelIndex &index, const QRect &blockRect, QMouseEvent *event); - - virtual void mouseButtonReleased(const QModelIndex &index, const QRect &blockRect, QMouseEvent *event); - - virtual void mouseMoved(const QModelIndex &index, const QRect &blockRect, QMouseEvent *event); - - virtual void mouseLeft(const QModelIndex &index,const QRect &blockRect); - -private: - enum HotSpot { - NoneHotSpot = 0, - SelectAllHotSpot, - UnselectAllHotSpot - }; - - HotSpot hotSpotPressed; - QModelIndex categoryPressed; - - QPixmap selectAll; - QPixmap selectAllHovered; - QPixmap selectAllDisabled; - QPixmap unselectAll; - QPixmap unselectAllHovered; - QPixmap unselectAllDisabled; - - QPoint pos; - QString category; -}; - -#endif // DOLPHINCATEGORYDRAWER_H diff --git a/src/dolphincolumnview.cpp b/src/dolphincolumnview.cpp deleted file mode 100644 index 7e2b522b4..000000000 --- a/src/dolphincolumnview.cpp +++ /dev/null @@ -1,466 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007-2009 by Peter Penz * - * * - * 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 "dolphincolumnview.h" - -#include "dolphinmodel.h" -#include "dolphincolumnviewcontainer.h" -#include "dolphinviewcontroller.h" -#include "dolphindirlister.h" -#include "dolphinsortfilterproxymodel.h" -#include "settings/dolphinsettings.h" -#include "dolphinviewautoscroller.h" -#include "dolphin_columnmodesettings.h" -#include "dolphin_generalsettings.h" -#include "draganddrophelper.h" -#include "folderexpander.h" -#include "tooltips/tooltipmanager.h" -#include "viewextensionsfactory.h" -#include "viewmodecontroller.h" -#include "zoomlevelinfo.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -DolphinColumnView::DolphinColumnView(QWidget* parent, - DolphinColumnViewContainer* container, - const KUrl& url) : - QListView(parent), - m_active(false), - m_container(container), - m_extensionsFactory(0), - m_url(url), - m_childUrl(), - m_font(), - m_decorationSize(), - m_dirLister(0), - m_dolphinModel(0), - m_proxyModel(0), - m_dropRect() -{ - setMouseTracking(true); - setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - setSelectionBehavior(SelectItems); - setSelectionMode(QAbstractItemView::ExtendedSelection); - setDragDropMode(QAbstractItemView::DragDrop); - setDropIndicatorShown(false); - setSelectionRectVisible(true); - setEditTriggers(QAbstractItemView::NoEditTriggers); - - setVerticalScrollMode(QListView::ScrollPerPixel); - setHorizontalScrollMode(QListView::ScrollPerPixel); - - // apply the column mode settings to the widget - const ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings(); - Q_ASSERT(settings != 0); - - if (settings->useSystemFont()) { - m_font = KGlobalSettings::generalFont(); - } else { - m_font = QFont(settings->fontFamily(), - qRound(settings->fontSize()), - settings->fontWeight(), - settings->italicFont()); - m_font.setPointSizeF(settings->fontSize()); - } - - connect(this, SIGNAL(viewportEntered()), - m_container->m_dolphinViewController, SLOT(emitViewportEntered())); - connect(this, SIGNAL(entered(const QModelIndex&)), - this, SLOT(slotEntered(const QModelIndex&))); - - const DolphinView* dolphinView = m_container->m_dolphinViewController->view(); - connect(dolphinView, SIGNAL(showPreviewChanged()), - this, SLOT(slotShowPreviewChanged())); - - m_dirLister = new DolphinDirLister(); - m_dirLister->setAutoUpdate(true); - m_dirLister->setMainWindow(window()); - m_dirLister->setDelayedMimeTypes(true); - const bool showHiddenFiles = m_container->m_dolphinViewController->view()->showHiddenFiles(); - m_dirLister->setShowingDotFiles(showHiddenFiles); - - m_dolphinModel = new DolphinModel(this); - m_dolphinModel->setDirLister(m_dirLister); - m_dolphinModel->setDropsAllowed(DolphinModel::DropOnDirectory); - - m_proxyModel = new DolphinSortFilterProxyModel(this); - m_proxyModel->setSourceModel(m_dolphinModel); - m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); - - m_proxyModel->setSorting(dolphinView->sorting()); - m_proxyModel->setSortOrder(dolphinView->sortOrder()); - m_proxyModel->setSortFoldersFirst(dolphinView->sortFoldersFirst()); - - setModel(m_proxyModel); - - connect(KGlobalSettings::self(), SIGNAL(kdisplayFontChanged()), - this, SLOT(updateFont())); - - const ViewModeController* viewModeController = m_container->m_viewModeController; - connect(viewModeController, SIGNAL(zoomLevelChanged(int)), - this, SLOT(setZoomLevel(int))); - const QString nameFilter = viewModeController->nameFilter(); - if (!nameFilter.isEmpty()) { - m_proxyModel->setFilterFixedString(nameFilter); - } - - updateDecorationSize(dolphinView->showPreview()); - updateBackground(); - - DolphinViewController* dolphinViewController = m_container->m_dolphinViewController; - m_extensionsFactory = new ViewExtensionsFactory(this, dolphinViewController, viewModeController); - - m_dirLister->openUrl(url, KDirLister::NoFlags); -} - -DolphinColumnView::~DolphinColumnView() -{ - delete m_proxyModel; - m_proxyModel = 0; - delete m_dolphinModel; - m_dolphinModel = 0; - m_dirLister = 0; // deleted by m_dolphinModel -} - -void DolphinColumnView::setActive(bool active) -{ - if (m_active != active) { - m_active = active; - - if (active) { - activate(); - } else { - deactivate(); - } - } -} - -void DolphinColumnView::updateBackground() -{ - // TODO: The alpha-value 150 is copied from DolphinView::setActive(). When - // cleaning up the cut-indication of DolphinColumnView with the code from - // DolphinView a common helper-class should be available which can be shared - // by all view implementations -> no hardcoded value anymore - const QPalette::ColorRole role = viewport()->backgroundRole(); - QColor color = viewport()->palette().color(role); - color.setAlpha((m_active && m_container->m_active) ? 255 : 150); - - QPalette palette = viewport()->palette(); - palette.setColor(role, color); - viewport()->setPalette(palette); - - update(); -} - -KFileItem DolphinColumnView::itemAt(const QPoint& pos) const -{ - KFileItem item; - const QModelIndex index = indexAt(pos); - if (index.isValid() && (index.column() == DolphinModel::Name)) { - const QModelIndex dolphinModelIndex = m_proxyModel->mapToSource(index); - item = m_dolphinModel->itemForIndex(dolphinModelIndex); - } - return item; -} - -void DolphinColumnView::setSelectionModel(QItemSelectionModel* model) -{ - // If a change of the selection is done although the view is not active - // (e. g. by the selection markers), the column must be activated. This - // is done by listening to the current selectionChanged() signal. - if (selectionModel() != 0) { - disconnect(selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), - this, SLOT(requestActivation())); - } - - QListView::setSelectionModel(model); - - connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), - this, SLOT(requestActivation())); -} - -QStyleOptionViewItem DolphinColumnView::viewOptions() const -{ - QStyleOptionViewItem viewOptions = QListView::viewOptions(); - viewOptions.font = m_font; - viewOptions.fontMetrics = QFontMetrics(m_font); - viewOptions.decorationSize = m_decorationSize; - viewOptions.showDecorationSelected = true; - return viewOptions; -} - -void DolphinColumnView::startDrag(Qt::DropActions supportedActions) -{ - DragAndDropHelper::instance().startDrag(this, supportedActions, m_container->m_dolphinViewController); -} - -void DolphinColumnView::dragEnterEvent(QDragEnterEvent* event) -{ - if (DragAndDropHelper::instance().isMimeDataSupported(event->mimeData())) { - event->acceptProposedAction(); - requestActivation(); - } -} - -void DolphinColumnView::dragLeaveEvent(QDragLeaveEvent* event) -{ - QListView::dragLeaveEvent(event); - setDirtyRegion(m_dropRect); -} - -void DolphinColumnView::dragMoveEvent(QDragMoveEvent* event) -{ - QListView::dragMoveEvent(event); - - // TODO: remove this code when the issue #160611 is solved in Qt 4.4 - const QModelIndex index = indexAt(event->pos()); - setDirtyRegion(m_dropRect); - - m_dropRect.setSize(QSize()); // set as invalid - if (index.isValid()) { - m_container->m_dolphinViewController->setItemView(this); - const KFileItem item = m_container->m_dolphinViewController->itemForIndex(index); - if (!item.isNull() && item.isDir()) { - m_dropRect = visualRect(index); - } - } - setDirtyRegion(m_dropRect); - - if (DragAndDropHelper::instance().isMimeDataSupported(event->mimeData())) { - // accept url drops, independently from the destination item - event->acceptProposedAction(); - } -} - -void DolphinColumnView::dropEvent(QDropEvent* event) -{ - const QModelIndex index = indexAt(event->pos()); - m_container->m_dolphinViewController->setItemView(this); - const KFileItem item = m_container->m_dolphinViewController->itemForIndex(index); - m_container->m_dolphinViewController->indicateDroppedUrls(item, url(), event); - QListView::dropEvent(event); -} - -void DolphinColumnView::paintEvent(QPaintEvent* event) -{ - if (!m_childUrl.isEmpty()) { - // indicate the shown URL of the next column by highlighting the shown folder item - const QModelIndex dirIndex = m_dolphinModel->indexForUrl(m_childUrl); - const QModelIndex proxyIndex = m_proxyModel->mapFromSource(dirIndex); - if (proxyIndex.isValid() && !selectionModel()->isSelected(proxyIndex)) { - const QRect itemRect = visualRect(proxyIndex); - QPainter painter(viewport()); - QColor color = KColorScheme(QPalette::Active, KColorScheme::View).foreground().color(); - color.setAlpha(32); - painter.setPen(Qt::NoPen); - painter.setBrush(color); - painter.drawRect(itemRect); - } - } - - QListView::paintEvent(event); -} - -void DolphinColumnView::mousePressEvent(QMouseEvent* event) -{ - requestActivation(); - if (!indexAt(event->pos()).isValid()) { - if (QApplication::mouseButtons() & Qt::MidButton) { - m_container->m_dolphinViewController->replaceUrlByClipboard(); - } - } else if (event->button() == Qt::LeftButton) { - // TODO: see comment in DolphinIconsView::mousePressEvent() - setState(QAbstractItemView::DraggingState); - } - QListView::mousePressEvent(event); -} - -void DolphinColumnView::keyPressEvent(QKeyEvent* event) -{ - QListView::keyPressEvent(event); - - DolphinViewController* controller = m_container->m_dolphinViewController; - controller->handleKeyPressEvent(event); - switch (event->key()) { - case Qt::Key_Right: { - // Special key handling for the column: A Key_Right should - // open a new column for the currently selected folder. - const QModelIndex index = currentIndex(); - const KFileItem item = controller->itemForIndex(index); - if (!item.isNull() && item.isDir()) { - controller->emitItemTriggered(item); - } - break; - } - - case Qt::Key_Escape: - selectionModel()->setCurrentIndex(selectionModel()->currentIndex(), - QItemSelectionModel::Current | - QItemSelectionModel::Clear); - break; - - default: - break; - } -} - -void DolphinColumnView::contextMenuEvent(QContextMenuEvent* event) -{ - requestActivation(); - QListView::contextMenuEvent(event); - m_container->m_dolphinViewController->triggerContextMenuRequest(event->pos()); -} - -void DolphinColumnView::wheelEvent(QWheelEvent* event) -{ - const int step = m_decorationSize.height(); - verticalScrollBar()->setSingleStep(step); - QListView::wheelEvent(event); -} - -void DolphinColumnView::leaveEvent(QEvent* event) -{ - QListView::leaveEvent(event); - // if the mouse is above an item and moved very fast outside the widget, - // no viewportEntered() signal might be emitted although the mouse has been moved - // above the viewport - m_container->m_dolphinViewController->emitViewportEntered(); -} - -void DolphinColumnView::currentChanged(const QModelIndex& current, const QModelIndex& previous) -{ - QListView::currentChanged(current, previous); - m_extensionsFactory->handleCurrentIndexChange(current, previous); -} - -void DolphinColumnView::setZoomLevel(int level) -{ - const int size = ZoomLevelInfo::iconSizeForZoomLevel(level); - ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings(); - - const bool showPreview = m_container->m_dolphinViewController->view()->showPreview(); - if (showPreview) { - settings->setPreviewSize(size); - } else { - settings->setIconSize(size); - } - - updateDecorationSize(showPreview); -} - -void DolphinColumnView::slotEntered(const QModelIndex& index) -{ - m_container->m_dolphinViewController->setItemView(this); - m_container->m_dolphinViewController->emitItemEntered(index); -} - -void DolphinColumnView::requestActivation() -{ - m_container->m_dolphinViewController->requestActivation(); - if (!m_active) { - m_container->requestActivation(this); - selectionModel()->clear(); - } -} - -void DolphinColumnView::updateFont() -{ - const ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings(); - Q_ASSERT(settings != 0); - - if (settings->useSystemFont()) { - m_font = KGlobalSettings::generalFont(); - } -} - -void DolphinColumnView::slotShowPreviewChanged() -{ - const DolphinView* view = m_container->m_dolphinViewController->view(); - updateDecorationSize(view->showPreview()); -} - -void DolphinColumnView::activate() -{ - setFocus(Qt::OtherFocusReason); - - if (KGlobalSettings::singleClick()) { - connect(this, SIGNAL(clicked(const QModelIndex&)), - m_container->m_dolphinViewController, SLOT(triggerItem(const QModelIndex&))); - } else { - connect(this, SIGNAL(doubleClicked(const QModelIndex&)), - m_container->m_dolphinViewController, SLOT(triggerItem(const QModelIndex&))); - } - - if (selectionModel() && selectionModel()->currentIndex().isValid()) { - selectionModel()->setCurrentIndex(selectionModel()->currentIndex(), QItemSelectionModel::SelectCurrent); - } - - updateBackground(); -} - -void DolphinColumnView::deactivate() -{ - clearFocus(); - if (KGlobalSettings::singleClick()) { - disconnect(this, SIGNAL(clicked(const QModelIndex&)), - m_container->m_dolphinViewController, SLOT(triggerItem(const QModelIndex&))); - } else { - disconnect(this, SIGNAL(doubleClicked(const QModelIndex&)), - m_container->m_dolphinViewController, SLOT(triggerItem(const QModelIndex&))); - } - - // It is important to disconnect the connection to requestActivation() temporary, otherwise the internal - // clearing of the selection would result in activating the column again. - disconnect(selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), - this, SLOT(requestActivation())); - const QModelIndex current = selectionModel()->currentIndex(); - selectionModel()->clear(); - selectionModel()->setCurrentIndex(current, QItemSelectionModel::NoUpdate); - connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), - this, SLOT(requestActivation())); - - updateBackground(); -} - -void DolphinColumnView::updateDecorationSize(bool showPreview) -{ - ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings(); - const int iconSize = showPreview ? settings->previewSize() : settings->iconSize(); - const QSize size(iconSize, iconSize); - setIconSize(size); - - m_decorationSize = size; - - doItemsLayout(); -} - -#include "dolphincolumnview.moc" diff --git a/src/dolphincolumnview.h b/src/dolphincolumnview.h deleted file mode 100644 index 64feac4f9..000000000 --- a/src/dolphincolumnview.h +++ /dev/null @@ -1,170 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007-2009 by Peter Penz * - * * - * 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 DOLPHINCOLUMNVIEW_H -#define DOLPHINCOLUMNVIEW_H - -#include "dolphinview.h" - -#include -#include -#include -#include - -#include - -class DolphinColumnViewContainer; -class DolphinModel; -class DolphinSortFilterProxyModel; -class DolphinDirLister; -class KFileItem; -class SelectionManager; -class ViewExtensionsFactory; - -/** - * Represents one column inside the DolphinColumnViewContainer. - */ -class DolphinColumnView : public QListView -{ - Q_OBJECT - -public: - DolphinColumnView(QWidget* parent, - DolphinColumnViewContainer* container, - const KUrl& url); - virtual ~DolphinColumnView(); - - /** - * An active column is defined as column, which shows the same URL - * as indicated by the URL navigator. The active column is usually - * drawn in a lighter color. All operations are applied to this column. - */ - void setActive(bool active); - bool isActive() const; - - /** - * Sets the directory URL of the child column that is shown next to - * this column. This property is only used for a visual indication - * of the shown directory, it does not trigger a loading of the model. - */ - void setChildUrl(const KUrl& url); - KUrl childUrl() const; - - /** Sets the directory URL that is shown inside the column widget. */ - void setUrl(const KUrl& url); - - /** Returns the directory URL that is shown inside the column widget. */ - KUrl url() const; - - /** - * Updates the background color dependent from the activation state - * \a isViewActive of the column view. - */ - void updateBackground(); - - /** - * Returns the item on the position \a pos. The KFileItem instance - * is null if no item is below the position. - */ - KFileItem itemAt(const QPoint& pos) const; - - virtual void setSelectionModel(QItemSelectionModel* model); - -protected: - virtual QStyleOptionViewItem viewOptions() const; - virtual void startDrag(Qt::DropActions supportedActions); - virtual void dragEnterEvent(QDragEnterEvent* event); - virtual void dragLeaveEvent(QDragLeaveEvent* event); - virtual void dragMoveEvent(QDragMoveEvent* event); - virtual void dropEvent(QDropEvent* event); - virtual void paintEvent(QPaintEvent* event); - virtual void mousePressEvent(QMouseEvent* event); - virtual void keyPressEvent(QKeyEvent* event); - virtual void contextMenuEvent(QContextMenuEvent* event); - virtual void wheelEvent(QWheelEvent* event); - virtual void leaveEvent(QEvent* event); - virtual void currentChanged(const QModelIndex& current, const QModelIndex& previous); - -private slots: - void setZoomLevel(int level); - - void slotEntered(const QModelIndex& index); - void requestActivation(); - void updateFont(); - - void slotShowPreviewChanged(); - -private: - /** Used by DolphinColumnView::setActive(). */ - void activate(); - - /** Used by DolphinColumnView::setActive(). */ - void deactivate(); - - void updateDecorationSize(bool showPreview); - -private: - bool m_active; - DolphinColumnViewContainer* m_container; - SelectionManager* m_selectionManager; - ViewExtensionsFactory* m_extensionsFactory; - KUrl m_url; // URL of the directory that is shown - KUrl m_childUrl; // URL of the next column that is shown - - QFont m_font; - QSize m_decorationSize; - - DolphinDirLister* m_dirLister; - DolphinModel* m_dolphinModel; - DolphinSortFilterProxyModel* m_proxyModel; - - QRect m_dropRect; - - friend class DolphinColumnViewContainer; -}; - -inline bool DolphinColumnView::isActive() const -{ - return m_active; -} - -inline void DolphinColumnView::setChildUrl(const KUrl& url) -{ - m_childUrl = url; -} - -inline KUrl DolphinColumnView::childUrl() const -{ - return m_childUrl; -} - -inline void DolphinColumnView::setUrl(const KUrl& url) -{ - if (url != m_url) { - m_url = url; - //reload(); - } -} - -inline KUrl DolphinColumnView::url() const -{ - return m_url; -} - -#endif diff --git a/src/dolphincolumnviewcontainer.cpp b/src/dolphincolumnviewcontainer.cpp deleted file mode 100644 index 344d38d8a..000000000 --- a/src/dolphincolumnviewcontainer.cpp +++ /dev/null @@ -1,416 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007-2009 by Peter Penz * - * * - * 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 "dolphincolumnviewcontainer.h" - -#include "dolphin_columnmodesettings.h" - -#include "dolphincolumnview.h" -#include "dolphinviewcontroller.h" -#include "dolphinsortfilterproxymodel.h" -#include "draganddrophelper.h" -#include "settings/dolphinsettings.h" -#include "viewmodecontroller.h" - -#include -#include -#include -#include - -DolphinColumnViewContainer::DolphinColumnViewContainer(QWidget* parent, - DolphinViewController* dolphinViewController, - const ViewModeController* viewModeController) : - QScrollArea(parent), - m_dolphinViewController(dolphinViewController), - m_viewModeController(viewModeController), - m_active(false), - m_index(-1), - m_contentX(0), - m_columns(), - m_emptyViewport(0), - m_animation(0), - m_dragSource(0), - m_activeUrlTimer(0) -{ - Q_ASSERT(dolphinViewController != 0); - Q_ASSERT(viewModeController != 0); - - setAcceptDrops(true); - setFocusPolicy(Qt::NoFocus); - setFrameShape(QFrame::NoFrame); - setLayoutDirection(Qt::LeftToRight); - - connect(viewModeController, SIGNAL(activationChanged(bool)), - this, SLOT(updateColumnsBackground(bool))); - - connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), - this, SLOT(moveContentHorizontally(int))); - - m_animation = new QTimeLine(500, this); - connect(m_animation, SIGNAL(frameChanged(int)), horizontalScrollBar(), SLOT(setValue(int))); - - m_activeUrlTimer = new QTimer(this); - m_activeUrlTimer->setSingleShot(true); - m_activeUrlTimer->setInterval(200); - connect(m_activeUrlTimer, SIGNAL(timeout()), - this, SLOT(updateActiveUrl())); - - DolphinColumnView* column = new DolphinColumnView(viewport(), this, viewModeController->url()); - m_columns.append(column); - requestActivation(column); - - m_emptyViewport = new QFrame(viewport()); - m_emptyViewport->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); - - updateColumnsBackground(true); - -} - -DolphinColumnViewContainer::~DolphinColumnViewContainer() -{ - delete m_dragSource; - m_dragSource = 0; -} - -KUrl DolphinColumnViewContainer::rootUrl() const -{ - return m_columns[0]->url(); -} - -QAbstractItemView* DolphinColumnViewContainer::activeColumn() const -{ - return m_columns[m_index]; -} - -void DolphinColumnViewContainer::showColumn(const KUrl& url) -{ - if (!rootUrl().isParentOf(url)) { - removeAllColumns(); - m_columns[0]->setUrl(url); - return; - } - - int columnIndex = 0; - foreach (DolphinColumnView* column, m_columns) { - if (column->url() == url) { - // the column represents already the requested URL, hence activate it - requestActivation(column); - layoutColumns(); - return; - } else if (!column->url().isParentOf(url)) { - // the column is no parent of the requested URL, hence - // just delete all remaining columns - if (columnIndex > 0) { - QList::iterator start = m_columns.begin() + columnIndex; - QList::iterator end = m_columns.end(); - for (QList::iterator it = start; it != end; ++it) { - deleteColumn(*it); - } - m_columns.erase(start, end); - - const int maxIndex = m_columns.count() - 1; - Q_ASSERT(maxIndex >= 0); - if (m_index > maxIndex) { - m_index = maxIndex; - } - break; - } - } - ++columnIndex; - } - - // Create missing columns. Assuming that the path is "/home/peter/Temp/" and - // the target path is "/home/peter/Temp/a/b/c/", then the columns "a", "b" and - // "c" will be created. - const int lastIndex = m_columns.count() - 1; - Q_ASSERT(lastIndex >= 0); - - const KUrl& activeUrl = m_columns[lastIndex]->url(); - Q_ASSERT(activeUrl.isParentOf(url)); - Q_ASSERT(activeUrl != url); - - QString path = activeUrl.url(KUrl::AddTrailingSlash); - const QString targetPath = url.url(KUrl::AddTrailingSlash); - - columnIndex = lastIndex; - int slashIndex = path.count('/'); - bool hasSubPath = (slashIndex >= 0); - while (hasSubPath) { - const QString subPath = targetPath.section('/', slashIndex, slashIndex); - if (subPath.isEmpty()) { - hasSubPath = false; - } else { - path += subPath + '/'; - ++slashIndex; - - const KUrl childUrl = KUrl(path); - m_columns[columnIndex]->setChildUrl(childUrl); - columnIndex++; - - DolphinColumnView* column = new DolphinColumnView(viewport(), this, childUrl); - m_columns.append(column); - - // Before invoking layoutColumns() the column must be set visible temporary. - // To prevent a flickering the initial geometry is set to a hidden position. - column->setGeometry(QRect(-1, -1, 1, 1)); - column->show(); - layoutColumns(); - updateScrollBar(); - } - } - - requestActivation(m_columns[columnIndex]); -} - -void DolphinColumnViewContainer::mousePressEvent(QMouseEvent* event) -{ - m_dolphinViewController->requestActivation(); - QScrollArea::mousePressEvent(event); -} - -void DolphinColumnViewContainer::keyPressEvent(QKeyEvent* event) -{ - if (event->key() == Qt::Key_Left) { - if (m_index > 0) { - requestActivation(m_columns[m_index - 1]); - } - } else { - QScrollArea::keyPressEvent(event); - } -} - -void DolphinColumnViewContainer::resizeEvent(QResizeEvent* event) -{ - QScrollArea::resizeEvent(event); - layoutColumns(); - updateScrollBar(); - assureVisibleActiveColumn(); -} - -void DolphinColumnViewContainer::wheelEvent(QWheelEvent* event) -{ - // let Ctrl+wheel events propagate to the DolphinView for icon zooming - if ((event->modifiers() & Qt::ControlModifier) == Qt::ControlModifier) { - event->ignore(); - } else { - QScrollArea::wheelEvent(event); - } -} - -void DolphinColumnViewContainer::moveContentHorizontally(int x) -{ - m_contentX = isRightToLeft() ? +x : -x; - layoutColumns(); -} - -void DolphinColumnViewContainer::updateColumnsBackground(bool active) -{ - if (active == m_active) { - return; - } - - m_active = active; - - // dim the background of the viewport - const QPalette::ColorRole role = viewport()->backgroundRole(); - QColor background = viewport()->palette().color(role); - background.setAlpha(0); // make background transparent - - QPalette palette = viewport()->palette(); - palette.setColor(role, background); - viewport()->setPalette(palette); - - foreach (DolphinColumnView* column, m_columns) { - column->updateBackground(); - } -} - -void DolphinColumnViewContainer::updateActiveUrl() -{ - const KUrl activeUrl = m_columns[m_index]->url(); - m_dolphinViewController->requestUrlChange(activeUrl); -} - -void DolphinColumnViewContainer::layoutColumns() -{ - const int gap = 4; - - ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings(); - const int columnWidth = settings->columnWidth(); - - QRect emptyViewportRect; - if (isRightToLeft()) { - int x = viewport()->width() - columnWidth + m_contentX; - foreach (DolphinColumnView* column, m_columns) { - column->setGeometry(QRect(x, 0, columnWidth - gap, viewport()->height())); - x -= columnWidth; - } - emptyViewportRect = QRect(0, 0, x + columnWidth - gap, viewport()->height()); - } else { - int x = m_contentX; - foreach (DolphinColumnView* column, m_columns) { - column->setGeometry(QRect(x, 0, columnWidth - gap, viewport()->height())); - x += columnWidth; - } - emptyViewportRect = QRect(x, 0, viewport()->width() - x - gap, viewport()->height()); - } - - if (emptyViewportRect.isValid()) { - m_emptyViewport->show(); - m_emptyViewport->setGeometry(emptyViewportRect); - } else { - m_emptyViewport->hide(); - } -} - -void DolphinColumnViewContainer::updateScrollBar() -{ - ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings(); - const int contentWidth = m_columns.count() * settings->columnWidth(); - - horizontalScrollBar()->setPageStep(contentWidth); - horizontalScrollBar()->setRange(0, contentWidth - viewport()->width()); -} - -void DolphinColumnViewContainer::assureVisibleActiveColumn() -{ - const int viewportWidth = viewport()->width(); - const int x = activeColumn()->x(); - - ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings(); - const int width = settings->columnWidth(); - - if (x + width > viewportWidth) { - const int newContentX = m_contentX - x - width + viewportWidth; - if (isRightToLeft()) { - m_animation->setFrameRange(m_contentX, newContentX); - } else { - m_animation->setFrameRange(-m_contentX, -newContentX); - } - if (m_animation->state() != QTimeLine::Running) { - m_animation->start(); - } - } else if (x < 0) { - const int newContentX = m_contentX - x; - if (isRightToLeft()) { - m_animation->setFrameRange(m_contentX, newContentX); - } else { - m_animation->setFrameRange(-m_contentX, -newContentX); - } - if (m_animation->state() != QTimeLine::Running) { - m_animation->start(); - } - } -} - -void DolphinColumnViewContainer::requestActivation(DolphinColumnView* column) -{ - if (m_dolphinViewController->itemView() != column) { - m_dolphinViewController->setItemView(column); - } - if (focusProxy() != column) { - setFocusProxy(column); - } - - if (column->isActive()) { - assureVisibleActiveColumn(); - } else { - // Deactivate the currently active column - if (m_index >= 0) { - m_columns[m_index]->setActive(false); - } - - // Get the index of the column that should get activated - int index = 0; - foreach (DolphinColumnView* currColumn, m_columns) { - if (currColumn == column) { - break; - } - ++index; - } - - Q_ASSERT(index != m_index); - Q_ASSERT(index < m_columns.count()); - - // Activate the requested column - m_index = index; - m_columns[m_index]->setActive(true); - - assureVisibleActiveColumn(); - m_activeUrlTimer->start(); // calls slot updateActiveUrl() - } -} - -void DolphinColumnViewContainer::removeAllColumns() -{ - QList::iterator start = m_columns.begin() + 1; - QList::iterator end = m_columns.end(); - for (QList::iterator it = start; it != end; ++it) { - deleteColumn(*it); - } - m_columns.erase(start, end); - m_index = 0; - m_columns[0]->setActive(true); - assureVisibleActiveColumn(); -} - -QPoint DolphinColumnViewContainer::columnPosition(DolphinColumnView* column, const QPoint& point) const -{ - const QPoint topLeft = column->frameGeometry().topLeft(); - return QPoint(point.x() - topLeft.x(), point.y() - topLeft.y()); -} - -void DolphinColumnViewContainer::deleteColumn(DolphinColumnView* column) -{ - if (column == 0) { - return; - } - - if (m_dolphinViewController->itemView() == column) { - m_dolphinViewController->setItemView(0); - } - // deleteWhenNotDragSource(column) does not necessarily delete column, - // and we want its preview generator destroyed immediately. - column->hide(); - // Prevent automatic destruction of column when this DolphinColumnViewContainer - // is destroyed. - column->setParent(0); - column->disconnect(); - - if (DragAndDropHelper::instance().isDragSource(column)) { - // The column is a drag source (the feature "Open folders - // during drag operations" is used). Deleting the view - // during an ongoing drag operation is not allowed, so - // this will postponed. - if (m_dragSource != 0) { - // the old stored view is obviously not the drag source anymore - m_dragSource->deleteLater(); - m_dragSource = 0; - } - column->hide(); - column->setParent(0); - column->disconnect(); - - m_dragSource = column; - } else { - column->deleteLater(); - } -} - -#include "dolphincolumnviewcontainer.moc" diff --git a/src/dolphincolumnviewcontainer.h b/src/dolphincolumnviewcontainer.h deleted file mode 100644 index c67fb3cff..000000000 --- a/src/dolphincolumnviewcontainer.h +++ /dev/null @@ -1,147 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007-2009 by Peter Penz * - * * - * 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 DOLPHINCOLUMNVIEWCONTAINER_H -#define DOLPHINCOLUMNVIEWCONTAINER_H - -#include "dolphinview.h" - -#include - -#include -#include -#include - -class DolphinColumnView; -class DolphinViewController; -class QFrame; -class QTimeLine; -class QTimer; - -/** - * @brief Represents a container for columns represented as instances - * of DolphinColumnView. - * - * @see DolphinColumnView - */ -class DolphinColumnViewContainer : public QScrollArea -{ - Q_OBJECT - -public: - /** - * @param parent Parent widget. - * @param dolphinViewController Allows the DolphinColumnView to control the - * DolphinView in a limited way. - * @param viewModeController Controller that is used by the DolphinView - * to control the DolphinColumnView. The DolphinColumnView - * only has read access to the controller. - * @param model Directory that is shown. - */ - explicit DolphinColumnViewContainer(QWidget* parent, - DolphinViewController* dolphinViewController, - const ViewModeController* viewModeController); - virtual ~DolphinColumnViewContainer(); - - KUrl rootUrl() const; - - QAbstractItemView* activeColumn() const; - - /** - * Shows the column which represents the URL \a url. If the column - * is already shown, it gets activated, otherwise it will be created. - */ - void showColumn(const KUrl& url); - -protected: - virtual void mousePressEvent(QMouseEvent* event); - virtual void keyPressEvent(QKeyEvent* event); - virtual void resizeEvent(QResizeEvent* event); - virtual void wheelEvent(QWheelEvent* event); - -private slots: - /** - * Moves the content of the columns view to represent - * the scrollbar position \a x. - */ - void moveContentHorizontally(int x); - - /** - * Updates the background color of the columns to respect - * the current activation state \a active. - */ - void updateColumnsBackground(bool active); - - /** - * Tells the Dolphin controller to update the active URL - * to m_activeUrl. The slot is called asynchronously with a - * small delay, as this prevents a flickering when a directory - * from an inactive column gets selected. - */ - void updateActiveUrl(); - -private: - void layoutColumns(); - void updateScrollBar(); - - /** - * Assures that the currently active column is fully visible - * by adjusting the horizontal position of the content. - */ - void assureVisibleActiveColumn(); - - /** - * Request the activation for the column \a column. It is assured - * that the columns gets fully visible by adjusting the horizontal - * position of the content. - */ - void requestActivation(DolphinColumnView* column); - - /** Removes all columns except of the root column. */ - void removeAllColumns(); - - /** - * Returns the position of the point \a point relative to the column - * \a column. - */ - QPoint columnPosition(DolphinColumnView* column, const QPoint& point) const; - - /** - * Deletes the column. If the itemview of the controller is set to the column, - * the controllers itemview is set to 0. - */ - void deleteColumn(DolphinColumnView* column); - -private: - DolphinViewController* m_dolphinViewController; - const ViewModeController* m_viewModeController; - bool m_active; - int m_index; - int m_contentX; - QList m_columns; - QFrame* m_emptyViewport; - QTimeLine* m_animation; - QAbstractItemView* m_dragSource; - - QTimer* m_activeUrlTimer; - - friend class DolphinColumnView; -}; - -#endif diff --git a/src/dolphincontextmenu.cpp b/src/dolphincontextmenu.cpp index 9b49f7c89..84ad9d632 100644 --- a/src/dolphincontextmenu.cpp +++ b/src/dolphincontextmenu.cpp @@ -23,7 +23,6 @@ #include "dolphinmainwindow.h" #include "dolphinnewmenu.h" #include "settings/dolphinsettings.h" -#include "dolphinview.h" #include "dolphinviewcontainer.h" #include "dolphin_generalsettings.h" @@ -52,6 +51,9 @@ #include #include +#include "views/dolphinview.h" +#include "views/viewmodecontroller.h" + DolphinContextMenu::DolphinContextMenu(DolphinMainWindow* parent, const KFileItem& fileInfo, const KUrl& baseUrl) : diff --git a/src/dolphindetailsview.cpp b/src/dolphindetailsview.cpp deleted file mode 100644 index 961bd7872..000000000 --- a/src/dolphindetailsview.cpp +++ /dev/null @@ -1,1113 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2006 by Peter Penz (peter.penz@gmx.at) * - * Copyright (C) 2008 by Simon St. James (kdedevel@etotheipiplusone.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 "dolphindetailsview.h" - -#include "additionalinfoaccessor.h" -#include "dolphinmodel.h" -#include "dolphinviewcontroller.h" -#include "dolphinfileitemdelegate.h" -#include "settings/dolphinsettings.h" -#include "dolphinsortfilterproxymodel.h" -#include "dolphinviewautoscroller.h" -#include "draganddrophelper.h" -#include "viewextensionsfactory.h" -#include "viewmodecontroller.h" -#include "viewproperties.h" -#include "zoomlevelinfo.h" - -#include "dolphin_detailsmodesettings.h" -#include "dolphin_generalsettings.h" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -DolphinDetailsView::DolphinDetailsView(QWidget* parent, - DolphinViewController* dolphinViewController, - const ViewModeController* viewModeController, - DolphinSortFilterProxyModel* proxyModel) : - QTreeView(parent), - m_autoResize(true), - m_expandingTogglePressed(false), - m_keyPressed(false), - m_useDefaultIndexAt(true), - m_ignoreScrollTo(false), - m_dolphinViewController(dolphinViewController), - m_viewModeController(viewModeController), - m_extensionsFactory(0), - m_expandableFoldersAction(0), - m_expandedUrls(), - m_font(), - m_decorationSize(), - m_band() -{ - const DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings(); - Q_ASSERT(settings != 0); - Q_ASSERT(dolphinViewController != 0); - Q_ASSERT(viewModeController != 0); - - setLayoutDirection(Qt::LeftToRight); - setAcceptDrops(true); - setSortingEnabled(true); - setUniformRowHeights(true); - setSelectionBehavior(SelectItems); - setDragDropMode(QAbstractItemView::DragDrop); - setDropIndicatorShown(false); - setAlternatingRowColors(true); - setRootIsDecorated(settings->expandableFolders()); - setItemsExpandable(settings->expandableFolders()); - setEditTriggers(QAbstractItemView::NoEditTriggers); - setModel(proxyModel); - - setMouseTracking(true); - - const ViewProperties props(viewModeController->url()); - setSortIndicatorSection(props.sorting()); - setSortIndicatorOrder(props.sortOrder()); - - QHeaderView* headerView = header(); - connect(headerView, SIGNAL(sectionClicked(int)), - this, SLOT(synchronizeSortingState(int))); - headerView->setContextMenuPolicy(Qt::CustomContextMenu); - connect(headerView, SIGNAL(customContextMenuRequested(const QPoint&)), - this, SLOT(configureSettings(const QPoint&))); - connect(headerView, SIGNAL(sectionResized(int, int, int)), - this, SLOT(slotHeaderSectionResized(int, int, int))); - connect(headerView, SIGNAL(sectionHandleDoubleClicked(int)), - this, SLOT(disableAutoResizing())); - - connect(parent, SIGNAL(sortingChanged(DolphinView::Sorting)), - this, SLOT(setSortIndicatorSection(DolphinView::Sorting))); - connect(parent, SIGNAL(sortOrderChanged(Qt::SortOrder)), - this, SLOT(setSortIndicatorOrder(Qt::SortOrder))); - - connect(this, SIGNAL(clicked(const QModelIndex&)), - dolphinViewController, SLOT(requestTab(const QModelIndex&))); - if (KGlobalSettings::singleClick()) { - connect(this, SIGNAL(clicked(const QModelIndex&)), - dolphinViewController, SLOT(triggerItem(const QModelIndex&))); - } else { - connect(this, SIGNAL(doubleClicked(const QModelIndex&)), - dolphinViewController, SLOT(triggerItem(const QModelIndex&))); - } - - connect(this, SIGNAL(entered(const QModelIndex&)), - this, SLOT(slotEntered(const QModelIndex&))); - connect(this, SIGNAL(viewportEntered()), - dolphinViewController, SLOT(emitViewportEntered())); - connect(viewModeController, SIGNAL(zoomLevelChanged(int)), - this, SLOT(setZoomLevel(int))); - connect(dolphinViewController->view(), SIGNAL(additionalInfoChanged()), - this, SLOT(updateColumnVisibility())); - connect(viewModeController, SIGNAL(activationChanged(bool)), - this, SLOT(slotActivationChanged(bool))); - - if (settings->useSystemFont()) { - m_font = KGlobalSettings::generalFont(); - } else { - m_font = QFont(settings->fontFamily(), - qRound(settings->fontSize()), - settings->fontWeight(), - settings->italicFont()); - m_font.setPointSizeF(settings->fontSize()); - } - - setVerticalScrollMode(QTreeView::ScrollPerPixel); - setHorizontalScrollMode(QTreeView::ScrollPerPixel); - - const DolphinView* view = dolphinViewController->view(); - connect(view, SIGNAL(showPreviewChanged()), - this, SLOT(slotShowPreviewChanged())); - - - setFocus(); - viewport()->installEventFilter(this); - - connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)), - this, SLOT(slotGlobalSettingsChanged(int))); - - m_useDefaultIndexAt = false; - - m_expandableFoldersAction = new QAction(i18nc("@option:check", "Expandable Folders"), this); - m_expandableFoldersAction->setCheckable(true); - 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, dolphinViewController, viewModeController); - m_extensionsFactory->fileItemDelegate()->setMinimizedNameColumn(true); - m_extensionsFactory->setAutoFolderExpandingEnabled(settings->expandableFolders()); -} - -DolphinDetailsView::~DolphinDetailsView() -{ -} - -QSet DolphinDetailsView::expandedUrls() const -{ - return m_expandedUrls; -} - -QRegion DolphinDetailsView::visualRegionForSelection(const QItemSelection& selection) const -{ - // We have to make sure that the visualRect of each model index is inside the region. - // QTreeView::visualRegionForSelection does not do it right because it assumes implicitly - // that all visualRects have the same width, which is in general not the case here. - QRegion selectionRegion; - const QModelIndexList indexes = selection.indexes(); - - foreach(const QModelIndex& index, indexes) { - selectionRegion += visualRect(index); - } - - return selectionRegion; -} - -bool DolphinDetailsView::event(QEvent* event) -{ - switch (event->type()) { - case QEvent::Polish: - header()->setResizeMode(QHeaderView::Interactive); - updateColumnVisibility(); - break; - - case QEvent::FocusOut: - // If a key-press triggers an action that e. g. opens a dialog, the - // widget gets no key-release event. Assure that the pressed state - // is reset to prevent accidently setting the current index during a selection. - m_keyPressed = false; - break; - - default: - break; - } - - return QTreeView::event(event); -} - -QStyleOptionViewItem DolphinDetailsView::viewOptions() const -{ - QStyleOptionViewItem viewOptions = QTreeView::viewOptions(); - viewOptions.font = m_font; - viewOptions.fontMetrics = QFontMetrics(m_font); - viewOptions.showDecorationSelected = true; - viewOptions.decorationSize = m_decorationSize; - return viewOptions; -} - -void DolphinDetailsView::contextMenuEvent(QContextMenuEvent* event) -{ - QTreeView::contextMenuEvent(event); - - DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings(); - m_expandableFoldersAction->setChecked(settings->expandableFolders()); - m_dolphinViewController->triggerContextMenuRequest(event->pos(), - QList() << m_expandableFoldersAction); -} - -void DolphinDetailsView::mousePressEvent(QMouseEvent* event) -{ - m_dolphinViewController->requestActivation(); - - const QModelIndex current = currentIndex(); - QTreeView::mousePressEvent(event); - - m_expandingTogglePressed = isAboveExpandingToggle(event->pos()); - - const QModelIndex index = indexAt(event->pos()); - const bool updateState = index.isValid() && - (index.column() == DolphinModel::Name) && - (event->button() == Qt::LeftButton); - if (updateState) { - setState(QAbstractItemView::DraggingState); - } - - if (!index.isValid() || (index.column() != DolphinModel::Name)) { - // the mouse press is done somewhere outside the filename column - if (QApplication::mouseButtons() & Qt::MidButton) { - m_dolphinViewController->replaceUrlByClipboard(); - } - - const Qt::KeyboardModifiers mod = QApplication::keyboardModifiers(); - if (!m_expandingTogglePressed && !(mod & Qt::ShiftModifier) && !(mod & Qt::ControlModifier)) { - clearSelection(); - } - - // restore the current index, other columns are handled as viewport area. - // setCurrentIndex(...) implicitly calls scrollTo(...), which we want to ignore. - m_ignoreScrollTo = true; - selectionModel()->setCurrentIndex(current, QItemSelectionModel::Current); - m_ignoreScrollTo = false; - - if ((event->button() == Qt::LeftButton) && !m_expandingTogglePressed) { - // Inform Qt about what we are doing - otherwise it starts dragging items around! - setState(DragSelectingState); - m_band.show = true; - // Incremental update data will not be useful - start from scratch. - m_band.ignoreOldInfo = true; - const QPoint scrollPos(horizontalScrollBar()->value(), verticalScrollBar()->value()); - m_band.origin = event->pos() + scrollPos; - m_band.destination = m_band.origin; - m_band.originalSelection = selectionModel()->selection(); - } - } -} - -void DolphinDetailsView::mouseMoveEvent(QMouseEvent* event) -{ - if (m_expandingTogglePressed) { - // Per default QTreeView starts either a selection or a drag operation when dragging - // the expanding toggle button (Qt-issue - see TODO comment in DolphinIconsView::mousePressEvent()). - // Turn off this behavior in Dolphin to stay predictable: - setState(QAbstractItemView::NoState); - return; - } - - if (m_band.show) { - const QPoint mousePos = event->pos(); - const QModelIndex index = indexAt(mousePos); - if (!index.isValid()) { - // the destination of the selection rectangle is above the viewport. In this - // case QTreeView does no selection at all, which is not the wanted behavior - // in Dolphin -> select all items within the elastic band rectangle - updateElasticBandSelection(); - } - - // TODO: enable QTreeView::mouseMoveEvent(event) again, as soon - // as the Qt-issue #199631 has been fixed. - // QTreeView::mouseMoveEvent(event); - QAbstractItemView::mouseMoveEvent(event); - updateElasticBand(); - } else { - // TODO: enable QTreeView::mouseMoveEvent(event) again, as soon - // as the Qt-issue #199631 has been fixed. - // QTreeView::mouseMoveEvent(event); - QAbstractItemView::mouseMoveEvent(event); - } -} - -void DolphinDetailsView::mouseReleaseEvent(QMouseEvent* event) -{ - if (!m_expandingTogglePressed) { - const QModelIndex index = indexAt(event->pos()); - if (index.isValid() && (index.column() == DolphinModel::Name)) { - QTreeView::mouseReleaseEvent(event); - } else { - // don't change the current index if the cursor is released - // above any other column than the name column, as the other - // columns act as viewport - const QModelIndex current = currentIndex(); - QTreeView::mouseReleaseEvent(event); - selectionModel()->setCurrentIndex(current, QItemSelectionModel::Current); - } - } - m_expandingTogglePressed = false; - - if (m_band.show) { - setState(NoState); - updateElasticBand(); - m_band.show = false; - } -} - -void DolphinDetailsView::startDrag(Qt::DropActions supportedActions) -{ - DragAndDropHelper::instance().startDrag(this, supportedActions, m_dolphinViewController); - m_band.show = false; -} - -void DolphinDetailsView::dragEnterEvent(QDragEnterEvent* event) -{ - if (DragAndDropHelper::instance().isMimeDataSupported(event->mimeData())) { - event->acceptProposedAction(); - } - - if (m_band.show) { - updateElasticBand(); - m_band.show = false; - } -} - -void DolphinDetailsView::dragLeaveEvent(QDragLeaveEvent* event) -{ - QTreeView::dragLeaveEvent(event); - setDirtyRegion(m_dropRect); -} - -void DolphinDetailsView::dragMoveEvent(QDragMoveEvent* event) -{ - QTreeView::dragMoveEvent(event); - - // TODO: remove this code when the issue #160611 is solved in Qt 4.4 - setDirtyRegion(m_dropRect); - const QModelIndex index = indexAt(event->pos()); - if (index.isValid() && (index.column() == DolphinModel::Name)) { - const KFileItem item = m_dolphinViewController->itemForIndex(index); - if (!item.isNull() && item.isDir()) { - m_dropRect = visualRect(index); - } else { - m_dropRect.setSize(QSize()); // set as invalid - } - setDirtyRegion(m_dropRect); - } - - if (DragAndDropHelper::instance().isMimeDataSupported(event->mimeData())) { - // accept url drops, independently from the destination item - event->acceptProposedAction(); - } -} - -void DolphinDetailsView::dropEvent(QDropEvent* event) -{ - const QModelIndex index = indexAt(event->pos()); - KFileItem item; - if (index.isValid() && (index.column() == DolphinModel::Name)) { - item = m_dolphinViewController->itemForIndex(index); - } - m_dolphinViewController->indicateDroppedUrls(item, m_viewModeController->url(), event); - QTreeView::dropEvent(event); -} - -void DolphinDetailsView::paintEvent(QPaintEvent* event) -{ - QTreeView::paintEvent(event); - if (m_band.show) { - // The following code has been taken from QListView - // and adapted to DolphinDetailsView. - // (C) 1992-2007 Trolltech ASA - QStyleOptionRubberBand opt; - opt.initFrom(this); - opt.shape = QRubberBand::Rectangle; - opt.opaque = false; - opt.rect = elasticBandRect(); - - QPainter painter(viewport()); - painter.save(); - style()->drawControl(QStyle::CE_RubberBand, &opt, &painter); - painter.restore(); - } -} - -void DolphinDetailsView::keyPressEvent(QKeyEvent* event) -{ - // If the Control modifier is pressed, a multiple selection - // is done and DolphinDetailsView::currentChanged() may not - // not change the selection in a custom way. - m_keyPressed = !(event->modifiers() & Qt::ControlModifier); - - QTreeView::keyPressEvent(event); - m_dolphinViewController->handleKeyPressEvent(event); -} - -void DolphinDetailsView::keyReleaseEvent(QKeyEvent* event) -{ - QTreeView::keyReleaseEvent(event); - m_keyPressed = false; -} - -void DolphinDetailsView::resizeEvent(QResizeEvent* event) -{ - QTreeView::resizeEvent(event); - if (m_autoResize) { - resizeColumns(); - } -} - -void DolphinDetailsView::wheelEvent(QWheelEvent* event) -{ - const int step = m_decorationSize.height(); - verticalScrollBar()->setSingleStep(step); - QTreeView::wheelEvent(event); -} - -void DolphinDetailsView::currentChanged(const QModelIndex& current, const QModelIndex& previous) -{ - QTreeView::currentChanged(current, previous); - m_extensionsFactory->handleCurrentIndexChange(current, previous); - - // Stay consistent with QListView: When changing the current index by key presses, - // also change the selection. - if (m_keyPressed) { - setCurrentIndex(current); - } - - // If folders are expanded, the width which is available for editing may have changed - // because it depends on the level of the current item in the folder hierarchy. - adjustMaximumSizeForEditing(current); -} - -bool DolphinDetailsView::eventFilter(QObject* watched, QEvent* event) -{ - if ((watched == viewport()) && (event->type() == QEvent::Leave)) { - // if the mouse is above an item and moved very fast outside the widget, - // no viewportEntered() signal might be emitted although the mouse has been moved - // above the viewport - m_dolphinViewController->emitViewportEntered(); - } - - return QTreeView::eventFilter(watched, event); -} - -QModelIndex DolphinDetailsView::indexAt(const QPoint& point) const -{ - // the blank portion of the name column counts as empty space - const QModelIndex index = QTreeView::indexAt(point); - const bool isAboveEmptySpace = !m_useDefaultIndexAt && - (index.column() == KDirModel::Name) && !visualRect(index).contains(point); - return isAboveEmptySpace ? QModelIndex() : index; -} - -QRect DolphinDetailsView::visualRect(const QModelIndex& index) const -{ - QRect rect = QTreeView::visualRect(index); - const KFileItem item = m_dolphinViewController->itemForIndex(index); - if (!item.isNull()) { - const int width = DolphinFileItemDelegate::nameColumnWidth(item.text(), viewOptions()); - rect.setWidth(width); - } - - return rect; -} - -void DolphinDetailsView::setSelection(const QRect& rect, QItemSelectionModel::SelectionFlags command) -{ - // We must override setSelection() as Qt calls it internally and when this happens - // we must ensure that the default indexAt() is used. - if (!m_band.show) { - m_useDefaultIndexAt = true; - QTreeView::setSelection(rect, command); - m_useDefaultIndexAt = false; - } else { - // Use our own elastic band selection algorithm - updateElasticBandSelection(); - } -} - -void DolphinDetailsView::scrollTo(const QModelIndex & index, ScrollHint hint) -{ - if (!m_ignoreScrollTo) { - QTreeView::scrollTo(index, hint); - } -} - -void DolphinDetailsView::setSortIndicatorSection(DolphinView::Sorting sorting) -{ - header()->setSortIndicator(sorting, header()->sortIndicatorOrder()); -} - -void DolphinDetailsView::setSortIndicatorOrder(Qt::SortOrder sortOrder) -{ - header()->setSortIndicator(header()->sortIndicatorSection(), sortOrder); -} - -void DolphinDetailsView::synchronizeSortingState(int column) -{ - // The sorting has already been changed in QTreeView if this slot is - // invoked, but Dolphin is not informed about this. - DolphinView::Sorting sorting = DolphinSortFilterProxyModel::sortingForColumn(column); - const Qt::SortOrder sortOrder = header()->sortIndicatorOrder(); - m_dolphinViewController->indicateSortingChange(sorting); - m_dolphinViewController->indicateSortOrderChange(sortOrder); -} - -void DolphinDetailsView::slotEntered(const QModelIndex& index) -{ - if (index.column() == DolphinModel::Name) { - m_dolphinViewController->emitItemEntered(index); - } else { - m_dolphinViewController->emitViewportEntered(); - } -} - -void DolphinDetailsView::updateElasticBand() -{ - if (m_band.show) { - QRect dirtyRegion(elasticBandRect()); - const QPoint scrollPos(horizontalScrollBar()->value(), verticalScrollBar()->value()); - m_band.destination = viewport()->mapFromGlobal(QCursor::pos()) + scrollPos; - // Going above the (logical) top-left of the view causes complications during selection; - // we may as well prevent it. - if (m_band.destination.y() < 0) { - m_band.destination.setY(0); - } - if (m_band.destination.x() < 0) { - m_band.destination.setX(0); - } - dirtyRegion = dirtyRegion.united(elasticBandRect()); - setDirtyRegion(dirtyRegion); - } -} - -QRect DolphinDetailsView::elasticBandRect() const -{ - const QPoint scrollPos(horizontalScrollBar()->value(), verticalScrollBar()->value()); - - const QPoint topLeft = m_band.origin - scrollPos; - const QPoint bottomRight = m_band.destination - scrollPos; - return QRect(topLeft, bottomRight).normalized(); -} - -void DolphinDetailsView::setZoomLevel(int level) -{ - const int size = ZoomLevelInfo::iconSizeForZoomLevel(level); - DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings(); - - const bool showPreview = m_dolphinViewController->view()->showPreview(); - if (showPreview) { - settings->setPreviewSize(size); - } else { - settings->setIconSize(size); - } - - updateDecorationSize(showPreview); -} - -void DolphinDetailsView::slotShowPreviewChanged() -{ - const DolphinView* view = m_dolphinViewController->view(); - updateDecorationSize(view->showPreview()); -} - -void DolphinDetailsView::configureSettings(const QPoint& pos) -{ - KMenu popup(this); - popup.addTitle(i18nc("@title:menu", "Columns")); - - // add checkbox items for each column - QHeaderView* headerView = header(); - const int columns = model()->columnCount(); - for (int i = 0; i < columns; ++i) { - const int logicalIndex = headerView->logicalIndex(i); - const QString text = model()->headerData(logicalIndex, Qt::Horizontal).toString(); - if (!text.isEmpty()) { - QAction* action = popup.addAction(text); - action->setCheckable(true); - action->setChecked(!headerView->isSectionHidden(logicalIndex)); - action->setData(logicalIndex); - action->setEnabled(logicalIndex != DolphinModel::Name); - } - } - popup.addSeparator(); - - QAction* activatedAction = popup.exec(header()->mapToGlobal(pos)); - if (activatedAction != 0) { - const bool show = activatedAction->isChecked(); - const int columnIndex = activatedAction->data().toInt(); - - KFileItemDelegate::InformationList list = m_dolphinViewController->view()->additionalInfo(); - const KFileItemDelegate::Information info = infoForColumn(columnIndex); - if (show) { - Q_ASSERT(!list.contains(info)); - list.append(info); - } else { - Q_ASSERT(list.contains(info)); - const int index = list.indexOf(info); - list.removeAt(index); - } - - m_dolphinViewController->indicateAdditionalInfoChange(list); - setColumnHidden(columnIndex, !show); - resizeColumns(); - } -} - -void DolphinDetailsView::updateColumnVisibility() -{ - QHeaderView* headerView = header(); - disconnect(headerView, SIGNAL(sectionMoved(int, int, int)), - this, SLOT(saveColumnPositions())); - - const DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings(); - const QList columnPositions = settings->columnPositions(); - - const KFileItemDelegate::InformationList list = m_dolphinViewController->view()->additionalInfo(); - for (int i = DolphinModel::Name; i < DolphinModel::ExtraColumnCount; ++i) { - const KFileItemDelegate::Information info = infoForColumn(i); - const bool hide = !list.contains(info) && (i != DolphinModel::Name); - if (isColumnHidden(i) != hide) { - setColumnHidden(i, hide); - } - - // If the list columnPositions has been written by an older Dolphin version, - // its length might be smaller than DolphinModel::ExtraColumnCount. Therefore, - // we have to check if item number i exists before accessing it. - if (i < columnPositions.length()) { - const int position = columnPositions[i]; - - // The position might be outside the correct range if the list columnPositions - // has been written by a newer Dolphin version with more columns. - if (position < DolphinModel::ExtraColumnCount) { - const int from = headerView->visualIndex(i); - headerView->moveSection(from, position); - } - } - } - - resizeColumns(); - - connect(headerView, SIGNAL(sectionMoved(int, int, int)), - this, SLOT(saveColumnPositions())); -} - -void DolphinDetailsView::saveColumnPositions() -{ - QList columnPositions; - for (int i = DolphinModel::Name; i < DolphinModel::ExtraColumnCount; ++i) { - columnPositions.append(header()->visualIndex(i)); - } - - DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings(); - settings->setColumnPositions(columnPositions); -} - -void DolphinDetailsView::slotHeaderSectionResized(int logicalIndex, int oldSize, int newSize) -{ - Q_UNUSED(logicalIndex); - Q_UNUSED(oldSize); - Q_UNUSED(newSize); - // If the user changes the size of the headers, the autoresize feature should be - // turned off. As there is no dedicated interface to find out whether the header - // section has been resized by the user or by a resize event, another approach is used. - // Attention: Take care when changing the if-condition to verify that there is no - // regression in combination with bug 178630 (see fix in comment #8). - if ((QApplication::mouseButtons() & Qt::LeftButton) && header()->underMouse()) { - disableAutoResizing(); - } - - adjustMaximumSizeForEditing(currentIndex()); -} - -void DolphinDetailsView::slotActivationChanged(bool active) -{ - setAlternatingRowColors(active); -} - -void DolphinDetailsView::disableAutoResizing() -{ - m_autoResize = false; -} - -void DolphinDetailsView::requestActivation() -{ - m_dolphinViewController->requestActivation(); -} - -void DolphinDetailsView::slotGlobalSettingsChanged(int category) -{ - Q_UNUSED(category); - - const DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings(); - Q_ASSERT(settings != 0); - if (settings->useSystemFont()) { - m_font = KGlobalSettings::generalFont(); - } - //Disconnect then reconnect, since the settings have been changed, the connection requirements may have also. - disconnect(this, SIGNAL(clicked(QModelIndex)), m_dolphinViewController, SLOT(triggerItem(QModelIndex))); - disconnect(this, SIGNAL(doubleClicked(QModelIndex)), m_dolphinViewController, SLOT(triggerItem(QModelIndex))); - if (KGlobalSettings::singleClick()) { - connect(this, SIGNAL(clicked(QModelIndex)), m_dolphinViewController, SLOT(triggerItem(QModelIndex))); - } else { - connect(this, SIGNAL(doubleClicked(QModelIndex)), m_dolphinViewController, SLOT(triggerItem(QModelIndex))); - } -} - -void DolphinDetailsView::updateElasticBandSelection() -{ - if (!m_band.show) { - return; - } - - // Ensure the elastic band itself is up-to-date, in - // case we are being called due to e.g. a drag event. - updateElasticBand(); - - // Clip horizontally to the name column, as some filenames will be - // longer than the column. We don't clip vertically as origin - // may be above or below the current viewport area. - const int nameColumnX = header()->sectionPosition(DolphinModel::Name); - const int nameColumnWidth = header()->sectionSize(DolphinModel::Name); - QRect selRect = elasticBandRect().normalized(); - QRect nameColumnArea(nameColumnX, selRect.y(), nameColumnWidth, selRect.height()); - selRect = nameColumnArea.intersect(selRect).normalized(); - // Get the last elastic band rectangle, expressed in viewpoint coordinates. - const QPoint scrollPos(horizontalScrollBar()->value(), verticalScrollBar()->value()); - QRect oldSelRect = QRect(m_band.lastSelectionOrigin - scrollPos, m_band.lastSelectionDestination - scrollPos).normalized(); - - if (selRect.isNull()) { - selectionModel()->select(m_band.originalSelection, QItemSelectionModel::ClearAndSelect); - m_band.ignoreOldInfo = true; - return; - } - - if (!m_band.ignoreOldInfo) { - // Do some quick checks to see if we can rule out the need to - // update the selection. - Q_ASSERT(uniformRowHeights()); - QModelIndex dummyIndex = model()->index(0, 0); - if (!dummyIndex.isValid()) { - // No items in the model presumably. - return; - } - - // If the elastic band does not cover the same rows as before, we'll - // need to re-check, and also invalidate the old item distances. - const int rowHeight = QTreeView::rowHeight(dummyIndex); - const bool coveringSameRows = - (selRect.top() / rowHeight == oldSelRect.top() / rowHeight) && - (selRect.bottom() / rowHeight == oldSelRect.bottom() / rowHeight); - if (coveringSameRows) { - // Covering the same rows, but have we moved far enough horizontally - // that we might have (de)selected some other items? - const bool itemSelectionChanged = - ((selRect.left() > oldSelRect.left()) && - (selRect.left() > m_band.insideNearestLeftEdge)) || - ((selRect.left() < oldSelRect.left()) && - (selRect.left() <= m_band.outsideNearestLeftEdge)) || - ((selRect.right() < oldSelRect.right()) && - (selRect.left() >= m_band.insideNearestRightEdge)) || - ((selRect.right() > oldSelRect.right()) && - (selRect.right() >= m_band.outsideNearestRightEdge)); - - if (!itemSelectionChanged) { - return; - } - } - } else { - // This is the only piece of optimization data that needs to be explicitly - // discarded. - m_band.lastSelectionOrigin = QPoint(); - m_band.lastSelectionDestination = QPoint(); - oldSelRect = selRect; - } - - // Do the selection from scratch. Force a update of the horizontal distances info. - m_band.insideNearestLeftEdge = nameColumnX + nameColumnWidth + 1; - m_band.insideNearestRightEdge = nameColumnX - 1; - m_band.outsideNearestLeftEdge = nameColumnX - 1; - m_band.outsideNearestRightEdge = nameColumnX + nameColumnWidth + 1; - - // Include the old selection rect as well, so we can deselect - // items that were inside it but not in the new selRect. - const QRect boundingRect = selRect.united(oldSelRect).normalized(); - if (boundingRect.isNull()) { - return; - } - - // Get the index of the item in this row in the name column. - // TODO - would this still work if the columns could be re-ordered? - QModelIndex startIndex = QTreeView::indexAt(boundingRect.topLeft()); - if (startIndex.parent().isValid()) { - startIndex = startIndex.parent().child(startIndex.row(), KDirModel::Name); - } else { - startIndex = model()->index(startIndex.row(), KDirModel::Name); - } - if (!startIndex.isValid()) { - selectionModel()->select(m_band.originalSelection, QItemSelectionModel::ClearAndSelect); - m_band.ignoreOldInfo = true; - return; - } - - // Go through all indexes between the top and bottom of boundingRect, and - // update the selection. - const int verticalCutoff = boundingRect.bottom(); - QModelIndex currIndex = startIndex; - QModelIndex lastIndex; - bool allItemsInBoundDone = false; - - // Calling selectionModel()->select(...) for each item that needs to be - // toggled is slow as each call emits selectionChanged(...) so store them - // and do the selection toggle in one batch. - QItemSelection itemsToToggle; - // QItemSelection's deal with continuous ranges of indexes better than - // single indexes, so try to portion items that need to be toggled into ranges. - bool formingToggleIndexRange = false; - QModelIndex toggleIndexRangeBegin = QModelIndex(); - - do { - QRect currIndexRect = visualRect(currIndex); - - // Update some optimization info as we go. - const int cr = currIndexRect.right(); - const int cl = currIndexRect.left(); - const int sl = selRect.left(); - const int sr = selRect.right(); - // "The right edge of the name is outside of the rect but nearer than m_outsideNearestLeft", etc - if ((cr < sl && cr > m_band.outsideNearestLeftEdge)) { - m_band.outsideNearestLeftEdge = cr; - } - if ((cl > sr && cl < m_band.outsideNearestRightEdge)) { - m_band.outsideNearestRightEdge = cl; - } - if ((cl >= sl && cl <= sr && cl > m_band.insideNearestRightEdge)) { - m_band.insideNearestRightEdge = cl; - } - if ((cr >= sl && cr <= sr && cr < m_band.insideNearestLeftEdge)) { - m_band.insideNearestLeftEdge = cr; - } - - bool currentlySelected = selectionModel()->isSelected(currIndex); - bool originallySelected = m_band.originalSelection.contains(currIndex); - bool intersectsSelectedRect = currIndexRect.intersects(selRect); - bool shouldBeSelected = (intersectsSelectedRect && !originallySelected) || (!intersectsSelectedRect && originallySelected); - bool needToToggleItem = (currentlySelected && !shouldBeSelected) || (!currentlySelected && shouldBeSelected); - if (needToToggleItem && !formingToggleIndexRange) { - toggleIndexRangeBegin = currIndex; - formingToggleIndexRange = true; - } - - // NOTE: indexBelow actually walks up and down expanded trees for us. - QModelIndex nextIndex = indexBelow(currIndex); - allItemsInBoundDone = !nextIndex.isValid() || currIndexRect.top() > verticalCutoff; - - const bool commitToggleIndexRange = formingToggleIndexRange && - (!needToToggleItem || - allItemsInBoundDone || - currIndex.parent() != toggleIndexRangeBegin.parent()); - if (commitToggleIndexRange) { - formingToggleIndexRange = false; - // If this is the last item in the bounds and it is also the beginning of a range, - // don't toggle lastIndex - it will already have been dealt with. - if (!allItemsInBoundDone || toggleIndexRangeBegin != currIndex) { - itemsToToggle.select(toggleIndexRangeBegin, lastIndex); - } - // Need to start a new range immediately with currIndex? - if (needToToggleItem) { - toggleIndexRangeBegin = currIndex; - formingToggleIndexRange = true; - } - if (allItemsInBoundDone && needToToggleItem) { - // Toggle the very last item in the bounds. - itemsToToggle.select(currIndex, currIndex); - } - } - - // next item - lastIndex = currIndex; - currIndex = nextIndex; - } while (!allItemsInBoundDone); - - - selectionModel()->select(itemsToToggle, QItemSelectionModel::Toggle); - - m_band.lastSelectionOrigin = m_band.origin; - m_band.lastSelectionDestination = m_band.destination; - m_band.ignoreOldInfo = false; -} - -void DolphinDetailsView::setFoldersExpandable(bool expandable) -{ - if (!expandable) { - // collapse all expanded folders, as QTreeView::setItemsExpandable(false) - // does not do this task - const int rowCount = model()->rowCount(); - for (int row = 0; row < rowCount; ++row) { - setExpanded(model()->index(row, 0), false); - } - } - DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings(); - settings->setExpandableFolders(expandable); - setRootIsDecorated(expandable); - setItemsExpandable(expandable); - - // The width of the space which is available for editing has changed - // because of the (dis)appearance of the expanding toggles - adjustMaximumSizeForEditing(currentIndex()); -} - -void DolphinDetailsView::slotExpanded(const QModelIndex& index) -{ - KFileItem item = m_dolphinViewController->itemForIndex(index); - if (!item.isNull()) { - m_expandedUrls.insert(item.url()); - } -} - -void DolphinDetailsView::slotCollapsed(const QModelIndex& index) -{ - KFileItem item = m_dolphinViewController->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(); - const int iconSize = showPreview ? settings->previewSize() : settings->iconSize(); - setIconSize(QSize(iconSize, iconSize)); - m_decorationSize = QSize(iconSize, iconSize); - - doItemsLayout(); -} - -KFileItemDelegate::Information DolphinDetailsView::infoForColumn(int columnIndex) const -{ - return AdditionalInfoAccessor::instance().keyForColumn(columnIndex); -} - -void DolphinDetailsView::resizeColumns() -{ - // Using the resize mode QHeaderView::ResizeToContents is too slow (it takes - // around 3 seconds for each (!) resize operation when having > 10000 items). - // This gets a problem especially when opening large directories, where several - // resize operations are received for showing the currently available items during - // loading (the application hangs around 20 seconds when loading > 10000 items). - - QHeaderView* headerView = header(); - QFontMetrics fontMetrics(viewport()->font()); - - // Calculate the required with for each column and store it in columnWidth[] - int columnWidth[DolphinModel::ExtraColumnCount]; - const int defaultWidth = fontMetrics.width("xxxxxxxxxx"); - - for (int i = 0; i < DolphinModel::ExtraColumnCount; ++i) { - const int logicalIndex = headerView->logicalIndex(i); - const QString headline = model()->headerData(logicalIndex, Qt::Horizontal).toString(); - const int headlineWidth = fontMetrics.width(headline); - - columnWidth[i] = qMax(defaultWidth, headlineWidth); - } - - const int defaultSizeWidth = fontMetrics.width("00000 Items"); - if (defaultSizeWidth > columnWidth[DolphinModel::Size]) { - columnWidth[DolphinModel::Size] = defaultSizeWidth; - } - - const int defaultTimeWidth = fontMetrics.width("0000-00-00 00:00"); - if (defaultTimeWidth > columnWidth[DolphinModel::ModifiedTime]) { - columnWidth[DolphinModel::ModifiedTime] = defaultTimeWidth; - } - - int requiredWidth = 0; - for (int i = KDirModel::Size; i < DolphinModel::ExtraColumnCount; ++i) { - if (!isColumnHidden(i)) { - columnWidth[i] += 20; // provide a default gap - requiredWidth += columnWidth[i]; - headerView->resizeSection(i, columnWidth[i]); - } - } - - // Resize the name column in a way that the whole available width is used - columnWidth[KDirModel::Name] = viewport()->width() - requiredWidth; - - const int minNameWidth = 300; - if (columnWidth[KDirModel::Name] < minNameWidth) { - columnWidth[KDirModel::Name] = minNameWidth; - - // It might be possible that the name column width can be - // decreased without clipping any text. For performance - // reasons the exact necessary width for full visible names is - // only checked for up to 200 items: - const int rowCount = model()->rowCount(); - if (rowCount > 0 && rowCount < 200) { - const int nameWidth = sizeHintForColumn(DolphinModel::Name); - if (nameWidth + requiredWidth <= viewport()->width()) { - columnWidth[KDirModel::Name] = viewport()->width() - requiredWidth; - } else if (nameWidth < minNameWidth) { - columnWidth[KDirModel::Name] = nameWidth; - } - } - } - - headerView->resizeSection(KDirModel::Name, columnWidth[KDirModel::Name]); -} - -bool DolphinDetailsView::isAboveExpandingToggle(const QPoint& pos) const -{ - // QTreeView offers no public API to get the information whether an index has an - // expanding toggle and what boundaries the toggle has. The following approach - // also assumes a toggle for file items. - if (itemsExpandable()) { - const QModelIndex index = QTreeView::indexAt(pos); - if (index.isValid() && (index.column() == KDirModel::Name)) { - QRect rect = visualRect(index); - const int toggleSize = rect.height(); - if (isRightToLeft()) { - rect.moveRight(rect.right()); - } else { - rect.moveLeft(rect.x() - toggleSize); - } - rect.setWidth(toggleSize); - - QStyleOption opt; - opt.initFrom(this); - opt.rect = rect; - rect = style()->subElementRect(QStyle::SE_TreeViewDisclosureItem, &opt, this); - - return rect.contains(pos); - } - } - return false; -} - -void DolphinDetailsView::adjustMaximumSizeForEditing(const QModelIndex& index) -{ - // Make sure that the full width of the "Name" column is available for "Rename Inline" - m_extensionsFactory->fileItemDelegate()->setMaximumSize(QTreeView::visualRect(index).size()); -} - -DolphinDetailsView::ElasticBand::ElasticBand() : - show(false), - origin(), - destination(), - lastSelectionOrigin(), - lastSelectionDestination(), - ignoreOldInfo(true), - outsideNearestLeftEdge(0), - outsideNearestRightEdge(0), - insideNearestLeftEdge(0), - insideNearestRightEdge(0) -{ -} - -#include "dolphindetailsview.moc" diff --git a/src/dolphindetailsview.h b/src/dolphindetailsview.h deleted file mode 100644 index 1dff8fe59..000000000 --- a/src/dolphindetailsview.h +++ /dev/null @@ -1,287 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2006 by Peter Penz (peter.penz@gmx.at) * - * Copyright (C) 2008 by Simon St. James (kdedevel@etotheipiplusone.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 DOLPHINDETAILSVIEW_H -#define DOLPHINDETAILSVIEW_H - -#include -#include -#include - -class DolphinViewController; -class DolphinSortFilterProxyModel; -class ViewExtensionsFactory; - -/** - * @brief Represents the details view which shows the name, size, - * date, permissions, owner and group of an item. - * - * The width of the columns is automatically adjusted in a way - * that full available width of the view is used by stretching the width - * of the name column. - */ -class LIBDOLPHINPRIVATE_EXPORT DolphinDetailsView : public QTreeView -{ - Q_OBJECT - -public: - /** - * @param parent Parent widget. - * @param dolphinViewController Allows the DolphinDetailsView to control the - * DolphinView in a limited way. - * @param viewModeController Controller that is used by the DolphinView - * to control the DolphinDetailsView. The DolphinDetailsView - * only has read access to the controller. - * @param model Directory that is shown. - */ - explicit DolphinDetailsView(QWidget* parent, - DolphinViewController* dolphinViewController, - const ViewModeController* viewModeController, - DolphinSortFilterProxyModel* model); - virtual ~DolphinDetailsView(); - - /** - * Returns a set containing the URLs of all expanded items. - */ - QSet expandedUrls() const; - - virtual QRegion visualRegionForSelection(const QItemSelection& selection) const; - -protected: - virtual bool event(QEvent* event); - virtual QStyleOptionViewItem viewOptions() const; - virtual void contextMenuEvent(QContextMenuEvent* event); - virtual void mousePressEvent(QMouseEvent* event); - virtual void mouseMoveEvent(QMouseEvent* event); - virtual void mouseReleaseEvent(QMouseEvent* event); - virtual void startDrag(Qt::DropActions supportedActions); - virtual void dragEnterEvent(QDragEnterEvent* event); - virtual void dragLeaveEvent(QDragLeaveEvent* event); - virtual void dragMoveEvent(QDragMoveEvent* event); - virtual void dropEvent(QDropEvent* event); - virtual void paintEvent(QPaintEvent* event); - virtual void keyPressEvent(QKeyEvent* event); - virtual void keyReleaseEvent(QKeyEvent* event); - virtual void resizeEvent(QResizeEvent* event); - virtual void wheelEvent(QWheelEvent* event); - virtual void currentChanged(const QModelIndex& current, const QModelIndex& previous); - virtual bool eventFilter(QObject* watched, QEvent* event); - virtual QModelIndex indexAt (const QPoint& point) const; - virtual QRect visualRect(const QModelIndex& index) const; - virtual void setSelection(const QRect& rect, QItemSelectionModel::SelectionFlags command); - virtual void scrollTo(const QModelIndex& index, ScrollHint hint = EnsureVisible); - -private slots: - /** - * Sets the sort indicator section of the header view - * corresponding to \a sorting. - */ - void setSortIndicatorSection(DolphinView::Sorting sorting); - - /** - * Sets the sort indicator order of the header view - * corresponding to \a sortOrder. - */ - void setSortIndicatorOrder(Qt::SortOrder sortOrder); - - /** - * Synchronizes the sorting state of the Dolphin menu 'View -> Sort' - * with the current state of the details view. - * @param column Index of the current sorting column. - */ - void synchronizeSortingState(int column); - - /** - * Is invoked when the mouse cursor has entered an item. The controller - * gets informed to emit the itemEntered() signal if the mouse cursor - * is above the name column. Otherwise the controller gets informed - * to emit the itemViewportEntered() signal (all other columns should - * behave as viewport area). - */ - void slotEntered(const QModelIndex& index); - - /** - * Updates the destination \a destination from - * the elastic band to the current mouse position and triggers - * an update. - */ - void updateElasticBand(); - - /** - * Returns the rectangle for the elastic band dependent from the - * origin \a origin, the current destination - * \a destination and the viewport position. - */ - QRect elasticBandRect() const; - - void setZoomLevel(int level); - - void slotShowPreviewChanged(); - - /** - * Opens a context menu at the position \a pos and allows to - * configure the visibility of the header columns and whether - * expandable folders should be shown. - */ - void configureSettings(const QPoint& pos); - - /** - * Updates the visibilty state of columns and their order. - */ - void updateColumnVisibility(); - - /** - * Saves order of the columns as global setting. - */ - void saveColumnPositions(); - - /** - * Disables the automatical resizing of columns, if the user has resized the columns - * with the mouse. - */ - void slotHeaderSectionResized(int logicalIndex, int oldSize, int newSize); - - /** - * Changes the alternating row colors setting depending from - * the activation state \a active. - */ - void slotActivationChanged(bool active); - - /** - * Disables the automatical resizing of the columns. Per default all columns - * are resized to use the maximum available width of the view as good as possible. - */ - void disableAutoResizing(); - - void requestActivation(); - - void slotGlobalSettingsChanged(int category); - - /** - * If the elastic band is currently shown, update the elastic band based on - * the current mouse position and ensure that the selection is the set of items - * intersecting it. - */ - void updateElasticBandSelection(); - - /** - * If \a expandable is true, the details view acts as tree view. - * The current expandable state is remembered in the settings. - */ - 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 - * will get informed about possible zoom in/zoom out - * operations. - */ - void updateDecorationSize(bool showPreview); - - KFileItemDelegate::Information infoForColumn(int columnIndex) const; - - /** - * Resizes all columns in a way to use the whole available width of the view. - */ - void resizeColumns(); - - /** - * Returns true, if \a pos is within the expanding toggle of a tree. - */ - bool isAboveExpandingToggle(const QPoint& pos) const; - - /** - * Sets the maximum size available for editing in the delegate. - */ - void adjustMaximumSizeForEditing(const QModelIndex& index); - -private: - bool m_autoResize : 1; // if true, the columns are resized automatically to the available width - bool m_expandingTogglePressed : 1; - bool m_keyPressed : 1; // true if a key is pressed currently; info used by currentChanged() - bool m_useDefaultIndexAt : 1; // true, if QTreeView::indexAt() should be used - bool m_ignoreScrollTo : 1; // true if calls to scrollTo(...) should do nothing. - - DolphinViewController* m_dolphinViewController; - const ViewModeController* m_viewModeController; - ViewExtensionsFactory* m_extensionsFactory; - QAction* m_expandableFoldersAction; - - // A set containing the URLs of all currently expanded folders. - // We cannot use a QSet because a QModelIndex is not guaranteed to remain valid over time. - // Also a QSet 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 m_expandedUrls; - - QFont m_font; - QSize m_decorationSize; - - QRect m_dropRect; - - struct ElasticBand - { - ElasticBand(); - - // Elastic band origin and destination coordinates are relative to t - // he origin of the view, not the viewport. - bool show; - QPoint origin; - QPoint destination; - - // Optimization mechanisms for use with elastic band selection. - // Basically, allow "incremental" updates to the selection based - // on the last elastic band shape. - QPoint lastSelectionOrigin; - QPoint lastSelectionDestination; - - // If true, compute the set of selected elements from scratch (slower) - bool ignoreOldInfo; - - // Edges of the filenames that are closest to the edges of oldSelectionRect. - // Used to decide whether horizontal changes in the elastic band are likely - // to require us to re-check which items are selected. - int outsideNearestLeftEdge; - int outsideNearestRightEdge; - int insideNearestLeftEdge; - int insideNearestRightEdge; - // The set of items that were selected at the time this band was shown. - // NOTE: Unless CTRL was pressed when the band was created, this is always empty. - QItemSelection originalSelection; - } m_band; -}; - -#endif diff --git a/src/dolphindetailsviewexpander.cpp b/src/dolphindetailsviewexpander.cpp deleted file mode 100644 index 0f3d3fde1..000000000 --- a/src/dolphindetailsviewexpander.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/*************************************************************************** - * 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 -#include - -DolphinDetailsViewExpander::DolphinDetailsViewExpander(DolphinDetailsView* parent, - const QSet& urlsToExpand) : - QObject(parent), - m_detailsView(parent), - m_dirLister(0), - m_dolphinModel(0), - m_proxyModel(0) -{ - Q_ASSERT(parent != 0); - - m_proxyModel = qobject_cast(parent->model()); - Q_ASSERT(m_proxyModel != 0); - - m_dolphinModel = qobject_cast(m_proxyModel->sourceModel()); - Q_ASSERT(m_dolphinModel != 0); - - m_dirLister = m_dolphinModel->dirLister(); - Q_ASSERT(m_dirLister != 0); - - // 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())); -} - -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); - } - else { - emit completed(); - stop(); - } -} diff --git a/src/dolphindetailsviewexpander.h b/src/dolphindetailsviewexpander.h deleted file mode 100644 index b4dc2fc72..000000000 --- a/src/dolphindetailsviewexpander.h +++ /dev/null @@ -1,77 +0,0 @@ -/*************************************************************************** - * 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 -#include -#include - -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& 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 m_urlsToExpand; - - DolphinDetailsView* m_detailsView; - const KDirLister* m_dirLister; - const DolphinModel* m_dolphinModel; - const DolphinSortFilterProxyModel* m_proxyModel; -}; - -#endif diff --git a/src/dolphinfileitemdelegate.cpp b/src/dolphinfileitemdelegate.cpp deleted file mode 100644 index 17447d8cb..000000000 --- a/src/dolphinfileitemdelegate.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Peter Penz * - * * - * 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 "dolphinfileitemdelegate.h" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -DolphinFileItemDelegate::DolphinFileItemDelegate(QObject* parent) : - KFileItemDelegate(parent), - m_hasMinimizedNameColumn(false), - m_cachedSize(), - m_cachedEmblems() -{ - setJobTransfersVisible(true); -} - -DolphinFileItemDelegate::~DolphinFileItemDelegate() -{ -} - -void DolphinFileItemDelegate::paint(QPainter* painter, - const QStyleOptionViewItem& option, - const QModelIndex& index) const -{ - const QAbstractProxyModel* proxyModel = static_cast(index.model()); - const DolphinModel* dolphinModel = static_cast(proxyModel->sourceModel()); - const bool isNameColumn = (index.column() == KDirModel::Name); - - QStyleOptionViewItemV4 opt(option); - if (m_hasMinimizedNameColumn && isNameColumn) { - adjustOptionWidth(opt, proxyModel, dolphinModel, index); - } - - if (dolphinModel->hasVersionData() && isNameColumn) { - // The currently shown items are under revision control. Show the current revision - // state by adding an emblem and changing the text tintColor. - const QModelIndex dirIndex = proxyModel->mapToSource(index); - const QModelIndex revisionIndex = dolphinModel->index(dirIndex.row(), DolphinModel::Version, dirIndex.parent()); - const QVariant data = dolphinModel->data(revisionIndex, Qt::DecorationRole); - const KVersionControlPlugin::VersionState state = static_cast(data.toInt()); - - adjustOptionTextColor(opt, state); - - KFileItemDelegate::paint(painter, opt, index); - - if (state != KVersionControlPlugin::UnversionedVersion) { - const QRect rect = iconRect(option, index); - const QPixmap emblem = emblemForState(state, rect.size()); - painter->drawPixmap(rect.x(), rect.y() + rect.height() - emblem.height(), emblem); - } - } else { - KFileItemDelegate::paint(painter, opt, index); - } -} - -int DolphinFileItemDelegate::nameColumnWidth(const QString& name, const QStyleOptionViewItem& option) -{ - QFontMetrics fontMetrics(option.font); - int width = option.decorationSize.width() + fontMetrics.width(name) + 16; - - const int defaultWidth = option.rect.width(); - if ((defaultWidth > 0) && (defaultWidth < width)) { - width = defaultWidth; - } - return width; -} - -void DolphinFileItemDelegate::adjustOptionWidth(QStyleOptionViewItemV4& option, - const QAbstractProxyModel* proxyModel, - const DolphinModel* dolphinModel, - const QModelIndex& index) -{ - const QModelIndex dirIndex = proxyModel->mapToSource(index); - const KFileItem item = dolphinModel->itemForIndex(dirIndex); - if (!item.isNull()) { - // symbolic links are displayed in an italic font - if (item.isLink()) { - option.font.setItalic(true); - } - - const int width = nameColumnWidth(item.text(), option); - option.rect.setWidth(width); - } -} - -void DolphinFileItemDelegate::adjustOptionTextColor(QStyleOptionViewItemV4& option, - KVersionControlPlugin::VersionState state) -{ - QColor tintColor; - - // Using hardcoded colors is generally a bad idea. In this case the colors just act - // as tint colors and are mixed with the current set text color. The tint colors - // have been optimized for the base colors of the corresponding Oxygen emblems. - switch (state) { - case KVersionControlPlugin::UpdateRequiredVersion: tintColor = Qt::yellow; break; - case KVersionControlPlugin::LocallyModifiedVersion: tintColor = Qt::green; break; - case KVersionControlPlugin::AddedVersion: tintColor = Qt::darkGreen; break; - case KVersionControlPlugin::RemovedVersion: tintColor = Qt::darkRed; break; - case KVersionControlPlugin::ConflictingVersion: tintColor = Qt::red; break; - case KVersionControlPlugin::UnversionedVersion: - case KVersionControlPlugin::NormalVersion: - default: - // use the default text color - return; - } - - QPalette palette = option.palette; - const QColor textColor = palette.color(QPalette::Text); - tintColor = QColor((tintColor.red() + textColor.red()) / 2, - (tintColor.green() + textColor.green()) / 2, - (tintColor.blue() + textColor.blue()) / 2, - (tintColor.alpha() + textColor.alpha()) / 2); - palette.setColor(QPalette::Text, tintColor); - option.palette = palette; -} - -QPixmap DolphinFileItemDelegate::emblemForState(KVersionControlPlugin::VersionState state, const QSize& size) const -{ - Q_ASSERT(state <= KVersionControlPlugin::ConflictingVersion); - if (m_cachedSize != size) { - m_cachedSize = size; - - const int iconHeight = size.height(); - int emblemHeight = KIconLoader::SizeSmall; - if (iconHeight >= KIconLoader::SizeEnormous) { - emblemHeight = KIconLoader::SizeMedium; - } else if (iconHeight >= KIconLoader::SizeLarge) { - emblemHeight = KIconLoader::SizeSmallMedium; - } else if (iconHeight >= KIconLoader::SizeMedium) { - emblemHeight = KIconLoader::SizeSmall; - } else { - emblemHeight = KIconLoader::SizeSmall / 2; - } - - const QSize emblemSize(emblemHeight, emblemHeight); - for (int i = KVersionControlPlugin::NormalVersion; i <= KVersionControlPlugin::ConflictingVersion; ++i) { - QString iconName; - switch (i) { - case KVersionControlPlugin::NormalVersion: iconName = "vcs-normal"; break; - case KVersionControlPlugin::UpdateRequiredVersion: iconName = "vcs-update-required"; break; - case KVersionControlPlugin::LocallyModifiedVersion: iconName = "vcs-locally-modified"; break; - case KVersionControlPlugin::AddedVersion: iconName = "vcs-added"; break; - case KVersionControlPlugin::RemovedVersion: iconName = "vcs-removed"; break; - case KVersionControlPlugin::ConflictingVersion: iconName = "vcs-conflicting"; break; - case KVersionControlPlugin::UnversionedVersion: - default: Q_ASSERT(false); break; - } - - m_cachedEmblems[i] = KIcon(iconName).pixmap(emblemSize); - } - } - return m_cachedEmblems[state]; -} - diff --git a/src/dolphinfileitemdelegate.h b/src/dolphinfileitemdelegate.h deleted file mode 100644 index 405f24916..000000000 --- a/src/dolphinfileitemdelegate.h +++ /dev/null @@ -1,90 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Peter Penz * - * * - * 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 DOLPHINFILEITEMDELEGATE_H -#define DOLPHINFILEITEMDELEGATE_H - -#include -#include - -class QAbstractProxyModel; - -/** - * Extends KFileItemDelegate by the ability to show the hover effect - * and the selection in a minimized way for the name column of - * the details view. - * - * Note that this is a workaround, as Qt does not support having custom - * shapes within the visual rect of an item view. The visual part of - * workaround is handled inside DolphinFileItemDelegate, the behavior - * changes are handled in DolphinDetailsView. - */ -class DolphinFileItemDelegate : public KFileItemDelegate -{ -public: - explicit DolphinFileItemDelegate(QObject* parent = 0); - virtual ~DolphinFileItemDelegate(); - - /** - * If \a minimized is true, the hover effect and the selection are - * only drawn above the icon and text of an item. Per default - * \a minimized is false, which means that the whole visual rect is - * used like in KFileItemDelegate. - */ - void setMinimizedNameColumn(bool minimized); - bool hasMinimizedNameColumn() const; - - virtual void paint(QPainter* painter, - const QStyleOptionViewItem& option, - const QModelIndex& index) const; - - /** - * Returns the minimized width of the name column for the name \a name. This method - * is also used in DolphinDetailsView to handle the selection of items correctly. - */ - static int nameColumnWidth(const QString& name, const QStyleOptionViewItem& option); - -private: - static void adjustOptionWidth(QStyleOptionViewItemV4& option, - const QAbstractProxyModel* proxyModel, - const DolphinModel* dolphinModel, - const QModelIndex& index); - - static void adjustOptionTextColor(QStyleOptionViewItemV4& option, - KVersionControlPlugin::VersionState state); - - QPixmap emblemForState(KVersionControlPlugin::VersionState state, const QSize& size) const; - -private: - bool m_hasMinimizedNameColumn; - mutable QSize m_cachedSize; - mutable QPixmap m_cachedEmblems[KVersionControlPlugin::ConflictingVersion + 1]; -}; - -inline void DolphinFileItemDelegate::setMinimizedNameColumn(bool minimized) -{ - m_hasMinimizedNameColumn = minimized; -} - -inline bool DolphinFileItemDelegate::hasMinimizedNameColumn() const -{ - return m_hasMinimizedNameColumn; -} - -#endif diff --git a/src/dolphiniconsview.cpp b/src/dolphiniconsview.cpp deleted file mode 100644 index 636bdd66c..000000000 --- a/src/dolphiniconsview.cpp +++ /dev/null @@ -1,532 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2006-2009 by Peter Penz * - * * - * 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 "dolphiniconsview.h" - -#include "dolphincategorydrawer.h" -#include "dolphinviewcontroller.h" -#include "settings/dolphinsettings.h" -#include "dolphinsortfilterproxymodel.h" -#include "dolphin_iconsmodesettings.h" -#include "dolphin_generalsettings.h" -#include "draganddrophelper.h" -#include "selectionmanager.h" -#include "viewextensionsfactory.h" -#include "viewmodecontroller.h" -#include "zoomlevelinfo.h" - -#include -#include -#include - -#include -#include -#include - -DolphinIconsView::DolphinIconsView(QWidget* parent, - DolphinViewController* dolphinViewController, - const ViewModeController* viewModeController, - DolphinSortFilterProxyModel* proxyModel) : - KCategorizedView(parent), - m_dolphinViewController(dolphinViewController), - m_viewModeController(viewModeController), - m_categoryDrawer(new DolphinCategoryDrawer(this)), - m_extensionsFactory(0), - m_font(), - m_decorationSize(), - m_decorationPosition(QStyleOptionViewItem::Top), - m_displayAlignment(Qt::AlignHCenter), - m_itemSize(), - m_dropRect() -{ - Q_ASSERT(dolphinViewController != 0); - Q_ASSERT(viewModeController != 0); - - setModel(proxyModel); - setLayoutDirection(Qt::LeftToRight); - setViewMode(QListView::IconMode); - setResizeMode(QListView::Adjust); - setMovement(QListView::Static); - setDragEnabled(true); - setEditTriggers(QAbstractItemView::NoEditTriggers); - viewport()->setAcceptDrops(true); - - setMouseTracking(true); - - connect(this, SIGNAL(clicked(const QModelIndex&)), - dolphinViewController, SLOT(requestTab(const QModelIndex&))); - if (KGlobalSettings::singleClick()) { - connect(this, SIGNAL(clicked(const QModelIndex&)), - dolphinViewController, SLOT(triggerItem(const QModelIndex&))); - } else { - connect(this, SIGNAL(doubleClicked(const QModelIndex&)), - dolphinViewController, SLOT(triggerItem(const QModelIndex&))); - } - - connect(this, SIGNAL(entered(const QModelIndex&)), - dolphinViewController, SLOT(emitItemEntered(const QModelIndex&))); - connect(this, SIGNAL(viewportEntered()), - dolphinViewController, SLOT(emitViewportEntered())); - connect(viewModeController, SIGNAL(zoomLevelChanged(int)), - this, SLOT(setZoomLevel(int))); - - const DolphinView* view = dolphinViewController->view(); - connect(view, SIGNAL(showPreviewChanged()), - this, SLOT(slotShowPreviewChanged())); - connect(view, SIGNAL(additionalInfoChanged()), - this, SLOT(slotAdditionalInfoChanged())); - - // apply the icons mode settings to the widget - const IconsModeSettings* settings = DolphinSettings::instance().iconsModeSettings(); - Q_ASSERT(settings != 0); - - if (settings->useSystemFont()) { - m_font = KGlobalSettings::generalFont(); - } else { - m_font = QFont(settings->fontFamily(), - qRound(settings->fontSize()), - settings->fontWeight(), - settings->italicFont()); - m_font.setPointSizeF(settings->fontSize()); - } - - setWordWrap(settings->numberOfTextlines() > 1); - - if (settings->arrangement() == QListView::TopToBottom) { - setFlow(QListView::LeftToRight); - m_decorationPosition = QStyleOptionViewItem::Top; - m_displayAlignment = Qt::AlignHCenter; - } else { - setFlow(QListView::TopToBottom); - m_decorationPosition = QStyleOptionViewItem::Left; - m_displayAlignment = Qt::AlignLeft | Qt::AlignVCenter; - } - - connect(m_categoryDrawer, SIGNAL(actionRequested(int,QModelIndex)), this, SLOT(categoryDrawerActionRequested(int,QModelIndex))); - setCategoryDrawer(m_categoryDrawer); - - setFocus(); - - connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)), - this, SLOT(slotGlobalSettingsChanged(int))); - - updateGridSize(view->showPreview(), 0); - m_extensionsFactory = new ViewExtensionsFactory(this, dolphinViewController, viewModeController); -} - -DolphinIconsView::~DolphinIconsView() -{ -} - -void DolphinIconsView::dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight) -{ - KCategorizedView::dataChanged(topLeft, bottomRight); - - KCategorizedSortFilterProxyModel* proxyModel = dynamic_cast(model()); - if (!proxyModel->isCategorizedModel()) { - // bypass a QListView issue that items are not layout correctly if the decoration size of - // an index changes - scheduleDelayedItemsLayout(); - } -} - -QStyleOptionViewItem DolphinIconsView::viewOptions() const -{ - QStyleOptionViewItem viewOptions = KCategorizedView::viewOptions(); - viewOptions.font = m_font; - viewOptions.fontMetrics = QFontMetrics(m_font); - viewOptions.decorationPosition = m_decorationPosition; - viewOptions.decorationSize = m_decorationSize; - viewOptions.displayAlignment = m_displayAlignment; - viewOptions.showDecorationSelected = true; - return viewOptions; -} - -void DolphinIconsView::contextMenuEvent(QContextMenuEvent* event) -{ - KCategorizedView::contextMenuEvent(event); - m_dolphinViewController->triggerContextMenuRequest(event->pos()); -} - -void DolphinIconsView::mousePressEvent(QMouseEvent* event) -{ - m_dolphinViewController->requestActivation(); - const QModelIndex index = indexAt(event->pos()); - if (index.isValid() && (event->button() == Qt::LeftButton)) { - // TODO: It should not be necessary to manually set the dragging state, but I could - // not reproduce this issue with a Qt-only example yet to find the root cause. - // Issue description: start Dolphin, split the view and drag an item from the - // inactive view to the active view by a very fast mouse movement. Result: - // the item gets selected instead of being dragged... - setState(QAbstractItemView::DraggingState); - } - - if (!index.isValid() && (QApplication::mouseButtons() & Qt::MidButton)) { - m_dolphinViewController->replaceUrlByClipboard(); - } - - KCategorizedView::mousePressEvent(event); -} - -void DolphinIconsView::startDrag(Qt::DropActions supportedActions) -{ - DragAndDropHelper::instance().startDrag(this, supportedActions, m_dolphinViewController); -} - -void DolphinIconsView::dragEnterEvent(QDragEnterEvent* event) -{ - if (DragAndDropHelper::instance().isMimeDataSupported(event->mimeData())) { - event->acceptProposedAction(); - } -} - -void DolphinIconsView::dragLeaveEvent(QDragLeaveEvent* event) -{ - KCategorizedView::dragLeaveEvent(event); - setDirtyRegion(m_dropRect); -} - -void DolphinIconsView::dragMoveEvent(QDragMoveEvent* event) -{ - KCategorizedView::dragMoveEvent(event); - - // TODO: remove this code when the issue #160611 is solved in Qt 4.4 - const QModelIndex index = indexAt(event->pos()); - setDirtyRegion(m_dropRect); - - m_dropRect.setSize(QSize()); // set as invalid - if (index.isValid()) { - const KFileItem item = m_dolphinViewController->itemForIndex(index); - if (!item.isNull() && item.isDir()) { - m_dropRect = visualRect(index); - } else { - m_dropRect.setSize(QSize()); // set as invalid - } - } - if (DragAndDropHelper::instance().isMimeDataSupported(event->mimeData())) { - // accept url drops, independently from the destination item - event->acceptProposedAction(); - } - - setDirtyRegion(m_dropRect); -} - -void DolphinIconsView::dropEvent(QDropEvent* event) -{ - const QModelIndex index = indexAt(event->pos()); - const KFileItem item = m_dolphinViewController->itemForIndex(index); - m_dolphinViewController->indicateDroppedUrls(item, m_viewModeController->url(), event); - // don't call KCategorizedView::dropEvent(event), as it moves - // the items which is not wanted -} - -QModelIndex DolphinIconsView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) -{ - const QModelIndex oldCurrent = currentIndex(); - - QModelIndex newCurrent = KCategorizedView::moveCursor(cursorAction, modifiers); - if (newCurrent != oldCurrent) { - return newCurrent; - } - - // The cursor has not been moved by the base implementation. Provide a - // wrap behavior, so that the cursor will go to the next item when reaching - // the border. - const IconsModeSettings* settings = DolphinSettings::instance().iconsModeSettings(); - if (settings->arrangement() == QListView::LeftToRight) { - switch (cursorAction) { - case MoveUp: - if (newCurrent.row() == 0) { - return newCurrent; - } - newCurrent = KCategorizedView::moveCursor(MoveLeft, modifiers); - selectionModel()->setCurrentIndex(newCurrent, QItemSelectionModel::NoUpdate); - newCurrent = KCategorizedView::moveCursor(MovePageDown, modifiers); - break; - - case MoveDown: - if (newCurrent.row() == (model()->rowCount() - 1)) { - return newCurrent; - } - newCurrent = KCategorizedView::moveCursor(MovePageUp, modifiers); - selectionModel()->setCurrentIndex(newCurrent, QItemSelectionModel::NoUpdate); - newCurrent = KCategorizedView::moveCursor(MoveRight, modifiers); - break; - - default: - break; - } - } else { - QModelIndex current = oldCurrent; - switch (cursorAction) { - case MoveLeft: - if (newCurrent.row() == 0) { - return newCurrent; - } - newCurrent = KCategorizedView::moveCursor(MoveUp, modifiers); - do { - selectionModel()->setCurrentIndex(newCurrent, QItemSelectionModel::NoUpdate); - current = newCurrent; - newCurrent = KCategorizedView::moveCursor(MoveRight, modifiers); - } while (newCurrent != current); - break; - - case MoveRight: - if (newCurrent.row() == (model()->rowCount() - 1)) { - return newCurrent; - } - do { - selectionModel()->setCurrentIndex(newCurrent, QItemSelectionModel::NoUpdate); - current = newCurrent; - newCurrent = KCategorizedView::moveCursor(MoveLeft, modifiers); - } while (newCurrent != current); - newCurrent = KCategorizedView::moveCursor(MoveDown, modifiers); - break; - - default: - break; - } - } - - // Revert all changes of the current item to make sure that item selection works correctly - selectionModel()->setCurrentIndex(oldCurrent, QItemSelectionModel::NoUpdate); - return newCurrent; -} - -void DolphinIconsView::keyPressEvent(QKeyEvent* event) -{ - KCategorizedView::keyPressEvent(event); - m_dolphinViewController->handleKeyPressEvent(event); -} - -void DolphinIconsView::wheelEvent(QWheelEvent* event) -{ - horizontalScrollBar()->setSingleStep(m_itemSize.width() / 5); - verticalScrollBar()->setSingleStep(m_itemSize.height() / 5); - - KCategorizedView::wheelEvent(event); - // if the icons are aligned left to right, the vertical wheel event should - // be applied to the horizontal scrollbar - const IconsModeSettings* settings = DolphinSettings::instance().iconsModeSettings(); - const bool scrollHorizontal = (event->orientation() == Qt::Vertical) && - (settings->arrangement() == QListView::LeftToRight); - if (scrollHorizontal) { - QWheelEvent horizEvent(event->pos(), - event->delta(), - event->buttons(), - event->modifiers(), - Qt::Horizontal); - QApplication::sendEvent(horizontalScrollBar(), &horizEvent); - } -} - -void DolphinIconsView::showEvent(QShowEvent* event) -{ - KFileItemDelegate* delegate = dynamic_cast(itemDelegate()); - delegate->setMaximumSize(m_itemSize); - - KCategorizedView::showEvent(event); -} - -void DolphinIconsView::leaveEvent(QEvent* event) -{ - KCategorizedView::leaveEvent(event); - // if the mouse is above an item and moved very fast outside the widget, - // no viewportEntered() signal might be emitted although the mouse has been moved - // above the viewport - m_dolphinViewController->emitViewportEntered(); -} - -void DolphinIconsView::currentChanged(const QModelIndex& current, const QModelIndex& previous) -{ - KCategorizedView::currentChanged(current, previous); - m_extensionsFactory->handleCurrentIndexChange(current, previous); -} - -void DolphinIconsView::resizeEvent(QResizeEvent* event) -{ - KCategorizedView::resizeEvent(event); - const DolphinView* view = m_dolphinViewController->view(); - updateGridSize(view->showPreview(), view->additionalInfo().count()); -} - -void DolphinIconsView::slotShowPreviewChanged() -{ - const DolphinView* view = m_dolphinViewController->view(); - updateGridSize(view->showPreview(), additionalInfoCount()); -} - -void DolphinIconsView::slotAdditionalInfoChanged() -{ - const DolphinView* view = m_dolphinViewController->view(); - const bool showPreview = view->showPreview(); - updateGridSize(showPreview, view->additionalInfo().count()); -} - -void DolphinIconsView::setZoomLevel(int level) -{ - IconsModeSettings* settings = DolphinSettings::instance().iconsModeSettings(); - - const int oldIconSize = settings->iconSize(); - int newIconSize = oldIconSize; - - const bool showPreview = m_dolphinViewController->view()->showPreview(); - if (showPreview) { - const int previewSize = ZoomLevelInfo::iconSizeForZoomLevel(level); - settings->setPreviewSize(previewSize); - } else { - newIconSize = ZoomLevelInfo::iconSizeForZoomLevel(level); - settings->setIconSize(newIconSize); - } - - // increase also the grid size - const int diff = newIconSize - oldIconSize; - settings->setItemWidth(settings->itemWidth() + diff); - settings->setItemHeight(settings->itemHeight() + diff); - - updateGridSize(showPreview, additionalInfoCount()); -} - -void DolphinIconsView::requestActivation() -{ - m_dolphinViewController->requestActivation(); -} - -void DolphinIconsView::slotGlobalSettingsChanged(int category) -{ - Q_UNUSED(category); - - const IconsModeSettings* settings = DolphinSettings::instance().iconsModeSettings(); - Q_ASSERT(settings != 0); - if (settings->useSystemFont()) { - m_font = KGlobalSettings::generalFont(); - } - - disconnect(this, SIGNAL(clicked(QModelIndex)), m_dolphinViewController, SLOT(triggerItem(QModelIndex))); - disconnect(this, SIGNAL(doubleClicked(QModelIndex)), m_dolphinViewController, SLOT(triggerItem(QModelIndex))); - if (KGlobalSettings::singleClick()) { - connect(this, SIGNAL(clicked(QModelIndex)), m_dolphinViewController, SLOT(triggerItem(QModelIndex))); - } else { - connect(this, SIGNAL(doubleClicked(QModelIndex)), m_dolphinViewController, SLOT(triggerItem(QModelIndex))); - } -} - -void DolphinIconsView::categoryDrawerActionRequested(int action, const QModelIndex &index) -{ - const QSortFilterProxyModel *model = dynamic_cast(index.model()); - const QModelIndex topLeft = model->index(index.row(), modelColumn()); - QModelIndex bottomRight = topLeft; - const QString category = model->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); - QModelIndex current = topLeft; - while (true) { - current = model->index(current.row() + 1, modelColumn()); - const QString curCategory = model->data(model->index(current.row(), index.column()), KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); - if (!current.isValid() || category != curCategory) { - break; - } - bottomRight = current; - } - switch (action) { - case DolphinCategoryDrawer::SelectAll: - selectionModel()->select(QItemSelection(topLeft, bottomRight), QItemSelectionModel::Select); - break; - case DolphinCategoryDrawer::UnselectAll: - selectionModel()->select(QItemSelection(topLeft, bottomRight), QItemSelectionModel::Deselect); - break; - default: - break; - } -} - -void DolphinIconsView::updateGridSize(bool showPreview, int additionalInfoCount) -{ - const IconsModeSettings* settings = DolphinSettings::instance().iconsModeSettings(); - Q_ASSERT(settings != 0); - - int itemWidth = settings->itemWidth(); - int itemHeight = settings->itemHeight(); - int size = settings->iconSize(); - - if (showPreview) { - const int previewSize = settings->previewSize(); - const int diff = previewSize - size; - itemWidth += diff; - itemHeight += diff; - - size = previewSize; - } - - Q_ASSERT(additionalInfoCount >= 0); - itemHeight += additionalInfoCount * QFontMetrics(m_font).height(); - - // Optimize the item size of the grid in a way to prevent large gaps on the - // right border (= row arrangement) or the bottom border (= column arrangement). - // There is no public API in QListView to find out the used width of the viewport - // for the layout. The following calculation of 'contentWidth'/'contentHeight' - // is based on QListViewPrivate::prepareItemsLayout() (Copyright (C) 2009 Nokia Corporation). - int frameAroundContents = 0; - if (style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents)) { - frameAroundContents = style()->pixelMetric(QStyle::PM_DefaultFrameWidth) * 2; - } - const int spacing = settings->gridSpacing(); - if (settings->arrangement() == QListView::TopToBottom) { - const int contentWidth = viewport()->width() - 1 - - frameAroundContents - - style()->pixelMetric(QStyle::PM_ScrollBarExtent, 0, horizontalScrollBar()); - const int gridWidth = itemWidth + spacing * 2; - const int horizItemCount = contentWidth / gridWidth; - if (horizItemCount > 0) { - itemWidth += (contentWidth - horizItemCount * gridWidth) / horizItemCount; - } - - // The decoration width indirectly defines the maximum - // width for the text wrapping. To use the maximum item width - // for text wrapping, it is used as decoration width. - m_decorationSize = QSize(itemWidth, size); - setIconSize(QSize(itemWidth, size)); - } else { - const int contentHeight = viewport()->height() - 1 - - frameAroundContents - - style()->pixelMetric(QStyle::PM_ScrollBarExtent, 0, verticalScrollBar()); - const int gridHeight = itemHeight + spacing; - const int vertItemCount = contentHeight / gridHeight; - if (vertItemCount > 0) { - itemHeight += (contentHeight - vertItemCount * gridHeight) / vertItemCount; - } - - m_decorationSize = QSize(size, size); - setIconSize(QSize(size, size)); - } - - m_itemSize = QSize(itemWidth, itemHeight); - setGridSizeOwn(QSize(itemWidth + spacing * 2, itemHeight + spacing)); - - KFileItemDelegate* delegate = dynamic_cast(itemDelegate()); - if (delegate != 0) { - delegate->setMaximumSize(m_itemSize); - } -} - -int DolphinIconsView::additionalInfoCount() const -{ - const DolphinView* view = m_dolphinViewController->view(); - return view->additionalInfo().count(); -} - -#include "dolphiniconsview.moc" diff --git a/src/dolphiniconsview.h b/src/dolphiniconsview.h deleted file mode 100644 index 21e37ba02..000000000 --- a/src/dolphiniconsview.h +++ /dev/null @@ -1,122 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2006-2009 by Peter Penz * - * * - * 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 DOLPHINICONSVIEW_H -#define DOLPHINICONSVIEW_H - -#include - -#include -#include - -#include -#include -#include - -#include - -class DolphinViewController; -class DolphinCategoryDrawer; -class DolphinSortFilterProxyModel; -class ViewExtensionsFactory; -class ViewModeController; - -/** - * @brief Represents the view, where each item is shown as an icon. - * - * It is also possible that instead of the icon a preview of the item - * content is shown. - */ -class LIBDOLPHINPRIVATE_EXPORT DolphinIconsView : public KCategorizedView -{ - Q_OBJECT - -public: - /** - * @param parent Parent widget. - * @param dolphinViewController Allows the DolphinIconsView to control the - * DolphinView in a limited way. - * @param viewModeController Controller that is used by the DolphinView - * to control the DolphinIconsView. The DolphinIconsView - * only has read access to the controller. - * @param model Directory that is shown. - */ - explicit DolphinIconsView(QWidget* parent, - DolphinViewController* dolphinViewController, - const ViewModeController* viewModeController, - DolphinSortFilterProxyModel* proxyModel); - virtual ~DolphinIconsView(); - -protected slots: - virtual void dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight); - -protected: - virtual QStyleOptionViewItem viewOptions() const; - virtual void contextMenuEvent(QContextMenuEvent* event); - virtual void mousePressEvent(QMouseEvent* event); - virtual void startDrag(Qt::DropActions supportedActions); - virtual void dragEnterEvent(QDragEnterEvent* event); - virtual void dragLeaveEvent(QDragLeaveEvent* event); - virtual void dragMoveEvent(QDragMoveEvent* event); - virtual void dropEvent(QDropEvent* event); - virtual QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers); - virtual void keyPressEvent(QKeyEvent* event); - virtual void wheelEvent(QWheelEvent* event); - virtual void showEvent(QShowEvent* event); - virtual void leaveEvent(QEvent* event); - virtual void currentChanged(const QModelIndex& current, const QModelIndex& previous); - virtual void resizeEvent(QResizeEvent* event); - -private slots: - void slotShowPreviewChanged(); - void slotAdditionalInfoChanged(); - void setZoomLevel(int level); - void requestActivation(); - void slotGlobalSettingsChanged(int category); - void categoryDrawerActionRequested(int action, const QModelIndex &index); - -private: - /** - * Updates the size of the grid depending on the state - * of \a showPreview and \a additionalInfoCount. - */ - void updateGridSize(bool showPreview, int additionalInfoCount); - - /** - * Returns the number of additional information lines that should - * be shown below the item name. - */ - int additionalInfoCount() const; - -private: - DolphinViewController* m_dolphinViewController; - const ViewModeController* m_viewModeController; - DolphinCategoryDrawer* m_categoryDrawer; - ViewExtensionsFactory* m_extensionsFactory; - - QFont m_font; - QSize m_decorationSize; - QStyleOptionViewItem::Position m_decorationPosition; - Qt::Alignment m_displayAlignment; - - QSize m_itemSize; - QRect m_dropRect; -}; - -#endif diff --git a/src/dolphinmainwindow.h b/src/dolphinmainwindow.h index dfc171cf9..4d993865f 100644 --- a/src/dolphinmainwindow.h +++ b/src/dolphinmainwindow.h @@ -22,7 +22,6 @@ #ifndef DOLPHIN_MAINWINDOW_H #define DOLPHIN_MAINWINDOW_H -#include "dolphinview.h" #include "panels/panel.h" #include @@ -33,7 +32,9 @@ #include #include -#include +#include "views/dolphinview.h" + +#include typedef KIO::FileUndoManager::CommandType CommandType; diff --git a/src/dolphinnewmenu.cpp b/src/dolphinnewmenu.cpp index 234f75f81..5769e28ad 100644 --- a/src/dolphinnewmenu.cpp +++ b/src/dolphinnewmenu.cpp @@ -22,9 +22,9 @@ #include "dolphinmainwindow.h" #include "dolphinnewmenuobserver.h" -#include "dolphinview.h" #include "dolphinviewcontainer.h" #include "statusbar/dolphinstatusbar.h" +#include "views/dolphinview.h" #include #include diff --git a/src/dolphinpart.cpp b/src/dolphinpart.cpp index 2dec262e1..18ace8df5 100644 --- a/src/dolphinpart.cpp +++ b/src/dolphinpart.cpp @@ -20,7 +20,6 @@ #include "dolphinpart.h" #include "dolphinviewactionhandler.h" #include "dolphinsortfilterproxymodel.h" -#include "dolphinview.h" #include "dolphinmodel.h" #include "dolphinnewmenuobserver.h" #include "dolphinremoteencoding.h" @@ -47,6 +46,7 @@ #include #include "settings/dolphinsettings.h" +#include "views/dolphinview.h" #include #include diff --git a/src/dolphinsortfilterproxymodel.h b/src/dolphinsortfilterproxymodel.h index bc101bd8b..3ae8a059c 100644 --- a/src/dolphinsortfilterproxymodel.h +++ b/src/dolphinsortfilterproxymodel.h @@ -20,7 +20,7 @@ #ifndef DOLPHINSORTFILTERPROXYMODEL_H #define DOLPHINSORTFILTERPROXYMODEL_H -#include +#include #include #include diff --git a/src/dolphinview.cpp b/src/dolphinview.cpp deleted file mode 100644 index 73a0c63c3..000000000 --- a/src/dolphinview.cpp +++ /dev/null @@ -1,1569 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2006-2009 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include "additionalinfoaccessor.h" -#include "dolphinmodel.h" -#include "dolphincolumnviewcontainer.h" -#include "dolphinviewcontroller.h" -#include "dolphindetailsview.h" -#include "dolphinfileitemdelegate.h" -#include "dolphinnewmenuobserver.h" -#include "dolphinsortfilterproxymodel.h" -#include "dolphin_detailsmodesettings.h" -#include "dolphiniconsview.h" -#include "dolphin_generalsettings.h" -#include "draganddrophelper.h" -#include "renamedialog.h" -#include "settings/dolphinsettings.h" -#include "viewmodecontroller.h" -#include "viewproperties.h" -#include "zoomlevelinfo.h" -#include "dolphindetailsviewexpander.h" - -/** - * Helper function for sorting items with qSort() in - * DolphinView::renameSelectedItems(). - */ -bool lessThan(const KFileItem& item1, const KFileItem& item2) -{ - return KStringHandler::naturalCompare(item1.name(), item2.name()) < 0; -} - -DolphinView::DolphinView(QWidget* parent, - const KUrl& url, - DolphinSortFilterProxyModel* proxyModel) : - QWidget(parent), - m_active(true), - m_showPreview(false), - m_storedCategorizedSorting(false), - m_tabsForFiles(false), - m_isContextMenuOpen(false), - m_ignoreViewProperties(false), - m_assureVisibleCurrentIndex(false), - m_mode(DolphinView::IconsView), - m_topLayout(0), - m_dolphinViewController(0), - m_viewModeController(0), - m_viewAccessor(proxyModel), - m_selectionModel(0), - m_selectionChangedTimer(0), - m_rootUrl(), - m_activeItemUrl(), - m_restoredContentsPosition(), - m_createdItemUrl(), - m_selectedItems(), - m_newFileNames() -{ - m_topLayout = new QVBoxLayout(this); - m_topLayout->setSpacing(0); - m_topLayout->setMargin(0); - - m_dolphinViewController = new DolphinViewController(this); - - m_viewModeController = new ViewModeController(this); - m_viewModeController->setUrl(url); - - connect(m_viewModeController, SIGNAL(urlChanged(const KUrl&)), - this, SIGNAL(urlChanged(const KUrl&))); - - connect(m_dolphinViewController, SIGNAL(requestContextMenu(const QPoint&, const QList&)), - this, SLOT(openContextMenu(const QPoint&, const QList&))); - connect(m_dolphinViewController, SIGNAL(urlsDropped(const KFileItem&, const KUrl&, QDropEvent*)), - this, SLOT(dropUrls(const KFileItem&, const KUrl&, QDropEvent*))); - connect(m_dolphinViewController, SIGNAL(sortingChanged(DolphinView::Sorting)), - this, SLOT(updateSorting(DolphinView::Sorting))); - connect(m_dolphinViewController, SIGNAL(sortOrderChanged(Qt::SortOrder)), - this, SLOT(updateSortOrder(Qt::SortOrder))); - connect(m_dolphinViewController, SIGNAL(sortFoldersFirstChanged(bool)), - this, SLOT(updateSortFoldersFirst(bool))); - connect(m_dolphinViewController, SIGNAL(additionalInfoChanged(const KFileItemDelegate::InformationList&)), - this, SLOT(updateAdditionalInfo(const KFileItemDelegate::InformationList&))); - connect(m_dolphinViewController, SIGNAL(itemTriggered(const KFileItem&)), - this, SLOT(triggerItem(const KFileItem&))); - connect(m_dolphinViewController, SIGNAL(tabRequested(const KUrl&)), - this, SIGNAL(tabRequested(const KUrl&))); - connect(m_dolphinViewController, SIGNAL(activated()), - this, SLOT(activate())); - connect(m_dolphinViewController, SIGNAL(itemEntered(const KFileItem&)), - this, SLOT(showHoverInformation(const KFileItem&))); - 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())); - - // 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 - // creation is done asynchronously, several signals must be checked: - connect(&DolphinNewMenuObserver::instance(), SIGNAL(itemCreated(const KUrl&)), - this, SLOT(observeCreatedItem(const KUrl&))); - - m_selectionChangedTimer = new QTimer(this); - m_selectionChangedTimer->setSingleShot(true); - m_selectionChangedTimer->setInterval(300); - connect(m_selectionChangedTimer, SIGNAL(timeout()), - this, SLOT(emitSelectionChangedSignal())); - - applyViewProperties(); - m_topLayout->addWidget(m_viewAccessor.layoutTarget()); -} - -DolphinView::~DolphinView() -{ -} - -KUrl DolphinView::url() const -{ - return m_viewModeController->url(); -} - -KUrl DolphinView::rootUrl() const -{ - const KUrl viewUrl = url(); - const KUrl root = m_viewAccessor.rootUrl(); - if (root.isEmpty() || !root.isParentOf(viewUrl)) { - return viewUrl; - } - return root; -} - -void DolphinView::setActive(bool active) -{ - if (active == m_active) { - return; - } - - m_active = active; - - QColor color = KColorScheme(QPalette::Active, KColorScheme::View).background().color(); - if (active) { - emitSelectionChangedSignal(); - } else { - color.setAlpha(150); - } - - QWidget* viewport = m_viewAccessor.itemView()->viewport(); - QPalette palette; - palette.setColor(viewport->backgroundRole(), color); - viewport->setPalette(palette); - - update(); - - if (active) { - m_viewAccessor.itemView()->setFocus(); - emit activated(); - } - - m_viewModeController->indicateActivationChange(active); -} - -bool DolphinView::isActive() const -{ - return m_active; -} - -void DolphinView::setMode(Mode mode) -{ - if (mode == m_mode) { - return; // the wished mode is already set - } - - const int oldZoomLevel = m_viewModeController->zoomLevel(); - m_mode = mode; - - // remember the currently selected items, so that they will - // be restored after reloading the directory - m_selectedItems = selectedItems(); - - deleteView(); - - const KUrl viewPropsUrl = rootUrl(); - ViewProperties props(viewPropsUrl); - props.setViewMode(m_mode); - createView(); - - // the file item delegate has been recreated, apply the current - // additional information manually - const KFileItemDelegate::InformationList infoList = props.additionalInfo(); - m_viewAccessor.itemDelegate()->setShowInformation(infoList); - emit additionalInfoChanged(); - - // Not all view modes support categorized sorting. Adjust the sorting model - // if changing the view mode results in a change of the categorized sorting - // capabilities. - m_storedCategorizedSorting = props.categorizedSorting(); - const bool categorized = m_storedCategorizedSorting && supportsCategorizedSorting(); - if (categorized != m_viewAccessor.proxyModel()->isCategorizedModel()) { - m_viewAccessor.proxyModel()->setCategorizedModel(categorized); - emit categorizedSortingChanged(); - } - - emit modeChanged(); - - updateZoomLevel(oldZoomLevel); - loadDirectory(viewPropsUrl); -} - -DolphinView::Mode DolphinView::mode() const -{ - return m_mode; -} - -bool DolphinView::showPreview() const -{ - return m_showPreview; -} - -bool DolphinView::showHiddenFiles() const -{ - return m_viewAccessor.dirLister()->showingDotFiles(); -} - -bool DolphinView::categorizedSorting() const -{ - // If all view modes would support categorized sorting, returning - // m_viewAccessor.proxyModel()->isCategorizedModel() would be the way to go. As - // currently only the icons view supports caterized sorting, we remember - // the stored view properties state in m_storedCategorizedSorting and - // return this state. The application takes care to disable the corresponding - // checkbox by checking DolphinView::supportsCategorizedSorting() to indicate - // that this setting is not applied to the current view mode. - return m_storedCategorizedSorting; -} - -bool DolphinView::supportsCategorizedSorting() const -{ - return m_viewAccessor.supportsCategorizedSorting(); -} - -bool DolphinView::hasSelection() const -{ - const QAbstractItemView* view = m_viewAccessor.itemView(); - return (view != 0) && view->selectionModel()->hasSelection(); -} - -void DolphinView::markUrlsAsSelected(const QList& urls) -{ - foreach (const KUrl& url, urls) { - KFileItem item(KFileItem::Unknown, KFileItem::Unknown, url); - m_selectedItems.append(item); - } -} - -KFileItemList DolphinView::selectedItems() const -{ - KFileItemList itemList; - const QAbstractItemView* view = m_viewAccessor.itemView(); - if (view == 0) { - return itemList; - } - - const QItemSelection selection = m_viewAccessor.proxyModel()->mapSelectionToSource(view->selectionModel()->selection()); - - const QModelIndexList indexList = selection.indexes(); - foreach (const QModelIndex &index, indexList) { - KFileItem item = m_viewAccessor.dirModel()->itemForIndex(index); - if (!item.isNull()) { - itemList.append(item); - } - } - - return itemList; -} - -KUrl::List DolphinView::selectedUrls() const -{ - KUrl::List urls; - const KFileItemList list = selectedItems(); - foreach (const KFileItem &item, list) { - urls.append(item.url()); - } - return urls; -} - -int DolphinView::selectedItemsCount() const -{ - const QAbstractItemView* view = m_viewAccessor.itemView(); - if (view == 0) { - return 0; - } - - return view->selectionModel()->selectedIndexes().count(); -} - -QItemSelectionModel* DolphinView::selectionModel() const -{ - return m_viewAccessor.itemView()->selectionModel(); -} - -void DolphinView::setZoomLevel(int level) -{ - if (level < ZoomLevelInfo::minimumLevel()) { - level = ZoomLevelInfo::minimumLevel(); - } else if (level > ZoomLevelInfo::maximumLevel()) { - level = ZoomLevelInfo::maximumLevel(); - } - - if (level != zoomLevel()) { - m_viewModeController->setZoomLevel(level); - emit zoomLevelChanged(level); - } -} - -int DolphinView::zoomLevel() const -{ - return m_viewModeController->zoomLevel(); -} - -void DolphinView::setSorting(Sorting sorting) -{ - if (sorting != this->sorting()) { - updateSorting(sorting); - } -} - -DolphinView::Sorting DolphinView::sorting() const -{ - return m_viewAccessor.proxyModel()->sorting(); -} - -void DolphinView::setSortOrder(Qt::SortOrder order) -{ - if (sortOrder() != order) { - updateSortOrder(order); - } -} - -Qt::SortOrder DolphinView::sortOrder() const -{ - return m_viewAccessor.proxyModel()->sortOrder(); -} - -void DolphinView::setSortFoldersFirst(bool foldersFirst) -{ - if (sortFoldersFirst() != foldersFirst) { - updateSortFoldersFirst(foldersFirst); - } -} - -bool DolphinView::sortFoldersFirst() const -{ - return m_viewAccessor.proxyModel()->sortFoldersFirst(); -} - -void DolphinView::setAdditionalInfo(KFileItemDelegate::InformationList info) -{ - const KUrl viewPropsUrl = rootUrl(); - ViewProperties props(viewPropsUrl); - props.setAdditionalInfo(info); - m_viewAccessor.itemDelegate()->setShowInformation(info); - - emit additionalInfoChanged(); - - if (m_viewAccessor.reloadOnAdditionalInfoChange()) { - loadDirectory(viewPropsUrl); - } -} - -KFileItemDelegate::InformationList DolphinView::additionalInfo() const -{ - return m_viewAccessor.itemDelegate()->showInformation(); -} - -void DolphinView::reload() -{ - QByteArray viewState; - QDataStream saveStream(&viewState, QIODevice::WriteOnly); - saveState(saveStream); - m_selectedItems= selectedItems(); - - setUrl(url()); - loadDirectory(url(), true); - - QDataStream restoreStream(viewState); - restoreState(restoreStream); -} - -void DolphinView::refresh() -{ - m_ignoreViewProperties = false; - - const bool oldActivationState = m_active; - const int oldZoomLevel = m_viewModeController->zoomLevel(); - m_active = true; - - createView(); - applyViewProperties(); - reload(); - - setActive(oldActivationState); - updateZoomLevel(oldZoomLevel); -} - -void DolphinView::setNameFilter(const QString& nameFilter) -{ - m_viewModeController->setNameFilter(nameFilter); -} - -void DolphinView::calculateItemCount(int& fileCount, - int& folderCount, - KIO::filesize_t& totalFileSize) const -{ - foreach (const KFileItem& item, m_viewAccessor.dirLister()->items()) { - if (item.isDir()) { - ++folderCount; - } else { - ++fileCount; - totalFileSize += item.size(); - } - } -} - -QString DolphinView::statusBarText() const -{ - QString text; - int folderCount = 0; - int fileCount = 0; - KIO::filesize_t totalFileSize = 0; - - if (hasSelection()) { - // give a summary of the status of the selected files - const KFileItemList list = selectedItems(); - if (list.isEmpty()) { - // when an item is triggered, it is temporary selected but selectedItems() - // will return an empty list - return text; - } - - KFileItemList::const_iterator it = list.begin(); - const KFileItemList::const_iterator end = list.end(); - while (it != end) { - const KFileItem& item = *it; - if (item.isDir()) { - ++folderCount; - } else { - ++fileCount; - totalFileSize += item.size(); - } - ++it; - } - - if (folderCount + fileCount == 1) { - // if only one item is selected, show the filename - const QString name = list.first().text(); - text = (folderCount == 1) ? i18nc("@info:status", "%1 selected", name) : - i18nc("@info:status", "%1 selected (%2)", - name, KIO::convertSize(totalFileSize)); - } else { - // at least 2 items are selected - const QString foldersText = i18ncp("@info:status", "1 Folder selected", "%1 Folders selected", folderCount); - const QString filesText = i18ncp("@info:status", "1 File selected", "%1 Files selected", fileCount); - if ((folderCount > 0) && (fileCount > 0)) { - text = i18nc("@info:status folders, files (size)", "%1, %2 (%3)", - foldersText, filesText, KIO::convertSize(totalFileSize)); - } else if (fileCount > 0) { - text = i18nc("@info:status files (size)", "%1 (%2)", filesText, KIO::convertSize(totalFileSize)); - } else { - Q_ASSERT(folderCount > 0); - text = foldersText; - } - } - } else { - calculateItemCount(fileCount, folderCount, totalFileSize); - text = KIO::itemsSummaryString(fileCount + folderCount, - fileCount, folderCount, - totalFileSize, true); - } - - return text; -} - -QList DolphinView::versionControlActions(const KFileItemList& items) const -{ - return m_dolphinViewController->versionControlActions(items); -} - -void DolphinView::setUrl(const KUrl& url) -{ - if (m_viewModeController->url() != url) { - 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); - } - - // the selection model might have changed in the case of a column view - QItemSelectionModel* selectionModel = m_viewAccessor.itemView()->selectionModel(); - if (m_selectionModel != selectionModel) { - disconnect(m_selectionModel, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), - this, SLOT(slotSelectionChanged(QItemSelection, QItemSelection))); - m_selectionModel = selectionModel; - connect(m_selectionModel, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), - this, SLOT(slotSelectionChanged(QItemSelection, QItemSelection))); - } -} - -void DolphinView::selectAll() -{ - m_viewAccessor.itemView()->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); - - const QItemSelection selection(topLeft, bottomRight); - selectionModel->select(selection, QItemSelectionModel::Toggle); -} - -void DolphinView::clearSelection() -{ - m_viewAccessor.itemView()->clearSelection(); -} - -void DolphinView::renameSelectedItems() -{ - KFileItemList items = selectedItems(); - const int itemCount = items.count(); - if (itemCount < 1) { - return; - } - - if (itemCount > 1) { - // More than one item has been selected for renaming. Open - // a rename dialog and rename all items afterwards. - QPointer dialog = new RenameDialog(this, items); - if (dialog->exec() == QDialog::Rejected) { - delete dialog; - return; - } - - const QString newName = dialog->newName(); - if (newName.isEmpty()) { - emit errorMessage(dialog->errorString()); - delete dialog; - return; - } - delete dialog; - - // the selection would be invalid after renaming the items, so just clear - // it before - clearSelection(); - - // TODO: check how this can be integrated into KIO::FileUndoManager/KonqOperations - // as one operation instead of n rename operations like it is done now... - Q_ASSERT(newName.contains('#')); - - // currently the items are sorted by the selection order, resort - // them by the file name - qSort(items.begin(), items.end(), lessThan); - - // iterate through all selected items and rename them... - int index = 1; - foreach (const KFileItem& item, items) { - const KUrl& oldUrl = item.url(); - QString number; - number.setNum(index++); - - QString name = newName; - name.replace('#', number); - - if (oldUrl.fileName() != name) { - KUrl newUrl = oldUrl; - newUrl.setFileName(name); - KonqOperations::rename(this, oldUrl, newUrl); - } - } - } else if (DolphinSettings::instance().generalSettings()->renameInline()) { - Q_ASSERT(itemCount == 1); - const QModelIndex dirIndex = m_viewAccessor.dirModel()->indexForItem(items.first()); - const QModelIndex proxyIndex = m_viewAccessor.proxyModel()->mapFromSource(dirIndex); - m_viewAccessor.itemView()->edit(proxyIndex); - } else { - Q_ASSERT(itemCount == 1); - - QPointer dialog = new RenameDialog(this, items); - if (dialog->exec() == QDialog::Rejected) { - delete dialog; - return; - } - - const QString newName = dialog->newName(); - if (newName.isEmpty()) { - emit errorMessage(dialog->errorString()); - delete dialog; - return; - } - delete dialog; - - const KUrl& oldUrl = items.first().url(); - KUrl newUrl = oldUrl; - newUrl.setFileName(newName); - KonqOperations::rename(this, oldUrl, newUrl); - } - - // assure that the current index remains visible when KDirLister - // will notify the view about changed items - m_assureVisibleCurrentIndex = true; -} - -void DolphinView::trashSelectedItems() -{ - const KUrl::List list = simplifiedSelectedUrls(); - KonqOperations::del(this, KonqOperations::TRASH, list); -} - -void DolphinView::deleteSelectedItems() -{ - const KUrl::List list = simplifiedSelectedUrls(); - const bool del = KonqOperations::askDeleteConfirmation(list, - KonqOperations::DEL, - KonqOperations::DEFAULT_CONFIRMATION, - this); - - if (del) { - KIO::Job* job = KIO::del(list); - connect(job, SIGNAL(result(KJob*)), - this, SLOT(slotDeleteFileFinished(KJob*))); - } -} - -void DolphinView::cutSelectedItems() -{ - QMimeData* mimeData = selectionMimeData(); - KonqMimeData::addIsCutSelection(mimeData, true); - QApplication::clipboard()->setMimeData(mimeData); -} - -void DolphinView::copySelectedItems() -{ - QMimeData* mimeData = selectionMimeData(); - QApplication::clipboard()->setMimeData(mimeData); -} - -void DolphinView::paste() -{ - pasteToUrl(url()); -} - -void DolphinView::pasteIntoFolder() -{ - const KFileItemList items = selectedItems(); - if ((items.count() == 1) && items.first().isDir()) { - pasteToUrl(items.first().url()); - } -} - -void DolphinView::setShowPreview(bool show) -{ - if (m_showPreview == show) { - return; - } - - const KUrl viewPropsUrl = rootUrl(); - ViewProperties props(viewPropsUrl); - props.setShowPreview(show); - - m_showPreview = show; - const int oldZoomLevel = m_viewModeController->zoomLevel(); - emit showPreviewChanged(); - - // Enabling or disabling the preview might change the icon size of the view. - // As the view does not emit a signal when the icon size has been changed, - // the used zoom level of the controller must be adjusted manually: - updateZoomLevel(oldZoomLevel); -} - -void DolphinView::setShowHiddenFiles(bool show) -{ - if (m_viewAccessor.dirLister()->showingDotFiles() == show) { - return; - } - - const KUrl viewPropsUrl = rootUrl(); - ViewProperties props(viewPropsUrl); - props.setShowHiddenFiles(show); - - m_viewAccessor.dirLister()->setShowingDotFiles(show); - emit showHiddenFilesChanged(); -} - -void DolphinView::setCategorizedSorting(bool categorized) -{ - if (categorized == categorizedSorting()) { - return; - } - - // setCategorizedSorting(true) may only get invoked - // if the view supports categorized sorting - Q_ASSERT(!categorized || supportsCategorizedSorting()); - - ViewProperties props(rootUrl()); - props.setCategorizedSorting(categorized); - props.save(); - - m_storedCategorizedSorting = categorized; - m_viewAccessor.proxyModel()->setCategorizedModel(categorized); - - emit categorizedSortingChanged(); -} - -void DolphinView::toggleSortOrder() -{ - const Qt::SortOrder order = (sortOrder() == Qt::AscendingOrder) ? - Qt::DescendingOrder : - Qt::AscendingOrder; - setSortOrder(order); -} - -void DolphinView::toggleSortFoldersFirst() -{ - setSortFoldersFirst(!sortFoldersFirst()); -} - -void DolphinView::toggleAdditionalInfo(QAction* action) -{ - const KFileItemDelegate::Information info = - static_cast(action->data().toInt()); - - KFileItemDelegate::InformationList list = additionalInfo(); - - const bool show = action->isChecked(); - - const int index = list.indexOf(info); - const bool containsInfo = (index >= 0); - if (show && !containsInfo) { - list.append(info); - setAdditionalInfo(list); - } else if (!show && containsInfo) { - list.removeAt(index); - setAdditionalInfo(list); - Q_ASSERT(list.indexOf(info) < 0); - } -} - -void DolphinView::mouseReleaseEvent(QMouseEvent* event) -{ - QWidget::mouseReleaseEvent(event); - setActive(true); -} - -bool DolphinView::eventFilter(QObject* watched, QEvent* event) -{ - switch (event->type()) { - case QEvent::FocusIn: - if (watched == m_viewAccessor.itemView()) { - m_dolphinViewController->requestActivation(); - } - break; - - case QEvent::DragEnter: - if (watched == m_viewAccessor.itemView()->viewport()) { - setActive(true); - } - break; - - case QEvent::KeyPress: - if (watched == m_viewAccessor.itemView()) { - // clear the selection when Escape has been pressed - QKeyEvent* keyEvent = static_cast(event); - if (keyEvent->key() == Qt::Key_Escape) { - clearSelection(); - } - } - break; - - case QEvent::Wheel: - if (watched == m_viewAccessor.itemView()->viewport()) { - // Ctrl+wheel events should cause icon zooming, but not if the left mouse button is pressed - // (the user is probably trying to scroll during a selection in that case) - QWheelEvent* wheelEvent = static_cast(event); - if (wheelEvent->modifiers() & Qt::ControlModifier && !(wheelEvent->buttons() & Qt::LeftButton)) { - const int delta = wheelEvent->delta(); - const int level = zoomLevel(); - if (delta > 0) { - setZoomLevel(level + 1); - } else if (delta < 0) { - setZoomLevel(level - 1); - } - return true; - } - } - break; - - default: - break; - } - - return QWidget::eventFilter(watched, event); -} - -void DolphinView::activate() -{ - setActive(true); -} - -void DolphinView::triggerItem(const KFileItem& item) -{ - 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; - } - - // TODO: the m_isContextMenuOpen check is a workaround for Qt-issue 207192 - if (item.isNull() || m_isContextMenuOpen) { - return; - } - - emit itemTriggered(item); // caught by DolphinViewContainer or DolphinPart -} - -void DolphinView::slotSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected) -{ - const int count = selectedItemsCount(); - const bool selectionStateChanged = ((count > 0) && (selected.count() == count)) || - ((count == 0) && !deselected.isEmpty()); - - // If nothing has been selected before and something got selected (or if something - // was selected before and now nothing is selected) the selectionChangedSignal must - // be emitted asynchronously as fast as possible to update the edit-actions. - m_selectionChangedTimer->setInterval(selectionStateChanged ? 0 : 300); - m_selectionChangedTimer->start(); -} - -void DolphinView::emitSelectionChangedSignal() -{ - emit selectionChanged(DolphinView::selectedItems()); -} - -void DolphinView::openContextMenu(const QPoint& pos, - const QList& customActions) -{ - KFileItem item; - const QModelIndex index = m_viewAccessor.itemView()->indexAt(pos); - if (index.isValid() && (index.column() == DolphinModel::Name)) { - const QModelIndex dolphinModelIndex = m_viewAccessor.proxyModel()->mapToSource(index); - item = m_viewAccessor.dirModel()->itemForIndex(dolphinModelIndex); - } - - m_isContextMenuOpen = true; // TODO: workaround for Qt-issue 207192 - emit requestContextMenu(item, url(), customActions); - m_isContextMenuOpen = false; -} - -void DolphinView::dropUrls(const KFileItem& destItem, - const KUrl& destPath, - QDropEvent* event) -{ - addNewFileNames(event->mimeData()); - DragAndDropHelper::instance().dropUrls(destItem, destPath, event, this); -} - -void DolphinView::updateSorting(DolphinView::Sorting sorting) -{ - ViewProperties props(rootUrl()); - props.setSorting(sorting); - - m_viewAccessor.proxyModel()->setSorting(sorting); - - emit sortingChanged(sorting); -} - -void DolphinView::updateSortOrder(Qt::SortOrder order) -{ - ViewProperties props(rootUrl()); - props.setSortOrder(order); - - m_viewAccessor.proxyModel()->setSortOrder(order); - - emit sortOrderChanged(order); -} - -void DolphinView::updateSortFoldersFirst(bool foldersFirst) -{ - ViewProperties props(rootUrl()); - props.setSortFoldersFirst(foldersFirst); - - m_viewAccessor.proxyModel()->setSortFoldersFirst(foldersFirst); - - emit sortFoldersFirstChanged(foldersFirst); -} - -void DolphinView::updateAdditionalInfo(const KFileItemDelegate::InformationList& info) -{ - ViewProperties props(rootUrl()); - props.setAdditionalInfo(info); - props.save(); - - m_viewAccessor.itemDelegate()->setShowInformation(info); - - emit additionalInfoChanged(); -} - -void DolphinView::updateAdditionalInfoActions(KActionCollection* collection) -{ - const AdditionalInfoAccessor& infoAccessor = AdditionalInfoAccessor::instance(); - - const KFileItemDelegate::InformationList checkedInfos = m_viewAccessor.itemDelegate()->showInformation(); - const KFileItemDelegate::InformationList infos = infoAccessor.keys(); - - const bool enable = (m_mode == DolphinView::DetailsView) || - (m_mode == DolphinView::IconsView); - - foreach (const KFileItemDelegate::Information& info, infos) { - const QString name = infoAccessor.actionCollectionName(info, AdditionalInfoAccessor::AdditionalInfoType); - QAction* action = collection->action(name); - Q_ASSERT(action != 0); - action->setEnabled(enable); - action->setChecked(checkedInfos.contains(info)); - } -} - -QPair DolphinView::pasteInfo() const -{ - return KonqOperations::pasteInfo(url()); -} - -void DolphinView::setTabsForFilesEnabled(bool tabsForFiles) -{ - m_tabsForFiles = tabsForFiles; -} - -bool DolphinView::isTabsForFilesEnabled() const -{ - return m_tabsForFiles; -} - -bool DolphinView::itemsExpandable() const -{ - 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 urlsToExpand; - stream >> urlsToExpand; - const DolphinDetailsViewExpander* expander = m_viewAccessor.setExpandedUrls(urlsToExpand); - if (expander != 0) { - 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 != 0) { - 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 - 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) - stream << m_viewAccessor.expandedUrls(); -} - -void DolphinView::observeCreatedItem(const KUrl& url) -{ - m_createdItemUrl = url; - connect(m_viewAccessor.dirModel(), SIGNAL(rowsInserted(const QModelIndex&, int, int)), - this, SLOT(selectAndScrollToCreatedItem())); -} - -void DolphinView::selectAndScrollToCreatedItem() -{ - const QModelIndex dirIndex = m_viewAccessor.dirModel()->indexForUrl(m_createdItemUrl); - if (dirIndex.isValid()) { - const QModelIndex proxyIndex = m_viewAccessor.proxyModel()->mapFromSource(dirIndex); - m_viewAccessor.itemView()->setCurrentIndex(proxyIndex); - } - - disconnect(m_viewAccessor.dirModel(), SIGNAL(rowsInserted(const QModelIndex&, int, int)), - this, SLOT(selectAndScrollToCreatedItem())); - m_createdItemUrl = KUrl(); -} - -void DolphinView::showHoverInformation(const KFileItem& item) -{ - emit requestItemInfo(item); -} - -void DolphinView::clearHoverInformation() -{ - emit requestItemInfo(KFileItem()); -} - -void DolphinView::slotDeleteFileFinished(KJob* job) -{ - if (job->error() == 0) { - emit operationCompletedMessage(i18nc("@info:status", "Delete operation completed.")); - } else if (job->error() != KIO::ERR_USER_CANCELED) { - emit errorMessage(job->errorString()); - } -} - -void DolphinView::slotDirListerCompleted() -{ - if (!m_expanderActive) { - slotLoadingCompleted(); - } - - if (!m_newFileNames.isEmpty()) { - // select all newly added items created by a paste operation or - // a drag & drop operation, and clear the previous selection - m_viewAccessor.itemView()->clearSelection(); - const int rowCount = m_viewAccessor.proxyModel()->rowCount(); - QItemSelection selection; - for (int row = 0; row < rowCount; ++row) { - const QModelIndex proxyIndex = m_viewAccessor.proxyModel()->index(row, 0); - const QModelIndex dirIndex = m_viewAccessor.proxyModel()->mapToSource(proxyIndex); - const KUrl url = m_viewAccessor.dirModel()->itemForIndex(dirIndex).url(); - if (m_newFileNames.contains(url.fileName())) { - selection.merge(QItemSelection(proxyIndex, proxyIndex), QItemSelectionModel::Select); - } - } - m_viewAccessor.itemView()->selectionModel()->select(selection, QItemSelectionModel::Select); - - m_newFileNames.clear(); - } -} - -void DolphinView::slotLoadingCompleted() -{ - m_expanderActive = 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(); - } - } - - if (!m_selectedItems.isEmpty()) { - const KUrl& baseUrl = url(); - KUrl url; - QItemSelection newSelection; - 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)); - newSelection.select(index, index); - } - } - m_viewAccessor.itemView()->selectionModel()->select(newSelection, - QItemSelectionModel::ClearAndSelect - | QItemSelectionModel::Current); - m_selectedItems.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_assureVisibleCurrentIndex = false; - m_viewAccessor.itemView()->scrollTo(m_viewAccessor.itemView()->currentIndex()); - } -} - -void DolphinView::loadDirectory(const KUrl& url, bool reload) -{ - if (!url.isValid()) { - const QString location(url.pathOrUrl()); - if (location.isEmpty()) { - emit errorMessage(i18nc("@info:status", "The location is empty.")); - } else { - emit errorMessage(i18nc("@info:status", "The location '%1' is invalid.", location)); - } - return; - } - - KDirLister* dirLister = m_viewAccessor.dirLister(); - dirLister->openUrl(url, reload ? KDirLister::Reload : KDirLister::NoFlags); -} - -void DolphinView::applyViewProperties() -{ - if (m_ignoreViewProperties) { - return; - } - - const ViewProperties props(rootUrl()); - - const Mode mode = props.viewMode(); - if (m_mode != mode) { - const int oldZoomLevel = m_viewModeController->zoomLevel(); - - m_mode = mode; - createView(); - emit modeChanged(); - - updateZoomLevel(oldZoomLevel); - } - if (m_viewAccessor.itemView() == 0) { - createView(); - } - Q_ASSERT(m_viewAccessor.itemView() != 0); - Q_ASSERT(m_viewAccessor.itemDelegate() != 0); - - const bool showHiddenFiles = props.showHiddenFiles(); - if (showHiddenFiles != m_viewAccessor.dirLister()->showingDotFiles()) { - m_viewAccessor.dirLister()->setShowingDotFiles(showHiddenFiles); - emit showHiddenFilesChanged(); - } - - m_storedCategorizedSorting = props.categorizedSorting(); - const bool categorized = m_storedCategorizedSorting && supportsCategorizedSorting(); - if (categorized != m_viewAccessor.proxyModel()->isCategorizedModel()) { - m_viewAccessor.proxyModel()->setCategorizedModel(categorized); - emit categorizedSortingChanged(); - } - - const DolphinView::Sorting sorting = props.sorting(); - if (sorting != m_viewAccessor.proxyModel()->sorting()) { - m_viewAccessor.proxyModel()->setSorting(sorting); - emit sortingChanged(sorting); - } - - const Qt::SortOrder sortOrder = props.sortOrder(); - if (sortOrder != m_viewAccessor.proxyModel()->sortOrder()) { - m_viewAccessor.proxyModel()->setSortOrder(sortOrder); - emit sortOrderChanged(sortOrder); - } - - const bool sortFoldersFirst = props.sortFoldersFirst(); - if (sortFoldersFirst != m_viewAccessor.proxyModel()->sortFoldersFirst()) { - m_viewAccessor.proxyModel()->setSortFoldersFirst(sortFoldersFirst); - emit sortFoldersFirstChanged(sortFoldersFirst); - } - - KFileItemDelegate::InformationList info = props.additionalInfo(); - if (info != m_viewAccessor.itemDelegate()->showInformation()) { - m_viewAccessor.itemDelegate()->setShowInformation(info); - emit additionalInfoChanged(); - } - - const bool showPreview = props.showPreview(); - if (showPreview != m_showPreview) { - m_showPreview = showPreview; - const int oldZoomLevel = m_viewModeController->zoomLevel(); - emit showPreviewChanged(); - - // Enabling or disabling the preview might change the icon size of the view. - // As the view does not emit a signal when the icon size has been changed, - // the used zoom level of the controller must be adjusted manually: - updateZoomLevel(oldZoomLevel); - } - - if (DolphinSettings::instance().generalSettings()->globalViewProps()) { - // During the lifetime of a DolphinView instance the global view properties - // should not be changed. This allows e. g. to split a view and use different - // view properties for each view. - m_ignoreViewProperties = true; - } -} - -void DolphinView::createView() -{ - deleteView(); - - Q_ASSERT(m_viewAccessor.itemView() == 0); - m_viewAccessor.createView(this, m_dolphinViewController, m_viewModeController, m_mode); - - QAbstractItemView* view = m_viewAccessor.itemView(); - Q_ASSERT(view != 0); - view->installEventFilter(this); - view->viewport()->installEventFilter(this); - - m_dolphinViewController->setItemView(view); - - // When changing the view mode, the selection is lost due to reinstantiating - // a new item view with a custom selection model. Pass the ownership of the - // selection model to DolphinView, so that it can be shared by all item views. - if (m_selectionModel != 0) { - view->setSelectionModel(m_selectionModel); - } else { - m_selectionModel = view->selectionModel(); - } - m_selectionModel->setParent(this); - connect(m_selectionModel, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), - this, SLOT(slotSelectionChanged(QItemSelection, QItemSelection))); - - setFocusProxy(m_viewAccessor.layoutTarget()); - m_topLayout->insertWidget(1, m_viewAccessor.layoutTarget()); -} - -void DolphinView::deleteView() -{ - QAbstractItemView* view = m_viewAccessor.itemView(); - if (view != 0) { - // 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_topLayout->removeWidget(view); - view->close(); - - // disconnect all signal/slots - disconnect(view); - m_viewModeController->disconnect(view); - view->disconnect(); - - m_viewAccessor.deleteView(); - } -} - -void DolphinView::pasteToUrl(const KUrl& url) -{ - addNewFileNames(QApplication::clipboard()->mimeData()); - KonqOperations::doPaste(this, url); -} - -void DolphinView::updateZoomLevel(int oldZoomLevel) -{ - const int newZoomLevel = ZoomLevelInfo::zoomLevelForIconSize(m_viewAccessor.itemView()->iconSize()); - if (oldZoomLevel != newZoomLevel) { - m_viewModeController->setZoomLevel(newZoomLevel); - emit zoomLevelChanged(newZoomLevel); - } -} - -KUrl::List DolphinView::simplifiedSelectedUrls() const -{ - KUrl::List list = selectedUrls(); - if (itemsExpandable() ) { - list = KDirModel::simplifiedUrlList(list); - } - return list; -} - -QMimeData* DolphinView::selectionMimeData() const -{ - const QAbstractItemView* view = m_viewAccessor.itemView(); - Q_ASSERT((view != 0) && (view->selectionModel() != 0)); - const QItemSelection selection = m_viewAccessor.proxyModel()->mapSelectionToSource(view->selectionModel()->selection()); - return m_viewAccessor.dirModel()->mimeData(selection.indexes()); -} - -void DolphinView::addNewFileNames(const QMimeData* mimeData) -{ - const KUrl::List urls = KUrl::List::fromMimeData(mimeData); - foreach (const KUrl& url, urls) { - m_newFileNames.insert(url.fileName()); - } -} - -DolphinView::ViewAccessor::ViewAccessor(DolphinSortFilterProxyModel* proxyModel) : - m_iconsView(0), - m_detailsView(0), - m_columnsContainer(0), - m_proxyModel(proxyModel), - m_dragSource(0) -{ -} - -DolphinView::ViewAccessor::~ViewAccessor() -{ - delete m_dragSource; - m_dragSource = 0; -} - -void DolphinView::ViewAccessor::createView(QWidget* parent, - DolphinViewController* dolphinViewController, - const ViewModeController* viewModeController, - Mode mode) -{ - Q_ASSERT(itemView() == 0); - - switch (mode) { - case IconsView: - m_iconsView = new DolphinIconsView(parent, - dolphinViewController, - viewModeController, - m_proxyModel); - break; - - case DetailsView: - m_detailsView = new DolphinDetailsView(parent, - dolphinViewController, - viewModeController, - m_proxyModel); - break; - - case ColumnView: - m_columnsContainer = new DolphinColumnViewContainer(parent, - dolphinViewController, - viewModeController); - break; - - default: - Q_ASSERT(false); - } -} - -void DolphinView::ViewAccessor::deleteView() -{ - QAbstractItemView* view = itemView(); - if (view != 0) { - if (DragAndDropHelper::instance().isDragSource(view)) { - // The view is a drag source (the feature "Open folders - // during drag operations" is used). Deleting the view - // during an ongoing drag operation is not allowed, so - // this will postponed. - if (m_dragSource != 0) { - // the old stored view is obviously not the drag source anymore - m_dragSource->deleteLater(); - m_dragSource = 0; - } - view->hide(); - m_dragSource = view; - } else { - view->deleteLater(); - } - } - - m_iconsView = 0; - m_detailsView = 0; - - if (m_columnsContainer != 0) { - m_columnsContainer->deleteLater(); - } - m_columnsContainer = 0; -} - - -void DolphinView::ViewAccessor::prepareUrlChange(const KUrl& url) -{ - if (m_columnsContainer != 0) { - m_columnsContainer->showColumn(url); - } -} - -QAbstractItemView* DolphinView::ViewAccessor::itemView() const -{ - if (m_iconsView != 0) { - return m_iconsView; - } - - if (m_detailsView != 0) { - return m_detailsView; - } - - if (m_columnsContainer != 0) { - return m_columnsContainer->activeColumn(); - } - - return 0; -} - -KFileItemDelegate* DolphinView::ViewAccessor::itemDelegate() const -{ - return static_cast(itemView()->itemDelegate()); -} - -QWidget* DolphinView::ViewAccessor::layoutTarget() const -{ - if (m_columnsContainer != 0) { - return m_columnsContainer; - } - return itemView(); -} - -KUrl DolphinView::ViewAccessor::rootUrl() const -{ - return (m_columnsContainer != 0) ? m_columnsContainer->rootUrl() : KUrl(); -} - -bool DolphinView::ViewAccessor::supportsCategorizedSorting() const -{ - return m_iconsView != 0; -} - -bool DolphinView::ViewAccessor::itemsExpandable() const -{ - return (m_detailsView != 0) && m_detailsView->itemsExpandable(); -} - - -QSet DolphinView::ViewAccessor::expandedUrls() const -{ - if (m_detailsView != 0) { - return m_detailsView->expandedUrls(); - } - - return QSet(); -} - -const DolphinDetailsViewExpander* DolphinView::ViewAccessor::setExpandedUrls(const QSet& urlsToExpand) -{ - if ((m_detailsView != 0) && m_detailsView->itemsExpandable() && !urlsToExpand.isEmpty()) { - // Check if another expander is already active and stop it if necessary. - if(!m_detailsViewExpander.isNull()) { - m_detailsViewExpander->stop(); - } - - 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 - // the file item delegate info to its columns internally - return m_detailsView != 0; -} - -DolphinModel* DolphinView::ViewAccessor::dirModel() const -{ - return static_cast(proxyModel()->sourceModel()); -} - -DolphinSortFilterProxyModel* DolphinView::ViewAccessor::proxyModel() const -{ - if (m_columnsContainer != 0) { - return static_cast(m_columnsContainer->activeColumn()->model()); - } - return m_proxyModel; -} - -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" diff --git a/src/dolphinview.h b/src/dolphinview.h deleted file mode 100644 index dbef511bf..000000000 --- a/src/dolphinview.h +++ /dev/null @@ -1,818 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2006-2009 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 * - ***************************************************************************/ - - -#ifndef DOLPHINVIEW_H -#define DOLPHINVIEW_H - -#include - -#include "libdolphin_export.h" - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -typedef KIO::FileUndoManager::CommandType CommandType; - -class DolphinColumnViewContainer; -class DolphinDetailsView; -class DolphinIconsView; -class DolphinModel; -class DolphinSortFilterProxyModel; -class DolphinViewController; -class KAction; -class KActionCollection; -class KDirLister; -class KUrl; -class ViewModeController; -class ViewProperties; -class DolphinDetailsViewExpander; - -/** - * @short Represents a view for the directory content. - * - * View modes for icons, details and columns are supported. It's - * possible to adjust: - * - sort order - * - sort type - * - show hidden files - * - show previews - * - * @see DolphinIconsView - * @see DolphinDetailsView - * @see DolphinColumnView - */ -class LIBDOLPHINPRIVATE_EXPORT DolphinView : public QWidget -{ - Q_OBJECT - -public: - /** - * Defines the view mode for a directory. The view mode - * can be defined when constructing a DolphinView. The - * view mode is automatically updated if the directory itself - * defines a view mode (see class ViewProperties for details). - */ - enum Mode - { - /** - * The directory items are shown as icons including an - * icon name. - */ - IconsView = 0, - - /** - * The icon, the name and at least the size of the directory - * items are shown in a table. It is possible to add columns - * for date, group and permissions. - */ - DetailsView = 1, - - /** - * Each folder is shown in a separate column. - */ - ColumnView = 2, - MaxModeEnum = ColumnView - }; - - /** Defines the sort order for the items of a directory. */ - enum Sorting - { - SortByName = 0, - SortBySize, - SortByDate, - SortByPermissions, - SortByOwner, - SortByGroup, - SortByType, - SortByDestination, - SortByPath, - MaxSortingEnum = SortByPath - }; - - /** - * @param parent Parent widget of the view. - * @param url Specifies the content which should be shown. - * @param proxyModel Used proxy model which specifies the sorting. The - * model is not owned by the view and won't get - * deleted. - */ - DolphinView(QWidget* parent, - const KUrl& url, - DolphinSortFilterProxyModel* proxyModel); - - virtual ~DolphinView(); - - /** - * Returns the current active URL, where all actions are applied. - * The URL navigator is synchronized with this URL. - */ - KUrl url() const; - - /** - * Returns the root URL of the view, which is defined as the first - * visible path of DolphinView::url(). Usually the root URL is - * equal to DolphinView::url(), but in the case of the column view - * when 2 columns are shown, the root URL might be: - * /home/peter/Documents - * and DolphinView::url() might return - * /home/peter/Documents/Music/ - */ - KUrl rootUrl() const; - - /** - * If \a active is true, the view will marked as active. The active - * view is defined as view where all actions are applied to. - */ - void setActive(bool active); - bool isActive() const; - - /** - * Changes the view mode for the current directory to \a mode. - * If the view properties should be remembered for each directory - * (GeneralSettings::globalViewProps() returns false), then the - * changed view mode will be stored automatically. - */ - void setMode(Mode mode); - Mode mode() const; - - /** See setShowPreview */ - bool showPreview() const; - - /** See setShowHiddenFiles */ - bool showHiddenFiles() const; - - /** See setCategorizedSorting */ - bool categorizedSorting() const; - - /** - * Returns true, if the categorized sorting is supported by the current - * used mode (see DolphinView::setMode()). Currently only DolphinView::IconsView - * supports categorizations. To check whether the categorized - * sorting is set, use DolphinView::categorizedSorting(). - */ - bool supportsCategorizedSorting() const; - - /** - * Marks the items indicated by \p urls to get selected after the - * directory DolphinView::url() has been loaded. Note that nothing - * gets selected if no loading of a directory has been triggered - * by DolphinView::setUrl() or DolphinView::reload(). - */ - void markUrlsAsSelected(const QList& urls); - - /** - * Returns the selected items. The list is empty if no item has been - * selected. - * @see DolphinView::selectedUrls() - */ - KFileItemList selectedItems() const; - - /** - * Returns a list of URLs for all selected items. An empty list - * is returned, if no item is selected. - * @see DolphinView::selectedItems() - */ - KUrl::List selectedUrls() const; - - /** - * Returns the number of selected items (this is faster than - * invoking selectedItems().count()). - */ - int selectedItemsCount() const; - - QItemSelectionModel* selectionModel() const; - - /** - * Sets the zoom level to \a level. It is assured that the used - * level is adjusted to be inside the range ZoomLevelInfo::minimumLevel() and - * ZoomLevelInfo::maximumLevel(). - */ - void setZoomLevel(int level); - int zoomLevel() const; - - /** - * Returns true, if zooming in is possible. If false is returned, - * the maximum zooming level has been reached. - */ - bool isZoomInPossible() const; - - /** - * Returns true, if zooming out is possible. If false is returned, - * the minimum zooming level has been reached. - */ - bool isZoomOutPossible() const; - - /** Sets the sort order of the items inside a directory (see DolphinView::Sorting). */ - void setSorting(Sorting sorting); - - /** Returns the sort order of the items inside a directory (see DolphinView::Sorting). */ - Sorting sorting() const; - - /** Sets the sort order (Qt::Ascending or Qt::Descending) for the items. */ - void setSortOrder(Qt::SortOrder order); - - /** Returns the current used sort order (Qt::Ascending or Qt::Descending). */ - Qt::SortOrder sortOrder() const; - - /** Sets a separate sorting with folders first (true) or a mixed sorting of files and folders (false). */ - void setSortFoldersFirst(bool foldersFirst); - - /** Returns if files and folders are sorted separately or not. */ - bool sortFoldersFirst() const; - - /** Sets the additional information which should be shown for the items. */ - void setAdditionalInfo(KFileItemDelegate::InformationList info); - - /** Returns the additional information which should be shown for the items. */ - KFileItemDelegate::InformationList additionalInfo() const; - - /** Reloads the current directory. */ - void reload(); - - /** - * Refreshes the view to get synchronized with the (updated) Dolphin settings. - * This method only needs to get invoked if the view settings for the Icons View, - * Details View or Columns View have been changed. - */ - void refresh(); - - /** - * Filters the currently shown items by \a nameFilter. All items - * which contain the given filter string will be shown. - */ - void setNameFilter(const QString& nameFilter); - - /** - * Calculates the number of currently shown files into - * \a fileCount and the number of folders into \a folderCount. - * The size of all files is written into \a totalFileSize. - * It is recommend using this method instead of asking the - * directory lister or the model directly, as it takes - * filtering and hierarchical previews into account. - */ - void calculateItemCount(int& fileCount, int& folderCount, KIO::filesize_t& totalFileSize) const; - - /** - * Returns a textual representation of the state of the current - * folder or selected items, suitable for use in the status bar. - */ - QString statusBarText() const; - - /** - * Returns the version control actions that are provided for the items \p items. - * Usually the actions are presented in the context menu. - */ - QList versionControlActions(const KFileItemList& items) const; - - /** - * Updates the state of the 'Additional Information' actions in \a collection. - */ - void updateAdditionalInfoActions(KActionCollection* collection); - - /** - * Returns the state of the paste action: - * first is whether the action should be enabled - * second is the text for the action - */ - QPair pasteInfo() const; - - /** - * If \a tabsForFiles is true, the signal tabRequested() will also - * emitted also for files. Per default tabs for files is disabled - * and hence the signal tabRequested() will only be emitted for - * directories. - */ - void setTabsForFilesEnabled(bool tabsForFiles); - bool isTabsForFilesEnabled() const; - - /** - * Returns true if the current view allows folders to be expanded, - * i.e. presents a hierarchical view to the user. - */ - 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 - * \a url, nothing will be done (use DolphinView::reload() instead). - */ - void setUrl(const KUrl& url); - - /** - * Selects all items. - * @see DolphinView::selectedItems() - */ - void selectAll(); - - /** - * Inverts the current selection: selected items get unselected, - * unselected items get selected. - * @see DolphinView::selectedItems() - */ - void invertSelection(); - - /** Returns true, if at least one item is selected. */ - bool hasSelection() const; - - void clearSelection(); - - /** - * Triggers the renaming of the currently selected items, where - * the user must input a new name for the items. - */ - void renameSelectedItems(); - - /** - * Moves all selected items to the trash. - */ - void trashSelectedItems(); - - /** - * Deletes all selected items. - */ - void deleteSelectedItems(); - - /** - * Copies all selected items to the clipboard and marks - * the items as cut. - */ - void cutSelectedItems(); - - /** Copies all selected items to the clipboard. */ - void copySelectedItems(); - - /** Pastes the clipboard data to this view. */ - void paste(); - - /** - * Pastes the clipboard data into the currently selected - * folder. If the current selection is not exactly one folder, no - * paste operation is done. - */ - void pasteIntoFolder(); - - /** - * Turns on the file preview for the all files of the current directory, - * if \a show is true. - * If the view properties should be remembered for each directory - * (GeneralSettings::globalViewProps() returns false), then the - * preview setting will be stored automatically. - */ - void setShowPreview(bool show); - - /** - * Shows all hidden files of the current directory, - * if \a show is true. - * If the view properties should be remembered for each directory - * (GeneralSettings::globalViewProps() returns false), then the - * show hidden file setting will be stored automatically. - */ - void setShowHiddenFiles(bool show); - - /** - * Summarizes all sorted items by their category \a categorized - * is true. - * If the view properties should be remembered for each directory - * (GeneralSettings::globalViewProps() returns false), then the - * categorized sorting setting will be stored automatically. - */ - void setCategorizedSorting(bool categorized); - - /** Switches between an ascending and descending sorting order. */ - void toggleSortOrder(); - - /** Switches between a separate sorting (with folders first) and a mixed sorting of files and folders. */ - void toggleSortFoldersFirst(); - - /** - * Switches on or off the displaying of additional information - * as specified by \a action. - */ - void toggleAdditionalInfo(QAction* action); - -signals: - /** - * Is emitted if the view has been activated by e. g. a mouse click. - */ - void activated(); - - /** Is emitted if URL of the view has been changed to \a url. */ - void urlChanged(const KUrl& url); - - /** - * Is emitted when clicking on an item with the left mouse button. - */ - void itemTriggered(const KFileItem& item); - - /** - * Is emitted if a new tab should be opened for the URL \a url. - */ - void tabRequested(const KUrl& url); - - /** - * Is emitted if the view mode (IconsView, DetailsView, - * PreviewsView) has been changed. - */ - void modeChanged(); - - /** Is emitted if the 'show preview' property has been changed. */ - void showPreviewChanged(); - - /** Is emitted if the 'show hidden files' property has been changed. */ - void showHiddenFilesChanged(); - - /** Is emitted if the 'categorized sorting' property has been changed. */ - void categorizedSortingChanged(); - - /** Is emitted if the sorting by name, size or date has been changed. */ - void sortingChanged(DolphinView::Sorting sorting); - - /** Is emitted if the sort order (ascending or descending) has been changed. */ - void sortOrderChanged(Qt::SortOrder order); - - /** Is emitted if the sorting of files and folders (separate with folders first or mixed) has been changed. */ - void sortFoldersFirstChanged(bool foldersFirst); - - /** Is emitted if the additional information shown for this view has been changed. */ - void additionalInfoChanged(); - - /** Is emitted if the zoom level has been changed by zooming in or out. */ - void zoomLevelChanged(int level); - - /** - * Is emitted if information of an item is requested to be shown e. g. in the panel. - * If item is null, no item information request is pending. - */ - void requestItemInfo(const KFileItem& item); - - /** - * Is emitted whenever the selection has been changed. - */ - void selectionChanged(const KFileItemList& selection); - - /** - * Is emitted if a context menu is requested for the item \a item, - * which is part of \a url. If the item is null, the context menu - * for the URL should be shown and the custom actions \a customActions - * will be added. - */ - void requestContextMenu(const KFileItem& item, - const KUrl& url, - const QList& customActions); - - /** - * Is emitted if an information message with the content \a msg - * should be shown. - */ - void infoMessage(const QString& msg); - - /** - * Is emitted if an error message with the content \a msg - * should be shown. - */ - void errorMessage(const QString& msg); - - /** - * Is emitted if an "operation completed" message with the content \a msg - * should be shown. - */ - void operationCompletedMessage(const QString& msg); - - /** - * Is emitted after DolphinView::setUrl() has been invoked and - * the path \a url is currently loaded. If this signal is emitted, - * it is assured that the view contains already the correct root - * URL and property settings. - */ - void startedPathLoading(const KUrl& url); - - /** - * Emitted when KDirLister emits redirection. - * Testcase: fish://localhost - */ - void redirection(const KUrl& oldUrl, const KUrl& newUrl); - -protected: - /** @see QWidget::mouseReleaseEvent */ - virtual void mouseReleaseEvent(QMouseEvent* event); - virtual bool eventFilter(QObject* watched, QEvent* event); - -private slots: - /** - * Marks the view as active (DolphinView:isActive() will return true) - * and emits the 'activated' signal if it is not already active. - */ - void activate(); - - /** - * If the item \a item is a directory, then this - * directory will be loaded. If the item is a file, the corresponding - * application will get started. - */ - void triggerItem(const KFileItem& index); - - /** - * Emits the signal \a selectionChanged() with a small delay. This is - * because getting all file items for the signal can be an expensive - * operation. Fast selection changes are collected in this case and - * the signal is emitted only after no selection change has been done - * within a small delay. - */ - void slotSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected); - - /** - * Is called by emitDelayedSelectionChangedSignal() and emits the - * signal \a selectionChanged() with all selected file items as parameter. - */ - void emitSelectionChangedSignal(); - - /** - * Opens the context menu on position \a pos. The position - * is used to check whether the context menu is related to an - * item or to the viewport. - */ - void openContextMenu(const QPoint& pos, const QList& customActions); - - /** - * Drops dragged URLs to the destination path \a destPath. If - * the URLs are dropped above an item inside the destination path, - * the item is indicated by \a destItem. - */ - void dropUrls(const KFileItem& destItem, - const KUrl& destPath, - QDropEvent* event); - - /** - * Updates the view properties of the current URL to the - * sorting given by \a sorting. - */ - void updateSorting(DolphinView::Sorting sorting); - - /** - * Updates the view properties of the current URL to the - * sort order given by \a order. - */ - void updateSortOrder(Qt::SortOrder order); - - /** - * Updates the view properties of the current URL to the - * sorting of files and folders (separate with folders first or mixed) given by \a foldersFirst. - */ - void updateSortFoldersFirst(bool foldersFirst); - - /** - * Updates the view properties of the current URL to the - * additional information given by \a info. - */ - void updateAdditionalInfo(const KFileItemDelegate::InformationList& info); - - /** - * Updates the status bar to show hover information for the - * item \a item. If currently other items are selected, - * no hover information is shown. - * @see DolphinView::clearHoverInformation() - */ - void showHoverInformation(const KFileItem& item); - - /** - * Clears the hover information shown in the status bar. - * @see DolphinView::showHoverInformation(). - */ - void clearHoverInformation(); - - /** - * Indicates in the status bar that the delete operation - * of the job \a job has been finished. - */ - void slotDeleteFileFinished(KJob* job); - - /** - * Invoked when the directory lister has completed the loading of - * items. Assures that pasted items and renamed items get seleced. - */ - 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 slotRefreshItems(); - - /** - * Observes the item with the URL \a url. As soon as the directory - * model indicates that the item is available, the item will - * get selected and it is assure that the item stays visible. - * - * @see selectAndScrollToCreatedItem() - */ - void observeCreatedItem(const KUrl& url); - - /** - * Selects and scrolls to the item that got observed - * by observeCreatedItem(). - */ - void selectAndScrollToCreatedItem(); - - /** - * Called when a redirection happens. - * Testcase: fish://localhost - */ - 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); - - /** - * Applies the view properties which are defined by the current URL - * to the DolphinView properties. - */ - void applyViewProperties(); - - /** - * Creates a new view representing the given view mode (DolphinView::mode()). - * The current view will get deleted. - */ - void createView(); - - void deleteView(); - - /** - * Helper method for DolphinView::paste() and DolphinView::pasteIntoFolder(). - * Pastes the clipboard data into the URL \a url. - */ - void pasteToUrl(const KUrl& url); - - /** - * Checks whether the current item view has the same zoom level - * as \a oldZoomLevel. If this is not the case, the zoom level - * of the controller is updated and a zoomLevelChanged() signal - * is emitted. - */ - void updateZoomLevel(int oldZoomLevel); - - /** - * Returns a list of URLs for all selected items. The list is - * simplified, so that when the URLs are part of different tree - * levels, only the parent is returned. - */ - KUrl::List simplifiedSelectedUrls() const; - - /** - * Returns the MIME data for all selected items. - */ - QMimeData* selectionMimeData() const; - - /** - * Is invoked after a paste operation or a drag & drop - * operation and adds the filenames of all URLs from \a mimeData to - * m_newFileNames. This allows to select all newly added - * items in slotDirListerCompleted(). - */ - void addNewFileNames(const QMimeData* mimeData); - -private: - /** - * Abstracts the access to the different view implementations - * for icons-, details- and column-view. - */ - class ViewAccessor - { - public: - ViewAccessor(DolphinSortFilterProxyModel* proxyModel); - ~ViewAccessor(); - - void createView(QWidget* parent, - DolphinViewController* dolphinViewController, - const ViewModeController* viewModeController, - Mode mode); - void deleteView(); - - /** - * Must be invoked before the URL has been changed and allows view implementations - * like the column view to create a new column. - */ - void prepareUrlChange(const KUrl& url); - - QAbstractItemView* itemView() const; - KFileItemDelegate* itemDelegate() const; - - /** - * Returns the widget that should be added to the layout as target. Usually - * the item view itself is returned, but in the case of the column view - * a container widget is returned. - */ - QWidget* layoutTarget() const; - - KUrl rootUrl() const; - - bool supportsCategorizedSorting() const; - bool itemsExpandable() const; - QSet expandedUrls() const; - const DolphinDetailsViewExpander* setExpandedUrls(const QSet& urlsToExpand); - - /** - * Returns true, if a reloading of the items is required - * when the additional information properties have been changed - * by the user. - */ - bool reloadOnAdditionalInfoChange() const; - - DolphinModel* dirModel() const; - DolphinSortFilterProxyModel* proxyModel() const; - KDirLister* dirLister() const; - - private: - DolphinIconsView* m_iconsView; - DolphinDetailsView* m_detailsView; - DolphinColumnViewContainer* m_columnsContainer; - DolphinSortFilterProxyModel* m_proxyModel; - QAbstractItemView* m_dragSource; - QPointer m_detailsViewExpander; - }; - - bool m_active : 1; - bool m_showPreview : 1; - bool m_storedCategorizedSorting : 1; - bool m_tabsForFiles : 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; - - QVBoxLayout* m_topLayout; - - DolphinViewController* m_dolphinViewController; - ViewModeController* m_viewModeController; - ViewAccessor m_viewAccessor; - - QItemSelectionModel* m_selectionModel; // allow to switch views without losing the selection - QTimer* m_selectionChangedTimer; - - 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 - - /** - * Remembers the filenames that have been added by a paste operation - * or a drag & drop operation. Allows to select the items in - * slotDirListerCompleted(). - */ - QSet m_newFileNames; -}; - -/// Allow using DolphinView::Mode in QVariant -Q_DECLARE_METATYPE(DolphinView::Mode) - -#endif // DOLPHINVIEW_H diff --git a/src/dolphinviewactionhandler.cpp b/src/dolphinviewactionhandler.cpp index 8b1d35ac9..d2eaa4d51 100644 --- a/src/dolphinviewactionhandler.cpp +++ b/src/dolphinviewactionhandler.cpp @@ -21,8 +21,8 @@ #include "additionalinfoaccessor.h" #include "settings/viewpropertiesdialog.h" -#include "dolphinview.h" -#include "zoomlevelinfo.h" +#include "views/dolphinview.h" +#include "views/zoomlevelinfo.h" #include #include diff --git a/src/dolphinviewactionhandler.h b/src/dolphinviewactionhandler.h index dbe02a706..05339ce37 100644 --- a/src/dolphinviewactionhandler.h +++ b/src/dolphinviewactionhandler.h @@ -21,10 +21,10 @@ #ifndef DOLPHINVIEWACTIONHANDLER_H #define DOLPHINVIEWACTIONHANDLER_H -#include "dolphinview.h" #include "libdolphin_export.h" #include #include +#include "views/dolphinview.h" #include class KToggleAction; diff --git a/src/dolphinviewautoscroller.cpp b/src/dolphinviewautoscroller.cpp deleted file mode 100644 index 45896a5eb..000000000 --- a/src/dolphinviewautoscroller.cpp +++ /dev/null @@ -1,223 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Peter Penz * - * * - * 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 "dolphinviewautoscroller.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -DolphinViewAutoScroller::DolphinViewAutoScroller(QAbstractItemView* parent) : - QObject(parent), - m_rubberBandSelection(false), - m_keyPressed(false), - m_initializedTimestamp(false), - m_horizontalScrollInc(0), - m_verticalScrollInc(0), - m_itemView(parent), - m_timer(0), - m_timestamp() -{ - m_itemView->setAutoScroll(false); - m_itemView->viewport()->installEventFilter(this); - m_itemView->installEventFilter(this); - - m_timer = new QTimer(this); - m_timer->setSingleShot(false); - m_timer->setInterval(1000 / 25); // 25 frames per second - connect(m_timer, SIGNAL(timeout()), this, SLOT(scrollViewport())); -} - -DolphinViewAutoScroller::~DolphinViewAutoScroller() -{ -} - -bool DolphinViewAutoScroller::isActive() const -{ - return m_timer->isActive(); -} - -void DolphinViewAutoScroller::handleCurrentIndexChange(const QModelIndex& current, - const QModelIndex& previous) -{ - // When the autoscroller is inactive and a key has been pressed, it must be - // assured that the current item stays visible. The check whether the previous - // item is valid is important because of #197951. The keypress check is done - // because of #199833. - if (current.isValid() && (previous.isValid() || m_keyPressed) && !isActive()) { - m_itemView->scrollTo(current); - } -} - -bool DolphinViewAutoScroller::eventFilter(QObject* watched, QEvent* event) -{ - if (watched == m_itemView->viewport()) { - switch (event->type()) { - case QEvent::MouseButtonPress: - if (static_cast(event)->button() == Qt::LeftButton) { - m_rubberBandSelection = true; - } - break; - - case QEvent::MouseMove: - if (m_rubberBandSelection) { - triggerAutoScroll(); - } - break; - - case QEvent::MouseButtonRelease: - m_rubberBandSelection = false; - stopAutoScroll(); - break; - - case QEvent::DragEnter: - case QEvent::DragMove: - m_rubberBandSelection = false; - triggerAutoScroll(); - break; - - case QEvent::Drop: - case QEvent::DragLeave: - m_rubberBandSelection = false; - stopAutoScroll(); - break; - - default: - break; - } - } else if (watched == m_itemView) { - switch (event->type()) { - case QEvent::KeyPress: - m_keyPressed = true; - break; - - case QEvent::KeyRelease: - m_keyPressed = false; - break; - - default: - break; - } - } - - return QObject::eventFilter(watched, event); -} - -void DolphinViewAutoScroller::scrollViewport() -{ - if (m_timestamp.elapsed() < QApplication::startDragTime()) { - return; - } - - QScrollBar* verticalScrollBar = m_itemView->verticalScrollBar(); - if (verticalScrollBar != 0) { - const int value = verticalScrollBar->value(); - verticalScrollBar->setValue(value + m_verticalScrollInc); - - } - QScrollBar* horizontalScrollBar = m_itemView->horizontalScrollBar(); - if (horizontalScrollBar != 0) { - const int value = horizontalScrollBar->value(); - horizontalScrollBar->setValue(value + m_horizontalScrollInc); - - } - - if (m_rubberBandSelection) { - // The scrolling does not lead to an update of the rubberband - // selection. Fake a mouse move event to let the QAbstractItemView - // update the rubberband. - QWidget* viewport = m_itemView->viewport(); - const QPoint pos = viewport->mapFromGlobal(QCursor::pos()); - QMouseEvent event(QEvent::MouseMove, pos, Qt::LeftButton, Qt::LeftButton, QApplication::keyboardModifiers()); - QCoreApplication::sendEvent(viewport, &event); - } -} - -void DolphinViewAutoScroller::triggerAutoScroll() -{ - const bool verticalScrolling = (m_itemView->verticalScrollBar() != 0) && - m_itemView->verticalScrollBar()->isVisible(); - const bool horizontalScrolling = (m_itemView->horizontalScrollBar() != 0) && - m_itemView->horizontalScrollBar()->isVisible(); - if (!verticalScrolling && !horizontalScrolling) { - // no scrollbars are shown at all, so no autoscrolling is necessary - stopAutoScroll(); - return; - } - - QWidget* viewport = m_itemView->viewport(); - const QPoint pos = viewport->mapFromGlobal(QCursor::pos()); - if (verticalScrolling) { - m_verticalScrollInc = calculateScrollIncrement(pos.y(), viewport->height()); - } - if (horizontalScrolling) { - m_horizontalScrollInc = calculateScrollIncrement(pos.x(), viewport->width()); - } - - if (m_timer->isActive()) { - if ((m_horizontalScrollInc == 0) && (m_verticalScrollInc == 0)) { - stopAutoScroll(); - } - } else if ((m_horizontalScrollInc != 0) || (m_verticalScrollInc != 0)) { - if (!m_initializedTimestamp) { - m_initializedTimestamp = true; - m_timestamp.start(); - } - m_timer->start(); - } -} - -void DolphinViewAutoScroller::stopAutoScroll() -{ - m_timer->stop(); - m_horizontalScrollInc = 0; - m_verticalScrollInc = 0; - m_initializedTimestamp = false; -} - -int DolphinViewAutoScroller::calculateScrollIncrement(int cursorPos, int rangeSize) const -{ - int inc = 0; - - const int minSpeed = 4; - const int maxSpeed = 768; - const int speedLimiter = 48; - const int autoScrollBorder = 64; - - if (cursorPos < autoScrollBorder) { - inc = -minSpeed + qAbs(cursorPos - autoScrollBorder) * (cursorPos - autoScrollBorder) / speedLimiter; - if (inc < -maxSpeed) { - inc = -maxSpeed; - } - } else if (cursorPos > rangeSize - autoScrollBorder) { - inc = minSpeed + qAbs(cursorPos - rangeSize + autoScrollBorder) * (cursorPos - rangeSize + autoScrollBorder) / speedLimiter; - if (inc > maxSpeed) { - inc = maxSpeed; - } - } - - return inc; -} - -#include "dolphinviewautoscroller.moc" diff --git a/src/dolphinviewautoscroller.h b/src/dolphinviewautoscroller.h deleted file mode 100644 index 9fd35d494..000000000 --- a/src/dolphinviewautoscroller.h +++ /dev/null @@ -1,79 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Peter Penz * - * * - * 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 DOLPHINVIEWAUTOSCROLLER_H -#define DOLPHINVIEWAUTOSCROLLER_H - -#include -#include - -class QAbstractItemView; -class QModelIndex; -class QTimer; - -/** - * @brief Assures that an autoscrolling is done for item views. - * - * This is a workaround as QAbstractItemView::setAutoScroll() is not usable - * when selecting items (see Qt issue #214542). - */ -class DolphinViewAutoScroller : public QObject -{ - Q_OBJECT - -public: - DolphinViewAutoScroller(QAbstractItemView* parent); - virtual ~DolphinViewAutoScroller(); - bool isActive() const; - - /** - * Must be invoked by the parent item view, when QAbstractItemView::currentChanged() - * has been called. Assures that the current item stays visible when it has been - * changed by the keyboard. - */ - void handleCurrentIndexChange(const QModelIndex& current, const QModelIndex& previous); - -protected: - virtual bool eventFilter(QObject* watched, QEvent* event); - -private slots: - void scrollViewport(); - -private: - void triggerAutoScroll(); - void stopAutoScroll(); - - /** - * Calculates the scroll increment dependent from - * the cursor position \a cursorPos and the range 0 - \a rangeSize - 1. - */ - int calculateScrollIncrement(int cursorPos, int rangeSize) const; - -private: - bool m_rubberBandSelection; - bool m_keyPressed; - bool m_initializedTimestamp; - int m_horizontalScrollInc; - int m_verticalScrollInc; - QAbstractItemView* m_itemView; - QTimer* m_timer; - QTime m_timestamp; -}; - -#endif diff --git a/src/dolphinviewcontainer.cpp b/src/dolphinviewcontainer.cpp index d11a4a9be..24ab43272 100644 --- a/src/dolphinviewcontainer.cpp +++ b/src/dolphinviewcontainer.cpp @@ -49,20 +49,20 @@ #include "dolphin_generalsettings.h" #include "dolphinmodel.h" -#include "dolphincolumnview.h" -#include "dolphinviewcontroller.h" #include "dolphinmainwindow.h" #include "dolphindirlister.h" #include "dolphinsortfilterproxymodel.h" -#include "dolphindetailsview.h" -#include "dolphiniconsview.h" #include "draganddrophelper.h" -#include "filterbar.h" +#include "filterbar/filterbar.h" #include "search/dolphinsearchbox.h" #include "settings/dolphinsettings.h" #include "statusbar/dolphinstatusbar.h" -#include "viewmodecontroller.h" #include "viewproperties.h" +#include "views/dolphincolumnview.h" +#include "views/dolphindetailsview.h" +#include "views/dolphiniconsview.h" +#include "views/dolphinviewcontroller.h" +#include "views/viewmodecontroller.h" DolphinViewContainer::DolphinViewContainer(const KUrl& url, QWidget* parent) : QWidget(parent), diff --git a/src/dolphinviewcontainer.h b/src/dolphinviewcontainer.h index c222e7a55..fe1ad8d6e 100644 --- a/src/dolphinviewcontainer.h +++ b/src/dolphinviewcontainer.h @@ -21,8 +21,6 @@ #ifndef DOLPHINVIEWCONTAINER_H #define DOLPHINVIEWCONTAINER_H -#include "dolphinview.h" - #include #include #include @@ -36,6 +34,8 @@ #include #include +#include + class FilterBar; class KUrl; class DolphinModel; diff --git a/src/dolphinviewcontroller.cpp b/src/dolphinviewcontroller.cpp deleted file mode 100644 index 6ef32f07f..000000000 --- a/src/dolphinviewcontroller.cpp +++ /dev/null @@ -1,249 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2010 by Peter Penz * - * * - * 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 "dolphinviewcontroller.h" -#include "zoomlevelinfo.h" - -#include -#include -#include -#include -#include -#include - -Qt::MouseButtons DolphinViewController::m_mouseButtons = Qt::NoButton; - -DolphinViewController::DolphinViewController(DolphinView* dolphinView) : - QObject(dolphinView), - m_dolphinView(dolphinView), - m_itemView(0), - m_versionControlActions() -{ -} - -DolphinViewController::~DolphinViewController() -{ -} - -const DolphinView* DolphinViewController::view() const -{ - return m_dolphinView; -} - -void DolphinViewController::requestUrlChange(const KUrl& url) -{ - emit urlChangeRequested(url); -} - -void DolphinViewController::setItemView(QAbstractItemView* view) -{ - if (m_itemView != 0) { - disconnect(m_itemView, SIGNAL(pressed(const QModelIndex&)), - this, SLOT(updateMouseButtonState())); - } - - m_itemView = view; - - if (m_itemView != 0) { - // TODO: this is a workaround until Qt-issue 176832 has been fixed - connect(m_itemView, SIGNAL(pressed(const QModelIndex&)), - this, SLOT(updateMouseButtonState())); - } -} - -QAbstractItemView* DolphinViewController::itemView() const -{ - return m_itemView; -} - -void DolphinViewController::triggerContextMenuRequest(const QPoint& pos, - const QList& customActions) -{ - emit activated(); - emit requestContextMenu(pos, customActions); -} - -void DolphinViewController::requestActivation() -{ - emit activated(); -} - -void DolphinViewController::indicateDroppedUrls(const KFileItem& destItem, - const KUrl& destPath, - QDropEvent* event) -{ - emit urlsDropped(destItem, destPath, event); -} - - -void DolphinViewController::indicateSortingChange(DolphinView::Sorting sorting) -{ - emit sortingChanged(sorting); -} - -void DolphinViewController::indicateSortOrderChange(Qt::SortOrder order) -{ - emit sortOrderChanged(order); -} - -void DolphinViewController::indicateSortFoldersFirstChange(bool foldersFirst) -{ - emit sortFoldersFirstChanged(foldersFirst); -} - -void DolphinViewController::indicateAdditionalInfoChange(const KFileItemDelegate::InformationList& info) -{ - emit additionalInfoChanged(info); -} - -void DolphinViewController::setVersionControlActions(QList actions) -{ - m_versionControlActions = actions; -} - -QList DolphinViewController::versionControlActions(const KFileItemList& items) -{ - emit requestVersionControlActions(items); - // All view implementations are connected with the signal requestVersionControlActions() - // (see ViewExtensionFactory) and will invoke DolphinViewController::setVersionControlActions(), - // so that the context dependent actions can be returned. - return m_versionControlActions; -} - -void DolphinViewController::handleKeyPressEvent(QKeyEvent* event) -{ - Q_ASSERT(m_itemView != 0); - - const QItemSelectionModel* selModel = m_itemView->selectionModel(); - const QModelIndex currentIndex = selModel->currentIndex(); - const bool trigger = currentIndex.isValid() - && ((event->key() == Qt::Key_Return) || (event->key() == Qt::Key_Enter)) - && !selModel->selectedIndexes().isEmpty(); - if (!trigger) { - return; - } - - // Collect the non-directory files into a list and - // call runPreferredApplications for that list. - // Several selected directories are opened in separate tabs, - // one selected directory will get opened in the view. - QModelIndexList dirQueue; - const QModelIndexList indexList = selModel->selectedIndexes(); - KFileItemList fileOpenList; - foreach (const QModelIndex& index, indexList) { - if (itemForIndex(index).isDir()) { - dirQueue << index; - } else { - fileOpenList << itemForIndex(index); - } - } - - KFileItemActions fileItemActions; - fileItemActions.runPreferredApplications(fileOpenList, "DesktopEntryName != 'dolphin'"); - - if (dirQueue.length() == 1) { - // open directory in the view - emit itemTriggered(itemForIndex(dirQueue[0])); - } else { - // open directories in separate tabs - foreach(const QModelIndex& dir, dirQueue) { - emit tabRequested(itemForIndex(dir).url()); - } - } -} - -void DolphinViewController::replaceUrlByClipboard() -{ - const QClipboard* clipboard = QApplication::clipboard(); - QString text; - if (clipboard->mimeData(QClipboard::Selection)->hasText()) { - text = clipboard->mimeData(QClipboard::Selection)->text(); - } else if (clipboard->mimeData(QClipboard::Clipboard)->hasText()) { - text = clipboard->mimeData(QClipboard::Clipboard)->text(); - } - if (!text.isEmpty() && QDir::isAbsolutePath(text)) { - m_dolphinView->setUrl(KUrl(text)); - } -} - -void DolphinViewController::requestToolTipHiding() -{ - emit hideToolTip(); -} - -void DolphinViewController::emitItemTriggered(const KFileItem& item) -{ - emit itemTriggered(item); -} - -KFileItem DolphinViewController::itemForIndex(const QModelIndex& index) const -{ - Q_ASSERT(m_itemView != 0); - - QAbstractProxyModel* proxyModel = static_cast(m_itemView->model()); - KDirModel* dirModel = static_cast(proxyModel->sourceModel()); - const QModelIndex dirIndex = proxyModel->mapToSource(index); - return dirModel->itemForIndex(dirIndex); -} - -void DolphinViewController::triggerItem(const QModelIndex& index) -{ - if (m_mouseButtons & Qt::LeftButton) { - const KFileItem item = itemForIndex(index); - if (index.isValid() && (index.column() == KDirModel::Name)) { - emit itemTriggered(item); - } else { - m_itemView->clearSelection(); - emit itemEntered(KFileItem()); - } - } -} - -void DolphinViewController::requestTab(const QModelIndex& index) -{ - if (m_mouseButtons & Qt::MidButton) { - const KFileItem item = itemForIndex(index); - const bool validRequest = index.isValid() && - (index.column() == KDirModel::Name) && - (item.isDir() || m_dolphinView->isTabsForFilesEnabled()); - if (validRequest) { - emit tabRequested(item.url()); - } - } -} - -void DolphinViewController::emitItemEntered(const QModelIndex& index) -{ - KFileItem item = itemForIndex(index); - if (!item.isNull()) { - emit itemEntered(item); - } -} - -void DolphinViewController::emitViewportEntered() -{ - emit viewportEntered(); -} - -void DolphinViewController::updateMouseButtonState() -{ - m_mouseButtons = QApplication::mouseButtons(); -} - -#include "dolphinviewcontroller.moc" diff --git a/src/dolphinviewcontroller.h b/src/dolphinviewcontroller.h deleted file mode 100644 index 848110770..000000000 --- a/src/dolphinviewcontroller.h +++ /dev/null @@ -1,314 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2010 by Peter Penz * - * * - * 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 DOLPHINVIEWCONTROLLER_H -#define DOLPHINVIEWCONTROLLER_H - -#include -#include -#include -#include - -class QAbstractItemView; -class DolphinView; -class KUrl; -class QPoint; - -/** - * @brief Allows the view mode implementations (DolphinIconsView, DolphinDetailsView, DolphinColumnView) - * to do a limited control of the DolphinView. - * - * The DolphinView connects to the signals of DolphinViewController to react on changes - * that have been triggered by the view mode implementations. The view mode implementations - * have read access to the whole DolphinView by DolphinViewController::view(). Limited control of the - * DolphinView by the view mode implementations are defined by the public DolphinController methods. - */ -class LIBDOLPHINPRIVATE_EXPORT DolphinViewController : public QObject -{ - Q_OBJECT - -public: - explicit DolphinViewController(DolphinView* dolphinView); - virtual ~DolphinViewController(); - - /** - * Allows read access for the view mode implementation - * to the DolphinView. - */ - const DolphinView* view() const; - - /** - * Requests the DolphinView to change the URL to \p url. The signal - * urlChangeRequested will be emitted. - */ - void requestUrlChange(const KUrl& url); - - /** - * Changes the current view mode implementation where the controller is working. - * This is only necessary for views like the tree view, where internally - * several QAbstractItemView instances are used. - */ - void setItemView(QAbstractItemView* view); - QAbstractItemView* itemView() const; - - /** - * Requests a context menu for the position \a pos. DolphinView - * takes care itself to get the selected items depending from - * \a pos. It is possible to define a custom list of actions for - * the context menu by \a customActions. - */ - void triggerContextMenuRequest(const QPoint& pos, - const QList& customActions = QList()); - - /** - * Requests an activation of the DolphinView and emits the signal - * activated(). This method should be invoked by the view mode implementation - * if e. g. a mouse click on the view has been done. - */ - void requestActivation(); - - /** - * Indicates that URLs are dropped above a destination. The DolphinView - * will start the corresponding action (copy, move, link). - * @param destItem Item of the destination (can be null, see KFileItem::isNull()). - * @param destPath Path of the destination. - * @param event Drop event - */ - void indicateDroppedUrls(const KFileItem& destItem, - const KUrl& destPath, - QDropEvent* event); - - /** - * Informs the DolphinView about a sorting change done inside - * the view mode implementation. - */ - void indicateSortingChange(DolphinView::Sorting sorting); - - /** - * Informs the DolphinView about a sort order change done inside - * the view mode implementation. - */ - void indicateSortOrderChange(Qt::SortOrder order); - - /** - * Informs the DolphinView about a change between separate sorting - * (with folders first) and mixed sorting of files and folders done inside - * the view mode implementation. - */ - void indicateSortFoldersFirstChange(bool foldersFirst); - - /** - * Informs the DolphinView about an additional information change - * done inside the view mode implementation. - */ - void indicateAdditionalInfoChange(const KFileItemDelegate::InformationList& info); - - /** - * Sets the available version control actions. Is called by the view - * mode implementation as soon as the DolphinView has requested them by the signal - * requestVersionControlActions(). - */ - void setVersionControlActions(QList actions); - - /** - * Emits the signal requestVersionControlActions(). The view mode implementation - * listens to the signal and will invoke a DolphinViewController::setVersionControlActions() - * and the result will be returned. - */ - QList versionControlActions(const KFileItemList& items); - - /** - * Must be be invoked in each view mode implementation whenever a key has been - * pressed. If the selection model of \a view is not empty and - * the return key has been pressed, the selected items will get triggered. - */ - void handleKeyPressEvent(QKeyEvent* event); - - /** - * Replaces the URL of the DolphinView with the content - * of the clipboard as URL. If the clipboard contains no text, - * nothing will be done. - */ - void replaceUrlByClipboard(); - - /** - * Requests the view mode implementation to hide tooltips. - */ - void requestToolTipHiding(); - - /** - * Emits the signal itemTriggered() for the item \a item. - * The method can be used by the view mode implementations to - * trigger an item directly without mouse interaction. - * If the item triggering is done by the mouse, it is recommended - * to use DolphinViewController::triggerItem(), as this will check - * the used mouse buttons to execute the correct action. - */ - void emitItemTriggered(const KFileItem& item); - - /** - * Returns the file item for the proxy index \a index of the DolphinView. - */ - KFileItem itemForIndex(const QModelIndex& index) const; - -public slots: - /** - * Emits the signal itemTriggered() if the file item for the index \a index - * is not null and the left mouse button has been pressed. If the item is - * null, the signal itemEntered() is emitted. - * The method should be invoked by the view mode implementations whenever the - * user has triggered an item with the mouse (see - * QAbstractItemView::clicked() or QAbstractItemView::doubleClicked()). - */ - void triggerItem(const QModelIndex& index); - - /** - * Emits the signal tabRequested(), if the file item for the index \a index - * represents a directory and when the middle mouse button has been pressed. - */ - void requestTab(const QModelIndex& index); - - /** - * Emits the signal itemEntered() if the file item for the index \a index - * is not null. The method should be invoked by the view mode implementation - * whenever the mouse cursor is above an item. - */ - void emitItemEntered(const QModelIndex& index); - - /** - * Emits the signal viewportEntered(). The method should be invoked by - * the view mode implementation whenever the mouse cursor is above the viewport. - */ - void emitViewportEntered(); - -signals: - void urlChangeRequested(const KUrl& url); - - /** - * Is emitted if a context menu should be opened (see triggerContextMenuRequest()). - * @param pos Position relative to the view widget where the - * context menu should be opened. It is recommended - * to get the corresponding model index from - * this position. - * @param customActions List of actions that is added to the context menu when - * the menu is opened above the viewport. - */ - void requestContextMenu(const QPoint& pos, QList customActions); - - /** - * Is emitted if the view has been activated by e. g. a mouse click. - */ - void activated(); - - /** - * Is emitted if URLs have been dropped to the destination - * path \a destPath. If the URLs have been dropped above an item of - * the destination path, the item is indicated by \a destItem - * (can be null, see KFileItem::isNull()). - */ - void urlsDropped(const KFileItem& destItem, - const KUrl& destPath, - QDropEvent* event); - - /** - * Is emitted if the sorting has been changed to \a sorting by - * the view mode implementation (see indicateSortingChanged(). - * The DolphinView connects to - * this signal to update its menu action. - */ - void sortingChanged(DolphinView::Sorting sorting); - - /** - * Is emitted if the sort order has been changed to \a order - * by the view mode implementation (see indicateSortOrderChanged(). - * The DolphinView connects - * to this signal to update its menu actions. - */ - void sortOrderChanged(Qt::SortOrder order); - - /** - * Is emitted if 'sort folders first' has been changed to \a foldersFirst - * by the view mode implementation (see indicateSortOrderChanged(). - * The DolphinView connects - * to this signal to update its menu actions. - */ - void sortFoldersFirstChanged(bool foldersFirst); - - /** - * Is emitted if the additional info has been changed to \a info - * by the view mode implementation. The DolphinView connects - * to this signal to update its menu actions. - */ - void additionalInfoChanged(const KFileItemDelegate::InformationList& info); - - /** - * Is emitted if the item \a item should be triggered. The abstract - * Dolphin view connects to this signal. If the item represents a directory, - * the directory is opened. On a file the corresponding application is opened. - * The item is null (see KFileItem::isNull()), when clicking on the viewport itself. - */ - void itemTriggered(const KFileItem& item); - - /** - * Is emitted if the mouse cursor has entered the item - * given by \a index (see emitItemEntered()). - */ - void itemEntered(const KFileItem& item); - - /** - * Is emitted if a new tab should be opened for the URL \a url. - */ - void tabRequested(const KUrl& url); - - /** - * Is emitted if the mouse cursor has entered - * the viewport (see emitViewportEntered()). - */ - void viewportEntered(); - - /** - * Is emitted, if DolphinViewController::requestToolTipHiding() is invoked - * and requests to hide all tooltips. - */ - void hideToolTip(); - - /** - * Is emitted if pending previews should be canceled (e. g. because of an URL change). - */ - void cancelPreviews(); - - /** - * Requests the view mode implementation to invoke DolphinViewController::setVersionControlActions(), - * so that they can be returned with DolphinViewController::versionControlActions() for - * the DolphinView. - */ - void requestVersionControlActions(const KFileItemList& items); - -private slots: - void updateMouseButtonState(); - -private: - static Qt::MouseButtons m_mouseButtons; // TODO: this is a workaround until Qt-issue 176832 has been fixed - - DolphinView* m_dolphinView; - QAbstractItemView* m_itemView; - QList m_versionControlActions; -}; - -#endif diff --git a/src/draganddrophelper.cpp b/src/draganddrophelper.cpp index 88dca9b40..0cca59ac4 100644 --- a/src/draganddrophelper.cpp +++ b/src/draganddrophelper.cpp @@ -19,8 +19,6 @@ ***************************************************************************/ #include "draganddrophelper.h" -#include "dolphiniconsview.h" -#include "dolphinviewcontroller.h" #include #include @@ -28,6 +26,9 @@ #include #include +#include "views/dolphiniconsview.h" +#include "views/dolphinviewcontroller.h" + #include #include #include diff --git a/src/filterbar.cpp b/src/filterbar.cpp deleted file mode 100644 index b108570ce..000000000 --- a/src/filterbar.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/*************************************************************************** - * 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 "filterbar.h" - -#include -#include -#include -#include - -#include -#include -#include -#include - -FilterBar::FilterBar(QWidget* parent) : - QWidget(parent) -{ - // Create close button - QToolButton *closeButton = new QToolButton(this); - closeButton->setAutoRaise(true); - closeButton->setIcon(KIcon("dialog-close")); - closeButton->setToolTip(i18nc("@info:tooltip", "Hide Filter Bar")); - connect(closeButton, SIGNAL(clicked()), this, SIGNAL(closeRequest())); - - // Create label - QLabel* filterLabel = new QLabel(i18nc("@label:textbox", "Filter:"), this); - - // Create filter editor - m_filterInput = new KLineEdit(this); - m_filterInput->setLayoutDirection(Qt::LeftToRight); - m_filterInput->setClearButtonShown(true); - connect(m_filterInput, SIGNAL(textChanged(const QString&)), - this, SIGNAL(filterChanged(const QString&))); - - // Apply layout - QHBoxLayout* hLayout = new QHBoxLayout(this); - hLayout->setMargin(0); - hLayout->addWidget(closeButton); - hLayout->addWidget(filterLabel); - hLayout->addWidget(m_filterInput); - - filterLabel->setBuddy(m_filterInput); -} - -FilterBar::~FilterBar() -{ -} - -void FilterBar::clear() -{ - m_filterInput->clear(); -} - -void FilterBar::showEvent(QShowEvent* event) -{ - if (!event->spontaneous()) { - m_filterInput->setFocus(); - } -} - -void FilterBar::keyReleaseEvent(QKeyEvent* event) -{ - QWidget::keyReleaseEvent(event); - if ((event->key() == Qt::Key_Escape)) { - if (m_filterInput->text().isEmpty()) { - emit closeRequest(); - } else { - m_filterInput->clear(); - } - } -} - -#include "filterbar.moc" diff --git a/src/filterbar.h b/src/filterbar.h deleted file mode 100644 index bf1bce684..000000000 --- a/src/filterbar.h +++ /dev/null @@ -1,65 +0,0 @@ -/*************************************************************************** - * 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 * - ***************************************************************************/ -#ifndef FILTERBAR_H -#define FILTERBAR_H - -#include - -class KLineEdit; - -/** - * @brief Provides an input field for filtering the currently shown items. - * - * @author Gregor Kališnik - * @author Peter Penz - */ -class FilterBar : public QWidget -{ - Q_OBJECT - -public: - FilterBar(QWidget* parent = 0); - virtual ~FilterBar(); - -public slots: - /** Clears the input field. */ - void clear(); - -signals: - /** - * Signal that reports the name filter has been - * changed to \a nameFilter. - */ - void filterChanged(const QString& nameFilter); - - /** - * Emitted as soon as the filterbar should get closed. - */ - void closeRequest(); - -protected: - virtual void showEvent(QShowEvent* event); - virtual void keyReleaseEvent(QKeyEvent* event); - -private: - KLineEdit* m_filterInput; -}; - -#endif diff --git a/src/filterbar/filterbar.cpp b/src/filterbar/filterbar.cpp new file mode 100644 index 000000000..b108570ce --- /dev/null +++ b/src/filterbar/filterbar.cpp @@ -0,0 +1,90 @@ +/*************************************************************************** + * 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 "filterbar.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +FilterBar::FilterBar(QWidget* parent) : + QWidget(parent) +{ + // Create close button + QToolButton *closeButton = new QToolButton(this); + closeButton->setAutoRaise(true); + closeButton->setIcon(KIcon("dialog-close")); + closeButton->setToolTip(i18nc("@info:tooltip", "Hide Filter Bar")); + connect(closeButton, SIGNAL(clicked()), this, SIGNAL(closeRequest())); + + // Create label + QLabel* filterLabel = new QLabel(i18nc("@label:textbox", "Filter:"), this); + + // Create filter editor + m_filterInput = new KLineEdit(this); + m_filterInput->setLayoutDirection(Qt::LeftToRight); + m_filterInput->setClearButtonShown(true); + connect(m_filterInput, SIGNAL(textChanged(const QString&)), + this, SIGNAL(filterChanged(const QString&))); + + // Apply layout + QHBoxLayout* hLayout = new QHBoxLayout(this); + hLayout->setMargin(0); + hLayout->addWidget(closeButton); + hLayout->addWidget(filterLabel); + hLayout->addWidget(m_filterInput); + + filterLabel->setBuddy(m_filterInput); +} + +FilterBar::~FilterBar() +{ +} + +void FilterBar::clear() +{ + m_filterInput->clear(); +} + +void FilterBar::showEvent(QShowEvent* event) +{ + if (!event->spontaneous()) { + m_filterInput->setFocus(); + } +} + +void FilterBar::keyReleaseEvent(QKeyEvent* event) +{ + QWidget::keyReleaseEvent(event); + if ((event->key() == Qt::Key_Escape)) { + if (m_filterInput->text().isEmpty()) { + emit closeRequest(); + } else { + m_filterInput->clear(); + } + } +} + +#include "filterbar.moc" diff --git a/src/filterbar/filterbar.h b/src/filterbar/filterbar.h new file mode 100644 index 000000000..bf1bce684 --- /dev/null +++ b/src/filterbar/filterbar.h @@ -0,0 +1,65 @@ +/*************************************************************************** + * 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 * + ***************************************************************************/ +#ifndef FILTERBAR_H +#define FILTERBAR_H + +#include + +class KLineEdit; + +/** + * @brief Provides an input field for filtering the currently shown items. + * + * @author Gregor Kališnik + * @author Peter Penz + */ +class FilterBar : public QWidget +{ + Q_OBJECT + +public: + FilterBar(QWidget* parent = 0); + virtual ~FilterBar(); + +public slots: + /** Clears the input field. */ + void clear(); + +signals: + /** + * Signal that reports the name filter has been + * changed to \a nameFilter. + */ + void filterChanged(const QString& nameFilter); + + /** + * Emitted as soon as the filterbar should get closed. + */ + void closeRequest(); + +protected: + virtual void showEvent(QShowEvent* event); + virtual void keyReleaseEvent(QKeyEvent* event); + +private: + KLineEdit* m_filterInput; +}; + +#endif diff --git a/src/panels/folders/folderspanel.cpp b/src/panels/folders/folderspanel.cpp index 0542665d5..fb1b84fa7 100644 --- a/src/panels/folders/folderspanel.cpp +++ b/src/panels/folders/folderspanel.cpp @@ -21,7 +21,6 @@ #include "dolphinmodel.h" #include "dolphinsortfilterproxymodel.h" -#include "dolphinview.h" #include "settings/dolphinsettings.h" #include "dolphin_folderspanelsettings.h" #include "dolphin_generalsettings.h" @@ -44,6 +43,8 @@ #include #include +#include "views/dolphinview.h" + FoldersPanel::FoldersPanel(QWidget* parent) : Panel(parent), m_setLeafVisible(false), diff --git a/src/panels/folders/paneltreeview.cpp b/src/panels/folders/paneltreeview.cpp index 58866d6c3..69cf46cd6 100644 --- a/src/panels/folders/paneltreeview.cpp +++ b/src/panels/folders/paneltreeview.cpp @@ -19,12 +19,11 @@ #include "paneltreeview.h" -#include "dolphinviewcontroller.h" #include "dolphinmodel.h" #include "draganddrophelper.h" -#include "viewmodecontroller.h" #include +#include #include #include #include diff --git a/src/selectionmanager.cpp b/src/selectionmanager.cpp deleted file mode 100644 index 0d3efae09..000000000 --- a/src/selectionmanager.cpp +++ /dev/null @@ -1,186 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Peter Penz * - * * - * 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 "selectionmanager.h" - -#include "dolphinmodel.h" -#include "selectiontoggle.h" -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -SelectionManager::SelectionManager(QAbstractItemView* parent) : - QObject(parent), - m_view(parent), - m_toggle(0), - m_connected(false) -{ - connect(parent, SIGNAL(entered(const QModelIndex&)), - this, SLOT(slotEntered(const QModelIndex&))); - connect(parent, SIGNAL(viewportEntered()), - this, SLOT(slotViewportEntered())); - m_toggle = new SelectionToggle(m_view->viewport()); - m_toggle->setCheckable(true); - m_toggle->hide(); - connect(m_toggle, SIGNAL(clicked(bool)), - this, SLOT(setItemSelected(bool))); -} - -SelectionManager::~SelectionManager() -{ -} - -void SelectionManager::reset() -{ - m_toggle->reset(); -} - -void SelectionManager::slotEntered(const QModelIndex& index) -{ - m_toggle->hide(); - const bool showToggle = index.isValid() && - (index.column() == DolphinModel::Name) && - (QApplication::mouseButtons() == Qt::NoButton); - if (showToggle) { - m_toggle->setUrl(urlForIndex(index)); - - if (!m_connected) { - connect(m_view->model(), SIGNAL(rowsRemoved(const QModelIndex&, int, int)), - this, SLOT(slotRowsRemoved(const QModelIndex&, int, int))); - connect(m_view->selectionModel(), - SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), - this, - SLOT(slotSelectionChanged(const QItemSelection&, const QItemSelection&))); - m_connected = true; - } - - // increase the size of the toggle for large items - const int height = m_view->iconSize().height(); - if (height >= KIconLoader::SizeEnormous) { - m_toggle->resize(KIconLoader::SizeMedium, KIconLoader::SizeMedium); - } else if (height >= KIconLoader::SizeLarge) { - m_toggle->resize(KIconLoader::SizeSmallMedium, KIconLoader::SizeSmallMedium); - } else { - m_toggle->resize(KIconLoader::SizeSmall, KIconLoader::SizeSmall); - } - - const QRect rect = m_view->visualRect(index); - int x = rect.left(); - int y = rect.top(); - if (height < KIconLoader::SizeSmallMedium) { - // The height is nearly equal to the smallest toggle height. - // Assure that the toggle is vertically centered instead - // of aligned on the top and gets more horizontal gap. - x += 2; - y += (rect.height() - m_toggle->height()) / 2; - } - m_toggle->move(QPoint(x, y)); - - QItemSelectionModel* selModel = m_view->selectionModel(); - m_toggle->setChecked(selModel->isSelected(index)); - m_toggle->show(); - } else { - m_toggle->setUrl(KUrl()); - disconnect(m_view->model(), SIGNAL(rowsRemoved(const QModelIndex&, int, int)), - this, SLOT(slotRowsRemoved(const QModelIndex&, int, int))); - disconnect(m_view->selectionModel(), - SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), - this, - SLOT(slotSelectionChanged(const QItemSelection&, const QItemSelection&))); - m_connected = false; - } -} - -void SelectionManager::slotViewportEntered() -{ - m_toggle->hide(); -} - -void SelectionManager::setItemSelected(bool selected) -{ - emit selectionChanged(); - - if (!m_toggle->url().isEmpty()) { - const QModelIndex index = indexForUrl(m_toggle->url()); - if (index.isValid()) { - QItemSelectionModel* selModel = m_view->selectionModel(); - if (selected) { - selModel->select(index, QItemSelectionModel::Select); - } else { - selModel->select(index, QItemSelectionModel::Deselect); - } - selModel->setCurrentIndex(index, QItemSelectionModel::Current); - } - } -} - -void SelectionManager::slotRowsRemoved(const QModelIndex& parent, int start, int end) -{ - Q_UNUSED(parent); - Q_UNUSED(start); - Q_UNUSED(end); - m_toggle->hide(); -} - -void SelectionManager::slotSelectionChanged(const QItemSelection& selected, - const QItemSelection& deselected) -{ - // The selection has been changed outside the scope of the selection manager - // (e. g. by the rubberband or the "Select All" action). Take care updating - // the state of the toggle button. - if (!m_toggle->url().isEmpty()) { - const QModelIndex index = indexForUrl(m_toggle->url()); - if (index.isValid()) { - if (selected.contains(index)) { - m_toggle->setChecked(true); - } - - if (deselected.contains(index)) { - m_toggle->setChecked(false); - } - } - } -} - -KUrl SelectionManager::urlForIndex(const QModelIndex& index) const -{ - QAbstractProxyModel* proxyModel = static_cast(m_view->model()); - KDirModel* dirModel = static_cast(proxyModel->sourceModel()); - const QModelIndex dirIndex = proxyModel->mapToSource(index); - return dirModel->itemForIndex(dirIndex).url(); -} - -const QModelIndex SelectionManager::indexForUrl(const KUrl& url) const -{ - QAbstractProxyModel* proxyModel = static_cast(m_view->model()); - KDirModel* dirModel = static_cast(proxyModel->sourceModel()); - const QModelIndex dirIndex = dirModel->indexForUrl(url); - return proxyModel->mapFromSource(dirIndex); -} - -#include "selectionmanager.moc" diff --git a/src/selectionmanager.h b/src/selectionmanager.h deleted file mode 100644 index c2fcc88b4..000000000 --- a/src/selectionmanager.h +++ /dev/null @@ -1,74 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Peter Penz * - * * - * 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 SELECTIONMANAGER_H -#define SELECTIONMANAGER_H - -#include - -#include - -class QAbstractItemView; -class QModelIndex; -class QItemSelection; -class SelectionToggle; - -/** - * @brief Allows to select and deselect items for item views. - * - * Whenever an item is hovered by the mouse, a toggle button is shown - * which allows to select/deselect the current item. - */ -class SelectionManager : public QObject -{ - Q_OBJECT - -public: - SelectionManager(QAbstractItemView* parent); - virtual ~SelectionManager(); - -public slots: - /** - * Resets the selection manager so that the toggle button gets - * invisible. - */ - void reset(); - -signals: - /** Is emitted if the selection has been changed by the toggle button. */ - void selectionChanged(); - -private slots: - void slotEntered(const QModelIndex& index); - void slotViewportEntered(); - void setItemSelected(bool selected); - void slotRowsRemoved(const QModelIndex& parent, int start, int end); - void slotSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected); - -private: - KUrl urlForIndex(const QModelIndex& index) const; - const QModelIndex indexForUrl(const KUrl& url) const; - -private: - QAbstractItemView* m_view; - SelectionToggle* m_toggle; - bool m_connected; -}; - -#endif diff --git a/src/selectiontoggle.cpp b/src/selectiontoggle.cpp deleted file mode 100644 index 6608b5821..000000000 --- a/src/selectiontoggle.cpp +++ /dev/null @@ -1,233 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Peter Penz * - * * - * 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 "selectiontoggle.h" - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -SelectionToggle::SelectionToggle(QWidget* parent) : - QAbstractButton(parent), - m_isHovered(false), - m_leftMouseButtonPressed(false), - m_fadingValue(0), - m_icon(), - m_fadingTimeLine(0) -{ - setFocusPolicy(Qt::NoFocus); - parent->installEventFilter(this); - resize(sizeHint()); - setIconOverlay(isChecked()); - connect(this, SIGNAL(toggled(bool)), - this, SLOT(setIconOverlay(bool))); - connect(KGlobalSettings::self(), SIGNAL(iconChanged(int)), - this, SLOT(refreshIcon())); -} - -SelectionToggle::~SelectionToggle() -{ -} - -QSize SelectionToggle::sizeHint() const -{ - return QSize(16, 16); -} - -void SelectionToggle::reset() -{ - m_url = KUrl(); - hide(); -} - -void SelectionToggle::setUrl(const KUrl& url) -{ - m_url = url; - if (!url.isEmpty()) { - startFading(); - } -} - -KUrl SelectionToggle::url() const -{ - return m_url; -} - -void SelectionToggle::setVisible(bool visible) -{ - QAbstractButton::setVisible(visible); - - stopFading(); - if (visible) { - startFading(); - } - -} - -bool SelectionToggle::eventFilter(QObject* obj, QEvent* event) -{ - if (obj == parent()) { - switch (event->type()) { - case QEvent::Leave: - hide(); - break; - - case QEvent::MouseMove: - if (m_leftMouseButtonPressed) { - // Don't forward mouse move events to the viewport, - // otherwise a rubberband selection will be shown when - // clicking on the selection toggle and moving the mouse - // above the viewport. - return true; - } - break; - - default: - break; - } - } - - return QAbstractButton::eventFilter(obj, event); -} - -void SelectionToggle::enterEvent(QEvent* event) -{ - QAbstractButton::enterEvent(event); - - // if the mouse cursor is above the selection toggle, display - // it immediately without fading timer - m_isHovered = true; - if (m_fadingTimeLine != 0) { - m_fadingTimeLine->stop(); - } - m_fadingValue = 255; - setToolTip(isChecked() ? i18nc("@info:tooltip", "Deselect Item") : - i18nc("@info:tooltip", "Select Item")); - update(); -} - -void SelectionToggle::leaveEvent(QEvent* event) -{ - QAbstractButton::leaveEvent(event); - m_isHovered = false; - update(); -} - -void SelectionToggle::mousePressEvent(QMouseEvent* event) -{ - QAbstractButton::mousePressEvent(event); - m_leftMouseButtonPressed = (event->buttons() & Qt::LeftButton); -} - -void SelectionToggle::mouseReleaseEvent(QMouseEvent* event) -{ - QAbstractButton::mouseReleaseEvent(event); - m_leftMouseButtonPressed = (event->buttons() & Qt::LeftButton); -} - -void SelectionToggle::resizeEvent(QResizeEvent* event) -{ - QAbstractButton::resizeEvent(event); - setIconOverlay(isChecked()); -} - -void SelectionToggle::paintEvent(QPaintEvent* event) -{ - QPainter painter(this); - painter.setClipRect(event->rect()); - - // draw the icon overlay - if (m_isHovered) { - KIconEffect iconEffect; - QPixmap activeIcon = iconEffect.apply(m_icon, KIconLoader::Desktop, KIconLoader::ActiveState); - painter.drawPixmap(0, 0, activeIcon); - } else { - if (m_fadingValue < 255) { - // apply an alpha mask respecting the fading value to the icon - QPixmap icon = m_icon; - QPixmap alphaMask(icon.width(), icon.height()); - const QColor color(m_fadingValue, m_fadingValue, m_fadingValue); - alphaMask.fill(color); - icon.setAlphaChannel(alphaMask); - painter.drawPixmap(0, 0, icon); - } else { - // no fading is required - painter.drawPixmap(0, 0, m_icon); - } - } -} - -void SelectionToggle::setFadingValue(int value) -{ - m_fadingValue = value; - if (m_fadingValue >= 255) { - Q_ASSERT(m_fadingTimeLine != 0); - m_fadingTimeLine->stop(); - } - update(); -} - -void SelectionToggle::setIconOverlay(bool checked) -{ - const char* icon = checked ? "list-remove" : "list-add"; - m_icon = KIconLoader::global()->loadIcon(icon, - KIconLoader::NoGroup, - qMin(width(), height())); - update(); -} - -void SelectionToggle::refreshIcon() -{ - setIconOverlay(isChecked()); -} - -void SelectionToggle::startFading() -{ - Q_ASSERT(m_fadingTimeLine == 0); - - const bool animate = KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects; - const int duration = animate ? 600 : 1; - - m_fadingTimeLine = new QTimeLine(duration, this); - connect(m_fadingTimeLine, SIGNAL(frameChanged(int)), - this, SLOT(setFadingValue(int))); - m_fadingTimeLine->setFrameRange(0, 255); - m_fadingTimeLine->start(); - m_fadingValue = 0; -} - -void SelectionToggle::stopFading() -{ - if (m_fadingTimeLine != 0) { - m_fadingTimeLine->stop(); - delete m_fadingTimeLine; - m_fadingTimeLine = 0; - } - m_fadingValue = 0; -} - -#include "selectiontoggle.moc" diff --git a/src/selectiontoggle.h b/src/selectiontoggle.h deleted file mode 100644 index 5519272b3..000000000 --- a/src/selectiontoggle.h +++ /dev/null @@ -1,91 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Peter Penz * - * * - * 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 SELECTIONTOGGLE_H -#define SELECTIONTOGGLE_H - -#include - -#include -#include - -class QTimeLine; - -/** - * @brief Toggle button for changing the selection of an hovered item. - * - * The toggle button is visually invisible until it is displayed at least - * for one second. - * - * @see SelectionManager - */ -class SelectionToggle : public QAbstractButton -{ - Q_OBJECT - -public: - explicit SelectionToggle(QWidget* parent); - virtual ~SelectionToggle(); - virtual QSize sizeHint() const; - - /** - * Resets the selection toggle so that it is hidden and stays - * visually invisible for at least one second after it is shown again. - */ - void reset(); - - void setUrl(const KUrl& url); - KUrl url() const; - -public slots: - virtual void setVisible(bool visible); - -protected: - virtual bool eventFilter(QObject* obj, QEvent* event); - virtual void enterEvent(QEvent* event); - virtual void leaveEvent(QEvent* event); - virtual void mousePressEvent(QMouseEvent* event); - virtual void mouseReleaseEvent(QMouseEvent* event); - virtual void resizeEvent(QResizeEvent* event); - virtual void paintEvent(QPaintEvent* event); - -private slots: - /** - * Sets the alpha value for the fading animation and is - * connected with m_fadingTimeLine. - */ - void setFadingValue(int value); - - void setIconOverlay(bool checked); - void refreshIcon(); - -private: - void startFading(); - void stopFading(); - -private: - bool m_isHovered; - bool m_leftMouseButtonPressed; - int m_fadingValue; - QPixmap m_icon; - QTimeLine* m_fadingTimeLine; - KUrl m_url; -}; - -#endif diff --git a/src/settings/dolphin_directoryviewpropertysettings.kcfgc b/src/settings/dolphin_directoryviewpropertysettings.kcfgc index 753642f8c..b938ab3e4 100644 --- a/src/settings/dolphin_directoryviewpropertysettings.kcfgc +++ b/src/settings/dolphin_directoryviewpropertysettings.kcfgc @@ -3,4 +3,4 @@ Singleton=false ClassName=ViewPropertySettings Mutators=true GlobalEnums=true -IncludeFiles=dolphinview.h,qnamespace.h +IncludeFiles=views/dolphinview.h,qnamespace.h diff --git a/src/settings/startup/startupsettingspage.cpp b/src/settings/startup/startupsettingspage.cpp index 1e1c6ed87..d891558e1 100644 --- a/src/settings/startup/startupsettingspage.cpp +++ b/src/settings/startup/startupsettingspage.cpp @@ -21,7 +21,6 @@ #include "settings/dolphinsettings.h" #include "dolphinmainwindow.h" -#include "dolphinview.h" #include "dolphinviewcontainer.h" #include "dolphin_generalsettings.h" @@ -39,6 +38,8 @@ #include #include +#include "views/dolphinview.h" + StartupSettingsPage::StartupSettingsPage(const KUrl& url, QWidget* parent) : SettingsPageBase(parent), m_url(url), diff --git a/src/settings/viewmodes/columnviewsettingspage.cpp b/src/settings/viewmodes/columnviewsettingspage.cpp index aac28f0fd..2a6265f2f 100644 --- a/src/settings/viewmodes/columnviewsettingspage.cpp +++ b/src/settings/viewmodes/columnviewsettingspage.cpp @@ -22,7 +22,6 @@ #include "dolphinfontrequester.h" #include #include "iconsizegroupbox.h" -#include "zoomlevelinfo.h" #include #include @@ -38,6 +37,8 @@ #include #include +#include + ColumnViewSettingsPage::ColumnViewSettingsPage(QWidget* parent) : ViewSettingsPageBase(parent), m_iconSizeGroupBox(0), diff --git a/src/settings/viewmodes/detailsviewsettingspage.cpp b/src/settings/viewmodes/detailsviewsettingspage.cpp index 67cef32fe..253d12a79 100644 --- a/src/settings/viewmodes/detailsviewsettingspage.cpp +++ b/src/settings/viewmodes/detailsviewsettingspage.cpp @@ -22,7 +22,6 @@ #include "iconsizegroupbox.h" #include "dolphinfontrequester.h" #include "dolphin_detailsmodesettings.h" -#include "zoomlevelinfo.h" #include #include @@ -36,7 +35,9 @@ #include #include #include -#include +#include + +#include DetailsViewSettingsPage::DetailsViewSettingsPage(QWidget* parent) : ViewSettingsPageBase(parent), diff --git a/src/settings/viewmodes/iconsizegroupbox.cpp b/src/settings/viewmodes/iconsizegroupbox.cpp index d8e0e889a..900c75b2c 100644 --- a/src/settings/viewmodes/iconsizegroupbox.cpp +++ b/src/settings/viewmodes/iconsizegroupbox.cpp @@ -29,7 +29,7 @@ #include #include -#include "zoomlevelinfo.h" +#include IconSizeGroupBox::IconSizeGroupBox(QWidget* parent) : QGroupBox(i18nc("@title:group", "Icon Size"), parent), diff --git a/src/settings/viewmodes/iconsviewsettingspage.cpp b/src/settings/viewmodes/iconsviewsettingspage.cpp index 059a4a846..a01b4a2db 100644 --- a/src/settings/viewmodes/iconsviewsettingspage.cpp +++ b/src/settings/viewmodes/iconsviewsettingspage.cpp @@ -22,7 +22,6 @@ #include "dolphinfontrequester.h" #include "settings/dolphinsettings.h" #include "iconsizegroupbox.h" -#include "zoomlevelinfo.h" #include "dolphin_iconsmodesettings.h" @@ -41,6 +40,8 @@ #include #include +#include + IconsViewSettingsPage::IconsViewSettingsPage(QWidget* parent) : ViewSettingsPageBase(parent), m_iconSizeGroupBox(0), diff --git a/src/settings/viewmodes/iconsviewsettingspage.h b/src/settings/viewmodes/iconsviewsettingspage.h index 17fda4e26..9a1a9e8b4 100644 --- a/src/settings/viewmodes/iconsviewsettingspage.h +++ b/src/settings/viewmodes/iconsviewsettingspage.h @@ -20,7 +20,7 @@ #ifndef ICONSVIEWSETTINGSPAGE_H #define ICONSVIEWSETTINGSPAGE_H -#include +#include #include "viewsettingspagebase.h" class DolphinFontRequester; diff --git a/src/settings/viewpropertiesdialog.cpp b/src/settings/viewpropertiesdialog.cpp index 3941a61cc..6e4efab1b 100644 --- a/src/settings/viewpropertiesdialog.cpp +++ b/src/settings/viewpropertiesdialog.cpp @@ -21,7 +21,7 @@ #include "viewpropertiesdialog.h" #include "additionalinfodialog.h" -#include "dolphinview.h" +#include "views/dolphinview.h" #include "settings/dolphinsettings.h" #include "dolphinsortfilterproxymodel.h" #include "dolphin_generalsettings.h" diff --git a/src/statusbar/dolphinstatusbar.cpp b/src/statusbar/dolphinstatusbar.cpp index 684a807b8..e08d94948 100644 --- a/src/statusbar/dolphinstatusbar.cpp +++ b/src/statusbar/dolphinstatusbar.cpp @@ -20,7 +20,6 @@ #include "dolphinstatusbar.h" -#include "dolphinview.h" #include "dolphin_generalsettings.h" #include @@ -41,7 +40,8 @@ #include #include -#include "zoomlevelinfo.h" +#include +#include DolphinStatusBar::DolphinStatusBar(QWidget* parent, DolphinView* view) : QWidget(parent), diff --git a/src/viewextensionsfactory.cpp b/src/viewextensionsfactory.cpp deleted file mode 100644 index e5638c03e..000000000 --- a/src/viewextensionsfactory.cpp +++ /dev/null @@ -1,244 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2009 by Peter Penz * - * * - * 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 "viewextensionsfactory.h" - -#include "dolphinfileitemdelegate.h" -#include "dolphinsortfilterproxymodel.h" -#include "dolphinview.h" -#include "dolphinviewcontroller.h" -#include "dolphinviewautoscroller.h" -#include "folderexpander.h" -#include "selectionmanager.h" -#include "settings/dolphinsettings.h" -#include "tooltips/tooltipmanager.h" -#include "versioncontrol/versioncontrolobserver.h" -#include "viewmodecontroller.h" - -#include "dolphin_generalsettings.h" - -#include -#include -#include -#include - -ViewExtensionsFactory::ViewExtensionsFactory(QAbstractItemView* view, - DolphinViewController* dolphinViewController, - const ViewModeController* viewModeController) : - QObject(view), - m_view(view), - m_dolphinViewController(dolphinViewController), - m_toolTipManager(0), - m_previewGenerator(0), - m_selectionManager(0), - m_autoScroller(0), - m_fileItemDelegate(0), - m_versionControlObserver(0) -{ - view->setSelectionMode(QAbstractItemView::ExtendedSelection); - - GeneralSettings* settings = DolphinSettings::instance().generalSettings(); - - // initialize tooltips - if (settings->showToolTips()) { - DolphinSortFilterProxyModel* proxyModel = static_cast(view->model()); - m_toolTipManager = new ToolTipManager(view, proxyModel); - - connect(dolphinViewController, SIGNAL(hideToolTip()), - m_toolTipManager, SLOT(hideTip())); - } - - // initialize preview generator - Q_ASSERT(view->iconSize().isValid()); - m_previewGenerator = new KFilePreviewGenerator(view); - m_previewGenerator->setPreviewShown(dolphinViewController->view()->showPreview()); - connect(viewModeController, SIGNAL(zoomLevelChanged(int)), - this, SLOT(slotZoomLevelChanged())); - connect(viewModeController, SIGNAL(cancelPreviews()), - this, SLOT(cancelPreviews())); - connect(dolphinViewController->view(), SIGNAL(showPreviewChanged()), - this, SLOT(slotShowPreviewChanged())); - - // initialize selection manager - if (settings->showSelectionToggle()) { - m_selectionManager = new SelectionManager(view); - connect(m_selectionManager, SIGNAL(selectionChanged()), - this, SLOT(requestActivation())); - connect(viewModeController, SIGNAL(urlChanged(const KUrl&)), - m_selectionManager, SLOT(reset())); - } - - // initialize auto scroller - m_autoScroller = new DolphinViewAutoScroller(view); - - // initialize file item delegate - m_fileItemDelegate = new DolphinFileItemDelegate(view); - m_fileItemDelegate->setShowToolTipWhenElided(false); - view->setItemDelegate(m_fileItemDelegate); - - // initialize version control observer - const DolphinView* dolphinView = dolphinViewController->view(); - m_versionControlObserver = new VersionControlObserver(view); - connect(m_versionControlObserver, SIGNAL(infoMessage(const QString&)), - dolphinView, SIGNAL(infoMessage(const QString&))); - connect(m_versionControlObserver, SIGNAL(errorMessage(const QString&)), - dolphinView, SIGNAL(errorMessage(const QString&))); - connect(m_versionControlObserver, SIGNAL(operationCompletedMessage(const QString&)), - dolphinView, SIGNAL(operationCompletedMessage(const QString&))); - connect(dolphinViewController, SIGNAL(requestVersionControlActions(const KFileItemList&)), - this, SLOT(slotRequestVersionControlActions(const KFileItemList&))); - - // react on view property changes - connect(dolphinView, SIGNAL(showHiddenFilesChanged()), - this, SLOT(slotShowHiddenFilesChanged())); - connect(dolphinView, SIGNAL(sortingChanged(DolphinView::Sorting)), - this, SLOT(slotSortingChanged(DolphinView::Sorting))); - connect(dolphinView, SIGNAL(sortOrderChanged(Qt::SortOrder)), - this, SLOT(slotSortOrderChanged(Qt::SortOrder))); - connect(dolphinView, SIGNAL(sortFoldersFirstChanged(bool)), - this, SLOT(slotSortFoldersFirstChanged(bool))); - - // Give the view the ability to auto-expand its directories on hovering - // (the column view takes care about this itself). If the details view - // uses expandable folders, the auto-expanding should be used always. - m_folderExpander = new FolderExpander(view, proxyModel()); - m_folderExpander->setEnabled(settings->autoExpandFolders()); - connect(m_folderExpander, SIGNAL(enterDir(const QModelIndex&)), - dolphinViewController, SLOT(triggerItem(const QModelIndex&))); - - // react on namefilter changes - connect(viewModeController, SIGNAL(nameFilterChanged(const QString&)), - this, SLOT(slotNameFilterChanged(const QString&))); - - view->viewport()->installEventFilter(this); -} - -ViewExtensionsFactory::~ViewExtensionsFactory() -{ -} - -void ViewExtensionsFactory::handleCurrentIndexChange(const QModelIndex& current, const QModelIndex& previous) -{ - m_autoScroller->handleCurrentIndexChange(current, previous); -} - -DolphinFileItemDelegate* ViewExtensionsFactory::fileItemDelegate() const -{ - return m_fileItemDelegate; -} - -void ViewExtensionsFactory::setAutoFolderExpandingEnabled(bool enabled) -{ - m_folderExpander->setEnabled(enabled); -} - -bool ViewExtensionsFactory::autoFolderExpandingEnabled() const -{ - return m_folderExpander->enabled(); -} - -bool ViewExtensionsFactory::eventFilter(QObject* watched, QEvent* event) -{ - Q_UNUSED(watched); - if ((event->type() == QEvent::Wheel) && (m_selectionManager != 0)) { - m_selectionManager->reset(); - } - return false; -} - -void ViewExtensionsFactory::slotZoomLevelChanged() -{ - m_previewGenerator->updateIcons(); - if (m_selectionManager != 0) { - m_selectionManager->reset(); - } -} - -void ViewExtensionsFactory::cancelPreviews() -{ - m_previewGenerator->cancelPreviews(); -} - -void ViewExtensionsFactory::slotShowPreviewChanged() -{ - const bool show = m_dolphinViewController->view()->showPreview(); - m_previewGenerator->setPreviewShown(show); -} - -void ViewExtensionsFactory::slotShowHiddenFilesChanged() -{ - KDirModel* dirModel = static_cast(proxyModel()->sourceModel()); - KDirLister* dirLister = dirModel->dirLister(); - - dirLister->stop(); - - const bool show = m_dolphinViewController->view()->showHiddenFiles(); - dirLister->setShowingDotFiles(show); - - const KUrl url = dirLister->url(); - if (url.isValid()) { - dirLister->openUrl(url, KDirLister::NoFlags); - } -} - -void ViewExtensionsFactory::slotSortingChanged(DolphinView::Sorting sorting) -{ - proxyModel()->setSorting(sorting); -} - -void ViewExtensionsFactory::slotSortOrderChanged(Qt::SortOrder order) -{ - proxyModel()->setSortOrder(order); -} - -void ViewExtensionsFactory::slotSortFoldersFirstChanged(bool foldersFirst) -{ - proxyModel()->setSortFoldersFirst(foldersFirst); -} - -void ViewExtensionsFactory::slotNameFilterChanged(const QString& nameFilter) -{ - proxyModel()->setFilterFixedString(nameFilter); -} - -void ViewExtensionsFactory::slotRequestVersionControlActions(const KFileItemList& items) -{ - QList actions; - if (items.isEmpty()) { - const KDirModel* dirModel = static_cast(proxyModel()->sourceModel()); - const KUrl url = dirModel->dirLister()->url(); - actions = m_versionControlObserver->contextMenuActions(url.path(KUrl::AddTrailingSlash)); - } else { - actions = m_versionControlObserver->contextMenuActions(items); - } - m_dolphinViewController->setVersionControlActions(actions); -} - -void ViewExtensionsFactory::requestActivation() -{ - m_dolphinViewController->requestActivation(); -} - -DolphinSortFilterProxyModel* ViewExtensionsFactory::proxyModel() const -{ - return static_cast(m_view->model()); -} - -#include "viewextensionsfactory.moc" - diff --git a/src/viewextensionsfactory.h b/src/viewextensionsfactory.h deleted file mode 100644 index 9324932ac..000000000 --- a/src/viewextensionsfactory.h +++ /dev/null @@ -1,105 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2009 by Peter Penz * - * * - * 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 VIEWEXTENSIONSFACTORY_H -#define VIEWEXTENSIONSFACTORY_H - -#include - -#include "dolphinview.h" - -class DolphinFileItemDelegate; -class DolphinSortFilterProxyModel; -class DolphinViewAutoScroller; -class KFilePreviewGenerator; -class FolderExpander; -class QModelIndex; -class SelectionManager; -class ToolTipManager; -class QAbstractItemView; -class VersionControlObserver; -class ViewModeController; - -/** - * @brief Responsible for creating extensions like tooltips and previews - * that are available in all view implementations. - * - * Each view implementation (iconsview, detailsview, columnview) must - * instantiate an instance of this class to assure having - * a common behavior that is independent from the custom functionality of - * a view implementation. - */ -class ViewExtensionsFactory : public QObject -{ - Q_OBJECT - -public: - explicit ViewExtensionsFactory(QAbstractItemView* view, - DolphinViewController* dolphinViewController, - const ViewModeController* viewModeController); - virtual ~ViewExtensionsFactory(); - - /** - * Must be invoked by the item view, when QAbstractItemView::currentChanged() - * has been called. Assures that the current item stays visible when it has been - * changed by the keyboard. - */ - void handleCurrentIndexChange(const QModelIndex& current, const QModelIndex& previous); - - DolphinFileItemDelegate* fileItemDelegate() const; - - /** - * Enables the automatically expanding of a folder when dragging - * items above the folder. - */ - void setAutoFolderExpandingEnabled(bool enabled); - bool autoFolderExpandingEnabled() const; - -protected: - virtual bool eventFilter(QObject* watched, QEvent* event); - -private slots: - void slotZoomLevelChanged(); - void cancelPreviews(); - void slotShowPreviewChanged(); - void slotShowHiddenFilesChanged(); - void slotSortingChanged(DolphinView::Sorting sorting); - void slotSortOrderChanged(Qt::SortOrder order); - void slotSortFoldersFirstChanged(bool foldersFirst); - void slotNameFilterChanged(const QString& nameFilter); - void slotRequestVersionControlActions(const KFileItemList& items); - void requestActivation(); - -private: - DolphinSortFilterProxyModel* proxyModel() const; - -private: - QAbstractItemView* m_view; - DolphinViewController* m_dolphinViewController; - ToolTipManager* m_toolTipManager; - KFilePreviewGenerator* m_previewGenerator; - SelectionManager* m_selectionManager; - DolphinViewAutoScroller* m_autoScroller; - DolphinFileItemDelegate* m_fileItemDelegate; - VersionControlObserver* m_versionControlObserver; - FolderExpander* m_folderExpander; -}; - -#endif - diff --git a/src/viewmodecontroller.cpp b/src/viewmodecontroller.cpp deleted file mode 100644 index 17d0ba61f..000000000 --- a/src/viewmodecontroller.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2010 by Peter Penz * - * * - * 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 "viewmodecontroller.h" - -#include "zoomlevelinfo.h" - -ViewModeController::ViewModeController(QObject* parent) : - QObject(parent), - m_zoomLevel(0), - m_nameFilter(), - m_url() -{ -} - -ViewModeController::~ViewModeController() -{ -} - -KUrl ViewModeController::url() const -{ - return m_url; -} - -void ViewModeController::redirectToUrl(const KUrl& url) -{ - m_url = url; -} - -void ViewModeController::indicateActivationChange(bool active) -{ - emit activationChanged(active); -} - -void ViewModeController::setNameFilter(const QString& nameFilter) -{ - if (nameFilter != m_nameFilter) { - m_nameFilter = nameFilter; - emit nameFilterChanged(nameFilter); - } -} - -QString ViewModeController::nameFilter() const -{ - return m_nameFilter; -} - -void ViewModeController::setZoomLevel(int level) -{ - Q_ASSERT(level >= ZoomLevelInfo::minimumLevel()); - Q_ASSERT(level <= ZoomLevelInfo::maximumLevel()); - if (level != m_zoomLevel) { - m_zoomLevel = level; - emit zoomLevelChanged(m_zoomLevel); - } -} - -int ViewModeController::zoomLevel() const -{ - return m_zoomLevel; -} - -void ViewModeController::setUrl(const KUrl& url) -{ - if (m_url != url) { - m_url = url; - emit cancelPreviews(); - emit urlChanged(url); - } -} - -#include "viewmodecontroller.moc" diff --git a/src/viewmodecontroller.h b/src/viewmodecontroller.h deleted file mode 100644 index 27b8381cf..000000000 --- a/src/viewmodecontroller.h +++ /dev/null @@ -1,124 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2010 by Peter Penz * - * * - * 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 VIEWMODECONTROLLER_H -#define VIEWMODECONTROLLER_H - -#include -#include -#include -#include - -/** - * @brief Allows the DolphinView to control the view implementations for the - * different view modes. - * - * The view implementations (DolphinIconsView, DolphinDetailsView, DolphinColumnView) - * connect to signals of the ViewModeController to react on changes. The view - * implementations get only read-access to the ViewModeController. - */ -class LIBDOLPHINPRIVATE_EXPORT ViewModeController : public QObject -{ - Q_OBJECT - -public: - explicit ViewModeController(QObject* parent = 0); - virtual ~ViewModeController(); - - /** - * @return URL that is shown by the view mode implementation. - */ - KUrl url() const; - - /** - * Sets the URL to \a url and does nothing else. Called when - * a redirection happens. See ViewModeController::setUrl() - */ - void redirectToUrl(const KUrl& url); - - /** - * Informs the view mode implementation about a change of the activation - * state by emitting the signal activationChanged(). - */ - void indicateActivationChange(bool active); - - /** - * Sets the zoom level to \a level and emits the signal zoomLevelChanged(). - * It must be assured that the used level is inside the range - * ViewModeController::zoomLevelMinimum() and - * ViewModeController::zoomLevelMaximum(). - */ - void setZoomLevel(int level); - int zoomLevel() const; - - /** - * Sets the name filter to \a and emits the signal nameFilterChanged(). - */ - void setNameFilter(const QString& nameFilter); - QString nameFilter() const; - - /** - * Requests the view mode implementation to hide tooltips. - */ - void requestToolTipHiding(); - -public slots: - /** - * Sets the URL to \a url and emits the signals cancelPreviews() and - * urlChanged() if \a url is different for the current URL. - */ - void setUrl(const KUrl& url); - -signals: - /** - * Is emitted if the URL has been changed by ViewModeController::setUrl(). - */ - void urlChanged(const KUrl& url); - - /** - * Is emitted, if ViewModeController::indicateActivationChange() has been - * invoked. The view mode implementation may update its visual state - * to represent the activation state. - */ - void activationChanged(bool active); - - /** - * Is emitted if the name filter has been changed by - * ViewModeController::setNameFilter(). - */ - void nameFilterChanged(const QString& nameFilter); - - /** - * Is emitted if the zoom level has been changed by - * ViewModeController::setZoomLevel(). - */ - void zoomLevelChanged(int level); - - /** - * Is emitted if pending previews should be canceled (e. g. because of an URL change). - */ - void cancelPreviews(); - -private: - int m_zoomLevel; - QString m_nameFilter; - KUrl m_url; -}; - -#endif diff --git a/src/viewproperties.h b/src/viewproperties.h index 517947022..bb476dc44 100644 --- a/src/viewproperties.h +++ b/src/viewproperties.h @@ -21,7 +21,7 @@ #ifndef VIEWPROPERTIES_H #define VIEWPROPERTIES_H -#include +#include #include #include diff --git a/src/views/dolphincategorydrawer.cpp b/src/views/dolphincategorydrawer.cpp new file mode 100644 index 000000000..59743b7f5 --- /dev/null +++ b/src/views/dolphincategorydrawer.cpp @@ -0,0 +1,378 @@ +/* + * This file is part of the KDE project + * Copyright (C) 2007 Rafael Fernández López + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "dolphincategorydrawer.h" + +#include + +#include +#include +#include +#include +#include + +#ifdef HAVE_NEPOMUK +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "dolphinview.h" +#include "dolphinmodel.h" + +#define HORIZONTAL_HINT 3 + +DolphinCategoryDrawer::DolphinCategoryDrawer(KCategorizedView *view) + : KCategoryDrawerV3(view) + , hotSpotPressed(NoneHotSpot) + , selectAll(KIconLoader::global()->loadIcon("list-add", KIconLoader::Desktop, 16)) + , selectAllHovered(KIconLoader::global()->iconEffect()->apply(selectAll, KIconLoader::Desktop, KIconLoader::ActiveState)) + , selectAllDisabled(KIconLoader::global()->iconEffect()->apply(selectAll, KIconLoader::Desktop, KIconLoader::DisabledState)) + , unselectAll(KIconLoader::global()->loadIcon("list-remove", KIconLoader::Desktop, 16)) + , unselectAllHovered(KIconLoader::global()->iconEffect()->apply(unselectAll, KIconLoader::Desktop, KIconLoader::ActiveState)) + , unselectAllDisabled(KIconLoader::global()->iconEffect()->apply(unselectAll, KIconLoader::Desktop, KIconLoader::DisabledState)) +{ +} + +DolphinCategoryDrawer::~DolphinCategoryDrawer() +{ +} + +bool DolphinCategoryDrawer::allCategorySelected(const QString &category) const +{ + const QModelIndexList list = view()->block(category); + foreach (const QModelIndex &index, list) { + if (!view()->selectionModel()->isSelected(index)) { + return false; + } + } + return true; +} + +bool DolphinCategoryDrawer::someCategorySelected(const QString &category) const +{ + const QModelIndexList list = view()->block(category); + foreach (const QModelIndex &index, list) { + if (view()->selectionModel()->isSelected(index)) { + return true; + } + } + return false; +} + +void DolphinCategoryDrawer::drawCategory(const QModelIndex &index, int sortRole, + const QStyleOption &option, QPainter *painter) const +{ + Q_UNUSED(sortRole); + painter->setRenderHint(QPainter::Antialiasing); + + if (!index.isValid()) { + return; + } + + const QString category = index.model()->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); + const QRect optRect = option.rect; + QFont font(QApplication::font()); + font.setBold(true); + const QFontMetrics fontMetrics = QFontMetrics(font); + + QColor outlineColor = option.palette.text().color(); + outlineColor.setAlphaF(0.35); + + //BEGIN: top left corner + { + painter->save(); + painter->setPen(outlineColor); + const QPointF topLeft(optRect.topLeft()); + QRectF arc(topLeft, QSizeF(4, 4)); + arc.translate(0.5, 0.5); + painter->drawArc(arc, 1440, 1440); + painter->restore(); + } + //END: top left corner + + //BEGIN: left vertical line + { + QPoint start(optRect.topLeft()); + start.ry() += 3; + QPoint verticalGradBottom(optRect.topLeft()); + verticalGradBottom.ry() += fontMetrics.height() + 5; + QLinearGradient gradient(start, verticalGradBottom); + gradient.setColorAt(0, outlineColor); + gradient.setColorAt(1, Qt::transparent); + painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient); + } + //END: left vertical line + + //BEGIN: horizontal line + { + QPoint start(optRect.topLeft()); + start.rx() += 3; + QPoint horizontalGradTop(optRect.topLeft()); + horizontalGradTop.rx() += optRect.width() - 6; + painter->fillRect(QRect(start, QSize(optRect.width() - 6, 1)), outlineColor); + } + //END: horizontal line + + //BEGIN: top right corner + { + painter->save(); + painter->setPen(outlineColor); + QPointF topRight(optRect.topRight()); + topRight.rx() -= 4; + QRectF arc(topRight, QSizeF(4, 4)); + arc.translate(0.5, 0.5); + painter->drawArc(arc, 0, 1440); + painter->restore(); + } + //END: top right corner + + //BEGIN: right vertical line + { + QPoint start(optRect.topRight()); + start.ry() += 3; + QPoint verticalGradBottom(optRect.topRight()); + verticalGradBottom.ry() += fontMetrics.height() + 5; + QLinearGradient gradient(start, verticalGradBottom); + gradient.setColorAt(0, outlineColor); + gradient.setColorAt(1, Qt::transparent); + painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient); + } + //END: right vertical line + + const int iconSize = KIconLoader::global()->currentSize(KIconLoader::Small); + + //BEGIN: select/unselect all + { + if (this->category == category) { + QRect iconAllRect(option.rect); + iconAllRect.setTop(iconAllRect.top() + 4); + iconAllRect.setLeft(iconAllRect.right() - 16 - 7); + iconAllRect.setSize(QSize(iconSize, iconSize)); + if (!allCategorySelected(category)) { + if (iconAllRect.contains(pos)) { + painter->drawPixmap(iconAllRect, selectAllHovered); + } else { + painter->drawPixmap(iconAllRect, selectAll); + } + } else { + painter->drawPixmap(iconAllRect, selectAllDisabled); + } + QRect iconNoneRect(option.rect); + iconNoneRect.setTop(iconNoneRect.top() + 4); + iconNoneRect.setLeft(iconNoneRect.right() - 16 * 2 - 7 * 2); + iconNoneRect.setSize(QSize(iconSize, iconSize)); + if (someCategorySelected(category)) { + if (iconNoneRect.contains(pos)) { + painter->drawPixmap(iconNoneRect, unselectAllHovered); + } else { + painter->drawPixmap(iconNoneRect, unselectAll); + } + } else { + painter->drawPixmap(iconNoneRect, unselectAllDisabled); + } + } + } + //END: select/unselect all + + //BEGIN: category information + { + bool paintIcon; + QPixmap icon; + switch (index.column()) { + case KDirModel::Owner: { + paintIcon = true; + KUser user(category); + const QString faceIconPath = user.faceIconPath(); + if (faceIconPath.isEmpty()) { + icon = KIconLoader::global()->loadIcon("user-identity", KIconLoader::NoGroup, iconSize); + } else { + icon = QPixmap::fromImage(QImage(faceIconPath).scaledToHeight(iconSize, Qt::SmoothTransformation)); + } + } + break; + case KDirModel::Type: { + paintIcon = true; + const KCategorizedSortFilterProxyModel *proxyModel = static_cast(index.model()); + const DolphinModel *model = static_cast(proxyModel->sourceModel()); + KFileItem item = model->itemForIndex(proxyModel->mapToSource(index)); + // This is the only way of getting the icon right. Others will fail on corner + // cases like the item representing this group has been set a different icon, + // so the group icon drawn is that one particularly. This way assures the drawn + // icon is the one of the mimetype of the group itself. (ereslibre) + icon = KIconLoader::global()->loadMimeTypeIcon(item.mimeTypePtr()->iconName(), KIconLoader::NoGroup, iconSize); + } + break; + default: + paintIcon = false; + } + + if (paintIcon) { + QRect iconRect(option.rect); + iconRect.setTop(iconRect.top() + 4); + iconRect.setLeft(iconRect.left() + 7); + iconRect.setSize(QSize(iconSize, iconSize)); + + painter->drawPixmap(iconRect, icon); + } + + //BEGIN: text + { + QRect textRect(option.rect); + textRect.setTop(textRect.top() + 7); + textRect.setLeft(textRect.left() + 7 + (paintIcon ? (iconSize + 6) : 0)); + textRect.setHeight(qMax(fontMetrics.height(), iconSize)); + textRect.setRight(textRect.right() - 7); + textRect.setBottom(textRect.bottom() - 5); // only one pixel separation here (no gradient) + + painter->save(); + painter->setFont(font); + QColor penColor(option.palette.text().color()); + penColor.setAlphaF(0.6); + painter->setPen(penColor); + painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, category); + painter->restore(); + } + //END: text + } + //BEGIN: category information +} + +int DolphinCategoryDrawer::categoryHeight(const QModelIndex &index, const QStyleOption &) const +{ + int iconSize = KIconLoader::global()->currentSize(KIconLoader::Small); + QFont font(QApplication::font()); + font.setBold(true); + const QFontMetrics fontMetrics = QFontMetrics(font); + int heightWithoutIcon = fontMetrics.height() + (iconSize / 4) * 2 + 1; /* 1 pixel-width gradient */ + bool paintIcon; + + switch (index.column()) { + case KDirModel::Owner: + case KDirModel::Type: + paintIcon = true; + break; + default: + paintIcon = false; + } + + if (paintIcon) { + return qMax(heightWithoutIcon + 5, iconSize + 1 /* 1 pixel-width gradient */ + + 5 /* top and bottom separation */); + } + + return heightWithoutIcon + 5; +} + +void DolphinCategoryDrawer::mouseButtonPressed(const QModelIndex &index, const QRect &blockRect, QMouseEvent *event) +{ + if (!index.isValid()) { + event->ignore(); + return; + } + const QString category = index.model()->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); + int iconSize = KIconLoader::global()->currentSize(KIconLoader::Small); + if (this->category == category) { + QRect iconAllRect(blockRect); + iconAllRect.setTop(iconAllRect.top() + 4); + iconAllRect.setLeft(iconAllRect.right() - 16 - 7); + iconAllRect.setSize(QSize(iconSize, iconSize)); + if (iconAllRect.contains(pos)) { + event->accept(); + hotSpotPressed = SelectAllHotSpot; + categoryPressed = index; + return; + } + QRect iconNoneRect(blockRect); + iconNoneRect.setTop(iconNoneRect.top() + 4); + iconNoneRect.setLeft(iconNoneRect.right() - 16 * 2 - 7 * 2); + iconNoneRect.setSize(QSize(iconSize, iconSize)); + if (iconNoneRect.contains(pos)) { + event->accept(); + hotSpotPressed = UnselectAllHotSpot; + categoryPressed = index; + return; + } + } + event->ignore(); +} + +void DolphinCategoryDrawer::mouseButtonReleased(const QModelIndex &index, const QRect &blockRect, QMouseEvent *event) +{ + if (!index.isValid() || hotSpotPressed == NoneHotSpot || categoryPressed != index) { + event->ignore(); + return; + } + categoryPressed = QModelIndex(); + const QString category = index.model()->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); + int iconSize = KIconLoader::global()->currentSize(KIconLoader::Small); + if (this->category == category) { + QRect iconAllRect(blockRect); + iconAllRect.setTop(iconAllRect.top() + 4); + iconAllRect.setLeft(iconAllRect.right() - 16 - 7); + iconAllRect.setSize(QSize(iconSize, iconSize)); + if (iconAllRect.contains(pos)) { + if (hotSpotPressed == SelectAllHotSpot) { + event->accept(); + emit actionRequested(SelectAll, index); + } else { + event->ignore(); + hotSpotPressed = NoneHotSpot; + } + return; + } + QRect iconNoneRect(blockRect); + iconNoneRect.setTop(iconNoneRect.top() + 4); + iconNoneRect.setLeft(iconNoneRect.right() - 16 * 2 - 7 * 2); + iconNoneRect.setSize(QSize(iconSize, iconSize)); + if (iconNoneRect.contains(pos)) { + if (hotSpotPressed == UnselectAllHotSpot) { + event->accept(); + emit actionRequested(UnselectAll, index); + } else { + event->ignore(); + hotSpotPressed = NoneHotSpot; + } + return; + } + } + event->ignore(); +} + +void DolphinCategoryDrawer::mouseMoved(const QModelIndex &index, const QRect &, QMouseEvent *event) +{ + event->ignore(); + if (!index.isValid()) { + return; + } + pos = event->pos(); + category = index.model()->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); +} + +void DolphinCategoryDrawer::mouseLeft(const QModelIndex &, const QRect &) +{ + pos = QPoint(); + category = QString(); +} diff --git a/src/views/dolphincategorydrawer.h b/src/views/dolphincategorydrawer.h new file mode 100644 index 000000000..d9849727e --- /dev/null +++ b/src/views/dolphincategorydrawer.h @@ -0,0 +1,85 @@ +/* This file is part of the KDE project + * Copyright (C) 2007 Rafael Fernández López + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef DOLPHINCATEGORYDRAWER_H +#define DOLPHINCATEGORYDRAWER_H + +#include + +#include +#include + +#include + +class LIBDOLPHINPRIVATE_EXPORT DolphinCategoryDrawer + : public KCategoryDrawerV3 +{ +public: + using KCategoryDrawerV2::mouseButtonPressed; + using KCategoryDrawerV2::mouseButtonReleased; + + enum Action { + SelectAll = 0, + UnselectAll + }; + + DolphinCategoryDrawer(KCategorizedView *view); + + virtual ~DolphinCategoryDrawer(); + + bool allCategorySelected(const QString &category) const; + + bool someCategorySelected(const QString &category) const; + + virtual void drawCategory(const QModelIndex &index, int sortRole, + const QStyleOption &option, QPainter *painter) const; + + virtual int categoryHeight(const QModelIndex &index, const QStyleOption &option) const; + +protected: + virtual void mouseButtonPressed(const QModelIndex &index, const QRect &blockRect, QMouseEvent *event); + + virtual void mouseButtonReleased(const QModelIndex &index, const QRect &blockRect, QMouseEvent *event); + + virtual void mouseMoved(const QModelIndex &index, const QRect &blockRect, QMouseEvent *event); + + virtual void mouseLeft(const QModelIndex &index,const QRect &blockRect); + +private: + enum HotSpot { + NoneHotSpot = 0, + SelectAllHotSpot, + UnselectAllHotSpot + }; + + HotSpot hotSpotPressed; + QModelIndex categoryPressed; + + QPixmap selectAll; + QPixmap selectAllHovered; + QPixmap selectAllDisabled; + QPixmap unselectAll; + QPixmap unselectAllHovered; + QPixmap unselectAllDisabled; + + QPoint pos; + QString category; +}; + +#endif // DOLPHINCATEGORYDRAWER_H diff --git a/src/views/dolphincolumnview.cpp b/src/views/dolphincolumnview.cpp new file mode 100644 index 000000000..7e2b522b4 --- /dev/null +++ b/src/views/dolphincolumnview.cpp @@ -0,0 +1,466 @@ +/*************************************************************************** + * Copyright (C) 2007-2009 by Peter Penz * + * * + * 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 "dolphincolumnview.h" + +#include "dolphinmodel.h" +#include "dolphincolumnviewcontainer.h" +#include "dolphinviewcontroller.h" +#include "dolphindirlister.h" +#include "dolphinsortfilterproxymodel.h" +#include "settings/dolphinsettings.h" +#include "dolphinviewautoscroller.h" +#include "dolphin_columnmodesettings.h" +#include "dolphin_generalsettings.h" +#include "draganddrophelper.h" +#include "folderexpander.h" +#include "tooltips/tooltipmanager.h" +#include "viewextensionsfactory.h" +#include "viewmodecontroller.h" +#include "zoomlevelinfo.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +DolphinColumnView::DolphinColumnView(QWidget* parent, + DolphinColumnViewContainer* container, + const KUrl& url) : + QListView(parent), + m_active(false), + m_container(container), + m_extensionsFactory(0), + m_url(url), + m_childUrl(), + m_font(), + m_decorationSize(), + m_dirLister(0), + m_dolphinModel(0), + m_proxyModel(0), + m_dropRect() +{ + setMouseTracking(true); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + setSelectionBehavior(SelectItems); + setSelectionMode(QAbstractItemView::ExtendedSelection); + setDragDropMode(QAbstractItemView::DragDrop); + setDropIndicatorShown(false); + setSelectionRectVisible(true); + setEditTriggers(QAbstractItemView::NoEditTriggers); + + setVerticalScrollMode(QListView::ScrollPerPixel); + setHorizontalScrollMode(QListView::ScrollPerPixel); + + // apply the column mode settings to the widget + const ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings(); + Q_ASSERT(settings != 0); + + if (settings->useSystemFont()) { + m_font = KGlobalSettings::generalFont(); + } else { + m_font = QFont(settings->fontFamily(), + qRound(settings->fontSize()), + settings->fontWeight(), + settings->italicFont()); + m_font.setPointSizeF(settings->fontSize()); + } + + connect(this, SIGNAL(viewportEntered()), + m_container->m_dolphinViewController, SLOT(emitViewportEntered())); + connect(this, SIGNAL(entered(const QModelIndex&)), + this, SLOT(slotEntered(const QModelIndex&))); + + const DolphinView* dolphinView = m_container->m_dolphinViewController->view(); + connect(dolphinView, SIGNAL(showPreviewChanged()), + this, SLOT(slotShowPreviewChanged())); + + m_dirLister = new DolphinDirLister(); + m_dirLister->setAutoUpdate(true); + m_dirLister->setMainWindow(window()); + m_dirLister->setDelayedMimeTypes(true); + const bool showHiddenFiles = m_container->m_dolphinViewController->view()->showHiddenFiles(); + m_dirLister->setShowingDotFiles(showHiddenFiles); + + m_dolphinModel = new DolphinModel(this); + m_dolphinModel->setDirLister(m_dirLister); + m_dolphinModel->setDropsAllowed(DolphinModel::DropOnDirectory); + + m_proxyModel = new DolphinSortFilterProxyModel(this); + m_proxyModel->setSourceModel(m_dolphinModel); + m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); + + m_proxyModel->setSorting(dolphinView->sorting()); + m_proxyModel->setSortOrder(dolphinView->sortOrder()); + m_proxyModel->setSortFoldersFirst(dolphinView->sortFoldersFirst()); + + setModel(m_proxyModel); + + connect(KGlobalSettings::self(), SIGNAL(kdisplayFontChanged()), + this, SLOT(updateFont())); + + const ViewModeController* viewModeController = m_container->m_viewModeController; + connect(viewModeController, SIGNAL(zoomLevelChanged(int)), + this, SLOT(setZoomLevel(int))); + const QString nameFilter = viewModeController->nameFilter(); + if (!nameFilter.isEmpty()) { + m_proxyModel->setFilterFixedString(nameFilter); + } + + updateDecorationSize(dolphinView->showPreview()); + updateBackground(); + + DolphinViewController* dolphinViewController = m_container->m_dolphinViewController; + m_extensionsFactory = new ViewExtensionsFactory(this, dolphinViewController, viewModeController); + + m_dirLister->openUrl(url, KDirLister::NoFlags); +} + +DolphinColumnView::~DolphinColumnView() +{ + delete m_proxyModel; + m_proxyModel = 0; + delete m_dolphinModel; + m_dolphinModel = 0; + m_dirLister = 0; // deleted by m_dolphinModel +} + +void DolphinColumnView::setActive(bool active) +{ + if (m_active != active) { + m_active = active; + + if (active) { + activate(); + } else { + deactivate(); + } + } +} + +void DolphinColumnView::updateBackground() +{ + // TODO: The alpha-value 150 is copied from DolphinView::setActive(). When + // cleaning up the cut-indication of DolphinColumnView with the code from + // DolphinView a common helper-class should be available which can be shared + // by all view implementations -> no hardcoded value anymore + const QPalette::ColorRole role = viewport()->backgroundRole(); + QColor color = viewport()->palette().color(role); + color.setAlpha((m_active && m_container->m_active) ? 255 : 150); + + QPalette palette = viewport()->palette(); + palette.setColor(role, color); + viewport()->setPalette(palette); + + update(); +} + +KFileItem DolphinColumnView::itemAt(const QPoint& pos) const +{ + KFileItem item; + const QModelIndex index = indexAt(pos); + if (index.isValid() && (index.column() == DolphinModel::Name)) { + const QModelIndex dolphinModelIndex = m_proxyModel->mapToSource(index); + item = m_dolphinModel->itemForIndex(dolphinModelIndex); + } + return item; +} + +void DolphinColumnView::setSelectionModel(QItemSelectionModel* model) +{ + // If a change of the selection is done although the view is not active + // (e. g. by the selection markers), the column must be activated. This + // is done by listening to the current selectionChanged() signal. + if (selectionModel() != 0) { + disconnect(selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), + this, SLOT(requestActivation())); + } + + QListView::setSelectionModel(model); + + connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), + this, SLOT(requestActivation())); +} + +QStyleOptionViewItem DolphinColumnView::viewOptions() const +{ + QStyleOptionViewItem viewOptions = QListView::viewOptions(); + viewOptions.font = m_font; + viewOptions.fontMetrics = QFontMetrics(m_font); + viewOptions.decorationSize = m_decorationSize; + viewOptions.showDecorationSelected = true; + return viewOptions; +} + +void DolphinColumnView::startDrag(Qt::DropActions supportedActions) +{ + DragAndDropHelper::instance().startDrag(this, supportedActions, m_container->m_dolphinViewController); +} + +void DolphinColumnView::dragEnterEvent(QDragEnterEvent* event) +{ + if (DragAndDropHelper::instance().isMimeDataSupported(event->mimeData())) { + event->acceptProposedAction(); + requestActivation(); + } +} + +void DolphinColumnView::dragLeaveEvent(QDragLeaveEvent* event) +{ + QListView::dragLeaveEvent(event); + setDirtyRegion(m_dropRect); +} + +void DolphinColumnView::dragMoveEvent(QDragMoveEvent* event) +{ + QListView::dragMoveEvent(event); + + // TODO: remove this code when the issue #160611 is solved in Qt 4.4 + const QModelIndex index = indexAt(event->pos()); + setDirtyRegion(m_dropRect); + + m_dropRect.setSize(QSize()); // set as invalid + if (index.isValid()) { + m_container->m_dolphinViewController->setItemView(this); + const KFileItem item = m_container->m_dolphinViewController->itemForIndex(index); + if (!item.isNull() && item.isDir()) { + m_dropRect = visualRect(index); + } + } + setDirtyRegion(m_dropRect); + + if (DragAndDropHelper::instance().isMimeDataSupported(event->mimeData())) { + // accept url drops, independently from the destination item + event->acceptProposedAction(); + } +} + +void DolphinColumnView::dropEvent(QDropEvent* event) +{ + const QModelIndex index = indexAt(event->pos()); + m_container->m_dolphinViewController->setItemView(this); + const KFileItem item = m_container->m_dolphinViewController->itemForIndex(index); + m_container->m_dolphinViewController->indicateDroppedUrls(item, url(), event); + QListView::dropEvent(event); +} + +void DolphinColumnView::paintEvent(QPaintEvent* event) +{ + if (!m_childUrl.isEmpty()) { + // indicate the shown URL of the next column by highlighting the shown folder item + const QModelIndex dirIndex = m_dolphinModel->indexForUrl(m_childUrl); + const QModelIndex proxyIndex = m_proxyModel->mapFromSource(dirIndex); + if (proxyIndex.isValid() && !selectionModel()->isSelected(proxyIndex)) { + const QRect itemRect = visualRect(proxyIndex); + QPainter painter(viewport()); + QColor color = KColorScheme(QPalette::Active, KColorScheme::View).foreground().color(); + color.setAlpha(32); + painter.setPen(Qt::NoPen); + painter.setBrush(color); + painter.drawRect(itemRect); + } + } + + QListView::paintEvent(event); +} + +void DolphinColumnView::mousePressEvent(QMouseEvent* event) +{ + requestActivation(); + if (!indexAt(event->pos()).isValid()) { + if (QApplication::mouseButtons() & Qt::MidButton) { + m_container->m_dolphinViewController->replaceUrlByClipboard(); + } + } else if (event->button() == Qt::LeftButton) { + // TODO: see comment in DolphinIconsView::mousePressEvent() + setState(QAbstractItemView::DraggingState); + } + QListView::mousePressEvent(event); +} + +void DolphinColumnView::keyPressEvent(QKeyEvent* event) +{ + QListView::keyPressEvent(event); + + DolphinViewController* controller = m_container->m_dolphinViewController; + controller->handleKeyPressEvent(event); + switch (event->key()) { + case Qt::Key_Right: { + // Special key handling for the column: A Key_Right should + // open a new column for the currently selected folder. + const QModelIndex index = currentIndex(); + const KFileItem item = controller->itemForIndex(index); + if (!item.isNull() && item.isDir()) { + controller->emitItemTriggered(item); + } + break; + } + + case Qt::Key_Escape: + selectionModel()->setCurrentIndex(selectionModel()->currentIndex(), + QItemSelectionModel::Current | + QItemSelectionModel::Clear); + break; + + default: + break; + } +} + +void DolphinColumnView::contextMenuEvent(QContextMenuEvent* event) +{ + requestActivation(); + QListView::contextMenuEvent(event); + m_container->m_dolphinViewController->triggerContextMenuRequest(event->pos()); +} + +void DolphinColumnView::wheelEvent(QWheelEvent* event) +{ + const int step = m_decorationSize.height(); + verticalScrollBar()->setSingleStep(step); + QListView::wheelEvent(event); +} + +void DolphinColumnView::leaveEvent(QEvent* event) +{ + QListView::leaveEvent(event); + // if the mouse is above an item and moved very fast outside the widget, + // no viewportEntered() signal might be emitted although the mouse has been moved + // above the viewport + m_container->m_dolphinViewController->emitViewportEntered(); +} + +void DolphinColumnView::currentChanged(const QModelIndex& current, const QModelIndex& previous) +{ + QListView::currentChanged(current, previous); + m_extensionsFactory->handleCurrentIndexChange(current, previous); +} + +void DolphinColumnView::setZoomLevel(int level) +{ + const int size = ZoomLevelInfo::iconSizeForZoomLevel(level); + ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings(); + + const bool showPreview = m_container->m_dolphinViewController->view()->showPreview(); + if (showPreview) { + settings->setPreviewSize(size); + } else { + settings->setIconSize(size); + } + + updateDecorationSize(showPreview); +} + +void DolphinColumnView::slotEntered(const QModelIndex& index) +{ + m_container->m_dolphinViewController->setItemView(this); + m_container->m_dolphinViewController->emitItemEntered(index); +} + +void DolphinColumnView::requestActivation() +{ + m_container->m_dolphinViewController->requestActivation(); + if (!m_active) { + m_container->requestActivation(this); + selectionModel()->clear(); + } +} + +void DolphinColumnView::updateFont() +{ + const ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings(); + Q_ASSERT(settings != 0); + + if (settings->useSystemFont()) { + m_font = KGlobalSettings::generalFont(); + } +} + +void DolphinColumnView::slotShowPreviewChanged() +{ + const DolphinView* view = m_container->m_dolphinViewController->view(); + updateDecorationSize(view->showPreview()); +} + +void DolphinColumnView::activate() +{ + setFocus(Qt::OtherFocusReason); + + if (KGlobalSettings::singleClick()) { + connect(this, SIGNAL(clicked(const QModelIndex&)), + m_container->m_dolphinViewController, SLOT(triggerItem(const QModelIndex&))); + } else { + connect(this, SIGNAL(doubleClicked(const QModelIndex&)), + m_container->m_dolphinViewController, SLOT(triggerItem(const QModelIndex&))); + } + + if (selectionModel() && selectionModel()->currentIndex().isValid()) { + selectionModel()->setCurrentIndex(selectionModel()->currentIndex(), QItemSelectionModel::SelectCurrent); + } + + updateBackground(); +} + +void DolphinColumnView::deactivate() +{ + clearFocus(); + if (KGlobalSettings::singleClick()) { + disconnect(this, SIGNAL(clicked(const QModelIndex&)), + m_container->m_dolphinViewController, SLOT(triggerItem(const QModelIndex&))); + } else { + disconnect(this, SIGNAL(doubleClicked(const QModelIndex&)), + m_container->m_dolphinViewController, SLOT(triggerItem(const QModelIndex&))); + } + + // It is important to disconnect the connection to requestActivation() temporary, otherwise the internal + // clearing of the selection would result in activating the column again. + disconnect(selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), + this, SLOT(requestActivation())); + const QModelIndex current = selectionModel()->currentIndex(); + selectionModel()->clear(); + selectionModel()->setCurrentIndex(current, QItemSelectionModel::NoUpdate); + connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), + this, SLOT(requestActivation())); + + updateBackground(); +} + +void DolphinColumnView::updateDecorationSize(bool showPreview) +{ + ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings(); + const int iconSize = showPreview ? settings->previewSize() : settings->iconSize(); + const QSize size(iconSize, iconSize); + setIconSize(size); + + m_decorationSize = size; + + doItemsLayout(); +} + +#include "dolphincolumnview.moc" diff --git a/src/views/dolphincolumnview.h b/src/views/dolphincolumnview.h new file mode 100644 index 000000000..64feac4f9 --- /dev/null +++ b/src/views/dolphincolumnview.h @@ -0,0 +1,170 @@ +/*************************************************************************** + * Copyright (C) 2007-2009 by Peter Penz * + * * + * 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 DOLPHINCOLUMNVIEW_H +#define DOLPHINCOLUMNVIEW_H + +#include "dolphinview.h" + +#include +#include +#include +#include + +#include + +class DolphinColumnViewContainer; +class DolphinModel; +class DolphinSortFilterProxyModel; +class DolphinDirLister; +class KFileItem; +class SelectionManager; +class ViewExtensionsFactory; + +/** + * Represents one column inside the DolphinColumnViewContainer. + */ +class DolphinColumnView : public QListView +{ + Q_OBJECT + +public: + DolphinColumnView(QWidget* parent, + DolphinColumnViewContainer* container, + const KUrl& url); + virtual ~DolphinColumnView(); + + /** + * An active column is defined as column, which shows the same URL + * as indicated by the URL navigator. The active column is usually + * drawn in a lighter color. All operations are applied to this column. + */ + void setActive(bool active); + bool isActive() const; + + /** + * Sets the directory URL of the child column that is shown next to + * this column. This property is only used for a visual indication + * of the shown directory, it does not trigger a loading of the model. + */ + void setChildUrl(const KUrl& url); + KUrl childUrl() const; + + /** Sets the directory URL that is shown inside the column widget. */ + void setUrl(const KUrl& url); + + /** Returns the directory URL that is shown inside the column widget. */ + KUrl url() const; + + /** + * Updates the background color dependent from the activation state + * \a isViewActive of the column view. + */ + void updateBackground(); + + /** + * Returns the item on the position \a pos. The KFileItem instance + * is null if no item is below the position. + */ + KFileItem itemAt(const QPoint& pos) const; + + virtual void setSelectionModel(QItemSelectionModel* model); + +protected: + virtual QStyleOptionViewItem viewOptions() const; + virtual void startDrag(Qt::DropActions supportedActions); + virtual void dragEnterEvent(QDragEnterEvent* event); + virtual void dragLeaveEvent(QDragLeaveEvent* event); + virtual void dragMoveEvent(QDragMoveEvent* event); + virtual void dropEvent(QDropEvent* event); + virtual void paintEvent(QPaintEvent* event); + virtual void mousePressEvent(QMouseEvent* event); + virtual void keyPressEvent(QKeyEvent* event); + virtual void contextMenuEvent(QContextMenuEvent* event); + virtual void wheelEvent(QWheelEvent* event); + virtual void leaveEvent(QEvent* event); + virtual void currentChanged(const QModelIndex& current, const QModelIndex& previous); + +private slots: + void setZoomLevel(int level); + + void slotEntered(const QModelIndex& index); + void requestActivation(); + void updateFont(); + + void slotShowPreviewChanged(); + +private: + /** Used by DolphinColumnView::setActive(). */ + void activate(); + + /** Used by DolphinColumnView::setActive(). */ + void deactivate(); + + void updateDecorationSize(bool showPreview); + +private: + bool m_active; + DolphinColumnViewContainer* m_container; + SelectionManager* m_selectionManager; + ViewExtensionsFactory* m_extensionsFactory; + KUrl m_url; // URL of the directory that is shown + KUrl m_childUrl; // URL of the next column that is shown + + QFont m_font; + QSize m_decorationSize; + + DolphinDirLister* m_dirLister; + DolphinModel* m_dolphinModel; + DolphinSortFilterProxyModel* m_proxyModel; + + QRect m_dropRect; + + friend class DolphinColumnViewContainer; +}; + +inline bool DolphinColumnView::isActive() const +{ + return m_active; +} + +inline void DolphinColumnView::setChildUrl(const KUrl& url) +{ + m_childUrl = url; +} + +inline KUrl DolphinColumnView::childUrl() const +{ + return m_childUrl; +} + +inline void DolphinColumnView::setUrl(const KUrl& url) +{ + if (url != m_url) { + m_url = url; + //reload(); + } +} + +inline KUrl DolphinColumnView::url() const +{ + return m_url; +} + +#endif diff --git a/src/views/dolphincolumnviewcontainer.cpp b/src/views/dolphincolumnviewcontainer.cpp new file mode 100644 index 000000000..344d38d8a --- /dev/null +++ b/src/views/dolphincolumnviewcontainer.cpp @@ -0,0 +1,416 @@ +/*************************************************************************** + * Copyright (C) 2007-2009 by Peter Penz * + * * + * 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 "dolphincolumnviewcontainer.h" + +#include "dolphin_columnmodesettings.h" + +#include "dolphincolumnview.h" +#include "dolphinviewcontroller.h" +#include "dolphinsortfilterproxymodel.h" +#include "draganddrophelper.h" +#include "settings/dolphinsettings.h" +#include "viewmodecontroller.h" + +#include +#include +#include +#include + +DolphinColumnViewContainer::DolphinColumnViewContainer(QWidget* parent, + DolphinViewController* dolphinViewController, + const ViewModeController* viewModeController) : + QScrollArea(parent), + m_dolphinViewController(dolphinViewController), + m_viewModeController(viewModeController), + m_active(false), + m_index(-1), + m_contentX(0), + m_columns(), + m_emptyViewport(0), + m_animation(0), + m_dragSource(0), + m_activeUrlTimer(0) +{ + Q_ASSERT(dolphinViewController != 0); + Q_ASSERT(viewModeController != 0); + + setAcceptDrops(true); + setFocusPolicy(Qt::NoFocus); + setFrameShape(QFrame::NoFrame); + setLayoutDirection(Qt::LeftToRight); + + connect(viewModeController, SIGNAL(activationChanged(bool)), + this, SLOT(updateColumnsBackground(bool))); + + connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), + this, SLOT(moveContentHorizontally(int))); + + m_animation = new QTimeLine(500, this); + connect(m_animation, SIGNAL(frameChanged(int)), horizontalScrollBar(), SLOT(setValue(int))); + + m_activeUrlTimer = new QTimer(this); + m_activeUrlTimer->setSingleShot(true); + m_activeUrlTimer->setInterval(200); + connect(m_activeUrlTimer, SIGNAL(timeout()), + this, SLOT(updateActiveUrl())); + + DolphinColumnView* column = new DolphinColumnView(viewport(), this, viewModeController->url()); + m_columns.append(column); + requestActivation(column); + + m_emptyViewport = new QFrame(viewport()); + m_emptyViewport->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); + + updateColumnsBackground(true); + +} + +DolphinColumnViewContainer::~DolphinColumnViewContainer() +{ + delete m_dragSource; + m_dragSource = 0; +} + +KUrl DolphinColumnViewContainer::rootUrl() const +{ + return m_columns[0]->url(); +} + +QAbstractItemView* DolphinColumnViewContainer::activeColumn() const +{ + return m_columns[m_index]; +} + +void DolphinColumnViewContainer::showColumn(const KUrl& url) +{ + if (!rootUrl().isParentOf(url)) { + removeAllColumns(); + m_columns[0]->setUrl(url); + return; + } + + int columnIndex = 0; + foreach (DolphinColumnView* column, m_columns) { + if (column->url() == url) { + // the column represents already the requested URL, hence activate it + requestActivation(column); + layoutColumns(); + return; + } else if (!column->url().isParentOf(url)) { + // the column is no parent of the requested URL, hence + // just delete all remaining columns + if (columnIndex > 0) { + QList::iterator start = m_columns.begin() + columnIndex; + QList::iterator end = m_columns.end(); + for (QList::iterator it = start; it != end; ++it) { + deleteColumn(*it); + } + m_columns.erase(start, end); + + const int maxIndex = m_columns.count() - 1; + Q_ASSERT(maxIndex >= 0); + if (m_index > maxIndex) { + m_index = maxIndex; + } + break; + } + } + ++columnIndex; + } + + // Create missing columns. Assuming that the path is "/home/peter/Temp/" and + // the target path is "/home/peter/Temp/a/b/c/", then the columns "a", "b" and + // "c" will be created. + const int lastIndex = m_columns.count() - 1; + Q_ASSERT(lastIndex >= 0); + + const KUrl& activeUrl = m_columns[lastIndex]->url(); + Q_ASSERT(activeUrl.isParentOf(url)); + Q_ASSERT(activeUrl != url); + + QString path = activeUrl.url(KUrl::AddTrailingSlash); + const QString targetPath = url.url(KUrl::AddTrailingSlash); + + columnIndex = lastIndex; + int slashIndex = path.count('/'); + bool hasSubPath = (slashIndex >= 0); + while (hasSubPath) { + const QString subPath = targetPath.section('/', slashIndex, slashIndex); + if (subPath.isEmpty()) { + hasSubPath = false; + } else { + path += subPath + '/'; + ++slashIndex; + + const KUrl childUrl = KUrl(path); + m_columns[columnIndex]->setChildUrl(childUrl); + columnIndex++; + + DolphinColumnView* column = new DolphinColumnView(viewport(), this, childUrl); + m_columns.append(column); + + // Before invoking layoutColumns() the column must be set visible temporary. + // To prevent a flickering the initial geometry is set to a hidden position. + column->setGeometry(QRect(-1, -1, 1, 1)); + column->show(); + layoutColumns(); + updateScrollBar(); + } + } + + requestActivation(m_columns[columnIndex]); +} + +void DolphinColumnViewContainer::mousePressEvent(QMouseEvent* event) +{ + m_dolphinViewController->requestActivation(); + QScrollArea::mousePressEvent(event); +} + +void DolphinColumnViewContainer::keyPressEvent(QKeyEvent* event) +{ + if (event->key() == Qt::Key_Left) { + if (m_index > 0) { + requestActivation(m_columns[m_index - 1]); + } + } else { + QScrollArea::keyPressEvent(event); + } +} + +void DolphinColumnViewContainer::resizeEvent(QResizeEvent* event) +{ + QScrollArea::resizeEvent(event); + layoutColumns(); + updateScrollBar(); + assureVisibleActiveColumn(); +} + +void DolphinColumnViewContainer::wheelEvent(QWheelEvent* event) +{ + // let Ctrl+wheel events propagate to the DolphinView for icon zooming + if ((event->modifiers() & Qt::ControlModifier) == Qt::ControlModifier) { + event->ignore(); + } else { + QScrollArea::wheelEvent(event); + } +} + +void DolphinColumnViewContainer::moveContentHorizontally(int x) +{ + m_contentX = isRightToLeft() ? +x : -x; + layoutColumns(); +} + +void DolphinColumnViewContainer::updateColumnsBackground(bool active) +{ + if (active == m_active) { + return; + } + + m_active = active; + + // dim the background of the viewport + const QPalette::ColorRole role = viewport()->backgroundRole(); + QColor background = viewport()->palette().color(role); + background.setAlpha(0); // make background transparent + + QPalette palette = viewport()->palette(); + palette.setColor(role, background); + viewport()->setPalette(palette); + + foreach (DolphinColumnView* column, m_columns) { + column->updateBackground(); + } +} + +void DolphinColumnViewContainer::updateActiveUrl() +{ + const KUrl activeUrl = m_columns[m_index]->url(); + m_dolphinViewController->requestUrlChange(activeUrl); +} + +void DolphinColumnViewContainer::layoutColumns() +{ + const int gap = 4; + + ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings(); + const int columnWidth = settings->columnWidth(); + + QRect emptyViewportRect; + if (isRightToLeft()) { + int x = viewport()->width() - columnWidth + m_contentX; + foreach (DolphinColumnView* column, m_columns) { + column->setGeometry(QRect(x, 0, columnWidth - gap, viewport()->height())); + x -= columnWidth; + } + emptyViewportRect = QRect(0, 0, x + columnWidth - gap, viewport()->height()); + } else { + int x = m_contentX; + foreach (DolphinColumnView* column, m_columns) { + column->setGeometry(QRect(x, 0, columnWidth - gap, viewport()->height())); + x += columnWidth; + } + emptyViewportRect = QRect(x, 0, viewport()->width() - x - gap, viewport()->height()); + } + + if (emptyViewportRect.isValid()) { + m_emptyViewport->show(); + m_emptyViewport->setGeometry(emptyViewportRect); + } else { + m_emptyViewport->hide(); + } +} + +void DolphinColumnViewContainer::updateScrollBar() +{ + ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings(); + const int contentWidth = m_columns.count() * settings->columnWidth(); + + horizontalScrollBar()->setPageStep(contentWidth); + horizontalScrollBar()->setRange(0, contentWidth - viewport()->width()); +} + +void DolphinColumnViewContainer::assureVisibleActiveColumn() +{ + const int viewportWidth = viewport()->width(); + const int x = activeColumn()->x(); + + ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings(); + const int width = settings->columnWidth(); + + if (x + width > viewportWidth) { + const int newContentX = m_contentX - x - width + viewportWidth; + if (isRightToLeft()) { + m_animation->setFrameRange(m_contentX, newContentX); + } else { + m_animation->setFrameRange(-m_contentX, -newContentX); + } + if (m_animation->state() != QTimeLine::Running) { + m_animation->start(); + } + } else if (x < 0) { + const int newContentX = m_contentX - x; + if (isRightToLeft()) { + m_animation->setFrameRange(m_contentX, newContentX); + } else { + m_animation->setFrameRange(-m_contentX, -newContentX); + } + if (m_animation->state() != QTimeLine::Running) { + m_animation->start(); + } + } +} + +void DolphinColumnViewContainer::requestActivation(DolphinColumnView* column) +{ + if (m_dolphinViewController->itemView() != column) { + m_dolphinViewController->setItemView(column); + } + if (focusProxy() != column) { + setFocusProxy(column); + } + + if (column->isActive()) { + assureVisibleActiveColumn(); + } else { + // Deactivate the currently active column + if (m_index >= 0) { + m_columns[m_index]->setActive(false); + } + + // Get the index of the column that should get activated + int index = 0; + foreach (DolphinColumnView* currColumn, m_columns) { + if (currColumn == column) { + break; + } + ++index; + } + + Q_ASSERT(index != m_index); + Q_ASSERT(index < m_columns.count()); + + // Activate the requested column + m_index = index; + m_columns[m_index]->setActive(true); + + assureVisibleActiveColumn(); + m_activeUrlTimer->start(); // calls slot updateActiveUrl() + } +} + +void DolphinColumnViewContainer::removeAllColumns() +{ + QList::iterator start = m_columns.begin() + 1; + QList::iterator end = m_columns.end(); + for (QList::iterator it = start; it != end; ++it) { + deleteColumn(*it); + } + m_columns.erase(start, end); + m_index = 0; + m_columns[0]->setActive(true); + assureVisibleActiveColumn(); +} + +QPoint DolphinColumnViewContainer::columnPosition(DolphinColumnView* column, const QPoint& point) const +{ + const QPoint topLeft = column->frameGeometry().topLeft(); + return QPoint(point.x() - topLeft.x(), point.y() - topLeft.y()); +} + +void DolphinColumnViewContainer::deleteColumn(DolphinColumnView* column) +{ + if (column == 0) { + return; + } + + if (m_dolphinViewController->itemView() == column) { + m_dolphinViewController->setItemView(0); + } + // deleteWhenNotDragSource(column) does not necessarily delete column, + // and we want its preview generator destroyed immediately. + column->hide(); + // Prevent automatic destruction of column when this DolphinColumnViewContainer + // is destroyed. + column->setParent(0); + column->disconnect(); + + if (DragAndDropHelper::instance().isDragSource(column)) { + // The column is a drag source (the feature "Open folders + // during drag operations" is used). Deleting the view + // during an ongoing drag operation is not allowed, so + // this will postponed. + if (m_dragSource != 0) { + // the old stored view is obviously not the drag source anymore + m_dragSource->deleteLater(); + m_dragSource = 0; + } + column->hide(); + column->setParent(0); + column->disconnect(); + + m_dragSource = column; + } else { + column->deleteLater(); + } +} + +#include "dolphincolumnviewcontainer.moc" diff --git a/src/views/dolphincolumnviewcontainer.h b/src/views/dolphincolumnviewcontainer.h new file mode 100644 index 000000000..c67fb3cff --- /dev/null +++ b/src/views/dolphincolumnviewcontainer.h @@ -0,0 +1,147 @@ +/*************************************************************************** + * Copyright (C) 2007-2009 by Peter Penz * + * * + * 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 DOLPHINCOLUMNVIEWCONTAINER_H +#define DOLPHINCOLUMNVIEWCONTAINER_H + +#include "dolphinview.h" + +#include + +#include +#include +#include + +class DolphinColumnView; +class DolphinViewController; +class QFrame; +class QTimeLine; +class QTimer; + +/** + * @brief Represents a container for columns represented as instances + * of DolphinColumnView. + * + * @see DolphinColumnView + */ +class DolphinColumnViewContainer : public QScrollArea +{ + Q_OBJECT + +public: + /** + * @param parent Parent widget. + * @param dolphinViewController Allows the DolphinColumnView to control the + * DolphinView in a limited way. + * @param viewModeController Controller that is used by the DolphinView + * to control the DolphinColumnView. The DolphinColumnView + * only has read access to the controller. + * @param model Directory that is shown. + */ + explicit DolphinColumnViewContainer(QWidget* parent, + DolphinViewController* dolphinViewController, + const ViewModeController* viewModeController); + virtual ~DolphinColumnViewContainer(); + + KUrl rootUrl() const; + + QAbstractItemView* activeColumn() const; + + /** + * Shows the column which represents the URL \a url. If the column + * is already shown, it gets activated, otherwise it will be created. + */ + void showColumn(const KUrl& url); + +protected: + virtual void mousePressEvent(QMouseEvent* event); + virtual void keyPressEvent(QKeyEvent* event); + virtual void resizeEvent(QResizeEvent* event); + virtual void wheelEvent(QWheelEvent* event); + +private slots: + /** + * Moves the content of the columns view to represent + * the scrollbar position \a x. + */ + void moveContentHorizontally(int x); + + /** + * Updates the background color of the columns to respect + * the current activation state \a active. + */ + void updateColumnsBackground(bool active); + + /** + * Tells the Dolphin controller to update the active URL + * to m_activeUrl. The slot is called asynchronously with a + * small delay, as this prevents a flickering when a directory + * from an inactive column gets selected. + */ + void updateActiveUrl(); + +private: + void layoutColumns(); + void updateScrollBar(); + + /** + * Assures that the currently active column is fully visible + * by adjusting the horizontal position of the content. + */ + void assureVisibleActiveColumn(); + + /** + * Request the activation for the column \a column. It is assured + * that the columns gets fully visible by adjusting the horizontal + * position of the content. + */ + void requestActivation(DolphinColumnView* column); + + /** Removes all columns except of the root column. */ + void removeAllColumns(); + + /** + * Returns the position of the point \a point relative to the column + * \a column. + */ + QPoint columnPosition(DolphinColumnView* column, const QPoint& point) const; + + /** + * Deletes the column. If the itemview of the controller is set to the column, + * the controllers itemview is set to 0. + */ + void deleteColumn(DolphinColumnView* column); + +private: + DolphinViewController* m_dolphinViewController; + const ViewModeController* m_viewModeController; + bool m_active; + int m_index; + int m_contentX; + QList m_columns; + QFrame* m_emptyViewport; + QTimeLine* m_animation; + QAbstractItemView* m_dragSource; + + QTimer* m_activeUrlTimer; + + friend class DolphinColumnView; +}; + +#endif diff --git a/src/views/dolphindetailsview.cpp b/src/views/dolphindetailsview.cpp new file mode 100644 index 000000000..961bd7872 --- /dev/null +++ b/src/views/dolphindetailsview.cpp @@ -0,0 +1,1113 @@ +/*************************************************************************** + * Copyright (C) 2006 by Peter Penz (peter.penz@gmx.at) * + * Copyright (C) 2008 by Simon St. James (kdedevel@etotheipiplusone.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 "dolphindetailsview.h" + +#include "additionalinfoaccessor.h" +#include "dolphinmodel.h" +#include "dolphinviewcontroller.h" +#include "dolphinfileitemdelegate.h" +#include "settings/dolphinsettings.h" +#include "dolphinsortfilterproxymodel.h" +#include "dolphinviewautoscroller.h" +#include "draganddrophelper.h" +#include "viewextensionsfactory.h" +#include "viewmodecontroller.h" +#include "viewproperties.h" +#include "zoomlevelinfo.h" + +#include "dolphin_detailsmodesettings.h" +#include "dolphin_generalsettings.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +DolphinDetailsView::DolphinDetailsView(QWidget* parent, + DolphinViewController* dolphinViewController, + const ViewModeController* viewModeController, + DolphinSortFilterProxyModel* proxyModel) : + QTreeView(parent), + m_autoResize(true), + m_expandingTogglePressed(false), + m_keyPressed(false), + m_useDefaultIndexAt(true), + m_ignoreScrollTo(false), + m_dolphinViewController(dolphinViewController), + m_viewModeController(viewModeController), + m_extensionsFactory(0), + m_expandableFoldersAction(0), + m_expandedUrls(), + m_font(), + m_decorationSize(), + m_band() +{ + const DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings(); + Q_ASSERT(settings != 0); + Q_ASSERT(dolphinViewController != 0); + Q_ASSERT(viewModeController != 0); + + setLayoutDirection(Qt::LeftToRight); + setAcceptDrops(true); + setSortingEnabled(true); + setUniformRowHeights(true); + setSelectionBehavior(SelectItems); + setDragDropMode(QAbstractItemView::DragDrop); + setDropIndicatorShown(false); + setAlternatingRowColors(true); + setRootIsDecorated(settings->expandableFolders()); + setItemsExpandable(settings->expandableFolders()); + setEditTriggers(QAbstractItemView::NoEditTriggers); + setModel(proxyModel); + + setMouseTracking(true); + + const ViewProperties props(viewModeController->url()); + setSortIndicatorSection(props.sorting()); + setSortIndicatorOrder(props.sortOrder()); + + QHeaderView* headerView = header(); + connect(headerView, SIGNAL(sectionClicked(int)), + this, SLOT(synchronizeSortingState(int))); + headerView->setContextMenuPolicy(Qt::CustomContextMenu); + connect(headerView, SIGNAL(customContextMenuRequested(const QPoint&)), + this, SLOT(configureSettings(const QPoint&))); + connect(headerView, SIGNAL(sectionResized(int, int, int)), + this, SLOT(slotHeaderSectionResized(int, int, int))); + connect(headerView, SIGNAL(sectionHandleDoubleClicked(int)), + this, SLOT(disableAutoResizing())); + + connect(parent, SIGNAL(sortingChanged(DolphinView::Sorting)), + this, SLOT(setSortIndicatorSection(DolphinView::Sorting))); + connect(parent, SIGNAL(sortOrderChanged(Qt::SortOrder)), + this, SLOT(setSortIndicatorOrder(Qt::SortOrder))); + + connect(this, SIGNAL(clicked(const QModelIndex&)), + dolphinViewController, SLOT(requestTab(const QModelIndex&))); + if (KGlobalSettings::singleClick()) { + connect(this, SIGNAL(clicked(const QModelIndex&)), + dolphinViewController, SLOT(triggerItem(const QModelIndex&))); + } else { + connect(this, SIGNAL(doubleClicked(const QModelIndex&)), + dolphinViewController, SLOT(triggerItem(const QModelIndex&))); + } + + connect(this, SIGNAL(entered(const QModelIndex&)), + this, SLOT(slotEntered(const QModelIndex&))); + connect(this, SIGNAL(viewportEntered()), + dolphinViewController, SLOT(emitViewportEntered())); + connect(viewModeController, SIGNAL(zoomLevelChanged(int)), + this, SLOT(setZoomLevel(int))); + connect(dolphinViewController->view(), SIGNAL(additionalInfoChanged()), + this, SLOT(updateColumnVisibility())); + connect(viewModeController, SIGNAL(activationChanged(bool)), + this, SLOT(slotActivationChanged(bool))); + + if (settings->useSystemFont()) { + m_font = KGlobalSettings::generalFont(); + } else { + m_font = QFont(settings->fontFamily(), + qRound(settings->fontSize()), + settings->fontWeight(), + settings->italicFont()); + m_font.setPointSizeF(settings->fontSize()); + } + + setVerticalScrollMode(QTreeView::ScrollPerPixel); + setHorizontalScrollMode(QTreeView::ScrollPerPixel); + + const DolphinView* view = dolphinViewController->view(); + connect(view, SIGNAL(showPreviewChanged()), + this, SLOT(slotShowPreviewChanged())); + + + setFocus(); + viewport()->installEventFilter(this); + + connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)), + this, SLOT(slotGlobalSettingsChanged(int))); + + m_useDefaultIndexAt = false; + + m_expandableFoldersAction = new QAction(i18nc("@option:check", "Expandable Folders"), this); + m_expandableFoldersAction->setCheckable(true); + 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, dolphinViewController, viewModeController); + m_extensionsFactory->fileItemDelegate()->setMinimizedNameColumn(true); + m_extensionsFactory->setAutoFolderExpandingEnabled(settings->expandableFolders()); +} + +DolphinDetailsView::~DolphinDetailsView() +{ +} + +QSet DolphinDetailsView::expandedUrls() const +{ + return m_expandedUrls; +} + +QRegion DolphinDetailsView::visualRegionForSelection(const QItemSelection& selection) const +{ + // We have to make sure that the visualRect of each model index is inside the region. + // QTreeView::visualRegionForSelection does not do it right because it assumes implicitly + // that all visualRects have the same width, which is in general not the case here. + QRegion selectionRegion; + const QModelIndexList indexes = selection.indexes(); + + foreach(const QModelIndex& index, indexes) { + selectionRegion += visualRect(index); + } + + return selectionRegion; +} + +bool DolphinDetailsView::event(QEvent* event) +{ + switch (event->type()) { + case QEvent::Polish: + header()->setResizeMode(QHeaderView::Interactive); + updateColumnVisibility(); + break; + + case QEvent::FocusOut: + // If a key-press triggers an action that e. g. opens a dialog, the + // widget gets no key-release event. Assure that the pressed state + // is reset to prevent accidently setting the current index during a selection. + m_keyPressed = false; + break; + + default: + break; + } + + return QTreeView::event(event); +} + +QStyleOptionViewItem DolphinDetailsView::viewOptions() const +{ + QStyleOptionViewItem viewOptions = QTreeView::viewOptions(); + viewOptions.font = m_font; + viewOptions.fontMetrics = QFontMetrics(m_font); + viewOptions.showDecorationSelected = true; + viewOptions.decorationSize = m_decorationSize; + return viewOptions; +} + +void DolphinDetailsView::contextMenuEvent(QContextMenuEvent* event) +{ + QTreeView::contextMenuEvent(event); + + DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings(); + m_expandableFoldersAction->setChecked(settings->expandableFolders()); + m_dolphinViewController->triggerContextMenuRequest(event->pos(), + QList() << m_expandableFoldersAction); +} + +void DolphinDetailsView::mousePressEvent(QMouseEvent* event) +{ + m_dolphinViewController->requestActivation(); + + const QModelIndex current = currentIndex(); + QTreeView::mousePressEvent(event); + + m_expandingTogglePressed = isAboveExpandingToggle(event->pos()); + + const QModelIndex index = indexAt(event->pos()); + const bool updateState = index.isValid() && + (index.column() == DolphinModel::Name) && + (event->button() == Qt::LeftButton); + if (updateState) { + setState(QAbstractItemView::DraggingState); + } + + if (!index.isValid() || (index.column() != DolphinModel::Name)) { + // the mouse press is done somewhere outside the filename column + if (QApplication::mouseButtons() & Qt::MidButton) { + m_dolphinViewController->replaceUrlByClipboard(); + } + + const Qt::KeyboardModifiers mod = QApplication::keyboardModifiers(); + if (!m_expandingTogglePressed && !(mod & Qt::ShiftModifier) && !(mod & Qt::ControlModifier)) { + clearSelection(); + } + + // restore the current index, other columns are handled as viewport area. + // setCurrentIndex(...) implicitly calls scrollTo(...), which we want to ignore. + m_ignoreScrollTo = true; + selectionModel()->setCurrentIndex(current, QItemSelectionModel::Current); + m_ignoreScrollTo = false; + + if ((event->button() == Qt::LeftButton) && !m_expandingTogglePressed) { + // Inform Qt about what we are doing - otherwise it starts dragging items around! + setState(DragSelectingState); + m_band.show = true; + // Incremental update data will not be useful - start from scratch. + m_band.ignoreOldInfo = true; + const QPoint scrollPos(horizontalScrollBar()->value(), verticalScrollBar()->value()); + m_band.origin = event->pos() + scrollPos; + m_band.destination = m_band.origin; + m_band.originalSelection = selectionModel()->selection(); + } + } +} + +void DolphinDetailsView::mouseMoveEvent(QMouseEvent* event) +{ + if (m_expandingTogglePressed) { + // Per default QTreeView starts either a selection or a drag operation when dragging + // the expanding toggle button (Qt-issue - see TODO comment in DolphinIconsView::mousePressEvent()). + // Turn off this behavior in Dolphin to stay predictable: + setState(QAbstractItemView::NoState); + return; + } + + if (m_band.show) { + const QPoint mousePos = event->pos(); + const QModelIndex index = indexAt(mousePos); + if (!index.isValid()) { + // the destination of the selection rectangle is above the viewport. In this + // case QTreeView does no selection at all, which is not the wanted behavior + // in Dolphin -> select all items within the elastic band rectangle + updateElasticBandSelection(); + } + + // TODO: enable QTreeView::mouseMoveEvent(event) again, as soon + // as the Qt-issue #199631 has been fixed. + // QTreeView::mouseMoveEvent(event); + QAbstractItemView::mouseMoveEvent(event); + updateElasticBand(); + } else { + // TODO: enable QTreeView::mouseMoveEvent(event) again, as soon + // as the Qt-issue #199631 has been fixed. + // QTreeView::mouseMoveEvent(event); + QAbstractItemView::mouseMoveEvent(event); + } +} + +void DolphinDetailsView::mouseReleaseEvent(QMouseEvent* event) +{ + if (!m_expandingTogglePressed) { + const QModelIndex index = indexAt(event->pos()); + if (index.isValid() && (index.column() == DolphinModel::Name)) { + QTreeView::mouseReleaseEvent(event); + } else { + // don't change the current index if the cursor is released + // above any other column than the name column, as the other + // columns act as viewport + const QModelIndex current = currentIndex(); + QTreeView::mouseReleaseEvent(event); + selectionModel()->setCurrentIndex(current, QItemSelectionModel::Current); + } + } + m_expandingTogglePressed = false; + + if (m_band.show) { + setState(NoState); + updateElasticBand(); + m_band.show = false; + } +} + +void DolphinDetailsView::startDrag(Qt::DropActions supportedActions) +{ + DragAndDropHelper::instance().startDrag(this, supportedActions, m_dolphinViewController); + m_band.show = false; +} + +void DolphinDetailsView::dragEnterEvent(QDragEnterEvent* event) +{ + if (DragAndDropHelper::instance().isMimeDataSupported(event->mimeData())) { + event->acceptProposedAction(); + } + + if (m_band.show) { + updateElasticBand(); + m_band.show = false; + } +} + +void DolphinDetailsView::dragLeaveEvent(QDragLeaveEvent* event) +{ + QTreeView::dragLeaveEvent(event); + setDirtyRegion(m_dropRect); +} + +void DolphinDetailsView::dragMoveEvent(QDragMoveEvent* event) +{ + QTreeView::dragMoveEvent(event); + + // TODO: remove this code when the issue #160611 is solved in Qt 4.4 + setDirtyRegion(m_dropRect); + const QModelIndex index = indexAt(event->pos()); + if (index.isValid() && (index.column() == DolphinModel::Name)) { + const KFileItem item = m_dolphinViewController->itemForIndex(index); + if (!item.isNull() && item.isDir()) { + m_dropRect = visualRect(index); + } else { + m_dropRect.setSize(QSize()); // set as invalid + } + setDirtyRegion(m_dropRect); + } + + if (DragAndDropHelper::instance().isMimeDataSupported(event->mimeData())) { + // accept url drops, independently from the destination item + event->acceptProposedAction(); + } +} + +void DolphinDetailsView::dropEvent(QDropEvent* event) +{ + const QModelIndex index = indexAt(event->pos()); + KFileItem item; + if (index.isValid() && (index.column() == DolphinModel::Name)) { + item = m_dolphinViewController->itemForIndex(index); + } + m_dolphinViewController->indicateDroppedUrls(item, m_viewModeController->url(), event); + QTreeView::dropEvent(event); +} + +void DolphinDetailsView::paintEvent(QPaintEvent* event) +{ + QTreeView::paintEvent(event); + if (m_band.show) { + // The following code has been taken from QListView + // and adapted to DolphinDetailsView. + // (C) 1992-2007 Trolltech ASA + QStyleOptionRubberBand opt; + opt.initFrom(this); + opt.shape = QRubberBand::Rectangle; + opt.opaque = false; + opt.rect = elasticBandRect(); + + QPainter painter(viewport()); + painter.save(); + style()->drawControl(QStyle::CE_RubberBand, &opt, &painter); + painter.restore(); + } +} + +void DolphinDetailsView::keyPressEvent(QKeyEvent* event) +{ + // If the Control modifier is pressed, a multiple selection + // is done and DolphinDetailsView::currentChanged() may not + // not change the selection in a custom way. + m_keyPressed = !(event->modifiers() & Qt::ControlModifier); + + QTreeView::keyPressEvent(event); + m_dolphinViewController->handleKeyPressEvent(event); +} + +void DolphinDetailsView::keyReleaseEvent(QKeyEvent* event) +{ + QTreeView::keyReleaseEvent(event); + m_keyPressed = false; +} + +void DolphinDetailsView::resizeEvent(QResizeEvent* event) +{ + QTreeView::resizeEvent(event); + if (m_autoResize) { + resizeColumns(); + } +} + +void DolphinDetailsView::wheelEvent(QWheelEvent* event) +{ + const int step = m_decorationSize.height(); + verticalScrollBar()->setSingleStep(step); + QTreeView::wheelEvent(event); +} + +void DolphinDetailsView::currentChanged(const QModelIndex& current, const QModelIndex& previous) +{ + QTreeView::currentChanged(current, previous); + m_extensionsFactory->handleCurrentIndexChange(current, previous); + + // Stay consistent with QListView: When changing the current index by key presses, + // also change the selection. + if (m_keyPressed) { + setCurrentIndex(current); + } + + // If folders are expanded, the width which is available for editing may have changed + // because it depends on the level of the current item in the folder hierarchy. + adjustMaximumSizeForEditing(current); +} + +bool DolphinDetailsView::eventFilter(QObject* watched, QEvent* event) +{ + if ((watched == viewport()) && (event->type() == QEvent::Leave)) { + // if the mouse is above an item and moved very fast outside the widget, + // no viewportEntered() signal might be emitted although the mouse has been moved + // above the viewport + m_dolphinViewController->emitViewportEntered(); + } + + return QTreeView::eventFilter(watched, event); +} + +QModelIndex DolphinDetailsView::indexAt(const QPoint& point) const +{ + // the blank portion of the name column counts as empty space + const QModelIndex index = QTreeView::indexAt(point); + const bool isAboveEmptySpace = !m_useDefaultIndexAt && + (index.column() == KDirModel::Name) && !visualRect(index).contains(point); + return isAboveEmptySpace ? QModelIndex() : index; +} + +QRect DolphinDetailsView::visualRect(const QModelIndex& index) const +{ + QRect rect = QTreeView::visualRect(index); + const KFileItem item = m_dolphinViewController->itemForIndex(index); + if (!item.isNull()) { + const int width = DolphinFileItemDelegate::nameColumnWidth(item.text(), viewOptions()); + rect.setWidth(width); + } + + return rect; +} + +void DolphinDetailsView::setSelection(const QRect& rect, QItemSelectionModel::SelectionFlags command) +{ + // We must override setSelection() as Qt calls it internally and when this happens + // we must ensure that the default indexAt() is used. + if (!m_band.show) { + m_useDefaultIndexAt = true; + QTreeView::setSelection(rect, command); + m_useDefaultIndexAt = false; + } else { + // Use our own elastic band selection algorithm + updateElasticBandSelection(); + } +} + +void DolphinDetailsView::scrollTo(const QModelIndex & index, ScrollHint hint) +{ + if (!m_ignoreScrollTo) { + QTreeView::scrollTo(index, hint); + } +} + +void DolphinDetailsView::setSortIndicatorSection(DolphinView::Sorting sorting) +{ + header()->setSortIndicator(sorting, header()->sortIndicatorOrder()); +} + +void DolphinDetailsView::setSortIndicatorOrder(Qt::SortOrder sortOrder) +{ + header()->setSortIndicator(header()->sortIndicatorSection(), sortOrder); +} + +void DolphinDetailsView::synchronizeSortingState(int column) +{ + // The sorting has already been changed in QTreeView if this slot is + // invoked, but Dolphin is not informed about this. + DolphinView::Sorting sorting = DolphinSortFilterProxyModel::sortingForColumn(column); + const Qt::SortOrder sortOrder = header()->sortIndicatorOrder(); + m_dolphinViewController->indicateSortingChange(sorting); + m_dolphinViewController->indicateSortOrderChange(sortOrder); +} + +void DolphinDetailsView::slotEntered(const QModelIndex& index) +{ + if (index.column() == DolphinModel::Name) { + m_dolphinViewController->emitItemEntered(index); + } else { + m_dolphinViewController->emitViewportEntered(); + } +} + +void DolphinDetailsView::updateElasticBand() +{ + if (m_band.show) { + QRect dirtyRegion(elasticBandRect()); + const QPoint scrollPos(horizontalScrollBar()->value(), verticalScrollBar()->value()); + m_band.destination = viewport()->mapFromGlobal(QCursor::pos()) + scrollPos; + // Going above the (logical) top-left of the view causes complications during selection; + // we may as well prevent it. + if (m_band.destination.y() < 0) { + m_band.destination.setY(0); + } + if (m_band.destination.x() < 0) { + m_band.destination.setX(0); + } + dirtyRegion = dirtyRegion.united(elasticBandRect()); + setDirtyRegion(dirtyRegion); + } +} + +QRect DolphinDetailsView::elasticBandRect() const +{ + const QPoint scrollPos(horizontalScrollBar()->value(), verticalScrollBar()->value()); + + const QPoint topLeft = m_band.origin - scrollPos; + const QPoint bottomRight = m_band.destination - scrollPos; + return QRect(topLeft, bottomRight).normalized(); +} + +void DolphinDetailsView::setZoomLevel(int level) +{ + const int size = ZoomLevelInfo::iconSizeForZoomLevel(level); + DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings(); + + const bool showPreview = m_dolphinViewController->view()->showPreview(); + if (showPreview) { + settings->setPreviewSize(size); + } else { + settings->setIconSize(size); + } + + updateDecorationSize(showPreview); +} + +void DolphinDetailsView::slotShowPreviewChanged() +{ + const DolphinView* view = m_dolphinViewController->view(); + updateDecorationSize(view->showPreview()); +} + +void DolphinDetailsView::configureSettings(const QPoint& pos) +{ + KMenu popup(this); + popup.addTitle(i18nc("@title:menu", "Columns")); + + // add checkbox items for each column + QHeaderView* headerView = header(); + const int columns = model()->columnCount(); + for (int i = 0; i < columns; ++i) { + const int logicalIndex = headerView->logicalIndex(i); + const QString text = model()->headerData(logicalIndex, Qt::Horizontal).toString(); + if (!text.isEmpty()) { + QAction* action = popup.addAction(text); + action->setCheckable(true); + action->setChecked(!headerView->isSectionHidden(logicalIndex)); + action->setData(logicalIndex); + action->setEnabled(logicalIndex != DolphinModel::Name); + } + } + popup.addSeparator(); + + QAction* activatedAction = popup.exec(header()->mapToGlobal(pos)); + if (activatedAction != 0) { + const bool show = activatedAction->isChecked(); + const int columnIndex = activatedAction->data().toInt(); + + KFileItemDelegate::InformationList list = m_dolphinViewController->view()->additionalInfo(); + const KFileItemDelegate::Information info = infoForColumn(columnIndex); + if (show) { + Q_ASSERT(!list.contains(info)); + list.append(info); + } else { + Q_ASSERT(list.contains(info)); + const int index = list.indexOf(info); + list.removeAt(index); + } + + m_dolphinViewController->indicateAdditionalInfoChange(list); + setColumnHidden(columnIndex, !show); + resizeColumns(); + } +} + +void DolphinDetailsView::updateColumnVisibility() +{ + QHeaderView* headerView = header(); + disconnect(headerView, SIGNAL(sectionMoved(int, int, int)), + this, SLOT(saveColumnPositions())); + + const DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings(); + const QList columnPositions = settings->columnPositions(); + + const KFileItemDelegate::InformationList list = m_dolphinViewController->view()->additionalInfo(); + for (int i = DolphinModel::Name; i < DolphinModel::ExtraColumnCount; ++i) { + const KFileItemDelegate::Information info = infoForColumn(i); + const bool hide = !list.contains(info) && (i != DolphinModel::Name); + if (isColumnHidden(i) != hide) { + setColumnHidden(i, hide); + } + + // If the list columnPositions has been written by an older Dolphin version, + // its length might be smaller than DolphinModel::ExtraColumnCount. Therefore, + // we have to check if item number i exists before accessing it. + if (i < columnPositions.length()) { + const int position = columnPositions[i]; + + // The position might be outside the correct range if the list columnPositions + // has been written by a newer Dolphin version with more columns. + if (position < DolphinModel::ExtraColumnCount) { + const int from = headerView->visualIndex(i); + headerView->moveSection(from, position); + } + } + } + + resizeColumns(); + + connect(headerView, SIGNAL(sectionMoved(int, int, int)), + this, SLOT(saveColumnPositions())); +} + +void DolphinDetailsView::saveColumnPositions() +{ + QList columnPositions; + for (int i = DolphinModel::Name; i < DolphinModel::ExtraColumnCount; ++i) { + columnPositions.append(header()->visualIndex(i)); + } + + DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings(); + settings->setColumnPositions(columnPositions); +} + +void DolphinDetailsView::slotHeaderSectionResized(int logicalIndex, int oldSize, int newSize) +{ + Q_UNUSED(logicalIndex); + Q_UNUSED(oldSize); + Q_UNUSED(newSize); + // If the user changes the size of the headers, the autoresize feature should be + // turned off. As there is no dedicated interface to find out whether the header + // section has been resized by the user or by a resize event, another approach is used. + // Attention: Take care when changing the if-condition to verify that there is no + // regression in combination with bug 178630 (see fix in comment #8). + if ((QApplication::mouseButtons() & Qt::LeftButton) && header()->underMouse()) { + disableAutoResizing(); + } + + adjustMaximumSizeForEditing(currentIndex()); +} + +void DolphinDetailsView::slotActivationChanged(bool active) +{ + setAlternatingRowColors(active); +} + +void DolphinDetailsView::disableAutoResizing() +{ + m_autoResize = false; +} + +void DolphinDetailsView::requestActivation() +{ + m_dolphinViewController->requestActivation(); +} + +void DolphinDetailsView::slotGlobalSettingsChanged(int category) +{ + Q_UNUSED(category); + + const DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings(); + Q_ASSERT(settings != 0); + if (settings->useSystemFont()) { + m_font = KGlobalSettings::generalFont(); + } + //Disconnect then reconnect, since the settings have been changed, the connection requirements may have also. + disconnect(this, SIGNAL(clicked(QModelIndex)), m_dolphinViewController, SLOT(triggerItem(QModelIndex))); + disconnect(this, SIGNAL(doubleClicked(QModelIndex)), m_dolphinViewController, SLOT(triggerItem(QModelIndex))); + if (KGlobalSettings::singleClick()) { + connect(this, SIGNAL(clicked(QModelIndex)), m_dolphinViewController, SLOT(triggerItem(QModelIndex))); + } else { + connect(this, SIGNAL(doubleClicked(QModelIndex)), m_dolphinViewController, SLOT(triggerItem(QModelIndex))); + } +} + +void DolphinDetailsView::updateElasticBandSelection() +{ + if (!m_band.show) { + return; + } + + // Ensure the elastic band itself is up-to-date, in + // case we are being called due to e.g. a drag event. + updateElasticBand(); + + // Clip horizontally to the name column, as some filenames will be + // longer than the column. We don't clip vertically as origin + // may be above or below the current viewport area. + const int nameColumnX = header()->sectionPosition(DolphinModel::Name); + const int nameColumnWidth = header()->sectionSize(DolphinModel::Name); + QRect selRect = elasticBandRect().normalized(); + QRect nameColumnArea(nameColumnX, selRect.y(), nameColumnWidth, selRect.height()); + selRect = nameColumnArea.intersect(selRect).normalized(); + // Get the last elastic band rectangle, expressed in viewpoint coordinates. + const QPoint scrollPos(horizontalScrollBar()->value(), verticalScrollBar()->value()); + QRect oldSelRect = QRect(m_band.lastSelectionOrigin - scrollPos, m_band.lastSelectionDestination - scrollPos).normalized(); + + if (selRect.isNull()) { + selectionModel()->select(m_band.originalSelection, QItemSelectionModel::ClearAndSelect); + m_band.ignoreOldInfo = true; + return; + } + + if (!m_band.ignoreOldInfo) { + // Do some quick checks to see if we can rule out the need to + // update the selection. + Q_ASSERT(uniformRowHeights()); + QModelIndex dummyIndex = model()->index(0, 0); + if (!dummyIndex.isValid()) { + // No items in the model presumably. + return; + } + + // If the elastic band does not cover the same rows as before, we'll + // need to re-check, and also invalidate the old item distances. + const int rowHeight = QTreeView::rowHeight(dummyIndex); + const bool coveringSameRows = + (selRect.top() / rowHeight == oldSelRect.top() / rowHeight) && + (selRect.bottom() / rowHeight == oldSelRect.bottom() / rowHeight); + if (coveringSameRows) { + // Covering the same rows, but have we moved far enough horizontally + // that we might have (de)selected some other items? + const bool itemSelectionChanged = + ((selRect.left() > oldSelRect.left()) && + (selRect.left() > m_band.insideNearestLeftEdge)) || + ((selRect.left() < oldSelRect.left()) && + (selRect.left() <= m_band.outsideNearestLeftEdge)) || + ((selRect.right() < oldSelRect.right()) && + (selRect.left() >= m_band.insideNearestRightEdge)) || + ((selRect.right() > oldSelRect.right()) && + (selRect.right() >= m_band.outsideNearestRightEdge)); + + if (!itemSelectionChanged) { + return; + } + } + } else { + // This is the only piece of optimization data that needs to be explicitly + // discarded. + m_band.lastSelectionOrigin = QPoint(); + m_band.lastSelectionDestination = QPoint(); + oldSelRect = selRect; + } + + // Do the selection from scratch. Force a update of the horizontal distances info. + m_band.insideNearestLeftEdge = nameColumnX + nameColumnWidth + 1; + m_band.insideNearestRightEdge = nameColumnX - 1; + m_band.outsideNearestLeftEdge = nameColumnX - 1; + m_band.outsideNearestRightEdge = nameColumnX + nameColumnWidth + 1; + + // Include the old selection rect as well, so we can deselect + // items that were inside it but not in the new selRect. + const QRect boundingRect = selRect.united(oldSelRect).normalized(); + if (boundingRect.isNull()) { + return; + } + + // Get the index of the item in this row in the name column. + // TODO - would this still work if the columns could be re-ordered? + QModelIndex startIndex = QTreeView::indexAt(boundingRect.topLeft()); + if (startIndex.parent().isValid()) { + startIndex = startIndex.parent().child(startIndex.row(), KDirModel::Name); + } else { + startIndex = model()->index(startIndex.row(), KDirModel::Name); + } + if (!startIndex.isValid()) { + selectionModel()->select(m_band.originalSelection, QItemSelectionModel::ClearAndSelect); + m_band.ignoreOldInfo = true; + return; + } + + // Go through all indexes between the top and bottom of boundingRect, and + // update the selection. + const int verticalCutoff = boundingRect.bottom(); + QModelIndex currIndex = startIndex; + QModelIndex lastIndex; + bool allItemsInBoundDone = false; + + // Calling selectionModel()->select(...) for each item that needs to be + // toggled is slow as each call emits selectionChanged(...) so store them + // and do the selection toggle in one batch. + QItemSelection itemsToToggle; + // QItemSelection's deal with continuous ranges of indexes better than + // single indexes, so try to portion items that need to be toggled into ranges. + bool formingToggleIndexRange = false; + QModelIndex toggleIndexRangeBegin = QModelIndex(); + + do { + QRect currIndexRect = visualRect(currIndex); + + // Update some optimization info as we go. + const int cr = currIndexRect.right(); + const int cl = currIndexRect.left(); + const int sl = selRect.left(); + const int sr = selRect.right(); + // "The right edge of the name is outside of the rect but nearer than m_outsideNearestLeft", etc + if ((cr < sl && cr > m_band.outsideNearestLeftEdge)) { + m_band.outsideNearestLeftEdge = cr; + } + if ((cl > sr && cl < m_band.outsideNearestRightEdge)) { + m_band.outsideNearestRightEdge = cl; + } + if ((cl >= sl && cl <= sr && cl > m_band.insideNearestRightEdge)) { + m_band.insideNearestRightEdge = cl; + } + if ((cr >= sl && cr <= sr && cr < m_band.insideNearestLeftEdge)) { + m_band.insideNearestLeftEdge = cr; + } + + bool currentlySelected = selectionModel()->isSelected(currIndex); + bool originallySelected = m_band.originalSelection.contains(currIndex); + bool intersectsSelectedRect = currIndexRect.intersects(selRect); + bool shouldBeSelected = (intersectsSelectedRect && !originallySelected) || (!intersectsSelectedRect && originallySelected); + bool needToToggleItem = (currentlySelected && !shouldBeSelected) || (!currentlySelected && shouldBeSelected); + if (needToToggleItem && !formingToggleIndexRange) { + toggleIndexRangeBegin = currIndex; + formingToggleIndexRange = true; + } + + // NOTE: indexBelow actually walks up and down expanded trees for us. + QModelIndex nextIndex = indexBelow(currIndex); + allItemsInBoundDone = !nextIndex.isValid() || currIndexRect.top() > verticalCutoff; + + const bool commitToggleIndexRange = formingToggleIndexRange && + (!needToToggleItem || + allItemsInBoundDone || + currIndex.parent() != toggleIndexRangeBegin.parent()); + if (commitToggleIndexRange) { + formingToggleIndexRange = false; + // If this is the last item in the bounds and it is also the beginning of a range, + // don't toggle lastIndex - it will already have been dealt with. + if (!allItemsInBoundDone || toggleIndexRangeBegin != currIndex) { + itemsToToggle.select(toggleIndexRangeBegin, lastIndex); + } + // Need to start a new range immediately with currIndex? + if (needToToggleItem) { + toggleIndexRangeBegin = currIndex; + formingToggleIndexRange = true; + } + if (allItemsInBoundDone && needToToggleItem) { + // Toggle the very last item in the bounds. + itemsToToggle.select(currIndex, currIndex); + } + } + + // next item + lastIndex = currIndex; + currIndex = nextIndex; + } while (!allItemsInBoundDone); + + + selectionModel()->select(itemsToToggle, QItemSelectionModel::Toggle); + + m_band.lastSelectionOrigin = m_band.origin; + m_band.lastSelectionDestination = m_band.destination; + m_band.ignoreOldInfo = false; +} + +void DolphinDetailsView::setFoldersExpandable(bool expandable) +{ + if (!expandable) { + // collapse all expanded folders, as QTreeView::setItemsExpandable(false) + // does not do this task + const int rowCount = model()->rowCount(); + for (int row = 0; row < rowCount; ++row) { + setExpanded(model()->index(row, 0), false); + } + } + DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings(); + settings->setExpandableFolders(expandable); + setRootIsDecorated(expandable); + setItemsExpandable(expandable); + + // The width of the space which is available for editing has changed + // because of the (dis)appearance of the expanding toggles + adjustMaximumSizeForEditing(currentIndex()); +} + +void DolphinDetailsView::slotExpanded(const QModelIndex& index) +{ + KFileItem item = m_dolphinViewController->itemForIndex(index); + if (!item.isNull()) { + m_expandedUrls.insert(item.url()); + } +} + +void DolphinDetailsView::slotCollapsed(const QModelIndex& index) +{ + KFileItem item = m_dolphinViewController->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(); + const int iconSize = showPreview ? settings->previewSize() : settings->iconSize(); + setIconSize(QSize(iconSize, iconSize)); + m_decorationSize = QSize(iconSize, iconSize); + + doItemsLayout(); +} + +KFileItemDelegate::Information DolphinDetailsView::infoForColumn(int columnIndex) const +{ + return AdditionalInfoAccessor::instance().keyForColumn(columnIndex); +} + +void DolphinDetailsView::resizeColumns() +{ + // Using the resize mode QHeaderView::ResizeToContents is too slow (it takes + // around 3 seconds for each (!) resize operation when having > 10000 items). + // This gets a problem especially when opening large directories, where several + // resize operations are received for showing the currently available items during + // loading (the application hangs around 20 seconds when loading > 10000 items). + + QHeaderView* headerView = header(); + QFontMetrics fontMetrics(viewport()->font()); + + // Calculate the required with for each column and store it in columnWidth[] + int columnWidth[DolphinModel::ExtraColumnCount]; + const int defaultWidth = fontMetrics.width("xxxxxxxxxx"); + + for (int i = 0; i < DolphinModel::ExtraColumnCount; ++i) { + const int logicalIndex = headerView->logicalIndex(i); + const QString headline = model()->headerData(logicalIndex, Qt::Horizontal).toString(); + const int headlineWidth = fontMetrics.width(headline); + + columnWidth[i] = qMax(defaultWidth, headlineWidth); + } + + const int defaultSizeWidth = fontMetrics.width("00000 Items"); + if (defaultSizeWidth > columnWidth[DolphinModel::Size]) { + columnWidth[DolphinModel::Size] = defaultSizeWidth; + } + + const int defaultTimeWidth = fontMetrics.width("0000-00-00 00:00"); + if (defaultTimeWidth > columnWidth[DolphinModel::ModifiedTime]) { + columnWidth[DolphinModel::ModifiedTime] = defaultTimeWidth; + } + + int requiredWidth = 0; + for (int i = KDirModel::Size; i < DolphinModel::ExtraColumnCount; ++i) { + if (!isColumnHidden(i)) { + columnWidth[i] += 20; // provide a default gap + requiredWidth += columnWidth[i]; + headerView->resizeSection(i, columnWidth[i]); + } + } + + // Resize the name column in a way that the whole available width is used + columnWidth[KDirModel::Name] = viewport()->width() - requiredWidth; + + const int minNameWidth = 300; + if (columnWidth[KDirModel::Name] < minNameWidth) { + columnWidth[KDirModel::Name] = minNameWidth; + + // It might be possible that the name column width can be + // decreased without clipping any text. For performance + // reasons the exact necessary width for full visible names is + // only checked for up to 200 items: + const int rowCount = model()->rowCount(); + if (rowCount > 0 && rowCount < 200) { + const int nameWidth = sizeHintForColumn(DolphinModel::Name); + if (nameWidth + requiredWidth <= viewport()->width()) { + columnWidth[KDirModel::Name] = viewport()->width() - requiredWidth; + } else if (nameWidth < minNameWidth) { + columnWidth[KDirModel::Name] = nameWidth; + } + } + } + + headerView->resizeSection(KDirModel::Name, columnWidth[KDirModel::Name]); +} + +bool DolphinDetailsView::isAboveExpandingToggle(const QPoint& pos) const +{ + // QTreeView offers no public API to get the information whether an index has an + // expanding toggle and what boundaries the toggle has. The following approach + // also assumes a toggle for file items. + if (itemsExpandable()) { + const QModelIndex index = QTreeView::indexAt(pos); + if (index.isValid() && (index.column() == KDirModel::Name)) { + QRect rect = visualRect(index); + const int toggleSize = rect.height(); + if (isRightToLeft()) { + rect.moveRight(rect.right()); + } else { + rect.moveLeft(rect.x() - toggleSize); + } + rect.setWidth(toggleSize); + + QStyleOption opt; + opt.initFrom(this); + opt.rect = rect; + rect = style()->subElementRect(QStyle::SE_TreeViewDisclosureItem, &opt, this); + + return rect.contains(pos); + } + } + return false; +} + +void DolphinDetailsView::adjustMaximumSizeForEditing(const QModelIndex& index) +{ + // Make sure that the full width of the "Name" column is available for "Rename Inline" + m_extensionsFactory->fileItemDelegate()->setMaximumSize(QTreeView::visualRect(index).size()); +} + +DolphinDetailsView::ElasticBand::ElasticBand() : + show(false), + origin(), + destination(), + lastSelectionOrigin(), + lastSelectionDestination(), + ignoreOldInfo(true), + outsideNearestLeftEdge(0), + outsideNearestRightEdge(0), + insideNearestLeftEdge(0), + insideNearestRightEdge(0) +{ +} + +#include "dolphindetailsview.moc" diff --git a/src/views/dolphindetailsview.h b/src/views/dolphindetailsview.h new file mode 100644 index 000000000..3ac08d337 --- /dev/null +++ b/src/views/dolphindetailsview.h @@ -0,0 +1,287 @@ +/*************************************************************************** + * Copyright (C) 2006 by Peter Penz (peter.penz@gmx.at) * + * Copyright (C) 2008 by Simon St. James (kdedevel@etotheipiplusone.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 DOLPHINDETAILSVIEW_H +#define DOLPHINDETAILSVIEW_H + +#include +#include +#include + +class DolphinViewController; +class DolphinSortFilterProxyModel; +class ViewExtensionsFactory; + +/** + * @brief Represents the details view which shows the name, size, + * date, permissions, owner and group of an item. + * + * The width of the columns is automatically adjusted in a way + * that full available width of the view is used by stretching the width + * of the name column. + */ +class LIBDOLPHINPRIVATE_EXPORT DolphinDetailsView : public QTreeView +{ + Q_OBJECT + +public: + /** + * @param parent Parent widget. + * @param dolphinViewController Allows the DolphinDetailsView to control the + * DolphinView in a limited way. + * @param viewModeController Controller that is used by the DolphinView + * to control the DolphinDetailsView. The DolphinDetailsView + * only has read access to the controller. + * @param model Directory that is shown. + */ + explicit DolphinDetailsView(QWidget* parent, + DolphinViewController* dolphinViewController, + const ViewModeController* viewModeController, + DolphinSortFilterProxyModel* model); + virtual ~DolphinDetailsView(); + + /** + * Returns a set containing the URLs of all expanded items. + */ + QSet expandedUrls() const; + + virtual QRegion visualRegionForSelection(const QItemSelection& selection) const; + +protected: + virtual bool event(QEvent* event); + virtual QStyleOptionViewItem viewOptions() const; + virtual void contextMenuEvent(QContextMenuEvent* event); + virtual void mousePressEvent(QMouseEvent* event); + virtual void mouseMoveEvent(QMouseEvent* event); + virtual void mouseReleaseEvent(QMouseEvent* event); + virtual void startDrag(Qt::DropActions supportedActions); + virtual void dragEnterEvent(QDragEnterEvent* event); + virtual void dragLeaveEvent(QDragLeaveEvent* event); + virtual void dragMoveEvent(QDragMoveEvent* event); + virtual void dropEvent(QDropEvent* event); + virtual void paintEvent(QPaintEvent* event); + virtual void keyPressEvent(QKeyEvent* event); + virtual void keyReleaseEvent(QKeyEvent* event); + virtual void resizeEvent(QResizeEvent* event); + virtual void wheelEvent(QWheelEvent* event); + virtual void currentChanged(const QModelIndex& current, const QModelIndex& previous); + virtual bool eventFilter(QObject* watched, QEvent* event); + virtual QModelIndex indexAt (const QPoint& point) const; + virtual QRect visualRect(const QModelIndex& index) const; + virtual void setSelection(const QRect& rect, QItemSelectionModel::SelectionFlags command); + virtual void scrollTo(const QModelIndex& index, ScrollHint hint = EnsureVisible); + +private slots: + /** + * Sets the sort indicator section of the header view + * corresponding to \a sorting. + */ + void setSortIndicatorSection(DolphinView::Sorting sorting); + + /** + * Sets the sort indicator order of the header view + * corresponding to \a sortOrder. + */ + void setSortIndicatorOrder(Qt::SortOrder sortOrder); + + /** + * Synchronizes the sorting state of the Dolphin menu 'View -> Sort' + * with the current state of the details view. + * @param column Index of the current sorting column. + */ + void synchronizeSortingState(int column); + + /** + * Is invoked when the mouse cursor has entered an item. The controller + * gets informed to emit the itemEntered() signal if the mouse cursor + * is above the name column. Otherwise the controller gets informed + * to emit the itemViewportEntered() signal (all other columns should + * behave as viewport area). + */ + void slotEntered(const QModelIndex& index); + + /** + * Updates the destination \a destination from + * the elastic band to the current mouse position and triggers + * an update. + */ + void updateElasticBand(); + + /** + * Returns the rectangle for the elastic band dependent from the + * origin \a origin, the current destination + * \a destination and the viewport position. + */ + QRect elasticBandRect() const; + + void setZoomLevel(int level); + + void slotShowPreviewChanged(); + + /** + * Opens a context menu at the position \a pos and allows to + * configure the visibility of the header columns and whether + * expandable folders should be shown. + */ + void configureSettings(const QPoint& pos); + + /** + * Updates the visibilty state of columns and their order. + */ + void updateColumnVisibility(); + + /** + * Saves order of the columns as global setting. + */ + void saveColumnPositions(); + + /** + * Disables the automatical resizing of columns, if the user has resized the columns + * with the mouse. + */ + void slotHeaderSectionResized(int logicalIndex, int oldSize, int newSize); + + /** + * Changes the alternating row colors setting depending from + * the activation state \a active. + */ + void slotActivationChanged(bool active); + + /** + * Disables the automatical resizing of the columns. Per default all columns + * are resized to use the maximum available width of the view as good as possible. + */ + void disableAutoResizing(); + + void requestActivation(); + + void slotGlobalSettingsChanged(int category); + + /** + * If the elastic band is currently shown, update the elastic band based on + * the current mouse position and ensure that the selection is the set of items + * intersecting it. + */ + void updateElasticBandSelection(); + + /** + * If \a expandable is true, the details view acts as tree view. + * The current expandable state is remembered in the settings. + */ + 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 + * will get informed about possible zoom in/zoom out + * operations. + */ + void updateDecorationSize(bool showPreview); + + KFileItemDelegate::Information infoForColumn(int columnIndex) const; + + /** + * Resizes all columns in a way to use the whole available width of the view. + */ + void resizeColumns(); + + /** + * Returns true, if \a pos is within the expanding toggle of a tree. + */ + bool isAboveExpandingToggle(const QPoint& pos) const; + + /** + * Sets the maximum size available for editing in the delegate. + */ + void adjustMaximumSizeForEditing(const QModelIndex& index); + +private: + bool m_autoResize : 1; // if true, the columns are resized automatically to the available width + bool m_expandingTogglePressed : 1; + bool m_keyPressed : 1; // true if a key is pressed currently; info used by currentChanged() + bool m_useDefaultIndexAt : 1; // true, if QTreeView::indexAt() should be used + bool m_ignoreScrollTo : 1; // true if calls to scrollTo(...) should do nothing. + + DolphinViewController* m_dolphinViewController; + const ViewModeController* m_viewModeController; + ViewExtensionsFactory* m_extensionsFactory; + QAction* m_expandableFoldersAction; + + // A set containing the URLs of all currently expanded folders. + // We cannot use a QSet because a QModelIndex is not guaranteed to remain valid over time. + // Also a QSet 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 m_expandedUrls; + + QFont m_font; + QSize m_decorationSize; + + QRect m_dropRect; + + struct ElasticBand + { + ElasticBand(); + + // Elastic band origin and destination coordinates are relative to t + // he origin of the view, not the viewport. + bool show; + QPoint origin; + QPoint destination; + + // Optimization mechanisms for use with elastic band selection. + // Basically, allow "incremental" updates to the selection based + // on the last elastic band shape. + QPoint lastSelectionOrigin; + QPoint lastSelectionDestination; + + // If true, compute the set of selected elements from scratch (slower) + bool ignoreOldInfo; + + // Edges of the filenames that are closest to the edges of oldSelectionRect. + // Used to decide whether horizontal changes in the elastic band are likely + // to require us to re-check which items are selected. + int outsideNearestLeftEdge; + int outsideNearestRightEdge; + int insideNearestLeftEdge; + int insideNearestRightEdge; + // The set of items that were selected at the time this band was shown. + // NOTE: Unless CTRL was pressed when the band was created, this is always empty. + QItemSelection originalSelection; + } m_band; +}; + +#endif diff --git a/src/views/dolphindetailsviewexpander.cpp b/src/views/dolphindetailsviewexpander.cpp new file mode 100644 index 000000000..0f3d3fde1 --- /dev/null +++ b/src/views/dolphindetailsviewexpander.cpp @@ -0,0 +1,87 @@ +/*************************************************************************** + * 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 +#include + +DolphinDetailsViewExpander::DolphinDetailsViewExpander(DolphinDetailsView* parent, + const QSet& urlsToExpand) : + QObject(parent), + m_detailsView(parent), + m_dirLister(0), + m_dolphinModel(0), + m_proxyModel(0) +{ + Q_ASSERT(parent != 0); + + m_proxyModel = qobject_cast(parent->model()); + Q_ASSERT(m_proxyModel != 0); + + m_dolphinModel = qobject_cast(m_proxyModel->sourceModel()); + Q_ASSERT(m_dolphinModel != 0); + + m_dirLister = m_dolphinModel->dirLister(); + Q_ASSERT(m_dirLister != 0); + + // 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())); +} + +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); + } + else { + emit completed(); + stop(); + } +} diff --git a/src/views/dolphindetailsviewexpander.h b/src/views/dolphindetailsviewexpander.h new file mode 100644 index 000000000..b4dc2fc72 --- /dev/null +++ b/src/views/dolphindetailsviewexpander.h @@ -0,0 +1,77 @@ +/*************************************************************************** + * 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 +#include +#include + +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& 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 m_urlsToExpand; + + DolphinDetailsView* m_detailsView; + const KDirLister* m_dirLister; + const DolphinModel* m_dolphinModel; + const DolphinSortFilterProxyModel* m_proxyModel; +}; + +#endif diff --git a/src/views/dolphinfileitemdelegate.cpp b/src/views/dolphinfileitemdelegate.cpp new file mode 100644 index 000000000..17447d8cb --- /dev/null +++ b/src/views/dolphinfileitemdelegate.cpp @@ -0,0 +1,180 @@ +/*************************************************************************** + * Copyright (C) 2008 by Peter Penz * + * * + * 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 "dolphinfileitemdelegate.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +DolphinFileItemDelegate::DolphinFileItemDelegate(QObject* parent) : + KFileItemDelegate(parent), + m_hasMinimizedNameColumn(false), + m_cachedSize(), + m_cachedEmblems() +{ + setJobTransfersVisible(true); +} + +DolphinFileItemDelegate::~DolphinFileItemDelegate() +{ +} + +void DolphinFileItemDelegate::paint(QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + const QAbstractProxyModel* proxyModel = static_cast(index.model()); + const DolphinModel* dolphinModel = static_cast(proxyModel->sourceModel()); + const bool isNameColumn = (index.column() == KDirModel::Name); + + QStyleOptionViewItemV4 opt(option); + if (m_hasMinimizedNameColumn && isNameColumn) { + adjustOptionWidth(opt, proxyModel, dolphinModel, index); + } + + if (dolphinModel->hasVersionData() && isNameColumn) { + // The currently shown items are under revision control. Show the current revision + // state by adding an emblem and changing the text tintColor. + const QModelIndex dirIndex = proxyModel->mapToSource(index); + const QModelIndex revisionIndex = dolphinModel->index(dirIndex.row(), DolphinModel::Version, dirIndex.parent()); + const QVariant data = dolphinModel->data(revisionIndex, Qt::DecorationRole); + const KVersionControlPlugin::VersionState state = static_cast(data.toInt()); + + adjustOptionTextColor(opt, state); + + KFileItemDelegate::paint(painter, opt, index); + + if (state != KVersionControlPlugin::UnversionedVersion) { + const QRect rect = iconRect(option, index); + const QPixmap emblem = emblemForState(state, rect.size()); + painter->drawPixmap(rect.x(), rect.y() + rect.height() - emblem.height(), emblem); + } + } else { + KFileItemDelegate::paint(painter, opt, index); + } +} + +int DolphinFileItemDelegate::nameColumnWidth(const QString& name, const QStyleOptionViewItem& option) +{ + QFontMetrics fontMetrics(option.font); + int width = option.decorationSize.width() + fontMetrics.width(name) + 16; + + const int defaultWidth = option.rect.width(); + if ((defaultWidth > 0) && (defaultWidth < width)) { + width = defaultWidth; + } + return width; +} + +void DolphinFileItemDelegate::adjustOptionWidth(QStyleOptionViewItemV4& option, + const QAbstractProxyModel* proxyModel, + const DolphinModel* dolphinModel, + const QModelIndex& index) +{ + const QModelIndex dirIndex = proxyModel->mapToSource(index); + const KFileItem item = dolphinModel->itemForIndex(dirIndex); + if (!item.isNull()) { + // symbolic links are displayed in an italic font + if (item.isLink()) { + option.font.setItalic(true); + } + + const int width = nameColumnWidth(item.text(), option); + option.rect.setWidth(width); + } +} + +void DolphinFileItemDelegate::adjustOptionTextColor(QStyleOptionViewItemV4& option, + KVersionControlPlugin::VersionState state) +{ + QColor tintColor; + + // Using hardcoded colors is generally a bad idea. In this case the colors just act + // as tint colors and are mixed with the current set text color. The tint colors + // have been optimized for the base colors of the corresponding Oxygen emblems. + switch (state) { + case KVersionControlPlugin::UpdateRequiredVersion: tintColor = Qt::yellow; break; + case KVersionControlPlugin::LocallyModifiedVersion: tintColor = Qt::green; break; + case KVersionControlPlugin::AddedVersion: tintColor = Qt::darkGreen; break; + case KVersionControlPlugin::RemovedVersion: tintColor = Qt::darkRed; break; + case KVersionControlPlugin::ConflictingVersion: tintColor = Qt::red; break; + case KVersionControlPlugin::UnversionedVersion: + case KVersionControlPlugin::NormalVersion: + default: + // use the default text color + return; + } + + QPalette palette = option.palette; + const QColor textColor = palette.color(QPalette::Text); + tintColor = QColor((tintColor.red() + textColor.red()) / 2, + (tintColor.green() + textColor.green()) / 2, + (tintColor.blue() + textColor.blue()) / 2, + (tintColor.alpha() + textColor.alpha()) / 2); + palette.setColor(QPalette::Text, tintColor); + option.palette = palette; +} + +QPixmap DolphinFileItemDelegate::emblemForState(KVersionControlPlugin::VersionState state, const QSize& size) const +{ + Q_ASSERT(state <= KVersionControlPlugin::ConflictingVersion); + if (m_cachedSize != size) { + m_cachedSize = size; + + const int iconHeight = size.height(); + int emblemHeight = KIconLoader::SizeSmall; + if (iconHeight >= KIconLoader::SizeEnormous) { + emblemHeight = KIconLoader::SizeMedium; + } else if (iconHeight >= KIconLoader::SizeLarge) { + emblemHeight = KIconLoader::SizeSmallMedium; + } else if (iconHeight >= KIconLoader::SizeMedium) { + emblemHeight = KIconLoader::SizeSmall; + } else { + emblemHeight = KIconLoader::SizeSmall / 2; + } + + const QSize emblemSize(emblemHeight, emblemHeight); + for (int i = KVersionControlPlugin::NormalVersion; i <= KVersionControlPlugin::ConflictingVersion; ++i) { + QString iconName; + switch (i) { + case KVersionControlPlugin::NormalVersion: iconName = "vcs-normal"; break; + case KVersionControlPlugin::UpdateRequiredVersion: iconName = "vcs-update-required"; break; + case KVersionControlPlugin::LocallyModifiedVersion: iconName = "vcs-locally-modified"; break; + case KVersionControlPlugin::AddedVersion: iconName = "vcs-added"; break; + case KVersionControlPlugin::RemovedVersion: iconName = "vcs-removed"; break; + case KVersionControlPlugin::ConflictingVersion: iconName = "vcs-conflicting"; break; + case KVersionControlPlugin::UnversionedVersion: + default: Q_ASSERT(false); break; + } + + m_cachedEmblems[i] = KIcon(iconName).pixmap(emblemSize); + } + } + return m_cachedEmblems[state]; +} + diff --git a/src/views/dolphinfileitemdelegate.h b/src/views/dolphinfileitemdelegate.h new file mode 100644 index 000000000..405f24916 --- /dev/null +++ b/src/views/dolphinfileitemdelegate.h @@ -0,0 +1,90 @@ +/*************************************************************************** + * Copyright (C) 2008 by Peter Penz * + * * + * 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 DOLPHINFILEITEMDELEGATE_H +#define DOLPHINFILEITEMDELEGATE_H + +#include +#include + +class QAbstractProxyModel; + +/** + * Extends KFileItemDelegate by the ability to show the hover effect + * and the selection in a minimized way for the name column of + * the details view. + * + * Note that this is a workaround, as Qt does not support having custom + * shapes within the visual rect of an item view. The visual part of + * workaround is handled inside DolphinFileItemDelegate, the behavior + * changes are handled in DolphinDetailsView. + */ +class DolphinFileItemDelegate : public KFileItemDelegate +{ +public: + explicit DolphinFileItemDelegate(QObject* parent = 0); + virtual ~DolphinFileItemDelegate(); + + /** + * If \a minimized is true, the hover effect and the selection are + * only drawn above the icon and text of an item. Per default + * \a minimized is false, which means that the whole visual rect is + * used like in KFileItemDelegate. + */ + void setMinimizedNameColumn(bool minimized); + bool hasMinimizedNameColumn() const; + + virtual void paint(QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const; + + /** + * Returns the minimized width of the name column for the name \a name. This method + * is also used in DolphinDetailsView to handle the selection of items correctly. + */ + static int nameColumnWidth(const QString& name, const QStyleOptionViewItem& option); + +private: + static void adjustOptionWidth(QStyleOptionViewItemV4& option, + const QAbstractProxyModel* proxyModel, + const DolphinModel* dolphinModel, + const QModelIndex& index); + + static void adjustOptionTextColor(QStyleOptionViewItemV4& option, + KVersionControlPlugin::VersionState state); + + QPixmap emblemForState(KVersionControlPlugin::VersionState state, const QSize& size) const; + +private: + bool m_hasMinimizedNameColumn; + mutable QSize m_cachedSize; + mutable QPixmap m_cachedEmblems[KVersionControlPlugin::ConflictingVersion + 1]; +}; + +inline void DolphinFileItemDelegate::setMinimizedNameColumn(bool minimized) +{ + m_hasMinimizedNameColumn = minimized; +} + +inline bool DolphinFileItemDelegate::hasMinimizedNameColumn() const +{ + return m_hasMinimizedNameColumn; +} + +#endif diff --git a/src/views/dolphiniconsview.cpp b/src/views/dolphiniconsview.cpp new file mode 100644 index 000000000..636bdd66c --- /dev/null +++ b/src/views/dolphiniconsview.cpp @@ -0,0 +1,532 @@ +/*************************************************************************** + * Copyright (C) 2006-2009 by Peter Penz * + * * + * 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 "dolphiniconsview.h" + +#include "dolphincategorydrawer.h" +#include "dolphinviewcontroller.h" +#include "settings/dolphinsettings.h" +#include "dolphinsortfilterproxymodel.h" +#include "dolphin_iconsmodesettings.h" +#include "dolphin_generalsettings.h" +#include "draganddrophelper.h" +#include "selectionmanager.h" +#include "viewextensionsfactory.h" +#include "viewmodecontroller.h" +#include "zoomlevelinfo.h" + +#include +#include +#include + +#include +#include +#include + +DolphinIconsView::DolphinIconsView(QWidget* parent, + DolphinViewController* dolphinViewController, + const ViewModeController* viewModeController, + DolphinSortFilterProxyModel* proxyModel) : + KCategorizedView(parent), + m_dolphinViewController(dolphinViewController), + m_viewModeController(viewModeController), + m_categoryDrawer(new DolphinCategoryDrawer(this)), + m_extensionsFactory(0), + m_font(), + m_decorationSize(), + m_decorationPosition(QStyleOptionViewItem::Top), + m_displayAlignment(Qt::AlignHCenter), + m_itemSize(), + m_dropRect() +{ + Q_ASSERT(dolphinViewController != 0); + Q_ASSERT(viewModeController != 0); + + setModel(proxyModel); + setLayoutDirection(Qt::LeftToRight); + setViewMode(QListView::IconMode); + setResizeMode(QListView::Adjust); + setMovement(QListView::Static); + setDragEnabled(true); + setEditTriggers(QAbstractItemView::NoEditTriggers); + viewport()->setAcceptDrops(true); + + setMouseTracking(true); + + connect(this, SIGNAL(clicked(const QModelIndex&)), + dolphinViewController, SLOT(requestTab(const QModelIndex&))); + if (KGlobalSettings::singleClick()) { + connect(this, SIGNAL(clicked(const QModelIndex&)), + dolphinViewController, SLOT(triggerItem(const QModelIndex&))); + } else { + connect(this, SIGNAL(doubleClicked(const QModelIndex&)), + dolphinViewController, SLOT(triggerItem(const QModelIndex&))); + } + + connect(this, SIGNAL(entered(const QModelIndex&)), + dolphinViewController, SLOT(emitItemEntered(const QModelIndex&))); + connect(this, SIGNAL(viewportEntered()), + dolphinViewController, SLOT(emitViewportEntered())); + connect(viewModeController, SIGNAL(zoomLevelChanged(int)), + this, SLOT(setZoomLevel(int))); + + const DolphinView* view = dolphinViewController->view(); + connect(view, SIGNAL(showPreviewChanged()), + this, SLOT(slotShowPreviewChanged())); + connect(view, SIGNAL(additionalInfoChanged()), + this, SLOT(slotAdditionalInfoChanged())); + + // apply the icons mode settings to the widget + const IconsModeSettings* settings = DolphinSettings::instance().iconsModeSettings(); + Q_ASSERT(settings != 0); + + if (settings->useSystemFont()) { + m_font = KGlobalSettings::generalFont(); + } else { + m_font = QFont(settings->fontFamily(), + qRound(settings->fontSize()), + settings->fontWeight(), + settings->italicFont()); + m_font.setPointSizeF(settings->fontSize()); + } + + setWordWrap(settings->numberOfTextlines() > 1); + + if (settings->arrangement() == QListView::TopToBottom) { + setFlow(QListView::LeftToRight); + m_decorationPosition = QStyleOptionViewItem::Top; + m_displayAlignment = Qt::AlignHCenter; + } else { + setFlow(QListView::TopToBottom); + m_decorationPosition = QStyleOptionViewItem::Left; + m_displayAlignment = Qt::AlignLeft | Qt::AlignVCenter; + } + + connect(m_categoryDrawer, SIGNAL(actionRequested(int,QModelIndex)), this, SLOT(categoryDrawerActionRequested(int,QModelIndex))); + setCategoryDrawer(m_categoryDrawer); + + setFocus(); + + connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)), + this, SLOT(slotGlobalSettingsChanged(int))); + + updateGridSize(view->showPreview(), 0); + m_extensionsFactory = new ViewExtensionsFactory(this, dolphinViewController, viewModeController); +} + +DolphinIconsView::~DolphinIconsView() +{ +} + +void DolphinIconsView::dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight) +{ + KCategorizedView::dataChanged(topLeft, bottomRight); + + KCategorizedSortFilterProxyModel* proxyModel = dynamic_cast(model()); + if (!proxyModel->isCategorizedModel()) { + // bypass a QListView issue that items are not layout correctly if the decoration size of + // an index changes + scheduleDelayedItemsLayout(); + } +} + +QStyleOptionViewItem DolphinIconsView::viewOptions() const +{ + QStyleOptionViewItem viewOptions = KCategorizedView::viewOptions(); + viewOptions.font = m_font; + viewOptions.fontMetrics = QFontMetrics(m_font); + viewOptions.decorationPosition = m_decorationPosition; + viewOptions.decorationSize = m_decorationSize; + viewOptions.displayAlignment = m_displayAlignment; + viewOptions.showDecorationSelected = true; + return viewOptions; +} + +void DolphinIconsView::contextMenuEvent(QContextMenuEvent* event) +{ + KCategorizedView::contextMenuEvent(event); + m_dolphinViewController->triggerContextMenuRequest(event->pos()); +} + +void DolphinIconsView::mousePressEvent(QMouseEvent* event) +{ + m_dolphinViewController->requestActivation(); + const QModelIndex index = indexAt(event->pos()); + if (index.isValid() && (event->button() == Qt::LeftButton)) { + // TODO: It should not be necessary to manually set the dragging state, but I could + // not reproduce this issue with a Qt-only example yet to find the root cause. + // Issue description: start Dolphin, split the view and drag an item from the + // inactive view to the active view by a very fast mouse movement. Result: + // the item gets selected instead of being dragged... + setState(QAbstractItemView::DraggingState); + } + + if (!index.isValid() && (QApplication::mouseButtons() & Qt::MidButton)) { + m_dolphinViewController->replaceUrlByClipboard(); + } + + KCategorizedView::mousePressEvent(event); +} + +void DolphinIconsView::startDrag(Qt::DropActions supportedActions) +{ + DragAndDropHelper::instance().startDrag(this, supportedActions, m_dolphinViewController); +} + +void DolphinIconsView::dragEnterEvent(QDragEnterEvent* event) +{ + if (DragAndDropHelper::instance().isMimeDataSupported(event->mimeData())) { + event->acceptProposedAction(); + } +} + +void DolphinIconsView::dragLeaveEvent(QDragLeaveEvent* event) +{ + KCategorizedView::dragLeaveEvent(event); + setDirtyRegion(m_dropRect); +} + +void DolphinIconsView::dragMoveEvent(QDragMoveEvent* event) +{ + KCategorizedView::dragMoveEvent(event); + + // TODO: remove this code when the issue #160611 is solved in Qt 4.4 + const QModelIndex index = indexAt(event->pos()); + setDirtyRegion(m_dropRect); + + m_dropRect.setSize(QSize()); // set as invalid + if (index.isValid()) { + const KFileItem item = m_dolphinViewController->itemForIndex(index); + if (!item.isNull() && item.isDir()) { + m_dropRect = visualRect(index); + } else { + m_dropRect.setSize(QSize()); // set as invalid + } + } + if (DragAndDropHelper::instance().isMimeDataSupported(event->mimeData())) { + // accept url drops, independently from the destination item + event->acceptProposedAction(); + } + + setDirtyRegion(m_dropRect); +} + +void DolphinIconsView::dropEvent(QDropEvent* event) +{ + const QModelIndex index = indexAt(event->pos()); + const KFileItem item = m_dolphinViewController->itemForIndex(index); + m_dolphinViewController->indicateDroppedUrls(item, m_viewModeController->url(), event); + // don't call KCategorizedView::dropEvent(event), as it moves + // the items which is not wanted +} + +QModelIndex DolphinIconsView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) +{ + const QModelIndex oldCurrent = currentIndex(); + + QModelIndex newCurrent = KCategorizedView::moveCursor(cursorAction, modifiers); + if (newCurrent != oldCurrent) { + return newCurrent; + } + + // The cursor has not been moved by the base implementation. Provide a + // wrap behavior, so that the cursor will go to the next item when reaching + // the border. + const IconsModeSettings* settings = DolphinSettings::instance().iconsModeSettings(); + if (settings->arrangement() == QListView::LeftToRight) { + switch (cursorAction) { + case MoveUp: + if (newCurrent.row() == 0) { + return newCurrent; + } + newCurrent = KCategorizedView::moveCursor(MoveLeft, modifiers); + selectionModel()->setCurrentIndex(newCurrent, QItemSelectionModel::NoUpdate); + newCurrent = KCategorizedView::moveCursor(MovePageDown, modifiers); + break; + + case MoveDown: + if (newCurrent.row() == (model()->rowCount() - 1)) { + return newCurrent; + } + newCurrent = KCategorizedView::moveCursor(MovePageUp, modifiers); + selectionModel()->setCurrentIndex(newCurrent, QItemSelectionModel::NoUpdate); + newCurrent = KCategorizedView::moveCursor(MoveRight, modifiers); + break; + + default: + break; + } + } else { + QModelIndex current = oldCurrent; + switch (cursorAction) { + case MoveLeft: + if (newCurrent.row() == 0) { + return newCurrent; + } + newCurrent = KCategorizedView::moveCursor(MoveUp, modifiers); + do { + selectionModel()->setCurrentIndex(newCurrent, QItemSelectionModel::NoUpdate); + current = newCurrent; + newCurrent = KCategorizedView::moveCursor(MoveRight, modifiers); + } while (newCurrent != current); + break; + + case MoveRight: + if (newCurrent.row() == (model()->rowCount() - 1)) { + return newCurrent; + } + do { + selectionModel()->setCurrentIndex(newCurrent, QItemSelectionModel::NoUpdate); + current = newCurrent; + newCurrent = KCategorizedView::moveCursor(MoveLeft, modifiers); + } while (newCurrent != current); + newCurrent = KCategorizedView::moveCursor(MoveDown, modifiers); + break; + + default: + break; + } + } + + // Revert all changes of the current item to make sure that item selection works correctly + selectionModel()->setCurrentIndex(oldCurrent, QItemSelectionModel::NoUpdate); + return newCurrent; +} + +void DolphinIconsView::keyPressEvent(QKeyEvent* event) +{ + KCategorizedView::keyPressEvent(event); + m_dolphinViewController->handleKeyPressEvent(event); +} + +void DolphinIconsView::wheelEvent(QWheelEvent* event) +{ + horizontalScrollBar()->setSingleStep(m_itemSize.width() / 5); + verticalScrollBar()->setSingleStep(m_itemSize.height() / 5); + + KCategorizedView::wheelEvent(event); + // if the icons are aligned left to right, the vertical wheel event should + // be applied to the horizontal scrollbar + const IconsModeSettings* settings = DolphinSettings::instance().iconsModeSettings(); + const bool scrollHorizontal = (event->orientation() == Qt::Vertical) && + (settings->arrangement() == QListView::LeftToRight); + if (scrollHorizontal) { + QWheelEvent horizEvent(event->pos(), + event->delta(), + event->buttons(), + event->modifiers(), + Qt::Horizontal); + QApplication::sendEvent(horizontalScrollBar(), &horizEvent); + } +} + +void DolphinIconsView::showEvent(QShowEvent* event) +{ + KFileItemDelegate* delegate = dynamic_cast(itemDelegate()); + delegate->setMaximumSize(m_itemSize); + + KCategorizedView::showEvent(event); +} + +void DolphinIconsView::leaveEvent(QEvent* event) +{ + KCategorizedView::leaveEvent(event); + // if the mouse is above an item and moved very fast outside the widget, + // no viewportEntered() signal might be emitted although the mouse has been moved + // above the viewport + m_dolphinViewController->emitViewportEntered(); +} + +void DolphinIconsView::currentChanged(const QModelIndex& current, const QModelIndex& previous) +{ + KCategorizedView::currentChanged(current, previous); + m_extensionsFactory->handleCurrentIndexChange(current, previous); +} + +void DolphinIconsView::resizeEvent(QResizeEvent* event) +{ + KCategorizedView::resizeEvent(event); + const DolphinView* view = m_dolphinViewController->view(); + updateGridSize(view->showPreview(), view->additionalInfo().count()); +} + +void DolphinIconsView::slotShowPreviewChanged() +{ + const DolphinView* view = m_dolphinViewController->view(); + updateGridSize(view->showPreview(), additionalInfoCount()); +} + +void DolphinIconsView::slotAdditionalInfoChanged() +{ + const DolphinView* view = m_dolphinViewController->view(); + const bool showPreview = view->showPreview(); + updateGridSize(showPreview, view->additionalInfo().count()); +} + +void DolphinIconsView::setZoomLevel(int level) +{ + IconsModeSettings* settings = DolphinSettings::instance().iconsModeSettings(); + + const int oldIconSize = settings->iconSize(); + int newIconSize = oldIconSize; + + const bool showPreview = m_dolphinViewController->view()->showPreview(); + if (showPreview) { + const int previewSize = ZoomLevelInfo::iconSizeForZoomLevel(level); + settings->setPreviewSize(previewSize); + } else { + newIconSize = ZoomLevelInfo::iconSizeForZoomLevel(level); + settings->setIconSize(newIconSize); + } + + // increase also the grid size + const int diff = newIconSize - oldIconSize; + settings->setItemWidth(settings->itemWidth() + diff); + settings->setItemHeight(settings->itemHeight() + diff); + + updateGridSize(showPreview, additionalInfoCount()); +} + +void DolphinIconsView::requestActivation() +{ + m_dolphinViewController->requestActivation(); +} + +void DolphinIconsView::slotGlobalSettingsChanged(int category) +{ + Q_UNUSED(category); + + const IconsModeSettings* settings = DolphinSettings::instance().iconsModeSettings(); + Q_ASSERT(settings != 0); + if (settings->useSystemFont()) { + m_font = KGlobalSettings::generalFont(); + } + + disconnect(this, SIGNAL(clicked(QModelIndex)), m_dolphinViewController, SLOT(triggerItem(QModelIndex))); + disconnect(this, SIGNAL(doubleClicked(QModelIndex)), m_dolphinViewController, SLOT(triggerItem(QModelIndex))); + if (KGlobalSettings::singleClick()) { + connect(this, SIGNAL(clicked(QModelIndex)), m_dolphinViewController, SLOT(triggerItem(QModelIndex))); + } else { + connect(this, SIGNAL(doubleClicked(QModelIndex)), m_dolphinViewController, SLOT(triggerItem(QModelIndex))); + } +} + +void DolphinIconsView::categoryDrawerActionRequested(int action, const QModelIndex &index) +{ + const QSortFilterProxyModel *model = dynamic_cast(index.model()); + const QModelIndex topLeft = model->index(index.row(), modelColumn()); + QModelIndex bottomRight = topLeft; + const QString category = model->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); + QModelIndex current = topLeft; + while (true) { + current = model->index(current.row() + 1, modelColumn()); + const QString curCategory = model->data(model->index(current.row(), index.column()), KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); + if (!current.isValid() || category != curCategory) { + break; + } + bottomRight = current; + } + switch (action) { + case DolphinCategoryDrawer::SelectAll: + selectionModel()->select(QItemSelection(topLeft, bottomRight), QItemSelectionModel::Select); + break; + case DolphinCategoryDrawer::UnselectAll: + selectionModel()->select(QItemSelection(topLeft, bottomRight), QItemSelectionModel::Deselect); + break; + default: + break; + } +} + +void DolphinIconsView::updateGridSize(bool showPreview, int additionalInfoCount) +{ + const IconsModeSettings* settings = DolphinSettings::instance().iconsModeSettings(); + Q_ASSERT(settings != 0); + + int itemWidth = settings->itemWidth(); + int itemHeight = settings->itemHeight(); + int size = settings->iconSize(); + + if (showPreview) { + const int previewSize = settings->previewSize(); + const int diff = previewSize - size; + itemWidth += diff; + itemHeight += diff; + + size = previewSize; + } + + Q_ASSERT(additionalInfoCount >= 0); + itemHeight += additionalInfoCount * QFontMetrics(m_font).height(); + + // Optimize the item size of the grid in a way to prevent large gaps on the + // right border (= row arrangement) or the bottom border (= column arrangement). + // There is no public API in QListView to find out the used width of the viewport + // for the layout. The following calculation of 'contentWidth'/'contentHeight' + // is based on QListViewPrivate::prepareItemsLayout() (Copyright (C) 2009 Nokia Corporation). + int frameAroundContents = 0; + if (style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents)) { + frameAroundContents = style()->pixelMetric(QStyle::PM_DefaultFrameWidth) * 2; + } + const int spacing = settings->gridSpacing(); + if (settings->arrangement() == QListView::TopToBottom) { + const int contentWidth = viewport()->width() - 1 + - frameAroundContents + - style()->pixelMetric(QStyle::PM_ScrollBarExtent, 0, horizontalScrollBar()); + const int gridWidth = itemWidth + spacing * 2; + const int horizItemCount = contentWidth / gridWidth; + if (horizItemCount > 0) { + itemWidth += (contentWidth - horizItemCount * gridWidth) / horizItemCount; + } + + // The decoration width indirectly defines the maximum + // width for the text wrapping. To use the maximum item width + // for text wrapping, it is used as decoration width. + m_decorationSize = QSize(itemWidth, size); + setIconSize(QSize(itemWidth, size)); + } else { + const int contentHeight = viewport()->height() - 1 + - frameAroundContents + - style()->pixelMetric(QStyle::PM_ScrollBarExtent, 0, verticalScrollBar()); + const int gridHeight = itemHeight + spacing; + const int vertItemCount = contentHeight / gridHeight; + if (vertItemCount > 0) { + itemHeight += (contentHeight - vertItemCount * gridHeight) / vertItemCount; + } + + m_decorationSize = QSize(size, size); + setIconSize(QSize(size, size)); + } + + m_itemSize = QSize(itemWidth, itemHeight); + setGridSizeOwn(QSize(itemWidth + spacing * 2, itemHeight + spacing)); + + KFileItemDelegate* delegate = dynamic_cast(itemDelegate()); + if (delegate != 0) { + delegate->setMaximumSize(m_itemSize); + } +} + +int DolphinIconsView::additionalInfoCount() const +{ + const DolphinView* view = m_dolphinViewController->view(); + return view->additionalInfo().count(); +} + +#include "dolphiniconsview.moc" diff --git a/src/views/dolphiniconsview.h b/src/views/dolphiniconsview.h new file mode 100644 index 000000000..21e37ba02 --- /dev/null +++ b/src/views/dolphiniconsview.h @@ -0,0 +1,122 @@ +/*************************************************************************** + * Copyright (C) 2006-2009 by Peter Penz * + * * + * 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 DOLPHINICONSVIEW_H +#define DOLPHINICONSVIEW_H + +#include + +#include +#include + +#include +#include +#include + +#include + +class DolphinViewController; +class DolphinCategoryDrawer; +class DolphinSortFilterProxyModel; +class ViewExtensionsFactory; +class ViewModeController; + +/** + * @brief Represents the view, where each item is shown as an icon. + * + * It is also possible that instead of the icon a preview of the item + * content is shown. + */ +class LIBDOLPHINPRIVATE_EXPORT DolphinIconsView : public KCategorizedView +{ + Q_OBJECT + +public: + /** + * @param parent Parent widget. + * @param dolphinViewController Allows the DolphinIconsView to control the + * DolphinView in a limited way. + * @param viewModeController Controller that is used by the DolphinView + * to control the DolphinIconsView. The DolphinIconsView + * only has read access to the controller. + * @param model Directory that is shown. + */ + explicit DolphinIconsView(QWidget* parent, + DolphinViewController* dolphinViewController, + const ViewModeController* viewModeController, + DolphinSortFilterProxyModel* proxyModel); + virtual ~DolphinIconsView(); + +protected slots: + virtual void dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight); + +protected: + virtual QStyleOptionViewItem viewOptions() const; + virtual void contextMenuEvent(QContextMenuEvent* event); + virtual void mousePressEvent(QMouseEvent* event); + virtual void startDrag(Qt::DropActions supportedActions); + virtual void dragEnterEvent(QDragEnterEvent* event); + virtual void dragLeaveEvent(QDragLeaveEvent* event); + virtual void dragMoveEvent(QDragMoveEvent* event); + virtual void dropEvent(QDropEvent* event); + virtual QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers); + virtual void keyPressEvent(QKeyEvent* event); + virtual void wheelEvent(QWheelEvent* event); + virtual void showEvent(QShowEvent* event); + virtual void leaveEvent(QEvent* event); + virtual void currentChanged(const QModelIndex& current, const QModelIndex& previous); + virtual void resizeEvent(QResizeEvent* event); + +private slots: + void slotShowPreviewChanged(); + void slotAdditionalInfoChanged(); + void setZoomLevel(int level); + void requestActivation(); + void slotGlobalSettingsChanged(int category); + void categoryDrawerActionRequested(int action, const QModelIndex &index); + +private: + /** + * Updates the size of the grid depending on the state + * of \a showPreview and \a additionalInfoCount. + */ + void updateGridSize(bool showPreview, int additionalInfoCount); + + /** + * Returns the number of additional information lines that should + * be shown below the item name. + */ + int additionalInfoCount() const; + +private: + DolphinViewController* m_dolphinViewController; + const ViewModeController* m_viewModeController; + DolphinCategoryDrawer* m_categoryDrawer; + ViewExtensionsFactory* m_extensionsFactory; + + QFont m_font; + QSize m_decorationSize; + QStyleOptionViewItem::Position m_decorationPosition; + Qt::Alignment m_displayAlignment; + + QSize m_itemSize; + QRect m_dropRect; +}; + +#endif diff --git a/src/views/dolphinview.cpp b/src/views/dolphinview.cpp new file mode 100644 index 000000000..73a0c63c3 --- /dev/null +++ b/src/views/dolphinview.cpp @@ -0,0 +1,1569 @@ +/*************************************************************************** + * Copyright (C) 2006-2009 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "additionalinfoaccessor.h" +#include "dolphinmodel.h" +#include "dolphincolumnviewcontainer.h" +#include "dolphinviewcontroller.h" +#include "dolphindetailsview.h" +#include "dolphinfileitemdelegate.h" +#include "dolphinnewmenuobserver.h" +#include "dolphinsortfilterproxymodel.h" +#include "dolphin_detailsmodesettings.h" +#include "dolphiniconsview.h" +#include "dolphin_generalsettings.h" +#include "draganddrophelper.h" +#include "renamedialog.h" +#include "settings/dolphinsettings.h" +#include "viewmodecontroller.h" +#include "viewproperties.h" +#include "zoomlevelinfo.h" +#include "dolphindetailsviewexpander.h" + +/** + * Helper function for sorting items with qSort() in + * DolphinView::renameSelectedItems(). + */ +bool lessThan(const KFileItem& item1, const KFileItem& item2) +{ + return KStringHandler::naturalCompare(item1.name(), item2.name()) < 0; +} + +DolphinView::DolphinView(QWidget* parent, + const KUrl& url, + DolphinSortFilterProxyModel* proxyModel) : + QWidget(parent), + m_active(true), + m_showPreview(false), + m_storedCategorizedSorting(false), + m_tabsForFiles(false), + m_isContextMenuOpen(false), + m_ignoreViewProperties(false), + m_assureVisibleCurrentIndex(false), + m_mode(DolphinView::IconsView), + m_topLayout(0), + m_dolphinViewController(0), + m_viewModeController(0), + m_viewAccessor(proxyModel), + m_selectionModel(0), + m_selectionChangedTimer(0), + m_rootUrl(), + m_activeItemUrl(), + m_restoredContentsPosition(), + m_createdItemUrl(), + m_selectedItems(), + m_newFileNames() +{ + m_topLayout = new QVBoxLayout(this); + m_topLayout->setSpacing(0); + m_topLayout->setMargin(0); + + m_dolphinViewController = new DolphinViewController(this); + + m_viewModeController = new ViewModeController(this); + m_viewModeController->setUrl(url); + + connect(m_viewModeController, SIGNAL(urlChanged(const KUrl&)), + this, SIGNAL(urlChanged(const KUrl&))); + + connect(m_dolphinViewController, SIGNAL(requestContextMenu(const QPoint&, const QList&)), + this, SLOT(openContextMenu(const QPoint&, const QList&))); + connect(m_dolphinViewController, SIGNAL(urlsDropped(const KFileItem&, const KUrl&, QDropEvent*)), + this, SLOT(dropUrls(const KFileItem&, const KUrl&, QDropEvent*))); + connect(m_dolphinViewController, SIGNAL(sortingChanged(DolphinView::Sorting)), + this, SLOT(updateSorting(DolphinView::Sorting))); + connect(m_dolphinViewController, SIGNAL(sortOrderChanged(Qt::SortOrder)), + this, SLOT(updateSortOrder(Qt::SortOrder))); + connect(m_dolphinViewController, SIGNAL(sortFoldersFirstChanged(bool)), + this, SLOT(updateSortFoldersFirst(bool))); + connect(m_dolphinViewController, SIGNAL(additionalInfoChanged(const KFileItemDelegate::InformationList&)), + this, SLOT(updateAdditionalInfo(const KFileItemDelegate::InformationList&))); + connect(m_dolphinViewController, SIGNAL(itemTriggered(const KFileItem&)), + this, SLOT(triggerItem(const KFileItem&))); + connect(m_dolphinViewController, SIGNAL(tabRequested(const KUrl&)), + this, SIGNAL(tabRequested(const KUrl&))); + connect(m_dolphinViewController, SIGNAL(activated()), + this, SLOT(activate())); + connect(m_dolphinViewController, SIGNAL(itemEntered(const KFileItem&)), + this, SLOT(showHoverInformation(const KFileItem&))); + 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())); + + // 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 + // creation is done asynchronously, several signals must be checked: + connect(&DolphinNewMenuObserver::instance(), SIGNAL(itemCreated(const KUrl&)), + this, SLOT(observeCreatedItem(const KUrl&))); + + m_selectionChangedTimer = new QTimer(this); + m_selectionChangedTimer->setSingleShot(true); + m_selectionChangedTimer->setInterval(300); + connect(m_selectionChangedTimer, SIGNAL(timeout()), + this, SLOT(emitSelectionChangedSignal())); + + applyViewProperties(); + m_topLayout->addWidget(m_viewAccessor.layoutTarget()); +} + +DolphinView::~DolphinView() +{ +} + +KUrl DolphinView::url() const +{ + return m_viewModeController->url(); +} + +KUrl DolphinView::rootUrl() const +{ + const KUrl viewUrl = url(); + const KUrl root = m_viewAccessor.rootUrl(); + if (root.isEmpty() || !root.isParentOf(viewUrl)) { + return viewUrl; + } + return root; +} + +void DolphinView::setActive(bool active) +{ + if (active == m_active) { + return; + } + + m_active = active; + + QColor color = KColorScheme(QPalette::Active, KColorScheme::View).background().color(); + if (active) { + emitSelectionChangedSignal(); + } else { + color.setAlpha(150); + } + + QWidget* viewport = m_viewAccessor.itemView()->viewport(); + QPalette palette; + palette.setColor(viewport->backgroundRole(), color); + viewport->setPalette(palette); + + update(); + + if (active) { + m_viewAccessor.itemView()->setFocus(); + emit activated(); + } + + m_viewModeController->indicateActivationChange(active); +} + +bool DolphinView::isActive() const +{ + return m_active; +} + +void DolphinView::setMode(Mode mode) +{ + if (mode == m_mode) { + return; // the wished mode is already set + } + + const int oldZoomLevel = m_viewModeController->zoomLevel(); + m_mode = mode; + + // remember the currently selected items, so that they will + // be restored after reloading the directory + m_selectedItems = selectedItems(); + + deleteView(); + + const KUrl viewPropsUrl = rootUrl(); + ViewProperties props(viewPropsUrl); + props.setViewMode(m_mode); + createView(); + + // the file item delegate has been recreated, apply the current + // additional information manually + const KFileItemDelegate::InformationList infoList = props.additionalInfo(); + m_viewAccessor.itemDelegate()->setShowInformation(infoList); + emit additionalInfoChanged(); + + // Not all view modes support categorized sorting. Adjust the sorting model + // if changing the view mode results in a change of the categorized sorting + // capabilities. + m_storedCategorizedSorting = props.categorizedSorting(); + const bool categorized = m_storedCategorizedSorting && supportsCategorizedSorting(); + if (categorized != m_viewAccessor.proxyModel()->isCategorizedModel()) { + m_viewAccessor.proxyModel()->setCategorizedModel(categorized); + emit categorizedSortingChanged(); + } + + emit modeChanged(); + + updateZoomLevel(oldZoomLevel); + loadDirectory(viewPropsUrl); +} + +DolphinView::Mode DolphinView::mode() const +{ + return m_mode; +} + +bool DolphinView::showPreview() const +{ + return m_showPreview; +} + +bool DolphinView::showHiddenFiles() const +{ + return m_viewAccessor.dirLister()->showingDotFiles(); +} + +bool DolphinView::categorizedSorting() const +{ + // If all view modes would support categorized sorting, returning + // m_viewAccessor.proxyModel()->isCategorizedModel() would be the way to go. As + // currently only the icons view supports caterized sorting, we remember + // the stored view properties state in m_storedCategorizedSorting and + // return this state. The application takes care to disable the corresponding + // checkbox by checking DolphinView::supportsCategorizedSorting() to indicate + // that this setting is not applied to the current view mode. + return m_storedCategorizedSorting; +} + +bool DolphinView::supportsCategorizedSorting() const +{ + return m_viewAccessor.supportsCategorizedSorting(); +} + +bool DolphinView::hasSelection() const +{ + const QAbstractItemView* view = m_viewAccessor.itemView(); + return (view != 0) && view->selectionModel()->hasSelection(); +} + +void DolphinView::markUrlsAsSelected(const QList& urls) +{ + foreach (const KUrl& url, urls) { + KFileItem item(KFileItem::Unknown, KFileItem::Unknown, url); + m_selectedItems.append(item); + } +} + +KFileItemList DolphinView::selectedItems() const +{ + KFileItemList itemList; + const QAbstractItemView* view = m_viewAccessor.itemView(); + if (view == 0) { + return itemList; + } + + const QItemSelection selection = m_viewAccessor.proxyModel()->mapSelectionToSource(view->selectionModel()->selection()); + + const QModelIndexList indexList = selection.indexes(); + foreach (const QModelIndex &index, indexList) { + KFileItem item = m_viewAccessor.dirModel()->itemForIndex(index); + if (!item.isNull()) { + itemList.append(item); + } + } + + return itemList; +} + +KUrl::List DolphinView::selectedUrls() const +{ + KUrl::List urls; + const KFileItemList list = selectedItems(); + foreach (const KFileItem &item, list) { + urls.append(item.url()); + } + return urls; +} + +int DolphinView::selectedItemsCount() const +{ + const QAbstractItemView* view = m_viewAccessor.itemView(); + if (view == 0) { + return 0; + } + + return view->selectionModel()->selectedIndexes().count(); +} + +QItemSelectionModel* DolphinView::selectionModel() const +{ + return m_viewAccessor.itemView()->selectionModel(); +} + +void DolphinView::setZoomLevel(int level) +{ + if (level < ZoomLevelInfo::minimumLevel()) { + level = ZoomLevelInfo::minimumLevel(); + } else if (level > ZoomLevelInfo::maximumLevel()) { + level = ZoomLevelInfo::maximumLevel(); + } + + if (level != zoomLevel()) { + m_viewModeController->setZoomLevel(level); + emit zoomLevelChanged(level); + } +} + +int DolphinView::zoomLevel() const +{ + return m_viewModeController->zoomLevel(); +} + +void DolphinView::setSorting(Sorting sorting) +{ + if (sorting != this->sorting()) { + updateSorting(sorting); + } +} + +DolphinView::Sorting DolphinView::sorting() const +{ + return m_viewAccessor.proxyModel()->sorting(); +} + +void DolphinView::setSortOrder(Qt::SortOrder order) +{ + if (sortOrder() != order) { + updateSortOrder(order); + } +} + +Qt::SortOrder DolphinView::sortOrder() const +{ + return m_viewAccessor.proxyModel()->sortOrder(); +} + +void DolphinView::setSortFoldersFirst(bool foldersFirst) +{ + if (sortFoldersFirst() != foldersFirst) { + updateSortFoldersFirst(foldersFirst); + } +} + +bool DolphinView::sortFoldersFirst() const +{ + return m_viewAccessor.proxyModel()->sortFoldersFirst(); +} + +void DolphinView::setAdditionalInfo(KFileItemDelegate::InformationList info) +{ + const KUrl viewPropsUrl = rootUrl(); + ViewProperties props(viewPropsUrl); + props.setAdditionalInfo(info); + m_viewAccessor.itemDelegate()->setShowInformation(info); + + emit additionalInfoChanged(); + + if (m_viewAccessor.reloadOnAdditionalInfoChange()) { + loadDirectory(viewPropsUrl); + } +} + +KFileItemDelegate::InformationList DolphinView::additionalInfo() const +{ + return m_viewAccessor.itemDelegate()->showInformation(); +} + +void DolphinView::reload() +{ + QByteArray viewState; + QDataStream saveStream(&viewState, QIODevice::WriteOnly); + saveState(saveStream); + m_selectedItems= selectedItems(); + + setUrl(url()); + loadDirectory(url(), true); + + QDataStream restoreStream(viewState); + restoreState(restoreStream); +} + +void DolphinView::refresh() +{ + m_ignoreViewProperties = false; + + const bool oldActivationState = m_active; + const int oldZoomLevel = m_viewModeController->zoomLevel(); + m_active = true; + + createView(); + applyViewProperties(); + reload(); + + setActive(oldActivationState); + updateZoomLevel(oldZoomLevel); +} + +void DolphinView::setNameFilter(const QString& nameFilter) +{ + m_viewModeController->setNameFilter(nameFilter); +} + +void DolphinView::calculateItemCount(int& fileCount, + int& folderCount, + KIO::filesize_t& totalFileSize) const +{ + foreach (const KFileItem& item, m_viewAccessor.dirLister()->items()) { + if (item.isDir()) { + ++folderCount; + } else { + ++fileCount; + totalFileSize += item.size(); + } + } +} + +QString DolphinView::statusBarText() const +{ + QString text; + int folderCount = 0; + int fileCount = 0; + KIO::filesize_t totalFileSize = 0; + + if (hasSelection()) { + // give a summary of the status of the selected files + const KFileItemList list = selectedItems(); + if (list.isEmpty()) { + // when an item is triggered, it is temporary selected but selectedItems() + // will return an empty list + return text; + } + + KFileItemList::const_iterator it = list.begin(); + const KFileItemList::const_iterator end = list.end(); + while (it != end) { + const KFileItem& item = *it; + if (item.isDir()) { + ++folderCount; + } else { + ++fileCount; + totalFileSize += item.size(); + } + ++it; + } + + if (folderCount + fileCount == 1) { + // if only one item is selected, show the filename + const QString name = list.first().text(); + text = (folderCount == 1) ? i18nc("@info:status", "%1 selected", name) : + i18nc("@info:status", "%1 selected (%2)", + name, KIO::convertSize(totalFileSize)); + } else { + // at least 2 items are selected + const QString foldersText = i18ncp("@info:status", "1 Folder selected", "%1 Folders selected", folderCount); + const QString filesText = i18ncp("@info:status", "1 File selected", "%1 Files selected", fileCount); + if ((folderCount > 0) && (fileCount > 0)) { + text = i18nc("@info:status folders, files (size)", "%1, %2 (%3)", + foldersText, filesText, KIO::convertSize(totalFileSize)); + } else if (fileCount > 0) { + text = i18nc("@info:status files (size)", "%1 (%2)", filesText, KIO::convertSize(totalFileSize)); + } else { + Q_ASSERT(folderCount > 0); + text = foldersText; + } + } + } else { + calculateItemCount(fileCount, folderCount, totalFileSize); + text = KIO::itemsSummaryString(fileCount + folderCount, + fileCount, folderCount, + totalFileSize, true); + } + + return text; +} + +QList DolphinView::versionControlActions(const KFileItemList& items) const +{ + return m_dolphinViewController->versionControlActions(items); +} + +void DolphinView::setUrl(const KUrl& url) +{ + if (m_viewModeController->url() != url) { + 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); + } + + // the selection model might have changed in the case of a column view + QItemSelectionModel* selectionModel = m_viewAccessor.itemView()->selectionModel(); + if (m_selectionModel != selectionModel) { + disconnect(m_selectionModel, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), + this, SLOT(slotSelectionChanged(QItemSelection, QItemSelection))); + m_selectionModel = selectionModel; + connect(m_selectionModel, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), + this, SLOT(slotSelectionChanged(QItemSelection, QItemSelection))); + } +} + +void DolphinView::selectAll() +{ + m_viewAccessor.itemView()->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); + + const QItemSelection selection(topLeft, bottomRight); + selectionModel->select(selection, QItemSelectionModel::Toggle); +} + +void DolphinView::clearSelection() +{ + m_viewAccessor.itemView()->clearSelection(); +} + +void DolphinView::renameSelectedItems() +{ + KFileItemList items = selectedItems(); + const int itemCount = items.count(); + if (itemCount < 1) { + return; + } + + if (itemCount > 1) { + // More than one item has been selected for renaming. Open + // a rename dialog and rename all items afterwards. + QPointer dialog = new RenameDialog(this, items); + if (dialog->exec() == QDialog::Rejected) { + delete dialog; + return; + } + + const QString newName = dialog->newName(); + if (newName.isEmpty()) { + emit errorMessage(dialog->errorString()); + delete dialog; + return; + } + delete dialog; + + // the selection would be invalid after renaming the items, so just clear + // it before + clearSelection(); + + // TODO: check how this can be integrated into KIO::FileUndoManager/KonqOperations + // as one operation instead of n rename operations like it is done now... + Q_ASSERT(newName.contains('#')); + + // currently the items are sorted by the selection order, resort + // them by the file name + qSort(items.begin(), items.end(), lessThan); + + // iterate through all selected items and rename them... + int index = 1; + foreach (const KFileItem& item, items) { + const KUrl& oldUrl = item.url(); + QString number; + number.setNum(index++); + + QString name = newName; + name.replace('#', number); + + if (oldUrl.fileName() != name) { + KUrl newUrl = oldUrl; + newUrl.setFileName(name); + KonqOperations::rename(this, oldUrl, newUrl); + } + } + } else if (DolphinSettings::instance().generalSettings()->renameInline()) { + Q_ASSERT(itemCount == 1); + const QModelIndex dirIndex = m_viewAccessor.dirModel()->indexForItem(items.first()); + const QModelIndex proxyIndex = m_viewAccessor.proxyModel()->mapFromSource(dirIndex); + m_viewAccessor.itemView()->edit(proxyIndex); + } else { + Q_ASSERT(itemCount == 1); + + QPointer dialog = new RenameDialog(this, items); + if (dialog->exec() == QDialog::Rejected) { + delete dialog; + return; + } + + const QString newName = dialog->newName(); + if (newName.isEmpty()) { + emit errorMessage(dialog->errorString()); + delete dialog; + return; + } + delete dialog; + + const KUrl& oldUrl = items.first().url(); + KUrl newUrl = oldUrl; + newUrl.setFileName(newName); + KonqOperations::rename(this, oldUrl, newUrl); + } + + // assure that the current index remains visible when KDirLister + // will notify the view about changed items + m_assureVisibleCurrentIndex = true; +} + +void DolphinView::trashSelectedItems() +{ + const KUrl::List list = simplifiedSelectedUrls(); + KonqOperations::del(this, KonqOperations::TRASH, list); +} + +void DolphinView::deleteSelectedItems() +{ + const KUrl::List list = simplifiedSelectedUrls(); + const bool del = KonqOperations::askDeleteConfirmation(list, + KonqOperations::DEL, + KonqOperations::DEFAULT_CONFIRMATION, + this); + + if (del) { + KIO::Job* job = KIO::del(list); + connect(job, SIGNAL(result(KJob*)), + this, SLOT(slotDeleteFileFinished(KJob*))); + } +} + +void DolphinView::cutSelectedItems() +{ + QMimeData* mimeData = selectionMimeData(); + KonqMimeData::addIsCutSelection(mimeData, true); + QApplication::clipboard()->setMimeData(mimeData); +} + +void DolphinView::copySelectedItems() +{ + QMimeData* mimeData = selectionMimeData(); + QApplication::clipboard()->setMimeData(mimeData); +} + +void DolphinView::paste() +{ + pasteToUrl(url()); +} + +void DolphinView::pasteIntoFolder() +{ + const KFileItemList items = selectedItems(); + if ((items.count() == 1) && items.first().isDir()) { + pasteToUrl(items.first().url()); + } +} + +void DolphinView::setShowPreview(bool show) +{ + if (m_showPreview == show) { + return; + } + + const KUrl viewPropsUrl = rootUrl(); + ViewProperties props(viewPropsUrl); + props.setShowPreview(show); + + m_showPreview = show; + const int oldZoomLevel = m_viewModeController->zoomLevel(); + emit showPreviewChanged(); + + // Enabling or disabling the preview might change the icon size of the view. + // As the view does not emit a signal when the icon size has been changed, + // the used zoom level of the controller must be adjusted manually: + updateZoomLevel(oldZoomLevel); +} + +void DolphinView::setShowHiddenFiles(bool show) +{ + if (m_viewAccessor.dirLister()->showingDotFiles() == show) { + return; + } + + const KUrl viewPropsUrl = rootUrl(); + ViewProperties props(viewPropsUrl); + props.setShowHiddenFiles(show); + + m_viewAccessor.dirLister()->setShowingDotFiles(show); + emit showHiddenFilesChanged(); +} + +void DolphinView::setCategorizedSorting(bool categorized) +{ + if (categorized == categorizedSorting()) { + return; + } + + // setCategorizedSorting(true) may only get invoked + // if the view supports categorized sorting + Q_ASSERT(!categorized || supportsCategorizedSorting()); + + ViewProperties props(rootUrl()); + props.setCategorizedSorting(categorized); + props.save(); + + m_storedCategorizedSorting = categorized; + m_viewAccessor.proxyModel()->setCategorizedModel(categorized); + + emit categorizedSortingChanged(); +} + +void DolphinView::toggleSortOrder() +{ + const Qt::SortOrder order = (sortOrder() == Qt::AscendingOrder) ? + Qt::DescendingOrder : + Qt::AscendingOrder; + setSortOrder(order); +} + +void DolphinView::toggleSortFoldersFirst() +{ + setSortFoldersFirst(!sortFoldersFirst()); +} + +void DolphinView::toggleAdditionalInfo(QAction* action) +{ + const KFileItemDelegate::Information info = + static_cast(action->data().toInt()); + + KFileItemDelegate::InformationList list = additionalInfo(); + + const bool show = action->isChecked(); + + const int index = list.indexOf(info); + const bool containsInfo = (index >= 0); + if (show && !containsInfo) { + list.append(info); + setAdditionalInfo(list); + } else if (!show && containsInfo) { + list.removeAt(index); + setAdditionalInfo(list); + Q_ASSERT(list.indexOf(info) < 0); + } +} + +void DolphinView::mouseReleaseEvent(QMouseEvent* event) +{ + QWidget::mouseReleaseEvent(event); + setActive(true); +} + +bool DolphinView::eventFilter(QObject* watched, QEvent* event) +{ + switch (event->type()) { + case QEvent::FocusIn: + if (watched == m_viewAccessor.itemView()) { + m_dolphinViewController->requestActivation(); + } + break; + + case QEvent::DragEnter: + if (watched == m_viewAccessor.itemView()->viewport()) { + setActive(true); + } + break; + + case QEvent::KeyPress: + if (watched == m_viewAccessor.itemView()) { + // clear the selection when Escape has been pressed + QKeyEvent* keyEvent = static_cast(event); + if (keyEvent->key() == Qt::Key_Escape) { + clearSelection(); + } + } + break; + + case QEvent::Wheel: + if (watched == m_viewAccessor.itemView()->viewport()) { + // Ctrl+wheel events should cause icon zooming, but not if the left mouse button is pressed + // (the user is probably trying to scroll during a selection in that case) + QWheelEvent* wheelEvent = static_cast(event); + if (wheelEvent->modifiers() & Qt::ControlModifier && !(wheelEvent->buttons() & Qt::LeftButton)) { + const int delta = wheelEvent->delta(); + const int level = zoomLevel(); + if (delta > 0) { + setZoomLevel(level + 1); + } else if (delta < 0) { + setZoomLevel(level - 1); + } + return true; + } + } + break; + + default: + break; + } + + return QWidget::eventFilter(watched, event); +} + +void DolphinView::activate() +{ + setActive(true); +} + +void DolphinView::triggerItem(const KFileItem& item) +{ + 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; + } + + // TODO: the m_isContextMenuOpen check is a workaround for Qt-issue 207192 + if (item.isNull() || m_isContextMenuOpen) { + return; + } + + emit itemTriggered(item); // caught by DolphinViewContainer or DolphinPart +} + +void DolphinView::slotSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected) +{ + const int count = selectedItemsCount(); + const bool selectionStateChanged = ((count > 0) && (selected.count() == count)) || + ((count == 0) && !deselected.isEmpty()); + + // If nothing has been selected before and something got selected (or if something + // was selected before and now nothing is selected) the selectionChangedSignal must + // be emitted asynchronously as fast as possible to update the edit-actions. + m_selectionChangedTimer->setInterval(selectionStateChanged ? 0 : 300); + m_selectionChangedTimer->start(); +} + +void DolphinView::emitSelectionChangedSignal() +{ + emit selectionChanged(DolphinView::selectedItems()); +} + +void DolphinView::openContextMenu(const QPoint& pos, + const QList& customActions) +{ + KFileItem item; + const QModelIndex index = m_viewAccessor.itemView()->indexAt(pos); + if (index.isValid() && (index.column() == DolphinModel::Name)) { + const QModelIndex dolphinModelIndex = m_viewAccessor.proxyModel()->mapToSource(index); + item = m_viewAccessor.dirModel()->itemForIndex(dolphinModelIndex); + } + + m_isContextMenuOpen = true; // TODO: workaround for Qt-issue 207192 + emit requestContextMenu(item, url(), customActions); + m_isContextMenuOpen = false; +} + +void DolphinView::dropUrls(const KFileItem& destItem, + const KUrl& destPath, + QDropEvent* event) +{ + addNewFileNames(event->mimeData()); + DragAndDropHelper::instance().dropUrls(destItem, destPath, event, this); +} + +void DolphinView::updateSorting(DolphinView::Sorting sorting) +{ + ViewProperties props(rootUrl()); + props.setSorting(sorting); + + m_viewAccessor.proxyModel()->setSorting(sorting); + + emit sortingChanged(sorting); +} + +void DolphinView::updateSortOrder(Qt::SortOrder order) +{ + ViewProperties props(rootUrl()); + props.setSortOrder(order); + + m_viewAccessor.proxyModel()->setSortOrder(order); + + emit sortOrderChanged(order); +} + +void DolphinView::updateSortFoldersFirst(bool foldersFirst) +{ + ViewProperties props(rootUrl()); + props.setSortFoldersFirst(foldersFirst); + + m_viewAccessor.proxyModel()->setSortFoldersFirst(foldersFirst); + + emit sortFoldersFirstChanged(foldersFirst); +} + +void DolphinView::updateAdditionalInfo(const KFileItemDelegate::InformationList& info) +{ + ViewProperties props(rootUrl()); + props.setAdditionalInfo(info); + props.save(); + + m_viewAccessor.itemDelegate()->setShowInformation(info); + + emit additionalInfoChanged(); +} + +void DolphinView::updateAdditionalInfoActions(KActionCollection* collection) +{ + const AdditionalInfoAccessor& infoAccessor = AdditionalInfoAccessor::instance(); + + const KFileItemDelegate::InformationList checkedInfos = m_viewAccessor.itemDelegate()->showInformation(); + const KFileItemDelegate::InformationList infos = infoAccessor.keys(); + + const bool enable = (m_mode == DolphinView::DetailsView) || + (m_mode == DolphinView::IconsView); + + foreach (const KFileItemDelegate::Information& info, infos) { + const QString name = infoAccessor.actionCollectionName(info, AdditionalInfoAccessor::AdditionalInfoType); + QAction* action = collection->action(name); + Q_ASSERT(action != 0); + action->setEnabled(enable); + action->setChecked(checkedInfos.contains(info)); + } +} + +QPair DolphinView::pasteInfo() const +{ + return KonqOperations::pasteInfo(url()); +} + +void DolphinView::setTabsForFilesEnabled(bool tabsForFiles) +{ + m_tabsForFiles = tabsForFiles; +} + +bool DolphinView::isTabsForFilesEnabled() const +{ + return m_tabsForFiles; +} + +bool DolphinView::itemsExpandable() const +{ + 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 urlsToExpand; + stream >> urlsToExpand; + const DolphinDetailsViewExpander* expander = m_viewAccessor.setExpandedUrls(urlsToExpand); + if (expander != 0) { + 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 != 0) { + 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 + 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) + stream << m_viewAccessor.expandedUrls(); +} + +void DolphinView::observeCreatedItem(const KUrl& url) +{ + m_createdItemUrl = url; + connect(m_viewAccessor.dirModel(), SIGNAL(rowsInserted(const QModelIndex&, int, int)), + this, SLOT(selectAndScrollToCreatedItem())); +} + +void DolphinView::selectAndScrollToCreatedItem() +{ + const QModelIndex dirIndex = m_viewAccessor.dirModel()->indexForUrl(m_createdItemUrl); + if (dirIndex.isValid()) { + const QModelIndex proxyIndex = m_viewAccessor.proxyModel()->mapFromSource(dirIndex); + m_viewAccessor.itemView()->setCurrentIndex(proxyIndex); + } + + disconnect(m_viewAccessor.dirModel(), SIGNAL(rowsInserted(const QModelIndex&, int, int)), + this, SLOT(selectAndScrollToCreatedItem())); + m_createdItemUrl = KUrl(); +} + +void DolphinView::showHoverInformation(const KFileItem& item) +{ + emit requestItemInfo(item); +} + +void DolphinView::clearHoverInformation() +{ + emit requestItemInfo(KFileItem()); +} + +void DolphinView::slotDeleteFileFinished(KJob* job) +{ + if (job->error() == 0) { + emit operationCompletedMessage(i18nc("@info:status", "Delete operation completed.")); + } else if (job->error() != KIO::ERR_USER_CANCELED) { + emit errorMessage(job->errorString()); + } +} + +void DolphinView::slotDirListerCompleted() +{ + if (!m_expanderActive) { + slotLoadingCompleted(); + } + + if (!m_newFileNames.isEmpty()) { + // select all newly added items created by a paste operation or + // a drag & drop operation, and clear the previous selection + m_viewAccessor.itemView()->clearSelection(); + const int rowCount = m_viewAccessor.proxyModel()->rowCount(); + QItemSelection selection; + for (int row = 0; row < rowCount; ++row) { + const QModelIndex proxyIndex = m_viewAccessor.proxyModel()->index(row, 0); + const QModelIndex dirIndex = m_viewAccessor.proxyModel()->mapToSource(proxyIndex); + const KUrl url = m_viewAccessor.dirModel()->itemForIndex(dirIndex).url(); + if (m_newFileNames.contains(url.fileName())) { + selection.merge(QItemSelection(proxyIndex, proxyIndex), QItemSelectionModel::Select); + } + } + m_viewAccessor.itemView()->selectionModel()->select(selection, QItemSelectionModel::Select); + + m_newFileNames.clear(); + } +} + +void DolphinView::slotLoadingCompleted() +{ + m_expanderActive = 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(); + } + } + + if (!m_selectedItems.isEmpty()) { + const KUrl& baseUrl = url(); + KUrl url; + QItemSelection newSelection; + 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)); + newSelection.select(index, index); + } + } + m_viewAccessor.itemView()->selectionModel()->select(newSelection, + QItemSelectionModel::ClearAndSelect + | QItemSelectionModel::Current); + m_selectedItems.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_assureVisibleCurrentIndex = false; + m_viewAccessor.itemView()->scrollTo(m_viewAccessor.itemView()->currentIndex()); + } +} + +void DolphinView::loadDirectory(const KUrl& url, bool reload) +{ + if (!url.isValid()) { + const QString location(url.pathOrUrl()); + if (location.isEmpty()) { + emit errorMessage(i18nc("@info:status", "The location is empty.")); + } else { + emit errorMessage(i18nc("@info:status", "The location '%1' is invalid.", location)); + } + return; + } + + KDirLister* dirLister = m_viewAccessor.dirLister(); + dirLister->openUrl(url, reload ? KDirLister::Reload : KDirLister::NoFlags); +} + +void DolphinView::applyViewProperties() +{ + if (m_ignoreViewProperties) { + return; + } + + const ViewProperties props(rootUrl()); + + const Mode mode = props.viewMode(); + if (m_mode != mode) { + const int oldZoomLevel = m_viewModeController->zoomLevel(); + + m_mode = mode; + createView(); + emit modeChanged(); + + updateZoomLevel(oldZoomLevel); + } + if (m_viewAccessor.itemView() == 0) { + createView(); + } + Q_ASSERT(m_viewAccessor.itemView() != 0); + Q_ASSERT(m_viewAccessor.itemDelegate() != 0); + + const bool showHiddenFiles = props.showHiddenFiles(); + if (showHiddenFiles != m_viewAccessor.dirLister()->showingDotFiles()) { + m_viewAccessor.dirLister()->setShowingDotFiles(showHiddenFiles); + emit showHiddenFilesChanged(); + } + + m_storedCategorizedSorting = props.categorizedSorting(); + const bool categorized = m_storedCategorizedSorting && supportsCategorizedSorting(); + if (categorized != m_viewAccessor.proxyModel()->isCategorizedModel()) { + m_viewAccessor.proxyModel()->setCategorizedModel(categorized); + emit categorizedSortingChanged(); + } + + const DolphinView::Sorting sorting = props.sorting(); + if (sorting != m_viewAccessor.proxyModel()->sorting()) { + m_viewAccessor.proxyModel()->setSorting(sorting); + emit sortingChanged(sorting); + } + + const Qt::SortOrder sortOrder = props.sortOrder(); + if (sortOrder != m_viewAccessor.proxyModel()->sortOrder()) { + m_viewAccessor.proxyModel()->setSortOrder(sortOrder); + emit sortOrderChanged(sortOrder); + } + + const bool sortFoldersFirst = props.sortFoldersFirst(); + if (sortFoldersFirst != m_viewAccessor.proxyModel()->sortFoldersFirst()) { + m_viewAccessor.proxyModel()->setSortFoldersFirst(sortFoldersFirst); + emit sortFoldersFirstChanged(sortFoldersFirst); + } + + KFileItemDelegate::InformationList info = props.additionalInfo(); + if (info != m_viewAccessor.itemDelegate()->showInformation()) { + m_viewAccessor.itemDelegate()->setShowInformation(info); + emit additionalInfoChanged(); + } + + const bool showPreview = props.showPreview(); + if (showPreview != m_showPreview) { + m_showPreview = showPreview; + const int oldZoomLevel = m_viewModeController->zoomLevel(); + emit showPreviewChanged(); + + // Enabling or disabling the preview might change the icon size of the view. + // As the view does not emit a signal when the icon size has been changed, + // the used zoom level of the controller must be adjusted manually: + updateZoomLevel(oldZoomLevel); + } + + if (DolphinSettings::instance().generalSettings()->globalViewProps()) { + // During the lifetime of a DolphinView instance the global view properties + // should not be changed. This allows e. g. to split a view and use different + // view properties for each view. + m_ignoreViewProperties = true; + } +} + +void DolphinView::createView() +{ + deleteView(); + + Q_ASSERT(m_viewAccessor.itemView() == 0); + m_viewAccessor.createView(this, m_dolphinViewController, m_viewModeController, m_mode); + + QAbstractItemView* view = m_viewAccessor.itemView(); + Q_ASSERT(view != 0); + view->installEventFilter(this); + view->viewport()->installEventFilter(this); + + m_dolphinViewController->setItemView(view); + + // When changing the view mode, the selection is lost due to reinstantiating + // a new item view with a custom selection model. Pass the ownership of the + // selection model to DolphinView, so that it can be shared by all item views. + if (m_selectionModel != 0) { + view->setSelectionModel(m_selectionModel); + } else { + m_selectionModel = view->selectionModel(); + } + m_selectionModel->setParent(this); + connect(m_selectionModel, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), + this, SLOT(slotSelectionChanged(QItemSelection, QItemSelection))); + + setFocusProxy(m_viewAccessor.layoutTarget()); + m_topLayout->insertWidget(1, m_viewAccessor.layoutTarget()); +} + +void DolphinView::deleteView() +{ + QAbstractItemView* view = m_viewAccessor.itemView(); + if (view != 0) { + // 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_topLayout->removeWidget(view); + view->close(); + + // disconnect all signal/slots + disconnect(view); + m_viewModeController->disconnect(view); + view->disconnect(); + + m_viewAccessor.deleteView(); + } +} + +void DolphinView::pasteToUrl(const KUrl& url) +{ + addNewFileNames(QApplication::clipboard()->mimeData()); + KonqOperations::doPaste(this, url); +} + +void DolphinView::updateZoomLevel(int oldZoomLevel) +{ + const int newZoomLevel = ZoomLevelInfo::zoomLevelForIconSize(m_viewAccessor.itemView()->iconSize()); + if (oldZoomLevel != newZoomLevel) { + m_viewModeController->setZoomLevel(newZoomLevel); + emit zoomLevelChanged(newZoomLevel); + } +} + +KUrl::List DolphinView::simplifiedSelectedUrls() const +{ + KUrl::List list = selectedUrls(); + if (itemsExpandable() ) { + list = KDirModel::simplifiedUrlList(list); + } + return list; +} + +QMimeData* DolphinView::selectionMimeData() const +{ + const QAbstractItemView* view = m_viewAccessor.itemView(); + Q_ASSERT((view != 0) && (view->selectionModel() != 0)); + const QItemSelection selection = m_viewAccessor.proxyModel()->mapSelectionToSource(view->selectionModel()->selection()); + return m_viewAccessor.dirModel()->mimeData(selection.indexes()); +} + +void DolphinView::addNewFileNames(const QMimeData* mimeData) +{ + const KUrl::List urls = KUrl::List::fromMimeData(mimeData); + foreach (const KUrl& url, urls) { + m_newFileNames.insert(url.fileName()); + } +} + +DolphinView::ViewAccessor::ViewAccessor(DolphinSortFilterProxyModel* proxyModel) : + m_iconsView(0), + m_detailsView(0), + m_columnsContainer(0), + m_proxyModel(proxyModel), + m_dragSource(0) +{ +} + +DolphinView::ViewAccessor::~ViewAccessor() +{ + delete m_dragSource; + m_dragSource = 0; +} + +void DolphinView::ViewAccessor::createView(QWidget* parent, + DolphinViewController* dolphinViewController, + const ViewModeController* viewModeController, + Mode mode) +{ + Q_ASSERT(itemView() == 0); + + switch (mode) { + case IconsView: + m_iconsView = new DolphinIconsView(parent, + dolphinViewController, + viewModeController, + m_proxyModel); + break; + + case DetailsView: + m_detailsView = new DolphinDetailsView(parent, + dolphinViewController, + viewModeController, + m_proxyModel); + break; + + case ColumnView: + m_columnsContainer = new DolphinColumnViewContainer(parent, + dolphinViewController, + viewModeController); + break; + + default: + Q_ASSERT(false); + } +} + +void DolphinView::ViewAccessor::deleteView() +{ + QAbstractItemView* view = itemView(); + if (view != 0) { + if (DragAndDropHelper::instance().isDragSource(view)) { + // The view is a drag source (the feature "Open folders + // during drag operations" is used). Deleting the view + // during an ongoing drag operation is not allowed, so + // this will postponed. + if (m_dragSource != 0) { + // the old stored view is obviously not the drag source anymore + m_dragSource->deleteLater(); + m_dragSource = 0; + } + view->hide(); + m_dragSource = view; + } else { + view->deleteLater(); + } + } + + m_iconsView = 0; + m_detailsView = 0; + + if (m_columnsContainer != 0) { + m_columnsContainer->deleteLater(); + } + m_columnsContainer = 0; +} + + +void DolphinView::ViewAccessor::prepareUrlChange(const KUrl& url) +{ + if (m_columnsContainer != 0) { + m_columnsContainer->showColumn(url); + } +} + +QAbstractItemView* DolphinView::ViewAccessor::itemView() const +{ + if (m_iconsView != 0) { + return m_iconsView; + } + + if (m_detailsView != 0) { + return m_detailsView; + } + + if (m_columnsContainer != 0) { + return m_columnsContainer->activeColumn(); + } + + return 0; +} + +KFileItemDelegate* DolphinView::ViewAccessor::itemDelegate() const +{ + return static_cast(itemView()->itemDelegate()); +} + +QWidget* DolphinView::ViewAccessor::layoutTarget() const +{ + if (m_columnsContainer != 0) { + return m_columnsContainer; + } + return itemView(); +} + +KUrl DolphinView::ViewAccessor::rootUrl() const +{ + return (m_columnsContainer != 0) ? m_columnsContainer->rootUrl() : KUrl(); +} + +bool DolphinView::ViewAccessor::supportsCategorizedSorting() const +{ + return m_iconsView != 0; +} + +bool DolphinView::ViewAccessor::itemsExpandable() const +{ + return (m_detailsView != 0) && m_detailsView->itemsExpandable(); +} + + +QSet DolphinView::ViewAccessor::expandedUrls() const +{ + if (m_detailsView != 0) { + return m_detailsView->expandedUrls(); + } + + return QSet(); +} + +const DolphinDetailsViewExpander* DolphinView::ViewAccessor::setExpandedUrls(const QSet& urlsToExpand) +{ + if ((m_detailsView != 0) && m_detailsView->itemsExpandable() && !urlsToExpand.isEmpty()) { + // Check if another expander is already active and stop it if necessary. + if(!m_detailsViewExpander.isNull()) { + m_detailsViewExpander->stop(); + } + + 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 + // the file item delegate info to its columns internally + return m_detailsView != 0; +} + +DolphinModel* DolphinView::ViewAccessor::dirModel() const +{ + return static_cast(proxyModel()->sourceModel()); +} + +DolphinSortFilterProxyModel* DolphinView::ViewAccessor::proxyModel() const +{ + if (m_columnsContainer != 0) { + return static_cast(m_columnsContainer->activeColumn()->model()); + } + return m_proxyModel; +} + +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" diff --git a/src/views/dolphinview.h b/src/views/dolphinview.h new file mode 100644 index 000000000..dbef511bf --- /dev/null +++ b/src/views/dolphinview.h @@ -0,0 +1,818 @@ +/*************************************************************************** + * Copyright (C) 2006-2009 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 * + ***************************************************************************/ + + +#ifndef DOLPHINVIEW_H +#define DOLPHINVIEW_H + +#include + +#include "libdolphin_export.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +typedef KIO::FileUndoManager::CommandType CommandType; + +class DolphinColumnViewContainer; +class DolphinDetailsView; +class DolphinIconsView; +class DolphinModel; +class DolphinSortFilterProxyModel; +class DolphinViewController; +class KAction; +class KActionCollection; +class KDirLister; +class KUrl; +class ViewModeController; +class ViewProperties; +class DolphinDetailsViewExpander; + +/** + * @short Represents a view for the directory content. + * + * View modes for icons, details and columns are supported. It's + * possible to adjust: + * - sort order + * - sort type + * - show hidden files + * - show previews + * + * @see DolphinIconsView + * @see DolphinDetailsView + * @see DolphinColumnView + */ +class LIBDOLPHINPRIVATE_EXPORT DolphinView : public QWidget +{ + Q_OBJECT + +public: + /** + * Defines the view mode for a directory. The view mode + * can be defined when constructing a DolphinView. The + * view mode is automatically updated if the directory itself + * defines a view mode (see class ViewProperties for details). + */ + enum Mode + { + /** + * The directory items are shown as icons including an + * icon name. + */ + IconsView = 0, + + /** + * The icon, the name and at least the size of the directory + * items are shown in a table. It is possible to add columns + * for date, group and permissions. + */ + DetailsView = 1, + + /** + * Each folder is shown in a separate column. + */ + ColumnView = 2, + MaxModeEnum = ColumnView + }; + + /** Defines the sort order for the items of a directory. */ + enum Sorting + { + SortByName = 0, + SortBySize, + SortByDate, + SortByPermissions, + SortByOwner, + SortByGroup, + SortByType, + SortByDestination, + SortByPath, + MaxSortingEnum = SortByPath + }; + + /** + * @param parent Parent widget of the view. + * @param url Specifies the content which should be shown. + * @param proxyModel Used proxy model which specifies the sorting. The + * model is not owned by the view and won't get + * deleted. + */ + DolphinView(QWidget* parent, + const KUrl& url, + DolphinSortFilterProxyModel* proxyModel); + + virtual ~DolphinView(); + + /** + * Returns the current active URL, where all actions are applied. + * The URL navigator is synchronized with this URL. + */ + KUrl url() const; + + /** + * Returns the root URL of the view, which is defined as the first + * visible path of DolphinView::url(). Usually the root URL is + * equal to DolphinView::url(), but in the case of the column view + * when 2 columns are shown, the root URL might be: + * /home/peter/Documents + * and DolphinView::url() might return + * /home/peter/Documents/Music/ + */ + KUrl rootUrl() const; + + /** + * If \a active is true, the view will marked as active. The active + * view is defined as view where all actions are applied to. + */ + void setActive(bool active); + bool isActive() const; + + /** + * Changes the view mode for the current directory to \a mode. + * If the view properties should be remembered for each directory + * (GeneralSettings::globalViewProps() returns false), then the + * changed view mode will be stored automatically. + */ + void setMode(Mode mode); + Mode mode() const; + + /** See setShowPreview */ + bool showPreview() const; + + /** See setShowHiddenFiles */ + bool showHiddenFiles() const; + + /** See setCategorizedSorting */ + bool categorizedSorting() const; + + /** + * Returns true, if the categorized sorting is supported by the current + * used mode (see DolphinView::setMode()). Currently only DolphinView::IconsView + * supports categorizations. To check whether the categorized + * sorting is set, use DolphinView::categorizedSorting(). + */ + bool supportsCategorizedSorting() const; + + /** + * Marks the items indicated by \p urls to get selected after the + * directory DolphinView::url() has been loaded. Note that nothing + * gets selected if no loading of a directory has been triggered + * by DolphinView::setUrl() or DolphinView::reload(). + */ + void markUrlsAsSelected(const QList& urls); + + /** + * Returns the selected items. The list is empty if no item has been + * selected. + * @see DolphinView::selectedUrls() + */ + KFileItemList selectedItems() const; + + /** + * Returns a list of URLs for all selected items. An empty list + * is returned, if no item is selected. + * @see DolphinView::selectedItems() + */ + KUrl::List selectedUrls() const; + + /** + * Returns the number of selected items (this is faster than + * invoking selectedItems().count()). + */ + int selectedItemsCount() const; + + QItemSelectionModel* selectionModel() const; + + /** + * Sets the zoom level to \a level. It is assured that the used + * level is adjusted to be inside the range ZoomLevelInfo::minimumLevel() and + * ZoomLevelInfo::maximumLevel(). + */ + void setZoomLevel(int level); + int zoomLevel() const; + + /** + * Returns true, if zooming in is possible. If false is returned, + * the maximum zooming level has been reached. + */ + bool isZoomInPossible() const; + + /** + * Returns true, if zooming out is possible. If false is returned, + * the minimum zooming level has been reached. + */ + bool isZoomOutPossible() const; + + /** Sets the sort order of the items inside a directory (see DolphinView::Sorting). */ + void setSorting(Sorting sorting); + + /** Returns the sort order of the items inside a directory (see DolphinView::Sorting). */ + Sorting sorting() const; + + /** Sets the sort order (Qt::Ascending or Qt::Descending) for the items. */ + void setSortOrder(Qt::SortOrder order); + + /** Returns the current used sort order (Qt::Ascending or Qt::Descending). */ + Qt::SortOrder sortOrder() const; + + /** Sets a separate sorting with folders first (true) or a mixed sorting of files and folders (false). */ + void setSortFoldersFirst(bool foldersFirst); + + /** Returns if files and folders are sorted separately or not. */ + bool sortFoldersFirst() const; + + /** Sets the additional information which should be shown for the items. */ + void setAdditionalInfo(KFileItemDelegate::InformationList info); + + /** Returns the additional information which should be shown for the items. */ + KFileItemDelegate::InformationList additionalInfo() const; + + /** Reloads the current directory. */ + void reload(); + + /** + * Refreshes the view to get synchronized with the (updated) Dolphin settings. + * This method only needs to get invoked if the view settings for the Icons View, + * Details View or Columns View have been changed. + */ + void refresh(); + + /** + * Filters the currently shown items by \a nameFilter. All items + * which contain the given filter string will be shown. + */ + void setNameFilter(const QString& nameFilter); + + /** + * Calculates the number of currently shown files into + * \a fileCount and the number of folders into \a folderCount. + * The size of all files is written into \a totalFileSize. + * It is recommend using this method instead of asking the + * directory lister or the model directly, as it takes + * filtering and hierarchical previews into account. + */ + void calculateItemCount(int& fileCount, int& folderCount, KIO::filesize_t& totalFileSize) const; + + /** + * Returns a textual representation of the state of the current + * folder or selected items, suitable for use in the status bar. + */ + QString statusBarText() const; + + /** + * Returns the version control actions that are provided for the items \p items. + * Usually the actions are presented in the context menu. + */ + QList versionControlActions(const KFileItemList& items) const; + + /** + * Updates the state of the 'Additional Information' actions in \a collection. + */ + void updateAdditionalInfoActions(KActionCollection* collection); + + /** + * Returns the state of the paste action: + * first is whether the action should be enabled + * second is the text for the action + */ + QPair pasteInfo() const; + + /** + * If \a tabsForFiles is true, the signal tabRequested() will also + * emitted also for files. Per default tabs for files is disabled + * and hence the signal tabRequested() will only be emitted for + * directories. + */ + void setTabsForFilesEnabled(bool tabsForFiles); + bool isTabsForFilesEnabled() const; + + /** + * Returns true if the current view allows folders to be expanded, + * i.e. presents a hierarchical view to the user. + */ + 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 + * \a url, nothing will be done (use DolphinView::reload() instead). + */ + void setUrl(const KUrl& url); + + /** + * Selects all items. + * @see DolphinView::selectedItems() + */ + void selectAll(); + + /** + * Inverts the current selection: selected items get unselected, + * unselected items get selected. + * @see DolphinView::selectedItems() + */ + void invertSelection(); + + /** Returns true, if at least one item is selected. */ + bool hasSelection() const; + + void clearSelection(); + + /** + * Triggers the renaming of the currently selected items, where + * the user must input a new name for the items. + */ + void renameSelectedItems(); + + /** + * Moves all selected items to the trash. + */ + void trashSelectedItems(); + + /** + * Deletes all selected items. + */ + void deleteSelectedItems(); + + /** + * Copies all selected items to the clipboard and marks + * the items as cut. + */ + void cutSelectedItems(); + + /** Copies all selected items to the clipboard. */ + void copySelectedItems(); + + /** Pastes the clipboard data to this view. */ + void paste(); + + /** + * Pastes the clipboard data into the currently selected + * folder. If the current selection is not exactly one folder, no + * paste operation is done. + */ + void pasteIntoFolder(); + + /** + * Turns on the file preview for the all files of the current directory, + * if \a show is true. + * If the view properties should be remembered for each directory + * (GeneralSettings::globalViewProps() returns false), then the + * preview setting will be stored automatically. + */ + void setShowPreview(bool show); + + /** + * Shows all hidden files of the current directory, + * if \a show is true. + * If the view properties should be remembered for each directory + * (GeneralSettings::globalViewProps() returns false), then the + * show hidden file setting will be stored automatically. + */ + void setShowHiddenFiles(bool show); + + /** + * Summarizes all sorted items by their category \a categorized + * is true. + * If the view properties should be remembered for each directory + * (GeneralSettings::globalViewProps() returns false), then the + * categorized sorting setting will be stored automatically. + */ + void setCategorizedSorting(bool categorized); + + /** Switches between an ascending and descending sorting order. */ + void toggleSortOrder(); + + /** Switches between a separate sorting (with folders first) and a mixed sorting of files and folders. */ + void toggleSortFoldersFirst(); + + /** + * Switches on or off the displaying of additional information + * as specified by \a action. + */ + void toggleAdditionalInfo(QAction* action); + +signals: + /** + * Is emitted if the view has been activated by e. g. a mouse click. + */ + void activated(); + + /** Is emitted if URL of the view has been changed to \a url. */ + void urlChanged(const KUrl& url); + + /** + * Is emitted when clicking on an item with the left mouse button. + */ + void itemTriggered(const KFileItem& item); + + /** + * Is emitted if a new tab should be opened for the URL \a url. + */ + void tabRequested(const KUrl& url); + + /** + * Is emitted if the view mode (IconsView, DetailsView, + * PreviewsView) has been changed. + */ + void modeChanged(); + + /** Is emitted if the 'show preview' property has been changed. */ + void showPreviewChanged(); + + /** Is emitted if the 'show hidden files' property has been changed. */ + void showHiddenFilesChanged(); + + /** Is emitted if the 'categorized sorting' property has been changed. */ + void categorizedSortingChanged(); + + /** Is emitted if the sorting by name, size or date has been changed. */ + void sortingChanged(DolphinView::Sorting sorting); + + /** Is emitted if the sort order (ascending or descending) has been changed. */ + void sortOrderChanged(Qt::SortOrder order); + + /** Is emitted if the sorting of files and folders (separate with folders first or mixed) has been changed. */ + void sortFoldersFirstChanged(bool foldersFirst); + + /** Is emitted if the additional information shown for this view has been changed. */ + void additionalInfoChanged(); + + /** Is emitted if the zoom level has been changed by zooming in or out. */ + void zoomLevelChanged(int level); + + /** + * Is emitted if information of an item is requested to be shown e. g. in the panel. + * If item is null, no item information request is pending. + */ + void requestItemInfo(const KFileItem& item); + + /** + * Is emitted whenever the selection has been changed. + */ + void selectionChanged(const KFileItemList& selection); + + /** + * Is emitted if a context menu is requested for the item \a item, + * which is part of \a url. If the item is null, the context menu + * for the URL should be shown and the custom actions \a customActions + * will be added. + */ + void requestContextMenu(const KFileItem& item, + const KUrl& url, + const QList& customActions); + + /** + * Is emitted if an information message with the content \a msg + * should be shown. + */ + void infoMessage(const QString& msg); + + /** + * Is emitted if an error message with the content \a msg + * should be shown. + */ + void errorMessage(const QString& msg); + + /** + * Is emitted if an "operation completed" message with the content \a msg + * should be shown. + */ + void operationCompletedMessage(const QString& msg); + + /** + * Is emitted after DolphinView::setUrl() has been invoked and + * the path \a url is currently loaded. If this signal is emitted, + * it is assured that the view contains already the correct root + * URL and property settings. + */ + void startedPathLoading(const KUrl& url); + + /** + * Emitted when KDirLister emits redirection. + * Testcase: fish://localhost + */ + void redirection(const KUrl& oldUrl, const KUrl& newUrl); + +protected: + /** @see QWidget::mouseReleaseEvent */ + virtual void mouseReleaseEvent(QMouseEvent* event); + virtual bool eventFilter(QObject* watched, QEvent* event); + +private slots: + /** + * Marks the view as active (DolphinView:isActive() will return true) + * and emits the 'activated' signal if it is not already active. + */ + void activate(); + + /** + * If the item \a item is a directory, then this + * directory will be loaded. If the item is a file, the corresponding + * application will get started. + */ + void triggerItem(const KFileItem& index); + + /** + * Emits the signal \a selectionChanged() with a small delay. This is + * because getting all file items for the signal can be an expensive + * operation. Fast selection changes are collected in this case and + * the signal is emitted only after no selection change has been done + * within a small delay. + */ + void slotSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected); + + /** + * Is called by emitDelayedSelectionChangedSignal() and emits the + * signal \a selectionChanged() with all selected file items as parameter. + */ + void emitSelectionChangedSignal(); + + /** + * Opens the context menu on position \a pos. The position + * is used to check whether the context menu is related to an + * item or to the viewport. + */ + void openContextMenu(const QPoint& pos, const QList& customActions); + + /** + * Drops dragged URLs to the destination path \a destPath. If + * the URLs are dropped above an item inside the destination path, + * the item is indicated by \a destItem. + */ + void dropUrls(const KFileItem& destItem, + const KUrl& destPath, + QDropEvent* event); + + /** + * Updates the view properties of the current URL to the + * sorting given by \a sorting. + */ + void updateSorting(DolphinView::Sorting sorting); + + /** + * Updates the view properties of the current URL to the + * sort order given by \a order. + */ + void updateSortOrder(Qt::SortOrder order); + + /** + * Updates the view properties of the current URL to the + * sorting of files and folders (separate with folders first or mixed) given by \a foldersFirst. + */ + void updateSortFoldersFirst(bool foldersFirst); + + /** + * Updates the view properties of the current URL to the + * additional information given by \a info. + */ + void updateAdditionalInfo(const KFileItemDelegate::InformationList& info); + + /** + * Updates the status bar to show hover information for the + * item \a item. If currently other items are selected, + * no hover information is shown. + * @see DolphinView::clearHoverInformation() + */ + void showHoverInformation(const KFileItem& item); + + /** + * Clears the hover information shown in the status bar. + * @see DolphinView::showHoverInformation(). + */ + void clearHoverInformation(); + + /** + * Indicates in the status bar that the delete operation + * of the job \a job has been finished. + */ + void slotDeleteFileFinished(KJob* job); + + /** + * Invoked when the directory lister has completed the loading of + * items. Assures that pasted items and renamed items get seleced. + */ + 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 slotRefreshItems(); + + /** + * Observes the item with the URL \a url. As soon as the directory + * model indicates that the item is available, the item will + * get selected and it is assure that the item stays visible. + * + * @see selectAndScrollToCreatedItem() + */ + void observeCreatedItem(const KUrl& url); + + /** + * Selects and scrolls to the item that got observed + * by observeCreatedItem(). + */ + void selectAndScrollToCreatedItem(); + + /** + * Called when a redirection happens. + * Testcase: fish://localhost + */ + 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); + + /** + * Applies the view properties which are defined by the current URL + * to the DolphinView properties. + */ + void applyViewProperties(); + + /** + * Creates a new view representing the given view mode (DolphinView::mode()). + * The current view will get deleted. + */ + void createView(); + + void deleteView(); + + /** + * Helper method for DolphinView::paste() and DolphinView::pasteIntoFolder(). + * Pastes the clipboard data into the URL \a url. + */ + void pasteToUrl(const KUrl& url); + + /** + * Checks whether the current item view has the same zoom level + * as \a oldZoomLevel. If this is not the case, the zoom level + * of the controller is updated and a zoomLevelChanged() signal + * is emitted. + */ + void updateZoomLevel(int oldZoomLevel); + + /** + * Returns a list of URLs for all selected items. The list is + * simplified, so that when the URLs are part of different tree + * levels, only the parent is returned. + */ + KUrl::List simplifiedSelectedUrls() const; + + /** + * Returns the MIME data for all selected items. + */ + QMimeData* selectionMimeData() const; + + /** + * Is invoked after a paste operation or a drag & drop + * operation and adds the filenames of all URLs from \a mimeData to + * m_newFileNames. This allows to select all newly added + * items in slotDirListerCompleted(). + */ + void addNewFileNames(const QMimeData* mimeData); + +private: + /** + * Abstracts the access to the different view implementations + * for icons-, details- and column-view. + */ + class ViewAccessor + { + public: + ViewAccessor(DolphinSortFilterProxyModel* proxyModel); + ~ViewAccessor(); + + void createView(QWidget* parent, + DolphinViewController* dolphinViewController, + const ViewModeController* viewModeController, + Mode mode); + void deleteView(); + + /** + * Must be invoked before the URL has been changed and allows view implementations + * like the column view to create a new column. + */ + void prepareUrlChange(const KUrl& url); + + QAbstractItemView* itemView() const; + KFileItemDelegate* itemDelegate() const; + + /** + * Returns the widget that should be added to the layout as target. Usually + * the item view itself is returned, but in the case of the column view + * a container widget is returned. + */ + QWidget* layoutTarget() const; + + KUrl rootUrl() const; + + bool supportsCategorizedSorting() const; + bool itemsExpandable() const; + QSet expandedUrls() const; + const DolphinDetailsViewExpander* setExpandedUrls(const QSet& urlsToExpand); + + /** + * Returns true, if a reloading of the items is required + * when the additional information properties have been changed + * by the user. + */ + bool reloadOnAdditionalInfoChange() const; + + DolphinModel* dirModel() const; + DolphinSortFilterProxyModel* proxyModel() const; + KDirLister* dirLister() const; + + private: + DolphinIconsView* m_iconsView; + DolphinDetailsView* m_detailsView; + DolphinColumnViewContainer* m_columnsContainer; + DolphinSortFilterProxyModel* m_proxyModel; + QAbstractItemView* m_dragSource; + QPointer m_detailsViewExpander; + }; + + bool m_active : 1; + bool m_showPreview : 1; + bool m_storedCategorizedSorting : 1; + bool m_tabsForFiles : 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; + + QVBoxLayout* m_topLayout; + + DolphinViewController* m_dolphinViewController; + ViewModeController* m_viewModeController; + ViewAccessor m_viewAccessor; + + QItemSelectionModel* m_selectionModel; // allow to switch views without losing the selection + QTimer* m_selectionChangedTimer; + + 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 + + /** + * Remembers the filenames that have been added by a paste operation + * or a drag & drop operation. Allows to select the items in + * slotDirListerCompleted(). + */ + QSet m_newFileNames; +}; + +/// Allow using DolphinView::Mode in QVariant +Q_DECLARE_METATYPE(DolphinView::Mode) + +#endif // DOLPHINVIEW_H diff --git a/src/views/dolphinviewautoscroller.cpp b/src/views/dolphinviewautoscroller.cpp new file mode 100644 index 000000000..45896a5eb --- /dev/null +++ b/src/views/dolphinviewautoscroller.cpp @@ -0,0 +1,223 @@ +/*************************************************************************** + * Copyright (C) 2008 by Peter Penz * + * * + * 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 "dolphinviewautoscroller.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +DolphinViewAutoScroller::DolphinViewAutoScroller(QAbstractItemView* parent) : + QObject(parent), + m_rubberBandSelection(false), + m_keyPressed(false), + m_initializedTimestamp(false), + m_horizontalScrollInc(0), + m_verticalScrollInc(0), + m_itemView(parent), + m_timer(0), + m_timestamp() +{ + m_itemView->setAutoScroll(false); + m_itemView->viewport()->installEventFilter(this); + m_itemView->installEventFilter(this); + + m_timer = new QTimer(this); + m_timer->setSingleShot(false); + m_timer->setInterval(1000 / 25); // 25 frames per second + connect(m_timer, SIGNAL(timeout()), this, SLOT(scrollViewport())); +} + +DolphinViewAutoScroller::~DolphinViewAutoScroller() +{ +} + +bool DolphinViewAutoScroller::isActive() const +{ + return m_timer->isActive(); +} + +void DolphinViewAutoScroller::handleCurrentIndexChange(const QModelIndex& current, + const QModelIndex& previous) +{ + // When the autoscroller is inactive and a key has been pressed, it must be + // assured that the current item stays visible. The check whether the previous + // item is valid is important because of #197951. The keypress check is done + // because of #199833. + if (current.isValid() && (previous.isValid() || m_keyPressed) && !isActive()) { + m_itemView->scrollTo(current); + } +} + +bool DolphinViewAutoScroller::eventFilter(QObject* watched, QEvent* event) +{ + if (watched == m_itemView->viewport()) { + switch (event->type()) { + case QEvent::MouseButtonPress: + if (static_cast(event)->button() == Qt::LeftButton) { + m_rubberBandSelection = true; + } + break; + + case QEvent::MouseMove: + if (m_rubberBandSelection) { + triggerAutoScroll(); + } + break; + + case QEvent::MouseButtonRelease: + m_rubberBandSelection = false; + stopAutoScroll(); + break; + + case QEvent::DragEnter: + case QEvent::DragMove: + m_rubberBandSelection = false; + triggerAutoScroll(); + break; + + case QEvent::Drop: + case QEvent::DragLeave: + m_rubberBandSelection = false; + stopAutoScroll(); + break; + + default: + break; + } + } else if (watched == m_itemView) { + switch (event->type()) { + case QEvent::KeyPress: + m_keyPressed = true; + break; + + case QEvent::KeyRelease: + m_keyPressed = false; + break; + + default: + break; + } + } + + return QObject::eventFilter(watched, event); +} + +void DolphinViewAutoScroller::scrollViewport() +{ + if (m_timestamp.elapsed() < QApplication::startDragTime()) { + return; + } + + QScrollBar* verticalScrollBar = m_itemView->verticalScrollBar(); + if (verticalScrollBar != 0) { + const int value = verticalScrollBar->value(); + verticalScrollBar->setValue(value + m_verticalScrollInc); + + } + QScrollBar* horizontalScrollBar = m_itemView->horizontalScrollBar(); + if (horizontalScrollBar != 0) { + const int value = horizontalScrollBar->value(); + horizontalScrollBar->setValue(value + m_horizontalScrollInc); + + } + + if (m_rubberBandSelection) { + // The scrolling does not lead to an update of the rubberband + // selection. Fake a mouse move event to let the QAbstractItemView + // update the rubberband. + QWidget* viewport = m_itemView->viewport(); + const QPoint pos = viewport->mapFromGlobal(QCursor::pos()); + QMouseEvent event(QEvent::MouseMove, pos, Qt::LeftButton, Qt::LeftButton, QApplication::keyboardModifiers()); + QCoreApplication::sendEvent(viewport, &event); + } +} + +void DolphinViewAutoScroller::triggerAutoScroll() +{ + const bool verticalScrolling = (m_itemView->verticalScrollBar() != 0) && + m_itemView->verticalScrollBar()->isVisible(); + const bool horizontalScrolling = (m_itemView->horizontalScrollBar() != 0) && + m_itemView->horizontalScrollBar()->isVisible(); + if (!verticalScrolling && !horizontalScrolling) { + // no scrollbars are shown at all, so no autoscrolling is necessary + stopAutoScroll(); + return; + } + + QWidget* viewport = m_itemView->viewport(); + const QPoint pos = viewport->mapFromGlobal(QCursor::pos()); + if (verticalScrolling) { + m_verticalScrollInc = calculateScrollIncrement(pos.y(), viewport->height()); + } + if (horizontalScrolling) { + m_horizontalScrollInc = calculateScrollIncrement(pos.x(), viewport->width()); + } + + if (m_timer->isActive()) { + if ((m_horizontalScrollInc == 0) && (m_verticalScrollInc == 0)) { + stopAutoScroll(); + } + } else if ((m_horizontalScrollInc != 0) || (m_verticalScrollInc != 0)) { + if (!m_initializedTimestamp) { + m_initializedTimestamp = true; + m_timestamp.start(); + } + m_timer->start(); + } +} + +void DolphinViewAutoScroller::stopAutoScroll() +{ + m_timer->stop(); + m_horizontalScrollInc = 0; + m_verticalScrollInc = 0; + m_initializedTimestamp = false; +} + +int DolphinViewAutoScroller::calculateScrollIncrement(int cursorPos, int rangeSize) const +{ + int inc = 0; + + const int minSpeed = 4; + const int maxSpeed = 768; + const int speedLimiter = 48; + const int autoScrollBorder = 64; + + if (cursorPos < autoScrollBorder) { + inc = -minSpeed + qAbs(cursorPos - autoScrollBorder) * (cursorPos - autoScrollBorder) / speedLimiter; + if (inc < -maxSpeed) { + inc = -maxSpeed; + } + } else if (cursorPos > rangeSize - autoScrollBorder) { + inc = minSpeed + qAbs(cursorPos - rangeSize + autoScrollBorder) * (cursorPos - rangeSize + autoScrollBorder) / speedLimiter; + if (inc > maxSpeed) { + inc = maxSpeed; + } + } + + return inc; +} + +#include "dolphinviewautoscroller.moc" diff --git a/src/views/dolphinviewautoscroller.h b/src/views/dolphinviewautoscroller.h new file mode 100644 index 000000000..9fd35d494 --- /dev/null +++ b/src/views/dolphinviewautoscroller.h @@ -0,0 +1,79 @@ +/*************************************************************************** + * Copyright (C) 2008 by Peter Penz * + * * + * 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 DOLPHINVIEWAUTOSCROLLER_H +#define DOLPHINVIEWAUTOSCROLLER_H + +#include +#include + +class QAbstractItemView; +class QModelIndex; +class QTimer; + +/** + * @brief Assures that an autoscrolling is done for item views. + * + * This is a workaround as QAbstractItemView::setAutoScroll() is not usable + * when selecting items (see Qt issue #214542). + */ +class DolphinViewAutoScroller : public QObject +{ + Q_OBJECT + +public: + DolphinViewAutoScroller(QAbstractItemView* parent); + virtual ~DolphinViewAutoScroller(); + bool isActive() const; + + /** + * Must be invoked by the parent item view, when QAbstractItemView::currentChanged() + * has been called. Assures that the current item stays visible when it has been + * changed by the keyboard. + */ + void handleCurrentIndexChange(const QModelIndex& current, const QModelIndex& previous); + +protected: + virtual bool eventFilter(QObject* watched, QEvent* event); + +private slots: + void scrollViewport(); + +private: + void triggerAutoScroll(); + void stopAutoScroll(); + + /** + * Calculates the scroll increment dependent from + * the cursor position \a cursorPos and the range 0 - \a rangeSize - 1. + */ + int calculateScrollIncrement(int cursorPos, int rangeSize) const; + +private: + bool m_rubberBandSelection; + bool m_keyPressed; + bool m_initializedTimestamp; + int m_horizontalScrollInc; + int m_verticalScrollInc; + QAbstractItemView* m_itemView; + QTimer* m_timer; + QTime m_timestamp; +}; + +#endif diff --git a/src/views/dolphinviewcontroller.cpp b/src/views/dolphinviewcontroller.cpp new file mode 100644 index 000000000..6ef32f07f --- /dev/null +++ b/src/views/dolphinviewcontroller.cpp @@ -0,0 +1,249 @@ +/*************************************************************************** + * Copyright (C) 2010 by Peter Penz * + * * + * 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 "dolphinviewcontroller.h" +#include "zoomlevelinfo.h" + +#include +#include +#include +#include +#include +#include + +Qt::MouseButtons DolphinViewController::m_mouseButtons = Qt::NoButton; + +DolphinViewController::DolphinViewController(DolphinView* dolphinView) : + QObject(dolphinView), + m_dolphinView(dolphinView), + m_itemView(0), + m_versionControlActions() +{ +} + +DolphinViewController::~DolphinViewController() +{ +} + +const DolphinView* DolphinViewController::view() const +{ + return m_dolphinView; +} + +void DolphinViewController::requestUrlChange(const KUrl& url) +{ + emit urlChangeRequested(url); +} + +void DolphinViewController::setItemView(QAbstractItemView* view) +{ + if (m_itemView != 0) { + disconnect(m_itemView, SIGNAL(pressed(const QModelIndex&)), + this, SLOT(updateMouseButtonState())); + } + + m_itemView = view; + + if (m_itemView != 0) { + // TODO: this is a workaround until Qt-issue 176832 has been fixed + connect(m_itemView, SIGNAL(pressed(const QModelIndex&)), + this, SLOT(updateMouseButtonState())); + } +} + +QAbstractItemView* DolphinViewController::itemView() const +{ + return m_itemView; +} + +void DolphinViewController::triggerContextMenuRequest(const QPoint& pos, + const QList& customActions) +{ + emit activated(); + emit requestContextMenu(pos, customActions); +} + +void DolphinViewController::requestActivation() +{ + emit activated(); +} + +void DolphinViewController::indicateDroppedUrls(const KFileItem& destItem, + const KUrl& destPath, + QDropEvent* event) +{ + emit urlsDropped(destItem, destPath, event); +} + + +void DolphinViewController::indicateSortingChange(DolphinView::Sorting sorting) +{ + emit sortingChanged(sorting); +} + +void DolphinViewController::indicateSortOrderChange(Qt::SortOrder order) +{ + emit sortOrderChanged(order); +} + +void DolphinViewController::indicateSortFoldersFirstChange(bool foldersFirst) +{ + emit sortFoldersFirstChanged(foldersFirst); +} + +void DolphinViewController::indicateAdditionalInfoChange(const KFileItemDelegate::InformationList& info) +{ + emit additionalInfoChanged(info); +} + +void DolphinViewController::setVersionControlActions(QList actions) +{ + m_versionControlActions = actions; +} + +QList DolphinViewController::versionControlActions(const KFileItemList& items) +{ + emit requestVersionControlActions(items); + // All view implementations are connected with the signal requestVersionControlActions() + // (see ViewExtensionFactory) and will invoke DolphinViewController::setVersionControlActions(), + // so that the context dependent actions can be returned. + return m_versionControlActions; +} + +void DolphinViewController::handleKeyPressEvent(QKeyEvent* event) +{ + Q_ASSERT(m_itemView != 0); + + const QItemSelectionModel* selModel = m_itemView->selectionModel(); + const QModelIndex currentIndex = selModel->currentIndex(); + const bool trigger = currentIndex.isValid() + && ((event->key() == Qt::Key_Return) || (event->key() == Qt::Key_Enter)) + && !selModel->selectedIndexes().isEmpty(); + if (!trigger) { + return; + } + + // Collect the non-directory files into a list and + // call runPreferredApplications for that list. + // Several selected directories are opened in separate tabs, + // one selected directory will get opened in the view. + QModelIndexList dirQueue; + const QModelIndexList indexList = selModel->selectedIndexes(); + KFileItemList fileOpenList; + foreach (const QModelIndex& index, indexList) { + if (itemForIndex(index).isDir()) { + dirQueue << index; + } else { + fileOpenList << itemForIndex(index); + } + } + + KFileItemActions fileItemActions; + fileItemActions.runPreferredApplications(fileOpenList, "DesktopEntryName != 'dolphin'"); + + if (dirQueue.length() == 1) { + // open directory in the view + emit itemTriggered(itemForIndex(dirQueue[0])); + } else { + // open directories in separate tabs + foreach(const QModelIndex& dir, dirQueue) { + emit tabRequested(itemForIndex(dir).url()); + } + } +} + +void DolphinViewController::replaceUrlByClipboard() +{ + const QClipboard* clipboard = QApplication::clipboard(); + QString text; + if (clipboard->mimeData(QClipboard::Selection)->hasText()) { + text = clipboard->mimeData(QClipboard::Selection)->text(); + } else if (clipboard->mimeData(QClipboard::Clipboard)->hasText()) { + text = clipboard->mimeData(QClipboard::Clipboard)->text(); + } + if (!text.isEmpty() && QDir::isAbsolutePath(text)) { + m_dolphinView->setUrl(KUrl(text)); + } +} + +void DolphinViewController::requestToolTipHiding() +{ + emit hideToolTip(); +} + +void DolphinViewController::emitItemTriggered(const KFileItem& item) +{ + emit itemTriggered(item); +} + +KFileItem DolphinViewController::itemForIndex(const QModelIndex& index) const +{ + Q_ASSERT(m_itemView != 0); + + QAbstractProxyModel* proxyModel = static_cast(m_itemView->model()); + KDirModel* dirModel = static_cast(proxyModel->sourceModel()); + const QModelIndex dirIndex = proxyModel->mapToSource(index); + return dirModel->itemForIndex(dirIndex); +} + +void DolphinViewController::triggerItem(const QModelIndex& index) +{ + if (m_mouseButtons & Qt::LeftButton) { + const KFileItem item = itemForIndex(index); + if (index.isValid() && (index.column() == KDirModel::Name)) { + emit itemTriggered(item); + } else { + m_itemView->clearSelection(); + emit itemEntered(KFileItem()); + } + } +} + +void DolphinViewController::requestTab(const QModelIndex& index) +{ + if (m_mouseButtons & Qt::MidButton) { + const KFileItem item = itemForIndex(index); + const bool validRequest = index.isValid() && + (index.column() == KDirModel::Name) && + (item.isDir() || m_dolphinView->isTabsForFilesEnabled()); + if (validRequest) { + emit tabRequested(item.url()); + } + } +} + +void DolphinViewController::emitItemEntered(const QModelIndex& index) +{ + KFileItem item = itemForIndex(index); + if (!item.isNull()) { + emit itemEntered(item); + } +} + +void DolphinViewController::emitViewportEntered() +{ + emit viewportEntered(); +} + +void DolphinViewController::updateMouseButtonState() +{ + m_mouseButtons = QApplication::mouseButtons(); +} + +#include "dolphinviewcontroller.moc" diff --git a/src/views/dolphinviewcontroller.h b/src/views/dolphinviewcontroller.h new file mode 100644 index 000000000..6eed68e1a --- /dev/null +++ b/src/views/dolphinviewcontroller.h @@ -0,0 +1,314 @@ +/*************************************************************************** + * Copyright (C) 2010 by Peter Penz * + * * + * 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 DOLPHINVIEWCONTROLLER_H +#define DOLPHINVIEWCONTROLLER_H + +#include +#include +#include +#include + +class QAbstractItemView; +class DolphinView; +class KUrl; +class QPoint; + +/** + * @brief Allows the view mode implementations (DolphinIconsView, DolphinDetailsView, DolphinColumnView) + * to do a limited control of the DolphinView. + * + * The DolphinView connects to the signals of DolphinViewController to react on changes + * that have been triggered by the view mode implementations. The view mode implementations + * have read access to the whole DolphinView by DolphinViewController::view(). Limited control of the + * DolphinView by the view mode implementations are defined by the public DolphinController methods. + */ +class LIBDOLPHINPRIVATE_EXPORT DolphinViewController : public QObject +{ + Q_OBJECT + +public: + explicit DolphinViewController(DolphinView* dolphinView); + virtual ~DolphinViewController(); + + /** + * Allows read access for the view mode implementation + * to the DolphinView. + */ + const DolphinView* view() const; + + /** + * Requests the DolphinView to change the URL to \p url. The signal + * urlChangeRequested will be emitted. + */ + void requestUrlChange(const KUrl& url); + + /** + * Changes the current view mode implementation where the controller is working. + * This is only necessary for views like the tree view, where internally + * several QAbstractItemView instances are used. + */ + void setItemView(QAbstractItemView* view); + QAbstractItemView* itemView() const; + + /** + * Requests a context menu for the position \a pos. DolphinView + * takes care itself to get the selected items depending from + * \a pos. It is possible to define a custom list of actions for + * the context menu by \a customActions. + */ + void triggerContextMenuRequest(const QPoint& pos, + const QList& customActions = QList()); + + /** + * Requests an activation of the DolphinView and emits the signal + * activated(). This method should be invoked by the view mode implementation + * if e. g. a mouse click on the view has been done. + */ + void requestActivation(); + + /** + * Indicates that URLs are dropped above a destination. The DolphinView + * will start the corresponding action (copy, move, link). + * @param destItem Item of the destination (can be null, see KFileItem::isNull()). + * @param destPath Path of the destination. + * @param event Drop event + */ + void indicateDroppedUrls(const KFileItem& destItem, + const KUrl& destPath, + QDropEvent* event); + + /** + * Informs the DolphinView about a sorting change done inside + * the view mode implementation. + */ + void indicateSortingChange(DolphinView::Sorting sorting); + + /** + * Informs the DolphinView about a sort order change done inside + * the view mode implementation. + */ + void indicateSortOrderChange(Qt::SortOrder order); + + /** + * Informs the DolphinView about a change between separate sorting + * (with folders first) and mixed sorting of files and folders done inside + * the view mode implementation. + */ + void indicateSortFoldersFirstChange(bool foldersFirst); + + /** + * Informs the DolphinView about an additional information change + * done inside the view mode implementation. + */ + void indicateAdditionalInfoChange(const KFileItemDelegate::InformationList& info); + + /** + * Sets the available version control actions. Is called by the view + * mode implementation as soon as the DolphinView has requested them by the signal + * requestVersionControlActions(). + */ + void setVersionControlActions(QList actions); + + /** + * Emits the signal requestVersionControlActions(). The view mode implementation + * listens to the signal and will invoke a DolphinViewController::setVersionControlActions() + * and the result will be returned. + */ + QList versionControlActions(const KFileItemList& items); + + /** + * Must be be invoked in each view mode implementation whenever a key has been + * pressed. If the selection model of \a view is not empty and + * the return key has been pressed, the selected items will get triggered. + */ + void handleKeyPressEvent(QKeyEvent* event); + + /** + * Replaces the URL of the DolphinView with the content + * of the clipboard as URL. If the clipboard contains no text, + * nothing will be done. + */ + void replaceUrlByClipboard(); + + /** + * Requests the view mode implementation to hide tooltips. + */ + void requestToolTipHiding(); + + /** + * Emits the signal itemTriggered() for the item \a item. + * The method can be used by the view mode implementations to + * trigger an item directly without mouse interaction. + * If the item triggering is done by the mouse, it is recommended + * to use DolphinViewController::triggerItem(), as this will check + * the used mouse buttons to execute the correct action. + */ + void emitItemTriggered(const KFileItem& item); + + /** + * Returns the file item for the proxy index \a index of the DolphinView. + */ + KFileItem itemForIndex(const QModelIndex& index) const; + +public slots: + /** + * Emits the signal itemTriggered() if the file item for the index \a index + * is not null and the left mouse button has been pressed. If the item is + * null, the signal itemEntered() is emitted. + * The method should be invoked by the view mode implementations whenever the + * user has triggered an item with the mouse (see + * QAbstractItemView::clicked() or QAbstractItemView::doubleClicked()). + */ + void triggerItem(const QModelIndex& index); + + /** + * Emits the signal tabRequested(), if the file item for the index \a index + * represents a directory and when the middle mouse button has been pressed. + */ + void requestTab(const QModelIndex& index); + + /** + * Emits the signal itemEntered() if the file item for the index \a index + * is not null. The method should be invoked by the view mode implementation + * whenever the mouse cursor is above an item. + */ + void emitItemEntered(const QModelIndex& index); + + /** + * Emits the signal viewportEntered(). The method should be invoked by + * the view mode implementation whenever the mouse cursor is above the viewport. + */ + void emitViewportEntered(); + +signals: + void urlChangeRequested(const KUrl& url); + + /** + * Is emitted if a context menu should be opened (see triggerContextMenuRequest()). + * @param pos Position relative to the view widget where the + * context menu should be opened. It is recommended + * to get the corresponding model index from + * this position. + * @param customActions List of actions that is added to the context menu when + * the menu is opened above the viewport. + */ + void requestContextMenu(const QPoint& pos, QList customActions); + + /** + * Is emitted if the view has been activated by e. g. a mouse click. + */ + void activated(); + + /** + * Is emitted if URLs have been dropped to the destination + * path \a destPath. If the URLs have been dropped above an item of + * the destination path, the item is indicated by \a destItem + * (can be null, see KFileItem::isNull()). + */ + void urlsDropped(const KFileItem& destItem, + const KUrl& destPath, + QDropEvent* event); + + /** + * Is emitted if the sorting has been changed to \a sorting by + * the view mode implementation (see indicateSortingChanged(). + * The DolphinView connects to + * this signal to update its menu action. + */ + void sortingChanged(DolphinView::Sorting sorting); + + /** + * Is emitted if the sort order has been changed to \a order + * by the view mode implementation (see indicateSortOrderChanged(). + * The DolphinView connects + * to this signal to update its menu actions. + */ + void sortOrderChanged(Qt::SortOrder order); + + /** + * Is emitted if 'sort folders first' has been changed to \a foldersFirst + * by the view mode implementation (see indicateSortOrderChanged(). + * The DolphinView connects + * to this signal to update its menu actions. + */ + void sortFoldersFirstChanged(bool foldersFirst); + + /** + * Is emitted if the additional info has been changed to \a info + * by the view mode implementation. The DolphinView connects + * to this signal to update its menu actions. + */ + void additionalInfoChanged(const KFileItemDelegate::InformationList& info); + + /** + * Is emitted if the item \a item should be triggered. The abstract + * Dolphin view connects to this signal. If the item represents a directory, + * the directory is opened. On a file the corresponding application is opened. + * The item is null (see KFileItem::isNull()), when clicking on the viewport itself. + */ + void itemTriggered(const KFileItem& item); + + /** + * Is emitted if the mouse cursor has entered the item + * given by \a index (see emitItemEntered()). + */ + void itemEntered(const KFileItem& item); + + /** + * Is emitted if a new tab should be opened for the URL \a url. + */ + void tabRequested(const KUrl& url); + + /** + * Is emitted if the mouse cursor has entered + * the viewport (see emitViewportEntered()). + */ + void viewportEntered(); + + /** + * Is emitted, if DolphinViewController::requestToolTipHiding() is invoked + * and requests to hide all tooltips. + */ + void hideToolTip(); + + /** + * Is emitted if pending previews should be canceled (e. g. because of an URL change). + */ + void cancelPreviews(); + + /** + * Requests the view mode implementation to invoke DolphinViewController::setVersionControlActions(), + * so that they can be returned with DolphinViewController::versionControlActions() for + * the DolphinView. + */ + void requestVersionControlActions(const KFileItemList& items); + +private slots: + void updateMouseButtonState(); + +private: + static Qt::MouseButtons m_mouseButtons; // TODO: this is a workaround until Qt-issue 176832 has been fixed + + DolphinView* m_dolphinView; + QAbstractItemView* m_itemView; + QList m_versionControlActions; +}; + +#endif diff --git a/src/views/selectionmanager.cpp b/src/views/selectionmanager.cpp new file mode 100644 index 000000000..0d3efae09 --- /dev/null +++ b/src/views/selectionmanager.cpp @@ -0,0 +1,186 @@ +/*************************************************************************** + * Copyright (C) 2008 by Peter Penz * + * * + * 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 "selectionmanager.h" + +#include "dolphinmodel.h" +#include "selectiontoggle.h" +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +SelectionManager::SelectionManager(QAbstractItemView* parent) : + QObject(parent), + m_view(parent), + m_toggle(0), + m_connected(false) +{ + connect(parent, SIGNAL(entered(const QModelIndex&)), + this, SLOT(slotEntered(const QModelIndex&))); + connect(parent, SIGNAL(viewportEntered()), + this, SLOT(slotViewportEntered())); + m_toggle = new SelectionToggle(m_view->viewport()); + m_toggle->setCheckable(true); + m_toggle->hide(); + connect(m_toggle, SIGNAL(clicked(bool)), + this, SLOT(setItemSelected(bool))); +} + +SelectionManager::~SelectionManager() +{ +} + +void SelectionManager::reset() +{ + m_toggle->reset(); +} + +void SelectionManager::slotEntered(const QModelIndex& index) +{ + m_toggle->hide(); + const bool showToggle = index.isValid() && + (index.column() == DolphinModel::Name) && + (QApplication::mouseButtons() == Qt::NoButton); + if (showToggle) { + m_toggle->setUrl(urlForIndex(index)); + + if (!m_connected) { + connect(m_view->model(), SIGNAL(rowsRemoved(const QModelIndex&, int, int)), + this, SLOT(slotRowsRemoved(const QModelIndex&, int, int))); + connect(m_view->selectionModel(), + SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), + this, + SLOT(slotSelectionChanged(const QItemSelection&, const QItemSelection&))); + m_connected = true; + } + + // increase the size of the toggle for large items + const int height = m_view->iconSize().height(); + if (height >= KIconLoader::SizeEnormous) { + m_toggle->resize(KIconLoader::SizeMedium, KIconLoader::SizeMedium); + } else if (height >= KIconLoader::SizeLarge) { + m_toggle->resize(KIconLoader::SizeSmallMedium, KIconLoader::SizeSmallMedium); + } else { + m_toggle->resize(KIconLoader::SizeSmall, KIconLoader::SizeSmall); + } + + const QRect rect = m_view->visualRect(index); + int x = rect.left(); + int y = rect.top(); + if (height < KIconLoader::SizeSmallMedium) { + // The height is nearly equal to the smallest toggle height. + // Assure that the toggle is vertically centered instead + // of aligned on the top and gets more horizontal gap. + x += 2; + y += (rect.height() - m_toggle->height()) / 2; + } + m_toggle->move(QPoint(x, y)); + + QItemSelectionModel* selModel = m_view->selectionModel(); + m_toggle->setChecked(selModel->isSelected(index)); + m_toggle->show(); + } else { + m_toggle->setUrl(KUrl()); + disconnect(m_view->model(), SIGNAL(rowsRemoved(const QModelIndex&, int, int)), + this, SLOT(slotRowsRemoved(const QModelIndex&, int, int))); + disconnect(m_view->selectionModel(), + SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), + this, + SLOT(slotSelectionChanged(const QItemSelection&, const QItemSelection&))); + m_connected = false; + } +} + +void SelectionManager::slotViewportEntered() +{ + m_toggle->hide(); +} + +void SelectionManager::setItemSelected(bool selected) +{ + emit selectionChanged(); + + if (!m_toggle->url().isEmpty()) { + const QModelIndex index = indexForUrl(m_toggle->url()); + if (index.isValid()) { + QItemSelectionModel* selModel = m_view->selectionModel(); + if (selected) { + selModel->select(index, QItemSelectionModel::Select); + } else { + selModel->select(index, QItemSelectionModel::Deselect); + } + selModel->setCurrentIndex(index, QItemSelectionModel::Current); + } + } +} + +void SelectionManager::slotRowsRemoved(const QModelIndex& parent, int start, int end) +{ + Q_UNUSED(parent); + Q_UNUSED(start); + Q_UNUSED(end); + m_toggle->hide(); +} + +void SelectionManager::slotSelectionChanged(const QItemSelection& selected, + const QItemSelection& deselected) +{ + // The selection has been changed outside the scope of the selection manager + // (e. g. by the rubberband or the "Select All" action). Take care updating + // the state of the toggle button. + if (!m_toggle->url().isEmpty()) { + const QModelIndex index = indexForUrl(m_toggle->url()); + if (index.isValid()) { + if (selected.contains(index)) { + m_toggle->setChecked(true); + } + + if (deselected.contains(index)) { + m_toggle->setChecked(false); + } + } + } +} + +KUrl SelectionManager::urlForIndex(const QModelIndex& index) const +{ + QAbstractProxyModel* proxyModel = static_cast(m_view->model()); + KDirModel* dirModel = static_cast(proxyModel->sourceModel()); + const QModelIndex dirIndex = proxyModel->mapToSource(index); + return dirModel->itemForIndex(dirIndex).url(); +} + +const QModelIndex SelectionManager::indexForUrl(const KUrl& url) const +{ + QAbstractProxyModel* proxyModel = static_cast(m_view->model()); + KDirModel* dirModel = static_cast(proxyModel->sourceModel()); + const QModelIndex dirIndex = dirModel->indexForUrl(url); + return proxyModel->mapFromSource(dirIndex); +} + +#include "selectionmanager.moc" diff --git a/src/views/selectionmanager.h b/src/views/selectionmanager.h new file mode 100644 index 000000000..c2fcc88b4 --- /dev/null +++ b/src/views/selectionmanager.h @@ -0,0 +1,74 @@ +/*************************************************************************** + * Copyright (C) 2008 by Peter Penz * + * * + * 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 SELECTIONMANAGER_H +#define SELECTIONMANAGER_H + +#include + +#include + +class QAbstractItemView; +class QModelIndex; +class QItemSelection; +class SelectionToggle; + +/** + * @brief Allows to select and deselect items for item views. + * + * Whenever an item is hovered by the mouse, a toggle button is shown + * which allows to select/deselect the current item. + */ +class SelectionManager : public QObject +{ + Q_OBJECT + +public: + SelectionManager(QAbstractItemView* parent); + virtual ~SelectionManager(); + +public slots: + /** + * Resets the selection manager so that the toggle button gets + * invisible. + */ + void reset(); + +signals: + /** Is emitted if the selection has been changed by the toggle button. */ + void selectionChanged(); + +private slots: + void slotEntered(const QModelIndex& index); + void slotViewportEntered(); + void setItemSelected(bool selected); + void slotRowsRemoved(const QModelIndex& parent, int start, int end); + void slotSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected); + +private: + KUrl urlForIndex(const QModelIndex& index) const; + const QModelIndex indexForUrl(const KUrl& url) const; + +private: + QAbstractItemView* m_view; + SelectionToggle* m_toggle; + bool m_connected; +}; + +#endif diff --git a/src/views/selectiontoggle.cpp b/src/views/selectiontoggle.cpp new file mode 100644 index 000000000..6608b5821 --- /dev/null +++ b/src/views/selectiontoggle.cpp @@ -0,0 +1,233 @@ +/*************************************************************************** + * Copyright (C) 2008 by Peter Penz * + * * + * 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 "selectiontoggle.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +SelectionToggle::SelectionToggle(QWidget* parent) : + QAbstractButton(parent), + m_isHovered(false), + m_leftMouseButtonPressed(false), + m_fadingValue(0), + m_icon(), + m_fadingTimeLine(0) +{ + setFocusPolicy(Qt::NoFocus); + parent->installEventFilter(this); + resize(sizeHint()); + setIconOverlay(isChecked()); + connect(this, SIGNAL(toggled(bool)), + this, SLOT(setIconOverlay(bool))); + connect(KGlobalSettings::self(), SIGNAL(iconChanged(int)), + this, SLOT(refreshIcon())); +} + +SelectionToggle::~SelectionToggle() +{ +} + +QSize SelectionToggle::sizeHint() const +{ + return QSize(16, 16); +} + +void SelectionToggle::reset() +{ + m_url = KUrl(); + hide(); +} + +void SelectionToggle::setUrl(const KUrl& url) +{ + m_url = url; + if (!url.isEmpty()) { + startFading(); + } +} + +KUrl SelectionToggle::url() const +{ + return m_url; +} + +void SelectionToggle::setVisible(bool visible) +{ + QAbstractButton::setVisible(visible); + + stopFading(); + if (visible) { + startFading(); + } + +} + +bool SelectionToggle::eventFilter(QObject* obj, QEvent* event) +{ + if (obj == parent()) { + switch (event->type()) { + case QEvent::Leave: + hide(); + break; + + case QEvent::MouseMove: + if (m_leftMouseButtonPressed) { + // Don't forward mouse move events to the viewport, + // otherwise a rubberband selection will be shown when + // clicking on the selection toggle and moving the mouse + // above the viewport. + return true; + } + break; + + default: + break; + } + } + + return QAbstractButton::eventFilter(obj, event); +} + +void SelectionToggle::enterEvent(QEvent* event) +{ + QAbstractButton::enterEvent(event); + + // if the mouse cursor is above the selection toggle, display + // it immediately without fading timer + m_isHovered = true; + if (m_fadingTimeLine != 0) { + m_fadingTimeLine->stop(); + } + m_fadingValue = 255; + setToolTip(isChecked() ? i18nc("@info:tooltip", "Deselect Item") : + i18nc("@info:tooltip", "Select Item")); + update(); +} + +void SelectionToggle::leaveEvent(QEvent* event) +{ + QAbstractButton::leaveEvent(event); + m_isHovered = false; + update(); +} + +void SelectionToggle::mousePressEvent(QMouseEvent* event) +{ + QAbstractButton::mousePressEvent(event); + m_leftMouseButtonPressed = (event->buttons() & Qt::LeftButton); +} + +void SelectionToggle::mouseReleaseEvent(QMouseEvent* event) +{ + QAbstractButton::mouseReleaseEvent(event); + m_leftMouseButtonPressed = (event->buttons() & Qt::LeftButton); +} + +void SelectionToggle::resizeEvent(QResizeEvent* event) +{ + QAbstractButton::resizeEvent(event); + setIconOverlay(isChecked()); +} + +void SelectionToggle::paintEvent(QPaintEvent* event) +{ + QPainter painter(this); + painter.setClipRect(event->rect()); + + // draw the icon overlay + if (m_isHovered) { + KIconEffect iconEffect; + QPixmap activeIcon = iconEffect.apply(m_icon, KIconLoader::Desktop, KIconLoader::ActiveState); + painter.drawPixmap(0, 0, activeIcon); + } else { + if (m_fadingValue < 255) { + // apply an alpha mask respecting the fading value to the icon + QPixmap icon = m_icon; + QPixmap alphaMask(icon.width(), icon.height()); + const QColor color(m_fadingValue, m_fadingValue, m_fadingValue); + alphaMask.fill(color); + icon.setAlphaChannel(alphaMask); + painter.drawPixmap(0, 0, icon); + } else { + // no fading is required + painter.drawPixmap(0, 0, m_icon); + } + } +} + +void SelectionToggle::setFadingValue(int value) +{ + m_fadingValue = value; + if (m_fadingValue >= 255) { + Q_ASSERT(m_fadingTimeLine != 0); + m_fadingTimeLine->stop(); + } + update(); +} + +void SelectionToggle::setIconOverlay(bool checked) +{ + const char* icon = checked ? "list-remove" : "list-add"; + m_icon = KIconLoader::global()->loadIcon(icon, + KIconLoader::NoGroup, + qMin(width(), height())); + update(); +} + +void SelectionToggle::refreshIcon() +{ + setIconOverlay(isChecked()); +} + +void SelectionToggle::startFading() +{ + Q_ASSERT(m_fadingTimeLine == 0); + + const bool animate = KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects; + const int duration = animate ? 600 : 1; + + m_fadingTimeLine = new QTimeLine(duration, this); + connect(m_fadingTimeLine, SIGNAL(frameChanged(int)), + this, SLOT(setFadingValue(int))); + m_fadingTimeLine->setFrameRange(0, 255); + m_fadingTimeLine->start(); + m_fadingValue = 0; +} + +void SelectionToggle::stopFading() +{ + if (m_fadingTimeLine != 0) { + m_fadingTimeLine->stop(); + delete m_fadingTimeLine; + m_fadingTimeLine = 0; + } + m_fadingValue = 0; +} + +#include "selectiontoggle.moc" diff --git a/src/views/selectiontoggle.h b/src/views/selectiontoggle.h new file mode 100644 index 000000000..5519272b3 --- /dev/null +++ b/src/views/selectiontoggle.h @@ -0,0 +1,91 @@ +/*************************************************************************** + * Copyright (C) 2008 by Peter Penz * + * * + * 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 SELECTIONTOGGLE_H +#define SELECTIONTOGGLE_H + +#include + +#include +#include + +class QTimeLine; + +/** + * @brief Toggle button for changing the selection of an hovered item. + * + * The toggle button is visually invisible until it is displayed at least + * for one second. + * + * @see SelectionManager + */ +class SelectionToggle : public QAbstractButton +{ + Q_OBJECT + +public: + explicit SelectionToggle(QWidget* parent); + virtual ~SelectionToggle(); + virtual QSize sizeHint() const; + + /** + * Resets the selection toggle so that it is hidden and stays + * visually invisible for at least one second after it is shown again. + */ + void reset(); + + void setUrl(const KUrl& url); + KUrl url() const; + +public slots: + virtual void setVisible(bool visible); + +protected: + virtual bool eventFilter(QObject* obj, QEvent* event); + virtual void enterEvent(QEvent* event); + virtual void leaveEvent(QEvent* event); + virtual void mousePressEvent(QMouseEvent* event); + virtual void mouseReleaseEvent(QMouseEvent* event); + virtual void resizeEvent(QResizeEvent* event); + virtual void paintEvent(QPaintEvent* event); + +private slots: + /** + * Sets the alpha value for the fading animation and is + * connected with m_fadingTimeLine. + */ + void setFadingValue(int value); + + void setIconOverlay(bool checked); + void refreshIcon(); + +private: + void startFading(); + void stopFading(); + +private: + bool m_isHovered; + bool m_leftMouseButtonPressed; + int m_fadingValue; + QPixmap m_icon; + QTimeLine* m_fadingTimeLine; + KUrl m_url; +}; + +#endif diff --git a/src/views/viewextensionsfactory.cpp b/src/views/viewextensionsfactory.cpp new file mode 100644 index 000000000..e5638c03e --- /dev/null +++ b/src/views/viewextensionsfactory.cpp @@ -0,0 +1,244 @@ +/*************************************************************************** + * Copyright (C) 2009 by Peter Penz * + * * + * 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 "viewextensionsfactory.h" + +#include "dolphinfileitemdelegate.h" +#include "dolphinsortfilterproxymodel.h" +#include "dolphinview.h" +#include "dolphinviewcontroller.h" +#include "dolphinviewautoscroller.h" +#include "folderexpander.h" +#include "selectionmanager.h" +#include "settings/dolphinsettings.h" +#include "tooltips/tooltipmanager.h" +#include "versioncontrol/versioncontrolobserver.h" +#include "viewmodecontroller.h" + +#include "dolphin_generalsettings.h" + +#include +#include +#include +#include + +ViewExtensionsFactory::ViewExtensionsFactory(QAbstractItemView* view, + DolphinViewController* dolphinViewController, + const ViewModeController* viewModeController) : + QObject(view), + m_view(view), + m_dolphinViewController(dolphinViewController), + m_toolTipManager(0), + m_previewGenerator(0), + m_selectionManager(0), + m_autoScroller(0), + m_fileItemDelegate(0), + m_versionControlObserver(0) +{ + view->setSelectionMode(QAbstractItemView::ExtendedSelection); + + GeneralSettings* settings = DolphinSettings::instance().generalSettings(); + + // initialize tooltips + if (settings->showToolTips()) { + DolphinSortFilterProxyModel* proxyModel = static_cast(view->model()); + m_toolTipManager = new ToolTipManager(view, proxyModel); + + connect(dolphinViewController, SIGNAL(hideToolTip()), + m_toolTipManager, SLOT(hideTip())); + } + + // initialize preview generator + Q_ASSERT(view->iconSize().isValid()); + m_previewGenerator = new KFilePreviewGenerator(view); + m_previewGenerator->setPreviewShown(dolphinViewController->view()->showPreview()); + connect(viewModeController, SIGNAL(zoomLevelChanged(int)), + this, SLOT(slotZoomLevelChanged())); + connect(viewModeController, SIGNAL(cancelPreviews()), + this, SLOT(cancelPreviews())); + connect(dolphinViewController->view(), SIGNAL(showPreviewChanged()), + this, SLOT(slotShowPreviewChanged())); + + // initialize selection manager + if (settings->showSelectionToggle()) { + m_selectionManager = new SelectionManager(view); + connect(m_selectionManager, SIGNAL(selectionChanged()), + this, SLOT(requestActivation())); + connect(viewModeController, SIGNAL(urlChanged(const KUrl&)), + m_selectionManager, SLOT(reset())); + } + + // initialize auto scroller + m_autoScroller = new DolphinViewAutoScroller(view); + + // initialize file item delegate + m_fileItemDelegate = new DolphinFileItemDelegate(view); + m_fileItemDelegate->setShowToolTipWhenElided(false); + view->setItemDelegate(m_fileItemDelegate); + + // initialize version control observer + const DolphinView* dolphinView = dolphinViewController->view(); + m_versionControlObserver = new VersionControlObserver(view); + connect(m_versionControlObserver, SIGNAL(infoMessage(const QString&)), + dolphinView, SIGNAL(infoMessage(const QString&))); + connect(m_versionControlObserver, SIGNAL(errorMessage(const QString&)), + dolphinView, SIGNAL(errorMessage(const QString&))); + connect(m_versionControlObserver, SIGNAL(operationCompletedMessage(const QString&)), + dolphinView, SIGNAL(operationCompletedMessage(const QString&))); + connect(dolphinViewController, SIGNAL(requestVersionControlActions(const KFileItemList&)), + this, SLOT(slotRequestVersionControlActions(const KFileItemList&))); + + // react on view property changes + connect(dolphinView, SIGNAL(showHiddenFilesChanged()), + this, SLOT(slotShowHiddenFilesChanged())); + connect(dolphinView, SIGNAL(sortingChanged(DolphinView::Sorting)), + this, SLOT(slotSortingChanged(DolphinView::Sorting))); + connect(dolphinView, SIGNAL(sortOrderChanged(Qt::SortOrder)), + this, SLOT(slotSortOrderChanged(Qt::SortOrder))); + connect(dolphinView, SIGNAL(sortFoldersFirstChanged(bool)), + this, SLOT(slotSortFoldersFirstChanged(bool))); + + // Give the view the ability to auto-expand its directories on hovering + // (the column view takes care about this itself). If the details view + // uses expandable folders, the auto-expanding should be used always. + m_folderExpander = new FolderExpander(view, proxyModel()); + m_folderExpander->setEnabled(settings->autoExpandFolders()); + connect(m_folderExpander, SIGNAL(enterDir(const QModelIndex&)), + dolphinViewController, SLOT(triggerItem(const QModelIndex&))); + + // react on namefilter changes + connect(viewModeController, SIGNAL(nameFilterChanged(const QString&)), + this, SLOT(slotNameFilterChanged(const QString&))); + + view->viewport()->installEventFilter(this); +} + +ViewExtensionsFactory::~ViewExtensionsFactory() +{ +} + +void ViewExtensionsFactory::handleCurrentIndexChange(const QModelIndex& current, const QModelIndex& previous) +{ + m_autoScroller->handleCurrentIndexChange(current, previous); +} + +DolphinFileItemDelegate* ViewExtensionsFactory::fileItemDelegate() const +{ + return m_fileItemDelegate; +} + +void ViewExtensionsFactory::setAutoFolderExpandingEnabled(bool enabled) +{ + m_folderExpander->setEnabled(enabled); +} + +bool ViewExtensionsFactory::autoFolderExpandingEnabled() const +{ + return m_folderExpander->enabled(); +} + +bool ViewExtensionsFactory::eventFilter(QObject* watched, QEvent* event) +{ + Q_UNUSED(watched); + if ((event->type() == QEvent::Wheel) && (m_selectionManager != 0)) { + m_selectionManager->reset(); + } + return false; +} + +void ViewExtensionsFactory::slotZoomLevelChanged() +{ + m_previewGenerator->updateIcons(); + if (m_selectionManager != 0) { + m_selectionManager->reset(); + } +} + +void ViewExtensionsFactory::cancelPreviews() +{ + m_previewGenerator->cancelPreviews(); +} + +void ViewExtensionsFactory::slotShowPreviewChanged() +{ + const bool show = m_dolphinViewController->view()->showPreview(); + m_previewGenerator->setPreviewShown(show); +} + +void ViewExtensionsFactory::slotShowHiddenFilesChanged() +{ + KDirModel* dirModel = static_cast(proxyModel()->sourceModel()); + KDirLister* dirLister = dirModel->dirLister(); + + dirLister->stop(); + + const bool show = m_dolphinViewController->view()->showHiddenFiles(); + dirLister->setShowingDotFiles(show); + + const KUrl url = dirLister->url(); + if (url.isValid()) { + dirLister->openUrl(url, KDirLister::NoFlags); + } +} + +void ViewExtensionsFactory::slotSortingChanged(DolphinView::Sorting sorting) +{ + proxyModel()->setSorting(sorting); +} + +void ViewExtensionsFactory::slotSortOrderChanged(Qt::SortOrder order) +{ + proxyModel()->setSortOrder(order); +} + +void ViewExtensionsFactory::slotSortFoldersFirstChanged(bool foldersFirst) +{ + proxyModel()->setSortFoldersFirst(foldersFirst); +} + +void ViewExtensionsFactory::slotNameFilterChanged(const QString& nameFilter) +{ + proxyModel()->setFilterFixedString(nameFilter); +} + +void ViewExtensionsFactory::slotRequestVersionControlActions(const KFileItemList& items) +{ + QList actions; + if (items.isEmpty()) { + const KDirModel* dirModel = static_cast(proxyModel()->sourceModel()); + const KUrl url = dirModel->dirLister()->url(); + actions = m_versionControlObserver->contextMenuActions(url.path(KUrl::AddTrailingSlash)); + } else { + actions = m_versionControlObserver->contextMenuActions(items); + } + m_dolphinViewController->setVersionControlActions(actions); +} + +void ViewExtensionsFactory::requestActivation() +{ + m_dolphinViewController->requestActivation(); +} + +DolphinSortFilterProxyModel* ViewExtensionsFactory::proxyModel() const +{ + return static_cast(m_view->model()); +} + +#include "viewextensionsfactory.moc" + diff --git a/src/views/viewextensionsfactory.h b/src/views/viewextensionsfactory.h new file mode 100644 index 000000000..9324932ac --- /dev/null +++ b/src/views/viewextensionsfactory.h @@ -0,0 +1,105 @@ +/*************************************************************************** + * Copyright (C) 2009 by Peter Penz * + * * + * 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 VIEWEXTENSIONSFACTORY_H +#define VIEWEXTENSIONSFACTORY_H + +#include + +#include "dolphinview.h" + +class DolphinFileItemDelegate; +class DolphinSortFilterProxyModel; +class DolphinViewAutoScroller; +class KFilePreviewGenerator; +class FolderExpander; +class QModelIndex; +class SelectionManager; +class ToolTipManager; +class QAbstractItemView; +class VersionControlObserver; +class ViewModeController; + +/** + * @brief Responsible for creating extensions like tooltips and previews + * that are available in all view implementations. + * + * Each view implementation (iconsview, detailsview, columnview) must + * instantiate an instance of this class to assure having + * a common behavior that is independent from the custom functionality of + * a view implementation. + */ +class ViewExtensionsFactory : public QObject +{ + Q_OBJECT + +public: + explicit ViewExtensionsFactory(QAbstractItemView* view, + DolphinViewController* dolphinViewController, + const ViewModeController* viewModeController); + virtual ~ViewExtensionsFactory(); + + /** + * Must be invoked by the item view, when QAbstractItemView::currentChanged() + * has been called. Assures that the current item stays visible when it has been + * changed by the keyboard. + */ + void handleCurrentIndexChange(const QModelIndex& current, const QModelIndex& previous); + + DolphinFileItemDelegate* fileItemDelegate() const; + + /** + * Enables the automatically expanding of a folder when dragging + * items above the folder. + */ + void setAutoFolderExpandingEnabled(bool enabled); + bool autoFolderExpandingEnabled() const; + +protected: + virtual bool eventFilter(QObject* watched, QEvent* event); + +private slots: + void slotZoomLevelChanged(); + void cancelPreviews(); + void slotShowPreviewChanged(); + void slotShowHiddenFilesChanged(); + void slotSortingChanged(DolphinView::Sorting sorting); + void slotSortOrderChanged(Qt::SortOrder order); + void slotSortFoldersFirstChanged(bool foldersFirst); + void slotNameFilterChanged(const QString& nameFilter); + void slotRequestVersionControlActions(const KFileItemList& items); + void requestActivation(); + +private: + DolphinSortFilterProxyModel* proxyModel() const; + +private: + QAbstractItemView* m_view; + DolphinViewController* m_dolphinViewController; + ToolTipManager* m_toolTipManager; + KFilePreviewGenerator* m_previewGenerator; + SelectionManager* m_selectionManager; + DolphinViewAutoScroller* m_autoScroller; + DolphinFileItemDelegate* m_fileItemDelegate; + VersionControlObserver* m_versionControlObserver; + FolderExpander* m_folderExpander; +}; + +#endif + diff --git a/src/views/viewmodecontroller.cpp b/src/views/viewmodecontroller.cpp new file mode 100644 index 000000000..17d0ba61f --- /dev/null +++ b/src/views/viewmodecontroller.cpp @@ -0,0 +1,88 @@ +/*************************************************************************** + * Copyright (C) 2010 by Peter Penz * + * * + * 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 "viewmodecontroller.h" + +#include "zoomlevelinfo.h" + +ViewModeController::ViewModeController(QObject* parent) : + QObject(parent), + m_zoomLevel(0), + m_nameFilter(), + m_url() +{ +} + +ViewModeController::~ViewModeController() +{ +} + +KUrl ViewModeController::url() const +{ + return m_url; +} + +void ViewModeController::redirectToUrl(const KUrl& url) +{ + m_url = url; +} + +void ViewModeController::indicateActivationChange(bool active) +{ + emit activationChanged(active); +} + +void ViewModeController::setNameFilter(const QString& nameFilter) +{ + if (nameFilter != m_nameFilter) { + m_nameFilter = nameFilter; + emit nameFilterChanged(nameFilter); + } +} + +QString ViewModeController::nameFilter() const +{ + return m_nameFilter; +} + +void ViewModeController::setZoomLevel(int level) +{ + Q_ASSERT(level >= ZoomLevelInfo::minimumLevel()); + Q_ASSERT(level <= ZoomLevelInfo::maximumLevel()); + if (level != m_zoomLevel) { + m_zoomLevel = level; + emit zoomLevelChanged(m_zoomLevel); + } +} + +int ViewModeController::zoomLevel() const +{ + return m_zoomLevel; +} + +void ViewModeController::setUrl(const KUrl& url) +{ + if (m_url != url) { + m_url = url; + emit cancelPreviews(); + emit urlChanged(url); + } +} + +#include "viewmodecontroller.moc" diff --git a/src/views/viewmodecontroller.h b/src/views/viewmodecontroller.h new file mode 100644 index 000000000..c7378d59a --- /dev/null +++ b/src/views/viewmodecontroller.h @@ -0,0 +1,124 @@ +/*************************************************************************** + * Copyright (C) 2010 by Peter Penz * + * * + * 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 VIEWMODECONTROLLER_H +#define VIEWMODECONTROLLER_H + +#include +#include +#include +#include + +/** + * @brief Allows the DolphinView to control the view implementations for the + * different view modes. + * + * The view implementations (DolphinIconsView, DolphinDetailsView, DolphinColumnView) + * connect to signals of the ViewModeController to react on changes. The view + * implementations get only read-access to the ViewModeController. + */ +class LIBDOLPHINPRIVATE_EXPORT ViewModeController : public QObject +{ + Q_OBJECT + +public: + explicit ViewModeController(QObject* parent = 0); + virtual ~ViewModeController(); + + /** + * @return URL that is shown by the view mode implementation. + */ + KUrl url() const; + + /** + * Sets the URL to \a url and does nothing else. Called when + * a redirection happens. See ViewModeController::setUrl() + */ + void redirectToUrl(const KUrl& url); + + /** + * Informs the view mode implementation about a change of the activation + * state by emitting the signal activationChanged(). + */ + void indicateActivationChange(bool active); + + /** + * Sets the zoom level to \a level and emits the signal zoomLevelChanged(). + * It must be assured that the used level is inside the range + * ViewModeController::zoomLevelMinimum() and + * ViewModeController::zoomLevelMaximum(). + */ + void setZoomLevel(int level); + int zoomLevel() const; + + /** + * Sets the name filter to \a and emits the signal nameFilterChanged(). + */ + void setNameFilter(const QString& nameFilter); + QString nameFilter() const; + + /** + * Requests the view mode implementation to hide tooltips. + */ + void requestToolTipHiding(); + +public slots: + /** + * Sets the URL to \a url and emits the signals cancelPreviews() and + * urlChanged() if \a url is different for the current URL. + */ + void setUrl(const KUrl& url); + +signals: + /** + * Is emitted if the URL has been changed by ViewModeController::setUrl(). + */ + void urlChanged(const KUrl& url); + + /** + * Is emitted, if ViewModeController::indicateActivationChange() has been + * invoked. The view mode implementation may update its visual state + * to represent the activation state. + */ + void activationChanged(bool active); + + /** + * Is emitted if the name filter has been changed by + * ViewModeController::setNameFilter(). + */ + void nameFilterChanged(const QString& nameFilter); + + /** + * Is emitted if the zoom level has been changed by + * ViewModeController::setZoomLevel(). + */ + void zoomLevelChanged(int level); + + /** + * Is emitted if pending previews should be canceled (e. g. because of an URL change). + */ + void cancelPreviews(); + +private: + int m_zoomLevel; + QString m_nameFilter; + KUrl m_url; +}; + +#endif diff --git a/src/views/zoomlevelinfo.cpp b/src/views/zoomlevelinfo.cpp new file mode 100644 index 000000000..08e95e3ca --- /dev/null +++ b/src/views/zoomlevelinfo.cpp @@ -0,0 +1,60 @@ +/*************************************************************************** + * Copyright (C) 2008 by Peter Penz * + * * + * 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 "zoomlevelinfo.h" +#include +#include + +int ZoomLevelInfo::minimumLevel() +{ + return 0; +} + +int ZoomLevelInfo::maximumLevel() +{ + return 16; +} + +int ZoomLevelInfo::iconSizeForZoomLevel(int level) +{ + int size = KIconLoader::SizeMedium; + switch (level) { + case 0: size = KIconLoader::SizeSmall; break; + case 1: size = KIconLoader::SizeSmallMedium; break; + case 2: size = KIconLoader::SizeMedium; break; + case 3: size = KIconLoader::SizeLarge; break; + case 4: size = KIconLoader::SizeHuge; break; + default: size = KIconLoader::SizeHuge + ((level - 4) << 4); + } + return size; +} + +int ZoomLevelInfo::zoomLevelForIconSize(const QSize& size) +{ + int level = 0; + switch (size.height()) { + case KIconLoader::SizeSmall: level = 0; break; + case KIconLoader::SizeSmallMedium: level = 1; break; + case KIconLoader::SizeMedium: level = 2; break; + case KIconLoader::SizeLarge: level = 3; break; + case KIconLoader::SizeHuge: level = 4; break; + default: level = 4 + ((size.height() - KIconLoader::SizeHuge) >> 4); + } + return level; +} diff --git a/src/views/zoomlevelinfo.h b/src/views/zoomlevelinfo.h new file mode 100644 index 000000000..a6e92e653 --- /dev/null +++ b/src/views/zoomlevelinfo.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright (C) 2008 by Peter Penz * + * * + * 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 ZOOMLEVELINFO_H +#define ZOOMLEVELINFO_H + +class QSize; + +/** + * @short Helper class for getting information about the zooming + * capabilities. + */ +class ZoomLevelInfo { +public: + static int minimumLevel(); + static int maximumLevel(); + + /** + * Helper method for the view implementation to get + * the icon size for the zoom level \a level that + * is between the range ZoomLevelInfo::minimumLevel() and + * ZoomLevelInfo::maximumLevel(). + */ + static int iconSizeForZoomLevel(int level); + + /** + * Helper method for the view implementation to get + * the zoom level for the icon size \a size that + * is between the range ZoomLevelInfo::minimumLevel() and + * ZoomLevelInfo::maximumLevel(). + */ + static int zoomLevelForIconSize(const QSize& size); +}; + +#endif diff --git a/src/zoomlevelinfo.cpp b/src/zoomlevelinfo.cpp deleted file mode 100644 index 08e95e3ca..000000000 --- a/src/zoomlevelinfo.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Peter Penz * - * * - * 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 "zoomlevelinfo.h" -#include -#include - -int ZoomLevelInfo::minimumLevel() -{ - return 0; -} - -int ZoomLevelInfo::maximumLevel() -{ - return 16; -} - -int ZoomLevelInfo::iconSizeForZoomLevel(int level) -{ - int size = KIconLoader::SizeMedium; - switch (level) { - case 0: size = KIconLoader::SizeSmall; break; - case 1: size = KIconLoader::SizeSmallMedium; break; - case 2: size = KIconLoader::SizeMedium; break; - case 3: size = KIconLoader::SizeLarge; break; - case 4: size = KIconLoader::SizeHuge; break; - default: size = KIconLoader::SizeHuge + ((level - 4) << 4); - } - return size; -} - -int ZoomLevelInfo::zoomLevelForIconSize(const QSize& size) -{ - int level = 0; - switch (size.height()) { - case KIconLoader::SizeSmall: level = 0; break; - case KIconLoader::SizeSmallMedium: level = 1; break; - case KIconLoader::SizeMedium: level = 2; break; - case KIconLoader::SizeLarge: level = 3; break; - case KIconLoader::SizeHuge: level = 4; break; - default: level = 4 + ((size.height() - KIconLoader::SizeHuge) >> 4); - } - return level; -} diff --git a/src/zoomlevelinfo.h b/src/zoomlevelinfo.h deleted file mode 100644 index a6e92e653..000000000 --- a/src/zoomlevelinfo.h +++ /dev/null @@ -1,51 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Peter Penz * - * * - * 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 ZOOMLEVELINFO_H -#define ZOOMLEVELINFO_H - -class QSize; - -/** - * @short Helper class for getting information about the zooming - * capabilities. - */ -class ZoomLevelInfo { -public: - static int minimumLevel(); - static int maximumLevel(); - - /** - * Helper method for the view implementation to get - * the icon size for the zoom level \a level that - * is between the range ZoomLevelInfo::minimumLevel() and - * ZoomLevelInfo::maximumLevel(). - */ - static int iconSizeForZoomLevel(int level); - - /** - * Helper method for the view implementation to get - * the zoom level for the icon size \a size that - * is between the range ZoomLevelInfo::minimumLevel() and - * ZoomLevelInfo::maximumLevel(). - */ - static int zoomLevelForIconSize(const QSize& size); -}; - -#endif -- cgit v1.3