void getAnchorPos(SwPosition& rPos)
{ // get the top most anchor position of the position if (SwFrameFormat* pFlyFormat = rPos.GetNode().GetFlyFormat())
{
SwNode* pAnchorNode;
SwFrameFormat* pTmp = pFlyFormat; while (pTmp && (pAnchorNode = pTmp->GetAnchor().GetAnchorNode()) &&
(pTmp = pAnchorNode->GetFlyFormat()))
{
pFlyFormat = pTmp;
} if (const SwPosition* pPos = pFlyFormat->GetAnchor().GetContentAnchor())
rPos = *pPos;
}
}
returnfalse;
} // Gets "YPos" for content, i.e. a number used to sort content members in Navigator's list
sal_Int32 getYPos(const SwNode& rNode)
{
SwNodeOffset nIndex = rNode.GetIndex(); if (rNode.GetNodes().GetEndOfExtras().GetIndex() >= nIndex)
{ // Not a node of BodyText // Are we in a fly? if (constauto pFlyFormat = rNode.GetFlyFormat())
{ // Get node index of anchor if (SwNode* pAnchorNode = pFlyFormat->GetAnchor().GetAnchorNode())
{ return getYPos(*pAnchorNode);
}
}
} return sal_Int32(nIndex);
}
} // end of anonymous namespace
// tdf#157250 Show deleted headings tracked changes in the Navigator only when show // tracked changes is on if (m_pWrtShell->GetLayout()->IsHideRedlines()
&& pNode->GetRedlineMergeFlag() != SwNode::Merge::None && aEntry.isEmpty()) continue;
auto pCnt(std::make_unique<SwOutlineContent>(this, aEntry, i, nLevel,
m_pWrtShell->IsOutlineMovable(i), nYPos)); if (!pNode->getLayoutFrame(m_pWrtShell->GetLayout()))
pCnt->SetInvisible();
m_pMember->insert(std::move(pCnt));
}
// need to check level and equal entry number after creation due to possible outline // nodes in frames, headers, footers if (pOldMember)
{
assert(pbContentChanged && "pbContentChanged is always set if pOldMember is"); if (pOldMember->size() != m_pMember->size())
{
*pbContentChanged = true; break;
} for (size_t i = 0; i < pOldMember->size(); i++)
{ if (static_cast<SwOutlineContent*>((*pOldMember)[i].get())->GetOutlineLevel() != static_cast<SwOutlineContent*>((*m_pMember)[i].get())->GetOutlineLevel())
{
*pbContentChanged = true; break;
}
}
}
} break; case ContentTypeId::TABLE :
{ const size_t nCount = m_pWrtShell->GetTableFrameFormatCount(true); const sw::TableFrameFormats* pFrameFormats = m_pWrtShell->GetDoc()->GetTableFrameFormats(); for(size_t n = 0, i = 0; i < nCount + n; ++i)
{ const SwTableFormat& rTableFormat = *(*pFrameFormats)[i]; if(!rTableFormat.IsUsed()) // skip deleted tables
{
n++; continue;
}
tools::Long nYPos = 0; if (!m_bAlphabeticSort)
{ if (SwTable* pTable = SwTable::FindTable(&rTableFormat))
nYPos = getYPos(*pTable->GetTableNode());
} auto pCnt = std::make_unique<SwContent>(this, rTableFormat.GetName().toString(), nYPos); if(!rTableFormat.IsVisible())
pCnt->SetInvisible();
m_pMember->insert(std::move(pCnt));
}
if (pOldMember)
{ // need to check visibility (and equal entry number) after // creation due to a sorted list being used here (before, // entries with same index were compared already at creation // time what worked before a sorted list was used)
*pbContentChanged = checkVisibilityChanged(
*pOldMember,
*m_pMember);
}
} break; case ContentTypeId::OLE : case ContentTypeId::FRAME : case ContentTypeId::GRAPHIC :
{
FlyCntType eType = FLYCNTTYPE_FRM; if(m_nContentType == ContentTypeId::OLE)
eType = FLYCNTTYPE_OLE; elseif(m_nContentType == ContentTypeId::GRAPHIC)
eType = FLYCNTTYPE_GRF;
Point aNullPt;
size_t nCount = m_pWrtShell->GetFlyCount(eType, /*bIgnoreTextBoxes=*/true);
std::vector<SwFrameFormat const*> formats(m_pWrtShell->GetFlyFrameFormats(eType, /*bIgnoreTextBoxes=*/true));
SAL_WARN_IF(nCount != formats.size(), "sw.ui", "Count differs");
nCount = formats.size(); for (size_t i = 0; i < nCount; ++i)
{
SwFrameFormat const*const pFrameFormat = formats[i]; const UIName sFrameName = pFrameFormat->GetName();
auto pCnt(std::make_unique<SwRegionContent>(this, sSectionName.toString(), nLevel,
m_bAlphabeticSort ? 0 : getYPos(pNodeIndex->GetNode()),
pFormat));
if (!pFormat->IsVisible() || pSection->IsHidden())
pCnt->SetInvisible();
m_pMember->insert(std::move(pCnt));
}
if (pOldMember)
{ // need to check visibility (and equal entry number) after // creation due to a sorted list being used here (before, // entries with same index were compared already at creation // time what worked before a sorted list was used)
assert(pbContentChanged && "pbContentChanged is always set if pOldMember is");
*pbContentChanged = checkVisibilityChanged(
*pOldMember,
*m_pMember);
}
}
} break; case ContentTypeId::REFERENCE:
{
std::vector<OUString> aRefMarks;
m_pWrtShell->GetRefMarks( &aRefMarks );
if (m_bAlphabeticSort)
{ for (auto& r : aArr)
{ auto pCnt(std::make_unique<SwURLFieldContent>(this, r.sText, INetURLObject::decode(
r.rINetAttr.GetINetFormat().GetValue(),
INetURLObject::DecodeMechanism::Unambiguous),
&r.rINetAttr, 0));
m_pMember->insert(std::move(pCnt));
} break;
}
// use stable sort array to list hyperlinks in document order const SwNodeOffset nEndOfExtrasIndex = m_pWrtShell->GetNodes().GetEndOfExtras().GetIndex(); bool bHasEntryInFly = false;
std::vector<SwGetINetAttr*> aStableSortINetAttrsArray;
for (SwGetINetAttr& r : aArr)
{
aStableSortINetAttrsArray.emplace_back(&r); if (!bHasEntryInFly)
{ if (nEndOfExtrasIndex >= r.rINetAttr.GetTextNode().GetIndex())
{ // Not a node of BodyText // Are we in a fly? if (r.rINetAttr.GetTextNode().GetFlyFormat())
bHasEntryInFly = true;
}
}
}
// When there are hyperlinks 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(aStableSortINetAttrsArray.begin(), aStableSortINetAttrsArray.end(),
[nEndOfExtrasIndex](const SwGetINetAttr* a, const SwGetINetAttr* b){ const SwTextNode& aTextNode = a->rINetAttr.GetTextNode(); const SwTextNode& bTextNode = b->rINetAttr.GetTextNode();
SwPosition aPos(aTextNode, a->rINetAttr.GetStart());
SwPosition bPos(bTextNode, b->rINetAttr.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;});
}
SwGetINetAttrs::size_type n = 0; for (auto p : aStableSortINetAttrsArray)
{ auto pCnt = std::make_unique<SwURLFieldContent>(this, p->sText,
INetURLObject::decode(p->rINetAttr.GetINetFormat().GetValue(),
INetURLObject::DecodeMechanism::Unambiguous),
&p->rINetAttr, ++n);
m_pMember->insert(std::move(pCnt));
}
} break; case ContentTypeId::INDEX:
{ const sal_uInt16 nCount = m_pWrtShell->GetTOXCount();
m_pMember->insert( std::unique_ptr<SwContent>(pCnt) ); const size_t nPos = m_pMember->size() - 1; if (pOldMember)
{
assert(pbContentChanged && "pbContentChanged is always set if pOldMember is"); if (!*pbContentChanged && nOldMemberCount > nPos &&
(*pOldMember)[nPos]->IsInvisible() != pCnt->IsInvisible())
*pbContentChanged = true;
}
}
} break; case ContentTypeId::POSTIT:
{
SwPostItMgr* aMgr = m_pWrtShell->GetView().GetPostItMgr(); if (aMgr)
{
tools::Long nYPos = 0; for(SwPostItMgr::const_iterator i = aMgr->begin(); i != aMgr->end(); ++i)
{ if (const SwFormatField* pFormatField = dynamic_cast<const SwFormatField *>((*i)->GetBroadcaster())) // SwPostit
{ if (pFormatField->GetTextField() && pFormatField->IsFieldInDoc())
{
OUString sEntry = pFormatField->GetField()->GetPar2();
sEntry = RemoveNewline(sEntry);
std::unique_ptr<SwPostItContent> pCnt(new SwPostItContent( this,
sEntry,
pFormatField,
nYPos)); if (!pFormatField->GetTextField()->GetTextNode().getLayoutFrame(
m_pWrtShell->GetLayout()))
pCnt->SetInvisible(); if (pOldMember)
{
assert(pbContentChanged && "pbContentChanged is always set if pOldMember is"); if (!*pbContentChanged &&
nOldMemberCount > o3tl::make_unsigned(nYPos) &&
(*pOldMember)[nYPos]->IsInvisible() != pCnt->IsInvisible())
*pbContentChanged = true;
}
m_pMember->insert(std::move(pCnt));
nYPos++;
}
}
}
}
} break; case ContentTypeId::DRAWOBJECT:
{
IDocumentDrawModelAccess& rIDDMA = m_pWrtShell->getIDocumentDrawModelAccess();
SwDrawModel* pModel = rIDDMA.GetDrawModel(); if(pModel)
{
SdrPage* pPage = pModel->GetPage(0); for (const rtl::Reference<SdrObject>& pTemp : *pPage)
{ // #i51726# - all drawing objects can be named now if (!pTemp->IsVirtualObj() && !pTemp->GetName().isEmpty())
{
tools::Long nYPos = LONG_MIN; constbool bIsVisible = rIDDMA.IsVisibleLayerId(pTemp->GetLayer()); if (bIsVisible)
nYPos = m_bAlphabeticSort ? 0 : pTemp->GetLogicRect().Top(); auto pCnt(std::make_unique<SwContent>(this, pTemp->GetName(), nYPos)); if (!bIsVisible)
pCnt->SetInvisible();
m_pMember->insert(std::move(pCnt));
}
}
if (pOldMember)
{ // need to check visibility (and equal entry number) after // creation due to a sorted list being used here (before, // entries with same index were compared already at creation // time what worked before a sorted list was used)
assert(pbContentChanged && "pbContentChanged is always set if pOldMember is");
*pbContentChanged = checkVisibilityChanged(
*pOldMember,
*m_pMember);
}
}
} break; default: break;
}
m_nMemberCount = m_pMember->size(); if (pOldMember)
{
assert(pbContentChanged && "pbContentChanged is always set if pOldMember is"); if (!*pbContentChanged && pOldMember->size() != m_nMemberCount)
*pbContentChanged = true;
}
IMPL_LINK(SwContentTree, MouseMoveHdl, const MouseEvent&, rMEvt, bool)
{ // Prevent trying to bring entry to attention when handling document change. The mouse over // entry might not be valid, for example, when the mouse pointer is on an entry that is deleted // in the document by an undo/redo. if (m_bDocHasChanged) returnfalse; if (m_eState == State::HIDDEN) returnfalse; if (std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
m_xTreeView->get_dest_row_at_pos(rMEvt.GetPosPixel(), xEntry.get(), false, false) &&
!rMEvt.IsLeaveWindow())
{ if (!m_xOverlayCompareEntry)
m_xOverlayCompareEntry.reset(m_xTreeView->make_iterator().release()); elseif (m_xTreeView->iter_compare(*xEntry, *m_xOverlayCompareEntry) == 0) returnfalse; // The entry under the mouse has not changed.
m_xTreeView->copy_iterator(*xEntry, *m_xOverlayCompareEntry);
BringEntryToAttention(*xEntry);
} else
{ if (m_xOverlayCompareEntry)
m_xOverlayCompareEntry.reset();
m_aOverlayObjectDelayTimer.Stop(); if (m_xOverlayObject && m_xOverlayObject->getOverlayManager())
{
m_xOverlayObject->getOverlayManager()->remove(*m_xOverlayObject);
m_xOverlayObject.reset();
}
} returnfalse;
}
if (nAccept != DND_ACTION_NONE)
{ // to enable the autoscroll when we're close to the edges
weld::TreeView& rWidget = m_rTreeView.get_widget();
rWidget.get_dest_row_at_pos(rEvt.maPosPixel, nullptr, true);
}
if (m_nRootType == ContentTypeId::OUTLINE)
{ if (xDropEntry && lcl_IsContent(*xDropEntry, *m_xTreeView))
{
assert(dynamic_cast<SwContent*>(weld::fromId<SwTypeNumber*>(m_xTreeView->get_id(*xDropEntry))));
SwOutlineContent* pOutlineContent = weld::fromId<SwOutlineContent*>(m_xTreeView->get_id(*xDropEntry));
assert(pOutlineContent);
void* key = lcl_GetOutlineKey(*this, pOutlineContent);
assert(key); if (!mOutLineNodeMap[key])
{ while (m_xTreeView->iter_has_child(*xDropEntry))
{
std::unique_ptr<weld::TreeIter> xChildEntry(m_xTreeView->make_iterator(xDropEntry.get())); bool bChildEntry = m_xTreeView->iter_children(*xChildEntry); while (bChildEntry)
{
m_xTreeView->copy_iterator(*xChildEntry, *xDropEntry);
bChildEntry = m_xTreeView->iter_next_sibling(*xChildEntry);
}
}
}
}
SwOutlineNodes::size_type nTargetPos = 0; if (!xDropEntry)
{ // dropped in blank space -> move to bottom
nTargetPos = GetWrtShell()->getIDocumentOutlineNodesAccess()->getOutlineNodesCount() - 1;
} elseif (!lcl_IsContent(*xDropEntry, *m_xTreeView))
{ // dropped on "heading" parent -> move to start
nTargetPos = SwOutlineNodes::npos;
} else
{
assert(dynamic_cast<SwOutlineContent*>(weld::fromId<SwTypeNumber*>(m_xTreeView->get_id(*xDropEntry))));
nTargetPos = weld::fromId<SwOutlineContent*>(m_xTreeView->get_id(*xDropEntry))->GetOutlinePos();
}
if( MAXLEVEL > m_nOutlineLevel && // Not all layers are displayed.
nTargetPos != SwOutlineNodes::npos)
{
std::unique_ptr<weld::TreeIter> xNext(m_xTreeView->make_iterator(xDropEntry.get())); bool bNext = m_xTreeView->iter_next(*xNext); if (bNext)
{
assert(dynamic_cast<SwOutlineContent*>(weld::fromId<SwTypeNumber*>(m_xTreeView->get_id(*xNext))));
nTargetPos = weld::fromId<SwOutlineContent*>(m_xTreeView->get_id(*xNext))->GetOutlinePos() - 1;
} else
nTargetPos = GetWrtShell()->getIDocumentOutlineNodesAccess()->getOutlineNodesCount() - 1;
}
// remove the drop highlight before we change the contents of the tree so we don't // try and dereference a removed entry in post-processing drop
m_xTreeView->unset_drag_dest_row();
MoveOutline(nTargetPos);
do
{ if (rContentTree.iter_has_child(*xChild) || rContentTree.get_children_on_demand(*xChild))
{ if (!IsAllExpanded(rContentTree, *xChild)) returnfalse;
}
} while (rContentTree.iter_next_sibling(*xChild)); returntrue;
}
// test for content in outline node
aIdx.Assign(*pSttNd); if (SwNodes::GoNext(&aIdx) != pEndNd)
{
bHasContent = true; break;
}
}
}
if (!bHasContent) return; // no content in any of the concerned outline nodes
}
// determine for subs if all are folded or unfolded or if they are mixed if (rContentTree.iter_has_child(rEntry) || rContentTree.get_children_on_demand(rEntry))
{ // skip no content nodes // we know there is content from results above so this is presumably safe
size_t nPos = nOutlinePos; while (true)
{
SwNode* pSttNd = rOutlineNodes[nPos];
SwNode* pEndNd = rOutlineNodes.back(); if (!bIsRoot && rOutlineNodes.size() > nPos + 1)
pEndNd = rOutlineNodes[nPos + 1];
SwNodeIndex aIdx(*pSttNd); if (SwNodes::GoNext(&aIdx) != pEndNd) break;
nPos++;
}
// select clicked entry or limit selection to root entry if needed if (std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
rCEvt.IsMouseEvent() && m_xTreeView->get_dest_row_at_pos(
rCEvt.GetMousePosPixel(), xEntry.get(), false))
{ // if clicked entry is not currently selected then clear selections and select it if (!m_xTreeView->is_selected(*xEntry))
m_xTreeView->set_cursor(*xEntry); // if root entry is selected then clear selections and select it elseif (m_xTreeView->is_selected(0))
m_xTreeView->set_cursor(0);
}
if (bRemoveToggleExpandEntry)
xPop->remove(OUString::number(800));
if (bRemoveGotoEntry)
xPop->remove(OUString::number(900));
if (bRemoveSelectEntry)
xPop->remove(OUString::number(805));
if (bRemoveChapterEntries)
{
xPop->remove(OUString::number(801));
xPop->remove(OUString::number(802));
xPop->remove(OUString::number(803));
xPop->remove(OUString::number(804));
}
if (bRemoveSendOutlineEntry)
xPop->remove(OUString::number(700));
if (bRemovePostItEntries)
{
xPop->remove(u"showcomments"_ustr);
xPop->remove(u"showresolvedcomments"_ustr);
}
if (bRemoveDeleteChapterEntry)
xPop->remove(u"deletechapter"_ustr);
if (bRemoveDeleteAllTablesEntry)
xPop->remove(u"deletealltables"_ustr);
if (bRemoveDeleteTableEntry)
xPop->remove(u"deletetable"_ustr);
if (bRemoveDeleteAllFramesEntry)
xPop->remove(u"deleteallframes"_ustr);
if (bRemoveDeleteFrameEntry)
xPop->remove(u"deleteframe"_ustr);
if (bRemoveDeleteAllImagesEntry)
xPop->remove(u"deleteallimages"_ustr);
if (bRemoveDeleteImageEntry)
xPop->remove(u"deleteimage"_ustr);
if (bRemoveDeleteAllOLEObjectsEntry)
xPop->remove(u"deletealloleobjects"_ustr);
if (bRemoveDeleteOLEObjectEntry)
xPop->remove(u"deleteoleobject"_ustr);
if (bRemoveDeleteAllBookmarksEntry)
xPop->remove(u"deleteallbookmarks"_ustr);
if (bRemoveDeleteBookmarkEntry)
xPop->remove(u"deletebookmark"_ustr);
if (bRemoveDeleteAllRegionsEntry)
xPop->remove(u"deleteallregions"_ustr);
if (bRemoveDeleteRegionEntry)
xPop->remove(u"deleteregion"_ustr);
if (bRemoveDeleteAllHyperlinksEntry)
xPop->remove(u"deleteallhyperlinks"_ustr);
if (bRemoveDeleteHyperlinkEntry)
xPop->remove(u"deletehyperlink"_ustr);
if (bRemoveDeleteAllReferencesEntry)
xPop->remove(u"deleteallreferences"_ustr);
if (bRemoveDeleteReferenceEntry)
xPop->remove(u"deletereference"_ustr);
if (bRemoveDeleteAllIndexesEntry)
xPop->remove(u"deleteallindexes"_ustr);
if (bRemoveDeleteIndexEntry)
xPop->remove(u"deleteindex"_ustr);
if (bRemoveDeleteAllCommentsEntry)
xPop->remove(u"deleteallcomments"_ustr);
if (bRemoveDeleteCommentEntry)
xPop->remove(u"deletecomment"_ustr);
if (bRemoveDeleteAllDrawingObjectsEntry)
xPop->remove(u"deletealldrawingobjects"_ustr);
if (bRemoveDeleteDrawingObjectEntry)
xPop->remove(u"deletedrawingobject"_ustr);
if (bRemoveDeleteAllFieldsEntry)
xPop->remove(u"deleteallfields"_ustr);
if (bRemoveDeleteFieldEntry)
xPop->remove(u"deletefield"_ustr);
if (bRemoveDeleteAllFootnotesEntry)
xPop->remove(u"deleteallfootnotes"_ustr);
if (bRemoveDeleteFootnoteEntry)
xPop->remove(u"deletefootnote"_ustr);
if (bRemoveDeleteAllEndnotesEntry)
xPop->remove(u"deleteallendnotes"_ustr);
if (bRemoveDeleteEndnoteEntry)
xPop->remove(u"deleteendnote"_ustr);
if (bRemoveMakeAllFootnotesEndnotesEntry)
xPop->remove(u"makeallfootnotesendnotes"_ustr);
if (bRemoveMakeAllEndnotesFootnotesEntry)
xPop->remove(u"makeallendnotesfootnotes"_ustr);
if (!bOutline)
{
xSubPop1.reset();
xPop->remove(OUString::number(1)); // outline level menu
}
if (!bOutline || State::HIDDEN == m_eState)
{
xSubPopOutlineTracking.reset();
xPop->remove(OUString::number(4)); // outline tracking menu
}
if (!bOutline || State::HIDDEN == m_eState ||
!m_pActiveShell->GetViewOptions()->IsShowOutlineContentVisibilityButton() ||
m_pActiveShell->getIDocumentOutlineNodesAccess()->getOutlineNodesCount() == 0)
{
xSubPopOutlineContent.reset();
xPop->remove(OUString::number(5)); // outline folding menu
xPop->remove(u"separator3"_ustr);
}
if (bRemoveTableTracking)
xPop->remove(u"tabletracking"_ustr);
if (bRemoveSectionTracking)
xPop->remove(u"sectiontracking"_ustr);
if (bRemoveFrameTracking)
xPop->remove(u"frametracking"_ustr);
if (bRemoveImageTracking)
xPop->remove(u"imagetracking"_ustr);
if (bRemoveOLEobjectTracking)
xPop->remove(u"oleobjecttracking"_ustr);
if (bRemoveBookmarkTracking)
xPop->remove(u"bookmarktracking"_ustr);
if (bRemoveHyperlinkTracking)
xPop->remove(u"hyperlinktracking"_ustr);
if (bRemoveReferenceTracking)
xPop->remove(u"referencetracking"_ustr);
if (bRemoveIndexTracking)
xPop->remove(u"indextracking"_ustr);
if (bRemoveCommentTracking)
xPop->remove(u"commenttracking"_ustr);
if (bRemoveDrawingObjectTracking)
xPop->remove(u"drawingobjecttracking"_ustr);
if (bRemoveFieldTracking)
xPop->remove(u"fieldtracking"_ustr);
if (bRemoveFootnoteTracking)
xPop->remove(u"footnotetracking"_ustr);
if (bRemoveEndnoteTracking)
xPop->remove(u"endnotetracking"_ustr);
if (bRemoveSortEntry)
xPop->remove(u"sort"_ustr);
if (bRemoveProtectSection)
xPop->remove(u"protectsection"_ustr);
if (bRemoveHideSection)
xPop->remove(u"hidesection"_ustr);
// Content will be integrated into the Box only on demand.
bool SwContentTree::RequestingChildren(const weld::TreeIter& rParent)
{
// Does the parent already have children or is it not a 'children on demand' node?
if (m_xTreeView->iter_has_child(rParent) || !m_xTreeView->get_children_on_demand(rParent))
return false;
// Is this a content type?
if (lcl_IsContentType(rParent, *m_xTreeView))
{
std::unique_ptr<weld::TreeIter> xChild = m_xTreeView->make_iterator();
// if there is a preceding outline node candidate with a lower outline level
// use that as a parent, otherwise use the root node
auto aFind = std::find_if(aParentCandidates.rbegin(),
aParentCandidates.rend(), lambda);
if (aFind != aParentCandidates.rend())
insert(aFind->get(), sEntry, sId, false, xChild.get());
else
insert(&rParent, sEntry, sId, false, xChild.get());
m_xTreeView->set_sensitive(*xChild, !pCnt->IsInvisible());
m_xTreeView->set_extra_row_indent(
*xChild, nLevel + 1 - m_xTreeView->get_iter_depth(*xChild));
// remove any parent candidates equal to or higher than this node
std::erase_if(aParentCandidates, std::not_fn(lambda));
// add this node as a parent candidate for any following nodes at a higher
// outline level
aParentCandidates.emplace_back(m_xTreeView->make_iterator(xChild.get()));
}
}
}
}
else if (pCntType->GetType() == ContentTypeId::REGION)
{
if (pCntType->IsAlphabeticSort())
{
for(size_t i = 0; i < nCount; ++i)
{
const SwRegionContent* pCnt =
static_cast<const SwRegionContent*>(pCntType->GetMember(i));
const auto nLevel = pCnt->GetRegionLevel();
auto lambda = [nLevel, this](const std::unique_ptr<weld::TreeIter>& xEntry)
{
return lcl_IsLowerRegionContent(*xEntry, *m_xTreeView, nLevel);
};
// if there is a preceding region node candidate with a lower region level use
// that as a parent, otherwise use the root node
auto aFind = std::find_if(aParentCandidates.rbegin(), aParentCandidates.rend(), lambda);
if (aFind != aParentCandidates.rend())
insert(aFind->get(), sEntry, sId, false, xChild.get());
else
insert(&rParent, sEntry, sId, false, xChild.get());
m_xTreeView->set_sensitive(*xChild, !pCnt->IsInvisible());
// remove any parent candidates equal to or higher than this node
std::erase_if(aParentCandidates, std::not_fn(lambda));
// add this node as a parent candidate for any following nodes at a higher region level
aParentCandidates.emplace_back(m_xTreeView->make_iterator(xChild.get()));
}
}
}
else if (pCntType->GetType() == ContentTypeId::POSTIT)
{
std::vector<std::unique_ptr<weld::TreeIter>> aParentCandidates;
for(size_t i = 0; i < nCount; ++i)
{
const SwPostItContent* pCnt =
static_cast<const SwPostItContent*>(pCntType->GetMember(i));
// if a parent candidate is not found use the passed root node
auto aFind = std::find_if(aParentCandidates.rbegin(), aParentCandidates.rend(), lambda);
if (aFind != aParentCandidates.rend())
insert(aFind->get(), sEntry, sId, false, xChild.get());
else
insert(&rParent, sEntry, sId, false, xChild.get());
// clear parent candidates when encountering a postit that doesn't have a parent
// following postits can't have a parent that is in these candidates
if (pPostItField->GetParentPostItId() == 0)
aParentCandidates.clear();
// pNodesToExpand is used by the Display function to restore the trees expand structure for
// hierarchical content types, e.g., OUTLINE and REGION.
if (pNodesToExpand)
pNodesToExpand->emplace_back(m_xTreeView->make_iterator(&rParent));
// rParentId is a string representation of a pointer to SwContentType or SwContent
const OUString aParentId = m_xTreeView->get_id(rParent);
// bParentIsContentType tells if the passed rParent tree entry is a content type or content
const bool bParentIsContentType = lcl_IsContentType(rParent, *m_xTreeView);
// eParentContentTypeId is the content type of the passed rParent tree entry
const ContentTypeId eParentContentTypeId =
bParentIsContentType ? weld::fromId<SwContentType*>(aParentId)->GetType() :
weld::fromId<SwContent*>(aParentId)->GetParent()->GetType();
if (m_nRootType == ContentTypeId::UNKNOWN && bParentIsContentType)
{
// m_nActiveBlock and m_nHiddenBlock are used to persist the content type expand state for
// the all content view mode
const int nShift = static_cast<int>(eParentContentTypeId);
SAL_WARN_IF(nShift < 0, "sw.ui", "ContentTypeId::UNKNOWN negative shift");
if (nShift >= 0)
{
const sal_Int32 nOr = 1 << nShift; //linear -> Bitposition
if (State::HIDDEN != m_eState)
{
m_nActiveBlock |= nOr;
m_pConfig->SetActiveBlock(m_nActiveBlock);
}
else
m_nHiddenBlock |= nOr;
}
}
if (lcl_IsContentType(rParent, *m_xTreeView))
{
if (m_bIsRoot)
{
// collapse to children of root node
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(&rParent));
if (m_xTreeView->iter_children(*xEntry))
{
do
{
m_xTreeView->collapse_row(*xEntry);
}
while (m_xTreeView->iter_next(*xEntry));
}
return false; // return false to notify caller not to do collapse
}
ContentTypeId eContentTypeId =
weld::fromId<SwContentType*>(m_xTreeView->get_id(rParent))->GetType();
const int nShift = static_cast<int>(eContentTypeId);
SAL_WARN_IF(nShift < 0, "sw.ui", "ContentTypeId::UNKNOWN negative shift");
if (nShift >= 0)
{
const sal_Int32 nAnd = ~(1 << nShift);
if (State::HIDDEN != m_eState)
{
m_nActiveBlock &= nAnd;
m_pConfig->SetActiveBlock(m_nActiveBlock);
}
else
m_nHiddenBlock &= nAnd;
}
}
else // content entry
{
SwWrtShell* pShell = GetWrtShell();
ContentTypeId eContentTypeId =
weld::fromId<SwContent*>(m_xTreeView->get_id(rParent))->GetParent()->GetType();
if (eContentTypeId == ContentTypeId::OUTLINE)
{
assert(dynamic_cast<SwOutlineContent*>(weld::fromId<SwTypeNumber*>(m_xTreeView->get_id(rParent))));
auto const nPos = weld::fromId<SwOutlineContent*>(m_xTreeView->get_id(rParent))->GetOutlinePos();
void* key = static_cast<void*>(pShell->getIDocumentOutlineNodesAccess()->getOutlineNode( nPos ));
mOutLineNodeMap[key] = false;
}
else if(eContentTypeId == ContentTypeId::REGION)
{
assert(dynamic_cast<SwRegionContent*>(weld::fromId<SwTypeNumber*>(m_xTreeView->get_id(rParent))));
const void* key = static_cast<const void*>(weld::fromId<SwRegionContent*>(m_xTreeView->get_id(rParent))->GetSectionFormat());
m_aRegionNodeExpandMap[key] = false;
}
else if(eContentTypeId == ContentTypeId::POSTIT)
{
assert(dynamic_cast<SwPostItContent*>(weld::fromId<SwTypeNumber*>(m_xTreeView->get_id(rParent))));
const void* key = static_cast<const void*>(weld::fromId<SwPostItContent*>(m_xTreeView->get_id(rParent))->GetPostIt());
m_aPostItNodeExpandMap[key] = false;
}
}
return true;
}
// Also on double click will be initially opened only.
IMPL_LINK_NOARG(SwContentTree, ContentDoubleClickHdl, weld::TreeView&, bool)
{
if (m_nRowActivateEventId)
Application::RemoveUserEvent(m_nRowActivateEventId);
// post the event to process row activate after mouse press event to be able to set key
// modifier for selection feature (tdf#154211)
m_nRowActivateEventId
= Application::PostUserEvent(LINK(this, SwContentTree, AsyncContentDoubleClickHdl));
bool bConsumed = false;
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
if (m_xTreeView->get_cursor(xEntry.get()) && lcl_IsContent(*xEntry, *m_xTreeView) &&
(State::HIDDEN != m_eState))
{
SwContent* pCnt = weld::fromId<SwContent*>(m_xTreeView->get_id(*xEntry));
assert(pCnt && "no UserData");
if (pCnt && !pCnt->IsInvisible())
{
// fdo#36308 don't expand outlines on double-click
bConsumed = pCnt->GetParent()->GetType() == ContentTypeId::OUTLINE;
}
}
return bConsumed; // false/true == allow/disallow more to be done, i.e. expand/collapse children
}
size_t nCount = 0;
auto nRefDepth = m_xTreeView->get_iter_depth(*xParent);
auto nActDepth = nRefDepth;
do
{
if (!m_xTreeView->iter_next(*xParent))
xParent.reset();
else
nActDepth = m_xTreeView->get_iter_depth(*xParent);
nCount++;
} while(xParent && nRefDepth < nActDepth);
nCount--;
return nCount;
}
std::unique_ptr<weld::TreeIter> SwContentTree::GetEntryAtAbsPos(size_t nAbsPos) const
{
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
if (!m_xTreeView->get_iter_first(*xEntry))
xEntry.reset();
while (nAbsPos && xEntry)
{
if (!m_xTreeView->iter_next(*xEntry))
xEntry.reset();
nAbsPos--;
}
return xEntry;
}
void SwContentTree::Display( bool bActive )
{
// First read the selected entry to select it later again if necessary
// -> the user data here are no longer valid!
std::unique_ptr<weld::TreeIter> xOldSelEntry(m_xTreeView->make_iterator());
if (!m_xTreeView->get_selected(xOldSelEntry.get()))
xOldSelEntry.reset();
size_t nEntryRelPos = 0; // relative position to their parent
size_t nOldEntryCount = GetEntryCount();
sal_Int32 nOldScrollPos = 0;
if (xOldSelEntry)
{
UpdateLastSelType();
nOldScrollPos = m_xTreeView->vadjustment_get_value();
std::unique_ptr<weld::TreeIter> xParentEntry = m_xTreeView->make_iterator(xOldSelEntry.get());
while (m_xTreeView->get_iter_depth(*xParentEntry))
m_xTreeView->iter_parent(*xParentEntry);
if (m_xTreeView->get_iter_depth(*xOldSelEntry))
nEntryRelPos = GetAbsPos(*xOldSelEntry) - GetAbsPos(*xParentEntry);
}
if (!bActive)
{
m_aOverlayObjectDelayTimer.Stop();
if (m_xOverlayObject && m_xOverlayObject->getOverlayManager())
{
m_xOverlayObject->getOverlayManager()->remove(*m_xOverlayObject);
m_xOverlayObject.reset();
}
m_eState = State::HIDDEN;
}
else if (State::HIDDEN == m_eState)
m_eState = State::ACTIVE;
if (!bChOnDemand)
InsertContent(*xEntry);
else
{
// fill contents of to-be expanded entries while frozen
Expand(*xEntry, &aNodesToExpand);
m_xTreeView->set_children_on_demand(*xEntry, false);
}
if (bChOnDemand)
{
// restore visual expanded tree state
for (const auto& rNode : aNodesToExpand)
m_xTreeView->expand_row(*rNode);
}
else
m_xTreeView->expand_row(*xEntry);
}
// Reselect the old selected entry. If it is not available, select the entry at the old
// selected entry position unless that entry position is now a content type or is past the
// end of the member list then select the entry at the previous entry position.
if (xOldSelEntry)
{
std::unique_ptr<weld::TreeIter> xSelEntry = m_xTreeView->make_iterator(xCntTypeEntry.get());
if (nEntryRelPos)
{
std::unique_ptr<weld::TreeIter> xIter(m_xTreeView->make_iterator(xCntTypeEntry.get()));
std::unique_ptr<weld::TreeIter> xTemp(m_xTreeView->make_iterator(xIter.get()));
sal_uLong nPos = 1;
bool bNext;
while ((bNext = m_xTreeView->iter_next(*xIter) && lcl_IsContent(*xIter, *m_xTreeView)))
{
if (nPos == nEntryRelPos)
{
m_xTreeView->copy_iterator(*xIter, *xSelEntry);
break;
}
m_xTreeView->copy_iterator(*xIter, *xTemp); // note previous entry
nPos++;
}
if (!bNext)
xSelEntry = std::move(xTemp);
}
// set_cursor unselects all entries, makes passed entry visible, and selects it
m_xTreeView->set_cursor(*xSelEntry);
}
UpdateContentFunctionsToolbar();
}
if (!m_bIgnoreDocChange && GetEntryCount() == nOldEntryCount)
{
m_xTreeView->vadjustment_set_value(nOldScrollPos);
}
}
sCrossRef = OUString::number(static_cast<int>(eReferenceSubType)) + u"|"
+ sEntry + u"|" + sVal;
}
else if (eActType == ContentTypeId::OUTLINE)
{
sEntry = sOutlineText;
const SwOutlineNodes::size_type nPos =
static_cast<SwOutlineContent*>(pCnt)->GetOutlinePos();
const SwTextNode* pTextNode =
pWrtShell->GetNodes().GetOutLineNds()[nPos]->GetTextNode();
sw::mark::MarkBase const * const pMark =
pWrtShell->getIDocumentMarkAccess()->getMarkForTextNode(
*pTextNode, IDocumentMarkAccess::MarkType::CROSSREF_HEADING_BOOKMARK);
// REFERENCESUBTYPE_OUTLINE is changed to REFERENCESUBTYPE::BOOKMARK in
// SwWrtShell::NavigatorPaste. It is used to differentiate between a
// headings reference and a regular bookmark reference to show different
// options in the reference mark type popup menu.
sCrossRef = OUString::number(static_cast<int>(REFERENCESUBTYPE::REF_OUTLINE))
+ u"|" + pMark->GetName().toString();
}
}
// An INetBookmark must a be delivered to foreign DocShells
if (bUrl && pDocShell->HasName())
{
INetBookmark aBkmk( sUrl, sEntry );
rTransfer.CopyINetBookmark( aBkmk );
}
}
return true;
}
void SwContentTree::ToggleToRoot()
{
if(!m_bIsRoot)
{
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
bool bEntry = m_xTreeView->get_cursor(xEntry.get());
if (bEntry)
{
const SwContentType* pCntType;
if (lcl_IsContentType(*xEntry, *m_xTreeView))
{
assert(dynamic_cast<SwContentType*>(weld::fromId<SwTypeNumber*>(m_xTreeView->get_id(*xEntry))));
pCntType = weld::fromId<SwContentType*>(m_xTreeView->get_id(*xEntry));
}
else
{
assert(dynamic_cast<SwContent*>(weld::fromId<SwTypeNumber*>(m_xTreeView->get_id(*xEntry))));
pCntType = weld::fromId<SwContent*>(m_xTreeView->get_id(*xEntry))->GetParent();
}
m_nRootType = pCntType->GetType();
m_bIsRoot = true;
if (m_nRootType == ContentTypeId::OUTLINE || m_nRootType == ContentTypeId::DRAWOBJECT)
{
m_xTreeView->set_selection_mode(SelectionMode::Multiple);
}
Display(State::HIDDEN != m_eState);
}
}
else
{
m_xTreeView->set_selection_mode(SelectionMode::Single);
m_nLastSelType = m_nRootType;
m_nRootType = ContentTypeId::UNKNOWN;
m_bIsRoot = false;
// Other content type member data could have changed while in root view. Fill the content
// member lists excluding the toggled from root content which should already have the most
// recent data.
if (State::HIDDEN != m_eState)
{
for (ContentTypeId i : o3tl::enumrange<ContentTypeId>())
{
if (i != m_nLastSelType && m_aActiveContentArr[i])
m_aActiveContentArr[i]->FillMemberList();
}
}
Display(State::HIDDEN != m_eState);
}
m_pConfig->SetRootType( m_nRootType );
weld::Toolbar* pBox = GetParentWindow()->m_xContent5ToolBox.get();
pBox->set_item_active(u"root"_ustr, m_bIsRoot);
}
bool SwContentTree::HasContentChanged()
{
if (m_bEditing)
{
return false;
}
bool bContentChanged = false;
// - Run through the local array and the Treelistbox in parallel.
// - Are the records not expanded, they are discarded only in the array
// and the content type will be set as the new UserData.
// - Is the root mode is active only this will be updated.
// Valid for the displayed content types is:
// the Memberlist will be erased and the membercount will be updated
// If content will be checked, the memberlists will be replenished
// at the same time. Once a difference occurs it will be only replenished
// no longer checked. Finally, the box is filled again.
if (State::HIDDEN == m_eState)
{
for(ContentTypeId i : o3tl::enumrange<ContentTypeId>())
{
if(m_aActiveContentArr[i])
m_aActiveContentArr[i]->Invalidate();
}
return false;
}
// single content type navigation view
if(m_bIsRoot)
{
std::unique_ptr<weld::TreeIter> xRootEntry(m_xTreeView->make_iterator());
if (!m_xTreeView->get_iter_first(*xRootEntry))
return true;
pArrType->FillMemberList(&bContentChanged);
if (bContentChanged)
return true;
// FillMemberList tests if member count in old member array equals member count in new
// member array. Test here for member count difference between array and tree.
const size_t nChildCount = GetChildCount(*xRootEntry);
if (nChildCount != pArrType->GetMemberCount())
return true;
// FillMemberList clears the content type member list and refills with new data.
// Treeview entry user data is set here to the string representation of the pointer to
// the member data in the array. The Display function will clear and recreate the
// treeview from the content type member arrays if content change is detected.
const SwContent* pCnt = pArrType->GetMember(j);
if (pCnt->IsInvisible() != m_xTreeView->get_sensitive(*xEntry, 0))
return true;
// Set_id needs to be done here because FillMemberList clears the content type member
// list and refills with new data making the previously set id invalid. If there is no
// content change detected the Display function will not be called and the tree entry
// user data will not be set to the new content member pointer address.
OUString sSubId(weld::toId(pCnt));
m_xTreeView->set_id(*xEntry, sSubId);
}
}
// all content types navigation view
else
{
// Fill member list for each content type and check for content change. If content change
// is detected only fill member lists for remaining content types. The Display function
// will clear and recreate the treeview from the content type member arrays if content has
// changed.
if (comphelper::LibreOfficeKit::isActive())
{
// In case of LOK, empty contentTypes are hidden, even in all content view
// so it is not enough to check only the m_xTreeView.
bool bCountChanged = false;
bool bHasContentChanged = false;
for (ContentTypeId i : o3tl::enumrange<ContentTypeId>())
{
if (m_aActiveContentArr[i])
{
auto nLastTMCount = m_aActiveContentArr[i]->GetMemberCount();
if (i == ContentTypeId::OUTLINE) // this is required for checking if header level is changed
m_aActiveContentArr[i]->FillMemberList(&bHasContentChanged);
else
m_aActiveContentArr[i]->FillMemberList();
// If the member count of a type is changed, then the content is surely changed
if (m_aActiveContentArr[i]->GetMemberCount() != nLastTMCount)
bCountChanged = true;
if (bHasContentChanged)
bContentChanged = true;
}
}
if (bCountChanged || bContentChanged)
return true;
}
// lambda function to find the next content type entry
auto lcl_nextContentTypeEntry = [this, &xEntry](){
while (m_xTreeView->get_iter_depth(*xEntry))
m_xTreeView->iter_parent(*xEntry);
return m_xTreeView->iter_next_sibling(*xEntry);
};
if (!pArrType)
{
bContentChanged = true;
continue;
}
// all content type member lists must be filled!
if (bContentChanged)
{
// If content change has already been detected there is no need to detect
// other content change so no argument is supplied here to FillMemberList.
pArrType->FillMemberList();
continue;
}
pArrType->FillMemberList(&bContentChanged);
if (bContentChanged)
continue;
// does entry have children?
if (m_xTreeView->get_row_expanded(*xEntry))
{
const size_t nChildCount = GetChildCount(*xEntry);
if(nChildCount != pArrType->GetMemberCount())
{
bContentChanged = true;
continue;
}
// If clear is called by TimerUpdate:
// Only for root can the validity of the UserData be guaranteed.
m_xTreeView->all_foreach([this](weld::TreeIter& rEntry){
m_xTreeView->set_id(rEntry, u""_ustr);
return false;
});
}
// tdf#148432 in LTR UI override the navigator treeview direction based on
// the first page directionality
if (m_pActiveShell && !AllSettings::GetLayoutRTL())
{
const SwPageDesc& rDesc = m_pActiveShell->GetPageDesc(0);
const SvxFrameDirectionItem& rFrameDir = rDesc.GetMaster().GetFrameDir();
m_xTreeView->set_direction(rFrameDir.GetValue() == SvxFrameDirection::Horizontal_RL_TB);
}
// Only if it is the active view, the array will be deleted and
// the screen filled new.
if (State::ACTIVE == m_eState && bClear)
{
if (m_pActiveShell)
StartListening(*m_pActiveShell->GetView().GetDocShell());
FindActiveTypeAndRemoveUserData();
for(ContentTypeId i : o3tl::enumrange<ContentTypeId>())
{
m_aActiveContentArr[i].reset();
}
Display(true);
}
}
m_xTreeView->selected_foreach([&](weld::TreeIter& rEntry){
// it's possible to select the root node too which is a really bad idea if (lcl_IsContentType(rEntry, *m_xTreeView))
return false;
// filter out children of selected parents so they don't get promoted
// or moved twice (except if there is Ctrl modifier, since in that
// case children are re-parented) if ((bLeftRight || bOutlineWithChildren) && !selected.empty())
{
std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(&rEntry)); for (bool bParent = m_xTreeView->iter_parent(*xParent); bParent; bParent = m_xTreeView->iter_parent(*xParent))
{ if (m_xTreeView->iter_compare(*selected.back(), *xParent) == 0)
{
return false;
}
}
}
selected.emplace_back(m_xTreeView->make_iterator(&rEntry));
// Use the outline node position in the SwOutlineNodes array. Bad things
// happen if the tree entry position is used and it doesn't match the node position
// in SwOutlineNodes, which is usually the case for outline nodes in frames.
const SwOutlineNodes::size_type nPos
= weld::fromId<SwOutlineContent*>(m_xTreeView->get_id(rEntry))->GetOutlinePos(); if (nPos < nOutlineNdsSize)
{
SwNode* pNode = rNodes.GetOutLineNds()[ nPos ]; if (pNode)
{
selectedOutlineNodes.push_back(pNode->GetTextNode());
}
}
return false;
});
if (!selected.size())
return;
if (bUpDown && !bUp)
{ // to move down, start at the end!
std::reverse(selected.begin(), selected.end());
}
// outline nodes in frames and tables are not up/down moveable if (nActPos == SwOutlineNodes::npos ||
(bUpDown && (!pShell->IsOutlineMovable(nActPos) ||
nFirstRegularDocContentOutlineNodePos == SwOutlineNodes::npos)))
{
// except inline headings, i.e. Inline Heading frames with
// single outlines, and anchored as characters, which headings
// are movable with their anchor node, if they are
// 1) not in other frames or 2) not in tables and 3) not protected
const SwNode* pRootNode = nHasInlineHeading > 0
? SwOutlineNodes::GetRootNode(rOutlineNodes[nActPos])
: nullptr; if ( !pRootNode || pRootNode == rOutlineNodes[nActPos] ||
pRootNode != SwOutlineNodes::GetRootNode(pRootNode) || // frame in frame
pRootNode->FindTableNode() || // frame in table
pRootNode->IsProtect() ) // write protection
{
continue;
}
}
// move outline position up/down (outline position promote/demote)
SwOutlineNodes::difference_type nDir = bUp ? -1 : 1;
SwOutlineNodesInline::size_type nActPosInline;
aOutlineNodesInline.Seek_Entry(rOutlineNodes[nActPos], &nActPosInline); if ( (nDir == -1 && nActPosInline > 0) ||
(nDir == 1 && nActPosInline < nOutlineNdsSizeInline - 1) )
{
// make outline selection for use by MoveOutlinePara
pShell->MakeOutlineSel(nActPos, nActPos, bOutlineWithChildren, true, &aOutlineNodesInline);
int nActPosOutlineLevel =
rOutlineNodes[nActPos]->GetTextNode()->GetAttrOutlineLevel();
// search for sorted position
SwOutlineNodesInline::size_type nPos;
aOutlineNodesInline.Seek_Entry_By_Anchor(SwOutlineNodes::GetRootNode(rOutlineNodes[nActPos]), &nPos); if (!bUp)
{
// move down
int nPosOutlineLevel = -1; while (++nPos < nOutlineNdsSizeInline)
{
nPosOutlineLevel = aOutlineNodesInline[nPos]->GetTextNode()->GetAttrOutlineLevel();
// discontinue if moving out of parent or equal level is found if (nPosOutlineLevel <= nActPosOutlineLevel)
{
break;
}
// count the children of the node when they are not included in the move if (!bOutlineWithChildren)
nDir++;
} if (nPosOutlineLevel >= nActPosOutlineLevel)
{
// move past children while (++nPos < nOutlineNdsSizeInline)
{
nPosOutlineLevel = aOutlineNodesInline[nPos]->GetTextNode()->GetAttrOutlineLevel();
// discontinue if moving out of parent or equal level is found if (nPosOutlineLevel <= nActPosOutlineLevel)
break;
nDir++;
}
}
} else
{
// move up while (nPos && --nPos >= nFirstRegularDocContentOutlineNodePos - nHasInlineHeading)
{
int nPosOutlineLevel =
aOutlineNodesInline[nPos]->GetTextNode()->GetAttrOutlineLevel();
// discontinue if equal level is found if (nPosOutlineLevel == nActPosOutlineLevel)
{
break;
}
// discontinue if moving out of parent if (nPosOutlineLevel < nActPosOutlineLevel)
{
// Required for expected chapter placement when the chapter being moved
// up has an outline level less than the outline level of chapters it
// is being moved above and then encounters a chapter with an outline
// level that is greater before reaching a chapter with the same
// outline level as itself. if (nDir < -1)
nDir++;
break;
}
nDir--;
}
}
pShell->MoveOutlinePara(nDir, &aOutlineNodesInline);
}
pShell->ClearMark();
} elseif (bUpDown)
{
// move outline position up/down (outline position promote/demote)
SwOutlineNodes::difference_type nDir = bUp ? -1 : 1; if ((nDir == -1 && nActPos > 0) || (nDir == 1 && nActPos < nOutlineNdsSize - 1))
{
// make outline selection for use by MoveOutlinePara
pShell->MakeOutlineSel(nActPos, nActPos, bOutlineWithChildren);
int nActPosOutlineLevel =
rOutlineNodes[nActPos]->GetTextNode()->GetAttrOutlineLevel();
SwOutlineNodes::size_type nPos = nActPos; if (!bUp)
{
// move down
int nPosOutlineLevel = -1; while (++nPos < nOutlineNdsSize)
{
nPosOutlineLevel =
rOutlineNodes[nPos]->GetTextNode()->GetAttrOutlineLevel();
// discontinue if moving out of parent or equal level is found if (nPosOutlineLevel <= nActPosOutlineLevel)
break;
// count the children of the node when they are not included in the move if (!bOutlineWithChildren)
nDir++;
} if (nPosOutlineLevel >= nActPosOutlineLevel)
{
// move past children while (++nPos < nOutlineNdsSize)
{
nPosOutlineLevel =
rOutlineNodes[nPos]->GetTextNode()->GetAttrOutlineLevel();
// discontinue if moving out of parent or equal level is found if (nPosOutlineLevel <= nActPosOutlineLevel)
break;
nDir++;
}
}
} else
{
// move up while (nPos && --nPos >= nFirstRegularDocContentOutlineNodePos)
{
int nPosOutlineLevel =
rOutlineNodes[nPos]->GetTextNode()->GetAttrOutlineLevel();
// discontinue if equal level is found if (nPosOutlineLevel == nActPosOutlineLevel)
break;
// discontinue if moving out of parent if (nPosOutlineLevel < nActPosOutlineLevel)
{
// Required for expected chapter placement when the chapter being moved
// up has an outline level less than the outline level of chapters it
// is being moved above and then encounters a chapter with an outline
// level that is greater before reaching a chapter with the same
// outline level as itself. if (nDir < -1)
nDir++;
break;
}
nDir--;
}
}
pShell->MoveOutlinePara(nDir);
}
pShell->ClearMark();
} else
{
// move outline left/right (outline level promote/demote) if (!pShell->IsProtectedOutlinePara())
{
bool bAllow = true;
const SwOutlineNodes& rOutlNds = pShell->GetDoc()->GetNodes().GetOutLineNds();
const int nActLevel = rOutlNds[nActPos]->GetTextNode()->GetAttrOutlineLevel(); if (!bLeft)
{
// disallow if any outline node to demote will exceed MAXLEVEL
SwOutlineNodes::size_type nPos = nActPos; do
{
int nLevel = rOutlNds[nPos]->GetTextNode()->GetAttrOutlineLevel(); if (nLevel == MAXLEVEL)
{
bAllow = false;
break;
}
} while (bOutlineWithChildren && ++nPos < rOutlNds.size() &&
rOutlNds[nPos]->GetTextNode()->GetAttrOutlineLevel() > nActLevel);
} else
{
// disallow if trying to promote outline of level 1 if (nActLevel == 1)
bAllow = false;
} if (bAllow)
{
SwOutlineNodes::size_type nPos = nActPos; do
{
pShell->SwCursorShell::GotoOutline(nPos);
pShell->OutlineUpDown(bLeft ? -1 : 1);
} while (bOutlineWithChildren && ++nPos < rOutlNds.size() &&
rOutlNds[nPos]->GetTextNode()->GetAttrOutlineLevel() > nActLevel);
}
}
}
pShell->Pop(SwCursorShell::PopMode::DeleteCurrent); // Cursor is now back at the current heading.
}
if (bStartedAction)
{
pShell->EndUndo();
pShell->EndAllAction(); if (m_aActiveContentArr[ContentTypeId::OUTLINE])
m_aActiveContentArr[ContentTypeId::OUTLINE]->Invalidate();
// tdf#143547 LO Writer: navigator should stand still on promoting and demoting
// In addition to m_bIgnoreDocChange being true, selections are cleared before the Display
// call. Either of these conditions disable restore of scroll position happening in the
// Display function so it needs to be done here.
auto nOldScrollPos = m_xTreeView->vadjustment_get_value();
// clear all selections to prevent the Display function from trying to reselect selected entries
m_xTreeView->unselect_all();
Display(true);
m_xTreeView->vadjustment_set_value(nOldScrollPos);
if (m_bIsRoot)
{
// reselect entries, do this only when in outline content navigation mode
const SwOutlineNodes& rOutlineNds = pShell->GetNodes().GetOutLineNds(); for (SwTextNode* pNode : selectedOutlineNodes)
{
m_xTreeView->all_foreach([this, &rOutlineNds, pNode](weld::TreeIter& rEntry){ if (lcl_IsContentType(rEntry, *m_xTreeView))
return false;
SwOutlineNodes::size_type nPos = weld::fromId<SwOutlineContent*>(
m_xTreeView->get_id(rEntry))->GetOutlinePos(); if (pNode == rOutlineNds[nPos]->GetTextNode())
{
std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(&rEntry)); if (m_xTreeView->iter_parent(*xParent)
&& !m_xTreeView->get_row_expanded(*xParent))
{
m_xTreeView->expand_row(*xParent);
}
m_xTreeView->select(rEntry);
return true;
}
return false;
});
}
UpdateContentFunctionsToolbar();
} else
{
m_pActiveShell->GetView().GetEditWin().GrabFocus();
m_bIgnoreDocChange = false;
UpdateTracking();
grab_focus();
}
}
m_bIgnoreDocChange = false;
}
// find content type entry
std::unique_ptr<weld::TreeIter> xIter(rContentTree.make_iterator());
bool bFoundEntry = rContentTree.get_iter_first(*xIter); while (bFoundEntry && rContentTypeName != rContentTree.get_text(*xIter))
bFoundEntry = rContentTree.iter_next_sibling(*xIter);
// find content type content entry and select it if (!bFoundEntry)
return;
rContentTree.expand_row(*xIter); // assure content type entry is expanded while (rContentTree.iter_next(*xIter) && lcl_IsContent(*xIter, rContentTree))
{ if (rName == rContentTree.get_text(*xIter))
{
// get first selected for comparison
std::unique_ptr<weld::TreeIter> xFirstSelected(rContentTree.make_iterator()); if (!rContentTree.get_selected(xFirstSelected.get()))
xFirstSelected.reset(); if (rContentTree.count_selected_rows() != 1 || !xFirstSelected ||
rContentTree.iter_compare(*xIter, *xFirstSelected) != 0)
{
// unselect all entries and make passed entry visible and selected
rContentTree.set_cursor(*xIter);
pThis->UpdateContentFunctionsToolbar();
}
break;
}
}
}
// find content type entry
std::unique_ptr<weld::TreeIter> xIter(rContentTree.make_iterator());
bool bFoundEntry = rContentTree.get_iter_first(*xIter); while (bFoundEntry && SwResId(STR_CONTENT_TYPE_DRAWOBJECT) != rContentTree.get_text(*xIter))
bFoundEntry = rContentTree.iter_next_sibling(*xIter);
// find content type content entry and select it if (bFoundEntry)
{
rContentTree.expand_row(*xIter); // assure content type entry is expanded while (rContentTree.iter_next(*xIter) && lcl_IsContent(*xIter, rContentTree))
{ if (rName == rContentTree.get_text(*xIter))
{ if (!rContentTree.is_selected(*xIter))
{
rContentTree.select(*xIter);
rContentTree.scroll_to_row(*xIter);
pThis->UpdateContentFunctionsToolbar();
}
break;
}
}
}
}
/** No idle with focus or while dragging */
IMPL_LINK_NOARG(SwContentTree, TimerUpdate, Timer *, void)
{
// No need to update if content tree is not visible if (!m_xTreeView->is_visible())
return;
// No update while focus is not in document.
// No update while drag and drop.
// Query view because the Navigator is cleared too late.
SwView* pView = GetParentWindow()->GetCreateView();
void SwContentTree::UpdateTracking()
{ if (State::HIDDEN == m_eState || !m_pActiveShell)
return;
// only when treeview or treeview context menu does not have focus if (m_xTreeView->has_focus() || m_xTreeView->has_child_focus())
return;
// m_bIgnoreDocChange is set on delete and outline visibility toggle if (m_bIgnoreDocChange)
{
m_bIgnoreDocChange = false;
return;
}
// bTrack is used to disallow tracking after jumping to an outline until the outline position
// that was jumped to is no longer the current outline position.
bool bTrack = true; if (m_nLastGotoContentWasOutlinePos != SwOutlineNodes::npos)
{ if (m_pActiveShell->GetOutlinePos() == m_nLastGotoContentWasOutlinePos)
bTrack = false; else
m_nLastGotoContentWasOutlinePos = SwOutlineNodes::npos;
}
if (bTrack)
{
// graphic, frame, and ole if (m_pActiveShell->GetSelectionType() &
(SelectionType::Graphic | SelectionType::Frame | SelectionType::Ole))
{
OUString aContentTypeName; if (m_pActiveShell->GetSelectionType() == SelectionType::Graphic &&
!(m_bIsRoot && m_nRootType != ContentTypeId::GRAPHIC))
{ if (!mTrackContentType[ContentTypeId::GRAPHIC]) return;
aContentTypeName = SwResId(STR_CONTENT_TYPE_GRAPHIC);
} elseif (m_pActiveShell->GetSelectionType() == SelectionType::Frame &&
!(m_bIsRoot && m_nRootType != ContentTypeId::FRAME))
{ if (!mTrackContentType[ContentTypeId::FRAME]) return;
aContentTypeName = SwResId(STR_CONTENT_TYPE_FRAME);
} elseif (m_pActiveShell->GetSelectionType() == SelectionType::Ole &&
!(m_bIsRoot && m_nRootType != ContentTypeId::OLE))
{ if (!mTrackContentType[ContentTypeId::OLE]) return;
aContentTypeName = SwResId(STR_CONTENT_TYPE_OLE);
} if (!aContentTypeName.isEmpty())
{
UIName aName(m_pActiveShell->GetFlyName());
lcl_SelectByContentTypeAndName(this, *m_xTreeView, aContentTypeName, aName.toString());
return;
}
}
// drawing if ((m_pActiveShell->GetSelectionType() & (SelectionType::DrawObject |
SelectionType::DrawObjectEditMode |
SelectionType::DbForm)) &&
!(m_bIsRoot && m_nRootType != ContentTypeId::DRAWOBJECT))
{ if (mTrackContentType[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)
{ for (size_t nIdx(0); nIdx < pSdrView->GetMarkedObjectList().GetMarkCount(); nIdx++)
{
SdrObject* pSelected = pSdrView->GetMarkedObjectList().GetMark(nIdx)->GetMarkedSdrObj();
OUString aName(pSelected->GetName()); if (!aName.isEmpty())
lcl_SelectDrawObjectByName(this, *m_xTreeView, aName);
}
} else
{
// clear treeview selections
m_xTreeView->unselect_all();
UpdateContentFunctionsToolbar();
}
}
return;
}
// footnotes and endnotes if (SwContentAtPos aContentAtPos(IsAttrAtPos::Footnote);
m_pActiveShell->GetContentAtPos(m_pActiveShell->GetCursorDocPos(), aContentAtPos)
&& aContentAtPos.pFndTextAttr &&
!(m_bIsRoot && (m_nRootType != ContentTypeId::FOOTNOTE &&
m_nRootType != ContentTypeId::ENDNOTE)))
{ if (!aContentAtPos.pFndTextAttr->GetFootnote().IsEndNote())
{ if (mTrackContentType[ContentTypeId::FOOTNOTE])
lcl_SelectByContentTypeAndAddress(this, *m_xTreeView, ContentTypeId::FOOTNOTE,
aContentAtPos.pFndTextAttr);
} elseif (mTrackContentType[ContentTypeId::ENDNOTE])
lcl_SelectByContentTypeAndAddress(this, *m_xTreeView, ContentTypeId::ENDNOTE,
aContentAtPos.pFndTextAttr);
return;
}
// references if (SwContentAtPos aContentAtPos(IsAttrAtPos::RefMark);
m_pActiveShell->GetContentAtPos(m_pActiveShell->GetCursorDocPos(), aContentAtPos) &&
aContentAtPos.pFndTextAttr &&
!(m_bIsRoot && m_nRootType != ContentTypeId::REFERENCE))
{ if (mTrackContentType[ContentTypeId::REFERENCE])
{
const SwFormatRefMark& rRefMark = aContentAtPos.pFndTextAttr->GetRefMark();
lcl_SelectByContentTypeAndName(this, *m_xTreeView, SwResId(STR_CONTENT_TYPE_REFERENCE),
rRefMark.GetRefName().toString());
}
return;
}
// hyperlinks
// not in ToxContent tdf#148312 if (const SwSection* pSection = m_pActiveShell->GetCurrSection(); !pSection
|| (pSection && pSection->GetType() != SectionType::ToxContent))
{ if (SwContentAtPos aContentAtPos(IsAttrAtPos::InetAttr);
m_pActiveShell->GetContentAtPos(m_pActiveShell->GetCursorDocPos(), aContentAtPos)
&& (!m_bIsRoot || m_nRootType == ContentTypeId::URLFIELD))
{
// Because hyperlink item names do not need to be unique, finding the corresponding
// item 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. if (mTrackContentType[ContentTypeId::URLFIELD])
lcl_SelectByContentTypeAndAddress(this, *m_xTreeView, ContentTypeId::URLFIELD,
aContentAtPos.pFndTextAttr);
return;
}
}
// fields, comments if (SwField* pField = m_pActiveShell->GetCurField(); pField &&
!(m_bIsRoot &&
m_nRootType != ContentTypeId::TEXTFIELD &&
m_nRootType != ContentTypeId::POSTIT))
{
ContentTypeId eCntTypeId =
pField->GetTypeId() == SwFieldTypesEnum::Postit ? ContentTypeId::POSTIT :
ContentTypeId::TEXTFIELD; if (mTrackContentType[eCntTypeId])
lcl_SelectByContentTypeAndAddress(this, *m_xTreeView, eCntTypeId, pField);
return;
} if (SwPostItMgr* pPostItMgr = m_pActiveShell->GetPostItMgr();
pPostItMgr && pPostItMgr->HasActiveAnnotationWin()
&& !(m_bIsRoot && m_nRootType != ContentTypeId::POSTIT))
{ if (mTrackContentType[ContentTypeId::POSTIT])
{ if (const SwField* pField = pPostItMgr->GetActiveSidebarWin()->GetPostItField())
lcl_SelectByContentTypeAndAddress(this, *m_xTreeView, ContentTypeId::POSTIT,
pField);
}
return;
}
// table if (m_pActiveShell->IsCursorInTable() &&
!(m_bIsRoot && m_nRootType != ContentTypeId::TABLE))
{ if (mTrackContentType[ContentTypeId::TABLE] && m_pActiveShell->GetTableFormat())
{
UIName aName = m_pActiveShell->GetTableFormat()->GetName();
lcl_SelectByContentTypeAndName(this, *m_xTreeView, SwResId(STR_CONTENT_TYPE_TABLE),
aName.toString());
return;
}
}
// indexes if (const SwTOXBase* pTOX = m_pActiveShell->GetCurTOX(); pTOX &&
!(m_bIsRoot && m_nRootType != ContentTypeId::INDEX))
{ if (mTrackContentType[ContentTypeId::INDEX])
lcl_SelectByContentTypeAndName(this, *m_xTreeView, SwResId(STR_CONTENT_TYPE_INDEX),
pTOX->GetTOXName().toString());
return;
}
// section if (const SwSection* pSection = m_pActiveShell->GetCurrSection(); pSection &&
!(m_bIsRoot && m_nRootType != ContentTypeId::REGION))
{ if (mTrackContentType[ContentTypeId::REGION])
{
lcl_SelectByContentTypeAndName(this, *m_xTreeView, SwResId(STR_CONTENT_TYPE_REGION),
pSection->GetSectionName().toString());
return;
} else
{
// prevent fall through to outline tracking when section tracking is off and the last
// GotoContent is the current section if (m_nLastSelType == ContentTypeId::REGION &&
m_xTreeView->get_selected_text() == pSection->GetSectionName())
return;
}
// fall through to outline tracking when section tracking is off and the last GotoContent
// is not the current section
}
}
// find out where the cursor is
const SwOutlineNodes::size_type nActPos = GetWrtShell()->GetOutlinePos(MAXLEVEL); if (m_nOutlineTracking != 3
&& !((m_bIsRoot && m_nRootType != ContentTypeId::OUTLINE)
|| nActPos == SwOutlineNodes::npos))
{
// assure outline content type is expanded
// this assumes outline content type is first in treeview
std::unique_ptr<weld::TreeIter> xFirstEntry(m_xTreeView->make_iterator()); if (m_xTreeView->get_iter_first(*xFirstEntry))
m_xTreeView->expand_row(*xFirstEntry);
m_xTreeView->all_foreach([this, nActPos](weld::TreeIter& rEntry){
bool bRet = false; if (lcl_IsContent(rEntry, *m_xTreeView) && weld::fromId<SwContent*>(
m_xTreeView->get_id(rEntry))->GetParent()->GetType() ==
ContentTypeId::OUTLINE)
{ if (weld::fromId<SwOutlineContent*>(
m_xTreeView->get_id(rEntry))->GetOutlinePos() == nActPos)
{
std::unique_ptr<weld::TreeIter> xFirstSelected(
m_xTreeView->make_iterator()); if (!m_xTreeView->get_selected(xFirstSelected.get()))
xFirstSelected.reset();
// only select if not already selected or tree has multiple entries selected if (m_xTreeView->count_selected_rows() != 1 || !xFirstSelected ||
m_xTreeView->iter_compare(rEntry, *xFirstSelected) != 0)
{ if (m_nOutlineTracking == 2) // focused outline tracking
{
// collapse to children of root node
std::unique_ptr<weld::TreeIter> xChildEntry(
m_xTreeView->make_iterator()); if (m_xTreeView->get_iter_first(*xChildEntry) &&
m_xTreeView->iter_children(*xChildEntry))
{ do
{ if (weld::fromId<SwContent*>(
m_xTreeView->get_id(*xChildEntry))->
GetParent()->GetType() == ContentTypeId::OUTLINE)
m_xTreeView->collapse_row(*xChildEntry); else
break;
} while (m_xTreeView->iter_next(*xChildEntry));
}
}
// unselect all entries, make pEntry visible, and select
m_xTreeView->set_cursor(rEntry);
UpdateContentFunctionsToolbar();
// tdf#149279 show at least two outline entries before the set cursor entry
std::unique_ptr<weld::TreeIter> xIter(m_xTreeView->make_iterator(&rEntry)); for (int i = 0; i < 2; i++)
{ if (m_xTreeView->get_iter_depth(*xIter) == 0)
break; if (!m_xTreeView->iter_previous(*xIter))
break; while (!weld::IsEntryVisible(*m_xTreeView, *xIter))
m_xTreeView->iter_parent(*xIter);
}
// Assure the scroll to row is collapsed after scrolling if it was collapsed
// before. This is required here to make gtkinst scroll_to_row behave like
// salinst.
const bool bRowExpanded = m_xTreeView->get_row_expanded(*xIter);
m_xTreeView->scroll_to_row(*xIter); if (!bRowExpanded)
m_xTreeView->collapse_row(*xIter);
}
bRet = true;
}
} else
{
// use of this break assumes outline content type is first in tree if (lcl_IsContentType(rEntry, *m_xTreeView) &&
weld::fromId<SwContentType*>(
m_xTreeView->get_id(rEntry))->GetType() !=
ContentTypeId::OUTLINE)
bRet = true;
}
return bRet;
});
return;
}
// bookmarks - track first bookmark at cursor
// tdf#159428 Only when no outline found. Showing the outline is more important than
// showing a bookmark at the cursor position. if (mTrackContentType[ContentTypeId::BOOKMARK] &&
(m_pActiveShell->GetSelectionType() & SelectionType::Text))
{
SwPaM* pCursor = m_pActiveShell->GetCursor();
IDocumentMarkAccess* const pMarkAccess = m_pActiveShell->getIDocumentMarkAccess();
auto ppBookmark = pMarkAccess->getBookmarksBegin(); if (pCursor && ppBookmark != pMarkAccess->getBookmarksEnd()
&& !(m_bIsRoot && m_nRootType != ContentTypeId::BOOKMARK))
{
SwMarkName sBookmarkName;
SwPosition* pCursorPoint = pCursor->GetPoint(); while (ppBookmark != pMarkAccess->getBookmarksEnd())
{ if (lcl_IsUiVisibleBookmark(*ppBookmark)
&& *pCursorPoint >= (*ppBookmark)->GetMarkStart()
&& *pCursorPoint <= (*ppBookmark)->GetMarkEnd())
{
sBookmarkName = (*ppBookmark)->GetName();
// keep previously selected bookmark instead
// of selecting a different bookmark inside of it if (sBookmarkName == m_sSelectedItem)
break;
} elseif (!sBookmarkName.isEmpty() && *pCursorPoint < (*ppBookmark)->GetMarkStart())
{
// don't search a different bookmark inside the
// previous one, if the starting position of the next bookmarks
// is after the cursor position (assuming that the
// bookmark iterator jumps inside the same text by positions)
break;
}
++ppBookmark;
}
if (!sBookmarkName.isEmpty())
{
// select the bookmark
lcl_SelectByContentTypeAndName(this, *m_xTreeView,
SwResId(STR_CONTENT_TYPE_BOOKMARK), sBookmarkName.toString());
return;
}
}
}
// find content type entry
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())
break;
bFoundEntry = rContentTree.iter_next_sibling(*xIter);
}
if (!bFoundEntry)
return false;
// find content type content entry and compare it to the passed entry while (rContentTree.iter_next(*xIter))
{ if (rName == rContentTree.get_text(*xIter))
{ if (rContentTree.iter_compare(*xIter, rEntry) == 0)
return true;
}
}
return false;
}
// Done on the first selection move if (bFirstMove) // only do once
{ if (nTargetPos == SwOutlineNodes::npos || nSourcePos > nTargetPos)
{
// Up moves
// The first up move sets the up move amount for the remaining selected outlines to be moved if (nTargetPos != SwOutlineNodes::npos)
nPrevTargetPosOrOffset = nSourcePos - nTargetPos; else
nPrevTargetPosOrOffset = nSourcePos + 1;
} elseif (nSourcePos < nTargetPos)
{
// Down moves
// The first down move sets the source and target positions for the remaining selected outlines to be moved
nPrevSourcePos = nSourcePos;
nPrevTargetPosOrOffset = nTargetPos;
}
bFirstMove = false;
} else
{ if (nTargetPos == SwOutlineNodes::npos || nSourcePos > nTargetPos)
{
// Move up
nTargetPos = nSourcePos - nPrevTargetPosOrOffset;
} elseif (nSourcePos < nTargetPos)
{
// Move down
nSourcePos = nPrevSourcePos;
nTargetPos = nPrevTargetPosOrOffset;
}
}
GetParentWindow()->MoveOutline(nSourcePos, nTargetPos);
}
}
} for (const rtl::Reference<SdrObject>& pTemp : *pPage)
{
bool bMark = pDrawView->IsObjMarked(pTemp.get());
switch( pTemp->GetObjIdentifier() )
{
case SdrObjKind::Group:
case SdrObjKind::Text:
case SdrObjKind::Line:
case SdrObjKind::Rectangle:
case SdrObjKind::CircleOrEllipse:
case SdrObjKind::CircleSection:
case SdrObjKind::CircleArc:
case SdrObjKind::CircleCut:
case SdrObjKind::Polygon:
case SdrObjKind::PolyLine:
case SdrObjKind::PathLine:
case SdrObjKind::PathFill:
case SdrObjKind::FreehandLine:
case SdrObjKind::FreehandFill:
case SdrObjKind::PathPoly:
case SdrObjKind::PathPolyLine:
case SdrObjKind::Caption:
case SdrObjKind::CustomShape: if( bMark )
hasObjectMarked = true;
break;
default: if ( bMark )
{
SdrPageView* pPV = pDrawView->GetSdrPageView/*GetPageViewPvNum*/(/*0*/); if (pPV)
{
pDrawView->MarkObj(pTemp.get(), pPV, true);
}
}
}
//mod end
} if ( !hasObjectMarked )
{
SwEditWin& rEditWindow = m_pActiveShell->GetView().GetEditWin();
vcl::KeyCode tempKeycode( KEY_ESCAPE );
KeyEvent rKEvt( 0 , tempKeycode );
static_cast<vcl::Window*>(&rEditWindow)->KeyInput( rKEvt );
}
}
}
IMPL_LINK(SwContentTree, QueryTooltipHdl, const weld::TreeIter&, rEntry, OUString)
{
// Prevent tool tip handling when handling document change. The entry that was present when
// the tooltip signal was fired might no longer be valid by the time it gets here. For example,
// when the mouse pointer is on an entry in the tree that is deleted in the document by an
// undo/redo. Please see similar note in MouseMoveHdl.
if (m_bDocHasChanged)
return OUString();
// tdf#163646 - Show in the tooltip for heading entries in Writer Navigator the
// outline word and character count of the heading including the outline word and
// character count of all sub headings
int nEntryDepth = m_xTreeView->get_iter_depth(rEntry);
std::unique_ptr<weld::TreeIter> xIter = m_xTreeView->make_iterator(&rEntry);
int nIterDepth;
while (m_xTreeView->iter_next(*xIter)
&& (nIterDepth = m_xTreeView->get_iter_depth(*xIter)))
{
if (nIterDepth <= nEntryDepth)
{
pOutlineContent
= weld::fromId<SwOutlineContent*>(m_xTreeView->get_id(*xIter));
pEndNode = rOutlineNodes[pOutlineContent->GetOutlinePos()];
break;
}
}
std::unique_ptr<weld::TreeIter> xFirst(m_xTreeView->make_iterator());
if (!m_xTreeView->get_selected(xFirst.get()))
return; // this shouldn't happen, but better to be safe than ...
// 1. Get the position of the bit in the block where the value of the alphabetical sort
// setting is persistently stored for the content type.
const int nShift = static_cast<int>(pCntType->GetType());
assert(nShift > -1);
// 2. Create a bit mask to use to filter the sort value from the persistent block.
const sal_Int32 nMask = 1 << nShift;
// 3. Toggle the persistent sort value only when it is different than the instance sort
// value. These may already be the same if both the floating and sidebar version of the
// Navigator are open.
const sal_Int32 nBlock = m_pConfig->GetSortAlphabeticallyBlock();
bool bConfigSortValue = ~nBlock & nMask;
bool bInstanceSortValue = pCntType->IsAlphabeticSort();
if (bConfigSortValue != bInstanceSortValue)
m_pConfig->SetSortAlphabeticallyBlock(nBlock ^ nMask);
// 4. Always toggle the instance value.
pCntType->SetAlphabeticSort(!bInstanceSortValue);
auto nSelectedPopupEntry = rSelectedPopupEntry.toUInt32();
switch (nSelectedPopupEntry)
{
case TOGGLE_OUTLINE_CONTENT_VISIBILITY:
case HIDE_OUTLINE_CONTENT_VISIBILITY:
case SHOW_OUTLINE_CONTENT_VISIBILITY:
{
m_pActiveShell->EnterStdMode();
m_bIgnoreDocChange = true;
SwOutlineContent* pCntFirst = weld::fromId<SwOutlineContent*>(m_xTreeView->get_id(*xFirst));
// toggle the outline node outline content visible attribute
if (nSelectedPopupEntry == TOGGLE_OUTLINE_CONTENT_VISIBILITY)
{
SwNode* pNode = m_pActiveShell->GetDoc()->GetNodes().GetOutLineNds()[pCntFirst->GetOutlinePos()];
pNode->GetTextNode()->SetAttrOutlineContentVisible(
!m_pActiveShell->GetAttrOutlineContentVisible(pCntFirst->GetOutlinePos()));
}
else
{
// with subs
SwOutlineNodes::size_type nPos = pCntFirst->GetOutlinePos();
if (lcl_IsContentType(*xFirst, *m_xTreeView)) // Headings root entry
nPos = SwOutlineNodes::npos;
SwOutlineNodes::size_type nOutlineNodesCount = m_pActiveShell->getIDocumentOutlineNodesAccess()->getOutlineNodesCount();
int nLevel = -1;
if (nPos != SwOutlineNodes::npos) // not root
nLevel = m_pActiveShell->getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos);
else
nPos = 0;
bool bShow(nSelectedPopupEntry == SHOW_OUTLINE_CONTENT_VISIBILITY);
do
{
if (m_pActiveShell->IsOutlineContentVisible(nPos) != bShow)
m_pActiveShell->GetDoc()->GetNodes().GetOutLineNds()[nPos]->GetTextNode()->SetAttrOutlineContentVisible(bShow);
} while (++nPos < nOutlineNodesCount
&& (nLevel == -1 || m_pActiveShell->getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos) > nLevel));
}
m_pActiveShell->InvalidateOutlineContentVisibility();
// show in the document what was toggled
if (lcl_IsContentType(*xFirst, *m_xTreeView)) // Headings root entry
m_pActiveShell->GotoPage(1, true);
else
m_pActiveShell->GotoOutline(pCntFirst->GetOutlinePos());
grab_focus();
m_bIgnoreDocChange = false;
m_pActiveShell->SetModified();
m_pActiveShell->GetDoc()->GetDocShell()->Broadcast(SfxHint(SfxHintId::DocChanged));
}
break;
case 11:
case 12:
case 13:
nSelectedPopupEntry -= 10;
if(m_nOutlineTracking != nSelectedPopupEntry)
SetOutlineTracking(static_cast<sal_uInt8>(nSelectedPopupEntry));
break;
//Outlinelevel
case 101:
case 102:
case 103:
case 104:
case 105:
case 106:
case 107:
case 108:
case 109:
case 110:
nSelectedPopupEntry -= 100;
if(m_nOutlineLevel != nSelectedPopupEntry )
SetOutlineLevel(static_cast<sal_Int8>(nSelectedPopupEntry));
break;
case 402:
EditEntry(*xFirst, EditEntryMode::UPD_IDX);
break;
// Edit entry
case 403:
EditEntry(*xFirst, EditEntryMode::EDIT);
break;
case 404:
EditEntry(*xFirst, EditEntryMode::UNPROTECT_TABLE);
break;
case 405 :
{
const SwTOXBase* pBase = weld::fromId<SwTOXBaseContent*>(m_xTreeView->get_id(*xFirst))
->GetTOXBase();
m_pActiveShell->SetTOXBaseReadonly(*pBase, !SwEditShell::IsTOXBaseReadonly(*pBase));
}
break;
case 502 :
EditEntry(*xFirst, EditEntryMode::RENAME);
break;
case 700:
{
m_pActiveShell->GetView().GetViewFrame().GetDispatcher()->Execute(FN_OUTLINE_TO_CLIPBOARD);
break;
}
case 800:
ExpandOrCollapseAll(*m_xTreeView, *xFirst);
break;
case 801:
ExecCommand(u"chapterup", true);
break;
case 802:
ExecCommand(u"chapterdown", true);
break;
case 803:
ExecCommand(u"promote", true);
break;
case 804:
ExecCommand(u"demote", true);
break;
case 805: // select document content
{
m_pActiveShell->KillPams();
m_pActiveShell->ClearMark();
m_pActiveShell->EnterAddMode();
SwContent* pCnt = weld::fromId<SwContent*>(m_xTreeView->get_id(*xFirst));
const ContentTypeId eTypeId = pCnt->GetParent()->GetType();
if (eTypeId == ContentTypeId::OUTLINE)
{
SwOutlineNodes::size_type nActPos = weld::fromId<SwOutlineContent*>(
m_xTreeView->get_id(*xFirst))->GetOutlinePos();
m_pActiveShell->GotoOutline(nActPos);
m_xTreeView->selected_foreach([this](weld::TreeIter& rEntry){
SwOutlineNodes::size_type nPos = weld::fromId<SwOutlineContent*>(
m_xTreeView->get_id(rEntry))->GetOutlinePos();
m_pActiveShell->SttSelect();
// select children if not expanded and don't kill PaMs
m_pActiveShell->MakeOutlineSel(nPos, nPos,
!m_xTreeView->get_row_expanded(rEntry), false);
m_pActiveShell->EndSelect();
return false;
});
}
else if (eTypeId == ContentTypeId::TABLE)
{
m_pActiveShell->GotoTable(UIName(pCnt->GetName()));
m_pActiveShell->GetView().GetViewFrame().GetDispatcher()->Execute(FN_TABLE_SELECT_ALL);
}
else if (eTypeId == ContentTypeId::REGION)
{
m_pActiveShell->EnterStdMode();
m_pActiveShell->GotoRegion(pCnt->GetName());
GotoCurrRegionAndSkip(m_pActiveShell->GetCurrentShellCursor(), fnRegionEnd, m_pActiveShell->IsReadOnlyAvailable());
m_pActiveShell->SttSelect();
GotoCurrRegionAndSkip(m_pActiveShell->GetCurrentShellCursor(), fnRegionStart, m_pActiveShell->IsReadOnlyAvailable());
m_pActiveShell->EndSelect();
m_pActiveShell->UpdateCursor();
}
m_pActiveShell->LeaveAddMode();
}
break;
case 900:
{
SwContent* pCnt = weld::fromId<SwContent*>(m_xTreeView->get_id(*xFirst));
GotoContent(pCnt);
}
break;
//Display
default:
if(nSelectedPopupEntry > 300 && nSelectedPopupEntry < 400)
{
nSelectedPopupEntry -= 300;
SwView *pView = SwModule::GetFirstView();
while (pView)
{
nSelectedPopupEntry --;
if(nSelectedPopupEntry == 0)
{
SetConstantShell(&pView->GetWrtShell());
break;
}
pView = SwModule::GetNextView(pView);
}
if(nSelectedPopupEntry)
{
m_bViewHasChanged = nSelectedPopupEntry == 1;
m_eState = (nSelectedPopupEntry == 1) ? State::ACTIVE : State::HIDDEN;
Display(nSelectedPopupEntry == 1);
}
GetParentWindow()->UpdateListBox();
}
}
}
void SwContentTree::DeleteOutlineSelections()
{
const SwOutlineNodes& rOutlineNodes = m_pActiveShell->GetNodes().GetOutLineNds();
auto nChapters(0);
m_pActiveShell->StartAction();
m_pActiveShell->EnterAddMode();
m_xTreeView->selected_foreach([this, &rOutlineNodes, &nChapters](weld::TreeIter& rEntry){
++nChapters;
if (m_xTreeView->iter_has_child(rEntry) &&
!m_xTreeView->get_row_expanded(rEntry)) // only count children if not expanded
{
nChapters += m_xTreeView->iter_n_children(rEntry);
}
SwOutlineNodes::size_type nActPos = weld::fromId<SwOutlineContent*>(m_xTreeView->get_id(rEntry))->GetOutlinePos();
if (m_pActiveShell->GetViewOptions()->IsShowOutlineContentVisibilityButton())
{
// make folded content visible so it can be selected
if (!m_pActiveShell->IsOutlineContentVisible(nActPos))
m_pActiveShell->MakeOutlineContentVisible(nActPos);
if (!m_xTreeView->get_row_expanded(rEntry))
{
// include children
SwNode* pNode = rOutlineNodes[nActPos];
const int nLevel = pNode->GetTextNode()->GetAttrOutlineLevel() - 1;
for (auto nPos = nActPos + 1; nPos < rOutlineNodes.size(); ++nPos)
{
pNode = rOutlineNodes[nPos];
const int nNextLevel = pNode->GetTextNode()->GetAttrOutlineLevel() - 1;
if (nNextLevel <= nLevel)
break;
if (!m_pActiveShell->IsOutlineContentVisible(nNextLevel))
m_pActiveShell->MakeOutlineContentVisible(nNextLevel);
}
}
}
m_pActiveShell->SttSelect();
m_pActiveShell->MakeOutlineSel(nActPos, nActPos, !m_xTreeView->get_row_expanded(rEntry), false); // select children if not expanded
// The outline selection may already be to the start of the following outline paragraph
// as happens when a table is the last content of the to be deleted outline. In this case
// do not extend the to be deleted selection right or the first character of the following
// outline paragraph will be removed. Also check if no selection was made which indicates
// an empty paragraph and selection right is needed.
if (!m_pActiveShell->IsSttPara() || !m_pActiveShell->HasSelection())
m_pActiveShell->Right(SwCursorSkipMode::Chars, true, 1, false);
m_pActiveShell->EndSelect();
return false;
});
m_pActiveShell->LeaveAddMode();
// Mode Change: Show active view
// only called from IMPL_LINK(SwNavigationPI, DocListBoxSelectHdl, weld::ComboBox&, rBox, void)
void SwContentTree::ShowActualView()
{
if (SwView* pView = m_pDialog->GetCreateView())
{
SetConstantShell(pView->GetWrtShellPtr());
m_pDialog->UpdateListBox();
}
}
IMPL_LINK_NOARG(SwContentTree, SelectHdl, weld::TreeView&, void)
{
if (m_pConfig->IsNavigateOnSelect())
{
ContentDoubleClickHdl(*m_xTreeView);
grab_focus();
}
UpdateContentFunctionsToolbar();
if (m_bIsRoot)
return;
// Select the content type in the Navigate By control
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
if (!m_xTreeView->get_selected(xEntry.get()))
return;
while (m_xTreeView->get_iter_depth(*xEntry))
m_xTreeView->iter_parent(*xEntry);
m_pDialog->SelectNavigateByContentType(m_xTreeView->get_text(*xEntry));
}
std::optional<SwPosition> oPosition;
if (m_bSelectTo)
oPosition.emplace(m_pActiveShell->GetCursor()->GetPoint()->nNode,
m_pActiveShell->GetCursor()->GetPoint()->nContent);
switch(m_nLastSelType = pCnt->GetParent()->GetType())
{
case ContentTypeId::TEXTFIELD:
{
m_pActiveShell->GotoFormatField(
*static_cast<const SwTextFieldContent*>(pCnt)->GetFormatField());
}
break;
case ContentTypeId::OUTLINE :
{
const SwOutlineNodes::size_type nPos =
static_cast<const SwOutlineContent*>(pCnt)->GetOutlinePos();
m_pActiveShell->GotoOutline(nPos);
m_nLastGotoContentWasOutlinePos = nPos;
}
break;
case ContentTypeId::TABLE :
{
m_pActiveShell->GotoTable(UIName(pCnt->GetName()));
}
break;
case ContentTypeId::FRAME :
case ContentTypeId::GRAPHIC :
case ContentTypeId::OLE :
{
m_pActiveShell->GotoFly(UIName(pCnt->GetName()));
}
break;
case ContentTypeId::BOOKMARK:
{
m_pActiveShell->StartAction();
m_pActiveShell->GotoMark(SwMarkName(pCnt->GetName()));
m_pActiveShell->EndAction();
m_sSelectedItem = pCnt->GetName();
// If the hidden title of SwNavigatorPanel was emptied via UNO XPanel interface,
// store the name of the selected bookmark there. This allows to query the
// selected bookmark using UNO e.g. in add-ons, i.e. to disambiguate when
// multiple bookmarks are there on the selected text range.
// Note: this is a workaround because getDialog() of XPanel is not implemented
// for SwNavigatorPanel.
rtl::Reference< SwXTextDocument > xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
Reference<frame::XController2> xController( xModel->getCurrentController(), uno::UNO_QUERY);
if ( !xController.is() )
break;
Reference<ui::XSidebarProvider> xSidebarProvider = xController->getSidebar();
if ( !xSidebarProvider.is() )
break;
Reference<ui::XDecks> xDecks = xSidebarProvider->getDecks();
if ( !xDecks.is() )
break;
if (!xDecks->hasByName(u"NavigatorDeck"_ustr))
break;
Reference<ui::XDeck> xDeck ( xDecks->getByName(u"NavigatorDeck"_ustr), uno::UNO_QUERY);
if ( !xDeck.is() )
break;
Reference<ui::XPanels> xPanels = xDeck->getPanels();
if ( !xPanels.is() )
break;
if (xPanels->hasByName(u"SwNavigatorPanel"_ustr))
{
Reference<ui::XPanel> xPanel ( xPanels->getByName(u"SwNavigatorPanel"_ustr), uno::UNO_QUERY);
if ( !xPanel.is() || !xPanel->getTitle().isEmpty() )
break;
xPanel->setTitle( pCnt->GetName() );
}
}
break;
case ContentTypeId::REGION :
{
m_pActiveShell->GotoRegion(pCnt->GetName());
}
break;
case ContentTypeId::URLFIELD:
{
if(m_pActiveShell->GotoINetAttr(
*static_cast<const SwURLFieldContent*>(pCnt)->GetINetAttr() ))
{
m_pActiveShell->Right(SwCursorSkipMode::Chars, false, 1, false);
}
}
break;
case ContentTypeId::REFERENCE:
{
m_pActiveShell->GotoRefMark(SwMarkName(pCnt->GetName()));
}
break;
case ContentTypeId::INDEX:
{
const UIName sName(pCnt->GetName());
if (!m_pActiveShell->GotoNextTOXBase(&sName))
m_pActiveShell->GotoPrevTOXBase(&sName);
}
break;
case ContentTypeId::POSTIT:
if (SwFormatField const*const pField{static_cast<const SwPostItContent*>(pCnt)->GetPostIt()})
{
m_pActiveShell->GotoFormatField(*pField);
}
break;
case ContentTypeId::DRAWOBJECT:
{
m_pActiveShell->GotoDrawingObject(pCnt->GetName());
}
break;
case ContentTypeId::FOOTNOTE:
case ContentTypeId::ENDNOTE:
{
const SwTextFootnote* pFootnote =
static_cast<const SwTextFootnoteContent*>(pCnt)->GetTextFootnote();
if (!pFootnote)
return;
m_pActiveShell->GotoFootnoteAnchor(*pFootnote);
}
break;
default: break;
}
if (m_bSelectTo)
{
m_pActiveShell->SttCursorMove();
while (m_pActiveShell->IsCursorInTable())
{
m_pActiveShell->MoveTable(GotoCurrTable, fnTableStart);
if (!m_pActiveShell->Left(SwCursorSkipMode::Chars, false, 1, false))
break; // Table is at the beginning of the document. It can't be selected this way.
}
m_pActiveShell->EndCursorMove();
// Assure cursor is in visible view area.
// (tdf#147041) Always show the navigated outline at the top of the visible view area.
if (pCnt->GetParent()->GetType() == ContentTypeId::OUTLINE ||
(!m_pActiveShell->IsCursorVisible() && !m_pActiveShell->IsFrameSelected() &&
!m_pActiveShell->GetSelectedObjCount()))
{
Point aPoint(rView.GetVisArea().getX(), m_pActiveShell->GetCursorDocPos().getY());
rView.SetVisArea(aPoint);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.