sw/source/uibase/inc/content.hxx | 29 + sw/source/uibase/inc/conttree.hxx | 2 sw/source/uibase/inc/swcont.hxx | 4 sw/source/uibase/utlui/content.cxx | 454 ++++++++++++++++++++++++++----- sw/source/uibase/utlui/navipi.cxx | 68 +++- sw/uiconfig/swriter/ui/navigatorpanel.ui | 69 +++- 6 files changed, 532 insertions(+), 94 deletions(-)
New commits: commit a66fd0b6d9300a7def03658c1661cb6d5f609ab9 Author: Jim Raykowski <[email protected]> AuthorDate: Sun Dec 21 23:31:53 2025 -0900 Commit: Jim Raykowski <[email protected]> CommitDate: Mon Jan 26 20:34:55 2026 +0100 tdf#164864 SwNavigator should show index entries Change-Id: I6aaef0c898d89ff017123e690bb9820962f9536b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/194911 Tested-by: Jenkins Reviewed-by: Jim Raykowski <[email protected]> diff --git a/sw/source/uibase/inc/content.hxx b/sw/source/uibase/inc/content.hxx index 26ef61325356..25f8341fe593 100644 --- a/sw/source/uibase/inc/content.hxx +++ b/sw/source/uibase/inc/content.hxx @@ -36,6 +36,7 @@ class SwContentType; class SwFormatField; class SwTextINetFormat; class SwTOXBase; +class SwTOXMark; class SwTextFootnote; // helper classes @@ -173,13 +174,33 @@ public: class SwTOXBaseContent final : public SwContent { const SwTOXBase* m_pBase; + SwTOXMarks m_aMarks; public: - SwTOXBaseContent(const SwContentType* pCnt, const OUString& rName, tools::Long nYPos, const SwTOXBase& rBase) - : SwContent( pCnt, rName, nYPos ), m_pBase(&rBase) - {} - virtual ~SwTOXBaseContent() override; + SwTOXBaseContent(const SwContentType* pCnt, const OUString& rName, tools::Long nYPos, + const SwTOXBase& rBase) + : SwContent(pCnt, rName, nYPos) + , m_pBase(&rBase) + { + const SwTOXType* pTOXType = m_pBase->GetTOXType(); + if (pTOXType && (m_pBase->GetCreateType() & SwTOXElement::Mark)) + pTOXType->CollectTextMarks(m_aMarks); + } const SwTOXBase* GetTOXBase() const {return m_pBase;} + SwTOXMarks& GetTOXMarks() { return m_aMarks; } +}; + +class SwTOXMarkContent final : public SwContent +{ + const SwTOXMark* m_pMark; +public: + SwTOXMarkContent(const SwContentType* pCnt, const OUString& rName, tools::Long nYPos, + const SwTOXMark& rMark) + : SwContent(pCnt, rName, nYPos) + , m_pMark(&rMark) + { + } + const SwTOXMark* GetTOXMark() const { return m_pMark; } }; /** diff --git a/sw/source/uibase/inc/conttree.hxx b/sw/source/uibase/inc/conttree.hxx index 6ca96ea24190..ca20d55bfdeb 100644 --- a/sw/source/uibase/inc/conttree.hxx +++ b/sw/source/uibase/inc/conttree.hxx @@ -111,6 +111,7 @@ class SwContentTree final : public SfxListener std::map< void*, bool > mOutLineNodeMap; std::map<const void*, bool> m_aRegionNodeExpandMap; std::map<const void*, bool> m_aPostItNodeExpandMap; + std::map<const void*, bool> m_aIndexNodeExpandMap; sal_Int32 m_nActiveBlock; // used to restore content types expand state sal_Int32 m_nHiddenBlock; @@ -159,6 +160,7 @@ class SwContentTree final : public SfxListener void BringFootnotesToAttention(std::vector<const SwTextAttr*>& rTextAttrsArr); void BringTypesWithFlowFramesToAttention(const std::vector<const SwNode*>& rNodes, const bool bIncludeTopMargin = true); + void BringTextTOXMarksToAttention(std::vector<const SwTextAttr*>& rTextAttrsArr); /** * Before any data will be deleted, the last active entry has to be found. diff --git a/sw/source/uibase/inc/swcont.hxx b/sw/source/uibase/inc/swcont.hxx index 0ffcd49218d5..66c42adb70af 100644 --- a/sw/source/uibase/inc/swcont.hxx +++ b/sw/source/uibase/inc/swcont.hxx @@ -44,7 +44,9 @@ enum class ContentTypeId FOOTNOTE = 13, ENDNOTE = 14, LAST = ENDNOTE, - UNKNOWN = -1 + UNKNOWN = -1, + INDEXTOXBASE = -2, + INDEXTOXMARK = -3 }; // strings for context menus diff --git a/sw/source/uibase/utlui/content.cxx b/sw/source/uibase/utlui/content.cxx index 1ee72b99aad4..382031dac22d 100644 --- a/sw/source/uibase/utlui/content.cxx +++ b/sw/source/uibase/utlui/content.cxx @@ -138,6 +138,8 @@ #include <officecfg/Office/Common.hxx> +#include <txttxmrk.hxx> + #define CTYPE_CNT 0 #define CTYPE_CTT 1 @@ -339,10 +341,6 @@ SwGraphicContent::~SwGraphicContent() { } -SwTOXBaseContent::~SwTOXBaseContent() -{ -} - const TranslateId STR_CONTENT_TYPE_ARY[] = { STR_CONTENT_TYPE_OUTLINE, @@ -1127,15 +1125,18 @@ void SwContentType::FillMemberList(bool* pbContentChanged) break; case ContentTypeId::INDEX: { - const sal_uInt16 nCount = m_pWrtShell->GetTOXCount(); - - for ( sal_uInt16 nTox = 0; nTox < nCount; nTox++ ) + for (sal_uInt16 nTox = 0, n = 0, nCount = m_pWrtShell->GetTOXCount(); nTox < nCount; + nTox++) { - const SwTOXBase* pBase = m_pWrtShell->GetTOX( nTox ); - UIName sTOXNm( pBase->GetTOXName() ); - - SwContent* pCnt = new SwTOXBaseContent(this, sTOXNm.toString(), - m_bAlphabeticSort ? 0 : nTox, *pBase); + const SwTOXBase* pBase = m_pWrtShell->GetTOX(nTox); + assert(pBase); + if (!pBase) + continue; + OUString sName = pBase->GetTitle(); + if (sName.isEmpty()) + sName = pBase->GetTOXName().toString(); + auto xTOXBaseCnt + = std::make_unique<SwTOXBaseContent>(this, sName, nTox + n, *pBase); // visibility const SwContentNode* pNode = nullptr; @@ -1149,16 +1150,80 @@ void SwContentType::FillMemberList(bool* pbContentChanged) pNode = SwNodes::GoNext(&aIdx); } } - lcl_MaybeSetInvisible(m_pWrtShell, pCnt, pNode); + lcl_MaybeSetInvisible(m_pWrtShell, xTOXBaseCnt.get(), pNode); - m_pMember->insert( std::unique_ptr<SwContent>(pCnt) ); - const size_t nPos = m_pMember->size() - 1; - if (pOldMember) + m_pMember->insert(std::move(xTOXBaseCnt)); + // xTOXBaseCnt no longer manages SwTOXBaseContent after move + SwTOXBaseContent* pTOXBaseCnt + = static_cast<SwTOXBaseContent*>(m_pMember->back().get()); + if (SwTOXMarks& rTOXMarks = pTOXBaseCnt->GetTOXMarks(); !rTOXMarks.empty()) { - assert(pbContentChanged && "pbContentChanged is always set if pOldMember is"); - if (!*pbContentChanged && nOldMemberCount > nPos && - (*pOldMember)[nPos]->IsInvisible() != pCnt->IsInvisible()) - *pbContentChanged = true; + // use stable sort array to list index marks in document order + const SwNodeOffset nEndOfExtrasIndex + = m_pWrtShell->GetNodes().GetEndOfExtras().GetIndex(); + bool bHasEntryInFly = false; + + for (SwTOXMark* pTOXMark : rTOXMarks) + { + if (nEndOfExtrasIndex + >= pTOXMark->GetTextTOXMark()->GetTextNode().GetIndex()) + { + // Not a node of BodyText + // Are we in a fly? + if (pTOXMark->GetTextTOXMark()->GetTextNode().GetFlyFormat()) + { + bHasEntryInFly = true; + break; + } + } + } + + std::stable_sort(rTOXMarks.begin(), rTOXMarks.end(), + [](const SwTOXMark* a, const SwTOXMark* b) + { + SwPosition aSwPos(a->GetTextTOXMark()->GetTextNode(), + a->GetTextTOXMark()->GetStart()); + SwPosition bSwPos(b->GetTextTOXMark()->GetTextNode(), + b->GetTextTOXMark()->GetStart()); + return aSwPos < bSwPos; + }); + + // When there are index marks in text frames do an additional sort using the + // text frame anchor position to place entries in the order of document layout + // appearance. + if (bHasEntryInFly) + { + std::stable_sort( + rTOXMarks.begin(), rTOXMarks.end(), + [nEndOfExtrasIndex](const SwTOXMark* a, const SwTOXMark* b) + { + const SwTextNode& aTextNode = a->GetTextTOXMark()->GetTextNode(); + const SwTextNode& bTextNode = b->GetTextTOXMark()->GetTextNode(); + SwPosition aPos(aTextNode, a->GetTextTOXMark()->GetStart()); + SwPosition bPos(bTextNode, b->GetTextTOXMark()->GetStart()); + // use anchor position for entries that are located in flys + if (nEndOfExtrasIndex >= aTextNode.GetIndex()) + if (auto pFlyFormat = aTextNode.GetFlyFormat()) + if (const SwPosition* pPos + = pFlyFormat->GetAnchor().GetContentAnchor()) + aPos = *pPos; + if (nEndOfExtrasIndex >= bTextNode.GetIndex()) + if (auto pFlyFormat = bTextNode.GetFlyFormat()) + if (const SwPosition* pPos + = pFlyFormat->GetAnchor().GetContentAnchor()) + bPos = *pPos; + return aPos < bPos; + }); + } + + for (const SwTOXMark* pTOXMark : rTOXMarks) + { + n++; + OUString sText = pTOXMark->GetText(m_pWrtShell->GetLayout()); + auto xTOXMarkContent + = std::make_unique<SwTOXMarkContent>(this, sText, nTox + n, *pTOXMark); + m_pMember->insert(std::move(xTOXMarkContent)); + } } } } @@ -1969,7 +2034,7 @@ IMPL_LINK(SwContentTree, CommandHdl, const CommandEvent&, rCEvt, bool) if (bIsContentType && nContentType != ContentTypeId::FOOTNOTE && nContentType != ContentTypeId::ENDNOTE && nContentType != ContentTypeId::POSTIT - && nContentType != ContentTypeId::UNKNOWN) + && nContentType != ContentTypeId::INDEX && nContentType != ContentTypeId::UNKNOWN) { bRemoveSortEntry = false; xPop->set_active(u"sort"_ustr, pType->IsAlphabeticSort()); @@ -2063,10 +2128,9 @@ IMPL_LINK(SwContentTree, CommandHdl, const CommandEvent&, rCEvt, bool) = !bReadonly && pType->IsEditable() && ((bVisible && !bProtected) || ContentTypeId::REGION == nContentType); const bool bDeletable = !bReadonly && pType->IsDeletable() && IsDeletable(*xEntry); - const bool bRenamable - = !bReadonly - && (pType->IsRenamable() - || (ContentTypeId::BOOKMARK == nContentType && !bProtectBM)); + bool bRenamable = !bReadonly + && (pType->IsRenamable() + || (ContentTypeId::BOOKMARK == nContentType && !bProtectBM)); // Choose which Delete entry to show. if (bDeletable) @@ -2143,14 +2207,44 @@ IMPL_LINK(SwContentTree, CommandHdl, const CommandEvent&, rCEvt, bool) { if (ContentTypeId::INDEX == nContentType) { - bRemoveIndexEntry = false; - bRemoveUpdateIndexEntry = false; bRemoveEditEntry = false; - bRemoveReadonlyIndexEntry = false; - const SwTOXBase* pBase - = weld::fromId<SwTOXBaseContent*>(m_xTreeView->get_id(*xEntry)) - ->GetTOXBase(); - xPop->set_active(OUString::number(405), SwEditShell::IsTOXBaseReadonly(*pBase)); + if (SwTOXBaseContent* pCnt + = dynamic_cast<SwTOXBaseContent*>(static_cast<SwTypeNumber*>( + weld::fromId<SwContent*>(m_xTreeView->get_id(*xEntry))))) + { + bRemoveIndexEntry = false; + bRemoveUpdateIndexEntry = false; + bRemoveReadonlyIndexEntry = false; + const SwTOXBase* pBase = pCnt->GetTOXBase(); + xPop->set_active(OUString::number(405/*Readonly*/), + SwEditShell::IsTOXBaseReadonly(*pBase)); + xPop->set_sensitive(OUString::number(403 /*Edit...*/), + !pBase->IsTOXBaseInReadonly()); + } + else // SwTOXMarkContent + { + // Use StartAction EndAction to prevent view movement during + // sensitivity setting of the Edit... menu item where the cursor is + // moved to the position of the TOX mark to determine the sensitivity + // setting using SwCursorShell::HasReadonlySel and then is moved back to + // the position of where it was. + m_pActiveShell->StartAction(); + SwPosition& rPos = *(m_pActiveShell->GetCurrentShellCursor().GetPoint()); + SwPosition aSavePos(rPos); + SwTOXMarkContent* pMarkCnt + = dynamic_cast<SwTOXMarkContent*>(static_cast<SwTypeNumber*>( + weld::fromId<SwContent*>(m_xTreeView->get_id(*xEntry)))); + GotoContent(pMarkCnt); + xPop->set_sensitive(OUString::number(403 /*Edit...*/), + !m_pActiveShell->HasReadonlySel()); + // move the current cursor back to the position of where it was + rPos = aSavePos; + // and grab focus back to content tree + grab_focus(); + m_pActiveShell->EndAction(); + + bRenamable = false; + } } else if(ContentTypeId::TABLE == nContentType) { @@ -2739,6 +2833,37 @@ bool SwContentTree::RequestingChildren(const weld::TreeIter& rParent) aParentCandidates.emplace_back(m_xTreeView->make_iterator(xChild.get())); } } + else if (pCntType->GetType() == ContentTypeId::INDEX) + { + for (size_t i = 0; i < nCount; ++i) + { + const SwTOXBaseContent* pTOXBaseContent + = static_cast<const SwTOXBaseContent*>(pCntType->GetMember(i)); + OUString sEntry = pTOXBaseContent->GetName(); + OUString sId(weld::toId(pTOXBaseContent)); + insert(&rParent, sEntry, sId, false, xChild.get()); + m_xTreeView->set_sensitive(*xChild, !pTOXBaseContent->IsInvisible()); + if (const size_t nTOXMarksCount + = const_cast<SwTOXBaseContent*>(pTOXBaseContent)->GetTOXMarks().size()) + { + std::unique_ptr<weld::TreeIter> xParent + = m_xTreeView->make_iterator(xChild.get()); + for (size_t nTOXMarksIndex = 0; nTOXMarksIndex < nTOXMarksCount; + ++nTOXMarksIndex) + { + ++i; + assert(dynamic_cast<const SwTOXMarkContent*>(pCntType->GetMember(i))); + const SwTOXMarkContent* pTOXMarkContent + = static_cast<const SwTOXMarkContent*>(pCntType->GetMember(i)); + sEntry = pTOXMarkContent->GetName(); + sId = weld::toId(pTOXMarkContent); + insert(xParent.get(), sEntry, sId, false, xChild.get()); + m_xTreeView->set_sensitive(*xChild, !pTOXBaseContent->IsInvisible() + && !pTOXMarkContent->IsInvisible()); + } + } + } + } else InsertContent(rParent); @@ -2876,6 +3001,50 @@ void SwContentTree::Expand(const weld::TreeIter& rParent, mOutLineNodeMap[key] = true; } } + else if (m_nRootType == ContentTypeId::INDEX + || (m_nRootType == ContentTypeId::UNKNOWN + && eParentContentTypeId == ContentTypeId::INDEX)) + { + if (bParentIsContentType) + { + std::map<const void*, bool> aCurrentIndexNodeExpandMap; + if (RequestingChildren(rParent)) + { + std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(&rParent)); + while (m_xTreeView->iter_next(*xChild) && lcl_IsContent(*xChild, *m_xTreeView)) + { + if (m_xTreeView->iter_has_child(*xChild)) + { + assert(dynamic_cast<SwTOXBaseContent*>( + weld::fromId<SwTypeNumber*>(m_xTreeView->get_id(*xChild)))); + const void* key = static_cast<const void*>( + weld::fromId<SwTOXBaseContent*>(m_xTreeView->get_id(*xChild)) + ->GetTOXBase()); + bool bExpandNode + = m_aIndexNodeExpandMap.contains(key) && m_aIndexNodeExpandMap[key]; + aCurrentIndexNodeExpandMap.emplace(key, bExpandNode); + if (bExpandNode) + { + if (pNodesToExpand) + pNodesToExpand->emplace_back( + m_xTreeView->make_iterator(xChild.get())); + RequestingChildren(*xChild); + m_xTreeView->set_children_on_demand(*xChild, false); + } + } + } + } + m_aIndexNodeExpandMap = std::move(aCurrentIndexNodeExpandMap); + return; + } + else + { + assert(dynamic_cast<SwTOXBaseContent*>(weld::fromId<SwTypeNumber*>(aParentId))); + const void* key = static_cast<const void*>( + weld::fromId<SwTOXBaseContent*>(aParentId)->GetTOXBase()); + m_aIndexNodeExpandMap[key] = true; + } + } else if (m_nRootType == ContentTypeId::REGION || (m_nRootType == ContentTypeId::UNKNOWN && eParentContentTypeId == ContentTypeId::REGION)) { @@ -2965,7 +3134,12 @@ void SwContentTree::Expand(const weld::TreeIter& rParent, IMPL_LINK(SwContentTree, EditingEntryHdl, const weld::TreeIter&, rIter, bool) { SwContent* pCnt = weld::fromId<SwContent*>(m_xTreeView->get_id(rIter)); - m_bEditing = pCnt->GetParent()->IsRenamable(); + if (dynamic_cast<SwTOXMarkContent*>(static_cast<SwTypeNumber*>(pCnt))) + m_bEditing = false; + else + m_bEditing = pCnt->GetParent()->IsRenamable(); + if (m_bEditing) + OverlayObject(); return m_bEditing; } @@ -3187,6 +3361,14 @@ IMPL_LINK(SwContentTree, CollapseHdl, const weld::TreeIter&, rParent, bool) const void* key = static_cast<const void*>(weld::fromId<SwPostItContent*>(m_xTreeView->get_id(rParent))->GetPostIt()); m_aPostItNodeExpandMap[key] = false; } + else if (eContentTypeId == ContentTypeId::INDEX) + { + assert(dynamic_cast<SwTOXBaseContent*>( + weld::fromId<SwTypeNumber*>(m_xTreeView->get_id(rParent)))); + const void* key = static_cast<const void*>( + weld::fromId<SwTOXBaseContent*>(m_xTreeView->get_id(rParent))->GetTOXBase()); + m_aIndexNodeExpandMap[key] = false; + } } return true; @@ -3307,6 +3489,8 @@ namespace case ContentTypeId::UNKNOWN: SAL_WARN("sw.ui", "ContentTypeId::UNKNOWN has no bitmap preview"); break; + default: // silence compiler warning + break; } return sResId; @@ -3467,7 +3651,8 @@ void SwContentTree::Display( bool bActive ) OUString aImage(GetImageIdForContentTypeId(m_nRootType)); bool bChOnDemand(m_nRootType == ContentTypeId::OUTLINE || m_nRootType == ContentTypeId::REGION || - m_nRootType == ContentTypeId::POSTIT); + m_nRootType == ContentTypeId::POSTIT || + m_nRootType == ContentTypeId::INDEX); OUString sId(weld::toId(rpRootContentT.get())); insert(nullptr, rpRootContentT->GetName(), sId, bChOnDemand, xEntry.get()); m_xTreeView->set_image(*xEntry, aImage); @@ -4626,15 +4811,19 @@ static void lcl_SelectByContentTypeAndAddress(SwContentTree* pThis, weld::TreeVi return; } - // find content type entry + // scratch iter std::unique_ptr<weld::TreeIter> xIter(rContentTree.make_iterator()); + // find content type entry + ContentTypeId eFindContentType = nType; + if (nType == ContentTypeId::INDEXTOXBASE || nType == ContentTypeId::INDEXTOXMARK) + eFindContentType = ContentTypeId::INDEX; bool bFoundEntry = rContentTree.get_iter_first(*xIter); while (bFoundEntry) { void* pUserData = weld::fromId<void*>(rContentTree.get_id(*xIter)); assert(dynamic_cast<SwContentType*>(static_cast<SwTypeNumber*>(pUserData))); - if (nType == static_cast<SwContentType*>(pUserData)->GetType()) + if (eFindContentType == static_cast<SwContentType*>(pUserData)->GetType()) break; bFoundEntry = rContentTree.iter_next_sibling(*xIter); } @@ -4685,6 +4874,26 @@ static void lcl_SelectByContentTypeAndAddress(SwContentTree* pThis, weld::TreeVi p = pCnt->GetPostItField(); break; } + case ContentTypeId::INDEXTOXBASE: + { + if (SwTOXBaseContent* pCnt + = dynamic_cast<SwTOXBaseContent*>(static_cast<SwTypeNumber*>(pUserData))) + { + p = pCnt->GetTOXBase(); + break; + } + continue; + } + case ContentTypeId::INDEXTOXMARK: + { + if (SwTOXMarkContent* pCnt + = dynamic_cast<SwTOXMarkContent*>(static_cast<SwTypeNumber*>(pUserData))) + { + p = pCnt->GetTOXMark(); + break; + } + continue; + } default: break; } @@ -5011,8 +5220,21 @@ void SwContentTree::UpdateTracking() !(m_bIsRoot && m_nRootType != ContentTypeId::INDEX)) { if (mTrackContentType[ContentTypeId::INDEX]) - lcl_SelectByContentTypeAndName(this, *m_xTreeView, SwResId(STR_CONTENT_TYPE_INDEX), - pTOX->GetTOXName().toString()); + lcl_SelectByContentTypeAndAddress(this, *m_xTreeView, ContentTypeId::INDEXTOXBASE, + pTOX); + return; + } + if (SwContentAtPos aContentAtPos(IsAttrAtPos::ToxMark); + m_pActiveShell->GetContentAtPos(m_pActiveShell->GetCursorDocPos(), aContentAtPos) + && aContentAtPos.pFndTextAttr + && (!m_bIsRoot || m_nRootType == ContentTypeId::INDEX)) + { + if (mTrackContentType[ContentTypeId::INDEX]) + { + const SwTOXMark& rTOXMark = aContentAtPos.pFndTextAttr->GetTOXMark(); + lcl_SelectByContentTypeAndAddress(this, *m_xTreeView, ContentTypeId::INDEXTOXMARK, + &rTOXMark); + } return; } // section @@ -5190,12 +5412,15 @@ static bool lcl_IsSelectedCompareByContentTypeAndAddress(const weld::TreeIter& r std::unique_ptr<weld::TreeIter> xIter(rContentTree.make_iterator()); // find content type entry + ContentTypeId eFindContentType = eContentType; + if (eContentType == ContentTypeId::INDEXTOXBASE || eContentType == ContentTypeId::INDEXTOXMARK) + eFindContentType = ContentTypeId::INDEX; bool bFoundEntry = rContentTree.get_iter_first(*xIter); while (bFoundEntry) { assert(dynamic_cast<SwContentType*>(weld::fromId<SwTypeNumber*>(rContentTree.get_id(*xIter)))); SwContentType* pContentType = weld::fromId<SwContentType*>(rContentTree.get_id(*xIter)); - if (eContentType == pContentType->GetType()) + if (eFindContentType == pContentType->GetType()) break; bFoundEntry = rContentTree.iter_next_sibling(*xIter); } @@ -5240,12 +5465,25 @@ static bool lcl_IsSelectedCompareByContentTypeAndAddress(const weld::TreeIter& r p = pCnt->GetPostItField(); break; } - case ContentTypeId::INDEX: + case ContentTypeId::INDEXTOXBASE: { - assert(dynamic_cast<SwTOXBaseContent*>(static_cast<SwTypeNumber*>(pContent))); - SwTOXBaseContent* pCnt = static_cast<SwTOXBaseContent*>(pContent); - p = pCnt->GetTOXBase(); - break; + if (SwTOXBaseContent* pCnt + = dynamic_cast<SwTOXBaseContent*>(static_cast<SwTypeNumber*>(pContent))) + { + p = pCnt->GetTOXBase(); + break; + } + continue; + } + case ContentTypeId::INDEXTOXMARK: + { + if (SwTOXMarkContent* pCnt + = dynamic_cast<SwTOXMarkContent*>(static_cast<SwTypeNumber*>(pContent))) + { + p = pCnt->GetTOXMark(); + break; + } + continue; } default: break; @@ -5346,11 +5584,15 @@ bool SwContentTree::IsSelectedEntryCurrentDocCursorPosition(const weld::TreeIter if (const SwTOXBase* pTOXBase = m_pActiveShell->GetCurTOX()) { return lcl_IsSelectedCompareByContentTypeAndAddress(rEntry, *m_xTreeView, - ContentTypeId::INDEX, pTOXBase); - // alternatively: - // return lcl_IsSelectedCompareByContentTypeAndName(rEntry, *m_xTreeView, - // ContentTypeId::INDEX, - // pTOX->GetTOXName()); + ContentTypeId::INDEXTOXBASE, pTOXBase); + } + if (SwContentAtPos aContentAtPos(IsAttrAtPos::ToxMark); + m_pActiveShell->GetContentAtPos(m_pActiveShell->GetCursorDocPos(), aContentAtPos) + && aContentAtPos.pFndTextAttr) + { + const SwTOXMark& rTOXMark = aContentAtPos.pFndTextAttr->GetTOXMark(); + return lcl_IsSelectedCompareByContentTypeAndAddress(rEntry, *m_xTreeView, + ContentTypeId::INDEXTOXMARK, &rTOXMark); } // fields, comments if (SwField* pField = m_pActiveShell->GetCurField()) @@ -5930,11 +6172,26 @@ IMPL_LINK(SwContentTree, QueryTooltipHdl, const weld::TreeIter&, rEntry, OUStrin } else { - size_t nMemberCount = static_cast<SwContentType*>(pUserData)->GetMemberCount(); - sEntry = OUString::number(nMemberCount) + " " + - (nMemberCount == 1 - ? static_cast<SwContentType*>(pUserData)->GetSingleName() - : static_cast<SwContentType*>(pUserData)->GetName()); + if (nType == ContentTypeId::INDEX) + { + SwContentType* pContentType = static_cast<SwContentType*>(pUserData); + size_t nTOXBaseCount = 0; + for (size_t i = 0, nMemberCount = pContentType->GetMemberCount(); i < nMemberCount; i++) + { + if (dynamic_cast<const SwTOXBaseContent*>(pContentType->GetMember(i))) + ++nTOXBaseCount; + } + sEntry + = OUString::number(nTOXBaseCount) + " " + + (nTOXBaseCount == 1 ? pContentType->GetSingleName() : pContentType->GetName()); + } + else + { + size_t nMemberCount = static_cast<SwContentType*>(pUserData)->GetMemberCount(); + sEntry = OUString::number(nMemberCount) + " " + + (nMemberCount == 1 ? static_cast<SwContentType*>(pUserData)->GetSingleName() + : static_cast<SwContentType*>(pUserData)->GetName()); + } } return sEntry; @@ -6623,6 +6880,33 @@ void SwContentTree::EditEntry(const weld::TreeIter& rEntry, EditEntryMode nMode) break; case ContentTypeId::INDEX: { + if (SwTOXMarkContent* pTOXMarkCnt + = dynamic_cast<SwTOXMarkContent*>(static_cast<SwTypeNumber*>(pCnt))) + { + if (nMode == EditEntryMode::EDIT) + { + m_pActiveShell->GetView().GetViewFrame().GetDispatcher()->Execute( + FN_EDIT_IDX_ENTRY_DLG, SfxCallMode::ASYNCHRON); + break; + } + else if (nMode == EditEntryMode::DELETE) + { + m_pActiveShell->StartUndo(SwUndoId::INDEX_ENTRY_DELETE); + m_pActiveShell->DeleteTOXMark(pTOXMarkCnt->GetTOXMark()); + // Update the table which the mark was removed + std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(&rEntry)); + if (m_xTreeView->iter_parent(*xEntry)) + { + pCnt = weld::fromId<SwContent*>(m_xTreeView->get_id(*xEntry)); + assert(dynamic_cast<SwTOXBaseContent*>(pCnt)); + const SwTOXBase* pBase = static_cast<SwTOXBaseContent*>(pCnt)->GetTOXBase(); + m_pActiveShell->UpdateTableOf(*pBase); + } + m_pActiveShell->EndUndo(SwUndoId::INDEX_ENTRY_DELETE); + break; + } + } + const SwTOXBase* pBase = static_cast<SwTOXBaseContent*>(pCnt)->GetTOXBase(); switch(nMode) { @@ -6900,8 +7184,10 @@ void SwContentTree::DeleteAllContentOfEntryContentType(const weld::TreeIter& rEn for (size_t i = 0; i < nCount; i++) { SwContent* pContent = const_cast<SwContent*>(pContentType->GetMember(i)); - const SwTOXBase* pBase - = static_cast<SwTOXBaseContent*>(pContent)->GetTOXBase(); + SwTOXBaseContent* pTOXBaseContent = dynamic_cast<SwTOXBaseContent*>(pContent); + if (!pTOXBaseContent) + continue; + const SwTOXBase* pBase = pTOXBaseContent->GetTOXBase(); if (pBase) m_pActiveShell->DeleteTOX(*pBase, true); } @@ -7126,9 +7412,22 @@ void SwContentTree::GotoContent(const SwContent* pCnt) break; case ContentTypeId::INDEX: { - const UIName sName(pCnt->GetName()); - if (!m_pActiveShell->GotoNextTOXBase(&sName)) - m_pActiveShell->GotoPrevTOXBase(&sName); + if (const SwTOXBaseContent* pTOXBaseContent + = dynamic_cast<const SwTOXBaseContent*>(pCnt)) + { + const UIName sName(pTOXBaseContent->GetTOXBase()->GetTOXName()); + if (!m_pActiveShell->GotoNextTOXBase(&sName)) + m_pActiveShell->GotoPrevTOXBase(&sName); + } + else + { + if (const SwTOXMarkContent* pTOXMarkContent + = dynamic_cast<const SwTOXMarkContent*>(pCnt)) + { + const SwTOXMark* pTOXMark = pTOXMarkContent->GetTOXMark(); + m_pActiveShell->GotoTOXMark(*pTOXMark, SwTOXSearch::TOX_SAME_NXT); + } + } } break; case ContentTypeId::POSTIT: @@ -7376,7 +7675,9 @@ void SwContentTree::BringEntryToAttention(const weld::TreeIter& rEntry) { BringBookmarksToAttention(std::vector<SwMarkName> {SwMarkName(pCnt->GetName())}); } - else if (nType == ContentTypeId::REGION || nType == ContentTypeId::INDEX) + else if (nType == ContentTypeId::REGION + || (nType == ContentTypeId::INDEX + && dynamic_cast<const SwTOXBaseContent*>(pCnt))) { for (size_t i = 0, nSectionFormatCount = m_pActiveShell->GetSectionFormatCount(); i < nSectionFormatCount; ++i) @@ -7410,6 +7711,15 @@ void SwContentTree::BringEntryToAttention(const weld::TreeIter& rEntry) } } } + else if (nType == ContentTypeId::INDEX && dynamic_cast<const SwTOXMarkContent*>(pCnt)) + { + if (const SwTextTOXMark* pTextAttr + = static_cast<SwTOXMarkContent*>(pCnt)->GetTOXMark()->GetTextTOXMark()) + { + std::vector<const SwTextAttr*> aTextAttrArr{ pTextAttr }; + BringTextTOXMarksToAttention(aTextAttrArr); + } + } else if (nType == ContentTypeId::URLFIELD) { // tdf#159147 - Assure the SwURLFieldContent::SwTextINetFormat pointer is valid @@ -7982,4 +8292,28 @@ void SwContentTree::BringTextFieldsToAttention(std::vector<const SwTextAttr*>& r OverlayObject(std::move(aRanges)); } +void SwContentTree::BringTextTOXMarksToAttention(std::vector<const SwTextAttr*>& rTextAttrsArr) +{ + std::vector<basegfx::B2DRange> aRanges; + for (const SwTextAttr* p : rTextAttrsArr) + { + if (!p) + continue; + const SwTOXMark& rTOXMark = p->GetTOXMark(); + if (const SwTextTOXMark* pTextTOXMark = rTOXMark.GetTextTOXMark()) + { + const SwTextNode& rTextNode = pTextTOXMark->GetTextNode(); + if (SwTextFrame* pFrame + = static_cast<SwTextFrame*>(rTextNode.getLayoutFrame(m_pActiveShell->GetLayout()))) + { + auto nStart = p->GetStart(); + auto nEnd = p->GetAnyEnd(); + SwPosition aStartPos(rTextNode, nStart), aEndPos(rTextNode, nEnd); + lcl_CalcOverlayRanges(pFrame, pFrame, aStartPos, aEndPos, aRanges); + } + } + OverlayObject(std::move(aRanges)); + } +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/utlui/navipi.cxx b/sw/source/uibase/utlui/navipi.cxx index 858198ec6252..e08c963af8fa 100644 --- a/sw/source/uibase/utlui/navipi.cxx +++ b/sw/source/uibase/utlui/navipi.cxx @@ -608,10 +608,27 @@ void SwNavigationPI::InitContentFunctionsToolbar() m_aContentTypeToolbarUnoDispatcherMap[eContentTypeId] = std::make_unique<ToolbarUnoDispatcher>(*m_aContentTypeUnoToolbarMap[eContentTypeId], *m_xBuilder, m_xFrame); - m_aContentUnoToolbarMap[eContentTypeId] = m_xBuilder->weld_toolbar( - sContentTypes[static_cast<int>(eContentTypeId)] + "ContentUnoToolbar"); - m_aContentToolbarUnoDispatcherMap[eContentTypeId] = std::make_unique<ToolbarUnoDispatcher>( - *m_aContentUnoToolbarMap[eContentTypeId], *m_xBuilder, m_xFrame); + if (eContentTypeId == ContentTypeId::INDEX) + { + m_aContentUnoToolbarMap[ContentTypeId::INDEXTOXBASE] + = m_xBuilder->weld_toolbar("IndexesTOXBaseContentUnoToolbar"); + m_aContentToolbarUnoDispatcherMap[ContentTypeId::INDEXTOXBASE] + = std::make_unique<ToolbarUnoDispatcher>( + *m_aContentUnoToolbarMap[ContentTypeId::INDEXTOXBASE], *m_xBuilder, m_xFrame); + m_aContentUnoToolbarMap[ContentTypeId::INDEXTOXMARK] + = m_xBuilder->weld_toolbar("IndexesTOXMarkContentUnoToolbar"); + m_aContentToolbarUnoDispatcherMap[ContentTypeId::INDEXTOXMARK] + = std::make_unique<ToolbarUnoDispatcher>( + *m_aContentUnoToolbarMap[ContentTypeId::INDEXTOXMARK], *m_xBuilder, m_xFrame); + } + else + { + m_aContentUnoToolbarMap[eContentTypeId] = m_xBuilder->weld_toolbar( + sContentTypes[static_cast<int>(eContentTypeId)] + "ContentUnoToolbar"); + m_aContentToolbarUnoDispatcherMap[eContentTypeId] + = std::make_unique<ToolbarUnoDispatcher>(*m_aContentUnoToolbarMap[eContentTypeId], + *m_xBuilder, m_xFrame); + } } Link<const OUString&, void> aLink @@ -641,7 +658,15 @@ void SwNavigationPI::UpdateContentFunctionsToolbar() if (eContentTypeId == ContentTypeId::OUTLINE) continue; m_aContentTypeUnoToolbarMap[eContentTypeId]->hide(); - m_aContentUnoToolbarMap[eContentTypeId]->hide(); + if (eContentTypeId == ContentTypeId::INDEX) + { + m_aContentUnoToolbarMap[ContentTypeId::INDEXTOXBASE]->hide(); + m_aContentUnoToolbarMap[ContentTypeId::INDEXTOXMARK]->hide(); + } + else + { + m_aContentUnoToolbarMap[eContentTypeId]->hide(); + } } m_xDeleteFunctionToolbar->hide(); @@ -690,23 +715,36 @@ void SwNavigationPI::UpdateContentFunctionsToolbar() } else if (m_xContentTree->IsSelectedEntryCurrentDocCursorPosition(*xEntry)) { - weld::Toolbar& rContentTypeToolbar = *m_aContentUnoToolbarMap[eContentTypeId]; - if (rContentTypeToolbar.get_n_items()) + weld::Toolbar* pContentUnoToolbar = nullptr; + if (eContentTypeId == ContentTypeId::INDEX) { - if (eContentTypeId == ContentTypeId::TABLE) + if (dynamic_cast<SwTOXBaseContent*>(static_cast<SwTypeNumber*>( + weld::fromId<SwTOXBaseContent*>(rTreeView.get_id(*xEntry))))) { - // prefer .uno:DeleteTable over delete functions toolbar + pContentUnoToolbar = m_aContentUnoToolbarMap[ContentTypeId::INDEXTOXBASE].get(); + // prefer .uno:RemoveTableOf over delete functions toolbar bUseDeleteFunctionsToolbar - = !lcl_ToolbarHasItemWithIdent(rContentTypeToolbar, u".uno:DeleteTable"); + = !lcl_ToolbarHasItemWithIdent(*pContentUnoToolbar, u".uno:RemoveTableOf"); } - else if (eContentTypeId == ContentTypeId::INDEX) + else { - // prefer .uno:RemoveTableOf over delete functions toolbar - bUseDeleteFunctionsToolbar - = !lcl_ToolbarHasItemWithIdent(rContentTypeToolbar, u".uno:RemoveTableOf"); + pContentUnoToolbar = m_aContentUnoToolbarMap[ContentTypeId::INDEXTOXMARK].get(); + } + } + else + { + pContentUnoToolbar = m_aContentUnoToolbarMap[eContentTypeId].get(); + if (pContentUnoToolbar->get_n_items()) + { + if (eContentTypeId == ContentTypeId::TABLE) + { + // prefer .uno:DeleteTable over delete functions toolbar + bUseDeleteFunctionsToolbar = !lcl_ToolbarHasItemWithIdent( + *pContentUnoToolbar, u".uno:DeleteTable"); + } } - rContentTypeToolbar.show(); } + pContentUnoToolbar->show(); } } diff --git a/sw/uiconfig/swriter/ui/navigatorpanel.ui b/sw/uiconfig/swriter/ui/navigatorpanel.ui index b2625ed87144..8ce53c218713 100644 --- a/sw/uiconfig/swriter/ui/navigatorpanel.ui +++ b/sw/uiconfig/swriter/ui/navigatorpanel.ui @@ -1041,7 +1041,7 @@ </packing> </child> <child> - <object class="GtkToolbar" id="IndexesContentUnoToolbar"> + <object class="GtkToolbar" id="IndexesTOXBaseContentUnoToolbar"> <property name="visible">True</property> <property name="can-focus">True</property> <property name="halign">start</property> @@ -1049,7 +1049,21 @@ <property name="toolbar-style">icons</property> <property name="show-arrow">False</property> <child> - <object class="GtkToolButton" id=".uno:InsertMultiIndex"> + <object class="GtkToolButton" id=".uno:UpdateCurIndex"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="halign">start</property> + <property name="valign">start</property> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">False</property> + </packing> + </child> + <child> + <object class="GtkToolButton" id=".uno:EditCurIndex"> + <property name="visible">True</property> + <property name="can-focus">False</property> <property name="visible">True</property> <property name="halign">start</property> <property name="valign">start</property> @@ -1074,7 +1088,34 @@ <packing> <property name="expand">False</property> <property name="fill">True</property> - <property name="position">18</property> + <property name="position">19</property> + </packing> + </child> + <child> + <object class="GtkToolbar" id="IndexesTOXMarkContentUnoToolbar"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="halign">start</property> + <property name="valign">start</property> + <property name="toolbar-style">icons</property> + <property name="show-arrow">False</property> + <child> + <object class="GtkToolButton" id=".uno:IndexEntryDialog"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="halign">start</property> + <property name="valign">start</property> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">False</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">20</property> </packing> </child> <child> @@ -1100,7 +1141,7 @@ <packing> <property name="expand">False</property> <property name="fill">True</property> - <property name="position">19</property> + <property name="position">21</property> </packing> </child> <child> @@ -1115,7 +1156,7 @@ <packing> <property name="expand">False</property> <property name="fill">True</property> - <property name="position">20</property> + <property name="position">22</property> </packing> </child> <child> @@ -1130,7 +1171,7 @@ <packing> <property name="expand">False</property> <property name="fill">True</property> - <property name="position">21</property> + <property name="position">23</property> </packing> </child> <child> @@ -1169,7 +1210,7 @@ <packing> <property name="expand">False</property> <property name="fill">True</property> - <property name="position">22</property> + <property name="position">24</property> </packing> </child> <child> @@ -1195,7 +1236,7 @@ <packing> <property name="expand">False</property> <property name="fill">True</property> - <property name="position">23</property> + <property name="position">25</property> </packing> </child> <child> @@ -1221,7 +1262,7 @@ <packing> <property name="expand">False</property> <property name="fill">True</property> - <property name="position">24</property> + <property name="position">26</property> </packing> </child> <child> @@ -1247,7 +1288,7 @@ <packing> <property name="expand">False</property> <property name="fill">True</property> - <property name="position">25</property> + <property name="position">27</property> </packing> </child> <child> @@ -1262,7 +1303,7 @@ <packing> <property name="expand">False</property> <property name="fill">True</property> - <property name="position">26</property> + <property name="position">28</property> </packing> </child> <child> @@ -1288,7 +1329,7 @@ <packing> <property name="expand">False</property> <property name="fill">True</property> - <property name="position">27</property> + <property name="position">29</property> </packing> </child> <child> @@ -1303,7 +1344,7 @@ <packing> <property name="expand">False</property> <property name="fill">True</property> - <property name="position">28</property> + <property name="position">30</property> </packing> </child> <child> @@ -1331,7 +1372,7 @@ <packing> <property name="expand">False</property> <property name="fill">True</property> - <property name="position">29</property> + <property name="position">31</property> </packing> </child> </object>
