Date: prev next · Thread: first prev next last
2013 Archives by date, by thread · List index


Hi,

I have submitted a patch for review:

    https://gerrit.libreoffice.org/3260

To pull it, you can do:

    git pull ssh://gerrit.libreoffice.org:29418/core refs/changes/60/3260/1

fdo#61390 - Thumbnail navigation by shift-click and shift-keyboard.

Change-Id: I0b107d0918e1914709de31fd52cd11480e7fd419
---
M sfx2/inc/sfx2/thumbnailview.hxx
M sfx2/source/control/thumbnailview.cxx
2 files changed, 189 insertions(+), 10 deletions(-)



diff --git a/sfx2/inc/sfx2/thumbnailview.hxx b/sfx2/inc/sfx2/thumbnailview.hxx
index 6d9f30e..1286385 100644
--- a/sfx2/inc/sfx2/thumbnailview.hxx
+++ b/sfx2/inc/sfx2/thumbnailview.hxx
@@ -305,6 +305,7 @@
 
     ValueItemList mItemList;
     ValueItemList mFilteredItemList; ///< Cache to store the filtered items
+    ValueItemList::iterator mpStartSelRange;
     ScrollBar* mpScrBar;
     Rectangle maItemListRect;
     long mnHeaderHeight;
diff --git a/sfx2/source/control/thumbnailview.cxx b/sfx2/source/control/thumbnailview.cxx
index 725520c..8d03d5a 100644
--- a/sfx2/source/control/thumbnailview.cxx
+++ b/sfx2/source/control/thumbnailview.cxx
@@ -10,6 +10,8 @@
 #include <sfx2/thumbnailview.hxx>
 #include <sfx2/thumbnailviewitem.hxx>
 
+#include <utility>
+
 #include "thumbnailviewacc.hxx"
 
 #include <basegfx/color/bcolortools.hxx>
@@ -84,7 +86,20 @@
 void ThumbnailView::AppendItem(ThumbnailViewItem *pItem)
 {
     if (maFilterFunc(pItem))
+    {
+        // Save current start,end range, iterator might get invalidated
+        size_t nSelStartPos = 0;
+        ThumbnailViewItem *pSelStartItem = NULL;
+
+        if (mpStartSelRange != mFilteredItemList.end())
+        {
+            pSelStartItem = *mpStartSelRange;
+            nSelStartPos = mpStartSelRange - mFilteredItemList.begin();
+        }
+
         mFilteredItemList.push_back(pItem);
+        mpStartSelRange = pSelStartItem != NULL ? mFilteredItemList.begin() + nSelStartPos : 
mFilteredItemList.end();
+    }
 
     mItemList.push_back(pItem);
 }
@@ -107,6 +122,7 @@
     mbHasVisibleItems   = false;
     maFilterFunc = ViewFilterAll();
     maColor = GetSettings().GetStyleSettings().GetFieldColor();
+    mpStartSelRange = mFilteredItemList.end();
 
     // Create the processor and process the primitives
     const drawinglayer::geometry::ViewInformation2D aNewViewInfos;
@@ -145,6 +161,8 @@
 
     mItemList.clear();
     mFilteredItemList.clear();
+
+    mpStartSelRange = mFilteredItemList.end();
 }
 
 void ThumbnailView::ImplInitSettings( bool bFont, bool bForeground, bool bBackground )
@@ -398,9 +416,9 @@
 
     if ( maItemListRect.IsInside( rPos ) )
     {
-        for (size_t i = 0; i < mItemList.size(); ++i)
+        for (size_t i = 0; i < mFilteredItemList.size(); ++i)
         {
-            if (mItemList[i]->isVisible() && mItemList[i]->getDrawArea().IsInside(rPos))
+            if (mFilteredItemList[i]->isVisible() && 
mFilteredItemList[i]->getDrawArea().IsInside(rPos))
                 return i;
         }
 
@@ -417,7 +435,7 @@
 
 ThumbnailViewItem* ThumbnailView::ImplGetItem( size_t nPos )
 {
-    return ( nPos < mItemList.size() ) ? mItemList[nPos] : NULL;
+    return ( nPos < mFilteredItemList.size() ) ? mFilteredItemList[nPos] : NULL;
 }
 
 sal_uInt16 ThumbnailView::ImplGetVisibleItemCount() const
@@ -505,39 +523,68 @@
         }
     }
 
+    bool bValidRange = false;
+    bool bHasSelRange = mpStartSelRange != mFilteredItemList.end();
+    size_t nNextPos = nLastPos;
     KeyCode aKeyCode = rKEvt.GetKeyCode();
     ThumbnailViewItem* pNext = NULL;
+
+    if (aKeyCode.IsShift() && bHasSelRange)
+    {
+        //If the last elemented selected is the start range position
+        //search for the first selected item
+        size_t nSelPos = mpStartSelRange - mFilteredItemList.begin();
+
+        if (nLastPos == nSelPos)
+        {
+            while (nLastPos && mFilteredItemList[nLastPos-1]->isSelected())
+                --nLastPos;
+        }
+    }
+
     switch ( aKeyCode.GetCode() )
     {
         case KEY_RIGHT:
             {
-                size_t nNextPos = nLastPos;
                 if ( bFoundLast && nLastPos < mFilteredItemList.size( ) - 1 )
+                {
+                    bValidRange = true;
                     nNextPos = nLastPos + 1;
+                }
+
                 pNext = mFilteredItemList[nNextPos];
             }
             break;
         case KEY_LEFT:
             {
-                size_t nNextPos = nLastPos;
                 if ( nLastPos > 0 )
+                {
+                    bValidRange = true;
                     nNextPos = nLastPos - 1;
+                }
+
                 pNext = mFilteredItemList[nNextPos];
             }
             break;
         case KEY_DOWN:
             {
-                size_t nNextPos = nLastPos;
                 if ( bFoundLast && nLastPos < mFilteredItemList.size( ) - mnCols )
+                {
+                    bValidRange = true;
                     nNextPos = nLastPos + mnCols;
+                }
+
                 pNext = mFilteredItemList[nNextPos];
             }
             break;
         case KEY_UP:
             {
-                size_t nNextPos = nLastPos;
                 if ( nLastPos >= mnCols )
+                {
+                    bValidRange = true;
                     nNextPos = nLastPos - mnCols;
+                }
+
                 pNext = mFilteredItemList[nNextPos];
             }
             break;
@@ -552,8 +599,67 @@
 
     if ( pNext )
     {
-        deselectItems();
-        SelectItem(pNext->mnId);
+        if (aKeyCode.IsShift() && bValidRange)
+        {
+            std::pair<size_t,size_t> aRange;
+            size_t nSelPos = mpStartSelRange - mFilteredItemList.begin();
+
+            if (nLastPos < nSelPos)
+            {
+                if (nNextPos > nLastPos)
+                {
+                    if ( nNextPos > nSelPos)
+                        aRange = std::make_pair(nLastPos,nNextPos);
+                    else
+                        aRange = std::make_pair(nLastPos,nNextPos-1);
+                }
+                else
+                    aRange = std::make_pair(nNextPos,nLastPos-1);
+            }
+            else if (nLastPos == nSelPos)
+            {
+                if (nNextPos > nLastPos)
+                    aRange = std::make_pair(nLastPos+1,nNextPos);
+                else
+                    aRange = std::make_pair(nNextPos,nLastPos-1);
+            }
+            else
+            {
+                if (nNextPos > nLastPos)
+                    aRange = std::make_pair(nLastPos+1,nNextPos);
+                else
+                {
+                    if ( nNextPos < nSelPos)
+                        aRange = std::make_pair(nNextPos,nLastPos);
+                    else
+                        aRange = std::make_pair(nNextPos+1,nLastPos);
+                }
+            }
+
+            for (size_t i = aRange.first; i <= aRange.second; ++i)
+            {
+                if (i != nSelPos)
+                {
+                    ThumbnailViewItem *pCurItem = mFilteredItemList[i];
+
+                    pCurItem->setSelection(!pCurItem->isSelected());
+
+                    if (pCurItem->isVisible())
+                        DrawItem(pCurItem);
+
+                    maItemStateHdl.Call(pCurItem);
+                }
+            }
+        }
+        else if (!aKeyCode.IsShift())
+        {
+            deselectItems();
+            SelectItem(pNext->mnId);
+
+            //Mark it as the selection range start position
+            mpStartSelRange = mFilteredItemList.begin() + nNextPos;
+        }
+
         MakeItemVisible(pNext->mnId);
     }
 }
@@ -588,7 +694,8 @@
 {
     if ( rMEvt.IsLeft() )
     {
-        ThumbnailViewItem* pItem = ImplGetItem( ImplGetItem( rMEvt.GetPosPixel() ) );
+        size_t nPos = ImplGetItem(rMEvt.GetPosPixel());
+        ThumbnailViewItem* pItem = ImplGetItem(nPos);
 
         if (pItem && pItem->isVisible())
         {
@@ -598,6 +705,62 @@
                 {
                     //Keep selected item group state and just invert current desired one state
                     pItem->setSelection(!pItem->isSelected());
+
+                    //This one becomes the selection range start position if it changes its state 
to selected otherwise resets it
+                    mpStartSelRange = pItem->isSelected() ? mFilteredItemList.begin() + nPos : 
mFilteredItemList.end();
+                }
+                else if (rMEvt.IsShift() && mpStartSelRange != mFilteredItemList.end())
+                {
+                    std::pair<size_t,size_t> aNewRange;
+                    aNewRange.first = mpStartSelRange - mFilteredItemList.begin();
+                    aNewRange.second = nPos;
+
+                    if (aNewRange.first > aNewRange.second)
+                        std::swap(aNewRange.first,aNewRange.second);
+
+                    //Deselect the ones outside of it
+                    for (size_t i = 0, n = mFilteredItemList.size(); i < n; ++i)
+                    {
+                        ThumbnailViewItem *pCurItem  = mFilteredItemList[i];
+
+                        if (pCurItem->isSelected() && (i < aNewRange.first || i > 
aNewRange.second))
+                        {
+                            pCurItem->setSelection(false);
+
+                            if (pCurItem->isVisible())
+                                DrawItem(pCurItem);
+
+                            maItemStateHdl.Call(pCurItem);
+                        }
+                    }
+
+                    size_t nSelPos = mpStartSelRange - mFilteredItemList.begin();
+
+                    //Select the items between start range and the selected item
+                    if (nSelPos != nPos)
+                    {
+                        int dir = nSelPos < nPos ? 1 : -1;
+                        size_t nCurPos = nSelPos + dir;
+
+                        while (nCurPos != nPos)
+                        {
+                            ThumbnailViewItem *pCurItem  = mFilteredItemList[nCurPos];
+
+                            if (!pCurItem->isSelected())
+                            {
+                                pCurItem->setSelection(true);
+
+                                if (pCurItem->isVisible())
+                                    DrawItem(pCurItem);
+
+                                maItemStateHdl.Call(pCurItem);
+                            }
+
+                            nCurPos += dir;
+                        }
+                    }
+
+                    pItem->setSelection(true);
                 }
                 else
                 {
@@ -606,6 +769,9 @@
                     pItem->setSelection(false);
                     deselectItems();
                     pItem->setSelection(true);
+
+                    //Mark as initial selection range position and reset end one
+                    mpStartSelRange = mFilteredItemList.begin() + nPos;
                 }
 
                 if (pItem->isSelected())
@@ -1053,6 +1219,11 @@
 {
     mnFirstLine = 0;        // start at the top of the list instead of the current position
     maFilterFunc = func;
+
+    size_t nSelPos = 0;
+    bool bHasSelRange = false;
+    ThumbnailViewItem *curSel = mpStartSelRange != mFilteredItemList.end() ? *mpStartSelRange : 
NULL;
+
     mFilteredItemList.clear();
 
     for (size_t i = 0, n = mItemList.size(); i < n; ++i)
@@ -1061,6 +1232,12 @@
 
         if (maFilterFunc(pItem))
         {
+            if (curSel == pItem)
+            {
+                nSelPos = i;
+                bHasSelRange = true;
+            }
+
             mFilteredItemList.push_back(pItem);
         }
         else
@@ -1082,6 +1259,7 @@
         }
     }
 
+    mpStartSelRange = bHasSelRange ? mFilteredItemList.begin()  + nSelPos : 
mFilteredItemList.end();
     CalculateItemPositions();
 
     Invalidate();

-- 
To view, visit https://gerrit.libreoffice.org/3260
To unsubscribe, visit https://gerrit.libreoffice.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I0b107d0918e1914709de31fd52cd11480e7fd419
Gerrit-PatchSet: 1
Gerrit-Project: core
Gerrit-Branch: libreoffice-4-0
Gerrit-Owner: Rafael Dominguez <venccsralph@gmail.com>


Context


Privacy Policy | Impressum (Legal Info) | Copyright information: Unless otherwise specified, all text and images on this website are licensed under the Creative Commons Attribution-Share Alike 3.0 License. This does not include the source code of LibreOffice, which is licensed under the Mozilla Public License (MPLv2). "LibreOffice" and "The Document Foundation" are registered trademarks of their corresponding registered owners or are in actual use as trademarks in one or more countries. Their respective logos and icons are also subject to international copyright laws. Use thereof is explained in our trademark policy.