/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
/* Symbolic name representations of numeric values used for the Outline Content Visibility popup menu item ids. The numbers are chosen arbitrarily to not over overlap other menu item ids. see: SwContentTree::ExecuteContextMenuAction, navigatorcontextmenu.ui
1512 toggle outline content visibility of the selected outline entry 1513 make the outline content of the selected outline entry and children not visible 1514 make the outline content of the selected entry and children visible
*/ const sal_uInt32 TOGGLE_OUTLINE_CONTENT_VISIBILITY = 1512; const sal_uInt32 HIDE_OUTLINE_CONTENT_VISIBILITY = 1513; const sal_uInt32 SHOW_OUTLINE_CONTENT_VISIBILITY = 1514;
constexpr char NAVI_BOOKMARK_DELIM = '\x01';
}
class SwContentArr
: public o3tl::sorted_vector<std::unique_ptr<SwContent>, o3tl::less_ptr_to,
o3tl::find_partialorder_ptrequals>
{
};
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);
}
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.