sw/inc/strings.hrc | 4 sw/source/uibase/inc/conttree.hxx | 2 sw/source/uibase/inc/swcont.hxx | 2 sw/source/uibase/utlui/content.cxx | 233 ++++++++++++++++++++----------------- 4 files changed, 139 insertions(+), 102 deletions(-)
New commits: commit 08313c42abc5fb735948f37789ef993c93b6ab5e Author: Jim Raykowski <rayk...@gmail..com> AuthorDate: Fri Feb 21 00:08:53 2020 -0900 Commit: Noel Grandin <noel.gran...@collabora.co.uk> CommitDate: Mon Feb 24 07:58:38 2020 +0100 tdf#108766 Add outline tracking to all content navigation view Here is effort to implement this request and improve code understanding/ readability in the areas touched. A choice of one of three modes of outline tracking is avaliable through the outline/heading content context menu. They are: Default - does not collapse expanded outline entries Focus - collapses all outline entries other than tracked Off The need for persistance of this setting is uncertain so has been left for future implementation. Change-Id: I9cb6420537d7ff9f584e94029a0c053f21f1ef8b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/89287 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk> diff --git a/sw/inc/strings.hrc b/sw/inc/strings.hrc index c2bb4ef19562..93df4d272220 100644 --- a/sw/inc/strings.hrc +++ b/sw/inc/strings.hrc @@ -643,6 +643,10 @@ #define STR_OUTLINE_LEVEL NC_("STR_OUTLINE_LEVEL", "Outline Level") #define STR_DRAGMODE NC_("STR_DRAGMODE", "Drag Mode") #define STR_SEND_OUTLINE_TO_CLIPBOARD_ENTRY NC_("STR_SEND_OUTLINE_TO_CLIPBOARD_ENTRY", "Send Outline to Clipboard") +#define STR_OUTLINE_TRACKING NC_("STR_OUTLINE_TRACKING", "Outline Tracking") +#define STR_OUTLINE_TRACKING_DEFAULT NC_("STR_OUTLINE_TRACKING_DEFAULT", "Default") +#define STR_OUTLINE_TRACKING_FOCUS NC_("STR_OUTLINE_TRACKING_FOCUS", "Focus") +#define STR_OUTLINE_TRACKING_OFF NC_("STR_OUTLINE_TRACKING_OFF", "Off") #define STR_GOTO NC_("STR_GOTO", "Go to") #define STR_SELECT NC_("STR_SELECT", "Select") #define STR_DEMOTE_CHAPTER NC_("STR_DEMOTE_CHAPTER", "Demote Chapter") diff --git a/sw/source/uibase/inc/conttree.hxx b/sw/source/uibase/inc/conttree.hxx index e9c227875c22..c134e10551b3 100644 --- a/sw/source/uibase/inc/conttree.hxx +++ b/sw/source/uibase/inc/conttree.hxx @@ -102,6 +102,8 @@ class SwContentTree final ContentTypeId m_nLastSelType; sal_uInt8 m_nOutlineLevel; + sal_uInt32 m_nOutlineTracking = 1; + enum class State { ACTIVE, CONSTANT, HIDDEN } m_eState; bool m_bDocChgdInDragging :1; diff --git a/sw/source/uibase/inc/swcont.hxx b/sw/source/uibase/inc/swcont.hxx index fb2d0a9d4b79..cb334f9141eb 100644 --- a/sw/source/uibase/inc/swcont.hxx +++ b/sw/source/uibase/inc/swcont.hxx @@ -44,7 +44,7 @@ enum class ContentTypeId }; // strings for context menus -#define CONTEXT_COUNT 13 +#define CONTEXT_COUNT 17 #define GLOBAL_CONTEXT_COUNT 14 // modes for Drag 'n Drop diff --git a/sw/source/uibase/utlui/content.cxx b/sw/source/uibase/utlui/content.cxx index 19a7b81f35c7..d0b1934aa1d8 100644 --- a/sw/source/uibase/utlui/content.cxx +++ b/sw/source/uibase/utlui/content.cxx @@ -830,7 +830,11 @@ enum STR_CONTEXT_IDX IDX_STR_INACTIVE = 9, IDX_STR_EDIT_ENTRY = 10, IDX_STR_DELETE_ENTRY = 11, - IDX_STR_SEND_OUTLINE_TO_CLIPBOARD_ENTRY = 12 + IDX_STR_SEND_OUTLINE_TO_CLIPBOARD_ENTRY = 12, + IDX_STR_OUTLINE_TRACKING = 13, + IDX_STR_OUTLINE_TRACKING_DEFAULT = 14, + IDX_STR_OUTLINE_TRACKING_FOCUS = 15, + IDX_STR_OUTLINE_TRACKING_OFF = 16 }; } @@ -849,7 +853,11 @@ static const char* STR_CONTEXT_ARY[] = STR_INACTIVE, STR_EDIT_ENTRY, STR_DELETE_ENTRY, - STR_SEND_OUTLINE_TO_CLIPBOARD_ENTRY + STR_SEND_OUTLINE_TO_CLIPBOARD_ENTRY, + STR_OUTLINE_TRACKING, + STR_OUTLINE_TRACKING_DEFAULT, + STR_OUTLINE_TRACKING_FOCUS, + STR_OUTLINE_TRACKING_OFF }; SwContentTree::SwContentTree(vcl::Window* pParent, SwNavigationPI* pDialog) @@ -1227,7 +1235,13 @@ VclPtr<PopupMenu> SwContentTree::CreateContextMenu() VclPtrInstance<PopupMenu> pSubPop1; VclPtrInstance<PopupMenu> pSubPop2; VclPtrInstance<PopupMenu> pSubPop3; + VclPtrInstance<PopupMenu> pSubPopOutlineTracking; + for(int i = 1; i <= 3; ++i) + { + pSubPopOutlineTracking->InsertItem(i + 10, m_aContextStrings[i + IDX_STR_OUTLINE_TRACKING], MenuItemBits::AUTOCHECK | MenuItemBits::RADIOCHECK); + } + pSubPopOutlineTracking->CheckItem(10 + m_nOutlineTracking); for(int i = 1; i <= MAXLEVEL; ++i) { pSubPop1->InsertItem(i + 100, OUString::number(i), MenuItemBits::AUTOCHECK | MenuItemBits::RADIOCHECK); @@ -1405,6 +1419,8 @@ VclPtr<PopupMenu> SwContentTree::CreateContextMenu() pPop->InsertSeparator(); if (bOutline) { + pPop->InsertItem(4, m_aContextStrings[IDX_STR_OUTLINE_TRACKING]); + pPop->SetPopupMenu(4, pSubPopOutlineTracking); pPop->InsertItem(1, m_aContextStrings[IDX_STR_OUTLINE_LEVEL]); pPop->SetPopupMenu(1, pSubPop1); } @@ -1744,14 +1760,14 @@ void SwContentTree::Display( bool bActive ) nOldScrollPos = pVScroll->GetThumbPos(); sEntryName = GetEntryText(pOldSelEntry); - SvTreeListEntry* pParantEntry = pOldSelEntry; - while( GetParent(pParantEntry)) + SvTreeListEntry* pParentEntry = pOldSelEntry; + while( GetParent(pParentEntry)) { - pParantEntry = GetParent(pParantEntry); + pParentEntry = GetParent(pParentEntry); } if(GetParent(pOldSelEntry)) { - nEntryRelPos = GetModel()->GetAbsPos(pOldSelEntry) - GetModel()->GetAbsPos(pParantEntry); + nEntryRelPos = GetModel()->GetAbsPos(pOldSelEntry) - GetModel()->GetAbsPos(pParentEntry); } } Clear(); @@ -1776,6 +1792,7 @@ void SwContentTree::Display( bool bActive ) if(pShell) { SvTreeListEntry* pSelEntry = nullptr; + // all content navigation view if(m_nRootType == ContentTypeId::UNKNOWN) { for( ContentTypeId nCntType : o3tl::enumrange<ContentTypeId>() ) @@ -1806,7 +1823,7 @@ void SwContentTree::Display( bool bActive ) Expand(pEntry); if(nEntryRelPos && nCntType == m_nLastSelType) { - // Now maybe select an additional child + // reselect the entry SvTreeListEntry* pChild = pEntry; SvTreeListEntry* pTemp = nullptr; sal_uLong nPos = 1; @@ -1825,7 +1842,6 @@ void SwContentTree::Display( bool bActive ) if(!pSelEntry || lcl_IsContentType(pSelEntry)) pSelEntry = pTemp; } - } } if(pSelEntry) @@ -1836,6 +1852,7 @@ void SwContentTree::Display( bool bActive ) else nOldScrollPos = 0; } + // root content navigation view else { std::unique_ptr<SwContentType>& rpRootContentT = bActive ? @@ -1866,49 +1883,29 @@ void SwContentTree::Display( bool bActive ) else RequestingChildren(pParent); Expand(pParent); - if (m_nRootType == ContentTypeId::OUTLINE && State::ACTIVE == m_eState) - { - // find out where the cursor is - const SwOutlineNodes::size_type nActPos = pShell->GetOutlinePos(MAXLEVEL); - SvTreeListEntry* pEntry = First(); - - while( nullptr != (pEntry = Next(pEntry)) ) - { - assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData()))); - if (static_cast<SwOutlineContent*>(pEntry->GetUserData())->GetOutlinePos() == nActPos) - { - MakeVisible(pEntry); - Select(pEntry); - SetCurEntry(pEntry); - } - } - } - else + // reselect the entry + SvTreeListEntry* pChild = pParent; + SvTreeListEntry* pTemp = nullptr; + sal_uLong nPos = 1; + while(nullptr != (pChild = Next(pChild))) { - // Now maybe select an additional child - SvTreeListEntry* pChild = pParent; - SvTreeListEntry* pTemp = nullptr; - sal_uLong nPos = 1; - while(nullptr != (pChild = Next(pChild))) - { - // The old text will be slightly favored - if(sEntryName == GetEntryText(pChild) || + // The old text will be slightly favored + if(sEntryName == GetEntryText(pChild) || nPos == nEntryRelPos ) - { - pSelEntry = pChild; - break; - } - pTemp = pChild; - nPos++; - } - if(!pSelEntry) - pSelEntry = pTemp; - if(pSelEntry) { - MakeVisible(pSelEntry); - Select(pSelEntry); + pSelEntry = pChild; + break; } + pTemp = pChild; + nPos++; + } + if(!pSelEntry) + pSelEntry = pTemp; + if(pSelEntry) + { + MakeVisible(pSelEntry); + Select(pSelEntry); } } } @@ -2140,47 +2137,47 @@ bool SwContentTree::HasContentChanged() m_aActiveContentArr[i]->Invalidate(); } } + // root content navigation view else if(m_bIsRoot) { - bool bOutline = false; - SvTreeListEntry* pEntry = First(); - if(!pEntry) + SvTreeListEntry* pRootEntry = First(); + if(!pRootEntry) bRepaint = true; else { - assert(dynamic_cast<SwContentType*>(static_cast<SwTypeNumber*>(pEntry->GetUserData()))); - const ContentTypeId nType = static_cast<SwContentType*>(pEntry->GetUserData())->GetType(); - bOutline = m_nRootType == ContentTypeId::OUTLINE; + assert(dynamic_cast<SwContentType*>(static_cast<SwTypeNumber*>(pRootEntry->GetUserData()))); + const ContentTypeId nType = static_cast<SwContentType*>(pRootEntry->GetUserData())->GetType(); SwContentType* pArrType = m_aActiveContentArr[nType].get(); if(!pArrType) bRepaint = true; else { + // start check if first selected outline level has changed SvTreeListEntry* pFirstSel; - if(bOutline && !HasFocus() && - nullptr != ( pFirstSel = FirstSelected()) && + if(m_nRootType == ContentTypeId::OUTLINE && !HasFocus() && + nullptr != (pFirstSel = FirstSelected()) && lcl_IsContent(pFirstSel)) { assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pFirstSel->GetUserData()))); - const auto nSelLevel = - static_cast<SwOutlineContent*>(pFirstSel->GetUserData())->GetOutlineLevel(); + const auto nSelLevel = static_cast<SwOutlineContent*>(pFirstSel->GetUserData())->GetOutlineLevel(); SwWrtShell* pSh = GetWrtShell(); const SwOutlineNodes::size_type nOutlinePos = pSh->GetOutlinePos(MAXLEVEL); - if (nOutlinePos != SwOutlineNodes::npos && - pSh->getIDocumentOutlineNodesAccess()->getOutlineLevel(nOutlinePos) != nSelLevel) + if (nOutlinePos != SwOutlineNodes::npos && pSh->getIDocumentOutlineNodesAccess()->getOutlineLevel(nOutlinePos) != nSelLevel) bRepaint = true; } + // end check if first selected outline level has changed pArrType->Init(&bInvalidate); pArrType->FillMemberList(); - pEntry->SetUserData(static_cast<void*>(pArrType)); + pRootEntry->SetUserData(static_cast<void*>(pArrType)); if(!bRepaint) { - if(GetChildCount(pEntry) != pArrType->GetMemberCount()) - bRepaint = true; + if(GetChildCount(pRootEntry) != pArrType->GetMemberCount()) + bRepaint = true; else { - const size_t nChildCount = GetChildCount(pEntry); + const size_t nChildCount = GetChildCount(pRootEntry); + SvTreeListEntry* pEntry = pRootEntry; for(size_t j = 0; j < nChildCount; ++j) { pEntry = Next(pEntry); @@ -2196,33 +2193,8 @@ bool SwContentTree::HasContentChanged() } } } - if( !bRepaint && bOutline && !HasFocus() ) - { - // find out where the cursor is - const SwOutlineNodes::size_type nActPos = GetWrtShell()->GetOutlinePos(MAXLEVEL); - SvTreeListEntry* pFirstEntry = First(); - - while( nullptr != (pFirstEntry = Next(pFirstEntry)) ) - { - assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pFirstEntry->GetUserData()))); - if (static_cast<SwOutlineContent*>(pFirstEntry->GetUserData())->GetOutlinePos() == nActPos) - { - if(FirstSelected() != pFirstEntry) - { - Select(pFirstEntry); - MakeVisible(pFirstEntry); - } - } - else if (IsSelected(pFirstEntry)) - { - SvTreeListBox::SelectListEntry(pFirstEntry, false); - bInvalidate = true; - } - } - - } - } + // all content navigation view else { SvTreeListEntry* pEntry = First(); @@ -2230,9 +2202,9 @@ bool SwContentTree::HasContentChanged() { bool bNext = true; // at least a next must be assert(dynamic_cast<SwContentType*>(static_cast<SwTypeNumber*>(pEntry->GetUserData()))); - SwContentType* pTreeType = static_cast<SwContentType*>(pEntry->GetUserData()); - const size_t nTreeCount = pTreeType->GetMemberCount(); - const ContentTypeId nType = pTreeType->GetType(); + SwContentType* pCntType = static_cast<SwContentType*>(pEntry->GetUserData()); + const size_t nCntCount = pCntType->GetMemberCount(); + const ContentTypeId nType = pCntType->GetType(); SwContentType* pArrType = m_aActiveContentArr[nType].get(); if(!pArrType) bRepaint = true; @@ -2242,15 +2214,15 @@ bool SwContentTree::HasContentChanged() pEntry->SetUserData(static_cast<void*>(pArrType)); if(IsExpanded(pEntry)) { - bool bLevelOrVisibiblityChanged = false; - // bLevelOrVisibiblityChanged is set if outlines have changed their level + bool bLevelOrVisibilityChanged = false; + // bLevelOrVisibilityChanged is set if outlines have changed their level // or if the visibility of objects (frames, sections, tables) has changed // i.e. in header/footer - pArrType->FillMemberList(&bLevelOrVisibiblityChanged); + pArrType->FillMemberList(&bLevelOrVisibilityChanged); const size_t nChildCount = GetChildCount(pEntry); - if((nType == ContentTypeId::OUTLINE) && bLevelOrVisibiblityChanged) + if((nType == ContentTypeId::OUTLINE) && bLevelOrVisibilityChanged) bRepaint = true; - if(bLevelOrVisibiblityChanged) + if(bLevelOrVisibilityChanged) bInvalidate = true; if(nChildCount != pArrType->GetMemberCount()) @@ -2270,18 +2242,18 @@ bool SwContentTree::HasContentChanged() bRepaint = true; } } - } + // not expanded and has children else if(pEntry->HasChildren()) { // was the entry once opened, then must also the // invisible records be examined. // At least the user data must be updated. - bool bLevelOrVisibiblityChanged = false; - // bLevelOrVisibiblityChanged is set if outlines have changed their level + bool bLevelOrVisibilityChanged = false; + // bLevelOrVisibilityChanged is set if outlines have changed their level // or if the visibility of objects (frames, sections, tables) has changed // i.e. in header/footer - pArrType->FillMemberList(&bLevelOrVisibiblityChanged); + pArrType->FillMemberList(&bLevelOrVisibilityChanged); bool bRemoveChildren = false; const size_t nChildCount = GetChildCount(pEntry); if( nChildCount != pArrType->GetMemberCount() ) @@ -2315,7 +2287,7 @@ bool SwContentTree::HasContentChanged() } } - else if((nTreeCount != 0) + else if((nCntCount != 0) != (pArrType->GetMemberCount()!=0)) { bRepaint = true; @@ -2803,6 +2775,58 @@ IMPL_LINK_NOARG(SwContentTree, TimerUpdate, Timer *, void) FindActiveTypeAndRemoveUserData(); Display(true); } + + // track document outline position at cursor + if (m_nOutlineTracking == 3) // no outline tracking + return; + const SwOutlineNodes::size_type nActPos = GetWrtShell()->GetOutlinePos(MAXLEVEL); // find out where the cursor is + if (nActPos == SwOutlineNodes::npos) + { + // cursor is not in an outline position so clear any selections in the tree list + if (FirstSelected()) + SelectAll(false); + } + else + { + SvTreeListEntry* pFirstSelected = FirstSelected(); + for (SvTreeListEntry* pEntry = First(); pEntry; pEntry = Next(pEntry)) + { + if (lcl_IsContent(pEntry) && + static_cast<SwContent*>(pEntry->GetUserData())->GetParent()->GetType() == ContentTypeId::OUTLINE) + { + // only select if not already selected + // might have been scrolled out of view by the user so leave it that way + if (static_cast<SwOutlineContent*>(pEntry->GetUserData())->GetOutlinePos() == nActPos) + { + if (pEntry != pFirstSelected) + { + if (m_nOutlineTracking == 2) // focused outline tracking + { + // collapse to children of root node + for (SvTreeListEntry* pChildEntry = FirstChild(First()); pChildEntry; pChildEntry = Next(pChildEntry)) + { + if (static_cast<SwContent*>(pChildEntry->GetUserData())->GetParent()->GetType() == ContentTypeId::OUTLINE) + Collapse(pChildEntry); + else + break; + } + } + SelectAll(false); + Select(pEntry); + MakeVisible(pEntry); + } + break; + } + } + else + { + // use of this break assumes outline content type is first in tree + if (lcl_IsContentType(pEntry) && + static_cast<SwContentType*>(pEntry->GetUserData())->GetType() != ContentTypeId::OUTLINE) + break; + } + } + } } else if (!pView && State::ACTIVE == m_eState && !m_bIsIdleClear) { @@ -3279,6 +3303,13 @@ void SwContentTree::ExecuteContextMenuAction( sal_uInt16 nSelectedPopupEntry ) SvTreeListEntry* pFirst = FirstSelected(); switch( nSelectedPopupEntry ) { + case 11: + case 12: + case 13: + nSelectedPopupEntry -= 10; + if(m_nOutlineTracking != nSelectedPopupEntry) + m_nOutlineTracking = nSelectedPopupEntry; + break; //Outlinelevel case 101: case 102: _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits