sw/source/uibase/utlui/content.cxx | 196 ++++++++++++++++++++----------------- 1 file changed, 111 insertions(+), 85 deletions(-)
New commits: commit 4be0ae19065b1b50870bc0b2a28189ad39c96a8a Author: Jim Raykowski <rayk...@gmail.com> AuthorDate: Sat Nov 13 18:27:01 2021 -0900 Commit: Jim Raykowski <rayk...@gmail.com> CommitDate: Thu Nov 18 00:40:40 2021 +0100 SwNavigator: Improve which entry is selected in the content tree after the tree is updated and when current document cursor position is at content that is set to not track Intended behavior when the content tree display is updated is for the selected entry before update to be reselected after update if the entry is still in the tree. Currently, if the selected entry before update is a content type, the selected entry after update is the first entry in the tree. If the selected entry before update is not present, e.g. the selected entry is the only member of a content type and is deleted, the first entry in the tree is selected. In these cases, this patch changes the selected entry after update to be the content type entry. Instead of reselecting by entry name, which can result in incorrect selection when non unique entry names are possible, as in Headings, this patch improves entry reselect by comparing unique entry user data. Content tracking is improved by not falling through to other tracked content, e.g. when tables are not being tracked and sections are being tracked, clicking in a table in a section will not select the section in the content tree, the selected entry in the content tree will be unchanged. Change-Id: I8d82059db8688c31c7c0d705445c1d8b4272bec6 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/125176 Tested-by: Jenkins Reviewed-by: Jim Raykowski <rayk...@gmail.com> diff --git a/sw/source/uibase/utlui/content.cxx b/sw/source/uibase/utlui/content.cxx index 19af01d363a8..2227cb04f4c8 100644 --- a/sw/source/uibase/utlui/content.cxx +++ b/sw/source/uibase/utlui/content.cxx @@ -2365,16 +2365,15 @@ void SwContentTree::Display( bool bActive ) std::unique_ptr<weld::TreeIter> xOldSelEntry(m_xTreeView->make_iterator()); if (!m_xTreeView->get_selected(xOldSelEntry.get())) xOldSelEntry.reset(); - OUString sEntryName; // Name of the entry + OUString sOldSelEntryId; size_t nEntryRelPos = 0; // relative position to their parent size_t nOldEntryCount = GetEntryCount(); sal_Int32 nOldScrollPos = 0; if (xOldSelEntry) { UpdateLastSelType(); - + sOldSelEntryId = m_xTreeView->get_id(*xOldSelEntry); nOldScrollPos = m_xTreeView->vadjustment_get_value(); - sEntryName = m_xTreeView->get_text(*xOldSelEntry); std::unique_ptr<weld::TreeIter> xParentEntry = m_xTreeView->make_iterator(xOldSelEntry.get()); while (m_xTreeView->get_iter_depth(*xParentEntry)) m_xTreeView->iter_parent(*xParentEntry); @@ -2447,40 +2446,44 @@ void SwContentTree::Display( bool bActive ) for (const auto& rNode : aNodesToExpand) m_xTreeView->expand_row(*rNode); - (void)m_xTreeView->get_iter_first(*xEntry); - for (ContentTypeId nCntType : o3tl::enumrange<ContentTypeId>()) + // reselect the old selected entry if it is available, else select the entry that is at + // the position of the old selected entry + if (xOldSelEntry) { - sal_Int32 nExpandOptions = (State::HIDDEN == m_eState) - ? m_nHiddenBlock - : m_nActiveBlock; - if (nExpandOptions & (1 << static_cast<int>(nCntType))) + (void)m_xTreeView->get_iter_first(*xEntry); + for (ContentTypeId nCntType : o3tl::enumrange<ContentTypeId>()) { - if (nEntryRelPos && nCntType == m_nLastSelType) + if (nCntType == m_nLastSelType) { - // reselect the entry - std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(xEntry.get())); - std::unique_ptr<weld::TreeIter> xTemp; - sal_uLong nPos = 1; - while (m_xTreeView->iter_next(*xChild)) + // nEntryRelPos == 0 means the old selected entry was a content type + if (nEntryRelPos) { - // The old text will be slightly favored - if (sEntryName == m_xTreeView->get_text(*xChild) || - nPos == nEntryRelPos) + std::unique_ptr<weld::TreeIter> xIter(m_xTreeView->make_iterator(xEntry.get())); + std::unique_ptr<weld::TreeIter> xTemp(m_xTreeView->make_iterator(xIter.get())); + sal_uLong nPos = 1; + while (m_xTreeView->iter_next(*xIter) && + lcl_IsContent(*xIter, *m_xTreeView)) { - m_xTreeView->copy_iterator(*xChild, *xSelEntry); - break; + if (m_xTreeView->get_id(*xIter) == sOldSelEntryId || + nPos == nEntryRelPos) + { + m_xTreeView->copy_iterator(*xIter, *xSelEntry); + break; + } + xTemp = m_xTreeView->make_iterator(xIter.get()); // note previous entry + nPos++; } - xTemp = m_xTreeView->make_iterator(xChild.get()); - nPos++; + if (!xSelEntry || lcl_IsContentType(*xSelEntry, *m_xTreeView)) + xSelEntry = std::move(xTemp); } - if (!xSelEntry || lcl_IsContentType(*xSelEntry, *m_xTreeView)) - xSelEntry = std::move(xTemp); + else + m_xTreeView->copy_iterator(*xEntry, *xSelEntry); + break; } + (void)m_xTreeView->iter_next_sibling(*xEntry); } - - (void)m_xTreeView->iter_next_sibling(*xEntry); } - + // select the first entry in the tree when there is no selected entry if (!xSelEntry) { nOldScrollPos = 0; @@ -2488,7 +2491,6 @@ void SwContentTree::Display( bool bActive ) if (!m_xTreeView->get_iter_first(*xSelEntry)) xSelEntry.reset(); } - if (xSelEntry) { m_xTreeView->set_cursor(*xSelEntry); @@ -2552,15 +2554,15 @@ void SwContentTree::Display( bool bActive ) else m_xTreeView->expand_row(*xEntry); - // reselect the entry + // reselect the old selected entry if it is available, else select the entry that is at + // the position of the old selected entry if (nEntryRelPos) { std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(xEntry.get())); sal_uLong nPos = 1; while (m_xTreeView->iter_next(*xChild)) { - // The old text will be slightly favored - if (sEntryName == m_xTreeView->get_text(*xChild) || nPos == nEntryRelPos) + if (m_xTreeView->get_id(*xChild) == sOldSelEntryId || nPos == nEntryRelPos) { xSelEntry = std::move(xChild); break; @@ -2569,7 +2571,8 @@ void SwContentTree::Display( bool bActive ) } if (xSelEntry) { - m_xTreeView->set_cursor(*xSelEntry); // unselect all entries, make pSelEntry visible, and select + // set_cursor unselects all entries, makes passed entry visible, and selects it + m_xTreeView->set_cursor(*xSelEntry); Select(); } } @@ -3689,15 +3692,24 @@ void SwContentTree::UpdateTracking() { // graphic, frame, and ole OUString aContentTypeName; - if (m_bImageTracking && m_pActiveShell->GetSelectionType() == SelectionType::Graphic && + if (m_pActiveShell->GetSelectionType() == SelectionType::Graphic && !(m_bIsRoot && m_nRootType != ContentTypeId::GRAPHIC)) + { + if (!m_bImageTracking) return; aContentTypeName = SwResId(STR_CONTENT_TYPE_GRAPHIC); - else if (m_bFrameTracking && m_pActiveShell->GetSelectionType() == SelectionType::Frame && + } + else if (m_pActiveShell->GetSelectionType() == SelectionType::Frame && !(m_bIsRoot && m_nRootType != ContentTypeId::FRAME)) + { + if (!m_bFrameTracking) return; aContentTypeName = SwResId(STR_CONTENT_TYPE_FRAME); - else if (m_bOLEobjectTracking && m_pActiveShell->GetSelectionType() == SelectionType::Ole && + } + else if (m_pActiveShell->GetSelectionType() == SelectionType::Ole && !(m_bIsRoot && m_nRootType != ContentTypeId::OLE)) + { + if (!m_bOLEobjectTracking) return; aContentTypeName = SwResId(STR_CONTENT_TYPE_OLE); + } if (!aContentTypeName.isEmpty()) { OUString aName(m_pActiveShell->GetFlyName()); @@ -3706,16 +3718,17 @@ void SwContentTree::UpdateTracking() } } // footnotes and endnotes - if (SwContentAtPos aContentAtPos(IsAttrAtPos::Ftn); m_bFootnoteTracking && + if (SwContentAtPos aContentAtPos(IsAttrAtPos::Ftn); m_pActiveShell->GetContentAtPos(m_pActiveShell->GetCursorDocPos(), aContentAtPos) && !(m_bIsRoot && m_nRootType != ContentTypeId::FOOTNOTE)) { - lcl_SelectByContentTypeAndAddress(this, *m_xTreeView, ContentTypeId::FOOTNOTE, - aContentAtPos.pFndTextAttr); + if (m_bFootnoteTracking) + lcl_SelectByContentTypeAndAddress(this, *m_xTreeView, ContentTypeId::FOOTNOTE, + aContentAtPos.pFndTextAttr); return; } // bookmarks - track first bookmark at cursor - if (m_bBookmarkTracking && m_pActiveShell->GetSelectionType() & SelectionType::Text) + if (m_pActiveShell->GetSelectionType() & SelectionType::Text) { SwDoc* pDoc = m_pActiveShell->GetDoc(); uno::Reference<text::XBookmarksSupplier> xBookmarksSupplier(pDoc->GetDocShell()->GetBaseModel(), @@ -3725,6 +3738,7 @@ void SwContentTree::UpdateTracking() sal_Int32 nBookmarkCount = xBookmarks->getCount(); if (nBookmarkCount && !(m_bIsRoot && m_nRootType != ContentTypeId::BOOKMARK)) { + if (!m_bBookmarkTracking) return; SwPaM* pCursor = pDoc->GetEditShell()->GetCursor(); uno::Reference<text::XTextRange> xRange( SwXTextRange::CreateXTextRange(*pDoc, *pCursor->GetPoint(), nullptr)); @@ -3755,18 +3769,21 @@ void SwContentTree::UpdateTracking() } } // references - if (SwContentAtPos aContentAtPos(IsAttrAtPos::RefMark); m_bReferenceTracking && + if (SwContentAtPos aContentAtPos(IsAttrAtPos::RefMark); m_pActiveShell->GetContentAtPos(m_pActiveShell->GetCursorDocPos(), aContentAtPos) && aContentAtPos.pFndTextAttr && !(m_bIsRoot && m_nRootType != ContentTypeId::REFERENCE)) { - const SwFormatRefMark& rRefMark = aContentAtPos.pFndTextAttr->GetRefMark(); - lcl_SelectByContentTypeAndName(this, *m_xTreeView, SwResId(STR_CONTENT_TYPE_REFERENCE), - rRefMark.GetRefName()); + if (m_bReferenceTracking) + { + const SwFormatRefMark& rRefMark = aContentAtPos.pFndTextAttr->GetRefMark(); + lcl_SelectByContentTypeAndName(this, *m_xTreeView, SwResId(STR_CONTENT_TYPE_REFERENCE), + rRefMark.GetRefName()); + } return; } // hyperlinks - if (SwContentAtPos aContentAtPos(IsAttrAtPos::InetAttr); m_bHyperlinkTracking && + if (SwContentAtPos aContentAtPos(IsAttrAtPos::InetAttr); m_pActiveShell->GetContentAtPos(m_pActiveShell->GetCursorDocPos(), aContentAtPos) && !(m_bIsRoot && m_nRootType != ContentTypeId::URLFIELD)) { @@ -3774,57 +3791,63 @@ void SwContentTree::UpdateTracking() // in the tree by name may result in incorrect selection. Find the item in the tree by // comparing the SwTextINetFormat pointer at the document cursor position to that stored // in the item SwURLFieldContent. - lcl_SelectByContentTypeAndAddress(this, *m_xTreeView, ContentTypeId::URLFIELD, - aContentAtPos.pFndTextAttr); + if (m_bHyperlinkTracking) + lcl_SelectByContentTypeAndAddress(this, *m_xTreeView, ContentTypeId::URLFIELD, + aContentAtPos.pFndTextAttr); return; } // fields - if (SwField* pField = m_pActiveShell->GetCurField(); m_bFieldTracking && pField && + if (SwField* pField = m_pActiveShell->GetCurField(); pField && !(m_bIsRoot && m_nRootType != ContentTypeId::TEXTFIELD)) { - ContentTypeId nContentTypeId = - pField->GetTypeId() == SwFieldTypesEnum::Postit ? ContentTypeId::POSTIT : - ContentTypeId::TEXTFIELD; - lcl_SelectByContentTypeAndAddress(this, *m_xTreeView, nContentTypeId, pField); + if (m_bFieldTracking) + { + ContentTypeId nContentTypeId = + pField->GetTypeId() == SwFieldTypesEnum::Postit ? ContentTypeId::POSTIT : + ContentTypeId::TEXTFIELD; + lcl_SelectByContentTypeAndAddress(this, *m_xTreeView, nContentTypeId, pField); + } return; } // drawing - if (m_bDrawingObjectTracking && (m_pActiveShell->GetSelectionType() & - (SelectionType::DrawObject | - SelectionType::DrawObjectEditMode | - SelectionType::DbForm)) && + if ((m_pActiveShell->GetSelectionType() & (SelectionType::DrawObject | + SelectionType::DrawObjectEditMode | + SelectionType::DbForm)) && !(m_bIsRoot && m_nRootType != ContentTypeId::DRAWOBJECT)) { - // Multiple selection is possible when in root content navigation view so unselect all - // selected entries before reselecting. This causes a bit of an annoyance when the treeview - // scroll bar is used and focus is in the document by causing the last selected entry to - // scroll back into view. - if (m_bIsRoot) - m_xTreeView->unselect_all(); - SdrView* pSdrView = m_pActiveShell->GetDrawView(); - if (pSdrView) + if (m_bDrawingObjectTracking) { - for (size_t nIdx(0); nIdx < pSdrView->GetMarkedObjectCount(); nIdx++) + // Multiple selection is possible when in root content navigation view so unselect all + // selected entries before reselecting. This causes a bit of an annoyance when the treeview + // scroll bar is used and focus is in the document by causing the last selected entry to + // scroll back into view. + if (m_bIsRoot) + m_xTreeView->unselect_all(); + SdrView* pSdrView = m_pActiveShell->GetDrawView(); + if (pSdrView) { - SdrObject* pSelected = pSdrView->GetMarkedObjectByIndex(nIdx); - OUString aName(pSelected->GetName()); - if (!aName.isEmpty()) - lcl_SelectDrawObjectByName(*m_xTreeView, aName); + for (size_t nIdx(0); nIdx < pSdrView->GetMarkedObjectCount(); nIdx++) + { + SdrObject* pSelected = pSdrView->GetMarkedObjectByIndex(nIdx); + OUString aName(pSelected->GetName()); + if (!aName.isEmpty()) + lcl_SelectDrawObjectByName(*m_xTreeView, aName); + } } + else + { + // clear treeview selections + m_xTreeView->unselect_all(); + } + Select(); } - else - { - // clear treeview selections - m_xTreeView->unselect_all(); - } - Select(); return; } // table - if (m_bTableTracking && m_pActiveShell->IsCursorInTable() && + if (m_pActiveShell->IsCursorInTable() && !(m_bIsRoot && m_nRootType != ContentTypeId::TABLE)) { - if(m_pActiveShell->GetTableFormat()) + if(m_bTableTracking && m_pActiveShell->GetTableFormat()) { OUString aName = m_pActiveShell->GetTableFormat()->GetName(); lcl_SelectByContentTypeAndName(this, *m_xTreeView, SwResId(STR_CONTENT_TYPE_TABLE), @@ -3833,27 +3856,30 @@ void SwContentTree::UpdateTracking() return; } // indexes - if (const SwTOXBase* pTOX = m_pActiveShell->GetCurTOX(); m_bIndexTracking && pTOX && + if (const SwTOXBase* pTOX = m_pActiveShell->GetCurTOX(); pTOX && !(m_bIsRoot && m_nRootType != ContentTypeId::INDEX)) { - lcl_SelectByContentTypeAndName(this, *m_xTreeView, SwResId(STR_CONTENT_TYPE_INDEX), - pTOX->GetTOXName()); + if (m_bIndexTracking) + lcl_SelectByContentTypeAndName(this, *m_xTreeView, SwResId(STR_CONTENT_TYPE_INDEX), + pTOX->GetTOXName()); return; } // section - if (const SwSection* pSection = m_pActiveShell->GetCurrSection(); m_bSectionTracking && - pSection && !(m_bIsRoot && m_nRootType != ContentTypeId::REGION)) + if (const SwSection* pSection = m_pActiveShell->GetCurrSection(); pSection && + !(m_bIsRoot && m_nRootType != ContentTypeId::REGION)) { - lcl_SelectByContentTypeAndName(this, *m_xTreeView, SwResId(STR_CONTENT_TYPE_REGION), - pSection->GetSectionName()); + if (m_bSectionTracking) + lcl_SelectByContentTypeAndName(this, *m_xTreeView, SwResId(STR_CONTENT_TYPE_REGION), + pSection->GetSectionName()); return; } } // outline + if (m_nOutlineTracking == 3) + return; // find out where the cursor is const SwOutlineNodes::size_type nActPos = GetWrtShell()->GetOutlinePos(MAXLEVEL); - if (!((m_bIsRoot && m_nRootType != ContentTypeId::OUTLINE) || - m_nOutlineTracking == 3 || nActPos == SwOutlineNodes::npos)) + if (!((m_bIsRoot && m_nRootType != ContentTypeId::OUTLINE) || nActPos == SwOutlineNodes::npos)) { // assure outline content type is expanded // this assumes outline content type is first in treeview