]> cloud.milkyroute.net Git - dolphin.git/commitdiff
Improvements for selections, smooth scrolling, tooltips and info-panel
authorPeter Penz <peter.penz19@gmail.com>
Mon, 8 Aug 2011 21:41:18 +0000 (23:41 +0200)
committerPeter Penz <peter.penz19@gmail.com>
Tue, 9 Aug 2011 14:22:36 +0000 (16:22 +0200)
28 files changed:
src/CMakeLists.txt
src/kitemviews/kfileitemlistwidget.cpp
src/kitemviews/kfileitemlistwidget.h
src/kitemviews/kfileitemmodel.cpp
src/kitemviews/kitemlistcontainer.cpp
src/kitemviews/kitemlistcontainer.h
src/kitemviews/kitemlistcontroller.cpp
src/kitemviews/kitemlistcontroller.h
src/kitemviews/kitemlistselectionmanager.cpp
src/kitemviews/kitemlistselectionmanager.h
src/kitemviews/kitemliststyleoption.cpp
src/kitemviews/kitemliststyleoption.h
src/kitemviews/kitemlistview.cpp
src/kitemviews/kitemlistview.h
src/kitemviews/kitemlistwidget.cpp
src/kitemviews/kitemlistwidget.h
src/kitemviews/kitemmodelbase.h
src/settings/dolphin_generalsettings.kcfgc
src/settings/dolphinsettings.cpp
src/settings/general/behaviorsettingspage.cpp
src/tests/CMakeLists.txt
src/tests/kfileitemlistviewtest.cpp
src/tests/kfileitemmodeltest.cpp
src/tests/kitemlistselectionmanagertest.cpp [new file with mode: 0644]
src/views/dolphinview.cpp
src/views/dolphinview.h
src/views/tooltips/tooltipmanager.cpp
src/views/tooltips/tooltipmanager.h

index 314c6cb280da4e8c02fe1a44747382cc2becc4e6..31f5fa49046e4068f00998462f387a606c4953cf 100644 (file)
@@ -154,6 +154,7 @@ kde4_add_kcfg_files(dolphin_SRCS
     panels/information/dolphin_informationpanelsettings.kcfgc
     settings/dolphin_compactmodesettings.kcfgc
     settings/dolphin_detailsmodesettings.kcfgc
+    settings/dolphin_generalsettings.kcfgc
     settings/dolphin_iconsmodesettings.kcfgc
     search/dolphin_searchsettings.kcfgc
     settings/dolphin_versioncontrolsettings.kcfgc
index 91c0cb597eeb4a21459609375a4c9e28b71fb2f9..a5251439fdfc50ba79fdb96f3c410f3aad54dcbc 100644 (file)
@@ -33,6 +33,7 @@
 #include <QFontMetricsF>
 #include <QGraphicsSceneResizeEvent>
 #include <QPainter>
+#include <QStyleOption>
 #include <QTextLayout>
 #include <QTextLine>
 
@@ -91,6 +92,7 @@ void KFileItemListWidget::paint(QPainter* painter, const QStyleOptionGraphicsIte
         const_cast<KFileItemListWidget*>(this)->updateCache();
     }
 
+    // Draw expansion toggle '>' or 'V'
     if (m_isDir && !m_expansionArea.isEmpty()) {
         QStyleOption arrowOption;
         arrowOption.rect = m_expansionArea.toRect();
@@ -99,10 +101,8 @@ void KFileItemListWidget::paint(QPainter* painter, const QStyleOptionGraphicsIte
         style()->drawPrimitive(arrow, &arrowOption, painter);
     }
 
-    const bool isHovered = (hoverOpacity() > 0.0);
-
     const KItemListStyleOption& itemListStyleOption = styleOption();
-    if (isHovered) {
+    if (isHovered()) {
         // Blend the unhovered and hovered pixmap if the hovering
         // animation is ongoing
         if (hoverOpacity() < 1.0) {
@@ -127,11 +127,11 @@ void KFileItemListWidget::paint(QPainter* painter, const QStyleOptionGraphicsIte
         drawPixmap(painter, m_pixmap);
     }
 
-    QFont font(itemListStyleOption.font);
-    if (itemListStyleOption.state & QStyle::State_HasFocus) {
-        font.setUnderline(true);
+    if (isCurrent()) {
+        drawFocusIndicator(painter);
     }
-    painter->setFont(font);
+
+    painter->setFont(itemListStyleOption.font);
     painter->setPen(itemListStyleOption.palette.text().color());
     painter->drawStaticText(m_textPos[Name], m_text[Name]);
 
@@ -244,6 +244,12 @@ void KFileItemListWidget::styleOptionChanged(const KItemListStyleOption& current
     m_dirtyLayout = true;
 }
 
+void KFileItemListWidget::hoveredChanged(bool hovered)
+{
+    Q_UNUSED(hovered);
+    m_dirtyLayout = true;
+}
+
 void KFileItemListWidget::resizeEvent(QGraphicsSceneResizeEvent* event)
 {
     KItemListWidget::resizeEvent(event);
@@ -374,7 +380,7 @@ void KFileItemListWidget::updatePixmapCache()
     m_hoverPixmapRect.moveTopLeft(QPointF(x, y));
 
     // Prepare the pixmap that is used when the item gets hovered
-    if (option.state & QStyle::State_MouseOver) {
+    if (isHovered()) {
         m_hoverPixmap = m_pixmap;
         KIconEffect* effect = KIconLoader::global()->iconEffect();
         // In the KIconLoader terminology, active = hover.
@@ -681,6 +687,31 @@ void KFileItemListWidget::drawPixmap(QPainter* painter, const QPixmap& pixmap)
     }
 }
 
+void KFileItemListWidget::drawFocusIndicator(QPainter* painter)
+{
+    // Ideally style()->drawPrimitive(QStyle::PE_FrameFocusRect...)
+    // should be used, but Oxygen only draws indicators within classes
+    // derived from QAbstractItemView or Q3ListView. As a workaround
+    // the indicator is drawn manually. Code copied from oxygenstyle.cpp
+    // Copyright ( C ) 2009-2010 Hugo Pereira Da Costa <hugo@oxygen-icons.org>
+    // TODO: Clarify with Oxygen maintainers how to proceed with this.
+
+    const KItemListStyleOption& option = styleOption();
+    const QPalette palette = option.palette;
+    const QRect rect = m_textsBoundingRect.toRect().adjusted(0, 0, 0, -1);
+
+    QLinearGradient gradient(rect.bottomLeft(), rect.bottomRight());
+    gradient.setColorAt(0.0, Qt::transparent);
+    gradient.setColorAt(1.0, Qt::transparent);
+    gradient.setColorAt(0.2, palette.color(QPalette::Text));
+    gradient.setColorAt(0.8, palette.color(QPalette::Text));
+
+    painter->setRenderHint(QPainter::Antialiasing, false);
+    painter->setPen(QPen(gradient, 1));
+    painter->drawLine(rect.bottomLeft(), rect.bottomRight());
+    painter->setRenderHint(QPainter::Antialiasing, true);
+}
+
 QPixmap KFileItemListWidget::pixmapForIcon(const QString& name, int size)
 {
     const KIcon icon(name);
index 3ce953106f99a54fe8431624b238b43ee6b4c129..1d1b6fd86bcbda68dcc8e32e8b353ee913936649 100644 (file)
@@ -57,6 +57,7 @@ protected:
     virtual void visibleRolesChanged(const QHash<QByteArray, int>& current, const QHash<QByteArray, int>& previous);
     virtual void visibleRolesSizesChanged(const QHash<QByteArray, QSizeF>& current, const QHash<QByteArray, QSizeF>& previous);
     virtual void styleOptionChanged(const KItemListStyleOption& current, const KItemListStyleOption& previous);
+    virtual void hoveredChanged(bool hovered);
     virtual void resizeEvent(QGraphicsSceneResizeEvent* event);
 
 private:
@@ -85,6 +86,7 @@ private:
     QString roleText(TextId textId, const QVariant& roleValue) const;
 
     void drawPixmap(QPainter* painter, const QPixmap& pixmap);
+    void drawFocusIndicator(QPainter* painter);
 
     static QPixmap pixmapForIcon(const QString& name, int size);
     static TextId roleTextId(const QByteArray& role);
index b191abab606f7769b8aab7e0ff2576c22464e515..ddc56209b8df72e1f319838640cb2e17f0dfd6a0 100644 (file)
@@ -403,8 +403,9 @@ void KFileItemModel::insertItems(const KFileItemList& items)
     KItemRangeList itemRanges;
     int targetIndex = 0;
     int sourceIndex = 0;
-    int insertedAtIndex = -1;
-    int insertedCount = 0;
+    int insertedAtIndex = -1;         // Index for the current item-range
+    int insertedCount = 0;            // Count for the current item-range
+    int previouslyInsertedCount = 0;  // Sum of previously inserted items for all ranges
     while (sourceIndex < sortedItems.count()) {
         // Find target index from m_items to insert the current item
         // in a sorted order
@@ -418,7 +419,8 @@ void KFileItemModel::insertItems(const KFileItemList& items)
 
         if (targetIndex - previousTargetIndex > 0 && insertedAtIndex >= 0) {
             itemRanges << KItemRange(insertedAtIndex, insertedCount);
-            insertedAtIndex = targetIndex;
+            previouslyInsertedCount += insertedCount;
+            insertedAtIndex = targetIndex - previouslyInsertedCount;
             insertedCount = 0;
         }
 
@@ -431,6 +433,7 @@ void KFileItemModel::insertItems(const KFileItemList& items)
 
         if (insertedAtIndex < 0) {
             insertedAtIndex = targetIndex;
+            Q_ASSERT(previouslyInsertedCount == 0);
         }
         ++targetIndex;
         ++sourceIndex;
index 09fb505d642ad6d8105dde61e849b0930a7ca864..e247df0c7f37cdd15041ccc4a14fc7fb76e29a7d 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <QGraphicsScene>
 #include <QGraphicsView>
+#include <QPropertyAnimation>
 #include <QScrollBar>
 #include <QStyle>
 
@@ -56,7 +57,9 @@ public:
 
 KItemListContainer::KItemListContainer(KItemListController* controller, QWidget* parent) :
     QAbstractScrollArea(parent),
-    m_controller(controller)
+    m_controller(controller),
+    m_sliderMovedByUser(false),
+    m_viewOffsetAnimation(0)
 {
     Q_ASSERT(controller);
     controller->setParent(this);
@@ -99,8 +102,86 @@ void KItemListContainer::scrollContentsBy(int dx, int dy)
     }
 
     const qreal currentOffset = view->offset();
-    const qreal offsetDiff = (view->scrollOrientation() == Qt::Vertical) ? dy : dx;
-    view->setOffset(currentOffset - offsetDiff);
+    qreal offsetDiff = (view->scrollOrientation() == Qt::Vertical) ? dy : dx;
+
+    const bool animRunning = (m_viewOffsetAnimation->state() == QAbstractAnimation::Running);
+    if (animRunning) {
+        // Stopping a running animation means skipping the range from the current offset
+        // until the target offset. To prevent skipping of the range the difference
+        // is added to the new target offset.
+        m_viewOffsetAnimation->stop();
+        const qreal targetOffset = m_viewOffsetAnimation->endValue().toReal();
+        offsetDiff += (currentOffset - targetOffset);
+    }
+
+    const qreal newOffset = currentOffset - offsetDiff;
+
+    if (m_sliderMovedByUser || animRunning) {
+        m_viewOffsetAnimation->stop();
+        m_viewOffsetAnimation->setStartValue(currentOffset);
+        m_viewOffsetAnimation->setEndValue(newOffset);
+        m_viewOffsetAnimation->setEasingCurve(animRunning ? QEasingCurve::OutQuad : QEasingCurve::InOutQuad);
+        m_viewOffsetAnimation->start();
+    } else {
+        view->setOffset(newOffset);
+    }
+}
+
+bool KItemListContainer::eventFilter(QObject* obj, QEvent* event)
+{
+    Q_ASSERT(obj == horizontalScrollBar() || obj == verticalScrollBar());
+
+    // Check whether the scrollbar has been adjusted by a mouse-event
+    // triggered by the user and remember this in m_sliderMovedByUser.
+    // The smooth scrolling will only get active if m_sliderMovedByUser
+    // is true (see scrollContentsBy()).
+    const bool scrollVertical = (m_controller->view()->scrollOrientation() == Qt::Vertical);
+    const bool checkEvent = ( scrollVertical && obj == verticalScrollBar()) ||
+                            (!scrollVertical && obj == horizontalScrollBar());
+    if (checkEvent) {
+        switch (event->type()) {
+        case QEvent::MouseButtonPress:
+            m_sliderMovedByUser = true;
+           break;
+
+        case QEvent::MouseButtonRelease:
+            m_sliderMovedByUser = false;
+            break;
+
+        case QEvent::Wheel:
+            wheelEvent(static_cast<QWheelEvent*>(event));
+            break;
+
+        default:
+            break;
+         }
+    }
+
+    return QAbstractScrollArea::eventFilter(obj, event);
+}
+
+void KItemListContainer::wheelEvent(QWheelEvent* event)
+{
+    KItemListView* view = m_controller->view();
+    if (!view || event->orientation() != view->scrollOrientation()) {
+        return;
+    }
+
+    const int numDegrees = event->delta() / 8;
+    const int numSteps = numDegrees / 15;
+
+    const bool previous = m_sliderMovedByUser;
+    m_sliderMovedByUser = true;
+    if (view->scrollOrientation() == Qt::Vertical) {
+        const int value = verticalScrollBar()->value();
+        verticalScrollBar()->setValue(value - numSteps * view->size().height());
+    } else {
+        const int value = horizontalScrollBar()->value();
+        horizontalScrollBar()->setValue(value - numSteps * view->size().width());
+    }
+    m_sliderMovedByUser = previous;
+
+    event->accept();
 }
 
 void KItemListContainer::slotModelChanged(KItemModelBase* current, KItemModelBase* previous)
@@ -116,37 +197,57 @@ void KItemListContainer::slotViewChanged(KItemListView* current, KItemListView*
         scene->removeItem(previous);
         disconnect(previous, SIGNAL(offsetChanged(int,int)), this, SLOT(updateScrollBars()));
         disconnect(previous, SIGNAL(maximumOffsetChanged(int,int)), this, SLOT(updateScrollBars()));
+        m_viewOffsetAnimation->setTargetObject(0);
     }
     if (current) {
         scene->addItem(current);
-        connect(previous, SIGNAL(offsetChanged(int,int)), this, SLOT(updateScrollBars()));
+        connect(current, SIGNAL(offsetChanged(int,int)), this, SLOT(updateScrollBars()));
         connect(current, SIGNAL(maximumOffsetChanged(int,int)), this, SLOT(updateScrollBars()));
+        m_viewOffsetAnimation->setTargetObject(current);
     }
 }
 
 void KItemListContainer::updateScrollBars()
 {
-    const QSizeF size = m_controller->view()->size();
-
-    if (m_controller->view()->scrollOrientation() == Qt::Vertical) {
-        QScrollBar* scrollBar = verticalScrollBar();
-        const int value = m_controller->view()->offset();
-        const int maximum = qMax(0, int(m_controller->view()->maximumOffset() - size.height()));
-        scrollBar->setPageStep(size.height());
-        scrollBar->setMinimum(0);
-        scrollBar->setMaximum(maximum);
-        scrollBar->setValue(value);
-        horizontalScrollBar()->setMaximum(0);
+    const KItemListView* view = m_controller->view();
+    if (!view) {
+        return;
+    }
+
+    QScrollBar* scrollBar = 0;
+    int singleStep = 0;
+    int pageStep = 0;
+    if (view->scrollOrientation() == Qt::Vertical) {
+        scrollBar = verticalScrollBar();
+        singleStep = view->itemSize().height();
+        pageStep = view->size().height();
     } else {
-        QScrollBar* scrollBar = horizontalScrollBar();
-        const int value = m_controller->view()->offset();
-        const int maximum = qMax(0, int(m_controller->view()->maximumOffset() - size.width()));
-        scrollBar->setPageStep(size.width());
-        scrollBar->setMinimum(0);
-        scrollBar->setMaximum(maximum);
-        scrollBar->setValue(value);
-        verticalScrollBar()->setMaximum(0);
+        scrollBar = horizontalScrollBar();
+        singleStep = view->itemSize().width();
+        pageStep = view->size().width();
     }
+
+    const int value = view->offset();
+    const int maximum = qMax(0, int(view->maximumOffset() - pageStep));
+    if (m_viewOffsetAnimation->state() == QAbstractAnimation::Running) {
+        if (maximum == scrollBar->maximum()) {
+            // The value has been changed by the animation, no update
+            // of the scrollbars is required as their target state will be
+            // reached with the end of the animation.
+            return;
+        }
+
+        // The maximum has been changed which indicates that the content
+        // of the view has been changed. Stop the animation in any case and
+        // update the scrollbars immediately.
+        m_viewOffsetAnimation->stop();
+    }
+
+    scrollBar->setSingleStep(singleStep);
+    scrollBar->setPageStep(pageStep);
+    scrollBar->setMinimum(0);
+    scrollBar->setMaximum(maximum);
+    scrollBar->setValue(value);
 }
 
 void KItemListContainer::updateGeometries()
@@ -186,6 +287,12 @@ void KItemListContainer::initialize()
 
     QGraphicsView* graphicsView = new KItemListContainerViewport(new QGraphicsScene(this), this);
     setViewport(graphicsView);
+
+    m_viewOffsetAnimation = new QPropertyAnimation(this, "offset");
+    m_viewOffsetAnimation->setDuration(500);
+
+    horizontalScrollBar()->installEventFilter(this);
+    verticalScrollBar()->installEventFilter(this);
 }
 
 #include "kitemlistcontainer.moc"
index 83044c4f8e831c320b3cb5df66284b4b518375e8..4994eb2499f78b6350a88c8169e079b95a1147bb 100644 (file)
@@ -30,6 +30,7 @@
 class KItemListController;
 class KItemListView;
 class KItemModelBase;
+class QPropertyAnimation;
 
 /**
  * @brief Provides a QWidget based scrolling view for a KItemListController.
@@ -51,6 +52,8 @@ protected:
     virtual void showEvent(QShowEvent* event);
     virtual void resizeEvent(QResizeEvent* event);
     virtual void scrollContentsBy(int dx, int dy);
+    virtual bool eventFilter(QObject* obj, QEvent* event);
+    virtual void wheelEvent(QWheelEvent* event);
 
 private slots:
     void slotModelChanged(KItemModelBase* current, KItemModelBase* previous);
@@ -63,6 +66,9 @@ private:
 
 private:
     KItemListController* m_controller;
+
+    bool m_sliderMovedByUser;
+    QPropertyAnimation* m_viewOffsetAnimation;
 };
 
 #endif
index 2d72a96de19867ef5c4d5afba6cb2c89fe6b1f7f..dcd62ad52caf89c1e5a67a0318109621beff64e4 100644 (file)
@@ -82,14 +82,9 @@ void KItemListController::setView(KItemListView* view)
     KItemListView* oldView = m_view;
     m_view = view;
 
-    if (oldView) {
-        disconnect(m_selectionManager, SIGNAL(currentChanged(int,int)), oldView, SLOT(currentChanged(int,int)));
-    }
-
     if (m_view) {
         m_view->setController(this);
         m_view->setModel(m_model);
-        connect(m_selectionManager, SIGNAL(currentChanged(int,int)), m_view, SLOT(currentChanged(int,int)));
     }
 
     emit viewChanged(m_view, oldView);
@@ -139,14 +134,20 @@ bool KItemListController::mousePressEvent(QGraphicsSceneMouseEvent* event, const
     const QPointF pos = transform.map(event->pos());
     m_pressedIndex = m_view->itemAt(pos);
 
-    m_selectionManager->setCurrentItem(m_pressedIndex);
-
-    // The anchor for the current selection is updated except for Shift+LeftButton events
-    // (the current selection is continued with the previous anchor in that case).
-    if (!(event->buttons() & Qt::LeftButton && event->modifiers() & Qt::ShiftModifier)) {
+    const bool shiftOrControlPressed = event->modifiers() & Qt::ShiftModifier ||
+                                       event->modifiers() & Qt::ControlModifier;
+    if (!shiftOrControlPressed) {
+        m_selectionManager->clearSelection();
         m_selectionManager->setAnchorItem(m_pressedIndex);
     }
 
+    if (m_pressedIndex >= 0) {
+        m_selectionManager->setCurrentItem(m_pressedIndex);
+        if (!m_view->isAboveExpansionToggle(m_pressedIndex, pos)) {
+            m_selectionManager->setSelected(m_pressedIndex);
+        }
+    }
+
     return false;
 }
 
@@ -162,15 +163,18 @@ bool KItemListController::mouseReleaseEvent(QGraphicsSceneMouseEvent* event, con
     if (m_view) {
         const QPointF pos = transform.map(event->pos());
         const int index = m_view->itemAt(pos);
+        const bool shiftOrControlPressed = event->modifiers() & Qt::ShiftModifier || event->modifiers() & Qt::ControlModifier;
+
         if (index >= 0 && index == m_pressedIndex) {
+            // The release event is done above the same item as the press event
             bool emitItemClicked = true;
             if (event->button() & Qt::LeftButton) {
                 if (m_view->isAboveExpansionToggle(index, pos)) {
                     emit itemExpansionToggleClicked(index);
                     emitItemClicked = false;
                 }
-                else if (event->modifiers() & Qt::ShiftModifier || event->modifiers() & Qt::ControlModifier) {
-                    // The mouse click should only update the selection, not trigger the item.
+                else if (shiftOrControlPressed) {
+                    // The mouse click should only update the selection, not trigger the item
                     emitItemClicked = false;
                 }
             }
@@ -178,6 +182,8 @@ bool KItemListController::mouseReleaseEvent(QGraphicsSceneMouseEvent* event, con
             if (emitItemClicked) {
                 emit itemClicked(index, event->button());
             }
+        } else if (!shiftOrControlPressed) {
+            m_selectionManager->clearSelection();
         }
     }
 
@@ -229,8 +235,49 @@ bool KItemListController::hoverEnterEvent(QGraphicsSceneHoverEvent* event, const
 
 bool KItemListController::hoverMoveEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform)
 {
-    Q_UNUSED(event);
+    // The implementation assumes that only one item can get hovered no matter
+    // whether they overlap or not.
+
     Q_UNUSED(transform);
+    if (!m_model || !m_view) {
+        return false;
+    }
+
+    // Search the previously hovered item that might get unhovered
+    KItemListWidget* unhoveredWidget = 0;
+    foreach (KItemListWidget* widget, m_view->visibleItemListWidgets()) {
+        if (widget->isHovered()) {
+            unhoveredWidget = widget;
+            break;
+        }
+    }
+
+    // Search the currently hovered item
+    KItemListWidget* hoveredWidget = 0;
+    foreach (KItemListWidget* widget, m_view->visibleItemListWidgets()) {
+        const QPointF mappedPos = widget->mapFromItem(m_view, event->pos());
+
+        const bool hovered = widget->contains(mappedPos) &&
+                             !widget->expansionToggleRect().contains(mappedPos) &&
+                             !widget->selectionToggleRect().contains(mappedPos);
+        if (hovered) {
+            hoveredWidget = widget;
+            break;
+        }
+    }
+
+    if (unhoveredWidget != hoveredWidget) {
+        if (unhoveredWidget) {
+            unhoveredWidget->setHovered(false);
+            emit itemUnhovered(unhoveredWidget->index());
+        }
+
+        if (hoveredWidget) {
+            hoveredWidget->setHovered(true);
+            emit itemHovered(hoveredWidget->index());
+        }
+    }
+
     return false;
 }
 
@@ -238,6 +285,17 @@ bool KItemListController::hoverLeaveEvent(QGraphicsSceneHoverEvent* event, const
 {
     Q_UNUSED(event);
     Q_UNUSED(transform);
+
+    if (!m_model || !m_view) {
+        return false;
+    }
+
+    foreach (KItemListWidget* widget, m_view->visibleItemListWidgets()) {
+        if (widget->isHovered()) {
+            widget->setHovered(false);
+            emit itemUnhovered(widget->index());
+        }
+    }
     return false;
 }
 
@@ -262,9 +320,6 @@ bool KItemListController::processEvent(QEvent* event, const QTransform& transfor
     }
 
     switch (event->type()) {
-//  case QEvent::FocusIn:
-//  case QEvent::FocusOut:
-//      return focusEvent(static_cast<QFocusEvent*>(event));
     case QEvent::KeyPress:
         return keyPressEvent(static_cast<QKeyEvent*>(event));
     case QEvent::InputMethod:
index 86f2b4ea62dd309f152868506f12acf2cb5e43a4..092a7bc6210b196c80e13640ab1b65bfcc3e6850 100644 (file)
@@ -101,6 +101,19 @@ public:
 
 signals:
     void itemClicked(int index, Qt::MouseButton button);
+
+    /**
+     * Is emitted if the item with the index \p index gets hovered.
+     */
+    void itemHovered(int index);
+
+    /**
+     * Is emitted if the item with the index \p index gets unhovered.
+     * It is assured that the signal itemHovered() for this index
+     * has been emitted before.
+     */
+    void itemUnhovered(int index);
+
     void itemExpansionToggleClicked(int index);
 
     void modelChanged(KItemModelBase* current, KItemModelBase* previous);
index 6fe9ed8185bb5e22b7acab4dade1b04e7f8d93d9..ee8ba929eec30e3bd62b76924ece7e0b317f64ef 100644 (file)
 #include "kitemlistselectionmanager.h"
 
 #include "kitemmodelbase.h"
+#include <KDebug>
 
 KItemListSelectionManager::KItemListSelectionManager(QObject* parent) :
     QObject(parent),
     m_currentItem(-1),
     m_anchorItem(-1),
+    m_selectedItems(),
     m_model(0)
 {
 }
@@ -39,7 +41,7 @@ KItemListSelectionManager::~KItemListSelectionManager()
 void KItemListSelectionManager::setCurrentItem(int current)
 {
     const int previous = m_currentItem;
-    if (m_model && current < m_model->count()) {
+    if (m_model && current >= 0 && current < m_model->count()) {
         m_currentItem = current;
     } else {
         m_currentItem = -1;
@@ -55,6 +57,88 @@ int KItemListSelectionManager::currentItem() const
     return m_currentItem;
 }
 
+void KItemListSelectionManager::setSelectedItems(const QSet<int>& items)
+{
+    if (m_selectedItems != items) {
+        const QSet<int> previous = m_selectedItems;
+        m_selectedItems = items;
+        emit selectionChanged(m_selectedItems, previous);
+    }
+}
+
+QSet<int> KItemListSelectionManager::selectedItems() const
+{
+    return m_selectedItems;
+}
+
+bool KItemListSelectionManager::hasSelection() const
+{
+    return !m_selectedItems.isEmpty();
+}
+
+void KItemListSelectionManager::setSelected(int index, int count, SelectionMode mode)
+{
+    if (index < 0 || count < 1 || !m_model || index >= m_model->count()) {
+        return;
+    }
+
+    const QSet<int> previous = m_selectedItems;
+
+    count = qMin(count, m_model->count() - index);
+
+    const int endIndex = index + count -1;
+    switch (mode) {
+    case Select:
+        for (int i = index; i <= endIndex; ++i) {
+            m_selectedItems.insert(i);
+        }
+        break;
+
+    case Deselect:
+        for (int i = index; i <= endIndex; ++i) {
+            m_selectedItems.remove(i);
+        }
+        break;
+
+    case Toggle:
+        for (int i = index; i <= endIndex; ++i) {
+            if (m_selectedItems.contains(i)) {
+                m_selectedItems.remove(i);
+            } else {
+                m_selectedItems.insert(i);
+            }
+        }
+        break;
+
+    default:
+        Q_ASSERT(false);
+        break;
+    }
+
+    if (m_selectedItems != previous) {
+        emit selectionChanged(m_selectedItems, previous);
+    }
+}
+
+void KItemListSelectionManager::clearSelection()
+{
+    if (!m_selectedItems.isEmpty()) {
+        const QSet<int> previous = m_selectedItems;
+        m_selectedItems.clear();
+        emit selectionChanged(m_selectedItems, previous);
+    }
+}
+
+void KItemListSelectionManager::beginAnchoredSelection(int anchor, SelectionMode mode)
+{
+    Q_UNUSED(anchor);
+    Q_UNUSED(mode);
+}
+
+void KItemListSelectionManager::endAnchoredSelection()
+{
+}
+
 void KItemListSelectionManager::setAnchorItem(int anchor)
 {
     const int previous = m_anchorItem;
@@ -82,6 +166,106 @@ KItemModelBase* KItemListSelectionManager::model() const
 void KItemListSelectionManager::setModel(KItemModelBase* model)
 {
     m_model = model;
+    if (model && model->count() > 0) {
+        m_currentItem = 0;
+    }
+}
+
+void KItemListSelectionManager::itemsInserted(const KItemRangeList& itemRanges)
+{
+    // Update the current item
+    if (m_currentItem < 0) {
+        setCurrentItem(0);
+    } else {
+        int inc = 0;
+        foreach (const KItemRange& itemRange, itemRanges) {
+            if (m_currentItem < itemRange.index) {
+                break;
+            }
+            inc += itemRange.count;
+        }
+        setCurrentItem(m_currentItem + inc);
+    }
+
+    // Update the selections
+    if (!m_selectedItems.isEmpty()) {
+        const QSet<int> previous = m_selectedItems;
+
+        QSet<int> current;
+        current.reserve(m_selectedItems.count());
+        QSetIterator<int> it(m_selectedItems);
+        while (it.hasNext()) {
+            const int index = it.next();
+            int inc = 0;
+            foreach (const KItemRange& itemRange, itemRanges) {
+                if (index < itemRange.index) {
+                    break;
+                }
+                inc += itemRange.count;
+            }
+            current.insert(index + inc);
+        }
+
+        if (current != previous) {
+            m_selectedItems = current;
+            emit selectionChanged(current, previous);
+        }
+    }
+}
+
+void KItemListSelectionManager::itemsRemoved(const KItemRangeList& itemRanges)
+{
+    // Update the current item
+    if (m_currentItem >= 0) {
+        int currentItem = m_currentItem;
+        foreach (const KItemRange& itemRange, itemRanges) {
+            if (currentItem < itemRange.index) {
+                break;
+            }
+            if (currentItem >= itemRange.index + itemRange.count) {
+                currentItem -= itemRange.count;
+            } else if (currentItem >= m_model->count()) {
+                currentItem = m_model->count() - 1;
+            }
+        }
+        setCurrentItem(currentItem);
+    }
+
+    // Update the selections
+    if (!m_selectedItems.isEmpty()) {
+        const QSet<int> previous = m_selectedItems;
+
+        QSet<int> current;
+        current.reserve(m_selectedItems.count());
+        QSetIterator<int> it(m_selectedItems);
+        while (it.hasNext()) {
+            int index = it.next();
+            int dec = 0;
+            foreach (const KItemRange& itemRange, itemRanges) {
+                if (index < itemRange.index) {
+                    break;
+                }
+
+                if (index < itemRange.index + itemRange.count) {
+                    // The selection is part of the removed range
+                    // and will get deleted
+                    index = -1;
+                    break;
+                }
+
+                dec += itemRange.count;
+            }
+            index -= dec;
+            if (index >= 0)  {
+                current.insert(index);
+            }
+        }
+
+        if (current != previous) {
+            m_selectedItems = current;
+            emit selectionChanged(current, previous);
+        }
+    }
 }
 
 #include "kitemlistselectionmanager.moc"
index 5c8e846142e8eaedf60b740d48a17be77c4d238f..5b329b40eebe50507a3cb907dc934deb6ed77b99 100644 (file)
 
 #include <libdolphin_export.h>
 
+#include <kitemviews/kitemmodelbase.h>
+
 #include <QObject>
+#include <QSet>
 
 class KItemModelBase;
 
+/**
+ * @brief Allows to select and deselect items of a KItemListView.
+ */
 class LIBDOLPHINPRIVATE_EXPORT KItemListSelectionManager : public QObject
 {
     Q_OBJECT
@@ -39,13 +45,22 @@ public:
         Deselect,
         Toggle
     };
-    
+
     KItemListSelectionManager(QObject* parent = 0);
     virtual ~KItemListSelectionManager();
 
     void setCurrentItem(int current);
     int currentItem() const;
 
+    void setSelectedItems(const QSet<int>& items);
+    QSet<int> selectedItems() const;
+    bool hasSelection() const;
+
+    void setSelected(int index, int count = 1, SelectionMode mode = Select);
+    void clearSelection();
+
+    void beginAnchoredSelection(int anchor, SelectionMode mode = Select);
+    void endAnchoredSelection();
     void setAnchorItem(int anchor);
     int anchorItem() const;
 
@@ -53,17 +68,24 @@ public:
 
 signals:
     void currentChanged(int current, int previous);
+    void selectionChanged(const QSet<int>& current, const QSet<int>& previous);
     void anchorChanged(int anchor, int previous);
 
-protected:
+private:
     void setModel(KItemModelBase* model);
+    void itemsInserted(const KItemRangeList& itemRanges);
+    void itemsRemoved(const KItemRangeList& itemRanges);
 
 private:
     int m_currentItem;
     int m_anchorItem;
+    QSet<int> m_selectedItems;
+
     KItemModelBase* m_model;
 
-    friend class KItemListController;
+    friend class KItemListController; // Calls setModel()
+    friend class KItemListView;       // Calls itemsInserted() and itemsRemoved()
+    friend class KItemListSelectionManagerTest;
 };
 
 #endif
index 261dfc07b956713c34996af6aaf400c8032ef198..f26b220bc1380ed092b99c5e385babb67283ac25 100644 (file)
 #include "kitemliststyleoption.h"
 
 KItemListStyleOption::KItemListStyleOption() :
-    QStyleOption(QStyleOption::Version, QStyleOption::SO_CustomBase + 1)
+    rect(),
+    font(),
+    fontMetrics(QFont()),
+    palette(),
+    margin(0),
+    iconSize(0)
 {
 }
 
 KItemListStyleOption::KItemListStyleOption(const KItemListStyleOption& other) :
-    QStyleOption(other)
+    rect(other.rect),
+    font(other.font),
+    fontMetrics(other.fontMetrics),
+    palette(other.palette),
+    margin(other.margin),
+    iconSize(other.iconSize)
 {
-    margin = other.margin;
-    iconSize = other.iconSize;
-    font = other.font;
 }
 
 KItemListStyleOption::~KItemListStyleOption()
index d181204d7e0734fa99acf9d34c07524ffff37df2..bafb81d3a9bfbb52aeab50277d9102edf0551c25 100644 (file)
 #include <libdolphin_export.h>
 
 #include <QFont>
-#include <QStyleOption>
+#include <QFontMetrics>
+#include <QPalette>
+#include <QRect>
 
-class LIBDOLPHINPRIVATE_EXPORT KItemListStyleOption : public QStyleOption
+class LIBDOLPHINPRIVATE_EXPORT KItemListStyleOption
 {
 public:
     KItemListStyleOption();
     KItemListStyleOption(const KItemListStyleOption& other);
     virtual ~KItemListStyleOption();
 
+    QRect rect;
+    QFont font;
+    QFontMetrics fontMetrics;
+    QPalette palette;
     int margin;
     int iconSize;
-    QFont font;
 };
 #endif
 
index b89f4d0f558af40a55c8a56327a6a2e7d56ea7d6..9c054e11912152b223cca7cecff724e9ef7e20c7 100644 (file)
@@ -256,10 +256,6 @@ void KItemListView::setGeometry(const QRectF& rect)
 
 int KItemListView::itemAt(const QPointF& pos) const
 {
-    if (!m_model) {
-        return -1;
-    }
-
     QHashIterator<int, KItemListWidget*> it(m_visibleItems);
     while (it.hasNext()) {
         it.next();
@@ -315,6 +311,11 @@ QHash<QByteArray, QSizeF> KItemListView::visibleRoleSizes() const
     return QHash<QByteArray, QSizeF>();
 }
 
+QRectF KItemListView::itemBoundingRect(int index) const
+{
+    return m_layouter->itemBoundingRect(index);
+}
+
 void KItemListView::beginTransaction()
 {
     ++m_activeTransactions;
@@ -412,56 +413,6 @@ void KItemListView::mousePressEvent(QGraphicsSceneMouseEvent* event)
     event->accept();
 }
 
-void KItemListView::hoverMoveEvent(QGraphicsSceneHoverEvent* event)
-{
-    if (!m_model) {
-        return;
-    }
-
-    QHashIterator<int, KItemListWidget*> it(m_visibleItems);
-    while (it.hasNext()) {
-        it.next();
-
-        KItemListWidget* widget = it.value();
-        KItemListStyleOption styleOption = widget->styleOption();
-        const QPointF mappedPos = widget->mapFromItem(this, event->pos());
-
-        const bool hovered = widget->contains(mappedPos) &&
-                             !widget->expansionToggleRect().contains(mappedPos) &&
-                             !widget->selectionToggleRect().contains(mappedPos);
-        if (hovered) {
-            if (!(styleOption.state & QStyle::State_MouseOver)) {
-                styleOption.state |= QStyle::State_MouseOver;
-                widget->setStyleOption(styleOption);
-            }
-        } else if (styleOption.state & QStyle::State_MouseOver) {
-            styleOption.state &= ~QStyle::State_MouseOver;
-            widget->setStyleOption(styleOption);
-        }
-    }
-}
-
-void KItemListView::hoverLeaveEvent(QGraphicsSceneHoverEvent* event)
-{
-    Q_UNUSED(event);
-
-    if (!m_model) {
-        return;
-    }
-
-    QHashIterator<int, KItemListWidget*> it(m_visibleItems);
-    while (it.hasNext()) {
-        it.next();
-
-        KItemListWidget* widget = it.value();
-        KItemListStyleOption styleOption = widget->styleOption();
-        if (styleOption.state & QStyle::State_MouseOver) {
-            styleOption.state &= ~QStyle::State_MouseOver;
-            widget->setStyleOption(styleOption);
-        }
-    }
-}
-
 QList<KItemListWidget*> KItemListView::visibleItemListWidgets() const
 {
     return m_visibleItems.values();
@@ -476,13 +427,18 @@ void KItemListView::slotItemsInserted(const KItemRangeList& itemRanges)
         beginTransaction();
     }
 
+    int previouslyInsertedCount = 0;
     foreach (const KItemRange& range, itemRanges) {
-        const int index = range.index;
+        // range.index is related to the model before anything has been inserted.
+        // As in each loop the current item-range gets inserted the index must
+        // be increased by the already previoulsy inserted items.
+        const int index = range.index + previouslyInsertedCount;
         const int count = range.count;
         if (index < 0 || count <= 0) {
             kWarning() << "Invalid item range (index:" << index << ", count:" << count << ")";
             continue;
         }
+        previouslyInsertedCount += count;
 
         m_sizeHintResolver->itemsInserted(index, count);
 
@@ -524,16 +480,10 @@ void KItemListView::slotItemsInserted(const KItemRangeList& itemRanges)
             doLayout(Animation, index, count);
             update();
         }
+    }
 
-        if (m_controller) {
-            KItemListSelectionManager* selectionManager = m_controller->selectionManager();
-            const int current = selectionManager->currentItem();
-            if (current < 0) {
-                selectionManager->setCurrentItem(0);
-            } else if (current >= index) {
-                selectionManager->setCurrentItem(current + count);
-            }
-        }
+    if (m_controller) {
+        m_controller->selectionManager()->itemsInserted(itemRanges);
     }
 
     if (hasMultipleRanges) {
@@ -611,14 +561,10 @@ void KItemListView::slotItemsRemoved(const KItemRangeList& itemRanges)
             doLayout(Animation, index, -count);
             update();
         }
+    }
 
-        /*KItemListSelectionManager* selectionManager = m_controller->selectionManager();
-        const int current = selectionManager->currentItem();
-        if (count() <= 0) {
-            selectionManager->setCurrentItem(-1);
-        } else if (current >= index) {
-            selectionManager->setCurrentItem(current + count);
-        }*/
+    if (m_controller) {
+        m_controller->selectionManager()->itemsRemoved(itemRanges);
     }
 
     if (hasMultipleRanges) {
@@ -645,24 +591,33 @@ void KItemListView::slotItemsChanged(const KItemRangeList& itemRanges,
     }
 }
 
-void KItemListView::currentChanged(int current, int previous)
+void KItemListView::slotCurrentChanged(int current, int previous)
+{
+    Q_UNUSED(previous);
+
+    KItemListWidget* previousWidget = m_visibleItems.value(previous, 0);
+    if (previousWidget) {
+        Q_ASSERT(previousWidget->isCurrent());
+        previousWidget->setCurrent(false);
+    }
+
+    KItemListWidget* currentWidget = m_visibleItems.value(current, 0);
+    if (currentWidget) {
+        Q_ASSERT(!currentWidget->isCurrent());
+        currentWidget->setCurrent(true);
+    }
+}
+
+void KItemListView::slotSelectionChanged(const QSet<int>& current, const QSet<int>& previous)
 {
     Q_UNUSED(previous);
 
     QHashIterator<int, KItemListWidget*> it(m_visibleItems);
     while (it.hasNext()) {
         it.next();
-
+        const int index = it.key();
         KItemListWidget* widget = it.value();
-        KItemListStyleOption styleOption = widget->styleOption();
-        if (it.key() == current) {
-            styleOption.state |= QStyle::State_HasFocus;
-            widget->setStyleOption(styleOption);
-        }
-        else if (styleOption.state & QStyle::State_HasFocus) {
-            styleOption.state &= ~QStyle::State_HasFocus;
-            widget->setStyleOption(styleOption);
-        }
+        widget->setSelected(current.contains(index));
     }
 }
 
@@ -717,7 +672,20 @@ void KItemListView::setController(KItemListController* controller)
 {
     if (m_controller != controller) {
         KItemListController* previous = m_controller;
+        if (previous) {
+            KItemListSelectionManager* selectionManager = previous->selectionManager();
+            disconnect(selectionManager, SIGNAL(currentChanged(int,int)), this, SLOT(slotCurrentChanged(int,int)));
+            disconnect(selectionManager, SIGNAL(selectionChanged(QSet<int>,QSet<int>)), this, SLOT(slotSelectionChanged(QSet<int>,QSet<int>)));
+        }
+
         m_controller = controller;
+
+        if (controller) {
+            KItemListSelectionManager* selectionManager = controller->selectionManager();
+            connect(selectionManager, SIGNAL(currentChanged(int,int)), this, SLOT(slotCurrentChanged(int,int)));
+            connect(selectionManager, SIGNAL(selectionChanged(QSet<int>,QSet<int>)), this, SLOT(slotSelectionChanged(QSet<int>,QSet<int>)));
+        }
+
         onControllerChanged(controller, previous);
     }
 }
@@ -918,17 +886,7 @@ void KItemListView::emitOffsetChanges()
 KItemListWidget* KItemListView::createWidget(int index)
 {
     KItemListWidget* widget = m_widgetCreator->create(this);
-    widget->setVisibleRoles(m_visibleRoles);
-    widget->setVisibleRolesSizes(m_visibleRolesSizes);
-
-    KItemListStyleOption option = m_styleOption;
-    if (index == m_controller->selectionManager()->currentItem()) {
-        option.state |= QStyle::State_HasFocus;
-    }
-    widget->setStyleOption(option);
-
-    widget->setIndex(index);
-    widget->setData(m_model->data(index));
+    updateWidgetProperties(widget, index);
     m_visibleItems.insert(index, widget);
 
     if (m_grouped) {
@@ -982,17 +940,7 @@ void KItemListView::setWidgetIndex(KItemListWidget* widget, int index)
 
     const int oldIndex = widget->index();
     m_visibleItems.remove(oldIndex);
-    widget->setVisibleRoles(m_visibleRoles);
-    widget->setVisibleRolesSizes(m_visibleRolesSizes);
-
-    KItemListStyleOption option = m_styleOption;
-    if (index == m_controller->selectionManager()->currentItem()) {
-        option.state |= QStyle::State_HasFocus;
-    }
-    widget->setStyleOption(option);
-
-    widget->setIndex(index);
-    widget->setData(m_model->data(index));
+    updateWidgetProperties(widget, index);
     m_visibleItems.insert(index, widget);
 
     initializeItemListWidget(widget);
@@ -1099,6 +1047,28 @@ void KItemListView::applyDynamicItemSize()
     }
 }
 
+void KItemListView::updateWidgetProperties(KItemListWidget* widget, int index)
+{
+    widget->setVisibleRoles(m_visibleRoles);
+    widget->setVisibleRolesSizes(m_visibleRolesSizes);
+    widget->setStyleOption(m_styleOption);
+
+    const KItemListSelectionManager* selectionManager = m_controller->selectionManager();
+    widget->setCurrent(index == selectionManager->currentItem());
+
+    if (selectionManager->hasSelection()) {
+        const QSet<int> selectedItems = selectionManager->selectedItems();
+        widget->setSelected(selectedItems.contains(index));
+    } else {
+        widget->setSelected(false);
+    }
+
+    widget->setHovered(false);
+
+    widget->setIndex(index);
+    widget->setData(m_model->data(index));
+}
+
 KItemListCreatorBase::~KItemListCreatorBase()
 {
     qDeleteAll(m_recycleableWidgets);
index 81ad52ac3cf5b3f2d342c1ac40725c4b85ded36a..23181db6e81254fbb4a34befe386ae443ec26ce7 100644 (file)
@@ -30,6 +30,7 @@
 #include <kitemviews/kitemlistwidget.h>
 #include <kitemviews/kitemmodelbase.h>
 #include <QGraphicsWidget>
+#include <QSet>
 
 class KItemListController;
 class KItemListWidgetCreatorBase;
@@ -62,6 +63,8 @@ class LIBDOLPHINPRIVATE_EXPORT KItemListView : public QGraphicsWidget
 {
     Q_OBJECT
 
+    Q_PROPERTY(qreal offset READ offset WRITE setOffset)
+
 public:
     KItemListView(QGraphicsWidget* parent = 0);
     virtual ~KItemListView();
@@ -132,6 +135,8 @@ public:
     virtual QSizeF itemSizeHint(int index) const;
     virtual QHash<QByteArray, QSizeF> visibleRoleSizes() const;
 
+    QRectF itemBoundingRect(int index) const;
+
     void beginTransaction();
     void endTransaction();
     bool isTransactionActive() const;
@@ -157,8 +162,6 @@ protected:
 
     virtual bool event(QEvent* event);
     virtual void mousePressEvent(QGraphicsSceneMouseEvent* event);
-    virtual void hoverMoveEvent(QGraphicsSceneHoverEvent* event);
-    virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent* event);
 
     QList<KItemListWidget*> visibleItemListWidgets() const;
 
@@ -169,7 +172,8 @@ protected slots:
                                   const QSet<QByteArray>& roles);
 
 private slots:
-    void currentChanged(int current, int previous);
+    void slotCurrentChanged(int current, int previous);
+    void slotSelectionChanged(const QSet<int>& current, const QSet<int>& previous);
     void slotAnimationFinished(QGraphicsWidget* widget,
                                KItemListViewAnimation::AnimationType type);
     void slotLayoutTimerFinished();
@@ -229,6 +233,12 @@ private:
      */
     void applyDynamicItemSize();
 
+    /**
+     * Helper method for createWidget() and setWidgetIndex() to update the properties
+     * of the itemlist widget.
+     */
+    void updateWidgetProperties(KItemListWidget* widget, int index);
+
 private:
     bool m_grouped;
     int m_activeTransactions; // Counter for beginTransaction()/endTransaction()
index 3f08d9f7a69c801828e52e2c4a5d4fcc9b8ceb1b..ef4c1f797a36156c5bf4120839ccf0407bb4c0fd 100644 (file)
 #include <QPainter>
 #include <QPropertyAnimation>
 #include <QStyle>
+#include <QStyleOption>
 
 KItemListWidget::KItemListWidget(QGraphicsItem* parent) :
     QGraphicsWidget(parent, 0),
     m_index(-1),
+    m_selected(false),
+    m_current(false),
+    m_hovered(false),
     m_data(),
     m_visibleRoles(),
     m_visibleRolesSizes(),
@@ -90,11 +94,21 @@ QHash<QByteArray, QVariant> KItemListWidget::data() const
 void KItemListWidget::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
 {
     Q_UNUSED(option);
+
+    const QRect hoverBounds = hoverBoundingRect().toRect();
+    if (m_selected) {
+        QStyleOptionViewItemV4 viewItemOption;
+        viewItemOption.initFrom(widget);
+        viewItemOption.rect = hoverBounds;
+        viewItemOption.state = QStyle::State_Enabled | QStyle::State_Selected | QStyle::State_Item;
+        viewItemOption.viewItemPosition = QStyleOptionViewItemV4::OnlyOne;
+        widget->style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &viewItemOption, painter, widget);
+    }
+
     if (m_hoverOpacity <= 0.0) {
         return;
     }
 
-    const QRect hoverBounds = hoverBoundingRect().toRect();
     if (!m_hoverCache) {
         m_hoverCache = new QPixmap(hoverBounds.size());
         m_hoverCache->fill(Qt::transparent);
@@ -104,7 +118,7 @@ void KItemListWidget::paint(QPainter* painter, const QStyleOptionGraphicsItem* o
         QStyleOptionViewItemV4 viewItemOption;
         viewItemOption.initFrom(widget);
         viewItemOption.rect = QRect(0, 0, hoverBounds.width(), hoverBounds.height());
-        viewItemOption.state = QStyle::State_Enabled | QStyle::State_MouseOver;
+        viewItemOption.state = QStyle::State_Enabled | QStyle::State_MouseOver | QStyle::State_Item;
         viewItemOption.viewItemPosition = QStyleOptionViewItemV4::OnlyOne;
 
         widget->style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &viewItemOption, &pixmapPainter, widget);
@@ -143,41 +157,75 @@ QHash<QByteArray, QSizeF> KItemListWidget::visibleRolesSizes() const
 void KItemListWidget::setStyleOption(const KItemListStyleOption& option)
 {
     const KItemListStyleOption previous = m_styleOption;
-    if (m_index >= 0) {
-        clearCache();
+    clearCache();
+    m_styleOption = option;
 
-        const bool wasHovered = (previous.state & QStyle::State_MouseOver);
-        m_styleOption = option;
-        const bool isHovered = (m_styleOption.state & QStyle::State_MouseOver);
-
-        if (wasHovered != isHovered) {
-            // The hovering state has been changed. Assure that a fade-animation
-            // is done to the new state.
-            if (!m_hoverAnimation) {
-                m_hoverAnimation = new QPropertyAnimation(this, "hoverOpacity", this);
-                m_hoverAnimation->setDuration(200);
-            }
-            m_hoverAnimation->stop();
+    styleOptionChanged(option, previous);
+}
+
+const KItemListStyleOption& KItemListWidget::styleOption() const
+{
+    return m_styleOption;
+}
+
+void KItemListWidget::setSelected(bool selected)
+{
+    if (m_selected != selected) {
+        m_selected = selected;
+        selectedChanged(selected);
+        update();
+    }
+}
 
-            if (!wasHovered && isHovered) {
-                m_hoverAnimation->setEndValue(1.0);
-            } else {
-                Q_ASSERT(wasHovered && !isHovered);
-                m_hoverAnimation->setEndValue(0.0);
-            }
+bool KItemListWidget::isSelected() const
+{
+    return m_selected;
+}
 
-            m_hoverAnimation->start();
-        }
+void KItemListWidget::setCurrent(bool current)
+{
+    if (m_current != current) {
+        m_current = current;
+        currentChanged(current);
+        update();
+    }
+}
+
+bool KItemListWidget::isCurrent() const
+{
+    return m_current;
+}
+
+void KItemListWidget::setHovered(bool hovered)
+{
+    if (hovered == m_hovered) {
+        return;
+    }
+
+    m_hovered = hovered;
+
+    if (!m_hoverAnimation) {
+        m_hoverAnimation = new QPropertyAnimation(this, "hoverOpacity", this);
+        m_hoverAnimation->setDuration(200);
+    }
+    m_hoverAnimation->stop();
+
+    if (hovered) {
+        m_hoverAnimation->setEndValue(1.0);
     } else {
-        m_styleOption = option;
+        m_hoverAnimation->setEndValue(0.0);
     }
 
-    styleOptionChanged(option, previous);
+    m_hoverAnimation->start();
+
+    hoveredChanged(hovered);
+
+    update();
 }
 
-const KItemListStyleOption& KItemListWidget::styleOption() const
+bool KItemListWidget::isHovered() const
 {
-    return m_styleOption;
+    return m_hovered;
 }
 
 bool KItemListWidget::contains(const QPointF& point) const
@@ -234,6 +282,21 @@ void KItemListWidget::styleOptionChanged(const KItemListStyleOption& current,
     update();
 }
 
+void KItemListWidget::currentChanged(bool current)
+{
+    Q_UNUSED(current);
+}
+
+void KItemListWidget::selectedChanged(bool selected)
+{
+    Q_UNUSED(selected);
+}
+
+void KItemListWidget::hoveredChanged(bool hovered)
+{
+    Q_UNUSED(hovered);
+}
+
 void KItemListWidget::resizeEvent(QGraphicsSceneResizeEvent* event)
 {
     QGraphicsWidget::resizeEvent(event);
index eb2ebf4558b42a3e490dfd892e535d10bff463ef..d655042b8c05b6d41afdd00a2d1e203518645231 100644 (file)
@@ -72,6 +72,15 @@ public:
     void setStyleOption(const KItemListStyleOption& option);
     const KItemListStyleOption& styleOption() const;
 
+    void setSelected(bool selected);
+    bool isSelected() const;
+
+    void setCurrent(bool current);
+    bool isCurrent() const;
+
+    void setHovered(bool hovered);
+    bool isHovered() const;
+
     /**
      * @return True if \a point is inside KItemListWidget::hoverBoundingRect(),
      *         KItemListWidget::selectionToggleRect() or KItemListWidget::expansionToggleRect().
@@ -104,6 +113,9 @@ protected:
     virtual void visibleRolesChanged(const QHash<QByteArray, int>& current, const QHash<QByteArray, int>& previous);
     virtual void visibleRolesSizesChanged(const QHash<QByteArray, QSizeF>& current, const QHash<QByteArray, QSizeF>& previous);
     virtual void styleOptionChanged(const KItemListStyleOption& current, const KItemListStyleOption& previous);
+    virtual void currentChanged(bool current);
+    virtual void selectedChanged(bool selected);
+    virtual void hoveredChanged(bool hovered);
     virtual void resizeEvent(QGraphicsSceneResizeEvent* event);
 
     /**
@@ -120,6 +132,9 @@ private:
     Q_PROPERTY(qreal hoverOpacity READ hoverOpacity WRITE setHoverOpacity)
 
     int m_index;
+    bool m_selected;
+    bool m_current;
+    bool m_hovered;
     QHash<QByteArray, QVariant> m_data;
     QHash<QByteArray, int> m_visibleRoles;
     QHash<QByteArray, QSizeF> m_visibleRolesSizes;
index 4eb96c8fd8d49c91029c84e2f2510fd02ea77005..44135d2f496c3465ac4dd9f4766b1a9925034a3d 100644 (file)
@@ -106,9 +106,46 @@ public:
     virtual QString roleDescription(const QByteArray& role) const;
 
 signals:
+    /**
+     * Is emitted if one or more items have been inserted. Each item-range consists
+     * of:
+     * - an index where items have been inserted
+     * - the number of inserted items.
+     * The index of each item-range represents the index of the model
+     * before the items have been inserted.
+     *
+     * For the item-ranges it is assured that:
+     * - They don't overlap
+     * - The index of item-range n is smaller than the index of item-range n + 1.
+     */
     void itemsInserted(const KItemRangeList& itemRanges);
+
+    /**
+     * Is emitted if one or more items have been removed. Each item-range consists
+     * of:
+     * - an index where items have been inserted
+     * - the number of inserted items.
+     * The index of each item-range represents the index of the model
+     * before the items have been removed.
+     *
+     * For the item-ranges it is assured that:
+     * - They don't overlap
+     * - The index of item-range n is smaller than the index of item-range n + 1.
+     */
     void itemsRemoved(const KItemRangeList& itemRanges);
-    void itemsMoved(const KItemRangeList& itemRanges);
+
+    /**
+     * Is emitted if one ore more items get moved.
+     * @param itemRanges     Item-ranges that get moved to a new position.
+     * @param movedToIndexes New position of the ranges.
+     * It is assured that the itemRanges list has the same size as the movedToIndexes list.
+     *
+     * For the item-ranges it is assured that:
+     * - They don't overlap
+     * - The index of item-range n is smaller than the index of item-range n + 1.
+     */
+    void itemsMoved(const KItemRangeList& itemRanges, const QList<int> movedToIndexes);
+
     void itemsChanged(const KItemRangeList& itemRanges, const QSet<QByteArray>& roles);
 
     void groupRoleChanged(const QByteArray& current, const QByteArray& previous);
index 91b1fee46824fcff16b3bad2ba669e47a8c1e6d1..7090dbce41467cc45302c812b3901e9e56bb602f 100644 (file)
@@ -1,4 +1,4 @@
 File=dolphin_generalsettings.kcfg
-ClassName=GeneralSettings 
-Singleton=false 
+ClassName=GeneralSettings
+Singleton=yes
 Mutators=true
index 9fc0cea3d3f7b0768a9b39163e13efafde5e8847..aae684201c49387f32281a16d3c643fed313136f 100644 (file)
@@ -48,15 +48,12 @@ void DolphinSettings::save()
 
 DolphinSettings::DolphinSettings()
 {
-    m_generalSettings = new GeneralSettings();
+    m_generalSettings = GeneralSettings::self();
     m_placesModel = new KFilePlacesModel();
 }
 
 DolphinSettings::~DolphinSettings()
 {
-    delete m_generalSettings;
-    m_generalSettings = 0;
-
     delete m_placesModel;
     m_placesModel = 0;
 }
index 814304801c3c6c1aa611824b7ff4cae40fadf78f..8a5b070ce2d1a72d23991981913819c36e53dfa8 100644 (file)
@@ -122,7 +122,7 @@ void BehaviorSettingsPage::applySettings()
 
     const bool useGlobalProps = m_globalProps->isChecked();
 
-    GeneralSettings* settings = DolphinSettings::instance().generalSettings();
+    GeneralSettings* settings = GeneralSettings::self();
     settings->setGlobalViewProps(useGlobalProps);
 
     if (useGlobalProps) {
index 5038ee8d7d7a04d9bfedef79aef446d71725f1e6..b35dc3b8b81c3bbb17136e8e398153b3e56379a0 100644 (file)
@@ -1,6 +1,15 @@
 set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} )
 include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BUILD_DIR}/.. ${KDE4_INCLUDES} )
 
+# KItemListSelectionManagerTest
+set(kitemlistselectionmanagertest_SRCS
+    kitemlistselectionmanagertest.cpp
+    ../kitemviews/kitemlistselectionmanager.cpp
+    ../kitemviews/kitemmodelbase.cpp
+)
+kde4_add_unit_test(kitemlistselectionmanagertest TEST ${kitemlistselectionmanagertest_SRCS})
+target_link_libraries(kitemlistselectionmanagertest dolphinprivate ${KDE4_KIO_LIBS} ${QT_QTTEST_LIBRARY})
+
 # KFileItemListViewTest
 set(kfileitemlistviewtest_SRCS
     kfileitemlistviewtest.cpp
index 1b9e1b31264388c0d7f0633c02fd92341d9b61e6..a7493d17f97a92a8d240c9969867f91bb937fb14 100644 (file)
@@ -38,8 +38,6 @@ private slots:
     void init();
     void cleanup();
 
-    void testFeffi();
-
 private:
     KFileItemListView* m_listView;
     KFileItemModel* m_model;
@@ -83,18 +81,6 @@ void KFileItemListViewTest::cleanup()
     m_testDir = 0;
 }
 
-void KFileItemListViewTest::testFeffi()
-{
-    QStringList files;
-    files << "a.txt" << "b.txt" << "c.txt";
-    m_testDir->createFiles(files);
-
-    m_dirLister->openUrl(m_testDir->url());
-    QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
-
-    QCOMPARE(m_model->count(), 3);
-}
-
 QTEST_KDEMAIN(KFileItemListViewTest, GUI)
 
 #include "kfileitemlistviewtest.moc"
index 82fc3fbc0fe78cdda8ded2522fd5f683e52bc3ef..74706d49ae7127d945eac0a2c02ca7a683605f69 100644 (file)
 #include "testdir.h"
 
 namespace {
-    const int DefaultTimeout = 2000;
+    const int DefaultTimeout = 5000;
 };
 
+Q_DECLARE_METATYPE(KItemRangeList)
+
 class KFileItemModelTest : public QObject
 {
     Q_OBJECT
@@ -39,7 +41,8 @@ private slots:
     void testDefaultSortRole();
     void testDefaultGroupRole();
     void testNewItems();
-    void testInsertingItems();
+    void testModelConsistencyWhenInsertingItems();
+    void testItemRangeConsistencyWhenInsertingItems();
 
     void testExpansionLevelsCompare_data();
     void testExpansionLevelsCompare();
@@ -120,9 +123,9 @@ void KFileItemModelTest::testNewItems()
     QVERIFY(isModelConsistent());
 }
 
-void KFileItemModelTest::testInsertingItems()
+void KFileItemModelTest::testModelConsistencyWhenInsertingItems()
 {
-    // QSKIP("Temporary disabled", SkipSingle);
+    QSKIP("Temporary disabled", SkipSingle);
 
     // KFileItemModel prevents that inserting a punch of items sequentially
     // results in an itemsInserted()-signal for each item. Instead internally
@@ -164,6 +167,58 @@ void KFileItemModelTest::testInsertingItems()
     QCOMPARE(m_model->count(), 201);
 }
 
+void KFileItemModelTest::testItemRangeConsistencyWhenInsertingItems()
+{
+    QStringList files;
+    files << "B" << "E" << "G";
+    m_testDir->createFiles(files);
+
+    // Due to inserting the 3 items one item-range with index == 0 and
+    // count == 3 must be given
+    QSignalSpy spy1(m_model, SIGNAL(itemsInserted(KItemRangeList)));
+    m_dirLister->openUrl(m_testDir->url());
+    QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+
+    QCOMPARE(spy1.count(), 1);
+    QList<QVariant> arguments = spy1.takeFirst();
+    KItemRangeList itemRangeList = arguments.at(0).value<KItemRangeList>();
+    QCOMPARE(itemRangeList.count(), 1);
+    KItemRange itemRange = itemRangeList.first();
+    QCOMPARE(itemRange.index, 0);
+    QCOMPARE(itemRange.count, 3);
+
+    // The indexes of the item-ranges must always be related to the model before
+    // the items have been inserted. Having:
+    //   0 1 2
+    //   B E G
+    // and inserting A, C, D, F the resulting model will be:
+    //   0 1 2 3 4 5 6
+    //   A B C D E F G
+    // and the item-ranges must be:
+    //   index: 0, count: 1 for A
+    //   index: 1, count: 2 for B, C
+    //   index: 2, count: 1 for G
+
+    files.clear();
+    files << "A" << "C" << "D" << "F";
+    m_testDir->createFiles(files);
+
+    QSignalSpy spy2(m_model, SIGNAL(itemsInserted(KItemRangeList)));
+    m_dirLister->updateDirectory(m_testDir->url());
+    QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+
+    QCOMPARE(spy2.count(), 1);
+    arguments = spy2.takeFirst();
+    itemRangeList = arguments.at(0).value<KItemRangeList>();
+    QCOMPARE(itemRangeList.count(), 3);
+    QCOMPARE(itemRangeList.at(0).index, 0);
+    QCOMPARE(itemRangeList.at(0).count, 1);
+    QCOMPARE(itemRangeList.at(1).index, 1);
+    QCOMPARE(itemRangeList.at(1).count, 2);
+    QCOMPARE(itemRangeList.at(2).index, 2);
+    QCOMPARE(itemRangeList.at(2).count, 1);
+}
+
 void KFileItemModelTest::testExpansionLevelsCompare_data()
 {
     QTest::addColumn<QString>("urlA");
diff --git a/src/tests/kitemlistselectionmanagertest.cpp b/src/tests/kitemlistselectionmanagertest.cpp
new file mode 100644 (file)
index 0000000..6fdf01b
--- /dev/null
@@ -0,0 +1,172 @@
+/***************************************************************************
+ *   Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.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 <qtest_kde.h>
+
+#include "kitemviews/kitemmodelbase.h"
+#include "kitemviews/kitemlistselectionmanager.h"
+
+class DummyModel : public KItemModelBase
+{
+public:
+    DummyModel();
+    virtual int count() const;
+    virtual QHash<QByteArray, QVariant> data(int index) const;
+};
+
+DummyModel::DummyModel() :
+    KItemModelBase()
+{
+}
+
+int DummyModel::count() const
+{
+    return 100;
+}
+
+QHash<QByteArray, QVariant> DummyModel::data(int index) const
+{
+    Q_UNUSED(index);
+    return QHash<QByteArray, QVariant>();
+}
+
+
+
+class KItemListSelectionManagerTest : public QObject
+{
+    Q_OBJECT
+
+private slots:
+    void init();
+    void cleanup();
+
+    void testConstructor();
+
+    void testSetSelected_data();
+    void testSetSelected();
+    void testItemsInserted();
+    void testItemsRemoved();
+
+private:
+    KItemListSelectionManager* m_selectionManager;
+};
+
+void KItemListSelectionManagerTest::init()
+{
+    m_selectionManager = new KItemListSelectionManager();
+    m_selectionManager->setModel(new DummyModel());
+}
+
+void KItemListSelectionManagerTest::cleanup()
+{
+    delete m_selectionManager->model();
+    delete m_selectionManager;
+    m_selectionManager = 0;
+}
+
+void KItemListSelectionManagerTest::testConstructor()
+{
+    QVERIFY(!m_selectionManager->hasSelection());
+    QCOMPARE(m_selectionManager->selectedItems().count(), 0);
+    QCOMPARE(m_selectionManager->currentItem(), 0);
+    QCOMPARE(m_selectionManager->anchorItem(), -1);
+}
+
+void KItemListSelectionManagerTest::testSetSelected_data()
+{
+    QTest::addColumn<int>("index");
+    QTest::addColumn<int>("count");
+    QTest::addColumn<int>("expectedSelectionCount");
+
+    QTest::newRow("Select all") << 0 << 100 << 100;
+    QTest::newRow("Sub selection 15 items") << 20 << 15 << 15;
+    QTest::newRow("Sub selection 1 item") << 20 << 1 << 1;
+    QTest::newRow("Too small index") << -1 << 100 << 0;
+    QTest::newRow("Too large index") << 100 << 100 << 0;
+    QTest::newRow("Too large count") << 0 << 100000 << 100;
+    QTest::newRow("Too small count") << 0 << 0 << 0;
+}
+
+void KItemListSelectionManagerTest::testSetSelected()
+{
+    QFETCH(int, index);
+    QFETCH(int, count);
+    QFETCH(int, expectedSelectionCount);
+    m_selectionManager->setSelected(index, count);
+    QCOMPARE(m_selectionManager->selectedItems().count(), expectedSelectionCount);
+}
+
+void KItemListSelectionManagerTest::testItemsInserted()
+{
+    // Select items 10 to 12
+    m_selectionManager->setSelected(10, 3);
+    QSet<int> selectedItems = m_selectionManager->selectedItems();
+    QVERIFY(selectedItems.contains(10));
+    QVERIFY(selectedItems.contains(11));
+    QVERIFY(selectedItems.contains(12));
+
+    // Insert items 0 to 4 -> selection must be 15 to 17
+    m_selectionManager->itemsInserted(KItemRangeList() << KItemRange(0, 5));
+    selectedItems = m_selectionManager->selectedItems();
+    QVERIFY(selectedItems.contains(15));
+    QVERIFY(selectedItems.contains(16));
+    QVERIFY(selectedItems.contains(17));
+
+    // Insert 3 items between the selections
+    m_selectionManager->itemsInserted(KItemRangeList() <<
+                                      KItemRange(15, 1) <<
+                                      KItemRange(16, 1) <<
+                                      KItemRange(17, 1));
+    selectedItems = m_selectionManager->selectedItems();
+    QVERIFY(selectedItems.contains(16));
+    QVERIFY(selectedItems.contains(18));
+    QVERIFY(selectedItems.contains(20));
+}
+
+void KItemListSelectionManagerTest::testItemsRemoved()
+{
+    // Select items 10 to 15
+    m_selectionManager->setSelected(10, 6);
+    QSet<int> selectedItems = m_selectionManager->selectedItems();
+    for (int i = 10; i <= 15; ++i) {
+        QVERIFY(selectedItems.contains(i));
+    }
+
+    // Remove items 0 to 4 -> selection must be 5 to 10
+    m_selectionManager->itemsRemoved(KItemRangeList() << KItemRange(0, 5));
+    selectedItems = m_selectionManager->selectedItems();
+    for (int i = 5; i <= 10; ++i) {
+        QVERIFY(selectedItems.contains(i));
+    }
+
+    // Remove the items 6 , 8 and 10
+    m_selectionManager->itemsRemoved(KItemRangeList() <<
+                                     KItemRange(6, 1) <<
+                                     KItemRange(8, 1) <<
+                                     KItemRange(10, 1));
+    selectedItems = m_selectionManager->selectedItems();
+    QCOMPARE(selectedItems.count(), 3);
+    QVERIFY(selectedItems.contains(5));
+    QVERIFY(selectedItems.contains(6));
+    QVERIFY(selectedItems.contains(7));
+}
+
+QTEST_KDEMAIN(KItemListSelectionManagerTest, NoGUI)
+
+#include "kitemlistselectionmanagertest.moc"
index 95a90edd88cd575f1abe08ea3d4d593c658efd4b..7076094b9e54cb5fededecc9f003be3f10cfd869 100644 (file)
@@ -38,6 +38,7 @@
 #include <KLocale>
 #include <kitemviews/kfileitemmodel.h>
 #include <kitemviews/kfileitemlistview.h>
+#include <kitemviews/kitemlistselectionmanager.h>
 #include <kitemviews/kitemlistview.h>
 #include <kitemviews/kitemlistcontroller.h>
 #include <KIO/DeleteJob>
 #include "dolphinnewfilemenuobserver.h"
 #include "dolphin_detailsmodesettings.h"
 #include "dolphin_generalsettings.h"
+#include "dolphinitemlistcontainer.h"
 #include "renamedialog.h"
 #include "settings/dolphinsettings.h"
 #include "viewmodecontroller.h"
 #include "viewproperties.h"
+#include "views/tooltips/tooltipmanager.h"
 #include "zoomlevelinfo.h"
 
-// TODO:
-#include "dolphinitemlistcontainer.h"
-
 namespace {
     const int MaxModeEnum = DolphinView::CompactView;
     const int MaxSortingEnum = DolphinView::SortByPath;
@@ -76,7 +76,6 @@ DolphinView::DolphinView(const KUrl& url, QWidget* parent) :
     m_active(true),
     m_tabsForFiles(false),
     m_assureVisibleCurrentIndex(false),
-    m_expanderActive(false),
     m_isFolderWritable(true),
     m_url(url),
     m_mode(DolphinView::IconsView),
@@ -84,12 +83,12 @@ DolphinView::DolphinView(const KUrl& url, QWidget* parent) :
     m_topLayout(0),
     m_dirLister(0),
     m_container(0),
+    m_toolTipManager(0),
     m_selectionChangedTimer(0),
-    m_activeItemUrl(),
+    m_currentItemIndex(-1),
     m_restoredContentsPosition(),
     m_createdItemUrl(),
-    m_selectedItems(),
-    m_newFileNames()
+    m_selectedItems()
 {
     m_topLayout = new QVBoxLayout(this);
     m_topLayout->setSpacing(0);
@@ -167,6 +166,14 @@ DolphinView::DolphinView(const KUrl& url, QWidget* parent) :
     connect(controller, SIGNAL(itemClicked(int,Qt::MouseButton)),
             this, SLOT(slotItemClicked(int,Qt::MouseButton)));
     connect(controller, SIGNAL(itemExpansionToggleClicked(int)), this, SLOT(slotItemExpansionToggleClicked(int)));
+    connect(controller, SIGNAL(itemHovered(int)), this, SLOT(slotItemHovered(int)));
+    connect(controller, SIGNAL(itemUnhovered(int)), this, SLOT(slotItemUnhovered(int)));
+
+    KItemListSelectionManager* selectionManager = controller->selectionManager();
+    connect(selectionManager, SIGNAL(selectionChanged(QSet<int>,QSet<int>)),
+            this, SLOT(slotSelectionChanged(QSet<int>,QSet<int>)));
+
+    m_toolTipManager = new ToolTipManager(this);
 
     applyViewProperties();
     m_topLayout->addWidget(m_container);
@@ -211,7 +218,6 @@ void DolphinView::setActive(bool active)
         //    view->setFocus();
         //}
         emit activated();
-        emitSelectionChangedSignal();
         emit writeStateChanged(m_isFolderWritable);
     }
 
@@ -261,35 +267,23 @@ KFileItemList DolphinView::items() const
 
 KFileItemList DolphinView::selectedItems() const
 {
-    return KFileItemList();
-/*    KFileItemList itemList;
-    const QAbstractItemView* view = m_viewAccessor.itemView();
-    if (!view) {
-        return itemList;
-    }
-
-    const QItemSelection selection = m_viewAccessor.proxyModel()->mapSelectionToSource(view->selectionModel()->selection());
+    const KFileItemModel* model = fileItemModel();
+    const KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager();
+    const QSet<int> selectedIndexes = selectionManager->selectedItems();
 
-    const QModelIndexList indexList = selection.indexes();
-    foreach (const QModelIndex &index, indexList) {
-        KFileItem item = m_viewAccessor.dirModel()->itemForIndex(index);
-        if (!item.isNull()) {
-            itemList.append(item);
-        }
+    KFileItemList selectedItems;
+    QSetIterator<int> it(selectedIndexes);
+    while (it.hasNext()) {
+        const int index = it.next();
+        selectedItems.append(model->fileItem(index));
     }
-
-    return itemList;*/
+    return selectedItems;
 }
 
 int DolphinView::selectedItemsCount() const
 {
-    return 0;
-    /*const QAbstractItemView* view = m_viewAccessor.itemView();
-    if (!view) {
-        return 0;
-    }
-
-    return view->selectionModel()->selectedIndexes().count();*/
+    const KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager();
+    return selectionManager->selectedItems().count();
 }
 
 void DolphinView::markUrlsAsSelected(const QList<KUrl>& urls)
@@ -509,11 +503,12 @@ void DolphinView::setUrl(const KUrl& url)
     }
 
     emit urlAboutToBeChanged(url);
-
-    const bool hadSelection = hasSelection();
-    m_newFileNames.clear();
     m_url = url;
 
+    if (GeneralSettings::showToolTips()) {
+        m_toolTipManager->hideToolTip();
+    }
+
     // It is important to clear the items from the model before
     // applying the view properties, otherwise expensive operations
     // might be done on the existing items although they get cleared
@@ -523,36 +518,28 @@ void DolphinView::setUrl(const KUrl& url)
     loadDirectory(url);
 
     emit urlChanged(url);
-    if (hadSelection || hasSelection()) {
-        emitSelectionChangedSignal();
-    }
 }
 
 void DolphinView::selectAll()
 {
-    //m_viewAccessor.itemView()->selectAll();
+    KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager();
+    selectionManager->setSelected(0, fileItemModel()->count());
 }
 
 void DolphinView::invertSelection()
 {
-/*    // Implementation note: Using selectionModel->select(selection, QItemSelectionModel::Toggle) does not
-    // work, as QItemSelectionModel::hasSelection() provides invalid values in this case. This might be a Qt-issue -
-    // when changing the implementation with an updated Qt-version don't forget to run the Dolphin-unit-tests that
-    // verify this usecase.
-    const KFileItemList selItems = selectedItems();
-    clearSelection();
-
-    QItemSelection invertedSelection;
-    foreach (const KFileItem& item, items()) {
-        if (!selItems.contains(item)) {
-            const QModelIndex index = m_viewAccessor.proxyModel()->mapFromSource(m_viewAccessor.dirModel()->indexForItem(item));
-            invertedSelection.select(index, index);
-        }
-    }
+     KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager();
+     const QSet<int> selectedItems = selectionManager->selectedItems();
+     QSet<int> invertedSelectedItems;
 
-    QItemSelectionModel* selectionModel = m_viewAccessor.itemView()->selectionModel();
-    selectionModel->select(invertedSelection, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Current);
-    */
+     const int maxIndex = fileItemModel()->count() - 1;
+     for (int i = 0; i <= maxIndex; ++i) {
+         if (!selectedItems.contains(i)) {
+             invertedSelectedItems.insert(i);
+         }
+     }
+
+     selectionManager->setSelectedItems(invertedSelectedItems);
 }
 
 void DolphinView::clearSelection()
@@ -711,23 +698,54 @@ void DolphinView::slotItemClicked(int index, Qt::MouseButton button)
             emit tabRequested(item.url());
         }
     } else if (button & Qt::RightButton) {
-        // TODO: attach customActions for the details-view
+        if (GeneralSettings::showToolTips()) {
+            m_toolTipManager->hideToolTip();
+        }
         emit requestContextMenu(item, url(), QList<QAction*>());
     }
 }
 
 void DolphinView::slotItemExpansionToggleClicked(int index)
 {
+    // TODO: When doing a model->setExpanded(false) it should
+    // be checked here whether the current index is part of the
+    // closed sub-tree. If this is the case, the current index
+    // should be adjusted to the parent index.
     KFileItemModel* model = fileItemModel();
     const bool expanded = model->isExpanded(index);
     model->setExpanded(index, !expanded);
 }
 
-void DolphinView::slotSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected)
+void DolphinView::slotItemHovered(int index)
+{
+    const KFileItem item = fileItemModel()->fileItem(index);
+
+    if (GeneralSettings::showToolTips()) {
+        QRectF itemRect = m_container->controller()->view()->itemBoundingRect(index);
+        const QPoint pos = m_container->mapToGlobal(itemRect.topLeft().toPoint());
+        itemRect.moveTo(pos);
+
+        m_toolTipManager->showToolTip(item, itemRect);
+    }
+
+    emit requestItemInfo(item);
+}
+
+void DolphinView::slotItemUnhovered(int index)
+{
+    Q_UNUSED(index);
+    if (GeneralSettings::showToolTips()) {
+        m_toolTipManager->hideToolTip();
+    }
+    emit requestItemInfo(KFileItem());
+}
+
+void DolphinView::slotSelectionChanged(const QSet<int>& current, const QSet<int>& previous)
 {
-    const int count = selectedItemsCount();
-    const bool selectionStateChanged = ((count >  0) && (selected.count() == count)) ||
-                                       ((count == 0) && !deselected.isEmpty());
+    const int currentCount = current.count();
+    const int previousCount = previous.count();
+    const bool selectionStateChanged = (currentCount == 0 && previousCount  > 0) ||
+                                       (currentCount >  0 && previousCount == 0);
 
     // If nothing has been selected before and something got selected (or if something
     // was selected before and now nothing is selected) the selectionChangedSignal must
@@ -745,19 +763,12 @@ void DolphinView::emitSelectionChangedSignal()
 void DolphinView::openContextMenu(const QPoint& pos,
                                   const QList<QAction*>& customActions)
 {
-    Q_UNUSED(pos);
     KFileItem item;
-    /*QAbstractItemView* view = m_viewAccessor.itemView();
-    QModelIndex index;
-    if (view) {
-        index = view->indexAt(pos);
+    const int index = m_container->controller()->view()->itemAt(pos);
+    if (index >= 0) {
+        item = fileItemModel()->fileItem(index);
     }
 
-    if (index.isValid() && (index.column() == DolphinModel::Name)) {
-        const QModelIndex dolphinModelIndex = m_viewAccessor.proxyModel()->mapToSource(index);
-        item = m_viewAccessor.dirModel()->itemForIndex(dolphinModelIndex);
-    }*/
-
     emit requestContextMenu(item, url(), customActions);
 }
 
@@ -767,7 +778,7 @@ void DolphinView::dropUrls(const KFileItem& destItem,
 {
     Q_UNUSED(destItem);
     Q_UNUSED(destPath);
-    addNewFileNames(event->mimeData());
+    markPastedUrlsAsSelected(event->mimeData());
     //DragAndDropHelper::instance().dropUrls(destItem, destPath, event, this);
 }
 
@@ -824,8 +835,8 @@ bool DolphinView::itemsExpandable() const
 
 void DolphinView::restoreState(QDataStream& stream)
 {
-    // Restore the URL of the current item that had the keyboard focus
-    stream >> m_activeItemUrl;
+    // Restore the current item that had the keyboard focus
+    stream >> m_currentItemIndex;
 
     // Restore the view position
     stream >> m_restoredContentsPosition;
@@ -845,20 +856,13 @@ void DolphinView::restoreState(QDataStream& stream)
 
 void DolphinView::saveState(QDataStream& stream)
 {
-    // Save the URL of the current item that has the keyboard focus
-
-    KUrl currentItemUrl;
-    //if (!currentItem.isNull()) {
-    //    currentItemUrl = currentItem.url();
-    //}
-
-    stream << currentItemUrl;
+    // Save the current item that has the keyboard focus
+    stream << m_container->controller()->selectionManager()->currentItem();
 
     // Save view position
     const qreal x = m_container->horizontalScrollBar()->value();
     const qreal y = m_container->verticalScrollBar()->value();
     stream << QPoint(x, y);
-    kDebug() << "saving view state" << QPoint(x, y);
 
     // Save expanded folders (only relevant for the details view - the set will be empty in other view modes)
     //stream << m_viewAccessor.expandedUrls();
@@ -866,9 +870,7 @@ void DolphinView::saveState(QDataStream& stream)
 
 bool DolphinView::hasSelection() const
 {
-    //const QAbstractItemView* view = m_viewAccessor.itemView();
-    //return view && view->selectionModel()->hasSelection();
-    return false;
+    return m_container->controller()->selectionManager()->hasSelection();
 }
 
 KFileItem DolphinView::rootItem() const
@@ -907,8 +909,14 @@ void DolphinView::slotRedirection(const KUrl& oldUrl, const KUrl& newUrl)
     }
 }
 
-void DolphinView::restoreContentsPosition()
+void DolphinView::updateViewState()
 {
+    if (m_currentItemIndex >= 0) {
+        KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager();
+        selectionManager->setCurrentItem(m_currentItemIndex);
+        m_currentItemIndex =-1;
+    }
+
     if (!m_restoredContentsPosition.isNull()) {
         const int x = m_restoredContentsPosition.x();
         const int y = m_restoredContentsPosition.y();
@@ -917,13 +925,23 @@ void DolphinView::restoreContentsPosition()
         m_container->horizontalScrollBar()->setValue(x);
         m_container->verticalScrollBar()->setValue(y);
     }
-}
 
-/*void DolphinView::slotUrlChangeRequested(const KUrl& url)
-{
-    m_viewModeController->setUrl(url);
-    updateWritableState();
-}*/
+    if (!m_selectedItems.isEmpty()) {
+        KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager();
+        QSet<int> selectedItems = selectionManager->selectedItems();
+        const KFileItemModel* model = fileItemModel();
+
+        foreach (const KFileItem& selectedItem, m_selectedItems) {
+            const int index = model->index(selectedItem);
+            if (index >= 0) {
+                selectedItems.insert(index);
+            }
+        }
+
+        selectionManager->setSelectedItems(selectedItems);
+        m_selectedItems.clear();
+    }
+}
 
 void DolphinView::showHoverInformation(const KFileItem& item)
 {
@@ -958,83 +976,17 @@ void DolphinView::slotDirListerStarted(const KUrl& url)
 
 void DolphinView::slotDirListerCompleted()
 {
-    if (!m_expanderActive) {
-        slotLoadingCompleted();
-    }
+    // Update the view-state. This has to be done using a Qt::QueuedConnection
+    // because the view might not be in its final state yet (the view also
+    // listens to the completed()-signal from KDirLister and the order of
+    // of slots is undefined).
+    QTimer::singleShot(0, this, SLOT(updateViewState()));
 
-    if (!m_newFileNames.isEmpty()) {
-        // select all newly added items created by a paste operation or
-        // a drag & drop operation, and clear the previous selection
-        /*QAbstractItemView* view = m_viewAccessor.itemView();
-        if (view) {
-            view->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);
-                }
-            }
-            view->selectionModel()->select(selection, QItemSelectionModel::Select);
-        }*/
-
-        m_newFileNames.clear();
-    }
+    emit finishedPathLoading(url());
 
     updateWritableState();
 }
 
-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();
-            if (view) {
-                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)) {
-                const QModelIndex index = m_viewAccessor.proxyModel()->mapFromSource(m_viewAccessor.dirModel()->indexForItem(item));
-                newSelection.select(index, index);
-            }
-        }
-        QAbstractItemView* view = m_viewAccessor.itemView();
-        if (view) {
-            view->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.
-    QTimer::singleShot(0, this, SLOT(restoreContentsPosition()));
-
-    emit finishedPathLoading(url());
-}
-
 void DolphinView::slotRefreshItems()
 {
     if (m_assureVisibleCurrentIndex) {
@@ -1172,7 +1124,7 @@ void DolphinView::applyAdditionalInfoListToView()
 
 void DolphinView::pasteToUrl(const KUrl& url)
 {
-    addNewFileNames(QApplication::clipboard()->mimeData());
+    markPastedUrlsAsSelected(QApplication::clipboard()->mimeData());
     KonqOperations::doPaste(this, url);
 }
 
@@ -1213,12 +1165,10 @@ QMimeData* DolphinView::selectionMimeData() const
     return 0;
 }
 
-void DolphinView::addNewFileNames(const QMimeData* mimeData)
+void DolphinView::markPastedUrlsAsSelected(const QMimeData* mimeData)
 {
     const KUrl::List urls = KUrl::List::fromMimeData(mimeData);
-    foreach (const KUrl& url, urls) {
-        m_newFileNames.insert(url.fileName());
-    }
+    markUrlsAsSelected(urls);
 }
 
 QItemSelection DolphinView::childrenMatchingPattern(const QModelIndex& parent, const QRegExp& pattern) const
@@ -1252,7 +1202,7 @@ void DolphinView::updateWritableState()
     const bool wasFolderWritable = m_isFolderWritable;
     m_isFolderWritable = true;
 
-    const KFileItem item; // = m_viewAccessor.dirLister()->rootItem();
+    const KFileItem item = m_dirLister->rootItem();
     if (!item.isNull()) {
         KFileItemListProperties capabilities(KFileItemList() << item);
         m_isFolderWritable = capabilities.supportsWriting();
index c9be8a56a1eed1b0ead6033b07c6561d6a6d4d4f..f49bd3f7ba409b5a9ac604cfdd547a776a484f61 100644 (file)
@@ -47,6 +47,7 @@ class KAction;
 class KActionCollection;
 class KFileItemModel;
 class KUrl;
+class ToolTipManager;
 class ViewProperties;
 class QRegExp;
 
@@ -553,17 +554,18 @@ private slots:
     void activate();
 
     void slotItemClicked(int index, Qt::MouseButton button);
-
     void slotItemExpansionToggleClicked(int index);
+    void slotItemHovered(int index);
+    void slotItemUnhovered(int index);
 
     /**
      * Emits the signal \a selectionChanged() with a small delay. This is
-     * because getting all file items for the signal can be an expensive
+     * because getting all file items for the selection 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);
+    void slotSelectionChanged(const QSet<int>& current, const QSet<int>& previous);
 
     /**
      * Is called by emitDelayedSelectionChangedSignal() and emits the
@@ -637,12 +639,6 @@ private slots:
      */
     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.
      */
@@ -670,9 +666,10 @@ private slots:
     void slotRedirection(const KUrl& oldUrl, const KUrl& newUrl);
 
     /**
-     * Restores the contents position, if history information about the old position is available.
+     * Applies the state that has been restored by restoreViewState()
+     * to the view.
      */
-    void restoreContentsPosition();
+    void updateViewState();
 
     //void slotUrlChangeRequested(const KUrl& url);
 
@@ -717,11 +714,11 @@ private:
 
     /**
      * 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().
+     * operation and URLs from \a mimeData as selected.
+     * This allows to select all newly pasted
+     * items in restoreViewState().
      */
-    void addNewFileNames(const QMimeData* mimeData);
+    void markPastedUrlsAsSelected(const QMimeData* mimeData);
 
     /**
      * Helper method for DolphinView::setItemSelectionEnabled(): Returns the selection for
@@ -742,7 +739,6 @@ private:
     bool m_active : 1;
     bool m_tabsForFiles : 1;
     bool m_assureVisibleCurrentIndex : 1;
-    bool m_expanderActive : 1;
     bool m_isFolderWritable : 1;
 
     KUrl m_url;
@@ -754,20 +750,15 @@ private:
     DolphinDirLister* m_dirLister;
     DolphinItemListContainer* m_container;
 
+    ToolTipManager* m_toolTipManager;
+
     QTimer* m_selectionChangedTimer;
 
-    KUrl m_activeItemUrl;
+    int m_currentItemIndex;
     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<QString> m_newFileNames;
-
     // For unit tests
     friend class TestBase;
     friend class DolphinDetailsViewTest;
index 8f18dbde4062aa0daa84e8ecb84b005d602d82f3..df89a882e6327900d11d8e0b156abdad18174fef 100644 (file)
 #include "filemetadatatooltip.h"
 #include <KIcon>
 #include <KIO/PreviewJob>
-#include <KSharedConfig>
 
 #include <QApplication>
 #include <QDesktopWidget>
 #include <QLayout>
 #include <QScrollArea>
 #include <QScrollBar>
+#include <QStyle>
 #include <QTimer>
 
 ToolTipManager::ToolTipManager(QWidget* parent) :
     QObject(parent),
-    m_view(parent),
+    m_parentWidget(parent),
     m_showToolTipTimer(0),
     m_contentRetrievalTimer(0),
     m_fileMetaDataToolTip(0),
@@ -43,13 +43,6 @@ ToolTipManager::ToolTipManager(QWidget* parent) :
     m_item(),
     m_itemRect()
 {
-    //m_dolphinModel = static_cast<DolphinModel*>(m_proxyModel->sourceModel());
-    //connect(parent, SIGNAL(entered(QModelIndex)),
-    //        this, SLOT(requestToolTip(QModelIndex)));
-    //connect(parent, SIGNAL(viewportEntered()),
-    //        this, SLOT(hideToolTip()));
-
-    // Initialize timers
     m_showToolTipTimer = new QTimer(this);
     m_showToolTipTimer->setSingleShot(true);
     m_showToolTipTimer->setInterval(500);
@@ -61,22 +54,36 @@ ToolTipManager::ToolTipManager(QWidget* parent) :
     connect(m_contentRetrievalTimer, SIGNAL(timeout()), this, SLOT(startContentRetrieval()));
 
     Q_ASSERT(m_contentRetrievalTimer->interval() < m_showToolTipTimer->interval());
-
-    // When the mousewheel is used, the items don't get a hovered indication
-    // (Qt-issue #200665). To assure that the tooltip still gets hidden,
-    // the scrollbars are observed.
-    /*connect(parent->horizontalScrollBar(), SIGNAL(valueChanged(int)),
-            this, SLOT(hideToolTip()));
-    connect(parent->verticalScrollBar(), SIGNAL(valueChanged(int)),
-            this, SLOT(hideToolTip()));*/
-
-    Q_ASSERT(m_view);
-    //m_view->viewport()->installEventFilter(this);
-    //m_view->installEventFilter(this);
 }
 
 ToolTipManager::~ToolTipManager()
 {
+    delete m_fileMetaDataToolTip;
+    m_fileMetaDataToolTip = 0;
+}
+
+void ToolTipManager::showToolTip(const KFileItem& item, const QRectF& itemRect)
+{
+    hideToolTip();
+
+    m_itemRect = itemRect.toRect();
+
+    const int margin = toolTipMargin();
+    m_itemRect.adjust(-margin, -margin, margin, margin);
+    m_item = item;
+
+    // Only start the retrieving of the content, when the mouse has been over this
+    // item for 200 milliseconds. This prevents a lot of useless preview jobs and
+    // meta data retrieval, when passing rapidly over a lot of items.
+    Q_ASSERT(!m_fileMetaDataToolTip);
+    m_fileMetaDataToolTip = new FileMetaDataToolTip(m_parentWidget);
+    connect(m_fileMetaDataToolTip, SIGNAL(metaDataRequestFinished(KFileItemList)),
+            this, SLOT(slotMetaDataRequestFinished()));
+
+    m_contentRetrievalTimer->start();
+    m_showToolTipTimer->start();
+    m_toolTipRequested = true;
+    Q_ASSERT(!m_metaDataRequested);
 }
 
 void ToolTipManager::hideToolTip()
@@ -91,56 +98,10 @@ void ToolTipManager::hideToolTip()
     m_showToolTipTimer->stop();
     m_contentRetrievalTimer->stop();
 
-    delete m_fileMetaDataToolTip;
-    m_fileMetaDataToolTip = 0;
-}
-
-
-bool ToolTipManager::eventFilter(QObject* watched, QEvent* event)
-{
-    /*if (watched == m_view->viewport()) {
-        switch (event->type()) {
-        case QEvent::Leave:
-        case QEvent::MouseButtonPress:
-            hideToolTip();
-            break;
-        default:
-            break;
-        }
-    } else if ((watched == m_view) && (event->type() == QEvent::KeyPress)) {
-        hideToolTip();
-    }*/
-
-    return QObject::eventFilter(watched, event);
-}
-
-void ToolTipManager::requestToolTip(const QModelIndex& index)
-{
-    Q_UNUSED(index);
-    hideToolTip();
-
-    // Only request a tooltip for the name column and when no selection or
-    // drag & drop operation is done (indicated by the left mouse button)
-    if (!(QApplication::mouseButtons() & Qt::LeftButton)) {
-        m_itemRect = QRect(); //m_view->visualRect(index);
-        const QPoint pos; // = m_view->viewport()->mapToGlobal(m_itemRect.topLeft());
-        m_itemRect.moveTo(pos);
-
-        //const QModelIndex dirIndex = m_proxyModel->mapToSource(index);
-        //m_item = m_dolphinModel->itemForIndex(dirIndex);
-
-        // Only start the retrieving of the content, when the mouse has been over this
-        // item for 200 milliseconds. This prevents a lot of useless preview jobs and
-        // meta data retrieval, when passing rapidly over a lot of items.
-        Q_ASSERT(!m_fileMetaDataToolTip);
-        m_fileMetaDataToolTip = new FileMetaDataToolTip(m_view);
-        connect(m_fileMetaDataToolTip, SIGNAL(metaDataRequestFinished(KFileItemList)),
-                this, SLOT(slotMetaDataRequestFinished()));
-
-        m_contentRetrievalTimer->start();
-        m_showToolTipTimer->start();
-        m_toolTipRequested = true;
-        Q_ASSERT(!m_metaDataRequested);
+    if (m_fileMetaDataToolTip) {
+        m_fileMetaDataToolTip->hide();
+        delete m_fileMetaDataToolTip;
+        m_fileMetaDataToolTip = 0;
     }
 }
 
@@ -223,10 +184,6 @@ void ToolTipManager::showToolTip()
         m_appliedWaitCursor = false;
     }
 
-    if (QApplication::mouseButtons() & Qt::LeftButton) {
-        return;
-    }
-
     if (m_fileMetaDataToolTip->preview().isNull() || m_metaDataRequested) {
         Q_ASSERT(!m_appliedWaitCursor);
         QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
@@ -259,7 +216,7 @@ void ToolTipManager::showToolTip()
     // It must be assured that:
     // - the content is fully visible
     // - the content is not drawn inside m_itemRect
-    const int margin = 3;
+    const int margin = toolTipMargin();
     const bool hasRoomToLeft  = (m_itemRect.left()   - size.width()  - margin >= screen.left());
     const bool hasRoomToRight = (m_itemRect.right()  + size.width()  + margin <= screen.right());
     const bool hasRoomAbove   = (m_itemRect.top()    - size.height() - margin >= screen.top());
@@ -300,4 +257,10 @@ void ToolTipManager::showToolTip()
     m_toolTipRequested = false;
 }
 
+int ToolTipManager::toolTipMargin() const
+{
+    const int margin = m_parentWidget->style()->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth);
+    return qMax(4, margin);
+}
+
 #include "tooltipmanager.moc"
index 11ef3d3aca33b17cb31b28654e63e3a7ac118de8..b13641109f67970f26c9d49ca9524ea025ab9ddb 100644 (file)
@@ -47,19 +47,20 @@ public:
     explicit ToolTipManager(QWidget* parent);
     virtual ~ToolTipManager();
 
-public slots:
     /**
-     * Hides the currently shown tooltip. Invoking this method is
-     * only needed when the tooltip should be hidden although
-     * an item is hovered.
+     * Triggers the showing of the tooltip for the item \p item
+     * where the item has the maximum boundaries of \p itemRect.
+     * The tooltip manager takes care that the tooltip is shown
+     * slightly delayed.
      */
-    void hideToolTip();
+    void showToolTip(const KFileItem& item, const QRectF& itemRect);
 
-protected:
-    virtual bool eventFilter(QObject* watched, QEvent* event);
+    /**
+     * Hides the currently shown tooltip.
+     */
+    void hideToolTip();
 
 private slots:
-    void requestToolTip(const QModelIndex& index);
     void startContentRetrieval();
     void setPreviewPix(const KFileItem& item, const QPixmap& pix);
     void previewFailed();
@@ -67,9 +68,10 @@ private slots:
     void showToolTip();
 
 private:
-    QWidget* m_view;
-    DolphinModel* m_dolphinModel;
-    DolphinSortFilterProxyModel* m_proxyModel;
+    int toolTipMargin() const;
+
+private:
+    QWidget* m_parentWidget;
 
     /// Timeout from requesting a tooltip until the tooltip
     /// should be shown