]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/dolphiniconsview.cpp
Also allow to use the selection toggle when double click is used. This allows to...
[dolphin.git] / src / dolphiniconsview.cpp
index 553cdcfe62e8a84630aaa945a222f0f76dc1282b..059ce89ab1c6b2907386ca75de64bbdf28131ea2 100644 (file)
 #include "dolphincontroller.h"
 #include "dolphinsettings.h"
 #include "dolphin_iconsmodesettings.h"
+#include "dolphin_generalsettings.h"
 #include "draganddrophelper.h"
+#include "selectionmanager.h"
 
 #include <kcategorizedsortfilterproxymodel.h>
 #include <kdialog.h>
 #include <kdirmodel.h>
+#include <kfileitemdelegate.h>
 
 #include <QAbstractProxyModel>
 #include <QApplication>
-#include <QPainter>
-#include <QPoint>
+#include <QScrollBar>
 
 DolphinIconsView::DolphinIconsView(QWidget* parent, DolphinController* controller) :
     KCategorizedView(parent),
+    m_enableScrollTo(false),
     m_controller(controller),
+    m_selectionManager(0),
     m_categoryDrawer(0),
     m_font(),
     m_decorationSize(),
     m_decorationPosition(QStyleOptionViewItem::Top),
     m_displayAlignment(Qt::AlignHCenter),
     m_itemSize(),
-    m_dragging(false),
     m_dropRect()
 {
     Q_ASSERT(controller != 0);
@@ -52,10 +55,10 @@ DolphinIconsView::DolphinIconsView(QWidget* parent, DolphinController* controlle
     setSpacing(KDialog::spacingHint());
     setMovement(QListView::Static);
     setDragEnabled(true);
+    setEditTriggers(QAbstractItemView::NoEditTriggers);
     viewport()->setAcceptDrops(true);
 
     setMouseTracking(true);
-    viewport()->setAttribute(Qt::WA_Hover);
 
     // TODO: Connecting to the signal 'activated()' is not possible, as kstyle
     // does not forward the single vs. doubleclick to it yet (KDE 4.1?). Hence it is
@@ -63,11 +66,22 @@ DolphinIconsView::DolphinIconsView(QWidget* parent, DolphinController* controlle
     // RETURN-key in keyPressEvent().
     if (KGlobalSettings::singleClick()) {
         connect(this, SIGNAL(clicked(const QModelIndex&)),
-                this, SLOT(triggerItem(const QModelIndex&)));
+                controller, SLOT(triggerItem(const QModelIndex&)));
     } else {
         connect(this, SIGNAL(doubleClicked(const QModelIndex&)),
-                this, SLOT(triggerItem(const QModelIndex&)));
+                controller, SLOT(triggerItem(const QModelIndex&)));
     }
+
+    if (DolphinSettings::instance().generalSettings()->showSelectionToggle()) {
+        m_selectionManager = new SelectionManager(this);
+        connect(m_selectionManager, SIGNAL(selectionChanged()),
+                this, SLOT(requestActivation()));
+        connect(m_controller, SIGNAL(urlChanged(const KUrl&)),
+                m_selectionManager, SLOT(reset()));
+    }
+
+    connect(this, SIGNAL(entered(const QModelIndex&)),
+            controller, SLOT(emitItemEntered(const QModelIndex&)));
     connect(this, SIGNAL(viewportEntered()),
             controller, SLOT(emitViewportEntered()));
     connect(controller, SIGNAL(zoomIn()),
@@ -78,19 +92,21 @@ DolphinIconsView::DolphinIconsView(QWidget* parent, DolphinController* controlle
     const DolphinView* view = controller->dolphinView();
     connect(view, SIGNAL(showPreviewChanged()),
             this, SLOT(slotShowPreviewChanged()));
-    connect(view, SIGNAL(additionalInfoChanged(const KFileItemDelegate::InformationList&)),
-            this, SLOT(slotAdditionalInfoChanged(const KFileItemDelegate::InformationList&)));
-
-    connect(this, SIGNAL(entered(const QModelIndex&)),
-            this, SLOT(slotEntered(const QModelIndex&)));
+    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);
 
-    m_font = QFont(settings->fontFamily(), settings->fontSize());
-    m_font.setItalic(settings->italicFont());
-    m_font.setBold(settings->boldFont());
+    if (settings->useSystemFont()) {
+        m_font = KGlobalSettings::generalFont();
+    } else {
+        m_font = QFont(settings->fontFamily(),
+                       settings->fontSize(),
+                       settings->fontWeight(),
+                       settings->italicFont());
+    }
 
     setWordWrap(settings->numberOfTextlines() > 1);
     updateGridSize(view->showPreview(), 0);
@@ -109,6 +125,9 @@ DolphinIconsView::DolphinIconsView(QWidget* parent, DolphinController* controlle
     setCategoryDrawer(m_categoryDrawer);
 
     setFocus();
+
+    connect(KGlobalSettings::self(), SIGNAL(kdisplayFontChanged()),
+            this, SLOT(updateFont()));
 }
 
 DolphinIconsView::~DolphinIconsView()
@@ -117,48 +136,29 @@ DolphinIconsView::~DolphinIconsView()
     m_categoryDrawer = 0;
 }
 
-QRect DolphinIconsView::visualRect(const QModelIndex& index) const
+void DolphinIconsView::scrollTo(const QModelIndex& index, ScrollHint hint)
 {
-    const bool leftToRightFlow = (flow() == QListView::LeftToRight);
-
-    QRect itemRect = KCategorizedView::visualRect(index);
-
-    const int maxWidth  = m_itemSize.width();
-    const int maxHeight = m_itemSize.height();
-
-    if (itemRect.width() > maxWidth) {
-        // assure that the maximum item width is not exceeded
-        if (leftToRightFlow) {
-            const int left = itemRect.left() + (itemRect.width() - maxWidth) / 2;
-            itemRect.setLeft(left);
-        }
-        itemRect.setWidth(maxWidth);
+    // Enable the QListView implementation of scrollTo() only if it has been
+    // triggered by a key press. Otherwise QAbstractItemView wants to scroll to the current
+    // index each time the layout has been changed. This becomes an issue when
+    // previews are loaded and the scrollbar is used: the scrollbar will always
+    // be reset to 0 on each new preview.
+    if (m_enableScrollTo || (state() != QAbstractItemView::NoState)) {
+        KCategorizedView::scrollTo(index, hint);
+        m_enableScrollTo = false;
     }
+}
 
-    if (itemRect.height() > maxHeight) {
-        // assure that the maximum item height is not exceeded
-        if (!leftToRightFlow) {
-            const int top = itemRect.top() + (itemRect.height() - maxHeight) / 2;
-            itemRect.setTop(top);
-        }
-        itemRect.setHeight(maxHeight);
-    }
+void DolphinIconsView::dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight)
+{
+    KCategorizedView::dataChanged(topLeft, bottomRight);
 
     KCategorizedSortFilterProxyModel* proxyModel = dynamic_cast<KCategorizedSortFilterProxyModel*>(model());
-    if (leftToRightFlow && !proxyModel->isCategorizedModel()) {
-        // TODO: QListView::visualRect() calculates a wrong position of the items under
-        // certain circumstances (e. g. if the text is too long). This issue is bypassed
-        // by the following code (I'll try create a patch for Qt but as Dolphin must also work with
-        // Qt 4.3.0 this workaround must get applied at least for KDE 4.0).
-        const IconsModeSettings* settings = DolphinSettings::instance().iconsModeSettings();
-        const int margin = settings->gridSpacing();
-        const int gridWidth = gridSize().width();
-        const int gridIndex = (itemRect.left() - margin + 1) / gridWidth;
-        const int centerInc = (maxWidth - itemRect.width()) / 2;
-        itemRect.moveLeft((gridIndex * gridWidth) + margin + centerInc);
+    if ((flow() == QListView::LeftToRight) && !proxyModel->isCategorizedModel()) {
+        // bypass a QListView issue that items are not layout correctly if the decoration size of
+        // an index changes
+        scheduleDelayedItemsLayout();
     }
-
-    return itemRect;
 }
 
 QStyleOptionViewItem DolphinIconsView::viewOptions() const
@@ -181,7 +181,20 @@ void DolphinIconsView::contextMenuEvent(QContextMenuEvent* event)
 void DolphinIconsView::mousePressEvent(QMouseEvent* event)
 {
     m_controller->requestActivation();
-    if (!indexAt(event->pos()).isValid()) {
+    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()) {
+        if (QApplication::mouseButtons() & Qt::MidButton) {
+            m_controller->replaceUrlByClipboard();
+        }
         const Qt::KeyboardModifiers modifier = QApplication::keyboardModifiers();
         if (!(modifier & Qt::ShiftModifier) && !(modifier & Qt::ControlModifier)) {
             clearSelection();
@@ -204,15 +217,11 @@ void DolphinIconsView::dragEnterEvent(QDragEnterEvent* event)
     if (event->mimeData()->hasUrls()) {
         event->acceptProposedAction();
     }
-    m_dragging = true;
 }
 
 void DolphinIconsView::dragLeaveEvent(QDragLeaveEvent* event)
 {
     KCategorizedView::dragLeaveEvent(event);
-
-    // TODO: remove this code when the issue #160611 is solved in Qt 4.4
-    m_dragging = false;
     setDirtyRegion(m_dropRect);
 }
 
@@ -226,7 +235,7 @@ void DolphinIconsView::dragMoveEvent(QDragMoveEvent* event)
 
     m_dropRect.setSize(QSize()); // set as invalid
     if (index.isValid()) {
-        const KFileItem item = itemForIndex(index);
+        const KFileItem item = m_controller->itemForIndex(index);
         if (!item.isNull() && item.isDir()) {
             m_dropRect = visualRect(index);
         } else {
@@ -247,7 +256,7 @@ void DolphinIconsView::dropEvent(QDropEvent* event)
         const KUrl::List urls = KUrl::List::fromMimeData(event->mimeData());
         if (!urls.isEmpty()) {
             const QModelIndex index = indexAt(event->pos());
-            const KFileItem item = itemForIndex(index);
+            const KFileItem item = m_controller->itemForIndex(index);
             m_controller->indicateDroppedUrls(urls,
                                               m_controller->url(),
                                               item);
@@ -256,43 +265,57 @@ void DolphinIconsView::dropEvent(QDropEvent* event)
     }
 
     KCategorizedView::dropEvent(event);
-
-    m_dragging = false;
 }
 
-void DolphinIconsView::paintEvent(QPaintEvent* event)
+void DolphinIconsView::keyPressEvent(QKeyEvent* event)
 {
-    KCategorizedView::paintEvent(event);
-
-    // TODO: remove this code when the issue #160611 is solved in Qt 4.4
-    if (m_dragging) {
-        const QBrush& brush = viewOptions().palette.brush(QPalette::Normal, QPalette::Highlight);
-        DragAndDropHelper::drawHoverIndication(this, m_dropRect, brush);
-    }
+    KCategorizedView::keyPressEvent(event);
+    m_controller->handleKeyPressEvent(event);
+    m_enableScrollTo = true; // see DolphinIconsView::scrollTo()
 }
 
-void DolphinIconsView::keyPressEvent(QKeyEvent* event)
+void DolphinIconsView::wheelEvent(QWheelEvent* event)
 {
-    KCategorizedView::keyPressEvent(event);
+    if (m_selectionManager != 0) {
+        m_selectionManager->reset();
+    }
 
-    const QItemSelectionModel* selModel = selectionModel();
-    const QModelIndex currentIndex = selModel->currentIndex();
-    const bool trigger = currentIndex.isValid()
-                         && (event->key() == Qt::Key_Return)
-                         && (selModel->selectedIndexes().count() <= 1);
-    if (trigger) {
-        triggerItem(currentIndex);
+    // let Ctrl+wheel events propagate to the DolphinView for icon zooming
+    if (event->modifiers() & Qt::ControlModifier) {
+        event->ignore();
+        return;
+    }
+    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::triggerItem(const QModelIndex& index)
+void DolphinIconsView::showEvent(QShowEvent* event)
 {
-    m_controller->triggerItem(itemForIndex(index));
+    KFileItemDelegate* delegate = dynamic_cast<KFileItemDelegate*>(itemDelegate());
+    delegate->setMaximumSize(m_itemSize);
+
+    KCategorizedView::showEvent(event);
 }
 
-void DolphinIconsView::slotEntered(const QModelIndex& index)
+void DolphinIconsView::leaveEvent(QEvent* event)
 {
-    m_controller->emitItemEntered(itemForIndex(index));
+    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_controller->emitViewportEntered();
 }
 
 void DolphinIconsView::slotShowPreviewChanged()
@@ -301,10 +324,11 @@ void DolphinIconsView::slotShowPreviewChanged()
     updateGridSize(view->showPreview(), additionalInfoCount());
 }
 
-void DolphinIconsView::slotAdditionalInfoChanged(const KFileItemDelegate::InformationList& info)
+void DolphinIconsView::slotAdditionalInfoChanged()
 {
-    const bool showPreview = m_controller->dolphinView()->showPreview();
-    updateGridSize(showPreview, info.count());
+    const DolphinView* view = m_controller->dolphinView();
+    const bool showPreview = view->showPreview();
+    updateGridSize(showPreview, view->additionalInfo().count());
 }
 
 void DolphinIconsView::zoomIn()
@@ -322,10 +346,6 @@ void DolphinIconsView::zoomIn()
         } else {
             newIconSize = increasedIconSize(oldIconSize);
             settings->setIconSize(newIconSize);
-            if (settings->previewSize() < newIconSize) {
-                // assure that the preview size is always >= the icon size
-                settings->setPreviewSize(newIconSize);
-            }
         }
 
         // increase also the grid size
@@ -349,11 +369,6 @@ void DolphinIconsView::zoomOut()
         if (showPreview) {
             const int previewSize = decreasedIconSize(settings->previewSize());
             settings->setPreviewSize(previewSize);
-            if (settings->iconSize() > previewSize) {
-                // assure that the icon size is always <= the preview size
-                newIconSize = previewSize;
-                settings->setIconSize(newIconSize);
-            }
         } else {
             newIconSize = decreasedIconSize(settings->iconSize());
             settings->setIconSize(newIconSize);
@@ -368,6 +383,21 @@ void DolphinIconsView::zoomOut()
     }
 }
 
+void DolphinIconsView::requestActivation()
+{
+    m_controller->requestActivation();
+}
+
+void DolphinIconsView::updateFont()
+{
+    const IconsModeSettings* settings = DolphinSettings::instance().iconsModeSettings();
+    Q_ASSERT(settings != 0);
+
+    if (settings->useSystemFont()) {
+        m_font = KGlobalSettings::generalFont();
+    }
+}
+
 bool DolphinIconsView::isZoomInPossible() const
 {
     IconsModeSettings* settings = DolphinSettings::instance().iconsModeSettings();
@@ -424,7 +454,6 @@ void DolphinIconsView::updateGridSize(bool showPreview, int additionalInfoCount)
     if (showPreview) {
         const int previewSize = settings->previewSize();
         const int diff = previewSize - size;
-        Q_ASSERT(diff >= 0);
         itemWidth  += diff;
         itemHeight += diff;
 
@@ -439,8 +468,10 @@ void DolphinIconsView::updateGridSize(bool showPreview, int additionalInfoCount)
         // 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 {
         m_decorationSize = QSize(size, size);
+        setIconSize(QSize(size, size));
     }
 
     m_itemSize = QSize(itemWidth, itemHeight);
@@ -450,14 +481,15 @@ void DolphinIconsView::updateGridSize(bool showPreview, int additionalInfoCount)
 
     m_controller->setZoomInPossible(isZoomInPossible());
     m_controller->setZoomOutPossible(isZoomOutPossible());
-}
 
-KFileItem DolphinIconsView::itemForIndex(const QModelIndex& index) const
-{
-    QAbstractProxyModel* proxyModel = static_cast<QAbstractProxyModel*>(model());
-    KDirModel* dirModel = static_cast<KDirModel*>(proxyModel->sourceModel());
-    const QModelIndex dirIndex = proxyModel->mapToSource(index);
-    return dirModel->itemForIndex(dirIndex);
+    KFileItemDelegate* delegate = dynamic_cast<KFileItemDelegate*>(itemDelegate());
+    if (delegate != 0) {
+        delegate->setMaximumSize(m_itemSize);
+    }
+
+    if (m_selectionManager != 0) {
+        m_selectionManager->reset();
+    }
 }
 
 int DolphinIconsView::additionalInfoCount() const