7579 lines
305 KiB
C++
7579 lines
305 KiB
C++
/* -*- 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 .
|
|
*/
|
|
|
|
#include <comphelper/lok.hxx>
|
|
#include <comphelper/string.hxx>
|
|
#include <editeng/frmdiritem.hxx>
|
|
#include <svl/urlbmk.hxx>
|
|
#include <osl/thread.h>
|
|
#include <sal/log.hxx>
|
|
#include <tools/urlobj.hxx>
|
|
#include <sfx2/docfile.hxx>
|
|
#include <sfx2/dispatch.hxx>
|
|
#include <sfx2/event.hxx>
|
|
#include <sfx2/viewfrm.hxx>
|
|
#include <o3tl/enumrange.hxx>
|
|
#include <o3tl/sorted_vector.hxx>
|
|
#include <utility>
|
|
#include <vcl/commandevent.hxx>
|
|
#include <vcl/weldutils.hxx>
|
|
#include <sot/formats.hxx>
|
|
#include <o3tl/string_view.hxx>
|
|
#include <uiitems.hxx>
|
|
#include <fmtanchr.hxx>
|
|
#include <fmtinfmt.hxx>
|
|
#include <txtinet.hxx>
|
|
#include <fmtfld.hxx>
|
|
#include <swmodule.hxx>
|
|
#include <wrtsh.hxx>
|
|
#include <view.hxx>
|
|
#include <docsh.hxx>
|
|
#include <drawdoc.hxx>
|
|
#include <content.hxx>
|
|
#include <frmatr.hxx>
|
|
#include <frmfmt.hxx>
|
|
#include <fldbas.hxx>
|
|
#include <IMark.hxx>
|
|
#include <section.hxx>
|
|
#include <tox.hxx>
|
|
#include <navipi.hxx>
|
|
#include <navicont.hxx>
|
|
#include <navicfg.hxx>
|
|
#include <edtwin.hxx>
|
|
#include <doc.hxx>
|
|
#include <IDocumentSettingAccess.hxx>
|
|
#include <IDocumentDrawModelAccess.hxx>
|
|
#include <IDocumentOutlineNodes.hxx>
|
|
#include <unotxvw.hxx>
|
|
#include <cmdid.h>
|
|
#include <helpids.h>
|
|
#include <strings.hrc>
|
|
#include <com/sun/star/text/XTextSectionsSupplier.hpp>
|
|
#include <com/sun/star/text/XTextGraphicObjectsSupplier.hpp>
|
|
#include <com/sun/star/text/XTextTablesSupplier.hpp>
|
|
#include <com/sun/star/text/XDocumentIndexesSupplier.hpp>
|
|
#include <com/sun/star/text/XDocumentIndex.hpp>
|
|
#include <com/sun/star/text/XBookmarksSupplier.hpp>
|
|
#include <com/sun/star/text/XTextEmbeddedObjectsSupplier.hpp>
|
|
#include <com/sun/star/text/XTextFramesSupplier.hpp>
|
|
#include <com/sun/star/ui/XSidebarProvider.hpp>
|
|
#include <com/sun/star/ui/XDecks.hpp>
|
|
#include <com/sun/star/ui/XDeck.hpp>
|
|
#include <com/sun/star/ui/XPanels.hpp>
|
|
#include <com/sun/star/ui/XPanel.hpp>
|
|
#include <svx/svdpage.hxx>
|
|
#include <svx/svdview.hxx>
|
|
#include <SwRewriter.hxx>
|
|
#include <hints.hxx>
|
|
#include <numrule.hxx>
|
|
#include <swundo.hxx>
|
|
#include <ndtxt.hxx>
|
|
#include <PostItMgr.hxx>
|
|
#include <postithelper.hxx>
|
|
|
|
#include <swabstdlg.hxx>
|
|
#include <bitmaps.hlst>
|
|
|
|
#include <AnnotationWin.hxx>
|
|
#include <memory>
|
|
|
|
#include <fmtcntnt.hxx>
|
|
#include <docstat.hxx>
|
|
|
|
#include <viewopt.hxx>
|
|
|
|
#include <IDocumentFieldsAccess.hxx>
|
|
#include <txtfld.hxx>
|
|
#include <fldmgr.hxx>
|
|
|
|
#include <frameformats.hxx>
|
|
|
|
#include <ftnidx.hxx>
|
|
#include <txtftn.hxx>
|
|
#include <fmtftn.hxx>
|
|
|
|
#include <txtannotationfld.hxx>
|
|
#include <txtfrm.hxx>
|
|
#include <txtrfmrk.hxx>
|
|
#include <svx/sdr/overlay/overlayselection.hxx>
|
|
#include <svx/sdr/overlay/overlayobject.hxx>
|
|
#include <svx/sdr/overlay/overlaymanager.hxx>
|
|
#include <svx/sdrpaintwindow.hxx>
|
|
#include <node2lay.hxx>
|
|
|
|
#include <sectfrm.hxx>
|
|
|
|
#include <docufld.hxx>
|
|
|
|
#include <svl/fstathelper.hxx>
|
|
|
|
#include <expfld.hxx>
|
|
#include <unotxdoc.hxx>
|
|
|
|
#define CTYPE_CNT 0
|
|
#define CTYPE_CTT 1
|
|
|
|
using namespace ::com::sun::star;
|
|
using namespace ::com::sun::star::text;
|
|
using namespace ::com::sun::star::uno;
|
|
using namespace ::com::sun::star::container;
|
|
|
|
namespace {
|
|
|
|
/*
|
|
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>
|
|
{
|
|
};
|
|
|
|
namespace
|
|
{
|
|
std::map<OUString, std::map<void*, bool>> lcl_DocOutLineExpandStateMap;
|
|
|
|
bool lcl_IsContent(const weld::TreeIter& rEntry, const weld::TreeView& rTreeView)
|
|
{
|
|
return weld::fromId<const SwTypeNumber*>(rTreeView.get_id(rEntry))->GetTypeId() == CTYPE_CNT;
|
|
}
|
|
|
|
bool lcl_IsContentType(const weld::TreeIter& rEntry, const weld::TreeView& rTreeView)
|
|
{
|
|
return weld::fromId<const SwTypeNumber*>(rTreeView.get_id(rEntry))->GetTypeId() == CTYPE_CTT;
|
|
}
|
|
|
|
bool lcl_IsLowerOutlineContent(const weld::TreeIter& rEntry, const weld::TreeView& rTreeView, sal_uInt8 nLevel)
|
|
{
|
|
return weld::fromId<const SwOutlineContent*>(rTreeView.get_id(rEntry))->GetOutlineLevel() < nLevel;
|
|
}
|
|
|
|
bool lcl_FindShell(SwWrtShell const * pShell)
|
|
{
|
|
bool bFound = false;
|
|
SwView *pView = SwModule::GetFirstView();
|
|
while (pView)
|
|
{
|
|
if(pShell == &pView->GetWrtShell())
|
|
{
|
|
bFound = true;
|
|
break;
|
|
}
|
|
pView = SwModule::GetNextView(pView);
|
|
}
|
|
return bFound;
|
|
}
|
|
|
|
bool lcl_IsUiVisibleBookmark(const ::sw::mark::MarkBase* pMark)
|
|
{
|
|
return IDocumentMarkAccess::GetType(*pMark) == IDocumentMarkAccess::MarkType::BOOKMARK;
|
|
}
|
|
|
|
OUString lcl_GetFootnoteText(const SwTextFootnote& rTextFootnote)
|
|
{
|
|
SwNodeIndex aIdx(*rTextFootnote.GetStartNode(), 1);
|
|
SwContentNode* pCNd = aIdx.GetNode().GetTextNode();
|
|
if(!pCNd)
|
|
pCNd = SwNodes::GoNext(&aIdx);
|
|
return pCNd->IsTextNode() ? static_cast<SwTextNode*>(pCNd)->GetText() : OUString();
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
bool lcl_IsLowerRegionContent(const weld::TreeIter& rEntry, const weld::TreeView& rTreeView, sal_uInt8 nLevel)
|
|
{
|
|
return weld::fromId<const SwRegionContent*>(rTreeView.get_id(rEntry))->GetRegionLevel() < nLevel;
|
|
}
|
|
|
|
void lcl_SelectAllFootnotesOrEndnotes(SwWrtShell& rWrtShell, SwContentType* pContentType)
|
|
{
|
|
const auto nCount = pContentType->GetMemberCount();
|
|
if (nCount == 0)
|
|
return;
|
|
|
|
rWrtShell.AssureStdMode();
|
|
SwCursor* pCursor = rWrtShell.getShellCursor(true);
|
|
|
|
rWrtShell.StartAction();
|
|
rWrtShell.EnterAddMode();
|
|
for (size_t i = 0; i < nCount; i++)
|
|
{
|
|
const SwTextFootnoteContent* pTextFootnoteCnt
|
|
= static_cast<const SwTextFootnoteContent*>(pContentType->GetMember(i));
|
|
if (pTextFootnoteCnt && !pTextFootnoteCnt->IsInvisible())
|
|
{
|
|
if (const SwTextAttr* pTextAttr = pTextFootnoteCnt->GetTextFootnote())
|
|
{
|
|
const SwTextFootnote* pTextFootnote
|
|
= pTextAttr->GetFootnote().GetTextFootnote();
|
|
if (!pTextFootnote)
|
|
continue;
|
|
const SwTextNode& rTextNode = pTextFootnote->GetTextNode();
|
|
auto nStart = pTextAttr->GetStart();
|
|
pCursor->GetPoint()->Assign(rTextNode, nStart + 1);
|
|
rWrtShell.SetMark();
|
|
rWrtShell.SttSelect();
|
|
pCursor->GetPoint()->Assign(rTextNode, nStart);
|
|
rWrtShell.EndSelect();
|
|
}
|
|
}
|
|
}
|
|
rWrtShell.LeaveAddMode();
|
|
rWrtShell.EndAction();
|
|
}
|
|
}
|
|
|
|
// Content, contains names and reference at the content type.
|
|
|
|
SwContent::SwContent(const SwContentType* pCnt, OUString aName, double nYPos) :
|
|
SwTypeNumber(CTYPE_CNT),
|
|
m_pParent(pCnt),
|
|
m_sContentName(std::move(aName)),
|
|
m_nYPosition(nYPos),
|
|
m_bInvisible(false)
|
|
{
|
|
}
|
|
|
|
|
|
SwTypeNumber::~SwTypeNumber()
|
|
{
|
|
}
|
|
|
|
bool SwContent::IsProtect() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool SwTextFieldContent::IsProtect() const
|
|
{
|
|
return m_pFormatField->IsProtect();
|
|
}
|
|
|
|
bool SwPostItContent::IsProtect() const
|
|
{
|
|
return m_pField->IsProtect();
|
|
}
|
|
|
|
bool SwURLFieldContent::IsProtect() const
|
|
{
|
|
return m_pINetAttr->IsProtect();
|
|
}
|
|
|
|
bool SwRegionContent::IsProtect() const
|
|
{
|
|
return m_pSectionFormat->GetSection()->IsProtect();
|
|
}
|
|
|
|
SwGraphicContent::~SwGraphicContent()
|
|
{
|
|
}
|
|
|
|
SwTOXBaseContent::~SwTOXBaseContent()
|
|
{
|
|
}
|
|
|
|
const TranslateId STR_CONTENT_TYPE_ARY[] =
|
|
{
|
|
STR_CONTENT_TYPE_OUTLINE,
|
|
STR_CONTENT_TYPE_TABLE,
|
|
STR_CONTENT_TYPE_FRAME,
|
|
STR_CONTENT_TYPE_GRAPHIC,
|
|
STR_CONTENT_TYPE_OLE,
|
|
STR_CONTENT_TYPE_BOOKMARK,
|
|
STR_CONTENT_TYPE_REGION,
|
|
STR_CONTENT_TYPE_URLFIELD,
|
|
STR_CONTENT_TYPE_REFERENCE,
|
|
STR_CONTENT_TYPE_INDEX,
|
|
STR_CONTENT_TYPE_POSTIT,
|
|
STR_CONTENT_TYPE_DRAWOBJECT,
|
|
STR_CONTENT_TYPE_TEXTFIELD,
|
|
STR_CONTENT_TYPE_FOOTNOTE,
|
|
STR_CONTENT_TYPE_ENDNOTE
|
|
};
|
|
|
|
const TranslateId STR_CONTENT_TYPE_SINGLE_ARY[] =
|
|
{
|
|
STR_CONTENT_TYPE_SINGLE_OUTLINE,
|
|
STR_CONTENT_TYPE_SINGLE_TABLE,
|
|
STR_CONTENT_TYPE_SINGLE_FRAME,
|
|
STR_CONTENT_TYPE_SINGLE_GRAPHIC,
|
|
STR_CONTENT_TYPE_SINGLE_OLE,
|
|
STR_CONTENT_TYPE_SINGLE_BOOKMARK,
|
|
STR_CONTENT_TYPE_SINGLE_REGION,
|
|
STR_CONTENT_TYPE_SINGLE_URLFIELD,
|
|
STR_CONTENT_TYPE_SINGLE_REFERENCE,
|
|
STR_CONTENT_TYPE_SINGLE_INDEX,
|
|
STR_CONTENT_TYPE_SINGLE_POSTIT,
|
|
STR_CONTENT_TYPE_SINGLE_DRAWOBJECT,
|
|
STR_CONTENT_TYPE_SINGLE_TEXTFIELD,
|
|
STR_CONTENT_TYPE_SINGLE_FOOTNOTE,
|
|
STR_CONTENT_TYPE_SINGLE_ENDNOTE
|
|
};
|
|
|
|
namespace
|
|
{
|
|
bool checkVisibilityChanged(
|
|
const SwContentArr& rSwContentArrA,
|
|
const SwContentArr& rSwContentArrB)
|
|
{
|
|
if(rSwContentArrA.size() != rSwContentArrB.size())
|
|
{
|
|
return true;
|
|
}
|
|
|
|
for(size_t a(0); a < rSwContentArrA.size(); a++)
|
|
{
|
|
if(rSwContentArrA[a]->IsInvisible() != rSwContentArrB[a]->IsInvisible())
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
// 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 (const auto 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
|
|
|
|
SwContentType::SwContentType(SwWrtShell* pShell, ContentTypeId nType, sal_uInt8 nLevel) :
|
|
SwTypeNumber(CTYPE_CTT),
|
|
m_pWrtShell(pShell),
|
|
m_sContentTypeName(SwResId(STR_CONTENT_TYPE_ARY[static_cast<int>(nType)])),
|
|
m_sSingleContentTypeName(SwResId(STR_CONTENT_TYPE_SINGLE_ARY[static_cast<int>(nType)])),
|
|
m_nMemberCount(0),
|
|
m_nContentType(nType),
|
|
m_nOutlineLevel(nLevel),
|
|
m_bDataValid(false),
|
|
m_bEdit(false),
|
|
m_bDelete(true)
|
|
{
|
|
switch(m_nContentType)
|
|
{
|
|
case ContentTypeId::OUTLINE:
|
|
m_sTypeToken = "outline";
|
|
break;
|
|
case ContentTypeId::TABLE:
|
|
m_sTypeToken = "table";
|
|
m_bEdit = true;
|
|
m_bRenamable = true;
|
|
break;
|
|
case ContentTypeId::FRAME:
|
|
m_sTypeToken = "frame";
|
|
m_bEdit = true;
|
|
m_bRenamable = true;
|
|
break;
|
|
case ContentTypeId::GRAPHIC:
|
|
m_sTypeToken = "graphic";
|
|
m_bEdit = true;
|
|
m_bRenamable = true;
|
|
break;
|
|
case ContentTypeId::OLE:
|
|
m_sTypeToken = "ole";
|
|
m_bEdit = true;
|
|
m_bRenamable = true;
|
|
break;
|
|
case ContentTypeId::TEXTFIELD:
|
|
m_bEdit = true;
|
|
break;
|
|
case ContentTypeId::FOOTNOTE:
|
|
case ContentTypeId::ENDNOTE:
|
|
m_bEdit = true;
|
|
break;
|
|
case ContentTypeId::BOOKMARK:
|
|
{
|
|
const bool bProtectedBM = m_pWrtShell->getIDocumentSettingAccess().get(
|
|
DocumentSettingId::PROTECT_BOOKMARKS);
|
|
m_bEdit = true;
|
|
m_bDelete = !bProtectedBM;
|
|
m_bRenamable = !bProtectedBM;
|
|
}
|
|
break;
|
|
case ContentTypeId::REGION:
|
|
m_sTypeToken = "region";
|
|
m_bEdit = true;
|
|
m_bRenamable = true;
|
|
break;
|
|
case ContentTypeId::INDEX:
|
|
m_bEdit = true;
|
|
m_bRenamable = true;
|
|
break;
|
|
case ContentTypeId::REFERENCE:
|
|
m_bEdit = false;
|
|
break;
|
|
case ContentTypeId::URLFIELD:
|
|
m_bEdit = true;
|
|
break;
|
|
case ContentTypeId::POSTIT:
|
|
m_bEdit = true;
|
|
break;
|
|
case ContentTypeId::DRAWOBJECT:
|
|
m_sTypeToken = "drawingobject";
|
|
m_bEdit = true;
|
|
m_bRenamable = true;
|
|
break;
|
|
default: break;
|
|
}
|
|
|
|
const int nShift = static_cast<int>(m_nContentType);
|
|
assert(nShift > -1);
|
|
const sal_Int32 nMask = 1 << nShift;
|
|
const sal_Int32 nBlock = SwModule::get()->GetNavigationConfig()->GetSortAlphabeticallyBlock();
|
|
m_bAlphabeticSort = nBlock & nMask;
|
|
|
|
FillMemberList();
|
|
}
|
|
|
|
SwContentType::~SwContentType()
|
|
{
|
|
}
|
|
|
|
const SwContent* SwContentType::GetMember(size_t nIndex)
|
|
{
|
|
if(!m_bDataValid || !m_pMember)
|
|
{
|
|
FillMemberList();
|
|
}
|
|
if(nIndex < m_pMember->size())
|
|
return (*m_pMember)[nIndex].get();
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void SwContentType::Invalidate()
|
|
{
|
|
m_bDataValid = false;
|
|
}
|
|
|
|
void SwContentType::FillMemberList(bool* pbContentChanged)
|
|
{
|
|
std::unique_ptr<SwContentArr> pOldMember;
|
|
size_t nOldMemberCount = 0;
|
|
if(m_pMember && pbContentChanged)
|
|
{
|
|
pOldMember = std::move(m_pMember);
|
|
nOldMemberCount = pOldMember->size();
|
|
m_pMember.reset( new SwContentArr );
|
|
*pbContentChanged = false;
|
|
}
|
|
else if(!m_pMember)
|
|
m_pMember.reset( new SwContentArr );
|
|
else
|
|
m_pMember->clear();
|
|
switch(m_nContentType)
|
|
{
|
|
case ContentTypeId::OUTLINE :
|
|
{
|
|
const SwNodeOffset nEndOfExtrasIndex = m_pWrtShell->GetNodes().GetEndOfExtras().GetIndex();
|
|
// provide for up to 99999 outline nodes in frames to be sorted in document layout order
|
|
double nOutlinesInFramesIndexAdjustment = 0.00001;
|
|
const SwOutlineNodes& rOutlineNodes(m_pWrtShell->GetNodes().GetOutLineNds());
|
|
const size_t nOutlineCount = rOutlineNodes.size();
|
|
|
|
for (size_t i = 0; i < nOutlineCount; ++i)
|
|
{
|
|
SwTextNode* pNode = rOutlineNodes[i]->GetTextNode();
|
|
const sal_uInt8 nLevel = pNode->GetAttrOutlineLevel() - 1;
|
|
if (nLevel >= m_nOutlineLevel)
|
|
continue;
|
|
double nYPos = m_bAlphabeticSort ? 0 : static_cast<double>(getYPos(*pNode));
|
|
if (nEndOfExtrasIndex >= pNode->GetIndex() && pNode->GetFlyFormat())
|
|
{
|
|
nYPos += nOutlinesInFramesIndexAdjustment;
|
|
nOutlinesInFramesIndexAdjustment += 0.00001;
|
|
}
|
|
OUString aEntry(comphelper::string::stripStart(
|
|
m_pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineText(
|
|
i, m_pWrtShell->GetLayout(), true, false, false), ' '));
|
|
aEntry = SwNavigationPI::CleanEntry(aEntry);
|
|
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(), 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;
|
|
else if(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 OUString sFrameName = pFrameFormat->GetName();
|
|
|
|
SwContent* pCnt;
|
|
tools::Long nYPos =
|
|
m_bAlphabeticSort ? 0 : pFrameFormat->FindLayoutRect(false, &aNullPt).Top();
|
|
if(ContentTypeId::GRAPHIC == m_nContentType)
|
|
{
|
|
OUString sLink;
|
|
SwDoc::GetGrfNms(*static_cast<const SwFlyFrameFormat*>(pFrameFormat), &sLink,
|
|
nullptr);
|
|
pCnt = new SwGraphicContent(this, sFrameName, INetURLObject::decode(sLink,
|
|
INetURLObject::DecodeMechanism::Unambiguous), nYPos);
|
|
}
|
|
else
|
|
{
|
|
pCnt = new SwContent(this, sFrameName, nYPos);
|
|
}
|
|
if(!pFrameFormat->IsVisible())
|
|
pCnt->SetInvisible();
|
|
m_pMember->insert(std::unique_ptr<SwContent>(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::BOOKMARK:
|
|
{
|
|
tools::Long nYPos = 0;
|
|
IDocumentMarkAccess* const pMarkAccess = m_pWrtShell->getIDocumentMarkAccess();
|
|
for(auto ppBookmark = pMarkAccess->getBookmarksBegin();
|
|
ppBookmark != pMarkAccess->getBookmarksEnd();
|
|
++ppBookmark)
|
|
{
|
|
if(lcl_IsUiVisibleBookmark(*ppBookmark))
|
|
{
|
|
const OUString& rBkmName = (*ppBookmark)->GetName();
|
|
//nYPos from 0 -> text::Bookmarks will be sorted alphabetically
|
|
auto pCnt(std::make_unique<SwContent>(this, rBkmName,
|
|
m_bAlphabeticSort ? 0 : nYPos++));
|
|
m_pMember->insert(std::move(pCnt));
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case ContentTypeId::TEXTFIELD:
|
|
{
|
|
std::vector<SwTextField*> aArr;
|
|
const SwFieldTypes& rFieldTypes =
|
|
*m_pWrtShell->GetDoc()->getIDocumentFieldsAccess().GetFieldTypes();
|
|
const size_t nSize = rFieldTypes.size();
|
|
for (size_t i = 0; i < nSize; ++i)
|
|
{
|
|
const SwFieldType* pFieldType = rFieldTypes[i].get();
|
|
if (pFieldType->Which() == SwFieldIds::Postit)
|
|
continue;
|
|
std::vector<SwFormatField*> vFields;
|
|
pFieldType->GatherFields(vFields);
|
|
for (SwFormatField* pFormatField: vFields)
|
|
{
|
|
if (SwTextField* pTextField = pFormatField->GetTextField())
|
|
{
|
|
// fields in header footer don't behave well, skip them
|
|
if (m_pWrtShell->GetDoc()->IsInHeaderFooter(pTextField->GetTextNode()))
|
|
continue;
|
|
aArr.emplace_back(pTextField);
|
|
}
|
|
}
|
|
}
|
|
if (!m_bAlphabeticSort)
|
|
{
|
|
const SwNodeOffset nEndOfExtrasIndex =
|
|
m_pWrtShell->GetNodes().GetEndOfExtras().GetIndex();
|
|
// use stable sort array to list fields in document model order
|
|
std::stable_sort(aArr.begin(), aArr.end(),
|
|
[&nEndOfExtrasIndex, this](
|
|
const SwTextField* a, const SwTextField* b){
|
|
SwPosition aPos(a->GetTextNode(), a->GetStart());
|
|
SwPosition bPos(b->GetTextNode(), b->GetStart());
|
|
// use anchor position for entries that are located in flys
|
|
if (nEndOfExtrasIndex >= aPos.GetNodeIndex())
|
|
getAnchorPos(aPos);
|
|
if (nEndOfExtrasIndex >= bPos.GetNodeIndex())
|
|
getAnchorPos(bPos);
|
|
if (aPos == bPos)
|
|
{
|
|
// probably in same or nested fly frame
|
|
// sort using layout position
|
|
SwRect aCharRect, bCharRect;
|
|
std::shared_ptr<SwPaM> pPamForTextField;
|
|
if (SwTextFrame* pFrame = static_cast<SwTextFrame*>(
|
|
a->GetTextNode().getLayoutFrame(m_pWrtShell->GetLayout())))
|
|
{
|
|
SwTextField::GetPamForTextField(*a, pPamForTextField);
|
|
if (pPamForTextField)
|
|
pFrame->GetCharRect(aCharRect, *pPamForTextField->GetPoint());
|
|
}
|
|
if (SwTextFrame* pFrame = static_cast<SwTextFrame*>(
|
|
b->GetTextNode().getLayoutFrame(m_pWrtShell->GetLayout())))
|
|
{
|
|
SwTextField::GetPamForTextField(*b, pPamForTextField);
|
|
if (pPamForTextField)
|
|
pFrame->GetCharRect(bCharRect, *pPamForTextField->GetPoint());
|
|
}
|
|
return aCharRect.Top() < bCharRect.Top();
|
|
}
|
|
return aPos < bPos;});
|
|
}
|
|
std::vector<OUString> aDocumentStatisticsSubTypesList;
|
|
tools::Long nYPos = 0;
|
|
for (SwTextField* pTextField : aArr)
|
|
{
|
|
const SwField* pField = pTextField->GetFormatField().GetField();
|
|
OUString sExpandField = pField->ExpandField(true, m_pWrtShell->GetLayout());
|
|
if (!sExpandField.isEmpty())
|
|
sExpandField = u" - " + sExpandField;
|
|
OUString sText;
|
|
if (pField->GetTypeId() == SwFieldTypesEnum::DocumentStatistics)
|
|
{
|
|
if (aDocumentStatisticsSubTypesList.empty())
|
|
SwFieldMgr(m_pWrtShell).GetSubTypes(SwFieldTypesEnum::DocumentStatistics,
|
|
aDocumentStatisticsSubTypesList);
|
|
OUString sSubType;
|
|
if (pField->GetSubType() < aDocumentStatisticsSubTypesList.size())
|
|
sSubType = u" - " + aDocumentStatisticsSubTypesList[pField->GetSubType()];
|
|
sText = pField->GetDescription() + u" - " + pField->GetFieldName() + sSubType +
|
|
sExpandField;
|
|
}
|
|
else if (pField->GetTypeId() == SwFieldTypesEnum::GetRef)
|
|
{
|
|
assert(dynamic_cast<const SwGetRefField*>(pField));
|
|
const SwGetRefField* pRefField(static_cast<const SwGetRefField*>(pField));
|
|
if (pRefField->IsRefToHeadingCrossRefBookmark() ||
|
|
pRefField->IsRefToNumItemCrossRefBookmark())
|
|
{
|
|
OUString sExpandedTextOfReferencedTextNode =
|
|
pRefField->GetExpandedTextOfReferencedTextNode(
|
|
*m_pWrtShell->GetLayout());
|
|
if (sExpandedTextOfReferencedTextNode.getLength() > 80)
|
|
{
|
|
sExpandedTextOfReferencedTextNode = OUString::Concat(
|
|
sExpandedTextOfReferencedTextNode.subView(0, 80)) + u"...";
|
|
}
|
|
sText = pField->GetDescription() + u" - "
|
|
+ sExpandedTextOfReferencedTextNode + sExpandField;
|
|
}
|
|
else
|
|
{
|
|
OUString sFieldSubTypeOrName;
|
|
auto nSubType = pField->GetSubType();
|
|
if (nSubType == REF_FOOTNOTE)
|
|
sFieldSubTypeOrName = SwResId(STR_FLDREF_FOOTNOTE);
|
|
else if (nSubType == REF_ENDNOTE)
|
|
sFieldSubTypeOrName = SwResId(STR_FLDREF_ENDNOTE);
|
|
else
|
|
sFieldSubTypeOrName = pField->GetFieldName();
|
|
sText = pField->GetDescription() + u" - " + sFieldSubTypeOrName
|
|
+ sExpandField;
|
|
}
|
|
}
|
|
else
|
|
sText = pField->GetDescription() + u" - " + pField->GetFieldName()
|
|
+ sExpandField;
|
|
auto pCnt(std::make_unique<SwTextFieldContent>(this, sText,
|
|
&pTextField->GetFormatField(),
|
|
m_bAlphabeticSort ? 0 : nYPos++));
|
|
if (!pTextField->GetTextNode().getLayoutFrame(m_pWrtShell->GetLayout()))
|
|
pCnt->SetInvisible();
|
|
m_pMember->insert(std::move(pCnt));
|
|
}
|
|
}
|
|
break;
|
|
// We will separate footnotes and endnotes here.
|
|
case ContentTypeId::FOOTNOTE:
|
|
case ContentTypeId::ENDNOTE:
|
|
{
|
|
const SwFootnoteIdxs& rFootnoteIdxs = m_pWrtShell->GetDoc()->GetFootnoteIdxs();
|
|
if (rFootnoteIdxs.empty())
|
|
break;
|
|
// insert footnotes and endnotes
|
|
tools::Long nPos = 0;
|
|
for (const SwTextFootnote* pTextFootnote : rFootnoteIdxs)
|
|
{
|
|
if ((!pTextFootnote->GetFootnote().IsEndNote()
|
|
&& m_nContentType == ContentTypeId::FOOTNOTE)
|
|
|| (pTextFootnote->GetFootnote().IsEndNote()
|
|
&& m_nContentType == ContentTypeId::ENDNOTE))
|
|
{
|
|
const SwFormatFootnote& rFormatFootnote = pTextFootnote->GetFootnote();
|
|
const OUString sText
|
|
= rFormatFootnote.GetViewNumStr(*m_pWrtShell->GetDoc(),
|
|
m_pWrtShell->GetLayout(), true)
|
|
+ " " + lcl_GetFootnoteText(*pTextFootnote);
|
|
auto pCnt(std::make_unique<SwTextFootnoteContent>(
|
|
this, sText, pTextFootnote, ++nPos));
|
|
if (!pTextFootnote->GetTextNode().getLayoutFrame(m_pWrtShell->GetLayout()))
|
|
pCnt->SetInvisible();
|
|
m_pMember->insert(std::move(pCnt));
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case ContentTypeId::REGION :
|
|
{
|
|
size_t nCount = m_pWrtShell->GetSectionFormatCount();
|
|
for (size_t i = 0; i < nCount; ++i)
|
|
{
|
|
const SwSectionFormat* pFormat = &m_pWrtShell->GetSectionFormat(i);
|
|
if (!pFormat->IsInNodesArr())
|
|
continue;
|
|
const SwSection* pSection = pFormat->GetSection();
|
|
if (SectionType eTmpType = pSection->GetType();
|
|
eTmpType == SectionType::ToxContent || eTmpType == SectionType::ToxHeader)
|
|
continue;
|
|
const SwNodeIndex* pNodeIndex = pFormat->GetContent().GetContentIdx();
|
|
if (pNodeIndex)
|
|
{
|
|
const OUString& sSectionName = pSection->GetSectionName();
|
|
|
|
sal_uInt8 nLevel = 0;
|
|
SwSectionFormat* pParentFormat = pFormat->GetParent();
|
|
while(pParentFormat)
|
|
{
|
|
nLevel++;
|
|
pParentFormat = pParentFormat->GetParent();
|
|
}
|
|
|
|
auto pCnt(std::make_unique<SwRegionContent>(this, sSectionName, 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 );
|
|
|
|
tools::Long nYPos = 0;
|
|
for (const auto& rRefMark : aRefMarks)
|
|
{
|
|
m_pMember->insert(std::make_unique<SwContent>(this, rRefMark,
|
|
m_bAlphabeticSort ? 0 : nYPos++));
|
|
}
|
|
}
|
|
break;
|
|
case ContentTypeId::URLFIELD:
|
|
{
|
|
SwGetINetAttrs aArr;
|
|
m_pWrtShell->GetINetAttrs(aArr, false);
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
std::stable_sort(aStableSortINetAttrsArray.begin(), aStableSortINetAttrsArray.end(),
|
|
[](const SwGetINetAttr* a, const SwGetINetAttr* b){
|
|
SwPosition aSwPos(a->rINetAttr.GetTextNode(),
|
|
a->rINetAttr.GetStart());
|
|
SwPosition bSwPos(b->rINetAttr.GetTextNode(),
|
|
b->rINetAttr.GetStart());
|
|
return aSwPos < bSwPos;});
|
|
|
|
// 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();
|
|
|
|
for ( sal_uInt16 nTox = 0; nTox < nCount; nTox++ )
|
|
{
|
|
const SwTOXBase* pBase = m_pWrtShell->GetTOX( nTox );
|
|
OUString sTOXNm( pBase->GetTOXName() );
|
|
|
|
SwContent* pCnt = new SwTOXBaseContent(
|
|
this, sTOXNm, m_bAlphabeticSort ? 0 : nTox, *pBase);
|
|
|
|
if(pBase && !pBase->IsVisible())
|
|
pCnt->SetInvisible();
|
|
|
|
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;
|
|
const bool 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;
|
|
}
|
|
|
|
m_bDataValid = true;
|
|
}
|
|
|
|
namespace {
|
|
|
|
enum STR_CONTEXT_IDX
|
|
{
|
|
IDX_STR_OUTLINE_LEVEL = 0,
|
|
IDX_STR_DISPLAY = 1,
|
|
IDX_STR_ACTIVE_VIEW = 2,
|
|
IDX_STR_HIDDEN = 3,
|
|
IDX_STR_ACTIVE = 4,
|
|
IDX_STR_INACTIVE = 5,
|
|
IDX_STR_EDIT_ENTRY = 6,
|
|
IDX_STR_DELETE_ENTRY = 7,
|
|
IDX_STR_SEND_OUTLINE_TO_CLIPBOARD_ENTRY = 8,
|
|
IDX_STR_OUTLINE_TRACKING = 9,
|
|
IDX_STR_OUTLINE_TRACKING_DEFAULT = 10,
|
|
IDX_STR_OUTLINE_TRACKING_FOCUS = 11,
|
|
IDX_STR_OUTLINE_TRACKING_OFF = 12
|
|
};
|
|
|
|
}
|
|
|
|
const TranslateId STR_CONTEXT_ARY[] =
|
|
{
|
|
STR_OUTLINE_LEVEL,
|
|
STR_DISPLAY,
|
|
STR_ACTIVE_VIEW,
|
|
STR_HIDDEN,
|
|
STR_ACTIVE,
|
|
STR_INACTIVE,
|
|
STR_EDIT_ENTRY,
|
|
STR_DELETE_ENTRY,
|
|
STR_SEND_OUTLINE_TO_CLIPBOARD_ENTRY,
|
|
STR_OUTLINE_TRACKING,
|
|
STR_OUTLINE_TRACKING_DEFAULT,
|
|
STR_OUTLINE_TRACKING_FOCUS,
|
|
STR_OUTLINE_TRACKING_OFF
|
|
};
|
|
|
|
SwContentTree::SwContentTree(std::unique_ptr<weld::TreeView> xTreeView, SwNavigationPI* pDialog)
|
|
: m_xTreeView(std::move(xTreeView))
|
|
, m_aDropTargetHelper(*this)
|
|
, m_pDialog(pDialog)
|
|
, m_sSpace(u" "_ustr)
|
|
, m_aUpdTimer("SwContentTree m_aUpdTimer")
|
|
, m_aOverlayObjectDelayTimer("SwContentTree m_aOverlayObjectDelayTimer")
|
|
, m_sInvisible(SwResId(STR_INVISIBLE))
|
|
, m_pHiddenShell(nullptr)
|
|
, m_pActiveShell(nullptr)
|
|
, m_pConfig(SwModule::get()->GetNavigationConfig())
|
|
, m_nActiveBlock(0)
|
|
, m_nHiddenBlock(0)
|
|
, m_nEntryCount(0)
|
|
, m_nRootType(ContentTypeId::UNKNOWN)
|
|
, m_nLastSelType(ContentTypeId::UNKNOWN)
|
|
, m_nOutlineLevel(MAXLEVEL)
|
|
, m_eState(State::ACTIVE)
|
|
, m_bIsRoot(false)
|
|
, m_bIsIdleClear(false)
|
|
, m_bIsLastReadOnly(false)
|
|
, m_bIsOutlineMoveable(true)
|
|
, m_bViewHasChanged(false)
|
|
{
|
|
m_xTreeView->set_size_request(m_xTreeView->get_approximate_digit_width() * 30,
|
|
m_xTreeView->get_text_height() * 14);
|
|
|
|
m_xTreeView->set_help_id(HID_NAVIGATOR_TREELIST);
|
|
|
|
m_xTreeView->connect_expanding(LINK(this, SwContentTree, ExpandHdl));
|
|
m_xTreeView->connect_collapsing(LINK(this, SwContentTree, CollapseHdl));
|
|
m_xTreeView->connect_row_activated(LINK(this, SwContentTree, ContentDoubleClickHdl));
|
|
m_xTreeView->connect_changed(LINK(this, SwContentTree, SelectHdl));
|
|
m_xTreeView->connect_focus_in(LINK(this, SwContentTree, FocusInHdl));
|
|
m_xTreeView->connect_key_press(LINK(this, SwContentTree, KeyInputHdl));
|
|
m_xTreeView->connect_popup_menu(LINK(this, SwContentTree, CommandHdl));
|
|
m_xTreeView->connect_query_tooltip(LINK(this, SwContentTree, QueryTooltipHdl));
|
|
m_xTreeView->connect_drag_begin(LINK(this, SwContentTree, DragBeginHdl));
|
|
m_xTreeView->connect_mouse_move(LINK(this, SwContentTree, MouseMoveHdl));
|
|
m_xTreeView->connect_mouse_press(LINK(this, SwContentTree, MousePressHdl));
|
|
|
|
for (ContentTypeId i : o3tl::enumrange<ContentTypeId>())
|
|
{
|
|
if (i != ContentTypeId::OUTLINE)
|
|
mTrackContentType[i] = true;
|
|
m_aActiveContentArr[i] = nullptr;
|
|
m_aHiddenContentArr[i] = nullptr;
|
|
}
|
|
for (int i = 0; i < CONTEXT_COUNT; ++i)
|
|
{
|
|
m_aContextStrings[i] = SwResId(STR_CONTEXT_ARY[i]);
|
|
}
|
|
m_nActiveBlock = m_pConfig->GetActiveBlock();
|
|
|
|
// Restore outline headings expand state (same session persistence only)
|
|
if (SwView* pView = GetActiveView(); pView && pView->GetDocShell())
|
|
{
|
|
OUString sDocTitle = pView->GetDocShell()->GetTitle();
|
|
auto it = lcl_DocOutLineExpandStateMap.find(sDocTitle);
|
|
if (it != lcl_DocOutLineExpandStateMap.end())
|
|
mOutLineNodeMap = it->second;
|
|
if (comphelper::LibreOfficeKit::isActive()) {
|
|
if (pView->m_nNaviExpandedStatus < 0)
|
|
m_nActiveBlock = 1;
|
|
else
|
|
m_nActiveBlock = pView->m_nNaviExpandedStatus;
|
|
}
|
|
}
|
|
|
|
m_aUpdTimer.SetInvokeHandler(LINK(this, SwContentTree, TimerUpdate));
|
|
m_aUpdTimer.SetTimeout(1000);
|
|
m_aOverlayObjectDelayTimer.SetInvokeHandler(LINK(this, SwContentTree, OverlayObjectDelayTimerHdl));
|
|
m_aOverlayObjectDelayTimer.SetTimeout(500);
|
|
}
|
|
|
|
SwContentTree::~SwContentTree()
|
|
{
|
|
if (SwView* pView = GetActiveView(); pView && pView->GetDocShell())
|
|
{
|
|
OUString sDocTitle = pView->GetDocShell()->GetTitle();
|
|
lcl_DocOutLineExpandStateMap[sDocTitle] = mOutLineNodeMap;
|
|
if (comphelper::LibreOfficeKit::isActive())
|
|
pView->m_nNaviExpandedStatus = m_nActiveBlock;
|
|
}
|
|
clear(); // If applicable erase content types previously.
|
|
m_aUpdTimer.Stop();
|
|
SetActiveShell(nullptr);
|
|
}
|
|
|
|
IMPL_LINK(SwContentTree, MousePressHdl, const MouseEvent&, rMEvt, bool)
|
|
{
|
|
m_bSelectTo = rMEvt.IsShift() && (m_pConfig->IsNavigateOnSelect() || rMEvt.GetClicks() == 2);
|
|
return false;
|
|
}
|
|
|
|
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)
|
|
return false;
|
|
if (m_eState == State::HIDDEN)
|
|
return false;
|
|
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());
|
|
else if (m_xTreeView->iter_compare(*xEntry, *m_xOverlayCompareEntry) == 0)
|
|
return false; // 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();
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Drag&Drop methods
|
|
IMPL_LINK(SwContentTree, DragBeginHdl, bool&, rUnsetDragIcon, bool)
|
|
{
|
|
rUnsetDragIcon = true;
|
|
|
|
bool bDisallow = true;
|
|
|
|
// don't allow if tree root is selected
|
|
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
|
|
bool bEntry = m_xTreeView->get_selected(xEntry.get());
|
|
if (!bEntry || lcl_IsContentType(*xEntry, *m_xTreeView))
|
|
{
|
|
return true; // disallow
|
|
}
|
|
|
|
if (m_bIsRoot && m_nRootType == ContentTypeId::OUTLINE)
|
|
{
|
|
// Only move drag entry and continuous selected siblings:
|
|
m_aDndOutlinesSelected.clear();
|
|
|
|
std::unique_ptr<weld::TreeIter> xScratch(m_xTreeView->make_iterator(xEntry.get()));
|
|
|
|
// Find first selected of continuous siblings
|
|
while (m_xTreeView->iter_previous_sibling(*xScratch) && m_xTreeView->is_selected(*xScratch))
|
|
{
|
|
m_xTreeView->copy_iterator(*xScratch, *xEntry);
|
|
}
|
|
// Record continuous selected siblings
|
|
do
|
|
{
|
|
SwOutlineContent* pOutlineContent
|
|
= weld::fromId<SwOutlineContent*>(m_xTreeView->get_id(*xEntry));
|
|
if (!pOutlineContent) // shouldn't happen
|
|
continue;
|
|
m_aDndOutlinesSelected.push_back(pOutlineContent->GetOutlinePos());
|
|
} while (m_xTreeView->iter_next_sibling(*xEntry) && m_xTreeView->is_selected(*xEntry));
|
|
|
|
bDisallow = false;
|
|
}
|
|
|
|
rtl::Reference<TransferDataContainer> xContainer = new TransferDataContainer;
|
|
|
|
if (FillTransferData(*xContainer))
|
|
{
|
|
bDisallow = false;
|
|
m_xTreeView->enable_drag_source(xContainer, DND_ACTION_COPY);
|
|
}
|
|
|
|
return bDisallow;
|
|
}
|
|
|
|
SwContentTreeDropTarget::SwContentTreeDropTarget(SwContentTree& rTreeView)
|
|
: DropTargetHelper(rTreeView.get_widget().get_drop_target())
|
|
, m_rTreeView(rTreeView)
|
|
{
|
|
}
|
|
|
|
sal_Int8 SwContentTreeDropTarget::AcceptDrop(const AcceptDropEvent& rEvt)
|
|
{
|
|
sal_Int8 nAccept = m_rTreeView.AcceptDrop(rEvt);
|
|
|
|
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);
|
|
}
|
|
|
|
return nAccept;
|
|
}
|
|
|
|
bool SwContentTree::IsInDrag() const
|
|
{
|
|
return m_xTreeView->get_drag_source() == m_xTreeView.get();
|
|
}
|
|
|
|
bool SwContentTree::HasHeadings() const
|
|
{
|
|
const std::unique_ptr<SwContentType>& rpContentT = m_aActiveContentArr[ContentTypeId::OUTLINE];
|
|
if (rpContentT && rpContentT->GetMemberCount() > 0)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
// QueryDrop will be executed in the navigator
|
|
sal_Int8 SwContentTree::AcceptDrop(const AcceptDropEvent& rEvt)
|
|
{
|
|
sal_Int8 nRet = DND_ACTION_NONE;
|
|
if( m_bIsRoot )
|
|
{
|
|
if( m_bIsOutlineMoveable )
|
|
nRet = rEvt.mnAction;
|
|
}
|
|
else if (!IsInDrag())
|
|
nRet = GetParentWindow()->AcceptDrop();
|
|
return nRet;
|
|
}
|
|
|
|
// Drop will be executed in the navigator
|
|
static void* lcl_GetOutlineKey(SwContentTree& rTree, SwOutlineContent const * pContent)
|
|
{
|
|
void* key = nullptr;
|
|
if (pContent)
|
|
{
|
|
SwWrtShell* pShell = rTree.GetWrtShell();
|
|
auto const nPos = pContent->GetOutlinePos();
|
|
|
|
key = static_cast<void*>(pShell->getIDocumentOutlineNodesAccess()->getOutlineNode( nPos ));
|
|
}
|
|
return key;
|
|
}
|
|
|
|
sal_Int8 SwContentTreeDropTarget::ExecuteDrop(const ExecuteDropEvent& rEvt)
|
|
{
|
|
return m_rTreeView.ExecuteDrop(rEvt);
|
|
}
|
|
|
|
sal_Int8 SwContentTree::ExecuteDrop(const ExecuteDropEvent& rEvt)
|
|
{
|
|
std::unique_ptr<weld::TreeIter> xDropEntry(m_xTreeView->make_iterator());
|
|
if (!m_xTreeView->get_dest_row_at_pos(rEvt.maPosPixel, xDropEntry.get(), true))
|
|
xDropEntry.reset();
|
|
|
|
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;
|
|
}
|
|
else if (!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);
|
|
|
|
}
|
|
return IsInDrag() ? DND_ACTION_NONE : GetParentWindow()->ExecuteDrop(rEvt);
|
|
}
|
|
|
|
namespace
|
|
{
|
|
bool IsAllExpanded(const weld::TreeView& rContentTree, const weld::TreeIter& rEntry)
|
|
{
|
|
if (!rContentTree.get_row_expanded(rEntry))
|
|
return false;
|
|
|
|
if (!rContentTree.iter_has_child(rEntry))
|
|
return false;
|
|
|
|
std::unique_ptr<weld::TreeIter> xChild(rContentTree.make_iterator(&rEntry));
|
|
(void)rContentTree.iter_children(*xChild);
|
|
|
|
do
|
|
{
|
|
if (rContentTree.iter_has_child(*xChild) || rContentTree.get_children_on_demand(*xChild))
|
|
{
|
|
if (!IsAllExpanded(rContentTree, *xChild))
|
|
return false;
|
|
}
|
|
}
|
|
while (rContentTree.iter_next_sibling(*xChild));
|
|
return true;
|
|
}
|
|
|
|
void ExpandOrCollapseAll(weld::TreeView& rContentTree, weld::TreeIter& rEntry)
|
|
{
|
|
bool bExpand = !IsAllExpanded(rContentTree, rEntry);
|
|
bExpand ? rContentTree.expand_row(rEntry) : rContentTree.collapse_row(rEntry);
|
|
int nRefDepth = rContentTree.get_iter_depth(rEntry);
|
|
while (rContentTree.iter_next(rEntry) && rContentTree.get_iter_depth(rEntry) > nRefDepth)
|
|
{
|
|
if (rContentTree.iter_has_child(rEntry))
|
|
bExpand ? rContentTree.expand_row(rEntry) : rContentTree.collapse_row(rEntry);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Handler for Dragging and ContextMenu
|
|
static bool lcl_InsertExpandCollapseAllItem(const weld::TreeView& rContentTree, const weld::TreeIter& rEntry, weld::Menu& rPop)
|
|
{
|
|
if (rContentTree.iter_has_child(rEntry) || rContentTree.get_children_on_demand(rEntry))
|
|
{
|
|
rPop.set_label(OUString::number(800), IsAllExpanded(rContentTree, rEntry) ? SwResId(STR_COLLAPSEALL) : SwResId(STR_EXPANDALL));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static void lcl_SetOutlineContentEntriesSensitivities(SwContentTree* pThis, const weld::TreeView& rContentTree, const weld::TreeIter& rEntry, weld::Menu& rPop)
|
|
{
|
|
rPop.set_sensitive(OUString::number(TOGGLE_OUTLINE_CONTENT_VISIBILITY), false);
|
|
rPop.set_sensitive(OUString::number(HIDE_OUTLINE_CONTENT_VISIBILITY), false);
|
|
rPop.set_sensitive(OUString::number(SHOW_OUTLINE_CONTENT_VISIBILITY), false);
|
|
|
|
// todo: multi selection
|
|
if (rContentTree.count_selected_rows() > 1)
|
|
return;
|
|
|
|
bool bIsRoot = lcl_IsContentType(rEntry, rContentTree);
|
|
|
|
const SwNodes& rNodes = pThis->GetWrtShell()->GetNodes();
|
|
const SwOutlineNodes& rOutlineNodes = rNodes.GetOutLineNds();
|
|
size_t nOutlinePos = weld::GetAbsPos(rContentTree, rEntry);
|
|
|
|
if (!bIsRoot)
|
|
--nOutlinePos;
|
|
|
|
if (nOutlinePos >= rOutlineNodes.size())
|
|
return;
|
|
|
|
int nFirstLevel = pThis->GetWrtShell()->getIDocumentOutlineNodesAccess()->getOutlineLevel(nOutlinePos);
|
|
{
|
|
// determine if any concerned outline node has content
|
|
bool bHasContent(false);
|
|
size_t nPos = nOutlinePos;
|
|
SwNode* pSttNd = rOutlineNodes[nPos];
|
|
SwNode* pEndNd = &rNodes.GetEndOfContent();
|
|
if (rOutlineNodes.size() > nPos + 1)
|
|
pEndNd = rOutlineNodes[nPos + 1];
|
|
|
|
// selected
|
|
SwNodeIndex aIdx(*pSttNd);
|
|
if (SwNodes::GoNext(&aIdx) != pEndNd)
|
|
bHasContent = true;
|
|
|
|
// descendants
|
|
if (!bHasContent && (rContentTree.iter_has_child(rEntry) || rContentTree.get_children_on_demand(rEntry)))
|
|
{
|
|
while (++nPos < rOutlineNodes.size() &&
|
|
(bIsRoot || pThis->GetWrtShell()->getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos) > nFirstLevel))
|
|
{
|
|
pSttNd = rOutlineNodes[nPos];
|
|
pEndNd = &rNodes.GetEndOfContent();
|
|
if (rOutlineNodes.size() > nPos + 1)
|
|
pEndNd = rOutlineNodes[nPos + 1];
|
|
|
|
// 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++;
|
|
}
|
|
|
|
bool bHasFolded(!pThis->GetWrtShell()->IsOutlineContentVisible(nPos));
|
|
bool bHasUnfolded(!bHasFolded);
|
|
|
|
while ((++nPos < pThis->GetWrtShell()->getIDocumentOutlineNodesAccess()->getOutlineNodesCount()) &&
|
|
(bIsRoot || pThis->GetWrtShell()->getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos) > nFirstLevel))
|
|
{
|
|
|
|
SwNode* pSttNd = rOutlineNodes[nPos];
|
|
SwNode* pEndNd = &rNodes.GetEndOfContent();
|
|
if (rOutlineNodes.size() > nPos + 1)
|
|
pEndNd = rOutlineNodes[nPos + 1];
|
|
|
|
SwNodeIndex aIdx(*pSttNd);
|
|
if (SwNodes::GoNext(&aIdx) == pEndNd)
|
|
continue; // skip if no content
|
|
|
|
if (!pThis->GetWrtShell()->IsOutlineContentVisible(nPos))
|
|
bHasFolded = true;
|
|
else
|
|
bHasUnfolded = true;
|
|
|
|
if (bHasFolded && bHasUnfolded)
|
|
break; // mixed so no need to continue
|
|
}
|
|
|
|
rPop.set_sensitive(OUString::number(HIDE_OUTLINE_CONTENT_VISIBILITY), bHasUnfolded);
|
|
rPop.set_sensitive(OUString::number(SHOW_OUTLINE_CONTENT_VISIBILITY), bHasFolded);
|
|
}
|
|
|
|
rPop.set_sensitive(OUString::number(TOGGLE_OUTLINE_CONTENT_VISIBILITY), !bIsRoot);
|
|
}
|
|
|
|
IMPL_LINK(SwContentTree, CommandHdl, const CommandEvent&, rCEvt, bool)
|
|
{
|
|
if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
|
|
return false;
|
|
|
|
grab_focus();
|
|
|
|
// 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
|
|
else if (m_xTreeView->is_selected(0))
|
|
m_xTreeView->set_cursor(0);
|
|
}
|
|
|
|
UpdateContentFunctionsToolbar();
|
|
|
|
std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xTreeView.get(), u"modules/swriter/ui/navigatorcontextmenu.ui"_ustr));
|
|
std::unique_ptr<weld::Menu> xPop = xBuilder->weld_menu(u"navmenu"_ustr);
|
|
|
|
bool bOutline(false);
|
|
std::unique_ptr<weld::Menu> xSubPop1 = xBuilder->weld_menu(u"outlinelevel"_ustr);
|
|
std::unique_ptr<weld::Menu> xSubPop2 = xBuilder->weld_menu(u"dragmodemenu"_ustr);
|
|
std::unique_ptr<weld::Menu> xSubPop3 = xBuilder->weld_menu(u"displaymenu"_ustr);
|
|
std::unique_ptr<weld::Menu> xSubPopOutlineTracking = xBuilder->weld_menu(u"outlinetracking"_ustr);
|
|
|
|
std::unique_ptr<weld::Menu> xSubPopOutlineContent = xBuilder->weld_menu(u"outlinecontent"_ustr);
|
|
|
|
xSubPopOutlineContent->append(OUString::number(TOGGLE_OUTLINE_CONTENT_VISIBILITY),
|
|
SwResId(STR_OUTLINE_CONTENT_VISIBILITY_TOGGLE));
|
|
xSubPopOutlineContent->append(OUString::number(HIDE_OUTLINE_CONTENT_VISIBILITY),
|
|
SwResId(STR_OUTLINE_CONTENT_VISIBILITY_HIDE_ALL));
|
|
xSubPopOutlineContent->append(OUString::number(SHOW_OUTLINE_CONTENT_VISIBILITY),
|
|
SwResId(STR_OUTLINE_CONTENT_VISIBILITY_SHOW_ALL));
|
|
|
|
xSubPopOutlineContent->set_item_help_id(OUString::number(TOGGLE_OUTLINE_CONTENT_VISIBILITY),
|
|
HID_NAVIGATOR_TREELIST);
|
|
xSubPopOutlineContent->set_item_help_id(OUString::number(HIDE_OUTLINE_CONTENT_VISIBILITY),
|
|
HID_NAVIGATOR_TREELIST);
|
|
xSubPopOutlineContent->set_item_help_id(OUString::number(SHOW_OUTLINE_CONTENT_VISIBILITY),
|
|
HID_NAVIGATOR_TREELIST);
|
|
|
|
// Add entries to the Outline Tracking submenu
|
|
OUString sId;
|
|
for(int i = 1; i <= 3; ++i)
|
|
{
|
|
sId = OUString::number(i + 10);
|
|
xSubPopOutlineTracking->append_radio(sId, m_aContextStrings[IDX_STR_OUTLINE_TRACKING + i]);
|
|
xSubPopOutlineTracking->set_item_help_id(sId, HID_NAV_OUTLINE_TRACKING);
|
|
}
|
|
xSubPopOutlineTracking->set_active(OUString::number(10 + m_nOutlineTracking), true);
|
|
|
|
// Add entries to the Outline Level submenu
|
|
for (int i = 1; i <= MAXLEVEL; ++i)
|
|
{
|
|
sId = OUString::number(i + 100);
|
|
xSubPop1->append_radio(sId, OUString::number(i));
|
|
xSubPop1->set_item_help_id(sId, HID_NAV_OUTLINE_LEVEL);
|
|
}
|
|
xSubPop1->set_active(OUString::number(100 + m_nOutlineLevel), true);
|
|
|
|
// Insert the list of the open files in the Display submenu
|
|
{
|
|
sal_uInt16 nId = 301;
|
|
SwView *pView = SwModule::GetFirstView();
|
|
while (pView)
|
|
{
|
|
OUString sInsert = pView->GetDocShell()->GetTitle() + " (" +
|
|
m_aContextStrings[pView == GetActiveView() ? IDX_STR_ACTIVE :
|
|
IDX_STR_INACTIVE] + ")";
|
|
sId = OUString::number(nId);
|
|
xSubPop3->append_radio(sId, sInsert);
|
|
xSubPop3->set_item_help_id(sId, HID_NAV_DISPLAY);
|
|
if (State::CONSTANT == m_eState && m_pActiveShell == &pView->GetWrtShell())
|
|
xSubPop3->set_active(sId, true);
|
|
pView = SwModule::GetNextView(pView);
|
|
nId++;
|
|
}
|
|
// Active Window
|
|
sId = OUString::number(nId++);
|
|
xSubPop3->append_radio(sId, m_aContextStrings[IDX_STR_ACTIVE_VIEW]);
|
|
xSubPop3->set_item_help_id(sId, HID_NAV_DISPLAY);
|
|
// There can be only one hidden shell
|
|
if (m_pHiddenShell)
|
|
{
|
|
OUString sHiddenEntry = m_pHiddenShell->GetView().GetDocShell()->GetTitle() +
|
|
" (" +
|
|
m_aContextStrings[IDX_STR_HIDDEN] +
|
|
")";
|
|
sId = OUString::number(nId);
|
|
xSubPop3->append_radio(sId, sHiddenEntry);
|
|
xSubPop3->set_item_help_id(sId, HID_NAV_DISPLAY);
|
|
}
|
|
if (State::ACTIVE == m_eState)
|
|
xSubPop3->set_active(OUString::number(--nId), true);
|
|
else if (State::HIDDEN == m_eState)
|
|
xSubPop3->set_active(OUString::number(nId), true);
|
|
}
|
|
|
|
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
|
|
if (!m_xTreeView->get_selected(xEntry.get()))
|
|
xEntry.reset();
|
|
|
|
bool bRemoveGotoEntry = false;
|
|
if (State::HIDDEN == m_eState || !xEntry || !lcl_IsContent(*xEntry, *m_xTreeView) ||
|
|
weld::fromId<SwContent*>(m_xTreeView->get_id(*xEntry))->IsInvisible())
|
|
bRemoveGotoEntry = true;
|
|
|
|
bool bRemovePostItEntries = true;
|
|
bool bRemoveUpdateIndexEntry = true;
|
|
bool bRemoveReadonlyIndexEntry = true;
|
|
bool bRemoveCopyEntry = true;
|
|
bool bRemoveEditEntry = true;
|
|
bool bRemoveUnprotectEntry = true;
|
|
bool bRemoveDeleteChapterEntry = true,
|
|
bRemoveDeleteAllTablesEntry = true,
|
|
bRemoveDeleteTableEntry = true,
|
|
bRemoveDeleteAllFramesEntry = true,
|
|
bRemoveDeleteFrameEntry = true,
|
|
bRemoveDeleteAllImagesEntry = true,
|
|
bRemoveDeleteImageEntry = true,
|
|
bRemoveDeleteAllOLEObjectsEntry = true,
|
|
bRemoveDeleteOLEObjectEntry = true,
|
|
bRemoveDeleteAllBookmarksEntry = true,
|
|
bRemoveDeleteBookmarkEntry = true,
|
|
bRemoveDeleteAllRegionsEntry = true,
|
|
bRemoveDeleteRegionEntry = true,
|
|
bRemoveDeleteAllHyperlinksEntry = true,
|
|
bRemoveDeleteHyperlinkEntry = true,
|
|
bRemoveDeleteAllReferencesEntry = true,
|
|
bRemoveDeleteReferenceEntry = true,
|
|
bRemoveDeleteAllIndexesEntry = true,
|
|
bRemoveDeleteIndexEntry= true,
|
|
bRemoveDeleteAllCommentsEntry = true,
|
|
bRemoveDeleteCommentEntry = true,
|
|
bRemoveDeleteAllDrawingObjectsEntry = true,
|
|
bRemoveDeleteDrawingObjectEntry = true,
|
|
bRemoveDeleteAllFieldsEntry = true,
|
|
bRemoveDeleteFieldEntry = true,
|
|
bRemoveDeleteAllFootnotesEntry = true,
|
|
bRemoveDeleteFootnoteEntry = true,
|
|
bRemoveDeleteAllEndnotesEntry = true,
|
|
bRemoveDeleteEndnoteEntry = true;
|
|
bool bRemoveMakeAllFootnotesEndnotesEntry = true,
|
|
bRemoveMakeAllEndnotesFootnotesEntry = true;
|
|
bool bRemoveRenameEntry = true;
|
|
bool bRemoveSelectEntry = true;
|
|
bool bRemoveToggleExpandEntry = true;
|
|
bool bRemoveChapterEntries = true;
|
|
bool bRemoveSendOutlineEntry = true;
|
|
|
|
bool bRemoveTableTracking = true;
|
|
bool bRemoveSectionTracking = true;
|
|
bool bRemoveFrameTracking = true;
|
|
bool bRemoveImageTracking = true;
|
|
bool bRemoveOLEobjectTracking = true;
|
|
bool bRemoveBookmarkTracking = true;
|
|
bool bRemoveHyperlinkTracking = true;
|
|
bool bRemoveReferenceTracking = true;
|
|
bool bRemoveIndexTracking = true;
|
|
bool bRemoveCommentTracking = true;
|
|
bool bRemoveDrawingObjectTracking = true;
|
|
bool bRemoveFieldTracking = true;
|
|
bool bRemoveFootnoteTracking = true;
|
|
bool bRemoveEndnoteTracking = true;
|
|
|
|
bool bRemoveSortEntry = true;
|
|
|
|
bool bRemoveProtectSection = true;
|
|
bool bRemoveHideSection = true;
|
|
|
|
if (xEntry)
|
|
{
|
|
const SwContentType* pType;
|
|
if (lcl_IsContentType(*xEntry, *m_xTreeView))
|
|
pType = weld::fromId<SwContentType*>(m_xTreeView->get_id(*xEntry));
|
|
else
|
|
pType = weld::fromId<SwContent*>(
|
|
m_xTreeView->get_id(*xEntry))->GetParent();
|
|
const ContentTypeId nContentType = pType->GetType();
|
|
|
|
if (nContentType != ContentTypeId::FOOTNOTE && nContentType != ContentTypeId::ENDNOTE
|
|
&& nContentType != ContentTypeId::POSTIT && nContentType != ContentTypeId::UNKNOWN)
|
|
{
|
|
bRemoveSortEntry = false;
|
|
xPop->set_active(u"sort"_ustr, pType->IsAlphabeticSort());
|
|
}
|
|
|
|
OUString aIdent;
|
|
switch (nContentType)
|
|
{
|
|
case ContentTypeId::TABLE:
|
|
aIdent = "tabletracking";
|
|
bRemoveTableTracking = false;
|
|
break;
|
|
case ContentTypeId::REGION:
|
|
aIdent = "sectiontracking";
|
|
bRemoveSectionTracking = false;
|
|
break;
|
|
case ContentTypeId::FRAME:
|
|
aIdent = "frametracking";
|
|
bRemoveFrameTracking = false;
|
|
break;
|
|
case ContentTypeId::GRAPHIC:
|
|
aIdent = "imagetracking";
|
|
bRemoveImageTracking = false;
|
|
break;
|
|
case ContentTypeId::OLE:
|
|
aIdent = "oleobjecttracking";
|
|
bRemoveOLEobjectTracking = false;
|
|
break;
|
|
case ContentTypeId::BOOKMARK:
|
|
aIdent = "bookmarktracking";
|
|
bRemoveBookmarkTracking = false;
|
|
break;
|
|
case ContentTypeId::URLFIELD:
|
|
aIdent = "hyperlinktracking";
|
|
bRemoveHyperlinkTracking = false;
|
|
break;
|
|
case ContentTypeId::REFERENCE:
|
|
aIdent = "referencetracking";
|
|
bRemoveReferenceTracking = false;
|
|
break;
|
|
case ContentTypeId::INDEX:
|
|
aIdent = "indextracking";
|
|
bRemoveIndexTracking = false;
|
|
break;
|
|
case ContentTypeId::POSTIT:
|
|
aIdent = "commenttracking";
|
|
bRemoveCommentTracking = false;
|
|
break;
|
|
case ContentTypeId::DRAWOBJECT:
|
|
aIdent = "drawingobjecttracking";
|
|
bRemoveDrawingObjectTracking = false;
|
|
break;
|
|
case ContentTypeId::TEXTFIELD:
|
|
aIdent = "fieldtracking";
|
|
bRemoveFieldTracking = false;
|
|
break;
|
|
case ContentTypeId::FOOTNOTE:
|
|
aIdent = "footnotetracking";
|
|
bRemoveFootnoteTracking = false;
|
|
break;
|
|
case ContentTypeId::ENDNOTE:
|
|
aIdent = "endnotetracking";
|
|
bRemoveEndnoteTracking = false;
|
|
break;
|
|
default: break;
|
|
}
|
|
if (!aIdent.isEmpty())
|
|
xPop->set_active(aIdent, mTrackContentType[nContentType]);
|
|
|
|
// Edit only if the shown content is coming from the current view.
|
|
if (State::HIDDEN != m_eState &&
|
|
(State::ACTIVE == m_eState || (GetActiveView() && m_pActiveShell == GetActiveView()->GetWrtShellPtr()))
|
|
&& lcl_IsContent(*xEntry, *m_xTreeView))
|
|
{
|
|
bool bReadonly = m_pActiveShell->GetView().GetDocShell()->IsReadOnly();
|
|
const bool bVisible = !weld::fromId<SwContent*>(m_xTreeView->get_id(*xEntry))->IsInvisible();
|
|
const bool bProtected = weld::fromId<SwContent*>(m_xTreeView->get_id(*xEntry))->IsProtect();
|
|
const bool bProtectBM = (ContentTypeId::BOOKMARK == nContentType)
|
|
&& m_pActiveShell->getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_BOOKMARKS);
|
|
const bool bEditable
|
|
= !bReadonly && pType->IsEditable()
|
|
&& ((bVisible && !bProtected) || ContentTypeId::REGION == nContentType);
|
|
const bool bDeletable = pType->IsDeletable() && IsDeletable(*xEntry);
|
|
const bool bRenamable
|
|
= !bReadonly
|
|
&& (pType->IsRenamable()
|
|
|| (ContentTypeId::BOOKMARK == nContentType && !bProtectBM));
|
|
|
|
// Choose which Delete entry to show.
|
|
if (bDeletable)
|
|
{
|
|
switch (nContentType)
|
|
{
|
|
case ContentTypeId::OUTLINE:
|
|
bRemoveDeleteChapterEntry = false;
|
|
break;
|
|
case ContentTypeId::FRAME:
|
|
bRemoveDeleteFrameEntry = false;
|
|
break;
|
|
case ContentTypeId::GRAPHIC:
|
|
bRemoveDeleteImageEntry = false;
|
|
break;
|
|
case ContentTypeId::OLE:
|
|
bRemoveDeleteOLEObjectEntry = false;
|
|
break;
|
|
case ContentTypeId::BOOKMARK:
|
|
bRemoveDeleteBookmarkEntry = false;
|
|
break;
|
|
case ContentTypeId::REGION:
|
|
bRemoveDeleteRegionEntry = false;
|
|
break;
|
|
case ContentTypeId::URLFIELD:
|
|
bRemoveDeleteHyperlinkEntry = false;
|
|
break;
|
|
case ContentTypeId::REFERENCE:
|
|
bRemoveDeleteReferenceEntry = false;
|
|
break;
|
|
case ContentTypeId::POSTIT:
|
|
bRemoveDeleteCommentEntry = false;
|
|
break;
|
|
case ContentTypeId::DRAWOBJECT:
|
|
bRemoveDeleteDrawingObjectEntry = false;
|
|
break;
|
|
case ContentTypeId::TEXTFIELD:
|
|
bRemoveDeleteFieldEntry = false;
|
|
break;
|
|
case ContentTypeId::FOOTNOTE:
|
|
bRemoveDeleteFootnoteEntry = false;
|
|
break;
|
|
case ContentTypeId::ENDNOTE:
|
|
bRemoveDeleteEndnoteEntry = false;
|
|
break;
|
|
default: break;
|
|
}
|
|
}
|
|
if (ContentTypeId::FOOTNOTE == nContentType || ContentTypeId::ENDNOTE == nContentType)
|
|
{
|
|
void* pUserData = weld::fromId<void*>(m_xTreeView->get_id(*xEntry));
|
|
const SwTextFootnote* pFootnote =
|
|
static_cast<const SwTextFootnoteContent*>(pUserData)->GetTextFootnote();
|
|
if (!pFootnote)
|
|
bRemoveGotoEntry = true;
|
|
}
|
|
else if(ContentTypeId::OUTLINE == nContentType)
|
|
{
|
|
bOutline = true;
|
|
lcl_SetOutlineContentEntriesSensitivities(this, *m_xTreeView, *xEntry, *xSubPopOutlineContent);
|
|
bRemoveToggleExpandEntry = lcl_InsertExpandCollapseAllItem(*m_xTreeView, *xEntry, *xPop);
|
|
if (!bReadonly)
|
|
{
|
|
bRemoveSelectEntry = false;
|
|
if (!pType->IsAlphabeticSort())
|
|
bRemoveChapterEntries = false;
|
|
}
|
|
bRemoveCopyEntry = false;
|
|
}
|
|
else if (bEditable)
|
|
{
|
|
if(ContentTypeId::INDEX == nContentType)
|
|
{
|
|
bRemoveReadonlyIndexEntry = false;
|
|
bRemoveEditEntry = false;
|
|
const SwTOXBase* pBase = weld::fromId<SwTOXBaseContent*>(m_xTreeView->get_id(*xEntry))->GetTOXBase();
|
|
if (!pBase->IsTOXBaseInReadonly() && !SwEditShell::IsTOXBaseReadonly(*pBase))
|
|
{
|
|
bRemoveUpdateIndexEntry = false;
|
|
bRemoveDeleteIndexEntry = false;
|
|
}
|
|
else
|
|
bReadonly = true;
|
|
xPop->set_active(OUString::number(405), SwEditShell::IsTOXBaseReadonly(*pBase));
|
|
}
|
|
else if(ContentTypeId::TABLE == nContentType)
|
|
{
|
|
bRemoveSelectEntry = false;
|
|
bRemoveEditEntry = false;
|
|
bRemoveUnprotectEntry = false;
|
|
bRemoveDeleteTableEntry = false;
|
|
bool bFull = false;
|
|
OUString sTableName = weld::fromId<SwContent*>(m_xTreeView->get_id(*xEntry))->GetName();
|
|
bool bProt = m_pActiveShell->HasTableAnyProtection( &sTableName, &bFull );
|
|
xPop->set_sensitive(OUString::number(403), !bFull);
|
|
xPop->set_sensitive(OUString::number(404), bProt);
|
|
xPop->set_sensitive(u"deletetable"_ustr, !bFull);
|
|
}
|
|
else if(ContentTypeId::REGION == nContentType)
|
|
{
|
|
bRemoveEditEntry = false;
|
|
bRemoveProtectSection = false;
|
|
bRemoveHideSection = false;
|
|
SwContent* pCnt = weld::fromId<SwContent*>(m_xTreeView->get_id(*xEntry));
|
|
assert(dynamic_cast<SwRegionContent*>(static_cast<SwTypeNumber*>(pCnt)));
|
|
const SwSectionFormat* pSectionFormat
|
|
= static_cast<SwRegionContent*>(pCnt)->GetSectionFormat();
|
|
bool bHidden = pSectionFormat->GetSection()->IsHidden();
|
|
bRemoveSelectEntry = bHidden || !bVisible;
|
|
xPop->set_active(u"protectsection"_ustr, bProtected);
|
|
xPop->set_active(u"hidesection"_ustr, bHidden);
|
|
}
|
|
else
|
|
bRemoveEditEntry = false;
|
|
}
|
|
if (bRenamable && !bReadonly)
|
|
bRemoveRenameEntry = false;
|
|
}
|
|
else
|
|
{
|
|
if (ContentTypeId::OUTLINE == nContentType)
|
|
{
|
|
bOutline = true;
|
|
if (State::HIDDEN != m_eState)
|
|
{
|
|
lcl_SetOutlineContentEntriesSensitivities(this, *m_xTreeView, *xEntry,
|
|
*xSubPopOutlineContent);
|
|
bRemoveSendOutlineEntry = false;
|
|
}
|
|
bRemoveToggleExpandEntry
|
|
= lcl_InsertExpandCollapseAllItem(*m_xTreeView, *xEntry, *xPop);
|
|
}
|
|
else if (State::HIDDEN != m_eState
|
|
&& !m_pActiveShell->GetView().GetDocShell()->IsReadOnly()
|
|
&& pType->GetMemberCount() > 0)
|
|
{
|
|
// Choose which Delete All entry to show.
|
|
if (pType->IsDeletable() && IsDeletable(*xEntry))
|
|
{
|
|
switch (nContentType)
|
|
{
|
|
case ContentTypeId::TABLE:
|
|
bRemoveDeleteAllTablesEntry = false;
|
|
break;
|
|
case ContentTypeId::FRAME:
|
|
bRemoveDeleteAllFramesEntry = false;
|
|
break;
|
|
case ContentTypeId::GRAPHIC:
|
|
bRemoveDeleteAllImagesEntry = false;
|
|
break;
|
|
case ContentTypeId::OLE:
|
|
bRemoveDeleteAllOLEObjectsEntry = false;
|
|
break;
|
|
case ContentTypeId::BOOKMARK:
|
|
bRemoveDeleteAllBookmarksEntry = false;
|
|
break;
|
|
case ContentTypeId::REGION:
|
|
bRemoveDeleteAllRegionsEntry = false;
|
|
break;
|
|
case ContentTypeId::URLFIELD:
|
|
bRemoveDeleteAllHyperlinksEntry = false;
|
|
break;
|
|
case ContentTypeId::REFERENCE:
|
|
bRemoveDeleteAllReferencesEntry = false;
|
|
break;
|
|
case ContentTypeId::INDEX:
|
|
bRemoveDeleteAllIndexesEntry = false;
|
|
break;
|
|
case ContentTypeId::POSTIT:
|
|
bRemoveDeleteAllCommentsEntry = false;
|
|
break;
|
|
case ContentTypeId::DRAWOBJECT:
|
|
bRemoveDeleteAllDrawingObjectsEntry = false;
|
|
break;
|
|
case ContentTypeId::TEXTFIELD:
|
|
bRemoveDeleteAllFieldsEntry = false;
|
|
break;
|
|
case ContentTypeId::FOOTNOTE:
|
|
bRemoveDeleteAllFootnotesEntry = false;
|
|
bRemoveMakeAllFootnotesEndnotesEntry = false;
|
|
break;
|
|
case ContentTypeId::ENDNOTE:
|
|
bRemoveDeleteAllEndnotesEntry = false;
|
|
bRemoveMakeAllEndnotesFootnotesEntry = false;
|
|
break;
|
|
default: break;
|
|
}
|
|
}
|
|
if (nContentType == ContentTypeId::POSTIT)
|
|
{
|
|
const SwViewOption* m_pViewOpt = m_pActiveShell->GetViewOptions();
|
|
xPop->set_active(u"showcomments"_ustr, m_pViewOpt->IsPostIts());
|
|
xPop->set_active(u"showresolvedcomments"_ustr, m_pViewOpt->IsResolvedPostIts());
|
|
bRemovePostItEntries = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
bool bRemoveDeleteEntry =
|
|
bRemoveDeleteChapterEntry &&
|
|
bRemoveDeleteTableEntry &&
|
|
bRemoveDeleteFrameEntry &&
|
|
bRemoveDeleteImageEntry &&
|
|
bRemoveDeleteOLEObjectEntry &&
|
|
bRemoveDeleteBookmarkEntry &&
|
|
bRemoveDeleteRegionEntry &&
|
|
bRemoveDeleteHyperlinkEntry &&
|
|
bRemoveDeleteReferenceEntry &&
|
|
bRemoveDeleteIndexEntry &&
|
|
bRemoveDeleteCommentEntry &&
|
|
bRemoveDeleteDrawingObjectEntry &&
|
|
bRemoveDeleteFieldEntry &&
|
|
bRemoveDeleteFootnoteEntry &&
|
|
bRemoveDeleteEndnoteEntry &&
|
|
bRemoveDeleteAllTablesEntry &&
|
|
bRemoveDeleteAllFramesEntry &&
|
|
bRemoveDeleteAllImagesEntry &&
|
|
bRemoveDeleteAllOLEObjectsEntry &&
|
|
bRemoveDeleteAllBookmarksEntry &&
|
|
bRemoveDeleteAllRegionsEntry &&
|
|
bRemoveDeleteAllHyperlinksEntry &&
|
|
bRemoveDeleteAllReferencesEntry &&
|
|
bRemoveDeleteAllIndexesEntry &&
|
|
bRemoveDeleteCommentEntry &&
|
|
bRemoveDeleteAllDrawingObjectsEntry &&
|
|
bRemoveDeleteAllFieldsEntry &&
|
|
bRemoveDeleteAllFootnotesEntry &&
|
|
bRemoveDeleteAllEndnotesEntry;
|
|
|
|
bool bRemoveMakeFootnotesEndnotesViceVersaEntry =
|
|
bRemoveMakeAllFootnotesEndnotesEntry &&
|
|
bRemoveMakeAllEndnotesFootnotesEntry;
|
|
|
|
if (bRemoveRenameEntry)
|
|
xPop->remove(OUString::number(502));
|
|
|
|
if (bRemoveUpdateIndexEntry)
|
|
xPop->remove(OUString::number(402));
|
|
|
|
if (bRemoveReadonlyIndexEntry)
|
|
xPop->remove(OUString::number(405));
|
|
|
|
if (bRemoveUnprotectEntry)
|
|
xPop->remove(OUString::number(404));
|
|
|
|
if (bRemoveEditEntry)
|
|
xPop->remove(OUString::number(403));
|
|
|
|
if (bRemoveToggleExpandEntry &&
|
|
bRemoveSendOutlineEntry)
|
|
xPop->remove(u"separator1"_ustr);
|
|
|
|
if (bRemoveCopyEntry)
|
|
xPop->remove(u"copy"_ustr);
|
|
|
|
if (bRemoveGotoEntry &&
|
|
bRemoveCopyEntry &&
|
|
bRemoveSelectEntry &&
|
|
bRemoveDeleteEntry &&
|
|
bRemoveMakeFootnotesEndnotesViceVersaEntry &&
|
|
bRemoveChapterEntries &&
|
|
bRemovePostItEntries &&
|
|
bRemoveRenameEntry &&
|
|
bRemoveReadonlyIndexEntry &&
|
|
bRemoveUnprotectEntry &&
|
|
bRemoveEditEntry)
|
|
xPop->remove(u"separator2"_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);
|
|
|
|
bool bSetSensitiveCollapseAllCategories = false;
|
|
if (!m_bIsRoot && xEntry)
|
|
{
|
|
bool bEntry = m_xTreeView->get_iter_first(*xEntry);
|
|
while (bEntry)
|
|
{
|
|
if (m_xTreeView->get_row_expanded(*xEntry))
|
|
{
|
|
bSetSensitiveCollapseAllCategories = true;
|
|
break;
|
|
}
|
|
bEntry = m_xTreeView->iter_next_sibling(*xEntry);
|
|
}
|
|
}
|
|
xPop->set_sensitive(u"collapseallcategories"_ustr, bSetSensitiveCollapseAllCategories);
|
|
|
|
OUString sCommand = xPop->popup_at_rect(m_xTreeView.get(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1)));
|
|
if (!sCommand.isEmpty())
|
|
ExecuteContextMenuAction(sCommand);
|
|
|
|
return true;
|
|
}
|
|
|
|
void SwContentTree::InsertContent(const weld::TreeIter& rParent)
|
|
{
|
|
assert(dynamic_cast<SwContentType*>(weld::fromId<SwTypeNumber*>(m_xTreeView->get_id(rParent))));
|
|
SwContentType* pCntType = weld::fromId<SwContentType*>(m_xTreeView->get_id(rParent));
|
|
bool bGraphic = pCntType->GetType() == ContentTypeId::GRAPHIC;
|
|
std::unique_ptr<weld::TreeIter> xChild = m_xTreeView->make_iterator();
|
|
const size_t nCount = pCntType->GetMemberCount();
|
|
for(size_t i = 0; i < nCount; ++i)
|
|
{
|
|
const SwContent* pCnt = pCntType->GetMember(i);
|
|
OUString sEntry = pCnt->GetName();
|
|
if (sEntry.isEmpty())
|
|
sEntry = m_sSpace;
|
|
OUString sId(weld::toId(pCnt));
|
|
insert(&rParent, sEntry, sId, false, xChild.get());
|
|
m_xTreeView->set_sensitive(*xChild, !pCnt->IsInvisible());
|
|
if (bGraphic)
|
|
{
|
|
const OUString& rsURL = static_cast<const SwGraphicContent*>(pCnt)->GetLink();
|
|
if (!rsURL.isEmpty())
|
|
{
|
|
if (FStatHelper::IsDocument(rsURL))
|
|
{
|
|
m_xTreeView->set_image(*xChild, RID_BMP_NAVI_GRAPHIC_LINK);
|
|
}
|
|
else
|
|
{
|
|
m_xTreeView->set_image(*xChild, RID_BMP_NAVI_GRAPHIC_BROKENLINK);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SwContentTree::insert(const weld::TreeIter* pParent, const OUString& rStr, const OUString& rId,
|
|
bool bChildrenOnDemand, weld::TreeIter* pRet)
|
|
{
|
|
m_xTreeView->insert(pParent, -1, &rStr, &rId, nullptr, nullptr, bChildrenOnDemand, pRet);
|
|
++m_nEntryCount;
|
|
}
|
|
|
|
void SwContentTree::remove(const weld::TreeIter& rIter)
|
|
{
|
|
if (m_xTreeView->iter_has_child(rIter))
|
|
{
|
|
std::unique_ptr<weld::TreeIter> xChild = m_xTreeView->make_iterator(&rIter);
|
|
(void)m_xTreeView->iter_children(*xChild);
|
|
remove(*xChild);
|
|
}
|
|
m_xTreeView->remove(rIter);
|
|
--m_nEntryCount;
|
|
}
|
|
|
|
// 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();
|
|
|
|
assert(dynamic_cast<SwContentType*>(weld::fromId<SwTypeNumber*>(m_xTreeView->get_id(rParent))));
|
|
SwContentType* pCntType = weld::fromId<SwContentType*>(m_xTreeView->get_id(rParent));
|
|
|
|
const size_t nCount = pCntType->GetMemberCount();
|
|
// Add for outline plus/minus
|
|
if (pCntType->GetType() == ContentTypeId::OUTLINE)
|
|
{
|
|
if (pCntType->IsAlphabeticSort())
|
|
{
|
|
for (size_t i = 0; i < nCount; ++i)
|
|
{
|
|
const SwContent* pCnt = pCntType->GetMember(i);
|
|
if (pCnt)
|
|
{
|
|
OUString sEntry = pCnt->GetName();
|
|
if (sEntry.isEmpty())
|
|
sEntry = m_sSpace;
|
|
OUString sId(weld::toId(pCnt));
|
|
|
|
insert(&rParent, sEntry, sId, false, xChild.get());
|
|
m_xTreeView->set_sensitive(*xChild, !pCnt->IsInvisible());
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::vector<std::unique_ptr<weld::TreeIter>> aParentCandidates;
|
|
for (size_t i = 0; i < nCount; ++i)
|
|
{
|
|
const SwContent* pCnt = pCntType->GetMember(i);
|
|
if (pCnt)
|
|
{
|
|
const auto nLevel
|
|
= static_cast<const SwOutlineContent*>(pCnt)->GetOutlineLevel();
|
|
OUString sEntry = pCnt->GetName();
|
|
if (sEntry.isEmpty())
|
|
sEntry = m_sSpace;
|
|
OUString sId(weld::toId(pCnt));
|
|
|
|
auto lambda = [nLevel, this](const std::unique_ptr<weld::TreeIter>& entry) {
|
|
return lcl_IsLowerOutlineContent(*entry, *m_xTreeView, nLevel);
|
|
};
|
|
|
|
// 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));
|
|
|
|
OUString sEntry = pCnt->GetName();
|
|
OUString sId(weld::toId(pCnt));
|
|
|
|
const auto nLevel = pCnt->GetRegionLevel();
|
|
insert(&rParent, sEntry, sId, false, xChild.get());
|
|
|
|
m_xTreeView->set_sensitive(*xChild, !pCnt->IsInvisible());
|
|
m_xTreeView->set_extra_row_indent(*xChild, nLevel);
|
|
|
|
bool bHidden = pCnt->GetSectionFormat()->GetSection()->IsHidden();
|
|
if (pCnt->IsProtect())
|
|
m_xTreeView->set_image(*xChild, bHidden ? RID_BMP_PROT_HIDE : RID_BMP_PROT_NO_HIDE);
|
|
else
|
|
m_xTreeView->set_image(*xChild, bHidden ? RID_BMP_HIDE : RID_BMP_NO_HIDE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::vector<std::unique_ptr<weld::TreeIter>> aParentCandidates;
|
|
for(size_t i = 0; i < nCount; ++i)
|
|
{
|
|
const SwRegionContent* pCnt =
|
|
static_cast<const SwRegionContent*>(pCntType->GetMember(i));
|
|
|
|
OUString sEntry = pCnt->GetName();
|
|
OUString sId(weld::toId(pCnt));
|
|
|
|
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());
|
|
|
|
bool bHidden = pCnt->GetSectionFormat()->GetSection()->IsHidden();
|
|
if (pCnt->IsProtect())
|
|
m_xTreeView->set_image(*xChild, bHidden ? RID_BMP_PROT_HIDE : RID_BMP_PROT_NO_HIDE);
|
|
else
|
|
m_xTreeView->set_image(*xChild, bHidden ? RID_BMP_HIDE : RID_BMP_NO_HIDE);
|
|
|
|
// 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));
|
|
|
|
OUString sEntry = pCnt->GetName();
|
|
OUString sId(weld::toId(pCnt));
|
|
|
|
const SwPostItField* pPostItField =
|
|
static_cast<const SwPostItField*>(pCnt->GetPostIt()->GetField());
|
|
auto lambda = [&pPostItField, this](const std::unique_ptr<weld::TreeIter>& xEntry)
|
|
{
|
|
SwPostItContent* pParentCandidateCnt =
|
|
weld::fromId<SwPostItContent*>(m_xTreeView->get_id(*xEntry));
|
|
return pPostItField->GetParentPostItId() ==
|
|
static_cast<const SwPostItField*>(pParentCandidateCnt->GetPostIt()
|
|
->GetField())->GetPostItId();
|
|
};
|
|
|
|
// 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());
|
|
|
|
m_xTreeView->set_sensitive(*xChild, !pCnt->IsInvisible());
|
|
|
|
// 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();
|
|
|
|
aParentCandidates.emplace_back(m_xTreeView->make_iterator(xChild.get()));
|
|
}
|
|
}
|
|
else
|
|
InsertContent(rParent);
|
|
|
|
return nCount != 0;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void SwContentTree::ExpandAllHeadings()
|
|
{
|
|
if (HasHeadings())
|
|
{
|
|
std::unique_ptr<weld::TreeIter> xEntry = GetEntryAtAbsPos(0);
|
|
if (xEntry)
|
|
{
|
|
if (!IsAllExpanded(*m_xTreeView, *xEntry))
|
|
ExpandOrCollapseAll(*m_xTreeView, *xEntry);
|
|
}
|
|
}
|
|
}
|
|
|
|
SdrObject* SwContentTree::GetDrawingObjectsByContent(const SwContent *pCnt)
|
|
{
|
|
SdrObject *pRetObj = nullptr;
|
|
switch(pCnt->GetParent()->GetType())
|
|
{
|
|
case ContentTypeId::DRAWOBJECT:
|
|
{
|
|
SdrView* pDrawView = m_pActiveShell->GetDrawView();
|
|
if (pDrawView)
|
|
{
|
|
SwDrawModel* pDrawModel = m_pActiveShell->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel();
|
|
SdrPage* pPage = pDrawModel->GetPage(0);
|
|
|
|
for (const rtl::Reference<SdrObject>& pTemp : *pPage)
|
|
{
|
|
if( pTemp->GetName() == pCnt->GetName())
|
|
{
|
|
pRetObj = pTemp.get();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
pRetObj = nullptr;
|
|
}
|
|
return pRetObj;
|
|
}
|
|
|
|
void SwContentTree::Expand(const weld::TreeIter& rParent,
|
|
std::vector<std::unique_ptr<weld::TreeIter>>* pNodesToExpand)
|
|
{
|
|
if (!m_xTreeView->iter_has_child(rParent) && !m_xTreeView->get_children_on_demand(rParent))
|
|
return;
|
|
|
|
// 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 (m_nRootType == ContentTypeId::OUTLINE || (m_nRootType == ContentTypeId::UNKNOWN &&
|
|
eParentContentTypeId == ContentTypeId::OUTLINE))
|
|
{
|
|
if (bParentIsContentType)
|
|
{
|
|
std::map< void*, bool > aCurrOutLineNodeMap;
|
|
|
|
SwWrtShell* pShell = GetWrtShell();
|
|
bool bParentHasChild = RequestingChildren(rParent);
|
|
if (bParentHasChild)
|
|
{
|
|
std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(&rParent));
|
|
bool bChild = m_xTreeView->iter_next(*xChild);
|
|
while (bChild && lcl_IsContent(*xChild, *m_xTreeView))
|
|
{
|
|
if (m_xTreeView->iter_has_child(*xChild))
|
|
{
|
|
assert(dynamic_cast<SwOutlineContent*>(weld::fromId<SwTypeNumber*>(m_xTreeView->get_id(*xChild))));
|
|
auto const nPos = weld::fromId<SwOutlineContent*>(m_xTreeView->get_id(*xChild))->GetOutlinePos();
|
|
void* key = static_cast<void*>(pShell->getIDocumentOutlineNodesAccess()->getOutlineNode( nPos ));
|
|
aCurrOutLineNodeMap.emplace( key, false );
|
|
std::map<void*, bool>::iterator iter = mOutLineNodeMap.find( key );
|
|
if( iter != mOutLineNodeMap.end() && mOutLineNodeMap[key])
|
|
{
|
|
aCurrOutLineNodeMap[key] = true;
|
|
RequestingChildren(*xChild);
|
|
if (pNodesToExpand)
|
|
pNodesToExpand->emplace_back(m_xTreeView->make_iterator(xChild.get()));
|
|
m_xTreeView->set_children_on_demand(*xChild, false);
|
|
}
|
|
}
|
|
bChild = m_xTreeView->iter_next(*xChild);
|
|
}
|
|
}
|
|
mOutLineNodeMap = std::move(aCurrOutLineNodeMap);
|
|
return;
|
|
}
|
|
else // content entry
|
|
{
|
|
SwWrtShell* pShell = GetWrtShell();
|
|
assert(dynamic_cast<SwOutlineContent*>(weld::fromId<SwTypeNumber*>(aParentId)));
|
|
auto const nPos = weld::fromId<SwOutlineContent*>(aParentId)->GetOutlinePos();
|
|
void* key = static_cast<void*>(pShell->getIDocumentOutlineNodesAccess()->getOutlineNode( nPos ));
|
|
mOutLineNodeMap[key] = true;
|
|
}
|
|
}
|
|
else if (m_nRootType == ContentTypeId::REGION || (m_nRootType == ContentTypeId::UNKNOWN &&
|
|
eParentContentTypeId == ContentTypeId::REGION))
|
|
{
|
|
if (bParentIsContentType)
|
|
{
|
|
std::map<const void*, bool> aCurrentRegionNodeExpandMap;
|
|
if (RequestingChildren(rParent))
|
|
{
|
|
std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(&rParent));
|
|
while (m_xTreeView->iter_next(*xChild) && lcl_IsContent(*xChild, *m_xTreeView))
|
|
{
|
|
if (m_xTreeView->iter_has_child(*xChild))
|
|
{
|
|
assert(dynamic_cast<SwRegionContent*>(weld::fromId<SwTypeNumber*>(m_xTreeView->get_id(*xChild))));
|
|
const void* key =
|
|
static_cast<const void*>(weld::fromId<SwRegionContent*>(
|
|
m_xTreeView->get_id(*xChild))->GetSectionFormat());
|
|
bool bExpandNode =
|
|
m_aRegionNodeExpandMap.contains(key) && m_aRegionNodeExpandMap[key];
|
|
aCurrentRegionNodeExpandMap.emplace(key, bExpandNode);
|
|
if (bExpandNode)
|
|
{
|
|
if (pNodesToExpand)
|
|
pNodesToExpand->emplace_back(m_xTreeView->make_iterator(xChild.get()));
|
|
RequestingChildren(*xChild);
|
|
m_xTreeView->set_children_on_demand(*xChild, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
m_aRegionNodeExpandMap = std::move(aCurrentRegionNodeExpandMap);
|
|
return;
|
|
}
|
|
else // content entry
|
|
{
|
|
assert(dynamic_cast<SwRegionContent*>(weld::fromId<SwTypeNumber*>(aParentId)));
|
|
const void* key = static_cast<const void*>(
|
|
weld::fromId<SwRegionContent*>(aParentId)->GetSectionFormat());
|
|
m_aRegionNodeExpandMap[key] = true;
|
|
}
|
|
}
|
|
else if (m_nRootType == ContentTypeId::POSTIT || (m_nRootType == ContentTypeId::UNKNOWN &&
|
|
eParentContentTypeId == ContentTypeId::POSTIT))
|
|
{
|
|
if (bParentIsContentType)
|
|
{
|
|
std::map<const void*, bool> aCurrentPostItNodeExpandMap;
|
|
if (RequestingChildren(rParent))
|
|
{
|
|
std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(&rParent));
|
|
while (m_xTreeView->iter_next(*xChild) && lcl_IsContent(*xChild, *m_xTreeView))
|
|
{
|
|
if (m_xTreeView->iter_has_child(*xChild))
|
|
{
|
|
assert(dynamic_cast<SwPostItContent*>(weld::fromId<SwTypeNumber*>(m_xTreeView->get_id(*xChild))));
|
|
const void* key =
|
|
static_cast<const void*>(weld::fromId<SwPostItContent*>(
|
|
m_xTreeView->get_id(*xChild))->GetPostIt());
|
|
bool bExpandNode =
|
|
m_aPostItNodeExpandMap.contains(key) && m_aPostItNodeExpandMap[key];
|
|
aCurrentPostItNodeExpandMap.emplace(key, bExpandNode);
|
|
if (bExpandNode)
|
|
{
|
|
if (pNodesToExpand)
|
|
pNodesToExpand->emplace_back(m_xTreeView->make_iterator(xChild.get()));
|
|
RequestingChildren(*xChild);
|
|
m_xTreeView->set_children_on_demand(*xChild, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
m_aPostItNodeExpandMap = std::move(aCurrentPostItNodeExpandMap);
|
|
return;
|
|
}
|
|
else // content entry
|
|
{
|
|
assert(dynamic_cast<SwPostItContent*>(weld::fromId<SwTypeNumber*>(aParentId)));
|
|
const void* key = static_cast<const void*>(
|
|
weld::fromId<SwPostItContent*>(aParentId)->GetPostIt());
|
|
m_aPostItNodeExpandMap[key] = true;
|
|
}
|
|
}
|
|
|
|
RequestingChildren(rParent);
|
|
}
|
|
|
|
IMPL_LINK(SwContentTree, ExpandHdl, const weld::TreeIter&, rParent, bool)
|
|
{
|
|
Expand(rParent, nullptr);
|
|
return true;
|
|
}
|
|
|
|
IMPL_LINK(SwContentTree, CollapseHdl, const weld::TreeIter&, rParent, bool)
|
|
{
|
|
if (!m_xTreeView->iter_has_child(rParent) || m_xTreeView->get_children_on_demand(rParent))
|
|
return true;
|
|
|
|
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
|
|
}
|
|
|
|
IMPL_LINK_NOARG(SwContentTree, AsyncContentDoubleClickHdl, void*, void)
|
|
{
|
|
m_nRowActivateEventId = nullptr;
|
|
|
|
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
|
|
bool bEntry = m_xTreeView->get_cursor(xEntry.get());
|
|
// Is it a content type?
|
|
OSL_ENSURE(bEntry, "no current entry!");
|
|
if (bEntry)
|
|
{
|
|
if (lcl_IsContentType(*xEntry, *m_xTreeView) && !m_xTreeView->iter_has_child(*xEntry))
|
|
{
|
|
RequestingChildren(*xEntry);
|
|
m_xTreeView->set_children_on_demand(*xEntry, false);
|
|
}
|
|
else if (!lcl_IsContentType(*xEntry, *m_xTreeView) && (State::HIDDEN != m_eState))
|
|
{
|
|
assert(dynamic_cast<SwContent*>(weld::fromId<SwTypeNumber*>(m_xTreeView->get_id(*xEntry))));
|
|
SwContent* pCnt = weld::fromId<SwContent*>(m_xTreeView->get_id(*xEntry));
|
|
assert(pCnt && "no UserData");
|
|
if (pCnt && !pCnt->IsInvisible())
|
|
{
|
|
if (State::CONSTANT == m_eState)
|
|
{
|
|
m_pActiveShell->GetView().GetViewFrame().GetWindow().ToTop();
|
|
}
|
|
//Jump to content type:
|
|
GotoContent(pCnt);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace
|
|
{
|
|
OUString GetImageIdForContentTypeId(ContentTypeId eType)
|
|
{
|
|
OUString sResId;
|
|
|
|
switch (eType)
|
|
{
|
|
case ContentTypeId::OUTLINE:
|
|
sResId = RID_BMP_NAVI_OUTLINE;
|
|
break;
|
|
case ContentTypeId::TABLE:
|
|
sResId = RID_BMP_NAVI_TABLE;
|
|
break;
|
|
case ContentTypeId::FRAME:
|
|
sResId = RID_BMP_NAVI_FRAME;
|
|
break;
|
|
case ContentTypeId::GRAPHIC:
|
|
sResId = RID_BMP_NAVI_GRAPHIC;
|
|
break;
|
|
case ContentTypeId::OLE:
|
|
sResId = RID_BMP_NAVI_OLE;
|
|
break;
|
|
case ContentTypeId::BOOKMARK:
|
|
sResId = RID_BMP_NAVI_BOOKMARK;
|
|
break;
|
|
case ContentTypeId::REGION:
|
|
sResId = RID_BMP_NAVI_REGION;
|
|
break;
|
|
case ContentTypeId::URLFIELD:
|
|
sResId = RID_BMP_NAVI_URLFIELD;
|
|
break;
|
|
case ContentTypeId::REFERENCE:
|
|
sResId = RID_BMP_NAVI_REFERENCE;
|
|
break;
|
|
case ContentTypeId::INDEX:
|
|
sResId = RID_BMP_NAVI_INDEX;
|
|
break;
|
|
case ContentTypeId::POSTIT:
|
|
sResId = RID_BMP_NAVI_POSTIT;
|
|
break;
|
|
case ContentTypeId::DRAWOBJECT:
|
|
sResId = RID_BMP_NAVI_DRAWOBJECT;
|
|
break;
|
|
case ContentTypeId::TEXTFIELD:
|
|
sResId = RID_BMP_NAVI_TEXTFIELD;
|
|
break;
|
|
case ContentTypeId::FOOTNOTE:
|
|
sResId = RID_BMP_NAVI_FOOTNOTE;
|
|
break;
|
|
case ContentTypeId::ENDNOTE:
|
|
sResId = RID_BMP_NAVI_ENDNOTE;
|
|
break;
|
|
case ContentTypeId::UNKNOWN:
|
|
SAL_WARN("sw.ui", "ContentTypeId::UNKNOWN has no bitmap preview");
|
|
break;
|
|
}
|
|
|
|
return sResId;
|
|
};
|
|
}
|
|
|
|
size_t SwContentTree::GetAbsPos(const weld::TreeIter& rIter)
|
|
{
|
|
return weld::GetAbsPos(*m_xTreeView, rIter);
|
|
}
|
|
|
|
size_t SwContentTree::GetEntryCount() const
|
|
{
|
|
return m_nEntryCount;
|
|
}
|
|
|
|
size_t SwContentTree::GetChildCount(const weld::TreeIter& rParent) const
|
|
{
|
|
if (!m_xTreeView->iter_has_child(rParent))
|
|
return 0;
|
|
|
|
std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(&rParent));
|
|
|
|
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);
|
|
}
|
|
|
|
clear();
|
|
|
|
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;
|
|
|
|
SwWrtShell* pShell = GetWrtShell();
|
|
if (pShell)
|
|
{
|
|
std::unique_ptr<weld::TreeIter> xEntry = m_xTreeView->make_iterator();
|
|
std::unique_ptr<weld::TreeIter> xCntTypeEntry;
|
|
std::vector<std::unique_ptr<weld::TreeIter>> aNodesToExpand;
|
|
// all content navigation view
|
|
if(m_nRootType == ContentTypeId::UNKNOWN)
|
|
{
|
|
m_xTreeView->freeze();
|
|
|
|
for( ContentTypeId nCntType : o3tl::enumrange<ContentTypeId>() )
|
|
{
|
|
std::unique_ptr<SwContentType>& rpContentT = bActive ?
|
|
m_aActiveContentArr[nCntType] :
|
|
m_aHiddenContentArr[nCntType];
|
|
if(!rpContentT)
|
|
rpContentT.reset(new SwContentType(pShell, nCntType, m_nOutlineLevel ));
|
|
|
|
OUString aImage(GetImageIdForContentTypeId(nCntType));
|
|
bool bChOnDemand = 0 != rpContentT->GetMemberCount();
|
|
|
|
// In case of LOK, empty content types must be hidden in the contenttree
|
|
if (comphelper::LibreOfficeKit::isActive() && !bChOnDemand)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
OUString sId(weld::toId(rpContentT.get()));
|
|
insert(nullptr, rpContentT->GetName(), sId, bChOnDemand, xEntry.get());
|
|
m_xTreeView->set_image(*xEntry, aImage);
|
|
|
|
m_xTreeView->set_sensitive(*xEntry, bChOnDemand);
|
|
|
|
if (nCntType == m_nLastSelType)
|
|
xCntTypeEntry = m_xTreeView->make_iterator(xEntry.get());
|
|
|
|
sal_Int32 nExpandOptions = (State::HIDDEN == m_eState)
|
|
? m_nHiddenBlock
|
|
: m_nActiveBlock;
|
|
if (nExpandOptions & (1 << static_cast<int>(nCntType)))
|
|
{
|
|
// fill contents of to-be expanded entries while frozen
|
|
Expand(*xEntry, &aNodesToExpand);
|
|
m_xTreeView->set_children_on_demand(*xEntry, false);
|
|
}
|
|
}
|
|
|
|
m_xTreeView->thaw();
|
|
|
|
// restore visual expanded tree state
|
|
for (const auto& rNode : aNodesToExpand)
|
|
m_xTreeView->expand_row(*rNode);
|
|
}
|
|
// root content navigation view
|
|
else
|
|
{
|
|
m_xTreeView->freeze();
|
|
|
|
std::unique_ptr<SwContentType>& rpRootContentT = bActive ?
|
|
m_aActiveContentArr[m_nRootType] :
|
|
m_aHiddenContentArr[m_nRootType];
|
|
if(!rpRootContentT)
|
|
rpRootContentT.reset(new SwContentType(pShell, m_nRootType, m_nOutlineLevel ));
|
|
OUString aImage(GetImageIdForContentTypeId(m_nRootType));
|
|
bool bChOnDemand(m_nRootType == ContentTypeId::OUTLINE ||
|
|
m_nRootType == ContentTypeId::REGION ||
|
|
m_nRootType == ContentTypeId::POSTIT);
|
|
OUString sId(weld::toId(rpRootContentT.get()));
|
|
insert(nullptr, rpRootContentT->GetName(), sId, bChOnDemand, xEntry.get());
|
|
m_xTreeView->set_image(*xEntry, aImage);
|
|
|
|
xCntTypeEntry = m_xTreeView->make_iterator(xEntry.get());
|
|
|
|
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);
|
|
}
|
|
|
|
m_xTreeView->set_sensitive(*xEntry, m_xTreeView->iter_has_child(*xEntry));
|
|
|
|
m_xTreeView->thaw();
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
void SwContentTree::clear()
|
|
{
|
|
m_xTreeView->freeze();
|
|
m_xTreeView->clear();
|
|
m_nEntryCount = 0;
|
|
m_xTreeView->thaw();
|
|
}
|
|
|
|
bool SwContentTree::FillTransferData(TransferDataContainer& rTransfer)
|
|
{
|
|
SwWrtShell* pWrtShell = GetWrtShell();
|
|
OSL_ENSURE(pWrtShell, "no Shell!");
|
|
|
|
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
|
|
bool bEntry = m_xTreeView->get_cursor(xEntry.get());
|
|
if (!bEntry || lcl_IsContentType(*xEntry, *m_xTreeView) || !pWrtShell)
|
|
return false;
|
|
assert(dynamic_cast<SwContent*>(weld::fromId<SwTypeNumber*>(m_xTreeView->get_id(*xEntry))));
|
|
SwContent* pCnt = weld::fromId<SwContent*>(m_xTreeView->get_id(*xEntry));
|
|
|
|
OUString sEntry;
|
|
OUString sUrl;
|
|
OUString sCrossRef;
|
|
bool bUrl = true;
|
|
bool bCrossRef = true;
|
|
OUString sOutlineText;
|
|
|
|
const ContentTypeId eActType = pCnt->GetParent()->GetType();
|
|
switch (eActType)
|
|
{
|
|
case ContentTypeId::OUTLINE:
|
|
{
|
|
const SwOutlineNodes::size_type nPos = static_cast<SwOutlineContent*>(pCnt)->GetOutlinePos();
|
|
OSL_ENSURE(nPos < pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineNodesCount(),
|
|
"outlinecnt changed");
|
|
|
|
// make sure outline may actually be copied
|
|
if( pWrtShell->IsOutlineCopyable( nPos ) )
|
|
{
|
|
const SwNumRule* pOutlRule = pWrtShell->GetOutlineNumRule();
|
|
const SwTextNode* pTextNd =
|
|
pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineNode(nPos);
|
|
if (pTextNd && pOutlRule && pTextNd->IsNumbered(pWrtShell->GetLayout()))
|
|
{
|
|
SwNumberTree::tNumberVector aNumVector =
|
|
pTextNd->GetNumberVector(pWrtShell->GetLayout());
|
|
for( int nLevel = 0;
|
|
nLevel <= pTextNd->GetActualListLevel();
|
|
nLevel++ )
|
|
{
|
|
const SwNumberTree::tSwNumTreeNumber nVal = aNumVector[nLevel] + 1;
|
|
sEntry += OUString::number( nVal - pOutlRule->Get(nLevel).GetStart() ) + ".";
|
|
}
|
|
}
|
|
sEntry += pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineText(nPos, pWrtShell->GetLayout(), false);
|
|
sOutlineText = pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineText(nPos, pWrtShell->GetLayout());
|
|
m_bIsOutlineMoveable = static_cast<SwOutlineContent*>(pCnt)->IsMoveable();
|
|
}
|
|
}
|
|
break;
|
|
case ContentTypeId::BOOKMARK:
|
|
sEntry = m_xTreeView->get_text(*xEntry);
|
|
break;
|
|
case ContentTypeId::TABLE:
|
|
case ContentTypeId::FRAME:
|
|
case ContentTypeId::REGION:
|
|
bCrossRef = false;
|
|
sEntry = m_xTreeView->get_text(*xEntry);
|
|
break;
|
|
// content types that cannot be inserted, as URL, section, or reference
|
|
case ContentTypeId::POSTIT:
|
|
case ContentTypeId::INDEX:
|
|
return false;
|
|
// content types than can only be inserted as a cross-reference
|
|
case ContentTypeId::REFERENCE:
|
|
case ContentTypeId::TEXTFIELD:
|
|
case ContentTypeId::FOOTNOTE:
|
|
case ContentTypeId::ENDNOTE:
|
|
bUrl = false;
|
|
sEntry = m_xTreeView->get_text(*xEntry);
|
|
break;
|
|
// content types that can only be inserted as a hyperlink
|
|
case ContentTypeId::URLFIELD:
|
|
sUrl = static_cast<SwURLFieldContent*>(pCnt)->GetURL();
|
|
[[fallthrough]];
|
|
case ContentTypeId::OLE:
|
|
case ContentTypeId::GRAPHIC:
|
|
case ContentTypeId::DRAWOBJECT:
|
|
bCrossRef = false;
|
|
sEntry = m_xTreeView->get_text(*xEntry);
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
if(!sEntry.isEmpty())
|
|
{
|
|
const SwDocShell* pDocShell = pWrtShell->GetView().GetDocShell();
|
|
if (bUrl && sUrl.isEmpty())
|
|
{
|
|
if(pDocShell->HasName())
|
|
{
|
|
SfxMedium* pMedium = pDocShell->GetMedium();
|
|
sUrl = pMedium->GetURLObject().GetURLNoMark();
|
|
}
|
|
else if (SwView* pView = GetActiveView(); State::CONSTANT == m_eState
|
|
&& (!pView || m_pActiveShell != pView->GetWrtShellPtr()))
|
|
{
|
|
// Urls of inactive views cannot dragged without
|
|
// file names, also.
|
|
return false;
|
|
}
|
|
else if (eActType != ContentTypeId::REGION && eActType != ContentTypeId::BOOKMARK)
|
|
{
|
|
// For sections and bookmarks a link is also allowed
|
|
// without a filename into its own document.
|
|
return false;
|
|
}
|
|
|
|
const OUString& rToken = pCnt->GetParent()->GetTypeToken();
|
|
sUrl += "#" + sEntry;
|
|
if(!rToken.isEmpty())
|
|
{
|
|
sUrl += OUStringChar(cMarkSeparator) + rToken;
|
|
}
|
|
}
|
|
|
|
if (bCrossRef)
|
|
{
|
|
if (eActType == ContentTypeId::TEXTFIELD)
|
|
{
|
|
SwTextFieldContent* pTextFieldContent = static_cast<SwTextFieldContent*>(pCnt);
|
|
const SwFormatField* pFormatField = pTextFieldContent->GetFormatField();
|
|
const SwField* pField = pFormatField->GetField();
|
|
|
|
if (SwFieldTypesEnum::Sequence != pField->GetTypeId())
|
|
return false;
|
|
|
|
OUString sVal = pField->ExpandField(true, m_pActiveShell->GetLayout());
|
|
sal_uInt32 nSeqNo = sVal.toUInt32();
|
|
if (nSeqNo > 0)
|
|
{
|
|
--nSeqNo;
|
|
sVal = OUString::number(nSeqNo);
|
|
}
|
|
else
|
|
return false;
|
|
|
|
const OUString sFieldTypeName = pField->GetTyp()->GetName();
|
|
sCrossRef = OUString::number(static_cast<int>(REFERENCESUBTYPE::REF_SEQUENCEFLD))
|
|
+ u"|" + sFieldTypeName + u"|" + sVal;
|
|
}
|
|
else if (eActType == ContentTypeId::REFERENCE)
|
|
{
|
|
sCrossRef = OUString::number(static_cast<int>(REFERENCESUBTYPE::REF_SETREFATTR))
|
|
+ u"|" + sEntry;
|
|
}
|
|
else if (eActType == ContentTypeId::BOOKMARK)
|
|
{
|
|
sCrossRef = OUString::number(static_cast<int>(REFERENCESUBTYPE::REF_BOOKMARK))
|
|
+ u"|" + sEntry;
|
|
}
|
|
else if (eActType == ContentTypeId::FOOTNOTE || eActType == ContentTypeId::ENDNOTE)
|
|
{
|
|
SeqFieldLstElem aElem(sEntry, 0);
|
|
SwSeqFieldList aArr;
|
|
size_t nIdx = 0;
|
|
OUString sVal;
|
|
|
|
if (m_pActiveShell->GetSeqFootnoteList(aArr, eActType == ContentTypeId::ENDNOTE)
|
|
&& aArr.SeekEntry(aElem, &nIdx))
|
|
sVal = OUString::number(aArr[nIdx].nSeqNo);
|
|
else
|
|
return false;
|
|
|
|
REFERENCESUBTYPE eReferenceSubType =
|
|
eActType == ContentTypeId::FOOTNOTE ? REFERENCESUBTYPE::REF_FOOTNOTE :
|
|
REFERENCESUBTYPE::REF_ENDNOTE;
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
NaviContentBookmark aBmk(sUrl, sCrossRef, sEntry, pDocShell);
|
|
aBmk.Copy(rTransfer);
|
|
|
|
// 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()
|
|
{
|
|
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;
|
|
|
|
assert(dynamic_cast<SwContentType*>(weld::fromId<SwTypeNumber*>(m_xTreeView->get_id(*xRootEntry))));
|
|
const ContentTypeId nType = weld::fromId<SwContentType*>(m_xTreeView->get_id(*xRootEntry))->GetType();
|
|
SwContentType* pArrType = m_aActiveContentArr[nType].get();
|
|
assert(weld::toId(pArrType) == m_xTreeView->get_id(*xRootEntry));
|
|
if (!pArrType)
|
|
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;
|
|
|
|
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(xRootEntry.get()));
|
|
for (size_t j = 0; j < nChildCount; ++j)
|
|
{
|
|
if (!m_xTreeView->iter_next(*xEntry))
|
|
{
|
|
SAL_WARN("sw.ui", "unexpected missing entry");
|
|
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;
|
|
|
|
OUString sEntryText = m_xTreeView->get_text(*xEntry);
|
|
if (sEntryText != pCnt->GetName() &&
|
|
!(sEntryText == m_sSpace && pCnt->GetName().isEmpty()))
|
|
{
|
|
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;
|
|
}
|
|
|
|
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
|
|
|
|
// 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);
|
|
};
|
|
|
|
for (bool bEntry = m_xTreeView->get_iter_first(*xEntry); bEntry;
|
|
bEntry = lcl_nextContentTypeEntry())
|
|
{
|
|
assert(dynamic_cast<SwContentType*>(weld::fromId<SwTypeNumber*>(m_xTreeView->get_id(*xEntry))));
|
|
SwContentType* pCntType = weld::fromId<SwContentType*>(m_xTreeView->get_id(*xEntry));
|
|
const size_t nCntCount = pCntType->GetMemberCount();
|
|
const ContentTypeId nType = pCntType->GetType();
|
|
SwContentType* pArrType = m_aActiveContentArr[nType].get();
|
|
assert(weld::toId(pArrType) == m_xTreeView->get_id(*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;
|
|
}
|
|
|
|
for(size_t j = 0; j < nChildCount; ++j)
|
|
{
|
|
if (!m_xTreeView->iter_next(*xEntry))
|
|
{
|
|
SAL_WARN("sw.ui", "unexpected missing entry");
|
|
bContentChanged = true;
|
|
break;
|
|
}
|
|
|
|
const SwContent* pCnt = pArrType->GetMember(j);
|
|
|
|
if (pCnt->IsInvisible() != m_xTreeView->get_sensitive(*xEntry, 0))
|
|
{
|
|
bContentChanged = true;
|
|
break;
|
|
}
|
|
|
|
OUString sEntryText = m_xTreeView->get_text(*xEntry);
|
|
if( sEntryText != pCnt->GetName() &&
|
|
!(sEntryText == m_sSpace && pCnt->GetName().isEmpty()))
|
|
{
|
|
bContentChanged = true;
|
|
break;
|
|
}
|
|
|
|
// See comment above in single content type navigation view block for why the
|
|
// following is done here.
|
|
OUString sSubId(weld::toId(pCnt));
|
|
m_xTreeView->set_id(*xEntry, sSubId);
|
|
}
|
|
}
|
|
// not expanded and has children
|
|
else if (m_xTreeView->iter_has_child(*xEntry))
|
|
{
|
|
bool bRemoveChildren = false;
|
|
const size_t nOldChildCount = GetChildCount(*xEntry);
|
|
const size_t nNewChildCount = pArrType->GetMemberCount();
|
|
if (nOldChildCount != nNewChildCount)
|
|
{
|
|
bRemoveChildren = true;
|
|
}
|
|
else
|
|
{
|
|
std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(xEntry.get()));
|
|
(void)m_xTreeView->iter_children(*xChild);
|
|
for (size_t j = 0; j < nOldChildCount; ++j)
|
|
{
|
|
const SwContent* pCnt = pArrType->GetMember(j);
|
|
OUString sSubId(weld::toId(pCnt));
|
|
m_xTreeView->set_id(*xChild, sSubId);
|
|
OUString sEntryText = m_xTreeView->get_text(*xChild);
|
|
if( sEntryText != pCnt->GetName() &&
|
|
!(sEntryText == m_sSpace && pCnt->GetName().isEmpty()))
|
|
{
|
|
bRemoveChildren = true;
|
|
}
|
|
(void)m_xTreeView->iter_next(*xChild);
|
|
}
|
|
}
|
|
if (bRemoveChildren)
|
|
{
|
|
std::unique_ptr<weld::TreeIter> xRemove(m_xTreeView->make_iterator(xEntry.get()));
|
|
while (m_xTreeView->iter_children(*xRemove))
|
|
{
|
|
remove(*xRemove);
|
|
m_xTreeView->copy_iterator(*xEntry, *xRemove);
|
|
}
|
|
m_xTreeView->set_children_on_demand(*xEntry, nNewChildCount != 0);
|
|
}
|
|
}
|
|
else if((nCntCount != 0)
|
|
!= (pArrType->GetMemberCount()!=0))
|
|
{
|
|
bContentChanged = true;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
return bContentChanged;
|
|
}
|
|
|
|
void SwContentTree::UpdateLastSelType()
|
|
{
|
|
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
|
|
if (m_xTreeView->get_selected(xEntry.get()))
|
|
{
|
|
while (m_xTreeView->get_iter_depth(*xEntry))
|
|
m_xTreeView->iter_parent(*xEntry);
|
|
void* pId = weld::fromId<void*>(m_xTreeView->get_id(*xEntry));
|
|
if (pId && lcl_IsContentType(*xEntry, *m_xTreeView))
|
|
{
|
|
assert(dynamic_cast<SwContentType*>(static_cast<SwTypeNumber*>(pId)));
|
|
m_nLastSelType = static_cast<SwContentType*>(pId)->GetType();
|
|
}
|
|
}
|
|
}
|
|
|
|
void SwContentTree::FindActiveTypeAndRemoveUserData()
|
|
{
|
|
UpdateLastSelType();
|
|
|
|
// 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;
|
|
});
|
|
}
|
|
|
|
void SwContentTree::SetHiddenShell(SwWrtShell* pSh)
|
|
{
|
|
m_pHiddenShell = pSh;
|
|
m_eState = State::HIDDEN;
|
|
FindActiveTypeAndRemoveUserData();
|
|
for(ContentTypeId i : o3tl::enumrange<ContentTypeId>())
|
|
{
|
|
m_aHiddenContentArr[i].reset();
|
|
}
|
|
Display(false);
|
|
|
|
GetParentWindow()->UpdateListBox();
|
|
}
|
|
|
|
void SwContentTree::SetActiveShell(SwWrtShell* pSh)
|
|
{
|
|
bool bClear = m_pActiveShell != pSh;
|
|
if (State::ACTIVE == m_eState && bClear)
|
|
{
|
|
EndListeningAll();
|
|
m_pActiveShell = pSh;
|
|
FindActiveTypeAndRemoveUserData();
|
|
clear();
|
|
}
|
|
else if (State::CONSTANT == m_eState)
|
|
{
|
|
EndListeningAll();
|
|
m_pActiveShell = pSh;
|
|
m_eState = State::ACTIVE;
|
|
bClear = true;
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
|
|
void SwContentTree::SetConstantShell(SwWrtShell* pSh)
|
|
{
|
|
EndListeningAll();
|
|
m_pActiveShell = pSh;
|
|
m_eState = State::CONSTANT;
|
|
StartListening(*m_pActiveShell->GetView().GetDocShell());
|
|
FindActiveTypeAndRemoveUserData();
|
|
for(ContentTypeId i : o3tl::enumrange<ContentTypeId>())
|
|
{
|
|
m_aActiveContentArr[i].reset();
|
|
}
|
|
Display(true);
|
|
}
|
|
|
|
void SwContentTree::Notify(SfxBroadcaster & rBC, SfxHint const& rHint)
|
|
{
|
|
if (rHint.GetId() == SfxHintId::ThisIsAnSfxEventHint)
|
|
{
|
|
const SfxEventHint* pEventHint = static_cast<const SfxEventHint*>(&rHint);
|
|
if (pEventHint->GetEventId() == SfxEventHintId::CloseView)
|
|
{
|
|
SfxViewEventHint const*const pVEHint(static_cast<SfxViewEventHint const*>(&rHint));
|
|
if (m_pActiveShell)
|
|
{
|
|
SwXTextView* pDyingShell = dynamic_cast<SwXTextView*>(pVEHint->GetController().get());
|
|
if (pDyingShell && pDyingShell->GetView() == &m_pActiveShell->GetView())
|
|
{
|
|
SetActiveShell(nullptr); // our view is dying, clear our pointers to it
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
SfxListener::Notify(rBC, rHint);
|
|
switch (rHint.GetId())
|
|
{
|
|
case SfxHintId::SwNavigatorUpdateTracking:
|
|
UpdateTracking();
|
|
break;
|
|
case SfxHintId::SwNavigatorSelectOutlinesWithSelections:
|
|
{
|
|
if (m_nRootType == ContentTypeId::OUTLINE)
|
|
{
|
|
SelectOutlinesWithSelection();
|
|
// make first selected entry visible
|
|
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
|
|
if (xEntry && m_xTreeView->get_selected(xEntry.get()))
|
|
m_xTreeView->scroll_to_row(*xEntry);
|
|
}
|
|
else if (m_nRootType == ContentTypeId::UNKNOWN)
|
|
m_xTreeView->unselect_all();
|
|
break;
|
|
}
|
|
case SfxHintId::DocChanged:
|
|
OverlayObject();
|
|
if (!m_bIgnoreDocChange)
|
|
{
|
|
m_bDocHasChanged = true;
|
|
TimerUpdate(&m_aUpdTimer);
|
|
}
|
|
break;
|
|
case SfxHintId::ModeChanged:
|
|
if (SwWrtShell* pShell = GetWrtShell())
|
|
{
|
|
const bool bReadOnly = pShell->GetView().GetDocShell()->IsReadOnly();
|
|
if (bReadOnly != m_bIsLastReadOnly)
|
|
{
|
|
m_bIsLastReadOnly = bReadOnly;
|
|
|
|
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
|
|
if (m_xTreeView->get_cursor(xEntry.get()))
|
|
{
|
|
m_xTreeView->select(*xEntry);
|
|
UpdateContentFunctionsToolbar();
|
|
}
|
|
else
|
|
m_xTreeView->unselect_all();
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Handler for outline entry up/down left/right movement
|
|
void SwContentTree::ExecCommand(std::u16string_view rCmd, bool bOutlineWithChildren)
|
|
{
|
|
if (m_xTreeView->count_selected_rows() == 0)
|
|
return;
|
|
|
|
const bool bUp = rCmd == u"chapterup";
|
|
const bool bUpDown = bUp || rCmd == u"chapterdown";
|
|
const bool bLeft = rCmd == u"promote";
|
|
const bool bLeftRight = bLeft || rCmd == u"demote";
|
|
if (!bUpDown && !bLeftRight)
|
|
return;
|
|
if (GetWrtShell()->GetView().GetDocShell()->IsReadOnly() ||
|
|
(State::ACTIVE != m_eState &&
|
|
(State::CONSTANT != m_eState || m_pActiveShell != GetParentWindow()->GetCreateView()->GetWrtShellPtr())))
|
|
{
|
|
return;
|
|
}
|
|
|
|
SwWrtShell *const pShell = GetWrtShell();
|
|
|
|
const SwNodes& rNodes = pShell->GetNodes();
|
|
const SwOutlineNodes& rOutlineNodes = rNodes.GetOutLineNds();
|
|
const SwOutlineNodes::size_type nOutlineNdsSize = rOutlineNodes.size();
|
|
|
|
std::vector<SwTextNode*> selectedOutlineNodes;
|
|
std::vector<std::unique_ptr<weld::TreeIter>> selected;
|
|
|
|
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());
|
|
}
|
|
|
|
m_bIgnoreDocChange = true;
|
|
|
|
SwOutlineNodes::size_type nActPos;
|
|
bool bStartedAction = false;
|
|
|
|
MakeAllOutlineContentTemporarilyVisible a(GetWrtShell()->GetDoc());
|
|
|
|
// get first regular document content node outline node position in outline nodes array
|
|
SwOutlineNodes::size_type nFirstRegularDocContentOutlineNodePos = SwOutlineNodes::npos;
|
|
SwNodeOffset nEndOfExtrasIndex = rNodes.GetEndOfExtras().GetIndex();
|
|
sal_Int32 nHasInlineHeading = 0;
|
|
for (SwOutlineNodes::size_type nPos = 0; nPos < nOutlineNdsSize; nPos++)
|
|
{
|
|
if (rOutlineNodes[nPos]->GetIndex() > nEndOfExtrasIndex)
|
|
{
|
|
nFirstRegularDocContentOutlineNodePos = nPos;
|
|
break;
|
|
}
|
|
if ( bUpDown && rOutlineNodes[nPos] != SwOutlineNodes::GetRootNode(rOutlineNodes[nPos]) )
|
|
++nHasInlineHeading;
|
|
}
|
|
|
|
for (auto const& pCurrentEntry : selected)
|
|
{
|
|
nActPos = weld::fromId<SwOutlineContent*>(
|
|
m_xTreeView->get_id(*pCurrentEntry))->GetOutlinePos();
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
if (!bStartedAction)
|
|
{
|
|
pShell->StartAllAction();
|
|
pShell->StartUndo(bLeftRight ? SwUndoId::OUTLINE_LR : SwUndoId::OUTLINE_UD);
|
|
bStartedAction = true;
|
|
}
|
|
|
|
pShell->GotoOutline( nActPos); // If text selection != box selection
|
|
pShell->Push();
|
|
|
|
if (nHasInlineHeading && bUpDown)
|
|
{
|
|
SwOutlineNodesInline aOutlineNodesInline;
|
|
// sort inline headings correctly
|
|
for (SwNode* pNode : rOutlineNodes)
|
|
aOutlineNodesInline.insert(pNode);
|
|
const SwOutlineNodes::size_type nOutlineNdsSizeInline = aOutlineNodesInline.size();
|
|
|
|
// 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();
|
|
}
|
|
else if (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;
|
|
}
|
|
|
|
void SwContentTree::ShowTree()
|
|
{
|
|
m_xTreeView->show();
|
|
m_aUpdTimer.Start();
|
|
}
|
|
|
|
void SwContentTree::HideTree()
|
|
{
|
|
// folded together will not be idled
|
|
m_aUpdTimer.Stop();
|
|
m_xTreeView->hide();
|
|
}
|
|
|
|
static void lcl_SelectByContentTypeAndAddress(SwContentTree* pThis, weld::TreeView& rContentTree,
|
|
ContentTypeId nType, const void* ptr)
|
|
{
|
|
if (!ptr)
|
|
{
|
|
rContentTree.set_cursor(-1);
|
|
pThis->UpdateContentFunctionsToolbar();
|
|
return;
|
|
}
|
|
|
|
// find content type entry
|
|
std::unique_ptr<weld::TreeIter> xIter(rContentTree.make_iterator());
|
|
|
|
bool bFoundEntry = rContentTree.get_iter_first(*xIter);
|
|
while (bFoundEntry)
|
|
{
|
|
void* pUserData = weld::fromId<void*>(rContentTree.get_id(*xIter));
|
|
assert(dynamic_cast<SwContentType*>(static_cast<SwTypeNumber*>(pUserData)));
|
|
if (nType == static_cast<SwContentType*>(pUserData)->GetType())
|
|
break;
|
|
bFoundEntry = rContentTree.iter_next_sibling(*xIter);
|
|
}
|
|
|
|
if (!bFoundEntry)
|
|
{
|
|
rContentTree.set_cursor(-1);
|
|
pThis->UpdateContentFunctionsToolbar();
|
|
return;
|
|
}
|
|
|
|
// assure content type entry is expanded
|
|
rContentTree.expand_row(*xIter);
|
|
|
|
// find content type content entry and select it
|
|
const void* p = nullptr;
|
|
while (rContentTree.iter_next(*xIter) && lcl_IsContent(*xIter, rContentTree))
|
|
{
|
|
void* pUserData = weld::fromId<void*>(rContentTree.get_id(*xIter));
|
|
switch( nType )
|
|
{
|
|
case ContentTypeId::FOOTNOTE:
|
|
case ContentTypeId::ENDNOTE:
|
|
{
|
|
assert(dynamic_cast<SwTextFootnoteContent*>(static_cast<SwTypeNumber*>(pUserData)));
|
|
SwTextFootnoteContent* pCnt = static_cast<SwTextFootnoteContent*>(pUserData);
|
|
p = pCnt->GetTextFootnote();
|
|
break;
|
|
}
|
|
case ContentTypeId::URLFIELD:
|
|
{
|
|
assert(dynamic_cast<SwURLFieldContent*>(static_cast<SwTypeNumber*>(pUserData)));
|
|
SwURLFieldContent* pCnt = static_cast<SwURLFieldContent*>(pUserData);
|
|
p = static_cast<const SwTextAttr*>(pCnt->GetINetAttr());
|
|
break;
|
|
}
|
|
case ContentTypeId::TEXTFIELD:
|
|
{
|
|
assert(dynamic_cast<SwTextFieldContent*>(static_cast<SwTypeNumber*>(pUserData)));
|
|
SwTextFieldContent* pCnt = static_cast<SwTextFieldContent*>(pUserData);
|
|
p = pCnt->GetFormatField()->GetField();
|
|
break;
|
|
}
|
|
case ContentTypeId::POSTIT:
|
|
{
|
|
assert(dynamic_cast<SwPostItContent*>(static_cast<SwTypeNumber*>(pUserData)));
|
|
SwPostItContent* pCnt = static_cast<SwPostItContent*>(pUserData);
|
|
p = pCnt->GetPostIt()->GetField();
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
if (ptr == p)
|
|
{
|
|
// 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();
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
rContentTree.set_cursor(-1);
|
|
pThis->UpdateContentFunctionsToolbar();
|
|
return;
|
|
}
|
|
|
|
static void lcl_SelectByContentTypeAndName(SwContentTree* pThis, weld::TreeView& rContentTree,
|
|
std::u16string_view rContentTypeName, std::u16string_view rName)
|
|
{
|
|
if (rName.empty())
|
|
return;
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void lcl_SelectDrawObjectByName(SwContentTree* pThis, weld::TreeView& rContentTree,
|
|
std::u16string_view rName)
|
|
{
|
|
if (rName.empty())
|
|
return;
|
|
|
|
// 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();
|
|
|
|
SwWrtShell* pActShell = pView ? pView->GetWrtShellPtr() : nullptr;
|
|
if(pActShell && pActShell->GetWin() &&
|
|
(pActShell->GetWin()->HasFocus() || m_bDocHasChanged || m_bViewHasChanged) &&
|
|
!IsInDrag() && !pActShell->ActionPend())
|
|
{
|
|
if (m_bDocHasChanged || m_bViewHasChanged)
|
|
{
|
|
if (State::CONSTANT == m_eState && !lcl_FindShell(m_pActiveShell))
|
|
{
|
|
SetActiveShell(pActShell);
|
|
GetParentWindow()->UpdateListBox();
|
|
}
|
|
if (State::ACTIVE == m_eState && pActShell != GetWrtShell())
|
|
{
|
|
SetActiveShell(pActShell);
|
|
}
|
|
else if (SolarMutexGuard aGuard;
|
|
(State::ACTIVE == m_eState || (State::CONSTANT == m_eState && pActShell == GetWrtShell())) &&
|
|
HasContentChanged())
|
|
{
|
|
FindActiveTypeAndRemoveUserData();
|
|
Display(true);
|
|
}
|
|
}
|
|
UpdateTracking();
|
|
m_bIsIdleClear = false;
|
|
m_bDocHasChanged = false;
|
|
m_bViewHasChanged = false;
|
|
}
|
|
else if (!pView && State::ACTIVE == m_eState && !m_bIsIdleClear) // this block seems never to be entered
|
|
{
|
|
if(m_pActiveShell)
|
|
{
|
|
SetActiveShell(nullptr);
|
|
}
|
|
clear();
|
|
m_bIsIdleClear = true;
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
else if (m_pActiveShell->GetSelectionType() == SelectionType::Frame &&
|
|
!(m_bIsRoot && m_nRootType != ContentTypeId::FRAME))
|
|
{
|
|
if (!mTrackContentType[ContentTypeId::FRAME]) return;
|
|
aContentTypeName = SwResId(STR_CONTENT_TYPE_FRAME);
|
|
}
|
|
else if (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())
|
|
{
|
|
OUString aName(m_pActiveShell->GetFlyName());
|
|
lcl_SelectByContentTypeAndName(this, *m_xTreeView, aContentTypeName, aName);
|
|
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::Ftn);
|
|
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);
|
|
}
|
|
else if (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());
|
|
}
|
|
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())
|
|
{
|
|
OUString aName = m_pActiveShell->GetTableFormat()->GetName();
|
|
lcl_SelectByContentTypeAndName(this, *m_xTreeView, SwResId(STR_CONTENT_TYPE_TABLE),
|
|
aName);
|
|
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());
|
|
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());
|
|
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))
|
|
{
|
|
OUString 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;
|
|
}
|
|
else if (!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);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// clear treeview selections
|
|
if (m_xTreeView->count_selected_rows() > 0)
|
|
{
|
|
m_xTreeView->unselect_all();
|
|
m_xTreeView->set_cursor(-1);
|
|
UpdateContentFunctionsToolbar();
|
|
}
|
|
}
|
|
|
|
static bool lcl_IsSelectedCompareByContentTypeAndAddress(const weld::TreeIter& rEntry,
|
|
weld::TreeView& rContentTree,
|
|
ContentTypeId eContentType,
|
|
const void* ptr)
|
|
{
|
|
if (!ptr)
|
|
return false;
|
|
|
|
std::unique_ptr<weld::TreeIter> xIter(rContentTree.make_iterator());
|
|
|
|
// 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
|
|
const void* p = nullptr;
|
|
while (rContentTree.iter_next(*xIter) && lcl_IsContent(*xIter, rContentTree))
|
|
{
|
|
assert(dynamic_cast<SwContent*>(weld::fromId<SwTypeNumber*>(rContentTree.get_id(*xIter))));
|
|
SwContent* pContent = weld::fromId<SwContent*>(rContentTree.get_id(*xIter));
|
|
switch (eContentType)
|
|
{
|
|
case ContentTypeId::FOOTNOTE:
|
|
case ContentTypeId::ENDNOTE:
|
|
{
|
|
assert(dynamic_cast<SwTextFootnoteContent*>(static_cast<SwTypeNumber*>(pContent)));
|
|
SwTextFootnoteContent* pCnt = static_cast<SwTextFootnoteContent*>(pContent);
|
|
p = pCnt->GetTextFootnote();
|
|
break;
|
|
}
|
|
case ContentTypeId::URLFIELD:
|
|
{
|
|
assert(dynamic_cast<SwURLFieldContent*>(static_cast<SwTypeNumber*>(pContent)));
|
|
SwURLFieldContent* pCnt = static_cast<SwURLFieldContent*>(pContent);
|
|
p = static_cast<const SwTextAttr*>(pCnt->GetINetAttr());
|
|
break;
|
|
}
|
|
case ContentTypeId::TEXTFIELD:
|
|
{
|
|
assert(dynamic_cast<SwTextFieldContent*>(static_cast<SwTypeNumber*>(pContent)));
|
|
SwTextFieldContent* pCnt = static_cast<SwTextFieldContent*>(pContent);
|
|
p = pCnt->GetFormatField()->GetField();
|
|
break;
|
|
}
|
|
case ContentTypeId::POSTIT:
|
|
{
|
|
assert(dynamic_cast<SwPostItContent*>(static_cast<SwTypeNumber*>(pContent)));
|
|
SwPostItContent* pCnt = static_cast<SwPostItContent*>(pContent);
|
|
p = pCnt->GetPostIt()->GetField();
|
|
break;
|
|
}
|
|
case ContentTypeId::INDEX:
|
|
{
|
|
assert(dynamic_cast<SwTOXBaseContent*>(static_cast<SwTypeNumber*>(pContent)));
|
|
SwTOXBaseContent* pCnt = static_cast<SwTOXBaseContent*>(pContent);
|
|
p = pCnt->GetTOXBase();
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
if (ptr == p)
|
|
return rContentTree.iter_compare(*xIter, rEntry) == 0;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool lcl_IsSelectedCompareByContentTypeAndName(const weld::TreeIter& rEntry,
|
|
weld::TreeView& rContentTree,
|
|
ContentTypeId eContentType,
|
|
std::u16string_view rName)
|
|
{
|
|
std::unique_ptr<weld::TreeIter> xIter(rContentTree.make_iterator());
|
|
|
|
// 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;
|
|
}
|
|
|
|
bool SwContentTree::IsSelectedEntryCurrentDocCursorPosition(const weld::TreeIter& rEntry)
|
|
{
|
|
if (State::HIDDEN == m_eState || !m_pActiveShell)
|
|
return false;
|
|
|
|
// table
|
|
if (m_pActiveShell->IsCursorInTable())
|
|
{
|
|
return lcl_IsSelectedCompareByContentTypeAndName(
|
|
rEntry, *m_xTreeView, ContentTypeId::TABLE,
|
|
m_pActiveShell->GetTableFormat()->GetName());
|
|
}
|
|
// graphic, frame, and ole
|
|
if (m_pActiveShell->GetSelectionType()
|
|
& (SelectionType::Graphic | SelectionType::Frame | SelectionType::Ole))
|
|
{
|
|
ContentTypeId eContentTypeId;
|
|
if (m_pActiveShell->GetSelectionType() == SelectionType::Graphic)
|
|
eContentTypeId = ContentTypeId::GRAPHIC;
|
|
else if (m_pActiveShell->GetSelectionType() == SelectionType::Frame)
|
|
eContentTypeId = ContentTypeId::FRAME;
|
|
else if (m_pActiveShell->GetSelectionType() == SelectionType::Ole)
|
|
eContentTypeId = ContentTypeId::OLE;
|
|
else // to quiet compiler warning/error
|
|
return false;
|
|
return lcl_IsSelectedCompareByContentTypeAndName(rEntry, *m_xTreeView, eContentTypeId,
|
|
m_pActiveShell->GetFlyName());
|
|
}
|
|
// hyperlinks
|
|
// not in ToxContent tdf#148312 <- does this apply here?
|
|
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))
|
|
{
|
|
// 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.
|
|
return lcl_IsSelectedCompareByContentTypeAndAddress(
|
|
rEntry, *m_xTreeView, ContentTypeId::URLFIELD, aContentAtPos.pFndTextAttr);
|
|
}
|
|
}
|
|
// references
|
|
if (SwContentAtPos aContentAtPos(IsAttrAtPos::RefMark);
|
|
m_pActiveShell->GetContentAtPos(m_pActiveShell->GetCursorDocPos(), aContentAtPos)
|
|
&& aContentAtPos.pFndTextAttr)
|
|
{
|
|
const SwFormatRefMark& rRefMark = aContentAtPos.pFndTextAttr->GetRefMark();
|
|
return lcl_IsSelectedCompareByContentTypeAndName(
|
|
rEntry, *m_xTreeView, ContentTypeId::REFERENCE, rRefMark.GetRefName());
|
|
}
|
|
// indexes
|
|
if (const SwTOXBase* pTOXBase = m_pActiveShell->GetCurTOX())
|
|
{
|
|
return lcl_IsSelectedCompareByContentTypeAndAddress(rEntry, *m_xTreeView,
|
|
ContentTypeId::INDEX, pTOXBase);
|
|
// alternatively:
|
|
// return lcl_IsSelectedCompareByContentTypeAndName(rEntry, *m_xTreeView,
|
|
// ContentTypeId::INDEX,
|
|
// pTOX->GetTOXName());
|
|
}
|
|
// fields, comments
|
|
if (SwField* pField = m_pActiveShell->GetCurField())
|
|
{
|
|
ContentTypeId eContentTypeId = pField->GetTypeId() == SwFieldTypesEnum::Postit
|
|
? ContentTypeId::POSTIT
|
|
: ContentTypeId::TEXTFIELD;
|
|
return lcl_IsSelectedCompareByContentTypeAndAddress(rEntry, *m_xTreeView, eContentTypeId,
|
|
pField);
|
|
}
|
|
// drawing
|
|
if (m_pActiveShell->GetSelectionType()
|
|
& (SelectionType::DrawObject | SelectionType::DrawObjectEditMode | SelectionType::DbForm))
|
|
{
|
|
SdrView* pSdrView = m_pActiveShell->GetDrawView();
|
|
if (!pSdrView)
|
|
return false;
|
|
// ONLY CHECKS FIRST MARKED OBJECT
|
|
for (size_t nIdx = 0; nIdx < pSdrView->GetMarkedObjectList().GetMarkCount(); nIdx++)
|
|
{
|
|
SdrObject* pObject = pSdrView->GetMarkedObjectList().GetMark(nIdx)->GetMarkedSdrObj();
|
|
if (lcl_IsSelectedCompareByContentTypeAndName(
|
|
rEntry, *m_xTreeView, ContentTypeId::DRAWOBJECT, pObject->GetName()))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
// footnotes and endnotes
|
|
if (SwContentAtPos aContentAtPos(IsAttrAtPos::Ftn);
|
|
m_pActiveShell->GetContentAtPos(m_pActiveShell->GetCursorDocPos(), aContentAtPos)
|
|
&& aContentAtPos.pFndTextAttr)
|
|
{
|
|
ContentTypeId eContentTypeId = aContentAtPos.pFndTextAttr->GetFootnote().IsEndNote()
|
|
? ContentTypeId::ENDNOTE
|
|
: ContentTypeId::FOOTNOTE;
|
|
return lcl_IsSelectedCompareByContentTypeAndAddress(rEntry, *m_xTreeView, eContentTypeId,
|
|
aContentAtPos.pFndTextAttr);
|
|
}
|
|
// section
|
|
if (const SwSection* pSection = m_pActiveShell->GetCurrSection())
|
|
{
|
|
return lcl_IsSelectedCompareByContentTypeAndName(
|
|
rEntry, *m_xTreeView, ContentTypeId::REGION, pSection->GetSectionName());
|
|
}
|
|
// bookmark (unsure about this)
|
|
if (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())
|
|
{
|
|
OUString 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)
|
|
return lcl_IsSelectedCompareByContentTypeAndName(
|
|
rEntry, *m_xTreeView, ContentTypeId::BOOKMARK, sBookmarkName);
|
|
}
|
|
else if (!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)
|
|
return lcl_IsSelectedCompareByContentTypeAndName(
|
|
rEntry, *m_xTreeView, ContentTypeId::BOOKMARK, sBookmarkName);
|
|
}
|
|
++ppBookmark;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void SwContentTree::SelectOutlinesWithSelection()
|
|
{
|
|
SwCursor* pFirstCursor = m_pActiveShell->GetCursor();
|
|
SwCursor* pCursor = pFirstCursor;
|
|
std::vector<SwOutlineNodes::size_type> aOutlinePositions;
|
|
do
|
|
{
|
|
if (pCursor)
|
|
{
|
|
if (pCursor->HasMark())
|
|
{
|
|
aOutlinePositions.push_back(m_pActiveShell->GetOutlinePos(UCHAR_MAX, pCursor));
|
|
}
|
|
pCursor = pCursor->GetNext();
|
|
}
|
|
} while (pCursor && pCursor != pFirstCursor);
|
|
|
|
if (aOutlinePositions.empty())
|
|
return;
|
|
|
|
// remove duplicates before selecting
|
|
aOutlinePositions.erase(std::unique(aOutlinePositions.begin(), aOutlinePositions.end()),
|
|
aOutlinePositions.end());
|
|
|
|
m_xTreeView->unselect_all();
|
|
|
|
for (auto nOutlinePosition : aOutlinePositions)
|
|
{
|
|
m_xTreeView->all_foreach([this, nOutlinePosition](const weld::TreeIter& rEntry){
|
|
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() ==
|
|
nOutlinePosition)
|
|
{
|
|
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();
|
|
}
|
|
|
|
void SwContentTree::MoveOutline(SwOutlineNodes::size_type nTargetPos)
|
|
{
|
|
MakeAllOutlineContentTemporarilyVisible a(GetWrtShell()->GetDoc());
|
|
|
|
SwWrtShell *const pShell = GetWrtShell();
|
|
pShell->StartAllAction();
|
|
pShell->StartUndo(SwUndoId::OUTLINE_UD);
|
|
|
|
SwOutlineNodes::size_type nPrevSourcePos = SwOutlineNodes::npos;
|
|
SwOutlineNodes::size_type nPrevTargetPosOrOffset = SwOutlineNodes::npos;
|
|
|
|
bool bFirstMove = true;
|
|
|
|
for (const SwOutlineNodes::size_type& nPos : m_aDndOutlinesSelected)
|
|
{
|
|
SwOutlineNodes::size_type nSourcePos = nPos;
|
|
|
|
// 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;
|
|
}
|
|
else if (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;
|
|
}
|
|
else if (nSourcePos < nTargetPos)
|
|
{
|
|
// Move down
|
|
nSourcePos = nPrevSourcePos;
|
|
nTargetPos = nPrevTargetPosOrOffset;
|
|
}
|
|
}
|
|
GetParentWindow()->MoveOutline(nSourcePos, nTargetPos);
|
|
}
|
|
|
|
pShell->EndUndo();
|
|
pShell->EndAllAction();
|
|
m_aActiveContentArr[ContentTypeId::OUTLINE]->Invalidate();
|
|
Display(true);
|
|
m_aDndOutlinesSelected.clear();
|
|
}
|
|
|
|
// Update immediately
|
|
IMPL_LINK_NOARG(SwContentTree, FocusInHdl, weld::Widget&, void)
|
|
{
|
|
SwView* pActView = GetParentWindow()->GetCreateView();
|
|
if(pActView)
|
|
{
|
|
SwWrtShell* pActShell = pActView->GetWrtShellPtr();
|
|
if (State::CONSTANT == m_eState && !lcl_FindShell(m_pActiveShell))
|
|
{
|
|
SetActiveShell(pActShell);
|
|
}
|
|
|
|
if (State::ACTIVE == m_eState && pActShell != GetWrtShell())
|
|
SetActiveShell(pActShell);
|
|
// Only call HasContentChanged() if the document has changed since last called
|
|
else if ((State::ACTIVE == m_eState || (State::CONSTANT == m_eState && pActShell == GetWrtShell())) &&
|
|
m_bDocHasChanged)
|
|
{
|
|
if (HasContentChanged())
|
|
Display(true);
|
|
m_bDocHasChanged = false;
|
|
}
|
|
}
|
|
else if (State::ACTIVE == m_eState)
|
|
clear();
|
|
}
|
|
|
|
IMPL_LINK(SwContentTree, KeyInputHdl, const KeyEvent&, rEvent, bool)
|
|
{
|
|
bool bConsumed = true;
|
|
|
|
const vcl::KeyCode aCode = rEvent.GetKeyCode();
|
|
if (aCode.GetCode() == KEY_MULTIPLY && aCode.IsMod1())
|
|
{
|
|
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
|
|
if (m_xTreeView->get_selected(xEntry.get()))
|
|
ExpandOrCollapseAll(*m_xTreeView, *xEntry);
|
|
}
|
|
else if (aCode.GetCode() == KEY_RETURN)
|
|
{
|
|
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
|
|
if (m_xTreeView->get_selected(xEntry.get()))
|
|
{
|
|
switch(aCode.GetModifier())
|
|
{
|
|
case KEY_MOD2:
|
|
// Switch boxes
|
|
GetParentWindow()->ToggleTree();
|
|
break;
|
|
case KEY_MOD1:
|
|
// Switch RootMode
|
|
ToggleToRoot();
|
|
break;
|
|
case 0:
|
|
if (lcl_IsContentType(*xEntry, *m_xTreeView))
|
|
{
|
|
m_xTreeView->get_row_expanded(*xEntry) ? m_xTreeView->collapse_row(*xEntry)
|
|
: m_xTreeView->expand_row(*xEntry);
|
|
}
|
|
else
|
|
ContentDoubleClickHdl(*m_xTreeView);
|
|
break;
|
|
case KEY_SHIFT:
|
|
m_bSelectTo = true;
|
|
ContentDoubleClickHdl(*m_xTreeView);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if(aCode.GetCode() == KEY_DELETE && 0 == aCode.GetModifier())
|
|
{
|
|
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
|
|
if (!m_pActiveShell->GetView().GetDocShell()->IsReadOnly()
|
|
&& m_xTreeView->get_selected(xEntry.get()))
|
|
{
|
|
if (lcl_IsContent(*xEntry, *m_xTreeView))
|
|
{
|
|
assert(dynamic_cast<SwContent*>(weld::fromId<SwTypeNumber*>(m_xTreeView->get_id(*xEntry))));
|
|
if (weld::fromId<SwContent*>(m_xTreeView->get_id(*xEntry))->GetParent()->IsDeletable())
|
|
{
|
|
EditEntry(*xEntry, EditEntryMode::DELETE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SwContentType* pContentType
|
|
= weld::fromId<SwContentType*>(m_xTreeView->get_id(*xEntry));
|
|
if (pContentType->GetMemberCount()
|
|
&& (pContentType->GetType() == ContentTypeId::FOOTNOTE
|
|
|| pContentType->GetType() == ContentTypeId::ENDNOTE))
|
|
{
|
|
DeleteAllContentOfEntryContentType(*xEntry);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//Make KEY_SPACE has same function as DoubleClick, and realize
|
|
//multi-selection.
|
|
else if (aCode.GetCode() == KEY_SPACE && 0 == aCode.GetModifier())
|
|
{
|
|
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
|
|
if (m_xTreeView->get_cursor(xEntry.get()))
|
|
{
|
|
if (State::HIDDEN != m_eState)
|
|
{
|
|
if (State::CONSTANT == m_eState)
|
|
{
|
|
m_pActiveShell->GetView().GetViewFrame().GetWindow().ToTop();
|
|
}
|
|
|
|
SwContent* pCnt = dynamic_cast<SwContent*>(weld::fromId<SwTypeNumber*>(m_xTreeView->get_id(*xEntry)));
|
|
|
|
if (pCnt && pCnt->GetParent()->GetType() == ContentTypeId::DRAWOBJECT)
|
|
{
|
|
SdrView* pDrawView = m_pActiveShell->GetDrawView();
|
|
if (pDrawView)
|
|
{
|
|
pDrawView->SdrEndTextEdit();
|
|
|
|
SwDrawModel* pDrawModel = m_pActiveShell->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel();
|
|
SdrPage* pPage = pDrawModel->GetPage(0);
|
|
bool hasObjectMarked = false;
|
|
|
|
if (SdrObject* pObject = GetDrawingObjectsByContent(pCnt))
|
|
{
|
|
SdrPageView* pPV = pDrawView->GetSdrPageView/*GetPageViewPvNum*/(/*0*/);
|
|
if( pPV )
|
|
{
|
|
bool bUnMark = pDrawView->IsObjMarked(pObject);
|
|
pDrawView->MarkObj( pObject, pPV, bUnMark);
|
|
|
|
}
|
|
}
|
|
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 );
|
|
}
|
|
}
|
|
}
|
|
|
|
m_bViewHasChanged = true;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
|
|
if (m_xTreeView->get_cursor(xEntry.get()))
|
|
{
|
|
SwContent* pCnt = dynamic_cast<SwContent*>(weld::fromId<SwTypeNumber*>(m_xTreeView->get_id(*xEntry)));
|
|
if (pCnt && pCnt->GetParent()->GetType() == ContentTypeId::OUTLINE)
|
|
{
|
|
if (m_bIsRoot && aCode.GetCode() == KEY_LEFT && aCode.GetModifier() == 0)
|
|
{
|
|
m_xTreeView->unselect_all();
|
|
bConsumed = false;
|
|
}
|
|
else if (aCode.IsMod1())
|
|
{
|
|
if (aCode.GetCode() == KEY_LEFT)
|
|
ExecCommand(u"promote", !aCode.IsShift());
|
|
else if (aCode.GetCode() == KEY_RIGHT)
|
|
ExecCommand(u"demote", !aCode.IsShift());
|
|
else if (aCode.GetCode() == KEY_UP)
|
|
ExecCommand(u"chapterup", !aCode.IsShift());
|
|
else if (aCode.GetCode() == KEY_DOWN)
|
|
ExecCommand(u"chapterdown", !aCode.IsShift());
|
|
else if (aCode.GetCode() == KEY_C)
|
|
CopyOutlineSelections();
|
|
else
|
|
bConsumed = false;
|
|
}
|
|
else
|
|
bConsumed = false;
|
|
}
|
|
else
|
|
bConsumed = false;
|
|
}
|
|
else
|
|
bConsumed = false;
|
|
}
|
|
return bConsumed;
|
|
}
|
|
|
|
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();
|
|
|
|
ContentTypeId nType;
|
|
bool bContent = false;
|
|
void* pUserData = weld::fromId<void*>(m_xTreeView->get_id(rEntry));
|
|
if (lcl_IsContentType(rEntry, *m_xTreeView))
|
|
{
|
|
assert(dynamic_cast<SwContentType*>(static_cast<SwTypeNumber*>(pUserData)));
|
|
nType = static_cast<SwContentType*>(pUserData)->GetType();
|
|
}
|
|
else
|
|
{
|
|
assert(dynamic_cast<SwContent*>(static_cast<SwTypeNumber*>(pUserData)));
|
|
nType = static_cast<SwContent*>(pUserData)->GetParent()->GetType();
|
|
bContent = true;
|
|
}
|
|
OUString sEntry;
|
|
if(bContent)
|
|
{
|
|
switch( nType )
|
|
{
|
|
case ContentTypeId::URLFIELD:
|
|
assert(dynamic_cast<SwURLFieldContent*>(static_cast<SwTypeNumber*>(pUserData)));
|
|
sEntry = static_cast<SwURLFieldContent*>(pUserData)->GetURL();
|
|
break;
|
|
|
|
case ContentTypeId::POSTIT:
|
|
assert(dynamic_cast<SwPostItContent*>(static_cast<SwTypeNumber*>(pUserData)));
|
|
sEntry = static_cast<SwPostItContent*>(pUserData)->GetName();
|
|
break;
|
|
case ContentTypeId::OUTLINE:
|
|
{
|
|
assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pUserData)));
|
|
SwOutlineContent* pOutlineContent = static_cast<SwOutlineContent*>(pUserData);
|
|
SwOutlineNodes::size_type nOutlinePos = pOutlineContent->GetOutlinePos();
|
|
const SwNodes& rNodes = m_pActiveShell->GetDoc()->GetNodes();
|
|
const SwOutlineNodes& rOutlineNodes = rNodes.GetOutLineNds();
|
|
SwNode* pStartNode = rOutlineNodes[nOutlinePos];
|
|
SwNode* pEndNode = &rNodes.GetEndOfContent();
|
|
if (nOutlinePos + 1 < rOutlineNodes.size())
|
|
pEndNode = rOutlineNodes[nOutlinePos + 1];
|
|
SwPaM aPaM(*pStartNode, *pEndNode);
|
|
SwDocStat aDocStat;
|
|
SwDoc::CountWords(aPaM, aDocStat);
|
|
sEntry = pOutlineContent->GetName() + "\n" + SwResId(FLD_STAT_WORD) + ": "
|
|
+ OUString::number(aDocStat.nWord) + "\n" + SwResId(FLD_STAT_CHAR) + ": "
|
|
+ OUString::number(aDocStat.nChar);
|
|
}
|
|
break;
|
|
case ContentTypeId::GRAPHIC:
|
|
assert(dynamic_cast<SwGraphicContent*>(static_cast<SwTypeNumber*>(pUserData)));
|
|
sEntry = static_cast<SwGraphicContent*>(pUserData)->GetLink();
|
|
break;
|
|
case ContentTypeId::REGION:
|
|
{
|
|
assert(dynamic_cast<SwRegionContent*>(static_cast<SwTypeNumber*>(pUserData)));
|
|
sEntry = static_cast<SwRegionContent*>(pUserData)->GetName();
|
|
const SwSectionFormats& rFormats = GetWrtShell()->GetDoc()->GetSections();
|
|
for (SwSectionFormats::size_type n = rFormats.size(); n;)
|
|
{
|
|
const SwNodeIndex* pIdx = nullptr;
|
|
const SwSectionFormat* pFormat = rFormats[--n];
|
|
const SwSection* pSect;
|
|
if (nullptr != (pSect = pFormat->GetSection()) &&
|
|
pSect->GetSectionName() == sEntry &&
|
|
nullptr != (pIdx = pFormat->GetContent().GetContentIdx()) &&
|
|
pIdx->GetNode().GetNodes().IsDocNodes())
|
|
{
|
|
SwDocStat aDocStat;
|
|
SwPaM aPaM(pIdx->GetNode(), *pIdx->GetNode().EndOfSectionNode());
|
|
SwDoc::CountWords(aPaM, aDocStat);
|
|
sEntry = SwResId(STR_REGION_DEFNAME) + ": " + sEntry + "\n" +
|
|
SwResId(FLD_STAT_WORD) + ": " + OUString::number(aDocStat.nWord) + "\n" +
|
|
SwResId(FLD_STAT_CHAR) + ": " + OUString::number(aDocStat.nChar);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case ContentTypeId::FOOTNOTE:
|
|
case ContentTypeId::ENDNOTE:
|
|
{
|
|
assert(dynamic_cast<SwTextFootnoteContent*>(static_cast<SwTypeNumber*>(pUserData)));
|
|
const SwTextFootnote* pFootnote =
|
|
static_cast<const SwTextFootnoteContent*>(pUserData)->GetTextFootnote();
|
|
|
|
sEntry = pFootnote->GetFootnote().IsEndNote() ? SwResId(STR_CONTENT_ENDNOTE) :
|
|
SwResId(STR_CONTENT_FOOTNOTE);
|
|
}
|
|
break;
|
|
default: break;
|
|
}
|
|
if(static_cast<SwContent*>(pUserData)->IsInvisible())
|
|
{
|
|
if(!sEntry.isEmpty())
|
|
sEntry += ", ";
|
|
sEntry += m_sInvisible;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
size_t nMemberCount = static_cast<SwContentType*>(pUserData)->GetMemberCount();
|
|
sEntry = OUString::number(nMemberCount) + " " +
|
|
(nMemberCount == 1
|
|
? static_cast<SwContentType*>(pUserData)->GetSingleName()
|
|
: static_cast<SwContentType*>(pUserData)->GetName());
|
|
}
|
|
|
|
return sEntry;
|
|
}
|
|
|
|
void SwContentTree::ExecuteContextMenuAction(const OUString& rSelectedPopupEntry)
|
|
{
|
|
if (rSelectedPopupEntry == "makeallfootnotesendnotes"
|
|
|| rSelectedPopupEntry == "makeallendnotesfootnotes")
|
|
{
|
|
std::unique_ptr<weld::TreeIter> xEntryIter(m_xTreeView->make_iterator());
|
|
if (!m_xTreeView->get_selected(xEntryIter.get()))
|
|
return; // this shouldn't happen
|
|
SwContentType* pContentType = weld::fromId<SwContentType*>(m_xTreeView->get_id(*xEntryIter));
|
|
m_pActiveShell->StartUndo(rSelectedPopupEntry == "makeallfootnotesendnotes"
|
|
? SwUndoId::MAKE_FOOTNOTES_ENDNOTES
|
|
: SwUndoId::MAKE_ENDNOTES_FOOTNOTES);
|
|
lcl_SelectAllFootnotesOrEndnotes(*m_pActiveShell, pContentType);
|
|
SwFormatFootnote aNote(rSelectedPopupEntry == "makeallfootnotesendnotes");
|
|
m_pActiveShell->SetCurFootnote(aNote);
|
|
m_pActiveShell->EndUndo();
|
|
return;
|
|
}
|
|
|
|
if (rSelectedPopupEntry == "copy")
|
|
{
|
|
CopyOutlineSelections();
|
|
return;
|
|
}
|
|
if (rSelectedPopupEntry == "collapseallcategories")
|
|
{
|
|
std::unique_ptr<weld::TreeIter> xEntry = m_xTreeView->make_iterator();
|
|
bool bEntry = m_xTreeView->get_iter_first(*xEntry);
|
|
while (bEntry)
|
|
{
|
|
m_xTreeView->collapse_row(*xEntry);
|
|
bEntry = m_xTreeView->iter_next_sibling(*xEntry);
|
|
}
|
|
return;
|
|
}
|
|
|
|
{
|
|
std::map<OUString, ContentTypeId> mPopupEntryToContentTypeId
|
|
{
|
|
{"tabletracking", ContentTypeId::TABLE},
|
|
{"frametracking", ContentTypeId::FRAME},
|
|
{"imagetracking", ContentTypeId::GRAPHIC},
|
|
{"oleobjecttracking", ContentTypeId::OLE},
|
|
{"bookmarktracking", ContentTypeId::BOOKMARK},
|
|
{"sectiontracking", ContentTypeId::REGION},
|
|
{"hyperlinktracking", ContentTypeId::URLFIELD},
|
|
{"referencetracking", ContentTypeId::REFERENCE},
|
|
{"indextracking", ContentTypeId::INDEX},
|
|
{"commenttracking", ContentTypeId::POSTIT},
|
|
{"drawingobjecttracking", ContentTypeId::DRAWOBJECT},
|
|
{"fieldtracking", ContentTypeId::TEXTFIELD},
|
|
{"footnotetracking", ContentTypeId::FOOTNOTE},
|
|
{"endnotetracking", ContentTypeId::ENDNOTE}
|
|
};
|
|
|
|
if (mPopupEntryToContentTypeId.count(rSelectedPopupEntry))
|
|
{
|
|
ContentTypeId eCntTypeId = mPopupEntryToContentTypeId[rSelectedPopupEntry];
|
|
SetContentTypeTracking(eCntTypeId, !mTrackContentType[eCntTypeId]);
|
|
return;
|
|
}
|
|
}
|
|
|
|
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 ...
|
|
|
|
if (rSelectedPopupEntry == "deletealltables" || rSelectedPopupEntry == "deleteallframes"
|
|
|| rSelectedPopupEntry == "deleteallimages" || rSelectedPopupEntry == "deletealloleobjects"
|
|
|| rSelectedPopupEntry == "deleteallbookmarks" || rSelectedPopupEntry == "deleteallregions"
|
|
|| rSelectedPopupEntry == "deleteallhyperlinks"
|
|
|| rSelectedPopupEntry == "deleteallreferences" || rSelectedPopupEntry == "deleteallindexes"
|
|
|| rSelectedPopupEntry == "deleteallcomments"
|
|
|| rSelectedPopupEntry == "deletealldrawingobjects"
|
|
|| rSelectedPopupEntry == "deleteallfields" || rSelectedPopupEntry == "deleteallfootnotes"
|
|
|| rSelectedPopupEntry == "deleteallendnotes")
|
|
{
|
|
DeleteAllContentOfEntryContentType(*xFirst);
|
|
return;
|
|
}
|
|
|
|
if (rSelectedPopupEntry == "protectsection" || rSelectedPopupEntry == "hidesection")
|
|
{
|
|
SwRegionContent* pCnt = weld::fromId<SwRegionContent*>(m_xTreeView->get_id(*xFirst));
|
|
assert(dynamic_cast<SwRegionContent*>(static_cast<SwTypeNumber*>(pCnt)));
|
|
const SwSectionFormat* pSectionFormat = pCnt->GetSectionFormat();
|
|
SwSection* pSection = pSectionFormat->GetSection();
|
|
SwSectionData aSectionData(*pSection);
|
|
if (rSelectedPopupEntry == "protectsection")
|
|
aSectionData.SetProtectFlag(!pSection->IsProtect());
|
|
else
|
|
aSectionData.SetHidden(!pSection->IsHidden());
|
|
m_pActiveShell->UpdateSection(m_pActiveShell->GetSectionFormatPos(*pSectionFormat),
|
|
aSectionData);
|
|
}
|
|
else if (rSelectedPopupEntry == "sort")
|
|
{
|
|
SwContentType* pCntType;
|
|
const OUString aId(m_xTreeView->get_id(*xFirst));
|
|
if (lcl_IsContentType(*xFirst, *m_xTreeView))
|
|
pCntType = weld::fromId<SwContentType*>(aId);
|
|
else
|
|
pCntType = const_cast<SwContentType*>(weld::fromId<SwContent*>(aId)->GetParent());
|
|
|
|
// toggle and persist alphabetical sort setting
|
|
|
|
// 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);
|
|
|
|
pCntType->FillMemberList();
|
|
Display(true);
|
|
return;
|
|
}
|
|
else if (rSelectedPopupEntry == "deletechapter" ||
|
|
rSelectedPopupEntry == "deletetable" ||
|
|
rSelectedPopupEntry == "deleteframe" ||
|
|
rSelectedPopupEntry == "deleteimage" ||
|
|
rSelectedPopupEntry == "deleteoleobject" ||
|
|
rSelectedPopupEntry == "deletebookmark" ||
|
|
rSelectedPopupEntry == "deleteregion" ||
|
|
rSelectedPopupEntry == "deletehyperlink" ||
|
|
rSelectedPopupEntry == "deletereference" ||
|
|
rSelectedPopupEntry == "deleteindex" ||
|
|
rSelectedPopupEntry == "deletecomment" ||
|
|
rSelectedPopupEntry == "deletedrawingobject" ||
|
|
rSelectedPopupEntry == "deletefield" ||
|
|
rSelectedPopupEntry == "deletefootnote" ||
|
|
rSelectedPopupEntry == "deleteendnote")
|
|
{
|
|
EditEntry(*xFirst, EditEntryMode::DELETE);
|
|
return;
|
|
}
|
|
|
|
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(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();
|
|
|
|
SwRewriter aRewriter;
|
|
aRewriter.AddRule(UndoArg1, SwResId(STR_CHAPTERS, nChapters));
|
|
m_pActiveShell->StartUndo(SwUndoId::DELETE, &aRewriter);
|
|
m_pActiveShell->Delete(false);
|
|
m_pActiveShell->EndUndo();
|
|
|
|
m_pActiveShell->EndAction();
|
|
}
|
|
|
|
void SwContentTree::SetOutlineLevel(sal_uInt8 nSet)
|
|
{
|
|
if (nSet == m_nOutlineLevel)
|
|
return;
|
|
m_nOutlineLevel = nSet;
|
|
m_pConfig->SetOutlineLevel( m_nOutlineLevel );
|
|
std::unique_ptr<SwContentType>& rpContentT = (State::ACTIVE == m_eState)
|
|
? m_aActiveContentArr[ContentTypeId::OUTLINE]
|
|
: m_aHiddenContentArr[ContentTypeId::OUTLINE];
|
|
if(rpContentT)
|
|
{
|
|
rpContentT->SetOutlineLevel(m_nOutlineLevel);
|
|
rpContentT->FillMemberList();
|
|
}
|
|
Display(State::ACTIVE == m_eState);
|
|
}
|
|
|
|
void SwContentTree::SetOutlineTracking(sal_uInt8 nSet)
|
|
{
|
|
m_nOutlineTracking = nSet;
|
|
m_pConfig->SetOutlineTracking(m_nOutlineTracking);
|
|
}
|
|
|
|
void SwContentTree::SetContentTypeTracking(ContentTypeId eCntTypeId, bool bSet)
|
|
{
|
|
mTrackContentType[eCntTypeId] = bSet;
|
|
m_pConfig->SetContentTypeTrack(eCntTypeId, bSet);
|
|
}
|
|
|
|
// Mode Change: Show dropped Doc
|
|
void SwContentTree::ShowHiddenShell()
|
|
{
|
|
if(m_pHiddenShell)
|
|
{
|
|
m_eState = State::HIDDEN;
|
|
Display(false);
|
|
}
|
|
}
|
|
|
|
// 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));
|
|
}
|
|
|
|
void SwContentTree::UpdateContentFunctionsToolbar()
|
|
{
|
|
SwNavigationPI* pNavi = GetParentWindow();
|
|
if (pNavi)
|
|
pNavi->UpdateContentFunctionsToolbar();
|
|
}
|
|
|
|
void SwContentTree::SetRootType(ContentTypeId nType)
|
|
{
|
|
m_nRootType = nType;
|
|
m_bIsRoot = true;
|
|
m_pConfig->SetRootType( m_nRootType );
|
|
}
|
|
|
|
OUString SwContentType::RemoveNewline(const OUString& rEntry)
|
|
{
|
|
if (rEntry.isEmpty())
|
|
return rEntry;
|
|
|
|
OUStringBuffer aEntry(rEntry);
|
|
for (sal_Int32 i = 0; i < rEntry.getLength(); ++i)
|
|
if(aEntry[i] == 10 || aEntry[i] == 13)
|
|
aEntry[i] = 0x20;
|
|
|
|
return aEntry.makeStringAndClear();
|
|
}
|
|
|
|
void SwContentTree::EditEntry(const weld::TreeIter& rEntry, EditEntryMode nMode)
|
|
{
|
|
SwContent* pCnt = weld::fromId<SwContent*>(m_xTreeView->get_id(rEntry));
|
|
GotoContent(pCnt);
|
|
const ContentTypeId nType = pCnt->GetParent()->GetType();
|
|
sal_uInt16 nSlot = 0;
|
|
|
|
if(EditEntryMode::DELETE == nMode)
|
|
m_bIgnoreDocChange = true;
|
|
|
|
uno::Reference< container::XNameAccess > xNameAccess, xSecond, xThird;
|
|
switch(nType)
|
|
{
|
|
case ContentTypeId::OUTLINE :
|
|
if(nMode == EditEntryMode::DELETE)
|
|
{
|
|
DeleteOutlineSelections();
|
|
}
|
|
break;
|
|
|
|
case ContentTypeId::TABLE :
|
|
if(nMode == EditEntryMode::UNPROTECT_TABLE)
|
|
{
|
|
m_pActiveShell->GetView().GetDocShell()->
|
|
GetDoc()->UnProtectCells( pCnt->GetName());
|
|
}
|
|
else if(nMode == EditEntryMode::DELETE)
|
|
{
|
|
nSlot = FN_TABLE_DELETE_TABLE;
|
|
}
|
|
else if(nMode == EditEntryMode::RENAME)
|
|
{
|
|
rtl::Reference< SwXTextDocument > xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
|
|
xNameAccess = xModel->getTextTables();
|
|
}
|
|
else
|
|
nSlot = FN_FORMAT_TABLE_DLG;
|
|
break;
|
|
|
|
case ContentTypeId::GRAPHIC :
|
|
if(nMode == EditEntryMode::DELETE)
|
|
{
|
|
m_pActiveShell->DelRight();
|
|
}
|
|
else if(nMode == EditEntryMode::RENAME)
|
|
{
|
|
rtl::Reference< SwXTextDocument > xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
|
|
xNameAccess = xModel->getGraphicObjects();
|
|
xSecond = xModel->getTextFrames();
|
|
xThird = xModel->getEmbeddedObjects();
|
|
}
|
|
else
|
|
nSlot = FN_FORMAT_GRAFIC_DLG;
|
|
break;
|
|
|
|
case ContentTypeId::FRAME :
|
|
case ContentTypeId::OLE :
|
|
if(nMode == EditEntryMode::DELETE)
|
|
{
|
|
m_pActiveShell->DelRight();
|
|
}
|
|
else if(nMode == EditEntryMode::RENAME)
|
|
{
|
|
rtl::Reference< SwXTextDocument > xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
|
|
if(ContentTypeId::FRAME == nType)
|
|
{
|
|
xNameAccess = xModel->getTextFrames();
|
|
xSecond = xModel->getEmbeddedObjects();
|
|
}
|
|
else
|
|
{
|
|
xNameAccess = xModel->getEmbeddedObjects();
|
|
xSecond = xModel->getTextFrames();
|
|
}
|
|
xThird = xModel->getGraphicObjects();
|
|
}
|
|
else
|
|
nSlot = FN_FORMAT_FRAME_DLG;
|
|
break;
|
|
case ContentTypeId::BOOKMARK :
|
|
if(nMode == EditEntryMode::DELETE)
|
|
{
|
|
assert(!m_pActiveShell->getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_BOOKMARKS));
|
|
IDocumentMarkAccess* const pMarkAccess = m_pActiveShell->getIDocumentMarkAccess();
|
|
pMarkAccess->deleteMark(pMarkAccess->findMark(pCnt->GetName()), false);
|
|
}
|
|
else if(nMode == EditEntryMode::RENAME)
|
|
{
|
|
assert(!m_pActiveShell->getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_BOOKMARKS));
|
|
rtl::Reference< SwXTextDocument > xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
|
|
xNameAccess = xModel->getBookmarks();
|
|
}
|
|
else
|
|
{
|
|
// allowed despite PROTECT_BOOKMARKS: the dialog itself enforces it
|
|
SfxStringItem const name(FN_EDIT_BOOKMARK, pCnt->GetName());
|
|
SfxPoolItem const* args[2] = { &name, nullptr };
|
|
m_pActiveShell->GetView().GetViewFrame().
|
|
GetDispatcher()->Execute(FN_EDIT_BOOKMARK, SfxCallMode::SYNCHRON, args);
|
|
}
|
|
break;
|
|
|
|
case ContentTypeId::REGION :
|
|
if (nMode == EditEntryMode::DELETE)
|
|
{
|
|
assert(dynamic_cast<SwRegionContent*>(static_cast<SwTypeNumber*>(pCnt)));
|
|
const SwSectionFormat* pSectionFormat
|
|
= static_cast<SwRegionContent*>(pCnt)->GetSectionFormat();
|
|
m_pActiveShell->GetDoc()->DelSectionFormat(
|
|
const_cast<SwSectionFormat*>(pSectionFormat), false);
|
|
}
|
|
else if (nMode == EditEntryMode::RENAME)
|
|
{
|
|
rtl::Reference< SwXTextDocument > xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
|
|
xNameAccess = xModel->getTextSections();
|
|
}
|
|
else
|
|
nSlot = FN_EDIT_REGION;
|
|
break;
|
|
|
|
case ContentTypeId::URLFIELD:
|
|
if (nMode == EditEntryMode::DELETE)
|
|
nSlot = SID_REMOVE_HYPERLINK;
|
|
else
|
|
nSlot = SID_EDIT_HYPERLINK;
|
|
break;
|
|
case ContentTypeId::REFERENCE:
|
|
{
|
|
if(nMode == EditEntryMode::DELETE)
|
|
{
|
|
const OUString& rName = pCnt->GetName();
|
|
m_pActiveShell->GetDoc()->ForEachRefMark(
|
|
[&rName, this] (const SwFormatRefMark& rFormatRefMark) -> bool
|
|
{
|
|
const SwTextRefMark* pTextRef = rFormatRefMark.GetTextRefMark();
|
|
if (pTextRef && rName == rFormatRefMark.GetRefName())
|
|
{
|
|
m_pActiveShell->GetDoc()->DeleteFormatRefMark(&rFormatRefMark);
|
|
m_pActiveShell->SwViewShell::UpdateFields();
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
}
|
|
break;
|
|
case ContentTypeId::TEXTFIELD:
|
|
{
|
|
if (nMode == EditEntryMode::DELETE)
|
|
{
|
|
const SwTextFieldContent* pTextFieldCnt =
|
|
static_cast<const SwTextFieldContent*>(pCnt);
|
|
const SwTextField* pTextField = pTextFieldCnt->GetFormatField()->GetTextField();
|
|
SwTextField::DeleteTextField(*pTextField);
|
|
}
|
|
else
|
|
nSlot = FN_EDIT_FIELD;
|
|
}
|
|
break;
|
|
case ContentTypeId::POSTIT:
|
|
{
|
|
auto& rView = m_pActiveShell->GetView();
|
|
auto pPostItMgr = rView.GetPostItMgr();
|
|
pPostItMgr->AssureStdModeAtShell();
|
|
pPostItMgr->SetActiveSidebarWin(nullptr);
|
|
rView.GetEditWin().GrabFocus();
|
|
if(nMode == EditEntryMode::DELETE)
|
|
m_pActiveShell->DelRight();
|
|
else
|
|
nSlot = FN_POSTIT;
|
|
}
|
|
break;
|
|
case ContentTypeId::INDEX:
|
|
{
|
|
const SwTOXBase* pBase = static_cast<SwTOXBaseContent*>(pCnt)->GetTOXBase();
|
|
switch(nMode)
|
|
{
|
|
case EditEntryMode::EDIT:
|
|
if(pBase)
|
|
{
|
|
SwPtrItem aPtrItem( FN_INSERT_MULTI_TOX, const_cast<SwTOXBase *>(pBase));
|
|
m_pActiveShell->GetView().GetViewFrame().
|
|
GetDispatcher()->ExecuteList(FN_INSERT_MULTI_TOX,
|
|
SfxCallMode::ASYNCHRON, { &aPtrItem });
|
|
|
|
}
|
|
break;
|
|
case EditEntryMode::DELETE:
|
|
{
|
|
if( pBase )
|
|
m_pActiveShell->DeleteTOX(*pBase, EditEntryMode::DELETE == nMode);
|
|
}
|
|
break;
|
|
case EditEntryMode::UPD_IDX:
|
|
case EditEntryMode::RENAME:
|
|
{
|
|
rtl::Reference< SwXTextDocument > xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
|
|
Reference< XIndexAccess> xIdxAcc(xModel->getDocumentIndexes());
|
|
Reference< XNameAccess >xLocalNameAccess(xIdxAcc, UNO_QUERY);
|
|
if(EditEntryMode::RENAME == nMode)
|
|
xNameAccess = std::move(xLocalNameAccess);
|
|
else if(xLocalNameAccess.is() && xLocalNameAccess->hasByName(pBase->GetTOXName()))
|
|
{
|
|
Any aIdx = xLocalNameAccess->getByName(pBase->GetTOXName());
|
|
Reference< XDocumentIndex> xIdx;
|
|
if(aIdx >>= xIdx)
|
|
xIdx->update();
|
|
}
|
|
}
|
|
break;
|
|
default: break;
|
|
}
|
|
}
|
|
break;
|
|
case ContentTypeId::DRAWOBJECT :
|
|
if(EditEntryMode::DELETE == nMode)
|
|
nSlot = SID_DELETE;
|
|
else if(nMode == EditEntryMode::RENAME)
|
|
nSlot = FN_NAME_SHAPE;
|
|
else if (nMode == EditEntryMode::EDIT)
|
|
{
|
|
vcl::KeyCode aKeyCode(KEY_RETURN, false, false, false, false);
|
|
KeyEvent aKeyEvent(0, aKeyCode);
|
|
m_pActiveShell->GetWin()->KeyInput(aKeyEvent);
|
|
}
|
|
break;
|
|
case ContentTypeId::FOOTNOTE:
|
|
case ContentTypeId::ENDNOTE:
|
|
{
|
|
if (nMode == EditEntryMode::DELETE)
|
|
m_pActiveShell->DelRight();
|
|
else if (EditEntryMode::EDIT == nMode)
|
|
nSlot = FN_FORMAT_FOOTNOTE_DLG;
|
|
}
|
|
break;
|
|
default: break;
|
|
}
|
|
if(nSlot)
|
|
m_pActiveShell->GetView().GetViewFrame().
|
|
GetDispatcher()->Execute(nSlot, SfxCallMode::SYNCHRON);
|
|
else if(xNameAccess.is())
|
|
{
|
|
uno::Any aObj = xNameAccess->getByName(pCnt->GetName());
|
|
uno::Reference< uno::XInterface > xTmp;
|
|
aObj >>= xTmp;
|
|
uno::Reference< container::XNamed > xNamed(xTmp, uno::UNO_QUERY);
|
|
SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
|
|
ScopedVclPtr<AbstractSwRenameXNamedDlg> pDlg(pFact->CreateSwRenameXNamedDlg(m_xTreeView.get(), xNamed, xNameAccess));
|
|
if(xSecond.is())
|
|
pDlg->SetAlternativeAccess( xSecond, xThird);
|
|
|
|
OUString sForbiddenChars;
|
|
if(ContentTypeId::BOOKMARK == nType)
|
|
{
|
|
sForbiddenChars = "/\\@:*?\";,.#";
|
|
}
|
|
else if(ContentTypeId::TABLE == nType)
|
|
{
|
|
sForbiddenChars = " .<>";
|
|
}
|
|
pDlg->SetForbiddenChars(sForbiddenChars);
|
|
pDlg->Execute();
|
|
}
|
|
if(EditEntryMode::DELETE == nMode)
|
|
{
|
|
auto nPos = m_xTreeView->vadjustment_get_value();
|
|
m_bViewHasChanged = true;
|
|
TimerUpdate(&m_aUpdTimer);
|
|
grab_focus();
|
|
m_xTreeView->vadjustment_set_value(nPos);
|
|
}
|
|
}
|
|
|
|
bool SwContentTree::IsDeletable(const weld::TreeIter& rEntry)
|
|
{
|
|
if (lcl_IsContentType(rEntry, *m_xTreeView))
|
|
{
|
|
if (State::HIDDEN == m_eState || !m_pActiveShell)
|
|
return false;
|
|
if (m_pActiveShell->GetView().GetDocShell()->IsReadOnly())
|
|
return false;
|
|
SwContentType* pContentType
|
|
= weld::fromId<SwContentType*>(m_xTreeView->get_id(rEntry));
|
|
auto nCount = pContentType->GetMemberCount();
|
|
if (nCount == 0)
|
|
return false;
|
|
for (size_t i = 0; i < nCount; i++)
|
|
{
|
|
const SwContent* pContent = pContentType->GetMember(i);
|
|
if (IsDeletable(pContent))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
return IsDeletable(weld::fromId<SwContent*>(m_xTreeView->get_id(rEntry)));
|
|
}
|
|
|
|
bool SwContentTree::IsDeletable(const SwContent* pContent)
|
|
{
|
|
if (State::HIDDEN == m_eState || !m_pActiveShell)
|
|
return false;
|
|
if (m_pActiveShell->GetView().GetDocShell()->IsReadOnly())
|
|
return false;
|
|
if (pContent->IsInvisible() || pContent->IsProtect())
|
|
return false;
|
|
|
|
ContentTypeId eContentTypeId = pContent->GetParent()->GetType();
|
|
|
|
// table
|
|
if (eContentTypeId == ContentTypeId::TABLE)
|
|
{
|
|
bool bFull = false;
|
|
m_pActiveShell->HasTableAnyProtection(&pContent->GetName(), &bFull);
|
|
return !bFull;
|
|
}
|
|
// bookmark
|
|
if (eContentTypeId == ContentTypeId::BOOKMARK)
|
|
return !m_pActiveShell->getIDocumentSettingAccess().get(
|
|
DocumentSettingId::PROTECT_BOOKMARKS);
|
|
// index
|
|
if (eContentTypeId == ContentTypeId::INDEX)
|
|
{
|
|
const SwTOXBase* pBase = static_cast<const SwTOXBaseContent*>(pContent)->GetTOXBase();
|
|
return !SwEditShell::IsTOXBaseReadonly(*pBase);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void SwContentTree::DeleteAllContentOfEntryContentType(const weld::TreeIter& rEntry)
|
|
{
|
|
weld::WaitObject aWait(m_xTreeView.get());
|
|
|
|
SwContentType* pContentType;
|
|
if (lcl_IsContentType(rEntry, *m_xTreeView))
|
|
{
|
|
assert(dynamic_cast<SwContentType*>(weld::fromId<SwTypeNumber*>(m_xTreeView->get_id(rEntry))));
|
|
pContentType = weld::fromId<SwContentType*>(m_xTreeView->get_id(rEntry));
|
|
}
|
|
else
|
|
{
|
|
assert(dynamic_cast<SwContent*>(weld::fromId<SwTypeNumber*>(m_xTreeView->get_id(rEntry))));
|
|
pContentType = const_cast<SwContentType*>(
|
|
weld::fromId<SwContent*>(m_xTreeView->get_id(rEntry))->GetParent());
|
|
}
|
|
|
|
const ContentTypeId eContentTypeId = pContentType->GetType();
|
|
if (eContentTypeId == ContentTypeId::TABLE)
|
|
{
|
|
m_pActiveShell->AssureStdMode();
|
|
|
|
const auto nCount = pContentType->GetMemberCount();
|
|
|
|
m_pActiveShell->StartAction();
|
|
SwRewriter aRewriter;
|
|
aRewriter.AddRule(UndoArg1, pContentType->GetName());
|
|
m_pActiveShell->StartUndo(SwUndoId::DELETE, &aRewriter);
|
|
for (size_t i = 0; i < nCount; i++)
|
|
{
|
|
const SwContent* pContent = pContentType->GetMember(i);
|
|
m_pActiveShell->GotoTable(pContent->GetName());
|
|
m_pActiveShell->SelTable();
|
|
m_pActiveShell->DeleteTable();
|
|
}
|
|
m_pActiveShell->EndUndo();
|
|
m_pActiveShell->EndAction();
|
|
}
|
|
else if (eContentTypeId == ContentTypeId::FRAME
|
|
|| eContentTypeId == ContentTypeId::GRAPHIC
|
|
|| eContentTypeId == ContentTypeId::OLE)
|
|
{
|
|
m_pActiveShell->AssureStdMode();
|
|
|
|
const auto nCount = pContentType->GetMemberCount();
|
|
|
|
m_pActiveShell->LockView(true);
|
|
SwRewriter aRewriter;
|
|
aRewriter.AddRule(UndoArg1, pContentType->GetName());
|
|
m_pActiveShell->StartUndo(SwUndoId::DELETE, &aRewriter);
|
|
for (size_t i = 0; i < nCount; i++)
|
|
{
|
|
const OUString& rName(pContentType->GetMember(i)->GetName());
|
|
m_pActiveShell->GotoFly(rName);
|
|
m_pActiveShell->DelRight();
|
|
}
|
|
m_pActiveShell->EndUndo();
|
|
m_pActiveShell->LockView(false);
|
|
}
|
|
else if (eContentTypeId == ContentTypeId::BOOKMARK)
|
|
{
|
|
m_pActiveShell->AssureStdMode();
|
|
|
|
const auto nCount = pContentType->GetMemberCount();
|
|
|
|
IDocumentMarkAccess* const pMarkAccess = m_pActiveShell->getIDocumentMarkAccess();
|
|
|
|
m_pActiveShell->StartAction();
|
|
SwRewriter aRewriter;
|
|
aRewriter.AddRule(UndoArg1, pContentType->GetName());
|
|
m_pActiveShell->StartUndo(SwUndoId::DELETE, &aRewriter);
|
|
for (size_t i = 0; i < nCount; i++)
|
|
{
|
|
const OUString& rName(pContentType->GetMember(i)->GetName());
|
|
pMarkAccess->deleteMark(pMarkAccess->findMark(rName), false);
|
|
}
|
|
m_pActiveShell->EndUndo();
|
|
m_pActiveShell->EndAction();
|
|
}
|
|
else if (eContentTypeId == ContentTypeId::REGION)
|
|
{
|
|
const auto nCount = pContentType->GetMemberCount();
|
|
|
|
m_pActiveShell->StartAction();
|
|
SwRewriter aRewriter;
|
|
aRewriter.AddRule(UndoArg1, pContentType->GetName());
|
|
m_pActiveShell->StartUndo(SwUndoId::DELETE, &aRewriter);
|
|
for (size_t i = 0; i < nCount; i++)
|
|
{
|
|
const SwRegionContent* pRegionContent
|
|
= static_cast<const SwRegionContent*>(pContentType->GetMember(i));
|
|
SwSectionFormat* pSectionFormat
|
|
= const_cast<SwSectionFormat*>(pRegionContent->GetSectionFormat());
|
|
m_pActiveShell->GetDoc()->DelSectionFormat(pSectionFormat, false);
|
|
}
|
|
m_pActiveShell->EndUndo();
|
|
m_pActiveShell->EndAction();
|
|
}
|
|
else if (eContentTypeId == ContentTypeId::URLFIELD) // hyperlinks
|
|
{
|
|
m_pActiveShell->AssureStdMode();
|
|
|
|
const auto nCount = pContentType->GetMemberCount();
|
|
|
|
m_pActiveShell->LockView(true);
|
|
SwRewriter aRewriter;
|
|
aRewriter.AddRule(UndoArg1, pContentType->GetName());
|
|
m_pActiveShell->StartUndo(SwUndoId::DELETE, &aRewriter);
|
|
for (size_t i = 0; i < nCount; i++)
|
|
{
|
|
if (m_pActiveShell->GotoINetAttr(*static_cast<const SwURLFieldContent*>(
|
|
pContentType->GetMember(i))->GetINetAttr()))
|
|
{
|
|
m_pActiveShell->Right(SwCursorSkipMode::Chars, false, 1, false);
|
|
m_pActiveShell->SwCursorShell::SelectTextAttr(RES_TXTATR_INETFMT, true);
|
|
m_pActiveShell->DelRight();
|
|
}
|
|
}
|
|
m_pActiveShell->EndUndo();
|
|
m_pActiveShell->LockView(false);
|
|
}
|
|
else if (eContentTypeId == ContentTypeId::REFERENCE )
|
|
{
|
|
m_pActiveShell->AssureStdMode();
|
|
|
|
const auto nCount = pContentType->GetMemberCount();
|
|
|
|
m_pActiveShell->StartAction();
|
|
SwRewriter aRewriter;
|
|
aRewriter.AddRule(UndoArg1, pContentType->GetName());
|
|
m_pActiveShell->StartUndo(SwUndoId::DELETE, &aRewriter);
|
|
for (size_t i = 0; i < nCount; i++)
|
|
{
|
|
const OUString& rName = pContentType->GetMember(i)->GetName();
|
|
m_pActiveShell->GetDoc()->ForEachRefMark(
|
|
[&rName, this] (const SwFormatRefMark& rFormatRefMark) -> bool
|
|
{
|
|
const SwTextRefMark* pTextRef = rFormatRefMark.GetTextRefMark();
|
|
if (pTextRef && rName == rFormatRefMark.GetRefName())
|
|
{
|
|
m_pActiveShell->GetDoc()->DeleteFormatRefMark(&rFormatRefMark);
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
m_pActiveShell->SwViewShell::UpdateFields();
|
|
m_pActiveShell->EndUndo();
|
|
m_pActiveShell->EndAction();
|
|
}
|
|
else if (eContentTypeId == ContentTypeId::INDEX)
|
|
{
|
|
m_pActiveShell->AssureStdMode();
|
|
|
|
const auto nCount = pContentType->GetMemberCount();
|
|
|
|
m_pActiveShell->StartAction();
|
|
SwRewriter aRewriter;
|
|
aRewriter.AddRule(UndoArg1, pContentType->GetName());
|
|
m_pActiveShell->StartUndo(SwUndoId::DELETE, &aRewriter);
|
|
for (size_t i = 0; i < nCount; i++)
|
|
{
|
|
SwContent* pContent = const_cast<SwContent*>(pContentType->GetMember(i));
|
|
const SwTOXBase* pBase
|
|
= static_cast<SwTOXBaseContent*>(pContent)->GetTOXBase();
|
|
if (pBase)
|
|
m_pActiveShell->DeleteTOX(*pBase, true);
|
|
}
|
|
m_pActiveShell->EndUndo();
|
|
m_pActiveShell->EndAction();
|
|
}
|
|
else if (eContentTypeId == ContentTypeId::POSTIT)
|
|
{
|
|
m_pActiveShell->AssureStdMode();
|
|
|
|
const auto nCount = pContentType->GetMemberCount();
|
|
|
|
m_pActiveShell->StartAction();
|
|
SwRewriter aRewriter;
|
|
aRewriter.AddRule(UndoArg1, pContentType->GetName());
|
|
m_pActiveShell->StartUndo(SwUndoId::DELETE, &aRewriter);
|
|
for (size_t i = 0; i < nCount; i++)
|
|
{
|
|
const SwPostItContent* pPostItContent
|
|
= static_cast<const SwPostItContent*>(pContentType->GetMember(i));
|
|
m_pActiveShell->GotoFormatField(*pPostItContent->GetPostIt());
|
|
m_pActiveShell->DelRight();
|
|
}
|
|
m_pActiveShell->EndUndo();
|
|
m_pActiveShell->EndAction();
|
|
}
|
|
else if (eContentTypeId == ContentTypeId::DRAWOBJECT)
|
|
{
|
|
m_pActiveShell->AssureStdMode();
|
|
|
|
const auto nCount = pContentType->GetMemberCount();
|
|
|
|
m_pActiveShell->StartAction();
|
|
SwRewriter aRewriter;
|
|
aRewriter.AddRule(UndoArg1, pContentType->GetName());
|
|
m_pActiveShell->StartUndo(SwUndoId::DELETE, &aRewriter);
|
|
for (size_t i = 0; i < nCount; i++)
|
|
{
|
|
const OUString& rName(pContentType->GetMember(i)->GetName());
|
|
m_pActiveShell->GotoDrawingObject(rName);
|
|
m_pActiveShell->DelRight();
|
|
//m_pActiveShell->DelSelectedObj();
|
|
}
|
|
m_pActiveShell->EndUndo();
|
|
m_pActiveShell->EndAction();
|
|
}
|
|
else if (eContentTypeId == ContentTypeId::TEXTFIELD)
|
|
{
|
|
m_pActiveShell->AssureStdMode();
|
|
|
|
const auto nCount = pContentType->GetMemberCount();
|
|
|
|
m_pActiveShell->StartAction();
|
|
SwRewriter aRewriter;
|
|
aRewriter.AddRule(UndoArg1, pContentType->GetName());
|
|
m_pActiveShell->StartUndo(SwUndoId::DELETE, &aRewriter);
|
|
for (size_t i = 0; i < nCount; i++)
|
|
{
|
|
const SwTextFieldContent* pTextFieldContent =
|
|
static_cast<const SwTextFieldContent*>(pContentType->GetMember(i));
|
|
const SwTextField* pTextField = pTextFieldContent->GetFormatField()->GetTextField();
|
|
SwTextField::DeleteTextField(*pTextField);
|
|
}
|
|
m_pActiveShell->EndUndo();
|
|
m_pActiveShell->EndAction();
|
|
}
|
|
else if (eContentTypeId == ContentTypeId::FOOTNOTE || eContentTypeId == ContentTypeId::ENDNOTE)
|
|
{
|
|
//MakeAllOutlineContentTemporarilyVisible a(m_pActiveShell->GetDoc());
|
|
lcl_SelectAllFootnotesOrEndnotes(*m_pActiveShell, pContentType);
|
|
SwRewriter aRewriter;
|
|
aRewriter.AddRule(UndoArg1, pContentType->GetName());
|
|
m_pActiveShell->StartUndo(SwUndoId::DELETE, &aRewriter);
|
|
m_pActiveShell->DelRight();
|
|
m_pActiveShell->EndUndo();
|
|
}
|
|
}
|
|
|
|
void SwContentTree::CopyOutlineSelections()
|
|
{
|
|
m_pActiveShell->LockView(true);
|
|
{
|
|
MakeAllOutlineContentTemporarilyVisible a(m_pActiveShell->GetDoc());
|
|
m_pActiveShell->AssureStdMode();
|
|
m_pActiveShell->EnterAddMode();
|
|
size_t nCount = m_xTreeView->get_selected_rows().size();
|
|
m_xTreeView->selected_foreach([this, &nCount](weld::TreeIter& rEntry){
|
|
SwOutlineNodes::size_type nOutlinePos = reinterpret_cast<SwOutlineContent*>(
|
|
m_xTreeView->get_id(rEntry).toInt64())->GetOutlinePos();
|
|
m_pActiveShell->SttSelect();
|
|
m_pActiveShell->MakeOutlineSel(nOutlinePos, nOutlinePos,
|
|
!m_xTreeView->get_row_expanded(rEntry), false);
|
|
// don't move if this is the last selected outline or the cursor is at start of para
|
|
if (--nCount && !m_pActiveShell->IsSttPara())
|
|
m_pActiveShell->Right(SwCursorSkipMode::Chars, true, 1, false);
|
|
m_pActiveShell->EndSelect();
|
|
return false;
|
|
});
|
|
m_pActiveShell->LeaveAddMode();
|
|
m_pActiveShell->GetView().GetViewFrame().GetBindings().Execute(SID_COPY);
|
|
}
|
|
m_pActiveShell->LockView(false);
|
|
}
|
|
|
|
void SwContentTree::GotoContent(const SwContent* pCnt)
|
|
{
|
|
if (pCnt->GetParent()->GetType() == ContentTypeId::OUTLINE)
|
|
{
|
|
// Maybe the outline node doesn't have a layout frame to go to.
|
|
const SwOutlineNodes::size_type nPos =
|
|
static_cast<const SwOutlineContent*>(pCnt)->GetOutlinePos();
|
|
const SwNodes& rNds = m_pActiveShell->GetDoc()->GetNodes();
|
|
SwTextNode* pTextNd = rNds.GetOutLineNds()[nPos]->GetTextNode();
|
|
if (!pTextNd->getLayoutFrame(m_pActiveShell->GetLayout()))
|
|
return;
|
|
}
|
|
|
|
if (m_bSelectTo)
|
|
{
|
|
if (m_pActiveShell->IsCursorInTable() ||
|
|
(m_pActiveShell->GetCursor()->GetPoint()->nNode.GetIndex() <=
|
|
m_pActiveShell->GetDoc()->GetNodes().GetEndOfExtras().GetIndex()))
|
|
{
|
|
m_bSelectTo = false;
|
|
m_pActiveShell->GetView().GetEditWin().GrabFocus();
|
|
return;
|
|
}
|
|
}
|
|
|
|
m_nLastGotoContentWasOutlinePos = SwOutlineNodes::npos;
|
|
m_sSelectedItem = "";
|
|
|
|
m_pActiveShell->AssureStdMode();
|
|
|
|
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(pCnt->GetName());
|
|
}
|
|
break;
|
|
case ContentTypeId::FRAME :
|
|
case ContentTypeId::GRAPHIC :
|
|
case ContentTypeId::OLE :
|
|
{
|
|
m_pActiveShell->GotoFly(pCnt->GetName());
|
|
}
|
|
break;
|
|
case ContentTypeId::BOOKMARK:
|
|
{
|
|
m_pActiveShell->StartAction();
|
|
m_pActiveShell->GotoMark(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(pCnt->GetName());
|
|
}
|
|
break;
|
|
case ContentTypeId::INDEX:
|
|
{
|
|
const OUString& sName(pCnt->GetName());
|
|
if (!m_pActiveShell->GotoNextTOXBase(&sName))
|
|
m_pActiveShell->GotoPrevTOXBase(&sName);
|
|
}
|
|
break;
|
|
case ContentTypeId::POSTIT:
|
|
m_pActiveShell->GotoFormatField(*static_cast<const SwPostItContent*>(pCnt)->GetPostIt());
|
|
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();
|
|
|
|
m_pActiveShell->AssureStdMode();
|
|
|
|
m_pActiveShell->SetMark();
|
|
m_pActiveShell->GetCursor()->GetMark()->nNode = oPosition->nNode;
|
|
m_pActiveShell->GetCursor()->GetMark()->nContent = oPosition->nContent;
|
|
m_pActiveShell->UpdateCursor();
|
|
|
|
m_pActiveShell->GetView().GetEditWin().GrabFocus();
|
|
|
|
m_bSelectTo = false;
|
|
}
|
|
else
|
|
{
|
|
if (m_pActiveShell->IsFrameSelected() || m_pActiveShell->IsObjSelected())
|
|
{
|
|
m_pActiveShell->HideCursor();
|
|
m_pActiveShell->EnterSelFrameMode();
|
|
}
|
|
|
|
SwView& rView = m_pActiveShell->GetView();
|
|
rView.StopShellTimer();
|
|
rView.GetPostItMgr()->SetActiveSidebarWin(nullptr);
|
|
rView.GetEditWin().GrabFocus();
|
|
|
|
// 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->IsObjSelected()))
|
|
{
|
|
Point aPoint(rView.GetVisArea().getX(), m_pActiveShell->GetCursorDocPos().getY());
|
|
rView.SetVisArea(aPoint);
|
|
}
|
|
}
|
|
|
|
UpdateContentFunctionsToolbar();
|
|
}
|
|
|
|
NaviContentBookmark::NaviContentBookmark() :
|
|
m_nDocSh(0)
|
|
{
|
|
}
|
|
|
|
NaviContentBookmark::NaviContentBookmark(OUString sURL, OUString sCrossRef, OUString aDesc,
|
|
const SwDocShell* pDocSh) :
|
|
m_sURL(std::move(sURL)),
|
|
m_sCrossRef(std::move(sCrossRef)),
|
|
m_aDescription(std::move(aDesc)),
|
|
m_nDocSh(reinterpret_cast<sal_IntPtr>(pDocSh))
|
|
{
|
|
}
|
|
|
|
void NaviContentBookmark::Copy( TransferDataContainer& rData ) const
|
|
{
|
|
rtl_TextEncoding eSysCSet = osl_getThreadTextEncoding();
|
|
OString sStrBuf(OUStringToOString(m_sURL, eSysCSet) + OStringChar(NAVI_BOOKMARK_DELIM) +
|
|
OUStringToOString(m_sCrossRef, eSysCSet) + OStringChar(NAVI_BOOKMARK_DELIM) +
|
|
OUStringToOString(m_aDescription, eSysCSet) + OStringChar(NAVI_BOOKMARK_DELIM) +
|
|
OString::number(m_nDocSh));
|
|
rData.CopyByteString(SotClipboardFormatId::SONLK, sStrBuf);
|
|
}
|
|
|
|
bool NaviContentBookmark::Paste( const TransferableDataHelper& rData, const OUString& rsDesc )
|
|
{
|
|
OUString sStr;
|
|
bool bRet = rData.GetString( SotClipboardFormatId::SONLK, sStr );
|
|
if( bRet )
|
|
{
|
|
sal_Int32 nPos = 0;
|
|
m_sURL = sStr.getToken(0, NAVI_BOOKMARK_DELIM, nPos );
|
|
m_sCrossRef = sStr.getToken(0, NAVI_BOOKMARK_DELIM, nPos);
|
|
m_aDescription = sStr.getToken(0, NAVI_BOOKMARK_DELIM, nPos );
|
|
m_nDocSh = o3tl::toInt32(o3tl::getToken(sStr, 0, NAVI_BOOKMARK_DELIM, nPos ));
|
|
if (!rsDesc.isEmpty())
|
|
m_aDescription = rsDesc;
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
SwNavigationPI* SwContentTree::GetParentWindow()
|
|
{
|
|
return m_pDialog;
|
|
}
|
|
|
|
void SwContentTree::SelectContentType(std::u16string_view rContentTypeName)
|
|
{
|
|
std::unique_ptr<weld::TreeIter> xIter(m_xTreeView->make_iterator());
|
|
if (!m_xTreeView->get_iter_first(*xIter))
|
|
return;
|
|
do
|
|
{
|
|
if (m_xTreeView->get_text(*xIter) == rContentTypeName)
|
|
{
|
|
m_xTreeView->set_cursor(*xIter);
|
|
UpdateContentFunctionsToolbar();
|
|
break;
|
|
}
|
|
} while (m_xTreeView->iter_next_sibling(*xIter));
|
|
}
|
|
|
|
IMPL_LINK_NOARG(SwContentTree, OverlayObjectDelayTimerHdl, Timer *, void)
|
|
{
|
|
m_aOverlayObjectDelayTimer.Stop();
|
|
if (m_xOverlayObject)
|
|
{
|
|
if (SdrView* pView = m_pActiveShell->GetDrawView())
|
|
{
|
|
if (SdrPaintWindow* pPaintWindow = pView->GetPaintWindow(0))
|
|
{
|
|
const rtl::Reference<sdr::overlay::OverlayManager>& xOverlayManager =
|
|
pPaintWindow->GetOverlayManager();
|
|
xOverlayManager->add(*m_xOverlayObject);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SwContentTree::OverlayObject(std::vector<basegfx::B2DRange>&& aRanges)
|
|
{
|
|
m_aOverlayObjectDelayTimer.Stop();
|
|
if (m_xOverlayObject && m_xOverlayObject->getOverlayManager())
|
|
m_xOverlayObject->getOverlayManager()->remove(*m_xOverlayObject);
|
|
if (aRanges.empty())
|
|
m_xOverlayObject.reset();
|
|
else
|
|
{
|
|
m_xOverlayObject.reset(new sdr::overlay::OverlaySelection(
|
|
sdr::overlay::OverlayType::Invert,
|
|
Color(), std::move(aRanges), true/*unused for Invert type*/));
|
|
m_aOverlayObjectDelayTimer.Start();
|
|
}
|
|
}
|
|
|
|
void SwContentTree::BringEntryToAttention(const weld::TreeIter& rEntry)
|
|
{
|
|
if (lcl_IsContent(rEntry, *m_xTreeView)) // content entry
|
|
{
|
|
SwContent* pCnt = weld::fromId<SwContent*>(m_xTreeView->get_id(rEntry));
|
|
if (pCnt->IsInvisible())
|
|
OverlayObject();
|
|
else
|
|
{
|
|
const ContentTypeId nType = pCnt->GetParent()->GetType();
|
|
if (nType == ContentTypeId::OUTLINE)
|
|
{
|
|
BringTypesWithFlowFramesToAttention({m_pActiveShell->GetNodes().
|
|
GetOutLineNds()[static_cast<SwOutlineContent*>(pCnt)->GetOutlinePos()]},
|
|
/*bIncludeTopMargin*/ false);
|
|
}
|
|
else if (nType == ContentTypeId::TABLE)
|
|
{
|
|
if (const sw::TableFrameFormats* pFrameFormats = m_pActiveShell->GetDoc()->GetTableFrameFormats())
|
|
if (const SwTableFormat* pFrameFormat = pFrameFormats->FindFrameFormatByName(pCnt->GetName()))
|
|
{
|
|
SwTable* pTable = SwTable::FindTable(pFrameFormat);
|
|
if (pTable)
|
|
BringTypesWithFlowFramesToAttention({pTable->GetTableNode()}, false);
|
|
}
|
|
}
|
|
else if (nType == ContentTypeId::FRAME || nType == ContentTypeId::GRAPHIC ||
|
|
nType == ContentTypeId::OLE)
|
|
{
|
|
SwNodeType eNodeType = SwNodeType::Text;
|
|
if(nType == ContentTypeId::GRAPHIC)
|
|
eNodeType = SwNodeType::Grf;
|
|
else if(nType == ContentTypeId::OLE)
|
|
eNodeType = SwNodeType::Ole;
|
|
if (const SwFrameFormat* pFrameFormat =
|
|
m_pActiveShell->GetDoc()->FindFlyByName(pCnt->GetName(), eNodeType))
|
|
BringFramesToAttention(std::vector<const SwFrameFormat*> {pFrameFormat});
|
|
}
|
|
else if (nType == ContentTypeId::BOOKMARK)
|
|
{
|
|
BringBookmarksToAttention(std::vector<OUString> {pCnt->GetName()});
|
|
}
|
|
else if (nType == ContentTypeId::REGION || nType == ContentTypeId::INDEX)
|
|
{
|
|
size_t nSectionFormatCount = m_pActiveShell->GetSectionFormatCount();
|
|
for (size_t i = 0; i < nSectionFormatCount; ++i)
|
|
{
|
|
const SwSectionFormat& rSectionFormat = m_pActiveShell->GetSectionFormat(i);
|
|
if (!rSectionFormat.IsInNodesArr())
|
|
continue;
|
|
const SwSection* pSection = rSectionFormat.GetSection();
|
|
if (!pSection)
|
|
continue;
|
|
if (pCnt->GetName() == pSection->GetSectionName())
|
|
{
|
|
BringTypesWithFlowFramesToAttention({rSectionFormat.GetSectionNode()});
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (nType == ContentTypeId::URLFIELD)
|
|
{
|
|
// tdf#159147 - Assure the SwURLFieldContent::SwTextINetFormat pointer is valid
|
|
// before bringing to attention.
|
|
const SwTextINetFormat* pTextINetFormat
|
|
= static_cast<SwURLFieldContent*>(pCnt)->GetINetAttr();
|
|
const SwCharFormats* pFormats = m_pActiveShell->GetDoc()->GetCharFormats();
|
|
for (auto n = pFormats->size(); 1 < n;)
|
|
{
|
|
SwIterator<SwTextINetFormat, SwCharFormat> aIter(*(*pFormats)[--n]);
|
|
for (SwTextINetFormat* pFnd = aIter.First(); pFnd; pFnd = aIter.Next())
|
|
{
|
|
if (pTextINetFormat == pFnd)
|
|
{
|
|
BringURLFieldsToAttention(SwGetINetAttrs {SwGetINetAttr(pCnt->GetName(),
|
|
*pTextINetFormat)});
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (nType == ContentTypeId::REFERENCE)
|
|
{
|
|
if (const SwTextAttr* pTextAttr =
|
|
m_pActiveShell->GetDoc()->GetRefMark(pCnt->GetName())->GetTextRefMark())
|
|
{
|
|
std::vector<const SwTextAttr*> aTextAttrArr {pTextAttr};
|
|
BringReferencesToAttention(aTextAttrArr);
|
|
}
|
|
}
|
|
else if (nType == ContentTypeId::POSTIT)
|
|
{
|
|
if (const SwTextAttr* pTextAttr =
|
|
static_cast<SwPostItContent*>(pCnt)->GetPostIt()->GetTextField())
|
|
{
|
|
std::vector<const SwTextAttr*> aTextAttrArr {pTextAttr};
|
|
BringPostItFieldsToAttention(aTextAttrArr);
|
|
}
|
|
}
|
|
else if (nType == ContentTypeId::DRAWOBJECT)
|
|
{
|
|
std::vector<const SdrObject*> aSdrObjectArr {GetDrawingObjectsByContent(pCnt)};
|
|
BringDrawingObjectsToAttention(aSdrObjectArr);
|
|
}
|
|
else if (nType == ContentTypeId::TEXTFIELD)
|
|
{
|
|
if (const SwTextAttr* pTextAttr =
|
|
static_cast<SwTextFieldContent*>(pCnt)->GetFormatField()->GetTextField())
|
|
{
|
|
std::vector<const SwTextAttr*> aTextAttrArr {pTextAttr};
|
|
BringTextFieldsToAttention(aTextAttrArr);
|
|
}
|
|
}
|
|
else if (nType == ContentTypeId::FOOTNOTE || nType == ContentTypeId::ENDNOTE)
|
|
{
|
|
if (const SwTextAttr* pTextAttr =
|
|
static_cast<SwTextFootnoteContent*> (pCnt)->GetTextFootnote())
|
|
{
|
|
std::vector<const SwTextAttr*> aTextAttrArr {pTextAttr};
|
|
BringFootnotesToAttention(aTextAttrArr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else // content type entry
|
|
{
|
|
SwContentType* pCntType = weld::fromId<SwContentType*>(m_xTreeView->get_id(rEntry));
|
|
if (pCntType->GetMemberCount() == 0)
|
|
OverlayObject();
|
|
else
|
|
{
|
|
const ContentTypeId nType = pCntType->GetType();
|
|
if (nType == ContentTypeId::OUTLINE)
|
|
{
|
|
std::vector<const SwNode*> aNodesArr(
|
|
m_pActiveShell->GetNodes().GetOutLineNds().begin(),
|
|
m_pActiveShell->GetNodes().GetOutLineNds().end());
|
|
BringTypesWithFlowFramesToAttention(aNodesArr, /*bIncludeTopMargin*/ false);
|
|
}
|
|
else if (nType == ContentTypeId::TABLE)
|
|
{
|
|
std::vector<const SwNode*> aNodesArr;
|
|
const size_t nCount = m_pActiveShell->GetTableFrameFormatCount(false);
|
|
const sw::TableFrameFormats& rTableFormats = *m_pActiveShell->GetDoc()->GetTableFrameFormats();
|
|
for(size_t i = 0; i < nCount; ++i)
|
|
{
|
|
if (const SwTableFormat* pTableFormat = rTableFormats[i])
|
|
if(pTableFormat->IsUsed()) // skip deleted tables
|
|
{
|
|
SwTable* pTable = SwTable::FindTable(pTableFormat);
|
|
if (pTable)
|
|
aNodesArr.push_back(pTable->GetTableNode());
|
|
}
|
|
}
|
|
BringTypesWithFlowFramesToAttention(aNodesArr, false);
|
|
}
|
|
else if (nType == ContentTypeId::FRAME || nType == ContentTypeId::GRAPHIC ||
|
|
nType == ContentTypeId::OLE)
|
|
{
|
|
FlyCntType eType = FLYCNTTYPE_FRM;
|
|
if(nType == ContentTypeId::GRAPHIC)
|
|
eType = FLYCNTTYPE_GRF;
|
|
else if(nType == ContentTypeId::OLE)
|
|
eType = FLYCNTTYPE_OLE;
|
|
BringFramesToAttention(m_pActiveShell->GetFlyFrameFormats(eType, true));
|
|
}
|
|
else if (nType == ContentTypeId::BOOKMARK)
|
|
{
|
|
std::vector<OUString> aNames;
|
|
const auto nCount = pCntType->GetMemberCount();
|
|
for (size_t i = 0; i < nCount; i++)
|
|
{
|
|
const SwContent* pMember = pCntType->GetMember(i);
|
|
if (pMember && !pMember->IsInvisible())
|
|
aNames.push_back(pMember->GetName());
|
|
}
|
|
BringBookmarksToAttention(aNames);
|
|
}
|
|
else if (nType == ContentTypeId::REGION || nType == ContentTypeId::INDEX)
|
|
{
|
|
std::vector<const SwNode*> aNodesArr;
|
|
const SwSectionFormats& rFormats = m_pActiveShell->GetDoc()->GetSections();
|
|
const size_t nSize = rFormats.size();
|
|
for (SwSectionFormats::size_type n = nSize; n;)
|
|
{
|
|
const SwSectionFormat* pSectionFormat = rFormats[--n];
|
|
if (pSectionFormat && pSectionFormat->IsInNodesArr())
|
|
{
|
|
const SwSection* pSection = pSectionFormat->GetSection();
|
|
if (pSection && !pSection->IsHiddenFlag())
|
|
{
|
|
const SectionType eSectionType = pSection->GetType();
|
|
if (nType == ContentTypeId::REGION &&
|
|
(eSectionType == SectionType::ToxContent ||
|
|
eSectionType == SectionType::ToxHeader))
|
|
continue;
|
|
if (nType == ContentTypeId::INDEX &&
|
|
eSectionType != SectionType::ToxContent)
|
|
continue;
|
|
if (const SwNode* pNode = pSectionFormat->GetSectionNode())
|
|
aNodesArr.push_back(pNode);
|
|
}
|
|
}
|
|
}
|
|
BringTypesWithFlowFramesToAttention(aNodesArr);
|
|
}
|
|
else if (nType == ContentTypeId::URLFIELD)
|
|
{
|
|
SwGetINetAttrs aINetAttrsArr;
|
|
m_pActiveShell->GetINetAttrs(aINetAttrsArr, false);
|
|
BringURLFieldsToAttention(aINetAttrsArr);
|
|
}
|
|
else if (nType == ContentTypeId::REFERENCE)
|
|
{
|
|
std::vector<const SwTextAttr*> aTextAttrArr;
|
|
m_pActiveShell->GetDoc()->ForEachRefMark(
|
|
[&aTextAttrArr] (const SwFormatRefMark& rRefMark) -> bool
|
|
{
|
|
const SwTextRefMark* pTextRef = rRefMark.GetTextRefMark();
|
|
if (pTextRef)
|
|
aTextAttrArr.push_back(pTextRef);
|
|
return true;
|
|
});
|
|
BringReferencesToAttention(aTextAttrArr);
|
|
}
|
|
else if (nType == ContentTypeId::POSTIT)
|
|
{
|
|
std::vector<const SwTextAttr*> aTextAttrArr;
|
|
const auto nCount = pCntType->GetMemberCount();
|
|
for (size_t i = 0; i < nCount; i++)
|
|
{
|
|
const SwPostItContent* pPostItContent = static_cast<const SwPostItContent*>(
|
|
pCntType->GetMember(i));
|
|
if (pPostItContent && !pPostItContent->IsInvisible())
|
|
if (const SwFormatField* pFormatField = pPostItContent->GetPostIt())
|
|
if (const SwTextAttr* pTextAttr = pFormatField->GetTextField())
|
|
aTextAttrArr.push_back(pTextAttr);
|
|
}
|
|
BringPostItFieldsToAttention(aTextAttrArr);
|
|
}
|
|
else if (nType == ContentTypeId::DRAWOBJECT)
|
|
{
|
|
IDocumentDrawModelAccess& rIDDMA = m_pActiveShell->getIDocumentDrawModelAccess();
|
|
if (const SwDrawModel* pModel = rIDDMA.GetDrawModel())
|
|
{
|
|
if (const SdrPage* pPage = pModel->GetPage(0))
|
|
{
|
|
if (pPage->GetObjCount())
|
|
{
|
|
std::vector<const SdrObject*> aSdrObjectArr;
|
|
for (const rtl::Reference<SdrObject>& pObject : *pPage)
|
|
{
|
|
if (pObject && !pObject->GetName().isEmpty() &&
|
|
rIDDMA.IsVisibleLayerId(pObject->GetLayer()))
|
|
aSdrObjectArr.push_back(pObject.get());
|
|
}
|
|
BringDrawingObjectsToAttention(aSdrObjectArr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (nType == ContentTypeId::TEXTFIELD)
|
|
{
|
|
std::vector<const SwTextAttr*> aTextAttrArr;
|
|
const auto nCount = pCntType->GetMemberCount();
|
|
for (size_t i = 0; i < nCount; i++)
|
|
{
|
|
const SwTextFieldContent* pTextFieldCnt =
|
|
static_cast<const SwTextFieldContent*>(pCntType->GetMember(i));
|
|
if (pTextFieldCnt && !pTextFieldCnt->IsInvisible())
|
|
if (const SwFormatField* pFormatField = pTextFieldCnt->GetFormatField())
|
|
if (const SwTextAttr* pTextAttr = pFormatField->GetTextField())
|
|
aTextAttrArr.push_back(pTextAttr);
|
|
}
|
|
BringTextFieldsToAttention(aTextAttrArr);
|
|
}
|
|
else if (nType == ContentTypeId::FOOTNOTE || nType == ContentTypeId::ENDNOTE)
|
|
{
|
|
std::vector<const SwTextAttr*> aTextAttrArr;
|
|
const auto nCount = pCntType->GetMemberCount();
|
|
for (size_t i = 0; i < nCount; i++)
|
|
{
|
|
const SwTextFootnoteContent* pTextFootnoteCnt =
|
|
static_cast<const SwTextFootnoteContent*>(pCntType->GetMember(i));
|
|
if (pTextFootnoteCnt && !pTextFootnoteCnt->IsInvisible())
|
|
if (const SwTextAttr* pTextAttr = pTextFootnoteCnt->GetTextFootnote())
|
|
aTextAttrArr.push_back(pTextAttr);
|
|
}
|
|
BringFootnotesToAttention(aTextAttrArr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void lcl_CalcOverlayRanges(const SwTextFrame* pStartFrame, const SwTextFrame* pEndFrame,
|
|
const SwPosition& aStartPos, const SwPosition& aEndPos,
|
|
std::vector<basegfx::B2DRange>& aRanges)
|
|
{
|
|
if (pStartFrame && pEndFrame)
|
|
{
|
|
SwRect aStartCharRect;
|
|
pStartFrame->GetCharRect(aStartCharRect, aStartPos);
|
|
SwRect aEndCharRect;
|
|
pEndFrame->GetCharRect(aEndCharRect, aEndPos);
|
|
if (aStartCharRect.Top() == aEndCharRect.Top())
|
|
{
|
|
// single line range
|
|
aRanges.emplace_back(aStartCharRect.Left(), aStartCharRect.Top(),
|
|
aEndCharRect.Right() + 1, aEndCharRect.Bottom() + 1);
|
|
}
|
|
else
|
|
{
|
|
// multi line range
|
|
SwRect aFrameRect = pStartFrame->getFrameArea();
|
|
aRanges.emplace_back(aStartCharRect.Left(), aStartCharRect.Top(),
|
|
aFrameRect.Right(), aStartCharRect.Bottom() + 1);
|
|
if (aStartCharRect.Bottom() + 1 != aEndCharRect.Top())
|
|
aRanges.emplace_back(aFrameRect.Left(), aStartCharRect.Bottom() + 1,
|
|
aFrameRect.Right(), aEndCharRect.Top() + 1);
|
|
aRanges.emplace_back(aFrameRect.Left(), aEndCharRect.Top() + 1,
|
|
aEndCharRect.Right() + 1, aEndCharRect.Bottom() + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SwContentTree::BringFramesToAttention(const std::vector<const SwFrameFormat*>& rFrameFormats)
|
|
{
|
|
std::vector<basegfx::B2DRange> aRanges;
|
|
for (const SwFrameFormat* pFrameFormat : rFrameFormats)
|
|
{
|
|
if (!pFrameFormat)
|
|
continue;
|
|
SwRect aFrameRect = pFrameFormat->FindLayoutRect();
|
|
if (!aFrameRect.IsEmpty())
|
|
aRanges.emplace_back(aFrameRect.Left(), aFrameRect.Top(), aFrameRect.Right(),
|
|
aFrameRect.Bottom());
|
|
}
|
|
OverlayObject(std::move(aRanges));
|
|
}
|
|
|
|
void SwContentTree::BringBookmarksToAttention(const std::vector<OUString>& rNames)
|
|
{
|
|
std::vector<basegfx::B2DRange> aRanges;
|
|
IDocumentMarkAccess* const pMarkAccess = m_pActiveShell->getIDocumentMarkAccess();
|
|
for (const auto& rName : rNames)
|
|
{
|
|
auto ppBkmk = pMarkAccess->findBookmark(rName);
|
|
if (ppBkmk == pMarkAccess->getBookmarksEnd())
|
|
continue;
|
|
SwPosition aMarkStart = (*ppBkmk)->GetMarkStart();
|
|
const SwTextNode* pMarkStartTextNode = aMarkStart.GetNode().GetTextNode();
|
|
if (!pMarkStartTextNode)
|
|
continue;
|
|
const SwTextFrame* pMarkStartFrame = static_cast<const SwTextFrame*>(
|
|
pMarkStartTextNode->getLayoutFrame(m_pActiveShell->GetLayout()));
|
|
if (!pMarkStartFrame)
|
|
continue;
|
|
SwPosition aMarkEnd = (*ppBkmk)->GetMarkEnd();
|
|
const SwTextNode* pMarkEndTextNode = aMarkEnd.GetNode().GetTextNode();
|
|
if (!pMarkEndTextNode)
|
|
continue;
|
|
const SwTextFrame* pMarkEndFrame = static_cast<const SwTextFrame*>(
|
|
pMarkEndTextNode->getLayoutFrame(m_pActiveShell->GetLayout()));
|
|
if (!pMarkEndFrame)
|
|
continue;
|
|
// adjust span when mark start equals mark end
|
|
if (aMarkStart == aMarkEnd)
|
|
{
|
|
if (aMarkEnd.GetContentIndex() < pMarkEndTextNode->Len() - 1)
|
|
aMarkEnd.AdjustContent(+1);
|
|
else if (aMarkStart.GetContentIndex() > 0)
|
|
aMarkStart.AdjustContent(-1);
|
|
}
|
|
lcl_CalcOverlayRanges(pMarkStartFrame, pMarkEndFrame, aMarkStart, aMarkEnd, aRanges);
|
|
}
|
|
OverlayObject(std::move(aRanges));
|
|
}
|
|
|
|
void SwContentTree::BringTypesWithFlowFramesToAttention(const std::vector<const SwNode*>& rNodes,
|
|
const bool bIncludeTopMargin)
|
|
{
|
|
std::vector<basegfx::B2DRange> aRanges;
|
|
for (const auto* pNode : rNodes)
|
|
{
|
|
if (!pNode)
|
|
continue;
|
|
const SwFrame* pFrame;
|
|
if (pNode->IsContentNode() || pNode->IsTableNode())
|
|
{
|
|
if (pNode->IsContentNode())
|
|
pFrame = pNode->GetContentNode()->getLayoutFrame(m_pActiveShell->GetLayout());
|
|
else // table node
|
|
{
|
|
SwNode2Layout aTmp(*pNode, pNode->GetIndex() - 1);
|
|
pFrame = aTmp.NextFrame();
|
|
}
|
|
while (pFrame)
|
|
{
|
|
const SwRect& rFrameRect = pFrame->getFrameArea();
|
|
if (!rFrameRect.IsEmpty())
|
|
aRanges.emplace_back(rFrameRect.Left(), bIncludeTopMargin ? rFrameRect.Top() :
|
|
rFrameRect.Top() + pFrame->GetTopMargin(),
|
|
rFrameRect.Right(), rFrameRect.Bottom());
|
|
if (!pFrame->IsFlowFrame())
|
|
break;
|
|
const SwFlowFrame *pFollow = SwFlowFrame::CastFlowFrame(pFrame)->GetFollow();
|
|
if (!pFollow)
|
|
break;
|
|
pFrame = &pFollow->GetFrame();
|
|
}
|
|
}
|
|
else if (pNode->IsSectionNode())
|
|
{
|
|
const SwNode* pEndOfSectionNode = pNode->EndOfSectionNode();
|
|
SwNodeIndex aIdx(*pNode);
|
|
while (&aIdx.GetNode() != pEndOfSectionNode)
|
|
{
|
|
if (aIdx.GetNode().IsContentNode())
|
|
{
|
|
if ((pFrame = aIdx.GetNode().GetContentNode()->
|
|
getLayoutFrame(m_pActiveShell->GetLayout())))
|
|
{
|
|
if (pFrame->IsInSct())
|
|
pFrame = pFrame->FindSctFrame();
|
|
if (pFrame)
|
|
{
|
|
const SwRect& rFrameRect = pFrame->getFrameArea();
|
|
if (!rFrameRect.IsEmpty())
|
|
aRanges.emplace_back(rFrameRect.Left(), rFrameRect.Top(),
|
|
rFrameRect.Right(), rFrameRect.Bottom());
|
|
}
|
|
}
|
|
++aIdx;
|
|
while (!aIdx.GetNode().IsEndNode() && !aIdx.GetNode().IsSectionNode())
|
|
++aIdx;
|
|
continue;
|
|
}
|
|
if (!aIdx.GetNode().IsSectionNode())
|
|
{
|
|
++aIdx;
|
|
continue;
|
|
}
|
|
SwNode2Layout aTmp(aIdx.GetNode(), aIdx.GetNode().GetIndex() - 1);
|
|
pFrame = aTmp.NextFrame();
|
|
if (pFrame)
|
|
{
|
|
if (!pFrame->getFrameArea().IsEmpty())
|
|
{
|
|
const SwRect& rFrameRect = pFrame->getFrameArea();
|
|
aRanges.emplace_back(rFrameRect.Left(), rFrameRect.Top(),
|
|
rFrameRect.Right(), rFrameRect.Bottom());
|
|
}
|
|
if (pFrame->IsSctFrame())
|
|
{
|
|
const SwSectionFrame* pSectionFrame
|
|
= static_cast<const SwSectionFrame*>(pFrame);
|
|
if (pSectionFrame->HasFollow())
|
|
{
|
|
const SwFlowFrame *pFollow
|
|
= SwFlowFrame::CastFlowFrame(pSectionFrame)->GetFollow();
|
|
while (pFollow)
|
|
{
|
|
pFrame = &pFollow->GetFrame();
|
|
if (!pFrame->getFrameArea().IsEmpty())
|
|
{
|
|
const SwRect& rFrameRect = pFrame->getFrameArea();
|
|
aRanges.emplace_back(rFrameRect.Left(), rFrameRect.Top(),
|
|
rFrameRect.Right(), rFrameRect.Bottom());
|
|
}
|
|
pFollow = SwFlowFrame::CastFlowFrame(pFrame)->GetFollow();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
++aIdx;
|
|
while (!aIdx.GetNode().IsEndNode() && !aIdx.GetNode().IsSectionNode())
|
|
++aIdx;
|
|
}
|
|
// Remove nested sections. This wouldn't be needed if the overlay wasn't invert type.
|
|
auto end = aRanges.end();
|
|
for (auto it = aRanges.begin(); it != end; ++it)
|
|
end = std::remove_if(it + 1, end, [&it](auto itt){ return it->isInside(itt); });
|
|
aRanges.erase(end, aRanges.end());
|
|
}
|
|
}
|
|
OverlayObject(std::move(aRanges));
|
|
}
|
|
|
|
void SwContentTree::BringURLFieldsToAttention(const SwGetINetAttrs& rINetAttrsArr)
|
|
{
|
|
std::vector<basegfx::B2DRange> aRanges;
|
|
for (const auto& r : rINetAttrsArr)
|
|
{
|
|
const SwTextNode& rTextNode = r.rINetAttr.GetTextNode();
|
|
if (SwTextFrame* pFrame = static_cast<SwTextFrame*>(
|
|
rTextNode.getLayoutFrame(m_pActiveShell->GetLayout())))
|
|
{
|
|
auto nStart = r.rINetAttr.GetStart();
|
|
auto nEnd = r.rINetAttr.GetAnyEnd();
|
|
SwPosition aStartPos(rTextNode, nStart), aEndPos(rTextNode, nEnd);
|
|
lcl_CalcOverlayRanges(pFrame, pFrame, aStartPos, aEndPos, aRanges);
|
|
}
|
|
}
|
|
OverlayObject(std::move(aRanges));
|
|
}
|
|
|
|
void SwContentTree::BringReferencesToAttention(std::vector<const SwTextAttr*>& rTextAttrsArr)
|
|
{
|
|
std::vector<basegfx::B2DRange> aRanges;
|
|
for (const SwTextAttr* p : rTextAttrsArr)
|
|
{
|
|
if (!p)
|
|
continue;
|
|
const SwTextRefMark* pTextRefMark = p->GetRefMark().GetTextRefMark();
|
|
if (!pTextRefMark)
|
|
continue;
|
|
const SwTextNode& rTextNode = pTextRefMark->GetTextNode();
|
|
if (SwTextFrame* pFrame = static_cast<SwTextFrame*>(
|
|
rTextNode.getLayoutFrame(m_pActiveShell->GetLayout())))
|
|
{
|
|
auto nStart = p->GetStart();
|
|
auto nEnd = p->GetAnyEnd();
|
|
SwPosition aStartPos(rTextNode, nStart), aEndPos(rTextNode, nEnd);
|
|
lcl_CalcOverlayRanges(pFrame, pFrame, aStartPos, aEndPos, aRanges);
|
|
}
|
|
}
|
|
OverlayObject(std::move(aRanges));
|
|
}
|
|
|
|
void SwContentTree::BringPostItFieldsToAttention(std::vector<const SwTextAttr*>& rTextAttrsArr)
|
|
{
|
|
std::vector<basegfx::B2DRange> aRanges;
|
|
for (const SwTextAttr* p : rTextAttrsArr)
|
|
{
|
|
if (!p)
|
|
continue;
|
|
const SwTextField* pTextField = p->GetFormatField().GetTextField();
|
|
if (!pTextField)
|
|
continue;
|
|
// use as a fallback when there is no mark
|
|
SwTextNode& rTextNode = pTextField->GetTextNode();
|
|
if (!rTextNode.getLayoutFrame(m_pActiveShell->GetLayout()))
|
|
continue;
|
|
assert(dynamic_cast<const SwTextAnnotationField*>(pTextField));
|
|
const SwTextAnnotationField* pTextAnnotationField =
|
|
static_cast<const SwTextAnnotationField*>(pTextField);
|
|
const ::sw::mark::MarkBase* pAnnotationMark = pTextAnnotationField->GetAnnotationMark();
|
|
const SwPosition aMarkStart = pAnnotationMark ? pAnnotationMark->GetMarkStart()
|
|
: SwPosition(rTextNode, p->GetStart());
|
|
const SwPosition aMarkEnd = pAnnotationMark ? pAnnotationMark->GetMarkEnd()
|
|
: SwPosition(rTextNode, p->GetAnyEnd());
|
|
const SwTextFrame* pMarkStartFrame = static_cast<SwTextFrame*>(
|
|
aMarkStart.GetNode().GetTextNode()->getLayoutFrame(m_pActiveShell->GetLayout()));
|
|
const SwTextFrame* pMarkEndFrame = static_cast<SwTextFrame*>(
|
|
aMarkEnd.GetNode().GetTextNode()->getLayoutFrame(m_pActiveShell->GetLayout()));
|
|
if (!pMarkStartFrame || !pMarkEndFrame)
|
|
continue;
|
|
lcl_CalcOverlayRanges(pMarkStartFrame, pMarkEndFrame, aMarkStart,
|
|
aMarkEnd, aRanges);
|
|
}
|
|
OverlayObject(std::move(aRanges));
|
|
}
|
|
|
|
void SwContentTree::BringFootnotesToAttention(std::vector<const SwTextAttr*>& rTextAttrsArr)
|
|
{
|
|
std::vector<basegfx::B2DRange> aRanges;
|
|
for (const SwTextAttr* p : rTextAttrsArr)
|
|
{
|
|
if (!p)
|
|
continue;
|
|
const SwTextFootnote* pTextFootnote = p->GetFootnote().GetTextFootnote();
|
|
if (!pTextFootnote)
|
|
continue;
|
|
const SwTextNode& rTextNode = pTextFootnote->GetTextNode();
|
|
if (SwTextFrame* pFrame = static_cast<SwTextFrame*>(
|
|
rTextNode.getLayoutFrame(m_pActiveShell->GetLayout())))
|
|
{
|
|
auto nStart = p->GetStart();
|
|
auto nEnd = nStart + 1;
|
|
SwPosition aStartPos(rTextNode, nStart), aEndPos(rTextNode, nEnd);
|
|
lcl_CalcOverlayRanges(pFrame, pFrame, aStartPos, aEndPos, aRanges);
|
|
}
|
|
}
|
|
OverlayObject(std::move(aRanges));
|
|
}
|
|
|
|
void SwContentTree::BringDrawingObjectsToAttention(std::vector<const SdrObject*>& rDrawingObjectsArr)
|
|
{
|
|
std::vector<basegfx::B2DRange> aRanges;
|
|
for (const SdrObject* pObject : rDrawingObjectsArr)
|
|
{
|
|
if (pObject)
|
|
{
|
|
tools::Rectangle aRect(pObject->GetLogicRect());
|
|
if (!aRect.IsEmpty())
|
|
aRanges.emplace_back(aRect.Left(), aRect.Top(), aRect.Right(), aRect.Bottom());
|
|
}
|
|
}
|
|
OverlayObject(std::move(aRanges));
|
|
}
|
|
|
|
void SwContentTree::BringTextFieldsToAttention(std::vector<const SwTextAttr*>& rTextAttrsArr)
|
|
{
|
|
std::vector<basegfx::B2DRange> aRanges;
|
|
std::shared_ptr<SwPaM> pPamForTextField;
|
|
for (const SwTextAttr* p : rTextAttrsArr)
|
|
{
|
|
if (!p)
|
|
continue;
|
|
const SwTextField* pTextField = p->GetFormatField().GetTextField();
|
|
if (!pTextField)
|
|
continue;
|
|
if (SwTextFrame* pFrame = static_cast<SwTextFrame*>(
|
|
pTextField->GetTextNode().getLayoutFrame(m_pActiveShell->GetLayout())))
|
|
{
|
|
SwTextField::GetPamForTextField(*pTextField, pPamForTextField);
|
|
if (!pPamForTextField)
|
|
continue;
|
|
SwPosition aStartPos(*pPamForTextField->GetMark());
|
|
SwPosition aEndPos(*pPamForTextField->GetPoint());
|
|
lcl_CalcOverlayRanges(pFrame, pFrame, aStartPos, aEndPos, aRanges);
|
|
}
|
|
}
|
|
OverlayObject(std::move(aRanges));
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|