diff options
author | Rafael Dominguez <venccsralph@gmail.com> | 2013-04-07 14:09:54 -0430 |
---|---|---|
committer | Miklos Vajna <vmiklos@suse.cz> | 2013-04-08 07:39:47 +0000 |
commit | b51875f39c86bd8082c983773756630b53df88af (patch) | |
tree | 25fb1f4321c99ec6e2292f735128ccb11cabc614 | |
parent | 397ebc0260ec6285e5965af26630610e71b5c3fc (diff) |
fdo#61390 - Thumbnail navigation by shift-click and shift-keyboard.
Change-Id: I0b107d0918e1914709de31fd52cd11480e7fd419
Reviewed-on: https://gerrit.libreoffice.org/3260
Reviewed-by: Miklos Vajna <vmiklos@suse.cz>
Tested-by: Miklos Vajna <vmiklos@suse.cz>
-rw-r--r-- | sfx2/inc/sfx2/thumbnailview.hxx | 1 | ||||
-rw-r--r-- | sfx2/source/control/thumbnailview.cxx | 198 |
2 files changed, 189 insertions, 10 deletions
diff --git a/sfx2/inc/sfx2/thumbnailview.hxx b/sfx2/inc/sfx2/thumbnailview.hxx index 6d9f30e4381d..1286385d680b 100644 --- a/sfx2/inc/sfx2/thumbnailview.hxx +++ b/sfx2/inc/sfx2/thumbnailview.hxx @@ -305,6 +305,7 @@ protected: 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 725520cc3301..8d03d5afc9f2 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 @@ ThumbnailView::~ThumbnailView() 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 @@ void ThumbnailView::ImplInit() 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 @@ void ThumbnailView::ImplDeleteItems() mItemList.clear(); mFilteredItemList.clear(); + + mpStartSelRange = mFilteredItemList.end(); } void ThumbnailView::ImplInitSettings( bool bFont, bool bForeground, bool bBackground ) @@ -398,9 +416,9 @@ size_t ThumbnailView::ImplGetItem( const Point& rPos, bool bMove ) const 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 @@ size_t ThumbnailView::ImplGetItem( const Point& rPos, bool bMove ) const 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 @@ void ThumbnailView::KeyInput( const KeyEvent& rKEvt ) } } + 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 @@ void ThumbnailView::KeyInput( const KeyEvent& rKEvt ) 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 @@ void ThumbnailView::MouseButtonDown( const MouseEvent& rMEvt ) { 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 @@ void ThumbnailView::MouseButtonDown( const MouseEvent& rMEvt ) { //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 @@ void ThumbnailView::MouseButtonDown( const MouseEvent& rMEvt ) 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 @@ void ThumbnailView::filterItems (const boost::function<bool (const ThumbnailView { 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 @@ void ThumbnailView::filterItems (const boost::function<bool (const ThumbnailView if (maFilterFunc(pItem)) { + if (curSel == pItem) + { + nSelPos = i; + bHasSelRange = true; + } + mFilteredItemList.push_back(pItem); } else @@ -1082,6 +1259,7 @@ void ThumbnailView::filterItems (const boost::function<bool (const ThumbnailView } } + mpStartSelRange = bHasSelRange ? mFilteredItemList.begin() + nSelPos : mFilteredItemList.end(); CalculateItemPositions(); Invalidate(); |