commit d2437852097ba042dd5445800505bb7942006759 Author: Miklos Vajna Date: Wed Feb 21 17:27:53 2018 +0100 tdf#115873 sd navigator: allow selecting but not focusing on objects There were also two cases here: - changing the selection with the keyboard or single-click only updated the selection in the navigator - pressing enter or double-click also selected the shape in the main window and gave the focus away Introduce a 3rd case for single-click: update the shape selection but doesn't give the focus away. This way double-click is not needed to sync navigator -> main doc selection but keyboard navigation should still work. An additional trick is to make sure that the current shell is the draw shell (and not the slide sorter) after navigation, so follow-up operations work with the selected object and not with the whole slide. Finally, a third related problem was that the selection jumped back to the item of the slide after clicking on a shape in the navigator. The reason for this was the navigator list was constantly cleared and re-filled in SdNavigatorWin::InitTreeLB(), as SdPageObjsTLB::IsEqualToDoc() returned false (even if the list was up to date) in case of shapes which had children but no name. Fix this by using the same SdrIterMode::Flat iteration mode that SdPageObjsTLB::AddShapeList() does, so the fill and the equality check of the navigator iterates the same way. Conflicts: sd/qa/unit/tiledrendering/tiledrendering.cxx (cherry picked from commit f3c68cdf8f6a0273c62b493552f78af0138a44e8) Change-Id: I0bfc3e8b49f7ef01d5797a68284616dcd2a81c5d Reviewed-on: https://gerrit.libreoffice.org/50158 Tested-by: Jenkins Reviewed-by: Andras Timar diff --git a/sd/source/ui/dlg/navigatr.cxx b/sd/source/ui/dlg/navigatr.cxx index 4552f262c7a1..53526c95473b 100644 --- a/sd/source/ui/dlg/navigatr.cxx +++ b/sd/source/ui/dlg/navigatr.cxx @@ -54,6 +54,7 @@ #include #include #include +#include namespace { static const sal_uInt16 nShowNamedShapesFilter=1; @@ -215,6 +216,11 @@ NavigatorDragType SdNavigatorWin::GetNavigatorDragType() return eDT; } +VclPtr SdNavigatorWin::GetObjects() +{ + return maTlbObjects; +} + IMPL_LINK_NOARG(SdNavigatorWin, SelectToolboxHdl, ToolBox *, void) { sal_uInt16 nId = maToolbox->GetCurItemId(); @@ -337,6 +343,27 @@ IMPL_LINK_NOARG(SdNavigatorWin, ClickObjectHdl, SvTreeListBox*, bool) if ( pShellWnd ) pShellWnd->GrabFocus(); } + + // We navigated to an object, but the current shell may be + // still the slide sorter. Explicitly try to grab the draw + // shell focus, so follow-up operations work with the object + // and not with the whole slide. + sd::DrawDocShell* pDocShell = pInfo->mpDocShell; + if (pDocShell) + { + sd::ViewShell* pViewShell = pDocShell->GetViewShell(); + if (pViewShell) + { + vcl::Window* pWindow = pViewShell->GetActiveWindow(); + if (pWindow) + pWindow->GrabFocus(); + } + } + + if (!maTlbObjects->IsNavigationGrabsFocus()) + // This is the case when keyboard navigation inside the + // navigator should continue to work. + maTlbObjects->GrabFocus(); } } } diff --git a/sd/source/ui/dlg/sdtreelb.cxx b/sd/source/ui/dlg/sdtreelb.cxx index 7667c66db132..d9d193e445c0 100644 --- a/sd/source/ui/dlg/sdtreelb.cxx +++ b/sd/source/ui/dlg/sdtreelb.cxx @@ -58,6 +58,7 @@ #include #include #include +#include using namespace com::sun::star; @@ -205,6 +206,8 @@ SdPageObjsTLB::SdPageObjsTLB( vcl::Window* pParentWin, WinBits nStyle ) , mbSaveTreeItemState ( false ) , mbShowAllShapes ( false ) , mbShowAllPages ( false ) +, mbSelectionHandlerNavigates(false) +, mbNavigationGrabsFocus(true) { // add lines to Tree-ListBox SetStyle( GetStyle() | WB_TABSTOP | WB_BORDER | WB_HASLINES | @@ -626,6 +629,52 @@ void SdPageObjsTLB::SetShowAllShapes ( } } +bool SdPageObjsTLB::IsEqualToShapeList(SvTreeListEntry*& pEntry, const SdrObjList& rList, + const OUString& rListName) +{ + if (!pEntry) + return false; + OUString aName = GetEntryText(pEntry); + + if (rListName != aName) + return false; + + pEntry = Next(pEntry); + + SdrObjListIter aIter(rList, + !rList.HasObjectNavigationOrder() /* use navigation order, if available */, + SdrIterMode::Flat); + + while (aIter.IsMore()) + { + SdrObject* pObj = aIter.Next(); + + const OUString aObjectName(GetObjectName(pObj)); + + if (!aObjectName.isEmpty()) + { + if (!pEntry) + return false; + + aName = GetEntryText(pEntry); + + if (aObjectName != aName) + return false; + + if (pObj->IsGroupObject()) + { + bool bRet = IsEqualToShapeList(pEntry, *pObj->GetSubList(), aObjectName); + if (!bRet) + return false; + } + else + pEntry = Next(pEntry); + } + } + + return true; +} + /** * Checks if the pages (PageKind::Standard) of a doc and the objects on the pages * are identical to the TreeLB. @@ -640,9 +689,7 @@ bool SdPageObjsTLB::IsEqualToDoc( const SdDrawDocument* pInDoc ) if( !mpDoc ) return false; - SdrObject* pObj = nullptr; SvTreeListEntry* pEntry = First(); - OUString aName; // compare all pages including the objects sal_uInt16 nPage = 0; @@ -653,39 +700,9 @@ bool SdPageObjsTLB::IsEqualToDoc( const SdDrawDocument* pInDoc ) const SdPage* pPage = static_cast( mpDoc->GetPage( nPage ) ); if( pPage->GetPageKind() == PageKind::Standard ) { - if( !pEntry ) + bool bRet = IsEqualToShapeList(pEntry, *pPage, pPage->GetName()); + if (!bRet) return false; - aName = GetEntryText( pEntry ); - - if( pPage->GetName() != aName ) - return false; - - pEntry = Next( pEntry ); - - SdrObjListIter aIter( - *pPage, - !pPage->HasObjectNavigationOrder() /* use navigation order, if available */, - SdrIterMode::DeepWithGroups ); - - while( aIter.IsMore() ) - { - pObj = aIter.Next(); - - const OUString aObjectName( GetObjectName( pObj ) ); - - if( !aObjectName.isEmpty() ) - { - if( !pEntry ) - return false; - - aName = GetEntryText( pEntry ); - - if( aObjectName != aName ) - return false; - - pEntry = Next( pEntry ); - } - } } nPage++; } @@ -895,6 +912,9 @@ void SdPageObjsTLB::SelectHdl() } SvTreeListBox::SelectHdl(); + + if (mbSelectionHandlerNavigates) + DoubleClickHdl(); } /** @@ -939,6 +959,16 @@ void SdPageObjsTLB::KeyInput( const KeyEvent& rKEvt ) SvTreeListBox::KeyInput( rKEvt ); } +void SdPageObjsTLB::MouseButtonDown(const MouseEvent& rMEvt) +{ + mbSelectionHandlerNavigates = rMEvt.GetClicks() == 1; + comphelper::ScopeGuard aNavigationGuard([this]() { this->mbSelectionHandlerNavigates = false; }); + mbNavigationGrabsFocus = rMEvt.GetClicks() != 1; + comphelper::ScopeGuard aGrabGuard([this]() { this->mbNavigationGrabsFocus = true; }); + + SvTreeListBox::MouseButtonDown(rMEvt); +} + /** * StartDrag-Request */ diff --git a/sd/source/ui/inc/navigatr.hxx b/sd/source/ui/inc/navigatr.hxx index cd487a249058..a9501c5236a4 100644 --- a/sd/source/ui/inc/navigatr.hxx +++ b/sd/source/ui/inc/navigatr.hxx @@ -76,7 +76,7 @@ private: ::sd::DrawDocShell* mpDocShell; }; -class SdNavigatorWin : public PanelLayout +class SD_DLLPUBLIC SdNavigatorWin : public PanelLayout { public: typedef ::std::function UpdateRequestFunctor; @@ -101,6 +101,7 @@ public: bool InsertFile(const OUString& rFileName); NavigatorDragType GetNavigatorDragType(); + VclPtr GetObjects(); protected: virtual bool EventNotify(NotifyEvent& rNEvt) override; diff --git a/sd/source/ui/inc/sdtreelb.hxx b/sd/source/ui/inc/sdtreelb.hxx index 6f9887ecd40e..b358e376672b 100644 --- a/sd/source/ui/inc/sdtreelb.hxx +++ b/sd/source/ui/inc/sdtreelb.hxx @@ -195,6 +195,7 @@ public: OUString GetEntryLongDescription( SvTreeListEntry* pEntry ) const override; virtual void SelectHdl() override; virtual void KeyInput( const KeyEvent& rKEvt ) override; + void MouseButtonDown(const MouseEvent& rMEvt) override; void SetViewFrame( SfxViewFrame* pViewFrame ); @@ -202,7 +203,11 @@ public: void Fill( const SdDrawDocument*, SfxMedium* pSfxMedium, const OUString& rDocName ); void SetShowAllShapes (const bool bShowAllShapes, const bool bFill); bool GetShowAllShapes() const { return mbShowAllShapes;} + bool IsNavigationGrabsFocus() const { return mbNavigationGrabsFocus; } bool IsEqualToDoc( const SdDrawDocument* pInDoc ); + /// Visits rList recursively and tries to advance pEntry accordingly. + bool IsEqualToShapeList(SvTreeListEntry*& pEntry, const SdrObjList& rList, + const OUString& rListName); bool HasSelectedChildren( const OUString& rName ); bool SelectEntry( const OUString& rName ); OUString GetSelectedEntry(); @@ -247,6 +252,16 @@ private: /** This flag controls whether to show all pages. */ bool mbShowAllPages; + /** + * If changing the selection should also result in navigating to the + * relevant shape. + */ + bool mbSelectionHandlerNavigates; + /** + * If navigation should not only select the relevant shape but also change + * focus to it. + */ + bool mbNavigationGrabsFocus; /** Return when the current transferable may be dropped at the given list box entry.