summaryrefslogtreecommitdiffstats
path: root/sw/source/uibase/utlui
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
commit267c6f2ac71f92999e969232431ba04678e7437e (patch)
tree358c9467650e1d0a1d7227a21dac2e3d08b622b2 /sw/source/uibase/utlui
parentInitial commit. (diff)
downloadlibreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz
libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sw/source/uibase/utlui')
-rw-r--r--sw/source/uibase/utlui/AccessibilityStatusBarControl.cxx81
-rw-r--r--sw/source/uibase/utlui/attrdesc.cxx846
-rw-r--r--sw/source/uibase/utlui/bookctrl.cxx112
-rw-r--r--sw/source/uibase/utlui/condedit.cxx84
-rw-r--r--sw/source/uibase/utlui/content.cxx6647
-rw-r--r--sw/source/uibase/utlui/glbltree.cxx1185
-rw-r--r--sw/source/uibase/utlui/gloslst.cxx445
-rw-r--r--sw/source/uibase/utlui/gotodlg.cxx105
-rw-r--r--sw/source/uibase/utlui/initui.cxx311
-rw-r--r--sw/source/uibase/utlui/navicfg.cxx196
-rw-r--r--sw/source/uibase/utlui/navipi.cxx1277
-rw-r--r--sw/source/uibase/utlui/numfmtlb.cxx470
-rw-r--r--sw/source/uibase/utlui/prcntfld.cxx231
-rw-r--r--sw/source/uibase/utlui/shdwcrsr.cxx56
-rw-r--r--sw/source/uibase/utlui/tmplctrl.cxx121
-rw-r--r--sw/source/uibase/utlui/uiitems.cxx277
-rw-r--r--sw/source/uibase/utlui/uitool.cxx921
-rw-r--r--sw/source/uibase/utlui/unotools.cxx496
-rw-r--r--sw/source/uibase/utlui/viewlayoutctrl.cxx213
-rw-r--r--sw/source/uibase/utlui/wordcountctrl.cxx45
-rw-r--r--sw/source/uibase/utlui/zoomctrl.cxx65
21 files changed, 14184 insertions, 0 deletions
diff --git a/sw/source/uibase/utlui/AccessibilityStatusBarControl.cxx b/sw/source/uibase/utlui/AccessibilityStatusBarControl.cxx
new file mode 100644
index 0000000000..9a99d3c578
--- /dev/null
+++ b/sw/source/uibase/utlui/AccessibilityStatusBarControl.cxx
@@ -0,0 +1,81 @@
+/* -*- 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/.
+ */
+
+#include <swtypes.hxx>
+#include <strings.hrc>
+#include <AccessibilityStatusBarControl.hxx>
+#include <svl/intitem.hxx>
+#include <vcl/status.hxx>
+#include <vcl/event.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <bitmaps.hlst>
+
+SFX_IMPL_STATUSBAR_CONTROL(sw::AccessibilityStatusBarControl, SfxInt32Item);
+
+namespace sw
+{
+AccessibilityStatusBarControl::AccessibilityStatusBarControl(sal_uInt16 _nSlotId, sal_uInt16 _nId,
+ StatusBar& rStb)
+ : SfxStatusBarControl(_nSlotId, _nId, rStb)
+ , mnIssues(0)
+ , maImageIssuesFound(Image(StockImage::Yes, RID_BMP_A11Y_CHECK_ISSUES_FOUND))
+ , maImageIssuesNotFound(Image(StockImage::Yes, RID_BMP_A11Y_CHECK_ISSUES_NOT_FOUND))
+{
+}
+
+AccessibilityStatusBarControl::~AccessibilityStatusBarControl() = default;
+
+void AccessibilityStatusBarControl::StateChangedAtStatusBarControl(sal_uInt16 /*nSID*/,
+ SfxItemState eState,
+ const SfxPoolItem* pState)
+{
+ mnIssues = -1;
+
+ bool bOnlineCheckStatus
+ = officecfg::Office::Common::Accessibility::OnlineAccessibilityCheck::get();
+
+ if (eState == SfxItemState::DEFAULT && bOnlineCheckStatus)
+ {
+ if (auto pItem = dynamic_cast<const SfxInt32Item*>(pState))
+ mnIssues = pItem->GetValue();
+ OUString aString = SwResId(STR_ACCESSIBILITY_CHECK_HINT)
+ .replaceFirst("%issues%", OUString::number(mnIssues));
+ GetStatusBar().SetQuickHelpText(GetId(), aString);
+ }
+ else
+ {
+ GetStatusBar().SetQuickHelpText(GetId(), u""_ustr);
+ }
+
+ GetStatusBar().Invalidate();
+}
+
+void AccessibilityStatusBarControl::Paint(const UserDrawEvent& rUserEvent)
+{
+ if (mnIssues < 0)
+ return;
+
+ vcl::RenderContext* pRenderContext = rUserEvent.GetRenderContext();
+
+ tools::Rectangle aRect = rUserEvent.GetRect();
+ const tools::Rectangle aControlRect = getControlRect();
+
+ Image aImage = mnIssues > 0 ? maImageIssuesFound : maImageIssuesNotFound;
+
+ Size aSize(aImage.GetSizePixel());
+
+ auto aPosition = Point(aRect.Left() + (aControlRect.GetWidth() - aSize.Width()) / 2,
+ aRect.Top() + (aControlRect.GetHeight() - aSize.Height()) / 2);
+
+ pRenderContext->DrawImage(aPosition, aImage);
+}
+
+} // end sw
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/utlui/attrdesc.cxx b/sw/source/uibase/utlui/attrdesc.cxx
new file mode 100644
index 0000000000..71fdd4ab54
--- /dev/null
+++ b/sw/source/uibase/utlui/attrdesc.cxx
@@ -0,0 +1,846 @@
+/* -*- 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 <i18nutil/unicode.hxx>
+#include <svl/itemiter.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/GraphicAttributes.hxx>
+
+#include <editeng/itemtype.hxx>
+#include <editeng/eerdll.hxx>
+#include <unotools/intlwrapper.hxx>
+#include <unotools/syslocale.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <fmtanchr.hxx>
+#include <fmtfsize.hxx>
+#include <fmtinfmt.hxx>
+#include <fchrfmt.hxx>
+#include <fmtautofmt.hxx>
+#include <fmtsrnd.hxx>
+#include <fmtornt.hxx>
+#include <fmtlsplt.hxx>
+#include <fmtrowsplt.hxx>
+#include <fmtpdsc.hxx>
+#include <fmtclds.hxx>
+#include <fmteiro.hxx>
+#include <fmturl.hxx>
+#include <fmthdft.hxx>
+#include <fmtcnct.hxx>
+#include <fmtline.hxx>
+#include <tgrditem.hxx>
+#include <hfspacingitem.hxx>
+#include <fmtruby.hxx>
+#include <paratr.hxx>
+#include <grfatr.hxx>
+#include <pagedesc.hxx>
+#include <charfmt.hxx>
+#include <strings.hrc>
+#include <fmtftntx.hxx>
+#include <fmtfollowtextflow.hxx>
+#include <libxml/xmlwriter.h>
+
+using namespace com::sun::star;
+
+
+// query the attribute descriptions
+void SwAttrSet::GetPresentation(
+ SfxItemPresentation ePres,
+ MapUnit eCoreMetric,
+ MapUnit ePresMetric,
+ OUString &rText ) const
+{
+ rText.clear();
+ OUString aStr;
+ if( !Count() )
+ return;
+
+ SfxItemIter aIter( *this );
+ const SfxPoolItem* pItem = aIter.GetCurItem();
+ const IntlWrapper aInt(SvtSysLocale().GetUILanguageTag());
+ do
+ {
+ pItem->GetPresentation(ePres, eCoreMetric, ePresMetric, aStr, aInt);
+ if( rText.getLength() && aStr.getLength() )
+ rText += ", ";
+ rText += aStr;
+ pItem = aIter.NextItem();
+ } while (pItem);
+}
+
+bool SwFormatCharFormat::GetPresentation
+(
+ SfxItemPresentation ePres,
+ MapUnit eCoreUnit,
+ MapUnit ePresUnit,
+ OUString& rText,
+ const IntlWrapper& /*rIntl*/
+) const
+{
+ const SwCharFormat *pCharFormat = GetCharFormat();
+ if ( pCharFormat )
+ {
+ OUString aStr;
+ pCharFormat->GetPresentation( ePres, eCoreUnit, ePresUnit, aStr );
+ rText = SwResId( STR_CHARFMT ) + "(" + aStr + ")";
+ }
+ else
+ rText = SwResId( STR_NO_CHARFMT );
+ return true;
+}
+
+bool SwFormatAutoFormat::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText,
+ const IntlWrapper& /*rIntl*/
+) const
+{
+ rText.clear(); //TODO
+ return true;
+}
+
+bool SwFormatINetFormat::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText,
+ const IntlWrapper& /*rIntl*/
+) const
+{
+ rText = GetValue();
+ return true;
+}
+
+bool SwFormatRuby::GetPresentation( SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreMetric*/, MapUnit /*ePresMetric*/,
+ OUString &rText, const IntlWrapper& /*rIntl*/ ) const
+{
+ rText.clear();
+ return true;
+}
+
+bool SwFormatDrop::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText,
+ const IntlWrapper& /*rIntl*/
+) const
+{
+ rText.clear();
+ if ( GetLines() > 1 )
+ {
+ if ( GetChars() > 1 )
+ {
+ rText = OUString::number( GetChars() ) + " ";
+ }
+ rText += SwResId( STR_DROP_OVER ) +
+ " " +
+ OUString::number( GetLines() ) +
+ " " +
+ SwResId( STR_DROP_LINES );
+ }
+ else
+ rText = SwResId( STR_NO_DROP_LINES );
+ return true;
+}
+
+bool SwRegisterItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText,
+ const IntlWrapper& /*rIntl*/
+) const
+{
+ TranslateId pId = GetValue() ? STR_REGISTER_ON : STR_REGISTER_OFF;
+ rText = SwResId(pId);
+ return true;
+}
+
+bool SwNumRuleItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText,
+ const IntlWrapper& /*rIntl*/
+) const
+{
+ if( !GetValue().isEmpty() )
+ rText = SwResId( STR_NUMRULE_ON ).replaceFirst("%LISTSTYLENAME", GetValue());
+ else
+ rText = SwResId( STR_NUMRULE_OFF );
+ return true;
+}
+
+bool SwParaConnectBorderItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText,
+ const IntlWrapper& /*rIntl*/
+) const
+{
+ TranslateId pId = GetValue() ? STR_CONNECT_BORDER_ON : STR_CONNECT_BORDER_OFF;
+ rText = SwResId(pId);
+ return true;
+}
+
+// Frame attribute
+
+bool SwFormatFrameSize::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit eCoreUnit,
+ MapUnit ePresUnit,
+ OUString& rText,
+ const IntlWrapper& rIntl
+) const
+{
+ rText = SwResId( STR_FRM_WIDTH ) + " ";
+ if ( GetWidthPercent() )
+ {
+ rText += unicode::formatPercent(GetWidthPercent(),
+ Application::GetSettings().GetUILanguageTag());
+ }
+ else
+ {
+ rText += ::GetMetricText( GetWidth(), eCoreUnit, ePresUnit, &rIntl ) +
+ " " + ::EditResId( ::GetMetricId( ePresUnit ) );
+ }
+ if ( SwFrameSize::Variable != GetHeightSizeType() )
+ {
+ TranslateId pId = SwFrameSize::Fixed == m_eFrameHeightType ?
+ STR_FRM_FIXEDHEIGHT : STR_FRM_MINHEIGHT;
+ rText += ", " + SwResId(pId) + " ";
+ if ( GetHeightPercent() )
+ {
+ rText += unicode::formatPercent(GetHeightPercent(),
+ Application::GetSettings().GetUILanguageTag());
+ }
+ else
+ {
+ rText = ::GetMetricText( GetHeight(), eCoreUnit, ePresUnit, &rIntl ) +
+ " " + EditResId( ::GetMetricId( ePresUnit ) );
+ }
+ }
+ return true;
+}
+
+//Header for page formats.
+//Client of FrameFormat which describes the header.
+
+bool SwFormatHeader::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText,
+ const IntlWrapper& /*rIntl*/
+) const
+{
+ TranslateId pId = GetHeaderFormat() ? STR_HEADER : STR_NO_HEADER;
+ rText = SwResId(pId);
+ return true;
+}
+
+//Footer for page formats.
+//Client of FrameFormat which describes the footer.
+
+bool SwFormatFooter::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText,
+ const IntlWrapper& /*rIntl*/
+) const
+{
+ TranslateId pId = GetFooterFormat() ? STR_FOOTER : STR_NO_FOOTER;
+ rText = SwResId(pId);
+ return true;
+}
+
+bool SwFormatSurround::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText,
+ const IntlWrapper& /*rIntl*/
+) const
+{
+ TranslateId pId;
+ switch ( GetValue() )
+ {
+ case css::text::WrapTextMode_NONE:
+ pId = STR_SURROUND_NONE;
+ break;
+ case css::text::WrapTextMode_THROUGH:
+ pId = STR_SURROUND_THROUGH;
+ break;
+ case css::text::WrapTextMode_PARALLEL:
+ pId = STR_SURROUND_PARALLEL;
+ break;
+ case css::text::WrapTextMode_DYNAMIC:
+ pId = STR_SURROUND_IDEAL;
+ break;
+ case css::text::WrapTextMode_LEFT:
+ pId = STR_SURROUND_LEFT;
+ break;
+ case css::text::WrapTextMode_RIGHT:
+ pId = STR_SURROUND_RIGHT;
+ break;
+ default:;//prevent warning
+ }
+ if (pId)
+ rText = SwResId(pId);
+
+ if ( IsAnchorOnly() )
+ {
+ rText += " " + SwResId( STR_SURROUND_ANCHORONLY );
+ }
+ return true;
+}
+
+//VertOrientation, how and by what orientate the FlyFrame in the vertical?
+
+bool SwFormatVertOrient::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit eCoreUnit,
+ MapUnit ePresUnit,
+ OUString& rText,
+ const IntlWrapper& rIntl
+) const
+{
+ TranslateId pId;
+ switch ( GetVertOrient() )
+ {
+ case text::VertOrientation::NONE:
+ {
+ rText += SwResId( STR_POS_Y ) + " " +
+ ::GetMetricText( GetPos(), eCoreUnit, ePresUnit, &rIntl ) +
+ " " + EditResId( ::GetMetricId( ePresUnit ) );
+ }
+ break;
+ case text::VertOrientation::TOP:
+ pId = STR_VERT_TOP;
+ break;
+ case text::VertOrientation::CENTER:
+ pId = STR_VERT_CENTER;
+ break;
+ case text::VertOrientation::BOTTOM:
+ pId = STR_VERT_BOTTOM;
+ break;
+ case text::VertOrientation::LINE_TOP:
+ pId = STR_LINE_TOP;
+ break;
+ case text::VertOrientation::LINE_CENTER:
+ pId = STR_LINE_CENTER;
+ break;
+ case text::VertOrientation::LINE_BOTTOM:
+ pId = STR_LINE_BOTTOM;
+ break;
+ default:;//prevent warning
+ }
+ if (pId)
+ rText += SwResId(pId);
+ return true;
+}
+
+//HoriOrientation, how and by what orientate the FlyFrame in the horizontal?
+
+bool SwFormatHoriOrient::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit eCoreUnit,
+ MapUnit ePresUnit,
+ OUString& rText,
+ const IntlWrapper& rIntl
+) const
+{
+ TranslateId pId;
+ switch ( GetHoriOrient() )
+ {
+ case text::HoriOrientation::NONE:
+ {
+ rText += SwResId( STR_POS_X ) + " " +
+ ::GetMetricText( GetPos(), eCoreUnit, ePresUnit, &rIntl ) +
+ " " + EditResId( ::GetMetricId( ePresUnit ) );
+ }
+ break;
+ case text::HoriOrientation::RIGHT:
+ pId = STR_HORI_RIGHT;
+ break;
+ case text::HoriOrientation::CENTER:
+ pId = STR_HORI_CENTER;
+ break;
+ case text::HoriOrientation::LEFT:
+ pId = STR_HORI_LEFT;
+ break;
+ case text::HoriOrientation::INSIDE:
+ pId = STR_HORI_INSIDE;
+ break;
+ case text::HoriOrientation::OUTSIDE:
+ pId = STR_HORI_OUTSIDE;
+ break;
+ case text::HoriOrientation::FULL:
+ pId = STR_HORI_FULL;
+ break;
+ default:;//prevent warning
+ }
+ if (pId)
+ rText += SwResId(pId);
+ return true;
+}
+
+// FlyAnchor, Anchor of the free-flying frame
+
+bool SwFormatAnchor::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText,
+ const IntlWrapper& /*rIntl*/
+) const
+{
+ TranslateId pId;
+ switch ( GetAnchorId() )
+ {
+ case RndStdIds::FLY_AT_PARA:
+ pId = STR_FLY_AT_PARA;
+ break;
+ case RndStdIds::FLY_AS_CHAR:
+ pId = STR_FLY_AS_CHAR;
+ break;
+ case RndStdIds::FLY_AT_CHAR:
+ pId = STR_FLY_AT_CHAR;
+ break;
+ case RndStdIds::FLY_AT_PAGE:
+ pId = STR_FLY_AT_PAGE;
+ break;
+ default:;//prevent warning
+ }
+ if (pId)
+ rText += SwResId(pId);
+ return true;
+}
+
+bool SwFormatPageDesc::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText,
+ const IntlWrapper& /*rIntl*/
+) const
+{
+ const SwPageDesc *pPageDesc = GetPageDesc();
+ if ( pPageDesc )
+ rText = pPageDesc->GetName();
+ else
+ rText = SwResId( STR_NO_PAGEDESC );
+ return true;
+}
+
+//The ColumnDescriptor
+
+bool SwFormatCol::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit eCoreUnit,
+ MapUnit /*ePresUnit*/,
+ OUString& rText,
+ const IntlWrapper& rIntl
+) const
+{
+ sal_uInt16 nCnt = GetNumCols();
+ if ( nCnt > 1 )
+ {
+ rText = OUString::number(nCnt) + " " + SwResId( STR_COLUMNS );
+ if ( COLADJ_NONE != GetLineAdj() )
+ {
+ const tools::Long nWdth = static_cast<tools::Long>(GetLineWidth());
+ rText += " " + SwResId( STR_LINE_WIDTH ) + " " +
+ ::GetMetricText( nWdth, eCoreUnit,
+ MapUnit::MapPoint, &rIntl );
+ }
+ }
+ else
+ rText.clear();
+ return true;
+}
+
+//URL's and maps
+
+bool SwFormatURL::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText,
+ const IntlWrapper& /*rIntl*/
+) const
+{
+ rText.clear();
+ if ( m_pMap )
+ rText += "Client-Map";
+ if ( !m_sURL.isEmpty() )
+ {
+ if ( m_pMap )
+ rText += " - ";
+ rText += "URL: " + m_sURL;
+ if ( m_bIsServerMap )
+ rText += " (Server-Map)";
+ }
+ if ( !m_sTargetFrameName.isEmpty() )
+ {
+ rText += ", Target: " + m_sTargetFrameName;
+ }
+ return true;
+}
+
+bool SwFormatEditInReadonly::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText,
+ const IntlWrapper& /*rIntl*/
+) const
+{
+ rText.clear();
+ if ( GetValue() )
+ rText = SwResId(STR_EDIT_IN_READONLY);
+ return true;
+}
+
+void SwFormatEditInReadonly::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwFormatEditInReadonly"));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), BAD_CAST(OString::boolean(GetValue()).getStr()));
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+bool SwFormatLayoutSplit::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText,
+ const IntlWrapper& /*rIntl*/
+) const
+{
+ if ( GetValue() )
+ rText = SwResId(STR_LAYOUT_SPLIT);
+ return true;
+}
+
+bool SwFormatRowSplit::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& /*rText*/,
+ const IntlWrapper& /*rIntl*/
+) const
+{
+ return false;
+}
+
+bool SwFormatFootnoteEndAtTextEnd::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& /*rText*/,
+ const IntlWrapper& /*rIntl*/
+) const
+{
+ return true;
+}
+
+bool SwFormatChain::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText,
+ const IntlWrapper& /*rIntl*/
+) const
+{
+ if ( GetPrev() || GetNext() )
+ {
+ rText = SwResId(STR_CONNECT1);
+ if ( GetPrev() )
+ {
+ rText += GetPrev()->GetName();
+ if ( GetNext() )
+ rText += SwResId(STR_CONNECT2);
+ }
+ if ( GetNext() )
+ rText += GetNext()->GetName();
+ }
+ return true;
+}
+
+bool SwFormatLineNumber::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText,
+ const IntlWrapper& /*rIntl*/
+) const
+{
+ if ( IsCount() )
+ rText += SwResId(STR_LINECOUNT);
+ else
+ rText += SwResId(STR_DONTLINECOUNT);
+ if ( GetStartValue() )
+ {
+ rText += " " + SwResId(STR_LINCOUNT_START) +
+ OUString::number( GetStartValue() );
+ }
+ return true;
+}
+
+bool SwTextGridItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText,
+ const IntlWrapper& /*rIntl*/
+) const
+{
+ TranslateId pId;
+
+ switch ( GetGridType() )
+ {
+ case GRID_NONE :
+ pId = STR_GRID_NONE;
+ break;
+ case GRID_LINES_ONLY :
+ pId = STR_GRID_LINES_ONLY;
+ break;
+ case GRID_LINES_CHARS :
+ pId = STR_GRID_LINES_CHARS;
+ break;
+ }
+ if (pId)
+ rText += SwResId(pId);
+ return true;
+}
+
+bool SwHeaderAndFooterEatSpacingItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& /*rText*/,
+ const IntlWrapper& /*rIntl*/
+) const
+{
+ return false;
+}
+
+// Graphic attributes
+
+bool SwMirrorGrf::GetPresentation(
+ SfxItemPresentation /*ePres*/, MapUnit /*eCoreUnit*/, MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper& /*rIntl*/ ) const
+{
+ TranslateId pId;
+ switch( GetValue() )
+ {
+ case MirrorGraph::Dont: pId = STR_NO_MIRROR; break;
+ case MirrorGraph::Vertical: pId = STR_VERT_MIRROR; break;
+ case MirrorGraph::Horizontal: pId = STR_HORI_MIRROR; break;
+ case MirrorGraph::Both: pId = STR_BOTH_MIRROR; break;
+ default: break;
+ }
+ if (pId)
+ {
+ rText = SwResId(pId);
+ if (m_bGrfToggle)
+ rText += SwResId( STR_MIRROR_TOGGLE );
+ }
+ return true;
+}
+
+bool SwRotationGrf::GetPresentation(
+ SfxItemPresentation ePres, MapUnit /*eCoreUnit*/, MapUnit /*ePresUnit*/,
+ OUString &rText, const IntlWrapper& /*rIntl*/) const
+{
+ if( SfxItemPresentation::Complete == ePres )
+ rText = SwResId( STR_ROTATION );
+ else if( rText.getLength() )
+ rText.clear();
+ rText += OUString::number( toDegrees(GetValue()) ) + "\xB0";
+ return true;
+}
+
+bool SwLuminanceGrf::GetPresentation(
+ SfxItemPresentation ePres, MapUnit /*eCoreUnit*/, MapUnit /*ePresUnit*/,
+ OUString &rText, const IntlWrapper& /*rIntl*/) const
+{
+ if( SfxItemPresentation::Complete == ePres )
+ rText = SwResId( STR_LUMINANCE );
+ else if( rText.getLength() )
+ rText.clear();
+ rText += unicode::formatPercent(GetValue(),
+ Application::GetSettings().GetUILanguageTag());
+ return true;
+}
+
+bool SwContrastGrf::GetPresentation(
+ SfxItemPresentation ePres, MapUnit /*eCoreUnit*/, MapUnit /*ePresUnit*/,
+ OUString &rText, const IntlWrapper& /*rIntl*/) const
+{
+ if( SfxItemPresentation::Complete == ePres )
+ rText = SwResId( STR_CONTRAST );
+ else if( rText.getLength() )
+ rText.clear();
+ rText += unicode::formatPercent(GetValue(),
+ Application::GetSettings().GetUILanguageTag());
+ return true;
+}
+
+bool SwChannelGrf::GetPresentation(
+ SfxItemPresentation ePres, MapUnit /*eCoreUnit*/, MapUnit /*ePresUnit*/,
+ OUString &rText, const IntlWrapper& /*rIntl*/) const
+{
+ if( SfxItemPresentation::Complete == ePres )
+ {
+ TranslateId pId;
+ switch ( Which() )
+ {
+ case RES_GRFATR_CHANNELR: pId = STR_CHANNELR; break;
+ case RES_GRFATR_CHANNELG: pId = STR_CHANNELG; break;
+ case RES_GRFATR_CHANNELB: pId = STR_CHANNELB; break;
+ default: break;
+ }
+ if (pId)
+ rText = SwResId(pId);
+ else if( rText.getLength() )
+ rText.clear();
+ }
+ else if( rText.getLength() )
+ rText.clear();
+ rText += unicode::formatPercent(GetValue(),
+ Application::GetSettings().GetUILanguageTag());
+ return true;
+}
+
+bool SwGammaGrf::GetPresentation(
+ SfxItemPresentation ePres, MapUnit /*eCoreUnit*/, MapUnit /*ePresUnit*/,
+ OUString &rText, const IntlWrapper& /*rIntl*/) const
+{
+ OUStringBuffer aText;
+ if( SfxItemPresentation::Complete == ePres )
+ aText.append(SwResId(STR_GAMMA));
+ aText.append(unicode::formatPercent(GetValue(),
+ Application::GetSettings().GetUILanguageTag()));
+ rText = aText.makeStringAndClear();
+ return true;
+}
+
+bool SwInvertGrf::GetPresentation(
+ SfxItemPresentation ePres, MapUnit /*eCoreUnit*/, MapUnit /*ePresUnit*/,
+ OUString &rText, const IntlWrapper& /*rIntl*/) const
+{
+ rText.clear();
+ if( SfxItemPresentation::Complete == ePres )
+ {
+ TranslateId pId = GetValue() ? STR_INVERT : STR_INVERT_NOT;
+ rText = SwResId(pId);
+ }
+ return true;
+}
+
+bool SwTransparencyGrf::GetPresentation(
+ SfxItemPresentation ePres, MapUnit /*eCoreUnit*/, MapUnit /*ePresUnit*/,
+ OUString &rText, const IntlWrapper& /*rIntl*/) const
+{
+ if( SfxItemPresentation::Complete == ePres )
+ rText = SwResId( STR_TRANSPARENCY );
+ else if( rText.getLength() )
+ rText.clear();
+ rText += unicode::formatPercent(GetValue(),
+ Application::GetSettings().GetUILanguageTag());
+ return true;
+}
+
+bool SwDrawModeGrf::GetPresentation(
+ SfxItemPresentation ePres, MapUnit /*eCoreUnit*/, MapUnit /*ePresUnit*/,
+ OUString &rText, const IntlWrapper& /*rIntl*/) const
+{
+ rText.clear();
+ if( SfxItemPresentation::Complete == ePres )
+ {
+ TranslateId pId;
+ switch ( GetValue() )
+ {
+
+ case GraphicDrawMode::Greys: pId = STR_DRAWMODE_GREY; break;
+ case GraphicDrawMode::Mono: pId = STR_DRAWMODE_BLACKWHITE; break;
+ case GraphicDrawMode::Watermark: pId = STR_DRAWMODE_WATERMARK; break;
+ default: pId = STR_DRAWMODE_STD; break;
+ }
+ rText = SwResId( STR_DRAWMODE ) + SwResId(pId);
+ }
+ return true;
+}
+
+bool SwFormatFollowTextFlow::GetPresentation( SfxItemPresentation ePres,
+ MapUnit /*eCoreMetric*/,
+ MapUnit /*ePresMetric*/,
+ OUString &rText,
+ const IntlWrapper& /*rIntl*/ ) const
+{
+ rText.clear();
+ if( SfxItemPresentation::Complete == ePres )
+ {
+ TranslateId pId = GetValue() ? STR_FOLLOW_TEXT_FLOW : STR_DONT_FOLLOW_TEXT_FLOW;
+ rText = SwResId(pId);
+ }
+ return true;
+}
+
+void SwFormatFollowTextFlow::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwFormatFollowTextFlow"));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), BAD_CAST(OString::boolean(GetValue()).getStr()));
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/utlui/bookctrl.cxx b/sw/source/uibase/utlui/bookctrl.cxx
new file mode 100644
index 0000000000..e79821022a
--- /dev/null
+++ b/sw/source/uibase/utlui/bookctrl.cxx
@@ -0,0 +1,112 @@
+/* -*- 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 <svl/intitem.hxx>
+#include <svl/slstitm.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+#include <vcl/status.hxx>
+#include <vcl/weldutils.hxx>
+#include <cmdid.h>
+#include <swmodule.hxx>
+#include <wrtsh.hxx>
+#include <IMark.hxx>
+#include <bookctrl.hxx>
+#include <map>
+
+SFX_IMPL_STATUSBAR_CONTROL(SwBookmarkControl, SfxStringListItem);
+
+SwBookmarkControl::SwBookmarkControl( sal_uInt16 _nSlotId,
+ sal_uInt16 _nId,
+ StatusBar& rStb ) :
+ SfxStatusBarControl( _nSlotId, _nId, rStb )
+{
+}
+
+SwBookmarkControl::~SwBookmarkControl()
+{
+}
+
+void SwBookmarkControl::StateChangedAtStatusBarControl(
+ sal_uInt16 /*nSID*/, SfxItemState eState, const SfxPoolItem* pState )
+{
+ if (eState != SfxItemState::DEFAULT || SfxItemState::DISABLED == eState)
+ {
+ GetStatusBar().SetItemText(GetId(), OUString());
+ GetStatusBar().SetQuickHelpText(GetId(), OUString());
+ }
+ else if (auto pStringListItem = dynamic_cast<const SfxStringListItem*>(pState))
+ {
+ const std::vector<OUString>& rStringList(pStringListItem->GetList());
+ GetStatusBar().SetItemText(GetId(), rStringList[0]);
+ GetStatusBar().SetQuickHelpText(GetId(), rStringList[1]);
+ }
+}
+
+void SwBookmarkControl::Paint( const UserDrawEvent& )
+{
+}
+
+void SwBookmarkControl::Command( const CommandEvent& rCEvt )
+{
+ if ( rCEvt.GetCommand() != CommandEventId::ContextMenu ||
+ GetStatusBar().GetItemText( GetId() ).isEmpty())
+ return;
+
+ SwWrtShell* pWrtShell = ::GetActiveWrtShell();
+ if( !(pWrtShell && pWrtShell->getIDocumentMarkAccess()->getAllMarksCount() > 0) )
+ return;
+
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if (!pViewFrm)
+ return;
+
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(nullptr, "modules/swriter/ui/bookmarkmenu.ui"));
+ std::unique_ptr<weld::Menu> xPopup(xBuilder->weld_menu("menu"));
+
+ IDocumentMarkAccess* const pMarkAccess = pWrtShell->getIDocumentMarkAccess();
+ IDocumentMarkAccess::const_iterator_t ppBookmarkStart = pMarkAccess->getBookmarksBegin();
+ sal_uInt32 nPopupId = 1;
+ std::map<sal_Int32, sal_uInt16> aBookmarkIdx;
+ for(IDocumentMarkAccess::const_iterator_t ppBookmark = ppBookmarkStart;
+ ppBookmark != pMarkAccess->getBookmarksEnd();
+ ++ppBookmark)
+ {
+ if(IDocumentMarkAccess::MarkType::BOOKMARK == IDocumentMarkAccess::GetType(**ppBookmark))
+ {
+ xPopup->append(OUString::number(nPopupId), (*ppBookmark)->GetName());
+ aBookmarkIdx[nPopupId] = o3tl::narrowing<sal_uInt16>(ppBookmark - ppBookmarkStart);
+ nPopupId++;
+ }
+ }
+ ::tools::Rectangle aRect(rCEvt.GetMousePosPixel(), Size(1, 1));
+ weld::Window* pParent = weld::GetPopupParent(GetStatusBar(), aRect);
+ OUString sResult = xPopup->popup_at_rect(pParent, aRect);
+ if (!sResult.isEmpty())
+ {
+ SfxUInt16Item aBookmark( FN_STAT_BOOKMARK, aBookmarkIdx[sResult.toUInt32()] );
+ pViewFrm->GetDispatcher()->ExecuteList(FN_STAT_BOOKMARK,
+ SfxCallMode::ASYNCHRON|SfxCallMode::RECORD,
+ { &aBookmark });
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/utlui/condedit.cxx b/sw/source/uibase/utlui/condedit.cxx
new file mode 100644
index 0000000000..1303ddfc75
--- /dev/null
+++ b/sw/source/uibase/utlui/condedit.cxx
@@ -0,0 +1,84 @@
+/* -*- 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 <condedit.hxx>
+#include <svx/dbaexchange.hxx>
+
+using namespace ::svx;
+using namespace ::com::sun::star::uno;
+
+ConditionEdit::ConditionEdit(std::unique_ptr<weld::Entry> xControl)
+ : m_xControl(std::move(xControl))
+ , m_aDropTargetHelper(*this)
+ , m_bBrackets(true)
+ , m_bEnableDrop(true)
+{
+}
+
+sal_Int8 ConditionEditDropTarget::AcceptDrop( const AcceptDropEvent& /*rEvt*/ )
+{
+ return OColumnTransferable::canExtractColumnDescriptor
+ ( GetDataFlavorExVector(),
+ ColumnTransferFormatFlags::COLUMN_DESCRIPTOR )
+ ? DND_ACTION_COPY
+ : DND_ACTION_NONE;
+}
+
+ConditionEditDropTarget::ConditionEditDropTarget(ConditionEdit& rEdit)
+ : DropTargetHelper(rEdit.get_widget().get_drop_target())
+ , m_rEdit(rEdit)
+{
+}
+
+sal_Int8 ConditionEditDropTarget::ExecuteDrop( const ExecuteDropEvent& rEvt )
+{
+ sal_Int8 nRet = DND_ACTION_NONE;
+ if (m_rEdit.GetDropEnable())
+ {
+ TransferableDataHelper aData( rEvt.maDropEvent.Transferable );
+
+ const DataFlavorExVector& rVector = aData.GetDataFlavorExVector();
+ if (OColumnTransferable::canExtractColumnDescriptor(rVector, ColumnTransferFormatFlags::COLUMN_DESCRIPTOR))
+ {
+ ODataAccessDescriptor aColDesc = OColumnTransferable::extractColumnDescriptor(
+ aData);
+ OUString sDBName;
+ bool bBrackets = m_rEdit.GetBrackets();
+ if (bBrackets)
+ sDBName += "[";
+ OUString sTmp = aColDesc.getDataSource();
+ sDBName += sTmp + ".";
+
+ aColDesc[DataAccessDescriptorProperty::Command] >>= sTmp;
+ sDBName += sTmp + ".";
+
+ aColDesc[DataAccessDescriptorProperty::ColumnName] >>= sTmp;
+ sDBName += sTmp;
+ if (bBrackets)
+ sDBName += "]";
+
+ m_rEdit.get_widget().set_text( sDBName );
+ nRet = DND_ACTION_COPY;
+ }
+ }
+ return nRet;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/utlui/content.cxx b/sw/source/uibase/utlui/content.cxx
new file mode 100644
index 0000000000..3bf29979dd
--- /dev/null
+++ b/sw/source/uibase/utlui/content.cxx
@@ -0,0 +1,6647 @@
+/* -*- 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>
+
+#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_uniqueptr_to<SwContent>,
+ 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::IMark* 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 = aIdx.GetNodes().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;
+ }
+}
+
+// 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;
+ break;
+ case ContentTypeId::FRAME:
+ m_sTypeToken = "frame";
+ m_bEdit = true;
+ break;
+ case ContentTypeId::GRAPHIC:
+ m_sTypeToken = "graphic";
+ m_bEdit = true;
+ break;
+ case ContentTypeId::OLE:
+ m_sTypeToken = "ole";
+ m_bEdit = true;
+ break;
+ case ContentTypeId::TEXTFIELD:
+ m_bEdit = true;
+ m_bDelete = true;
+ break;
+ case ContentTypeId::FOOTNOTE:
+ case ContentTypeId::ENDNOTE:
+ m_bEdit = true;
+ m_bDelete = false;
+ break;
+ case ContentTypeId::BOOKMARK:
+ {
+ const bool bProtectedBM = m_pWrtShell->getIDocumentSettingAccess().get(
+ DocumentSettingId::PROTECT_BOOKMARKS);
+ m_bEdit = true;
+ m_bDelete = !bProtectedBM;
+ }
+ break;
+ case ContentTypeId::REGION:
+ m_sTypeToken = "region";
+ m_bEdit = true;
+ m_bDelete = true;
+ break;
+ case ContentTypeId::INDEX:
+ m_bEdit = true;
+ m_bDelete = true;
+ break;
+ case ContentTypeId::REFERENCE:
+ m_bEdit = false;
+ m_bDelete = true;
+ break;
+ case ContentTypeId::URLFIELD:
+ m_bEdit = true;
+ m_bDelete = true;
+ break;
+ case ContentTypeId::POSTIT:
+ m_bEdit = true;
+ break;
+ case ContentTypeId::DRAWOBJECT:
+ m_sTypeToken = "drawingobject";
+ m_bEdit = 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 = SW_MOD()->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;
+ m_pWrtShell->GetGrfNms( &sLink, nullptr, static_cast<const SwFlyFrameFormat*>( pFrameFormat));
+ 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(IDocumentMarkAccess::const_iterator_t 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(), nullptr, nullptr);
+ 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.size() == 0)
+ 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->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_DRAGMODE = 1,
+ IDX_STR_HYPERLINK = 2,
+ IDX_STR_LINK_REGION = 3,
+ IDX_STR_COPY_REGION = 4,
+ IDX_STR_DISPLAY = 5,
+ IDX_STR_ACTIVE_VIEW = 6,
+ IDX_STR_HIDDEN = 7,
+ IDX_STR_ACTIVE = 8,
+ IDX_STR_INACTIVE = 9,
+ IDX_STR_EDIT_ENTRY = 10,
+ IDX_STR_DELETE_ENTRY = 11,
+ IDX_STR_SEND_OUTLINE_TO_CLIPBOARD_ENTRY = 12,
+ IDX_STR_OUTLINE_TRACKING = 13,
+ IDX_STR_OUTLINE_TRACKING_DEFAULT = 14,
+ IDX_STR_OUTLINE_TRACKING_FOCUS = 15,
+ IDX_STR_OUTLINE_TRACKING_OFF = 16
+};
+
+}
+
+const TranslateId STR_CONTEXT_ARY[] =
+{
+ STR_OUTLINE_LEVEL,
+ STR_DRAGMODE,
+ STR_HYPERLINK,
+ STR_LINK_REGION,
+ STR_COPY_REGION,
+ 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(OUString(" "))
+ , m_aUpdTimer("SwContentTree m_aUpdTimer")
+ , m_aOverlayObjectDelayTimer("SwContentTree m_aOverlayObjectDelayTimer")
+ , m_sInvisible(SwResId(STR_INVISIBLE))
+ , m_pHiddenShell(nullptr)
+ , m_pActiveShell(nullptr)
+ , m_pConfig(SW_MOD()->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)
+{
+ 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
+ }
+
+ rtl::Reference<TransferDataContainer> xContainer = new TransferDataContainer;
+ sal_Int8 nDragMode = DND_ACTION_COPYMOVE | DND_ACTION_LINK;
+
+ if (FillTransferData(*xContainer, nDragMode))
+ bDisallow = false;
+
+ 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());
+
+ // Find first selected of continuous siblings
+ while (true)
+ {
+ m_xTreeView->copy_iterator(*xEntry, *xScratch);
+ if (!m_xTreeView->iter_previous_sibling(*xScratch))
+ break;
+ if (!m_xTreeView->is_selected(*xScratch))
+ break;
+ m_xTreeView->copy_iterator(*xScratch, *xEntry);
+ }
+ // Record continuous selected siblings
+ do
+ {
+ m_aDndOutlinesSelected.push_back(m_xTreeView->make_iterator(xEntry.get()));
+ }
+ while (m_xTreeView->iter_next_sibling(*xEntry) && m_xTreeView->is_selected(*xEntry));
+ bDisallow = false;
+ }
+
+ if (!bDisallow)
+ m_xTreeView->enable_drag_source(xContainer, nDragMode);
+ 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 (rNodes.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 (rNodes.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 (rNodes.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 (rNodes.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);
+ }
+
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xTreeView.get(), "modules/swriter/ui/navigatorcontextmenu.ui"));
+ std::unique_ptr<weld::Menu> xPop = xBuilder->weld_menu("navmenu");
+
+ bool bOutline(false);
+ std::unique_ptr<weld::Menu> xSubPop1 = xBuilder->weld_menu("outlinelevel");
+ std::unique_ptr<weld::Menu> xSubPop2 = xBuilder->weld_menu("dragmodemenu");
+ std::unique_ptr<weld::Menu> xSubPop3 = xBuilder->weld_menu("displaymenu");
+ std::unique_ptr<weld::Menu> xSubPopOutlineTracking = xBuilder->weld_menu("outlinetracking");
+
+ std::unique_ptr<weld::Menu> xSubPopOutlineContent = xBuilder->weld_menu("outlinecontent");
+
+ 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);
+
+ // Add entries to the Drag Mode submenu
+ for (int i=0; i < 3; ++i)
+ {
+ sId = OUString::number(i + 201);
+ xSubPop2->append_radio(sId, m_aContextStrings[IDX_STR_HYPERLINK + i]);
+ xSubPop2->set_item_help_id(sId, HID_NAV_DRAG_MODE);
+ }
+ xSubPop2->set_active(OUString::number(201 + static_cast<int>(GetParentWindow()->GetRegionDropMode())), 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 bRemoveIndexEntries = true;
+ bool bRemoveCopyEntry = true;
+ bool bRemoveEditEntry = true;
+ bool bRemoveUnprotectEntry = true;
+ bool bRemoveDeleteChapterEntry = true,
+ bRemoveDeleteTableEntry = true,
+ bRemoveDeleteFrameEntry = true,
+ bRemoveDeleteImageEntry = true,
+ bRemoveDeleteOLEObjectEntry = true,
+ bRemoveDeleteBookmarkEntry = true,
+ bRemoveDeleteRegionEntry = true,
+ bRemoveDeleteHyperlinkEntry = true,
+ bRemoveDeleteReferenceEntry = true,
+ bRemoveDeleteIndexEntry= true,
+ bRemoveDeleteCommentEntry = true,
+ bRemoveDeleteDrawingObjectEntry = true,
+ bRemoveDeleteFieldEntry = 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;
+ const sal_Int32 nMask = 1 << static_cast<int>(nContentType);
+ sal_uInt64 nSortAlphabeticallyBlock = m_pConfig->GetSortAlphabeticallyBlock();
+ xPop->set_active("sort", nSortAlphabeticallyBlock & nMask);
+ }
+
+ 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))
+ {
+ const 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 = pType->IsEditable() &&
+ ((bVisible && !bProtected) || ContentTypeId::REGION == nContentType);
+ const bool bDeletable = pType->IsDeletable()
+ && ((bVisible && !bProtected && !bProtectBM) || ContentTypeId::REGION == nContentType);
+ const bool bRenamable = bEditable && !bReadonly &&
+ (ContentTypeId::TABLE == nContentType ||
+ ContentTypeId::FRAME == nContentType ||
+ ContentTypeId::GRAPHIC == nContentType ||
+ ContentTypeId::OLE == nContentType ||
+ (ContentTypeId::BOOKMARK == nContentType && !bProtectBM) ||
+ ContentTypeId::REGION == nContentType ||
+ ContentTypeId::INDEX == nContentType ||
+ ContentTypeId::DRAWOBJECT == nContentType);
+ // Choose which Delete entry to show.
+ if (bDeletable)
+ {
+ switch (nContentType)
+ {
+ case ContentTypeId::OUTLINE:
+ bRemoveDeleteChapterEntry = false;
+ break;
+ case ContentTypeId::TABLE:
+ bRemoveDeleteTableEntry = 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::INDEX:
+ bRemoveDeleteIndexEntry = false;
+ break;
+ case ContentTypeId::POSTIT:
+ bRemoveDeleteCommentEntry = false;
+ break;
+ case ContentTypeId::DRAWOBJECT:
+ bRemoveDeleteDrawingObjectEntry = false;
+ break;
+ case ContentTypeId::TEXTFIELD:
+ bRemoveDeleteFieldEntry = 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;
+ bRemoveChapterEntries = false;
+ }
+ bRemoveCopyEntry = false;
+ }
+ else if (!bReadonly && bEditable)
+ {
+ if(ContentTypeId::INDEX == nContentType)
+ {
+ bRemoveIndexEntries = false;
+
+ const SwTOXBase* pBase = weld::fromId<SwTOXBaseContent*>(m_xTreeView->get_id(*xEntry))->GetTOXBase();
+ if (!pBase->IsTOXBaseInReadonly())
+ bRemoveEditEntry = false;
+
+ xPop->set_active(OUString::number(405), SwEditShell::IsTOXBaseReadonly(*pBase));
+ }
+ else if(ContentTypeId::TABLE == nContentType)
+ {
+ bRemoveSelectEntry = false;
+ bRemoveEditEntry = false;
+ bRemoveUnprotectEntry = 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);
+ }
+ 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("protectsection", bProtected);
+ xPop->set_active("hidesection", bHidden);
+ }
+ else if (bEditable)
+ bRemoveEditEntry = false;
+ //Rename object
+ if (bRenamable)
+ bRemoveRenameEntry = false;
+ }
+ }
+ else
+ {
+ 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();
+ if (pType)
+ {
+ 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 &&
+ nContentType == ContentTypeId::POSTIT &&
+ !m_pActiveShell->GetView().GetDocShell()->IsReadOnly() &&
+ pType->GetMemberCount() > 0)
+ 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(OUString::number(600));
+ xPop->remove(OUString::number(601));
+ xPop->remove(OUString::number(602));
+ }
+
+ if (bRemoveDeleteChapterEntry)
+ xPop->remove("deletechapter");
+ if (bRemoveDeleteTableEntry)
+ xPop->remove("deletetable");
+ if (bRemoveDeleteFrameEntry)
+ xPop->remove("deleteframe");
+ if (bRemoveDeleteImageEntry)
+ xPop->remove("deleteimage");
+ if (bRemoveDeleteOLEObjectEntry)
+ xPop->remove("deleteoleobject");
+ if (bRemoveDeleteBookmarkEntry)
+ xPop->remove("deletebookmark");
+ if (bRemoveDeleteRegionEntry)
+ xPop->remove("deleteregion");
+ if (bRemoveDeleteHyperlinkEntry)
+ xPop->remove("deletehyperlink");
+ if (bRemoveDeleteReferenceEntry)
+ xPop->remove("deletereference");
+ if (bRemoveDeleteIndexEntry)
+ xPop->remove("deleteindex");
+ if (bRemoveDeleteCommentEntry)
+ xPop->remove("deletecomment");
+ if (bRemoveDeleteDrawingObjectEntry)
+ xPop->remove("deletedrawingobject");
+ if (bRemoveDeleteFieldEntry)
+ xPop->remove("deletefield");
+
+ bool bRemoveDeleteEntry =
+ bRemoveDeleteChapterEntry &&
+ bRemoveDeleteTableEntry &&
+ bRemoveDeleteFrameEntry &&
+ bRemoveDeleteImageEntry &&
+ bRemoveDeleteOLEObjectEntry &&
+ bRemoveDeleteBookmarkEntry &&
+ bRemoveDeleteRegionEntry &&
+ bRemoveDeleteHyperlinkEntry &&
+ bRemoveDeleteReferenceEntry &&
+ bRemoveDeleteIndexEntry &&
+ bRemoveDeleteCommentEntry &&
+ bRemoveDeleteDrawingObjectEntry &&
+ bRemoveDeleteFieldEntry;
+
+ if (bRemoveRenameEntry)
+ xPop->remove(OUString::number(502));
+
+ if (bRemoveIndexEntries)
+ {
+ xPop->remove(OUString::number(401));
+ xPop->remove(OUString::number(402));
+ xPop->remove(OUString::number(405));
+ }
+
+ if (bRemoveUnprotectEntry)
+ xPop->remove(OUString::number(404));
+
+ if (bRemoveEditEntry)
+ xPop->remove(OUString::number(403));
+
+ if (bRemoveToggleExpandEntry &&
+ bRemoveSendOutlineEntry)
+ xPop->remove("separator1");
+
+ if (bRemoveCopyEntry)
+ xPop->remove("copy");
+
+ if (bRemoveGotoEntry &&
+ bRemoveCopyEntry &&
+ bRemoveSelectEntry &&
+ bRemoveDeleteEntry &&
+ bRemoveChapterEntries &&
+ bRemovePostItEntries &&
+ bRemoveRenameEntry &&
+ bRemoveIndexEntries &&
+ bRemoveUnprotectEntry &&
+ bRemoveEditEntry)
+ xPop->remove("separator2");
+
+ 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("separator3");
+ }
+
+ if (bRemoveTableTracking)
+ xPop->remove("tabletracking");
+ if (bRemoveSectionTracking)
+ xPop->remove("sectiontracking");
+ if (bRemoveFrameTracking)
+ xPop->remove("frametracking");
+ if (bRemoveImageTracking)
+ xPop->remove("imagetracking");
+ if (bRemoveOLEobjectTracking)
+ xPop->remove("oleobjecttracking");
+ if (bRemoveBookmarkTracking)
+ xPop->remove("bookmarktracking");
+ if (bRemoveHyperlinkTracking)
+ xPop->remove("hyperlinktracking");
+ if (bRemoveReferenceTracking)
+ xPop->remove("referencetracking");
+ if (bRemoveIndexTracking)
+ xPop->remove("indextracking");
+ if (bRemoveCommentTracking)
+ xPop->remove("commenttracking");
+ if (bRemoveDrawingObjectTracking)
+ xPop->remove("drawingobjecttracking");
+ if (bRemoveFieldTracking)
+ xPop->remove("fieldtracking");
+ if (bRemoveFootnoteTracking)
+ xPop->remove("footnotetracking");
+ if (bRemoveEndnoteTracking)
+ xPop->remove("endnotetracking");
+ if (bRemoveSortEntry)
+ xPop->remove("sort");
+ if (bRemoveProtectSection)
+ xPop->remove("protectsection");
+ if (bRemoveHideSection)
+ xPop->remove("hidesection");
+
+ 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("collapseallcategories", 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 && !static_cast<const SwGraphicContent*>(pCnt)->GetLink().isEmpty())
+ m_xTreeView->set_image(*xChild, RID_BMP_NAVI_GRAPHIC_LINK);
+ }
+}
+
+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)
+ {
+ 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& rParentId = 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*>(rParentId)->GetType() :
+ weld::fromId<SwContent*>(rParentId)->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 = aCurrOutLineNodeMap;
+ return;
+ }
+ else // content entry
+ {
+ SwWrtShell* pShell = GetWrtShell();
+ assert(dynamic_cast<SwOutlineContent*>(weld::fromId<SwTypeNumber*>(rParentId)));
+ auto const nPos = weld::fromId<SwOutlineContent*>(rParentId)->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 = aCurrentRegionNodeExpandMap;
+ return;
+ }
+ else // content entry
+ {
+ assert(dynamic_cast<SwRegionContent*>(weld::fromId<SwTypeNumber*>(rParentId)));
+ const void* key = static_cast<const void*>(
+ weld::fromId<SwRegionContent*>(rParentId)->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 = aCurrentPostItNodeExpandMap;
+ return;
+ }
+ else // content entry
+ {
+ assert(dynamic_cast<SwPostItContent*>(weld::fromId<SwTypeNumber*>(rParentId)));
+ const void* key = static_cast<const void*>(
+ weld::fromId<SwPostItContent*>(rParentId)->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();
+ OUString sOldSelEntryId;
+ size_t nEntryRelPos = 0; // relative position to their parent
+ size_t nOldEntryCount = GetEntryCount();
+ sal_Int32 nOldScrollPos = 0;
+ if (xOldSelEntry)
+ {
+ UpdateLastSelType();
+ sOldSelEntryId = m_xTreeView->get_id(*xOldSelEntry);
+ nOldScrollPos = m_xTreeView->vadjustment_get_value();
+ 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();
+ const bool bReadOnly = !pShell || pShell->GetView().GetDocShell()->IsReadOnly();
+ if(bReadOnly != m_bIsLastReadOnly)
+ {
+ m_bIsLastReadOnly = bReadOnly;
+ bool bDisable = pShell == nullptr || bReadOnly;
+ SwNavigationPI* pNavi = GetParentWindow();
+ pNavi->m_xContent6ToolBox->set_item_sensitive("chapterup", !bDisable);
+ pNavi->m_xContent6ToolBox->set_item_sensitive("chapterdown", !bDisable);
+ pNavi->m_xContent6ToolBox->set_item_sensitive("promote", !bDisable);
+ pNavi->m_xContent6ToolBox->set_item_sensitive("demote", !bDisable);
+ pNavi->m_xContent5ToolBox->set_item_sensitive("reminder", !bDisable);
+ }
+
+ 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 (m_xTreeView->get_id(*xIter) == sOldSelEntryId || 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);
+ Select();
+ }
+ }
+
+ 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,
+ sal_Int8& rDragMode )
+{
+ bool bRet = false;
+ 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;
+ OUString sEntry;
+ assert(dynamic_cast<SwContent*>(weld::fromId<SwTypeNumber*>(m_xTreeView->get_id(*xEntry))));
+ SwContent* pCnt = weld::fromId<SwContent*>(m_xTreeView->get_id(*xEntry));
+
+ const ContentTypeId nActType = pCnt->GetParent()->GetType();
+ OUString sUrl;
+ bool bOutline = false;
+ OUString sOutlineText;
+ switch( nActType )
+ {
+ 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();
+ bOutline = true;
+ }
+ }
+ break;
+ case ContentTypeId::POSTIT:
+ case ContentTypeId::INDEX:
+ case ContentTypeId::REFERENCE :
+ case ContentTypeId::TEXTFIELD:
+ case ContentTypeId::FOOTNOTE:
+ case ContentTypeId::ENDNOTE:
+ // cannot be inserted, neither as URL nor as section
+ break;
+ case ContentTypeId::URLFIELD:
+ sUrl = static_cast<SwURLFieldContent*>(pCnt)->GetURL();
+ [[fallthrough]];
+ case ContentTypeId::OLE:
+ case ContentTypeId::GRAPHIC:
+ if(GetParentWindow()->GetRegionDropMode() != RegionMode::NONE)
+ break;
+ else
+ rDragMode &= ~( DND_ACTION_MOVE | DND_ACTION_LINK );
+ [[fallthrough]];
+ default:
+ sEntry = m_xTreeView->get_text(*xEntry);
+ }
+
+ if(!sEntry.isEmpty())
+ {
+ const SwDocShell* pDocShell = pWrtShell->GetView().GetDocShell();
+ if(sUrl.isEmpty())
+ {
+ if(pDocShell->HasName())
+ {
+ SfxMedium* pMedium = pDocShell->GetMedium();
+ sUrl = pMedium->GetURLObject().GetURLNoMark();
+ // only if a primarily link shall be integrated.
+ bRet = true;
+ }
+ else if ( nActType == ContentTypeId::REGION || nActType == ContentTypeId::BOOKMARK )
+ {
+ // For field and bookmarks a link is also allowed
+ // without a filename into its own document.
+ bRet = true;
+ }
+ else if (State::CONSTANT == m_eState &&
+ ( !::GetActiveView() ||
+ m_pActiveShell != ::GetActiveView()->GetWrtShellPtr()))
+ {
+ // Urls of inactive views cannot dragged without
+ // file names, also.
+ bRet = false;
+ }
+ else
+ {
+ bRet = GetParentWindow()->GetRegionDropMode() == RegionMode::NONE;
+ rDragMode = DND_ACTION_MOVE;
+ }
+
+ const OUString& rToken = pCnt->GetParent()->GetTypeToken();
+ sUrl += "#" + sEntry;
+ if(!rToken.isEmpty())
+ {
+ sUrl += OUStringChar(cMarkSeparator) + rToken;
+ }
+ }
+ else
+ bRet = true;
+
+ if( bRet )
+ {
+ // In Outlines of heading text must match
+ // the real number into the description.
+ if(bOutline)
+ sEntry = sOutlineText;
+
+ {
+ NaviContentBookmark aBmk( sUrl, sEntry,
+ GetParentWindow()->GetRegionDropMode(),
+ pDocShell);
+ aBmk.Copy( rTransfer );
+ }
+
+ // An INetBookmark must a be delivered to foreign DocShells
+ if( pDocShell->HasName() )
+ {
+ INetBookmark aBkmk( sUrl, sEntry );
+ rTransfer.CopyINetBookmark( aBkmk );
+ }
+ }
+ }
+ return bRet;
+}
+
+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("root", 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, "");
+ 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)
+{
+ SfxViewEventHint const*const pVEHint(dynamic_cast<SfxViewEventHint const*>(&rHint));
+ SwXTextView* pDyingShell = nullptr;
+ if (m_pActiveShell && pVEHint && pVEHint->GetEventName() == "OnViewClosed")
+ 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
+ }
+ else
+ {
+ 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);
+ Select();
+ }
+ 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();
+ for (SwOutlineNodes::size_type nPos = 0; nPos < nOutlineNdsSize; nPos++)
+ {
+ if (rOutlineNodes[nPos]->GetIndex() > nEndOfExtrasIndex)
+ {
+ nFirstRegularDocContentOutlineNodePos = nPos;
+ break;
+ }
+ }
+
+ 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)))
+ {
+ 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 (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;
+ });
+ }
+ }
+ 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->Select();
+ 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->Select();
+ 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->Select();
+ }
+ return;
+ }
+ }
+
+ rContentTree.set_cursor(-1);
+ pThis->Select();
+ 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->Select();
+ }
+ break;
+ }
+ }
+}
+
+static void lcl_SelectDrawObjectByName(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);
+ }
+ 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 ((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->GetMarkedObjectCount(); nIdx++)
+ {
+ SdrObject* pSelected = pSdrView->GetMarkedObjectByIndex(nIdx);
+ OUString aName(pSelected->GetName());
+ if (!aName.isEmpty())
+ lcl_SelectDrawObjectByName(*m_xTreeView, aName);
+ }
+ }
+ else
+ {
+ // clear treeview selections
+ m_xTreeView->unselect_all();
+ }
+ Select();
+ }
+ 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;
+ }
+ // bookmarks - track first bookmark at cursor
+ if (mTrackContentType[ContentTypeId::BOOKMARK] &&
+ (m_pActiveShell->GetSelectionType() & SelectionType::Text))
+ {
+ SwPaM* pCursor = m_pActiveShell->GetCursor();
+ IDocumentMarkAccess* const pMarkAccess = m_pActiveShell->getIDocumentMarkAccess();
+ IDocumentMarkAccess::const_iterator_t 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;
+ }
+ }
+ }
+ // 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;
+ }
+ // 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
+ }
+ }
+ // outline
+ if (m_nOutlineTracking == 3)
+ return;
+ // find out where the cursor is
+ const SwOutlineNodes::size_type nActPos = GetWrtShell()->GetOutlinePos(MAXLEVEL);
+ if (!((m_bIsRoot && m_nRootType != ContentTypeId::OUTLINE) || 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);
+ Select();
+
+ // 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;
+ });
+ }
+ else
+ {
+ // clear treeview selections
+ if (m_xTreeView->count_selected_rows() > 0)
+ {
+ m_xTreeView->unselect_all();
+ m_xTreeView->set_cursor(-1);
+ Select();
+ }
+ }
+}
+
+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;
+ });
+ }
+
+ Select();
+}
+
+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 auto& source : m_aDndOutlinesSelected)
+ {
+ SwOutlineNodes::size_type nSourcePos = weld::fromId<SwOutlineContent*>(m_xTreeView->get_id(*source))->GetOutlinePos();
+
+ // 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_xTreeView->get_selected(xEntry.get()) && 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() &&
+ !m_pActiveShell->GetView().GetDocShell()->IsReadOnly())
+ {
+ EditEntry(*xEntry, EditEntryMode::DELETE);
+ }
+ }
+ }
+ //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)
+{
+ 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)));
+ sEntry = static_cast<SwOutlineContent*>(pUserData)->GetName();
+ 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 == "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 == "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& rId(m_xTreeView->get_id(*xFirst));
+ if (lcl_IsContentType(*xFirst, *m_xTreeView))
+ pCntType = weld::fromId<SwContentType*>(rId);
+ else
+ pCntType = const_cast<SwContentType*>(weld::fromId<SwContent*>(rId)->GetParent());
+
+ // toggle and persist alphabetical sort setting
+ const int nShift = static_cast<int>(pCntType->GetType());
+ assert(nShift > -1);
+ const sal_Int32 nMask = 1 << nShift;
+ const sal_Int32 nBlock = m_pConfig->GetSortAlphabeticallyBlock();
+ pCntType->SetAlphabeticSort(~nBlock & nMask);
+ m_pConfig->SetSortAlphabeticallyBlock(nBlock ^ nMask);
+
+ 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")
+ {
+ 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 201:
+ case 202:
+ case 203:
+ GetParentWindow()->SetRegionDropMode(static_cast<RegionMode>(nSelectedPopupEntry - 201));
+ break;
+ case 401:
+ case 402:
+ EditEntry(*xFirst, nSelectedPopupEntry == 401 ? EditEntryMode::RMV_IDX : 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 600:
+ m_pActiveShell->GetView().GetPostItMgr()->Show();
+ break;
+ case 601:
+ m_pActiveShell->GetView().GetPostItMgr()->Hide();
+ break;
+ case 602:
+ {
+ m_pActiveShell->GetView().GetPostItMgr()->SetActiveSidebarWin(nullptr);
+ m_pActiveShell->GetView().GetPostItMgr()->Delete();
+ 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
+void SwContentTree::ShowActualView()
+{
+ m_eState = State::ACTIVE;
+ Display(true);
+ GetParentWindow()->UpdateListBox();
+}
+
+IMPL_LINK_NOARG(SwContentTree, SelectHdl, weld::TreeView&, void)
+{
+ if (m_pConfig->IsNavigateOnSelect())
+ {
+ ContentDoubleClickHdl(*m_xTreeView);
+ grab_focus();
+ }
+ Select();
+ 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));
+}
+
+// Here the buttons for moving outlines are en-/disabled.
+void SwContentTree::Select()
+{
+ std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
+ if (!m_xTreeView->get_selected(xEntry.get()))
+ return;
+
+ bool bEnable = false;
+ std::unique_ptr<weld::TreeIter> xParentEntry(m_xTreeView->make_iterator(xEntry.get()));
+ bool bParentEntry = m_xTreeView->iter_parent(*xParentEntry);
+ while (bParentEntry && (!lcl_IsContentType(*xParentEntry, *m_xTreeView)))
+ bParentEntry = m_xTreeView->iter_parent(*xParentEntry);
+ if (!m_bIsLastReadOnly)
+ {
+ if (!m_xTreeView->get_visible())
+ bEnable = true;
+ else if (bParentEntry)
+ {
+ if ((m_bIsRoot && m_nRootType == ContentTypeId::OUTLINE) ||
+ (lcl_IsContent(*xEntry, *m_xTreeView) &&
+ weld::fromId<SwContentType*>(m_xTreeView->get_id(*xParentEntry))->GetType() == ContentTypeId::OUTLINE))
+ {
+ bEnable = true;
+ }
+ }
+ }
+
+ SwNavigationPI* pNavi = GetParentWindow();
+ pNavi->m_xContent6ToolBox->set_item_sensitive("chapterup", bEnable);
+ pNavi->m_xContent6ToolBox->set_item_sensitive("chapterdown", bEnable);
+ pNavi->m_xContent6ToolBox->set_item_sensitive("promote", bEnable);
+ pNavi->m_xContent6ToolBox->set_item_sensitive("demote", bEnable);
+}
+
+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)
+ {
+ m_pActiveShell->StartAction();
+ OUString sTable = SwResId(STR_TABLE_NAME);
+ SwRewriter aRewriterTableName;
+ aRewriterTableName.AddRule(UndoArg1, SwResId(STR_START_QUOTE));
+ aRewriterTableName.AddRule(UndoArg2, pCnt->GetName());
+ aRewriterTableName.AddRule(UndoArg3, SwResId(STR_END_QUOTE));
+ sTable = aRewriterTableName.Apply(sTable);
+
+ SwRewriter aRewriter;
+ aRewriter.AddRule(UndoArg1, sTable);
+ m_pActiveShell->StartUndo(SwUndoId::DELETE, &aRewriter);
+ m_pActiveShell->GetView().GetViewFrame().GetDispatcher()->Execute(FN_TABLE_SELECT_ALL);
+ m_pActiveShell->DeleteRow();
+ m_pActiveShell->EndUndo();
+ m_pActiveShell->EndAction();
+ }
+ else if(nMode == EditEntryMode::RENAME)
+ {
+ uno::Reference< frame::XModel > xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
+ uno::Reference< text::XTextTablesSupplier > xTables(xModel, uno::UNO_QUERY);
+ xNameAccess = xTables->getTextTables();
+ }
+ else
+ nSlot = FN_FORMAT_TABLE_DLG;
+ break;
+
+ case ContentTypeId::GRAPHIC :
+ if(nMode == EditEntryMode::DELETE)
+ {
+ m_pActiveShell->DelRight();
+ }
+ else if(nMode == EditEntryMode::RENAME)
+ {
+ uno::Reference< frame::XModel > xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
+ uno::Reference< text::XTextGraphicObjectsSupplier > xGraphics(xModel, uno::UNO_QUERY);
+ xNameAccess = xGraphics->getGraphicObjects();
+ uno::Reference< text::XTextFramesSupplier > xFrames(xModel, uno::UNO_QUERY);
+ xSecond = xFrames->getTextFrames();
+ uno::Reference< text::XTextEmbeddedObjectsSupplier > xObjs(xModel, uno::UNO_QUERY);
+ xThird = xObjs->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)
+ {
+ uno::Reference< frame::XModel > xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
+ uno::Reference< text::XTextFramesSupplier > xFrames(xModel, uno::UNO_QUERY);
+ uno::Reference< text::XTextEmbeddedObjectsSupplier > xObjs(xModel, uno::UNO_QUERY);
+ if(ContentTypeId::FRAME == nType)
+ {
+ xNameAccess = xFrames->getTextFrames();
+ xSecond = xObjs->getEmbeddedObjects();
+ }
+ else
+ {
+ xNameAccess = xObjs->getEmbeddedObjects();
+ xSecond = xFrames->getTextFrames();
+ }
+ uno::Reference< text::XTextGraphicObjectsSupplier > xGraphics(xModel, uno::UNO_QUERY);
+ xThird = xGraphics->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));
+ uno::Reference< frame::XModel > xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
+ uno::Reference< text::XBookmarksSupplier > xBkms(xModel, uno::UNO_QUERY);
+ xNameAccess = xBkms->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)
+ {
+ uno::Reference< frame::XModel > xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
+ uno::Reference< text::XTextSectionsSupplier > xSects(xModel, uno::UNO_QUERY);
+ xNameAccess = xSects->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();
+ for (const SfxPoolItem* pItem :
+ m_pActiveShell->GetDoc()->GetAttrPool().GetItemSurrogates(RES_TXTATR_REFMARK))
+ {
+ assert(dynamic_cast<const SwFormatRefMark*>(pItem));
+ const auto pFormatRefMark = static_cast<const SwFormatRefMark*>(pItem);
+ if (!pFormatRefMark)
+ continue;
+ const SwTextRefMark* pTextRef = pFormatRefMark->GetTextRefMark();
+ if (pTextRef && &pTextRef->GetTextNode().GetNodes() ==
+ &m_pActiveShell->GetNodes() && rName == pFormatRefMark->GetRefName())
+ {
+ m_pActiveShell->GetDoc()->DeleteFormatRefMark(pFormatRefMark);
+ m_pActiveShell->SwViewShell::UpdateFields();
+ break;
+ }
+ }
+ }
+ }
+ 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::RMV_IDX:
+ case EditEntryMode::DELETE:
+ {
+ if( pBase )
+ m_pActiveShell->DeleteTOX(*pBase, EditEntryMode::DELETE == nMode);
+ }
+ break;
+ case EditEntryMode::UPD_IDX:
+ case EditEntryMode::RENAME:
+ {
+ Reference< frame::XModel > xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
+ Reference< XDocumentIndexesSupplier > xIndexes(xModel, UNO_QUERY);
+ Reference< XIndexAccess> xIdxAcc(xIndexes->getDocumentIndexes());
+ Reference< XNameAccess >xLocalNameAccess(xIdxAcc, UNO_QUERY);
+ if(EditEntryMode::RENAME == nMode)
+ xNameAccess = 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 (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);
+ }
+}
+
+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<std::unique_ptr<SwPosition>> oPosition;
+ if (m_bSelectTo)
+ oPosition.emplace(new SwPosition(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.
+ uno::Reference< frame::XModel > 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("NavigatorDeck"))
+ break;
+
+ Reference<ui::XDeck> xDeck ( xDecks->getByName("NavigatorDeck"), uno::UNO_QUERY);
+ if ( !xDeck.is() )
+ break;
+
+ Reference<ui::XPanels> xPanels = xDeck->getPanels();
+ if ( !xPanels.is() )
+ break;
+
+ if (xPanels->hasByName("SwNavigatorPanel"))
+ {
+ Reference<ui::XPanel> xPanel ( xPanels->getByName("SwNavigatorPanel"), 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, true, 1, false);
+ m_pActiveShell->SwCursorShell::SelectTextAttr( RES_TXTATR_INETFMT, true );
+ }
+ }
+ 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.value()->nNode;
+ m_pActiveShell->GetCursor()->GetMark()->nContent = oPosition.value()->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);
+ }
+ }
+}
+
+// Now even the matching text::Bookmark
+NaviContentBookmark::NaviContentBookmark()
+ :
+ m_nDocSh(0),
+ m_nDefaultDrag( RegionMode::NONE )
+{
+}
+
+NaviContentBookmark::NaviContentBookmark( OUString aUrl,
+ OUString aDesc,
+ RegionMode nDragType,
+ const SwDocShell* pDocSh ) :
+ m_aUrl(std::move( aUrl )),
+ m_aDescription(std::move(aDesc)),
+ m_nDocSh(reinterpret_cast<sal_IntPtr>(pDocSh)),
+ m_nDefaultDrag( nDragType )
+{
+}
+
+void NaviContentBookmark::Copy( TransferDataContainer& rData ) const
+{
+ rtl_TextEncoding eSysCSet = osl_getThreadTextEncoding();
+
+ OString sStrBuf(OUStringToOString(m_aUrl, eSysCSet) + OStringChar(NAVI_BOOKMARK_DELIM) +
+ OUStringToOString(m_aDescription, eSysCSet) + OStringChar(NAVI_BOOKMARK_DELIM) +
+ OString::number(static_cast<int>(m_nDefaultDrag)) + 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_aUrl = sStr.getToken(0, NAVI_BOOKMARK_DELIM, nPos );
+ m_aDescription = sStr.getToken(0, NAVI_BOOKMARK_DELIM, nPos );
+ m_nDefaultDrag= static_cast<RegionMode>( o3tl::toInt32(o3tl::getToken(sStr, 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);
+ Select();
+ 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)});
+ break;
+ }
+ }
+ }
+ }
+ 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;
+ for (const SfxPoolItem* pItem :
+ m_pActiveShell->GetAttrPool().GetItemSurrogates(RES_TXTATR_REFMARK))
+ {
+ if (const auto pRefMark = dynamic_cast<const SwFormatRefMark*>(pItem))
+ {
+ const SwTextRefMark* pTextRef = pRefMark->GetTextRefMark();
+ if (pTextRef && &pTextRef->GetTextNode().GetNodes() ==
+ &m_pActiveShell->GetNodes())
+ aTextAttrArr.push_back(pTextRef);
+ }
+ }
+ 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)
+ {
+ IDocumentMarkAccess::const_iterator_t 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::IMark* 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: */
diff --git a/sw/source/uibase/utlui/glbltree.cxx b/sw/source/uibase/utlui/glbltree.cxx
new file mode 100644
index 0000000000..4ddf32dd02
--- /dev/null
+++ b/sw/source/uibase/utlui/glbltree.cxx
@@ -0,0 +1,1185 @@
+/* -*- 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 <o3tl/safeint.hxx>
+#include <svl/stritem.hxx>
+#include <sfx2/fcontnr.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/docfilt.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+#include <sot/filelist.hxx>
+#include <svl/eitem.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <osl/diagnose.h>
+
+#include <sfx2/docinsert.hxx>
+#include <sfx2/filedlghelper.hxx>
+
+#include <wrtsh.hxx>
+#include <view.hxx>
+#include <docsh.hxx>
+#include <edglbldc.hxx>
+#include <section.hxx>
+#include <tox.hxx>
+#include <navipi.hxx>
+#include <edtwin.hxx>
+#include <toxmgr.hxx>
+
+#include <cmdid.h>
+#include <helpids.h>
+#include <strings.hrc>
+#include <bitmaps.hlst>
+#include <swabstdlg.hxx>
+#include <memory>
+
+#include <sfx2/event.hxx>
+#include <unotxvw.hxx>
+
+using namespace ::com::sun::star::uno;
+
+#define GLOBAL_UPDATE_TIMEOUT 2000
+
+const SfxObjectShell* SwGlobalTree::s_pShowShell = nullptr;
+
+namespace {
+
+class SwGlobalFrameListener_Impl : public SfxListener
+{
+ bool m_bValid;
+public:
+ explicit SwGlobalFrameListener_Impl(SfxViewFrame& rFrame)
+ : m_bValid(true)
+ {
+ StartListening(rFrame);
+ }
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ bool IsValid() const {return m_bValid;}
+};
+
+}
+
+void SwGlobalFrameListener_Impl::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
+{
+ if( rHint.GetId() == SfxHintId::Dying)
+ m_bValid = false;
+}
+
+namespace {
+
+enum GLOBAL_CONTEXT_IDX
+{
+ IDX_STR_UPDATE = 0,
+ IDX_STR_EDIT_CONTENT = 1,
+ IDX_STR_EDIT_INSERT = 2,
+ IDX_STR_INDEX = 3,
+ IDX_STR_FILE = 4,
+ IDX_STR_NEW_FILE = 5,
+ IDX_STR_INSERT_TEXT = 6,
+ IDX_STR_DELETE = 7,
+ IDX_STR_UPDATE_SEL = 8,
+ IDX_STR_UPDATE_INDEX = 9,
+ IDX_STR_UPDATE_LINK = 10,
+ IDX_STR_UPDATE_ALL = 11,
+ IDX_STR_BROKEN_LINK = 12,
+ IDX_STR_EDIT_LINK = 13
+};
+
+}
+
+const TranslateId GLOBAL_CONTEXT_ARY[] =
+{
+ STR_UPDATE,
+ STR_EDIT_CONTENT,
+ STR_EDIT_INSERT,
+ STR_INDEX,
+ STR_FILE,
+ STR_NEW_FILE,
+ STR_INSERT_TEXT,
+ STR_DELETE,
+ STR_UPDATE_SEL,
+ STR_UPDATE_INDEX,
+ STR_UPDATE_LINK,
+ STR_UPDATE_ALL,
+ STR_BROKEN_LINK,
+ STR_EDIT_LINK
+};
+
+SwGlobalTree::SwGlobalTree(std::unique_ptr<weld::TreeView> xTreeView, SwNavigationPI* pDialog)
+ : m_xTreeView(std::move(xTreeView))
+ , m_aDropTargetHelper(*this)
+ , m_pDialog(pDialog)
+ , m_aUpdateTimer("SwGlobalTree m_aUpdateTimer")
+ , m_pActiveShell(nullptr)
+{
+ m_xTreeView->set_size_request(m_xTreeView->get_approximate_digit_width() * 30,
+ m_xTreeView->get_text_height() * 14);
+
+ m_aUpdateTimer.SetTimeout(GLOBAL_UPDATE_TIMEOUT);
+ m_aUpdateTimer.SetInvokeHandler(LINK(this, SwGlobalTree, Timeout));
+ m_aUpdateTimer.Start();
+ for (sal_uInt16 i = 0; i < GLOBAL_CONTEXT_COUNT; i++)
+ {
+ m_aContextStrings[i] = SwResId(GLOBAL_CONTEXT_ARY[i]);
+ }
+ m_xTreeView->set_help_id(HID_NAVIGATOR_GLOB_TREELIST);
+ Select();
+ m_xTreeView->connect_row_activated(LINK(this, SwGlobalTree, DoubleClickHdl));
+ m_xTreeView->connect_changed(LINK(this, SwGlobalTree, SelectHdl));
+ m_xTreeView->connect_focus_in(LINK(this, SwGlobalTree, FocusInHdl));
+ m_xTreeView->connect_key_press(LINK(this, SwGlobalTree, KeyInputHdl));
+ m_xTreeView->connect_popup_menu(LINK(this, SwGlobalTree, CommandHdl));
+ m_xTreeView->connect_query_tooltip(LINK(this, SwGlobalTree, QueryTooltipHdl));
+}
+
+SwGlobalTree::~SwGlobalTree()
+{
+ m_pSwGlblDocContents.reset();
+ m_pDocInserter.reset();
+ m_aUpdateTimer.Stop();
+}
+
+SwGlobalTreeDropTarget::SwGlobalTreeDropTarget(SwGlobalTree& rTreeView)
+ : DropTargetHelper(rTreeView.get_widget().get_drop_target())
+ , m_rTreeView(rTreeView)
+{
+}
+
+sal_Int8 SwGlobalTreeDropTarget::ExecuteDrop( const ExecuteDropEvent& rEvt )
+{
+ sal_Int8 nRet = DND_ACTION_NONE;
+
+ weld::TreeView& rWidget = m_rTreeView.get_widget();
+ std::unique_ptr<weld::TreeIter> xDropEntry(rWidget.make_iterator());
+ if (!rWidget.get_dest_row_at_pos(rEvt.maPosPixel, xDropEntry.get(), true))
+ xDropEntry.reset();
+
+ if (rWidget.get_drag_source() == &rWidget) // internal drag
+ m_rTreeView.MoveSelectionTo(xDropEntry.get());
+ else
+ {
+ TransferableDataHelper aData( rEvt.maDropEvent.Transferable );
+
+ OUString sFileName;
+ const SwGlblDocContent* pCnt = xDropEntry ?
+ weld::fromId<const SwGlblDocContent*>(rWidget.get_id(*xDropEntry)) :
+ nullptr;
+ if( aData.HasFormat( SotClipboardFormatId::FILE_LIST ))
+ {
+ nRet = rEvt.mnAction;
+ SwGlblDocContents aTempContents;
+ int nAbsContPos = xDropEntry ?
+ rWidget.get_iter_index_in_parent(*xDropEntry):
+ - 1;
+ size_t nEntryCount = rWidget.n_children();
+
+ // Get data
+ FileList aFileList;
+ aData.GetFileList( SotClipboardFormatId::FILE_LIST, aFileList );
+ for ( size_t n = aFileList.Count(); n--; )
+ {
+ sFileName = aFileList.GetFile(n);
+ m_rTreeView.InsertRegion(pCnt, &sFileName);
+ // The list of contents must be newly fetched after inserting,
+ // to not work on an old content.
+ if(n)
+ {
+ if (const SwWrtShell* pSh = m_rTreeView.GetActiveWrtShell())
+ {
+ pSh->GetGlobalDocContent(aTempContents);
+ // If the file was successfully inserted,
+ // then the next content must also be fetched.
+ if(nEntryCount < aTempContents.size())
+ {
+ nEntryCount++;
+ nAbsContPos++;
+ pCnt = aTempContents[ nAbsContPos ].get();
+ }
+ }
+ }
+ }
+ }
+ else if( !(sFileName =
+ SwNavigationPI::CreateDropFileName( aData )).isEmpty())
+ {
+ INetURLObject aTemp(sFileName);
+ GraphicDescriptor aDesc(aTemp);
+ if( !aDesc.Detect() ) // accept no graphics
+ {
+ nRet = rEvt.mnAction;
+ m_rTreeView.InsertRegion(pCnt, &sFileName);
+ }
+ }
+ }
+ return nRet;
+}
+
+sal_Int8 SwGlobalTreeDropTarget::AcceptDrop( const AcceptDropEvent& rEvt )
+{
+ // 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);
+
+ sal_Int8 nRet = rEvt.mnAction;
+
+ if (rWidget.get_drag_source() == &rWidget) // internal drag
+ return nRet;
+
+ if (IsDropFormatSupported( SotClipboardFormatId::SIMPLE_FILE) ||
+ IsDropFormatSupported( SotClipboardFormatId::STRING) ||
+ IsDropFormatSupported( SotClipboardFormatId::FILE_LIST) ||
+ IsDropFormatSupported( SotClipboardFormatId::SOLK) ||
+ IsDropFormatSupported( SotClipboardFormatId::NETSCAPE_BOOKMARK )||
+ IsDropFormatSupported( SotClipboardFormatId::FILECONTENT) ||
+ IsDropFormatSupported( SotClipboardFormatId::FILEGRPDESCRIPTOR) ||
+ IsDropFormatSupported( SotClipboardFormatId::UNIFORMRESOURCELOCATOR) ||
+ IsDropFormatSupported( SotClipboardFormatId::FILENAME))
+ {
+ nRet = DND_ACTION_LINK;
+ }
+
+ return nRet;
+}
+
+IMPL_LINK(SwGlobalTree, CommandHdl, const CommandEvent&, rCEvt, bool)
+{
+ if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
+ return false;
+
+ bool bPop = false;
+ if (m_pActiveShell && !m_pActiveShell->GetView().GetDocShell()->IsReadOnly())
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xTreeView.get(), "modules/swriter/ui/mastercontextmenu.ui"));
+ std::unique_ptr<weld::Menu> xPopup = xBuilder->weld_menu("navmenu");
+ std::unique_ptr<weld::Menu> xSubPopup = xBuilder->weld_menu("insertmenu");
+
+ const MenuEnableFlags nEnableFlags = GetEnableFlags();
+
+ xPopup->set_sensitive("updatesel", bool(nEnableFlags & MenuEnableFlags::UpdateSel));
+
+ xPopup->set_sensitive("editlink", bool(nEnableFlags & MenuEnableFlags::EditLink));
+
+ //disabling if applicable
+ xSubPopup->set_sensitive("insertindex", bool(nEnableFlags & MenuEnableFlags::InsertIdx ));
+ xSubPopup->set_sensitive("insertfile", bool(nEnableFlags & MenuEnableFlags::InsertFile));
+ xSubPopup->set_sensitive("insertnewfile", bool(nEnableFlags & MenuEnableFlags::InsertFile));
+ xSubPopup->set_sensitive("inserttext", bool(nEnableFlags & MenuEnableFlags::InsertText));
+
+ xPopup->set_sensitive("update", bool(nEnableFlags & MenuEnableFlags::Update));
+ xPopup->set_sensitive("insert", bool(nEnableFlags & MenuEnableFlags::InsertIdx));
+ xPopup->set_sensitive("editcontent", bool(nEnableFlags & MenuEnableFlags::Edit));
+ xPopup->set_sensitive("deleteentry", bool(nEnableFlags & MenuEnableFlags::Delete));
+
+ OUString sCommand = xPopup->popup_at_rect(m_xTreeView.get(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1)));
+ if (!sCommand.isEmpty())
+ ExecuteContextMenuAction(sCommand);
+
+ bPop = true;
+ }
+ return bPop;
+}
+
+void SwGlobalTree::TbxMenuHdl(std::u16string_view rCommand, weld::Menu& rMenu)
+{
+ const MenuEnableFlags nEnableFlags = GetEnableFlags();
+ if (rCommand == u"insert")
+ {
+ rMenu.set_sensitive("insertindex", bool(nEnableFlags & MenuEnableFlags::InsertIdx));
+ rMenu.set_sensitive("insertfile", bool(nEnableFlags & MenuEnableFlags::InsertFile));
+ rMenu.set_sensitive("insertnewfile", bool(nEnableFlags & MenuEnableFlags::InsertFile));
+ rMenu.set_sensitive("inserttext", bool(nEnableFlags & MenuEnableFlags::InsertText));
+ }
+ else if (rCommand == u"update")
+ {
+ rMenu.set_sensitive("updatesel", bool(nEnableFlags & MenuEnableFlags::UpdateSel));
+ }
+}
+
+MenuEnableFlags SwGlobalTree::GetEnableFlags() const
+{
+ std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
+ bool bEntry = m_xTreeView->get_selected(xEntry.get());
+
+ int nSelCount = m_xTreeView->count_selected_rows();
+ size_t nEntryCount = m_xTreeView->n_children();
+ std::unique_ptr<weld::TreeIter> xPrevEntry;
+ bool bPrevEntry = false;
+ if (bEntry)
+ {
+ xPrevEntry = m_xTreeView->make_iterator(xEntry.get());
+ bPrevEntry = m_xTreeView->iter_previous(*xPrevEntry);
+ }
+
+ MenuEnableFlags nRet = MenuEnableFlags::NONE;
+ if(nSelCount == 1 || !nEntryCount)
+ nRet |= MenuEnableFlags::InsertIdx|MenuEnableFlags::InsertFile;
+ if(nSelCount == 1)
+ {
+ nRet |= MenuEnableFlags::Edit;
+ if (bEntry && weld::fromId<SwGlblDocContent*>(m_xTreeView->get_id(*xEntry))->GetType() != GLBLDOC_UNKNOWN &&
+ (!bPrevEntry || weld::fromId<SwGlblDocContent*>(m_xTreeView->get_id(*xPrevEntry))->GetType() != GLBLDOC_UNKNOWN))
+ nRet |= MenuEnableFlags::InsertText;
+ if (bEntry && GLBLDOC_SECTION == weld::fromId<SwGlblDocContent*>(m_xTreeView->get_id(*xEntry))->GetType())
+ nRet |= MenuEnableFlags::EditLink;
+ }
+ else if(!nEntryCount)
+ {
+ nRet |= MenuEnableFlags::InsertText;
+ }
+ if(nEntryCount)
+ nRet |= MenuEnableFlags::Update|MenuEnableFlags::Delete;
+ if(nSelCount)
+ nRet |= MenuEnableFlags::UpdateSel;
+ return nRet;
+}
+
+IMPL_LINK(SwGlobalTree, QueryTooltipHdl, const weld::TreeIter&, rIter, OUString)
+{
+ OUString sEntry;
+
+ const SwGlblDocContent* pCont = weld::fromId<const SwGlblDocContent*>(m_xTreeView->get_id(rIter));
+ if (pCont && GLBLDOC_SECTION == pCont->GetType())
+ {
+ const SwSection* pSect = pCont->GetSection();
+ sEntry = pSect->GetLinkFileName().getToken(0, sfx2::cTokenSeparator);
+ if (!pSect->IsConnectFlag())
+ sEntry = m_aContextStrings[IDX_STR_BROKEN_LINK] + sEntry;
+ }
+
+ return sEntry;
+}
+
+IMPL_LINK_NOARG(SwGlobalTree, SelectHdl, weld::TreeView&, void)
+{
+ Select();
+}
+
+void SwGlobalTree::Select()
+{
+ int nSelCount = m_xTreeView->count_selected_rows();
+ int nSel = m_xTreeView->get_selected_index();
+ int nAbsPos = nSel != -1 ? nSel : 0;
+ SwNavigationPI* pNavi = GetParentWindow();
+ bool bReadonly = !m_pActiveShell ||
+ m_pActiveShell->GetView().GetDocShell()->IsReadOnly();
+ pNavi->m_xGlobalToolBox->set_item_sensitive("edit", nSelCount == 1 && !bReadonly);
+ pNavi->m_xGlobalToolBox->set_item_sensitive("insert", nSelCount <= 1 && !bReadonly);
+ pNavi->m_xGlobalToolBox->set_item_sensitive("update", m_xTreeView->n_children() > 0 && !bReadonly);
+ pNavi->m_xGlobalToolBox->set_item_sensitive("moveup",
+ nSelCount == 1 && nAbsPos && !bReadonly);
+ pNavi->m_xGlobalToolBox->set_item_sensitive("movedown",
+ nSelCount == 1 && nAbsPos < m_xTreeView->n_children() - 1 && !bReadonly);
+
+}
+
+void SwGlobalTree::MoveSelectionTo(const weld::TreeIter* pDropEntry)
+{
+ int nSource = m_xTreeView->get_selected_index();
+
+ int nDest = pDropEntry ? m_xTreeView->get_iter_index_in_parent(*pDropEntry)
+ : m_pSwGlblDocContents->size();
+
+ if (m_pActiveShell->MoveGlobalDocContent(
+ *m_pSwGlblDocContents, nSource, nSource + 1, nDest ) &&
+ Update( false ))
+ Display();
+}
+
+IMPL_LINK_NOARG(SwGlobalTree, FocusInHdl, weld::Widget&, void)
+{
+ if (Update(false))
+ Display();
+}
+
+IMPL_LINK(SwGlobalTree, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ bool bHandled = false;
+ const vcl::KeyCode aCode = rKEvt.GetKeyCode();
+ if (aCode.GetCode() == KEY_RETURN)
+ {
+ switch (aCode.GetModifier())
+ {
+ case KEY_MOD2:
+ // Switch boxes
+ GetParentWindow()->ToggleTree();
+ bHandled = true;
+ break;
+ }
+ }
+ return bHandled;
+}
+
+void SwGlobalTree::Display(bool bOnlyUpdateUserData)
+{
+ size_t nCount = m_pSwGlblDocContents->size();
+ size_t nChildren = m_xTreeView->n_children();
+ if (bOnlyUpdateUserData && nChildren == m_pSwGlblDocContents->size())
+ {
+ std::unique_ptr<weld::TreeIter> xEntry = m_xTreeView->make_iterator();
+ bool bEntry = m_xTreeView->get_iter_first(*xEntry);
+ for (size_t i = 0; i < nCount && bEntry; i++)
+ {
+ const SwGlblDocContent* pCont = (*m_pSwGlblDocContents)[i].get();
+ OUString sId(weld::toId(pCont));
+ m_xTreeView->set_id(*xEntry, sId);
+ if (pCont->GetType() == GLBLDOC_SECTION && !pCont->GetSection()->IsConnectFlag())
+ m_xTreeView->set_font_color(*xEntry, COL_LIGHTRED);
+ else
+ m_xTreeView->set_font_color(*xEntry, COL_AUTO);
+ bEntry = m_xTreeView->iter_next(*xEntry);
+ assert(bEntry || i == nCount - 1);
+ }
+ }
+ else
+ {
+ int nOldSelEntry = m_xTreeView->get_selected_index();
+ OUString sEntryName; // Name of the entry
+ int nSelPos = -1;
+ if (nOldSelEntry != -1)
+ {
+ sEntryName = m_xTreeView->get_text(nOldSelEntry);
+ nSelPos = nOldSelEntry;
+ }
+ m_xTreeView->freeze();
+ m_xTreeView->clear();
+
+ int nSelEntry = -1;
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ const SwGlblDocContent* pCont = (*m_pSwGlblDocContents)[i].get();
+
+ OUString sId(weld::toId(pCont));
+ OUString sEntry;
+ OUString aImage;
+ switch (pCont->GetType())
+ {
+ case GLBLDOC_UNKNOWN:
+ sEntry = m_aContextStrings[IDX_STR_INSERT_TEXT];
+ break;
+ case GLBLDOC_TOXBASE:
+ {
+ const SwTOXBase* pBase = pCont->GetTOX();
+ sEntry = pBase->GetTitle();
+ aImage = RID_BMP_NAVI_INDEX;
+ }
+ break;
+ case GLBLDOC_SECTION:
+ {
+ const SwSection* pSect = pCont->GetSection();
+ sEntry = pSect->GetSectionName();
+ aImage = RID_BMP_DROP_REGION;
+ }
+ break;
+ }
+
+ m_xTreeView->append(sId, sEntry);
+ if (!aImage.isEmpty())
+ m_xTreeView->set_image(i, aImage);
+
+ if (pCont->GetType() == GLBLDOC_SECTION && !pCont->GetSection()->IsConnectFlag())
+ m_xTreeView->set_font_color(i, COL_LIGHTRED);
+
+ if (sEntry == sEntryName)
+ nSelEntry = i;
+ }
+ m_xTreeView->thaw();
+ if (nSelEntry != -1)
+ m_xTreeView->select(nSelEntry);
+ else if (nSelPos != -1 && o3tl::make_unsigned(nSelPos) < nCount)
+ m_xTreeView->select(nSelPos);
+ else if (nCount)
+ m_xTreeView->select(0);
+ Select();
+ }
+}
+
+void SwGlobalTree::InsertRegion( const SwGlblDocContent* pCont, const OUString* pFileName )
+{
+ Sequence< OUString > aFileNames;
+ if ( !pFileName )
+ {
+ SwNavigationPI* pNavi = GetParentWindow();
+ m_pDocInserter.reset(new ::sfx2::DocumentInserter(pNavi->GetFrameWeld(), "swriter", sfx2::DocumentInserter::Mode::InsertMulti));
+ m_pDocInserter->StartExecuteModal( LINK( this, SwGlobalTree, DialogClosedHdl ) );
+ }
+ else if ( !pFileName->isEmpty() )
+ {
+ aFileNames.realloc(1);
+ INetURLObject aFileName;
+ aFileName.SetSmartURL( *pFileName );
+ // tdf#127978 - don't URL encode filename for navigator's tooltip
+ aFileNames.getArray()[0]
+ = aFileName.GetMainURL(INetURLObject::DecodeMechanism::Unambiguous);
+ InsertRegion( pCont, aFileNames );
+ }
+}
+
+void SwGlobalTree::EditContent(const SwGlblDocContent* pCont )
+{
+ sal_uInt16 nSlot = 0;
+ switch( pCont->GetType() )
+ {
+ case GLBLDOC_UNKNOWN:
+ m_pActiveShell->GetView().GetEditWin().GrabFocus();
+ break;
+ case GLBLDOC_TOXBASE:
+ {
+ const SwTOXBase* pBase = pCont->GetTOX();
+ if(pBase)
+ nSlot = FN_INSERT_MULTI_TOX;
+ }
+ break;
+ case GLBLDOC_SECTION:
+ {
+ OpenDoc(pCont);
+
+ nSlot = 0;
+ pCont = nullptr;
+ }
+ break;
+ }
+ if(pCont)
+ GotoContent(pCont);
+ if(nSlot)
+ {
+ m_pActiveShell->GetView().GetViewFrame().GetDispatcher()->Execute(nSlot);
+ if(Update( false ))
+ Display();
+ }
+}
+
+void SwGlobalTree::ExecuteContextMenuAction(std::u16string_view rSelectedPopupEntry)
+{
+ bool bUpdateHard = false;
+
+ int nEntry = m_xTreeView->get_selected_index();
+ SwGlblDocContent* pCont = nEntry != -1 ? weld::fromId<SwGlblDocContent*>(m_xTreeView->get_id(nEntry)) : nullptr;
+ // If a RequestHelp is called during the dialogue,
+ // then the content gets lost. Because of that a copy
+ // is created in which only the DocPos is set correctly.
+ std::optional<SwGlblDocContent> oContCopy;
+ if(pCont)
+ oContCopy.emplace(pCont->GetDocPos());
+ SfxDispatcher& rDispatch = *m_pActiveShell->GetView().GetViewFrame().GetDispatcher();
+ sal_uInt16 nSlot = 0;
+ if (rSelectedPopupEntry == u"updatesel")
+ {
+ // Two passes: first update the areas, then the directories.
+ m_xTreeView->selected_foreach([this](weld::TreeIter& rSelEntry){
+ SwGlblDocContent* pContent = weld::fromId<SwGlblDocContent*>(m_xTreeView->get_id(rSelEntry));
+ if (GLBLDOC_SECTION == pContent->GetType() &&
+ pContent->GetSection()->IsConnected())
+ {
+ const_cast<SwSection*>(pContent->GetSection())->UpdateNow();
+ }
+ return false;
+ });
+ m_xTreeView->selected_foreach([this](weld::TreeIter& rSelEntry){
+ SwGlblDocContent* pContent = weld::fromId<SwGlblDocContent*>(m_xTreeView->get_id(rSelEntry));
+ if (GLBLDOC_TOXBASE == pContent->GetType())
+ m_pActiveShell->UpdateTableOf(*pContent->GetTOX());
+ return false;
+ });
+
+ bUpdateHard = true;
+ }
+ else if (rSelectedPopupEntry == u"updateindex")
+ {
+ nSlot = FN_UPDATE_TOX;
+ bUpdateHard = true;
+ }
+ else if (rSelectedPopupEntry == u"updatelinks" || rSelectedPopupEntry == u"updateall")
+ {
+ m_pActiveShell->GetLinkManager().UpdateAllLinks(true, false, nullptr);
+ if (rSelectedPopupEntry == u"updateall")
+ nSlot = FN_UPDATE_TOX;
+ pCont = nullptr;
+ bUpdateHard = true;
+ }
+ else if (rSelectedPopupEntry == u"editcontent")
+ {
+ OSL_ENSURE(pCont, "edit without entry ? " );
+ if (pCont)
+ {
+ EditContent(pCont);
+ }
+ }
+ else if (rSelectedPopupEntry == u"editlink")
+ {
+ OSL_ENSURE(pCont, "edit without entry ? " );
+ if (pCont)
+ {
+ SfxStringItem aName(FN_EDIT_REGION,
+ pCont->GetSection()->GetSectionName());
+ rDispatch.ExecuteList(FN_EDIT_REGION, SfxCallMode::ASYNCHRON,
+ { &aName });
+ }
+ }
+ else if (rSelectedPopupEntry == u"deleteentry")
+ {
+ // If several entries selected, then after each delete the array
+ // must be refilled. So you do not have to remember anything,
+ // deleting begins at the end.
+ std::vector<int> aRows = m_xTreeView->get_selected_rows();
+ std::sort(aRows.begin(), aRows.end());
+
+ std::unique_ptr<SwGlblDocContents> pTempContents;
+ m_pActiveShell->StartAction();
+ for (auto iter = aRows.rbegin(); iter != aRows.rend(); ++iter)
+ {
+ m_pActiveShell->DeleteGlobalDocContent(
+ pTempContents ? *pTempContents : *m_pSwGlblDocContents,
+ *iter);
+ pTempContents.reset(new SwGlblDocContents);
+ m_pActiveShell->GetGlobalDocContent(*pTempContents);
+ }
+ pTempContents.reset();
+ m_pActiveShell->EndAction();
+ pCont = nullptr;
+ }
+ else if (rSelectedPopupEntry == u"insertindex")
+ {
+ if(oContCopy)
+ {
+ SfxItemSetFixed<
+ RES_FRM_SIZE, RES_FRM_SIZE,
+ RES_LR_SPACE, RES_LR_SPACE,
+ RES_BACKGROUND, RES_BACKGROUND,
+ RES_COL, RES_COL,
+ SID_ATTR_PAGE_SIZE, SID_ATTR_PAGE_SIZE,
+ FN_PARAM_TOX_TYPE, FN_PARAM_TOX_TYPE>
+ aSet( m_pActiveShell->GetView().GetPool() );
+
+ SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractMultiTOXTabDialog> pDlg(pFact->CreateMultiTOXTabDialog(
+ m_xTreeView.get(), aSet,
+ *m_pActiveShell,
+ nullptr,
+ true));
+ if(RET_OK == pDlg->Execute())
+ {
+ SwTOXDescription& rDesc = pDlg->GetTOXDescription(
+ pDlg->GetCurrentTOXType());
+ SwTOXMgr aMgr(m_pActiveShell);
+ SwTOXBase* pToInsert = nullptr;
+ if(aMgr.UpdateOrInsertTOX(rDesc, &pToInsert, pDlg->GetOutputItemSet()))
+ m_pActiveShell->InsertGlobalDocContent( *oContCopy, *pToInsert );
+ }
+ pCont = nullptr;
+ }
+ }
+ else if (rSelectedPopupEntry == u"insertfile")
+ {
+ m_oDocContent = std::move(oContCopy);
+ InsertRegion( &*m_oDocContent );
+ pCont = nullptr;
+ }
+ else if (rSelectedPopupEntry == u"insertnewfile")
+ {
+ SfxViewFrame& rGlobFrame = m_pActiveShell->GetView().GetViewFrame();
+ SwGlobalFrameListener_Impl aFrameListener(rGlobFrame);
+
+ // Creating a new doc
+ SfxStringItem aFactory(SID_NEWDOCDIRECT,
+ SwDocShell::Factory().GetFilterContainer()->GetName());
+
+ SfxPoolItemHolder aResult(
+ rDispatch.ExecuteList(SID_NEWDOCDIRECT,
+ SfxCallMode::SYNCHRON, { &aFactory }));
+ const SfxFrameItem* pItem(static_cast<const SfxFrameItem*>(aResult.getItem()));
+
+ // save at
+ SfxFrame* pFrame = pItem ? pItem->GetFrame() : nullptr;
+ SfxViewFrame* pViewFrame = pFrame ? pFrame->GetCurrentViewFrame() : nullptr;
+ if (pViewFrame)
+ {
+ aResult = pViewFrame->GetDispatcher()->Execute(
+ SID_SAVEASDOC, SfxCallMode::SYNCHRON );
+ const SfxBoolItem* pBool(static_cast<const SfxBoolItem*>(aResult.getItem()));
+ SfxObjectShell& rObj = *pViewFrame->GetObjectShell();
+ const SfxMedium* pMedium = rObj.GetMedium();
+ OUString sNewFile(pMedium->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::ToIUri));
+ // Insert the area with the Doc-Name
+ // Bring the own Doc in the foreground
+ if(aFrameListener.IsValid() && !sNewFile.isEmpty())
+ {
+ rGlobFrame.ToTop();
+ // Due to the update the entries are invalid
+ if (nEntry != -1)
+ {
+ Update( false );
+ Display();
+ m_xTreeView->select(nEntry);
+ Select();
+ nEntry = m_xTreeView->get_selected_index();
+ pCont = nEntry != -1 ? weld::fromId<SwGlblDocContent*>(m_xTreeView->get_id(nEntry)) : nullptr;
+ }
+ else
+ {
+ nEntry = -1;
+ pCont = nullptr;
+ }
+ if(pBool->GetValue())
+ {
+ InsertRegion(pCont, &sNewFile);
+ pViewFrame->ToTop();
+ }
+ else
+ pViewFrame->GetDispatcher()->Execute(SID_CLOSEWIN, SfxCallMode::SYNCHRON);
+ }
+ else
+ {
+ pViewFrame->ToTop();
+ return;
+ }
+ }
+ }
+ else if (rSelectedPopupEntry == u"inserttext")
+ {
+ if (pCont)
+ m_pActiveShell->InsertGlobalDocContent(*pCont);
+ else
+ {
+ m_pActiveShell->SplitNode(); // Empty document
+ m_pActiveShell->Up( false );
+ }
+ m_pActiveShell->GetView().GetEditWin().GrabFocus();
+ }
+ else if (rSelectedPopupEntry == u"update")
+ pCont = nullptr;
+
+ if (pCont)
+ GotoContent(pCont);
+ if (nSlot)
+ rDispatch.Execute(nSlot);
+ if (Update(bUpdateHard))
+ Display();
+}
+
+IMPL_LINK_NOARG(SwGlobalTree, Timeout, Timer *, void)
+{
+ SwView* pView = GetParentWindow()->GetCreateView();
+ if (pView && pView->GetEditWin().HasFocus())
+ {
+ if (Update(false))
+ Display();
+ UpdateTracking();
+ }
+}
+
+// track GlobalDocContentType at the cursor position in the document
+void SwGlobalTree::UpdateTracking()
+{
+ if (!m_pActiveShell)
+ return;
+
+ m_xTreeView->unselect_all();
+
+ const SwSection* pActiveShellCurrSection = m_pActiveShell->GetCurrSection();
+ if (pActiveShellCurrSection)
+ {
+ const SwSection* pSection = pActiveShellCurrSection;
+ while (SwSection* pParent = pSection->GetParent())
+ pSection = pParent;
+ for (const std::unique_ptr<SwGlblDocContent>& rGlblDocContent : *m_pSwGlblDocContents)
+ {
+ if (rGlblDocContent->GetType() == GlobalDocContentType::GLBLDOC_UNKNOWN)
+ continue;
+ if ((pSection->GetType() == SectionType::ToxContent
+ && rGlblDocContent->GetTOX() == pSection->GetTOXBase())
+ || (pSection->GetType() != SectionType::ToxContent
+ && rGlblDocContent->GetSection() == pSection))
+ {
+ const OUString& rId(weld::toId(rGlblDocContent.get()));
+ m_xTreeView->select(m_xTreeView->find_id(rId));
+ break;
+ }
+ }
+ }
+ else
+ {
+ const SwCursor* pCursor = m_pActiveShell->GetCursor();
+ const SwNode& rNode = pCursor->GetPoint()->GetNode();
+ if (rNode.IsTextNode())
+ {
+ // only the first text node in each series of text nodes is stored in the
+ // SwGlblDocContents array
+ SwNodeIndex aIdx(rNode);
+ do
+ {
+ --aIdx;
+ } while (aIdx.GetNode().IsTextNode());
+ ++aIdx;
+ SwNodeOffset aTextNodeIndex(aIdx.GetNode().GetIndex());
+ for (const std::unique_ptr<SwGlblDocContent>& rGlblDocContent : *m_pSwGlblDocContents)
+ {
+ if (rGlblDocContent->GetType() == GlobalDocContentType::GLBLDOC_UNKNOWN
+ && rGlblDocContent->GetDocPos() == aTextNodeIndex)
+ {
+ const OUString& rId(weld::toId(rGlblDocContent.get()));
+ m_xTreeView->select(m_xTreeView->find_id(rId));
+ }
+ }
+ }
+ }
+
+ Select();
+}
+
+void SwGlobalTree::GotoContent(const SwGlblDocContent* pCont)
+{
+ m_pActiveShell->EnterStdMode();
+
+ switch( pCont->GetType() )
+ {
+ case GLBLDOC_UNKNOWN:
+ m_pActiveShell->GotoGlobalDocContent(*pCont);
+ break;
+ case GLBLDOC_TOXBASE:
+ {
+ const OUString sName = pCont->GetTOX()->GetTOXName();
+ if (!m_pActiveShell->GotoNextTOXBase(&sName))
+ m_pActiveShell->GotoPrevTOXBase(&sName);
+ }
+ break;
+ case GLBLDOC_SECTION:
+ break;
+ }
+
+}
+
+void SwGlobalTree::ShowTree()
+{
+ m_aUpdateTimer.Start();
+ m_xTreeView->show();
+ UpdateTracking();
+}
+
+void SwGlobalTree::HideTree()
+{
+ m_aUpdateTimer.Stop();
+ m_xTreeView->hide();
+}
+
+void SwGlobalTree::ExecCommand(std::u16string_view rCmd)
+{
+ int nEntry = m_xTreeView->get_selected_index();
+ if (nEntry == -1)
+ return;
+ if (rCmd == u"edit")
+ {
+ const SwGlblDocContent* pCont = weld::fromId<const SwGlblDocContent*>(
+ m_xTreeView->get_id(nEntry));
+ EditContent(pCont);
+ }
+ else
+ {
+ if (m_xTreeView->count_selected_rows() == 1)
+ {
+ bool bMove = false;
+ int nSource = nEntry;
+ int nDest = nSource;
+ if (rCmd == u"movedown")
+ {
+ int nEntryCount = m_xTreeView->n_children();
+ bMove = nEntryCount > nSource + 1;
+ nDest+= 2;
+ }
+ else if (rCmd == u"moveup")
+ {
+ bMove = 0 != nSource;
+ nDest--;
+ }
+ if( bMove && m_pActiveShell->MoveGlobalDocContent(
+ *m_pSwGlblDocContents, nSource, nSource + 1, nDest ) &&
+ Update( false ))
+ Display();
+ }
+ }
+}
+
+bool SwGlobalTree::Update(bool bHard)
+{
+ SwView* pActView = GetParentWindow()->GetCreateView();
+ bool bRet = false;
+ if (pActView && pActView->GetWrtShellPtr())
+ {
+ const SwWrtShell* pOldShell = m_pActiveShell;
+ m_pActiveShell = pActView->GetWrtShellPtr();
+ if(m_pActiveShell != pOldShell)
+ {
+ m_pSwGlblDocContents.reset();
+ if (!IsListening(*m_pActiveShell->GetView().GetDocShell()))
+ StartListening(*m_pActiveShell->GetView().GetDocShell());
+ }
+ if(!m_pSwGlblDocContents)
+ {
+ m_pSwGlblDocContents.reset(new SwGlblDocContents);
+ bRet = true;
+ m_pActiveShell->GetGlobalDocContent(*m_pSwGlblDocContents);
+ }
+ else
+ {
+ bool bCopy = false;
+ SwGlblDocContents aTempContents;
+ m_pActiveShell->GetGlobalDocContent(aTempContents);
+ size_t nChildren = m_xTreeView->n_children();
+ if (aTempContents.size() != m_pSwGlblDocContents->size() ||
+ aTempContents.size() != nChildren)
+ {
+ bRet = true;
+ bCopy = true;
+ }
+ else
+ {
+ for(size_t i = 0; i < aTempContents.size() && !bCopy; i++)
+ {
+ SwGlblDocContent* pLeft = aTempContents[i].get();
+ SwGlblDocContent* pRight = (*m_pSwGlblDocContents)[i].get();
+ GlobalDocContentType eType = pLeft->GetType();
+ OUString sTemp = m_xTreeView->get_text(i);
+ if (
+ eType != pRight->GetType() ||
+ (
+ eType == GLBLDOC_SECTION &&
+ pLeft->GetSection()->GetSectionName() != sTemp
+ ) ||
+ (
+ eType == GLBLDOC_TOXBASE &&
+ pLeft->GetTOX()->GetTitle() != sTemp
+ )
+ )
+ {
+ bCopy = true;
+ }
+ }
+ }
+ if (bCopy || bHard)
+ {
+ *m_pSwGlblDocContents = std::move( aTempContents );
+ bRet = true;
+ }
+ }
+ }
+ else
+ {
+ m_xTreeView->clear();
+ if(m_pSwGlblDocContents)
+ m_pSwGlblDocContents->clear();
+ }
+ // FIXME: Implement a test for changes!
+ return bRet;
+}
+
+void SwGlobalTree::OpenDoc(const SwGlblDocContent* pCont)
+{
+ const OUString sFileName(pCont->GetSection()->GetLinkFileName().getToken(0,
+ sfx2::cTokenSeparator));
+ bool bFound = false;
+ const SfxObjectShell* pCurr = SfxObjectShell::GetFirst();
+ while( !bFound && pCurr )
+ {
+ if(pCurr->GetMedium() &&
+ pCurr->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::ToIUri) == sFileName)
+ {
+ bFound = true;
+ SwGlobalTree::SetShowShell(pCurr);
+ Application::PostUserEvent(LINK(this, SwGlobalTree, ShowFrameHdl));
+ pCurr = nullptr;
+ }
+ else
+ pCurr = SfxObjectShell::GetNext(*pCurr);
+ }
+ if(!bFound)
+ {
+ SfxStringItem aURL(SID_FILE_NAME, sFileName);
+ SfxBoolItem aReadOnly(SID_DOC_READONLY, false);
+ SfxStringItem aTargetFrameName( SID_TARGETNAME, "_blank" );
+ SfxStringItem aReferer(SID_REFERER, m_pActiveShell->GetView().GetDocShell()->GetTitle());
+ m_pActiveShell->GetView().GetViewFrame().GetDispatcher()->
+ ExecuteList(SID_OPENDOC, SfxCallMode::ASYNCHRON,
+ { &aURL, &aReadOnly, &aReferer, &aTargetFrameName });
+ }
+}
+
+IMPL_LINK_NOARG( SwGlobalTree, DoubleClickHdl, weld::TreeView&, bool)
+{
+ int nEntry = m_xTreeView->get_cursor_index();
+ SwGlblDocContent* pCont = weld::fromId<SwGlblDocContent*>(m_xTreeView->get_id(nEntry));
+ if (pCont->GetType() == GLBLDOC_SECTION)
+ OpenDoc(pCont);
+ else
+ {
+ GotoContent(pCont);
+ m_pActiveShell->GetView().GetEditWin().GrabFocus();
+ }
+ return false;
+}
+
+SwNavigationPI* SwGlobalTree::GetParentWindow()
+{
+ return m_pDialog;
+}
+
+IMPL_STATIC_LINK_NOARG(SwGlobalTree, ShowFrameHdl, void*, void)
+{
+ SfxViewFrame* pFirst = s_pShowShell ? SfxViewFrame::GetFirst(s_pShowShell) : nullptr;
+ if (pFirst)
+ pFirst->ToTop();
+ SwGlobalTree::SetShowShell(nullptr);
+}
+
+void SwGlobalTree::InsertRegion( const SwGlblDocContent* _pContent, const Sequence< OUString >& _rFiles )
+{
+ sal_Int32 nFiles = _rFiles.getLength();
+ if (!nFiles)
+ return;
+
+ size_t nEntryCount = m_xTreeView->n_children();
+
+ bool bMove = _pContent == nullptr;
+ const OUString* pFileNames = _rFiles.getConstArray();
+ SwWrtShell& rSh = GetParentWindow()->GetCreateView()->GetWrtShell();
+ rSh.StartAction();
+ // after insertion of the first new content the 'pCont' parameter becomes invalid
+ // find the index of the 'anchor' content to always use a current anchor content
+ size_t nAnchorContent = m_pSwGlblDocContents->size() - 1;
+ if (!bMove)
+ {
+ for (size_t nContent = 0; nContent < m_pSwGlblDocContents->size();
+ ++nContent)
+ {
+ if( *_pContent == *(*m_pSwGlblDocContents)[ nContent ] )
+ {
+ nAnchorContent = nContent;
+ break;
+ }
+ }
+ }
+ SwGlblDocContents aTempContents;
+ for ( sal_Int32 nFile = 0; nFile < nFiles; ++nFile )
+ {
+ //update the global document content after each inserted document
+ rSh.GetGlobalDocContent(aTempContents);
+ SwGlblDocContent* pAnchorContent = nullptr;
+ OSL_ENSURE(aTempContents.size() > (nAnchorContent + nFile), "invalid anchor content -> last insertion failed");
+ if ( aTempContents.size() > (nAnchorContent + nFile) )
+ pAnchorContent = aTempContents[nAnchorContent + nFile].get();
+ else
+ pAnchorContent = aTempContents.back().get();
+ OUString sFileName(pFileNames[nFile]);
+ INetURLObject aFileUrl;
+ aFileUrl.SetSmartURL( sFileName );
+ OUString sSectionName(aFileUrl.GetLastName(
+ INetURLObject::DecodeMechanism::Unambiguous).getToken(0, sfx2::cTokenSeparator));
+ sal_uInt16 nSectCount = rSh.GetSectionFormatCount();
+ OUString sTempSectionName(sSectionName);
+ sal_uInt16 nAddNumber = 0;
+ sal_uInt16 nCount = 0;
+ // if applicable: add index if the range name is already in use.
+ while ( nCount < nSectCount )
+ {
+ const SwSectionFormat& rFormat = rSh.GetSectionFormat(nCount);
+ if ((rFormat.GetSection()->GetSectionName() == sTempSectionName)
+ && rFormat.IsInNodesArr())
+ {
+ nCount = 0;
+ nAddNumber++;
+ sTempSectionName = sSectionName + ":" + OUString::number( nAddNumber );
+ }
+ else
+ nCount++;
+ }
+
+ if ( nAddNumber )
+ sSectionName = sTempSectionName;
+
+ SwSectionData aSectionData(SectionType::Content, sSectionName);
+ aSectionData.SetProtectFlag(true);
+ aSectionData.SetHidden(false);
+
+ aSectionData.SetLinkFileName(sFileName);
+ aSectionData.SetType(SectionType::FileLink);
+ aSectionData.SetLinkFilePassword( OUString() );
+
+ rSh.InsertGlobalDocContent( *pAnchorContent, aSectionData );
+ }
+ if (bMove)
+ {
+ Update( false );
+ rSh.MoveGlobalDocContent(
+ *m_pSwGlblDocContents, nEntryCount, nEntryCount + nFiles, nEntryCount - nFiles );
+ }
+ rSh.EndAction();
+ Update( false );
+ Display();
+
+}
+
+IMPL_LINK( SwGlobalTree, DialogClosedHdl, sfx2::FileDialogHelper*, _pFileDlg, void )
+{
+ if ( ERRCODE_NONE != _pFileDlg->GetError() )
+ return;
+
+ SfxMediumList aMedList(m_pDocInserter->CreateMediumList());
+ if ( aMedList.empty() )
+ return;
+
+ Sequence< OUString >aFileNames( aMedList.size() );
+ OUString* pFileNames = aFileNames.getArray();
+ sal_Int32 nPos = 0;
+ for (const std::unique_ptr<SfxMedium>& pMed : aMedList)
+ {
+ // tdf#127978 - don't URL encode filename for navigator's tooltip
+ OUString sFileName
+ = pMed->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::Unambiguous)
+ + OUStringChar(sfx2::cTokenSeparator)
+ + pMed->GetFilter()->GetFilterName()
+ + OUStringChar(sfx2::cTokenSeparator);
+ pFileNames[nPos++] = sFileName;
+ }
+ InsertRegion( &*m_oDocContent, aFileNames );
+ m_oDocContent.reset();
+}
+
+void SwGlobalTree::Notify(SfxBroadcaster& rBC, SfxHint const& rHint)
+{
+ SfxViewEventHint const*const pVEHint(dynamic_cast<SfxViewEventHint const*>(&rHint));
+ SwXTextView* pDyingShell = nullptr;
+ if (m_pActiveShell && pVEHint && pVEHint->GetEventName() == "OnViewClosed")
+ pDyingShell = dynamic_cast<SwXTextView*>(pVEHint->GetController().get());
+ if (pDyingShell && pDyingShell->GetView() == &m_pActiveShell->GetView())
+ {
+ EndListening(*m_pActiveShell->GetView().GetDocShell());
+ m_pActiveShell = nullptr;
+ }
+ else
+ {
+ SfxListener::Notify(rBC, rHint);
+ if (rHint.GetId() == SfxHintId::SwNavigatorUpdateTracking)
+ UpdateTracking();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/utlui/gloslst.cxx b/sw/source/uibase/utlui/gloslst.cxx
new file mode 100644
index 0000000000..9878d0aa67
--- /dev/null
+++ b/sw/source/uibase/utlui/gloslst.cxx
@@ -0,0 +1,445 @@
+/* -*- 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 <vcl/weld.hxx>
+#include <svl/fstathelper.hxx>
+#include <unotools/pathoptions.hxx>
+#include <unotools/transliterationwrapper.hxx>
+#include <osl/diagnose.h>
+#include <o3tl/string_view.hxx>
+#include <swtypes.hxx>
+#include <swmodule.hxx>
+#include <shellio.hxx>
+#include <initui.hxx>
+#include <glosdoc.hxx>
+#include <gloslst.hxx>
+#include <swunohelper.hxx>
+#include <view.hxx>
+
+#include <vector>
+
+#define STRING_DELIM char(0x0A)
+#define GLOS_TIMEOUT 30000 // update every 30 seconds
+#define FIND_MAX_GLOS 20
+
+namespace {
+
+struct TripleString
+{
+ OUString sGroup;
+ OUString sBlock;
+ OUString sShort;
+};
+
+class SwGlossDecideDlg : public weld::GenericDialogController
+{
+ std::unique_ptr<weld::Button> m_xOk;
+ std::unique_ptr<weld::TreeView> m_xListLB;
+
+ DECL_LINK(DoubleClickHdl, weld::TreeView&, bool);
+ DECL_LINK(SelectHdl, weld::TreeView&, void);
+
+public:
+ explicit SwGlossDecideDlg(weld::Window* pParent);
+
+ weld::TreeView& GetTreeView() {return *m_xListLB;}
+};
+
+}
+
+SwGlossDecideDlg::SwGlossDecideDlg(weld::Window* pParent)
+ : GenericDialogController(pParent, "modules/swriter/ui/selectautotextdialog.ui", "SelectAutoTextDialog")
+ , m_xOk(m_xBuilder->weld_button("ok"))
+ , m_xListLB(m_xBuilder->weld_tree_view("treeview"))
+{
+ m_xListLB->set_size_request(m_xListLB->get_approximate_digit_width() * 32,
+ m_xListLB->get_height_rows(8));
+ m_xListLB->connect_row_activated(LINK(this, SwGlossDecideDlg, DoubleClickHdl));
+ m_xListLB->connect_changed(LINK(this, SwGlossDecideDlg, SelectHdl));
+}
+
+IMPL_LINK_NOARG(SwGlossDecideDlg, DoubleClickHdl, weld::TreeView&, bool)
+{
+ m_xDialog->response(RET_OK);
+ return true;
+}
+
+IMPL_LINK_NOARG(SwGlossDecideDlg, SelectHdl, weld::TreeView&, void)
+{
+ m_xOk->set_sensitive(m_xListLB->get_selected_index() != -1);
+}
+
+SwGlossaryList::SwGlossaryList() :
+ AutoTimer("SwGlossaryList"), m_bFilled(false)
+{
+ SvtPathOptions aPathOpt;
+ m_sPath = aPathOpt.GetAutoTextPath();
+ SetTimeout(GLOS_TIMEOUT);
+}
+
+SwGlossaryList::~SwGlossaryList()
+{
+ ClearGroups();
+}
+
+// If the GroupName is already known, then only rShortName
+// will be filled. Otherwise also rGroupName will be set and
+// on demand asked for the right group.
+
+bool SwGlossaryList::GetShortName(std::u16string_view rLongName,
+ OUString& rShortName, OUString& rGroupName )
+{
+ if(!m_bFilled)
+ Update();
+
+ std::vector<TripleString> aTripleStrings;
+
+ size_t nCount = m_aGroupArr.size();
+ for(size_t i = 0; i < nCount; i++ )
+ {
+ AutoTextGroup* pGroup = m_aGroupArr[i].get();
+ if(!rGroupName.isEmpty() && rGroupName != pGroup->sName)
+ continue;
+
+ sal_Int32 nPosLong = 0;
+ for(sal_uInt16 j = 0; j < pGroup->nCount; j++)
+ {
+ const OUString sLong = pGroup->sLongNames.getToken(0, STRING_DELIM, nPosLong);
+ if(rLongName != sLong)
+ continue;
+
+ TripleString aTriple;
+ aTriple.sGroup = pGroup->sName;
+ aTriple.sBlock = sLong;
+ aTriple.sShort = pGroup->sShortNames.getToken(j, STRING_DELIM);
+ aTripleStrings.push_back(aTriple);
+ }
+ }
+
+ bool bRet = false;
+ nCount = aTripleStrings.size();
+ if(1 == nCount)
+ {
+ const TripleString& rTriple(aTripleStrings.front());
+ rShortName = rTriple.sShort;
+ rGroupName = rTriple.sGroup;
+ bRet = true;
+ }
+ else if(1 < nCount)
+ {
+ SwView *pView = ::GetActiveView();
+ if (!pView)
+ return bRet;
+ SwGlossDecideDlg aDlg(pView->GetFrameWeld());
+ OUString sTitle = aDlg.get_title() + " " + aTripleStrings.front().sBlock;
+ aDlg.set_title(sTitle);
+
+ weld::TreeView& rLB = aDlg.GetTreeView();
+ for (const auto& rTriple : aTripleStrings)
+ rLB.append_text(rTriple.sGroup.getToken(0, GLOS_DELIM));
+
+ rLB.select(0);
+ if (aDlg.run() == RET_OK && rLB.get_selected_index() != -1)
+ {
+ const TripleString& rTriple(aTripleStrings[rLB.get_selected_index()]);
+ rShortName = rTriple.sShort;
+ rGroupName = rTriple.sGroup;
+ bRet = true;
+ }
+ else
+ bRet = false;
+ }
+ return bRet;
+}
+
+size_t SwGlossaryList::GetGroupCount()
+{
+ if(!m_bFilled)
+ Update();
+ return m_aGroupArr.size();
+}
+
+OUString SwGlossaryList::GetGroupName(size_t nPos)
+{
+ OSL_ENSURE(m_aGroupArr.size() > nPos, "group not available");
+ if(nPos < m_aGroupArr.size())
+ {
+ AutoTextGroup* pGroup = m_aGroupArr[nPos].get();
+ OUString sRet = pGroup->sName;
+ return sRet;
+ }
+ return OUString();
+}
+
+OUString SwGlossaryList::GetGroupTitle(size_t nPos)
+{
+ OSL_ENSURE(m_aGroupArr.size() > nPos, "group not available");
+ if(nPos < m_aGroupArr.size())
+ {
+ AutoTextGroup* pGroup = m_aGroupArr[nPos].get();
+ return pGroup->sTitle;
+ }
+ return OUString();
+}
+
+sal_uInt16 SwGlossaryList::GetBlockCount(size_t nGroup)
+{
+ OSL_ENSURE(m_aGroupArr.size() > nGroup, "group not available");
+ if(nGroup < m_aGroupArr.size())
+ {
+ AutoTextGroup* pGroup = m_aGroupArr[nGroup].get();
+ return pGroup->nCount;
+ }
+ return 0;
+}
+
+OUString SwGlossaryList::GetBlockLongName(size_t nGroup, sal_uInt16 nBlock)
+{
+ OSL_ENSURE(m_aGroupArr.size() > nGroup, "group not available");
+ if(nGroup < m_aGroupArr.size())
+ {
+ AutoTextGroup* pGroup = m_aGroupArr[nGroup].get();
+ return pGroup->sLongNames.getToken(nBlock, STRING_DELIM);
+ }
+ return OUString();
+}
+
+OUString SwGlossaryList::GetBlockShortName(size_t nGroup, sal_uInt16 nBlock)
+{
+ OSL_ENSURE(m_aGroupArr.size() > nGroup, "group not available");
+ if(nGroup < m_aGroupArr.size())
+ {
+ AutoTextGroup* pGroup = m_aGroupArr[nGroup].get();
+ return pGroup->sShortNames.getToken(nBlock, STRING_DELIM);
+ }
+ return OUString();
+}
+
+void SwGlossaryList::Update()
+{
+ if(!IsActive())
+ Start();
+
+ SvtPathOptions aPathOpt;
+ const OUString& sTemp( aPathOpt.GetAutoTextPath() );
+ if(sTemp != m_sPath)
+ {
+ m_sPath = sTemp;
+ m_bFilled = false;
+ ClearGroups();
+ }
+ SwGlossaries* pGlossaries = ::GetGlossaries();
+ const std::vector<OUString> & rPathArr = pGlossaries->GetPathArray();
+ const OUString sExt( SwGlossaries::GetExtension() );
+ if(!m_bFilled)
+ {
+ const size_t nGroupCount = pGlossaries->GetGroupCnt();
+ for(size_t i = 0; i < nGroupCount; ++i)
+ {
+ OUString sGrpName = pGlossaries->GetGroupName(i);
+ const size_t nPath = static_cast<size_t>(
+ o3tl::toInt32(o3tl::getToken(sGrpName, 1, GLOS_DELIM)));
+ if( nPath < rPathArr.size() )
+ {
+ std::unique_ptr<AutoTextGroup> pGroup(new AutoTextGroup);
+ pGroup->sName = sGrpName;
+
+ FillGroup(pGroup.get(), pGlossaries);
+ OUString sName = rPathArr[nPath] + "/" +
+ o3tl::getToken(pGroup->sName, 0, GLOS_DELIM) + sExt;
+ FStatHelper::GetModifiedDateTimeOfFile( sName,
+ &pGroup->aDateModified,
+ &pGroup->aDateModified );
+
+ m_aGroupArr.insert( m_aGroupArr.begin(), std::move(pGroup) );
+ }
+ }
+ m_bFilled = true;
+ }
+ else
+ {
+ for( size_t nPath = 0; nPath < rPathArr.size(); nPath++ )
+ {
+ std::vector<OUString> aFoundGroupNames;
+ std::vector<OUString> aFiles;
+ std::vector<DateTime> aDateTimeArr;
+
+ SWUnoHelper::UCB_GetFileListOfFolder( rPathArr[nPath], aFiles,
+ &sExt, &aDateTimeArr );
+ for( size_t nFiles = 0; nFiles < aFiles.size(); ++nFiles )
+ {
+ const OUString aTitle = aFiles[ nFiles ];
+ ::DateTime& rDT = aDateTimeArr[ nFiles ];
+
+ OUString sName( aTitle.copy( 0, aTitle.getLength() - sExt.getLength() ));
+
+ aFoundGroupNames.push_back(sName);
+ sName += OUStringChar(GLOS_DELIM) + OUString::number( o3tl::narrowing<sal_uInt16>(nPath) );
+ AutoTextGroup* pFound = FindGroup( sName );
+ if( !pFound )
+ {
+ pFound = new AutoTextGroup;
+ pFound->sName = sName;
+ FillGroup( pFound, pGlossaries );
+ pFound->aDateModified = rDT;
+
+ m_aGroupArr.push_back(std::unique_ptr<AutoTextGroup>(pFound));
+ }
+ else if( pFound->aDateModified != rDT )
+ {
+ FillGroup(pFound, pGlossaries);
+ pFound->aDateModified = rDT;
+ }
+ }
+
+ for( size_t i = m_aGroupArr.size(); i>0; )
+ {
+ --i;
+ // maybe remove deleted groups
+ AutoTextGroup* pGroup = m_aGroupArr[i].get();
+ const size_t nGroupPath = static_cast<size_t>(
+ o3tl::toInt32(o3tl::getToken(pGroup->sName, 1, GLOS_DELIM)));
+ // Only the groups will be checked which are registered
+ // for the current subpath.
+ if( nGroupPath == nPath )
+ {
+ std::u16string_view sCompareGroup = o3tl::getToken(pGroup->sName, 0, GLOS_DELIM);
+ bool bFound = std::any_of(aFoundGroupNames.begin(), aFoundGroupNames.end(),
+ [&sCompareGroup](const OUString& rGroupName) { return sCompareGroup == rGroupName; });
+
+ if(!bFound)
+ {
+ m_aGroupArr.erase(m_aGroupArr.begin() + i);
+ }
+ }
+ }
+ }
+ }
+}
+
+void SwGlossaryList::Invoke()
+{
+ // Only update automatically if a SwView has the focus.
+ if(::GetActiveView())
+ Update();
+}
+
+AutoTextGroup* SwGlossaryList::FindGroup(std::u16string_view rGroupName)
+{
+ for(const auto & pRet : m_aGroupArr)
+ {
+ if(pRet->sName == rGroupName)
+ return pRet.get();
+ }
+ return nullptr;
+}
+
+void SwGlossaryList::FillGroup(AutoTextGroup* pGroup, SwGlossaries* pGlossaries)
+{
+ std::unique_ptr<SwTextBlocks> pBlock = pGlossaries->GetGroupDoc(pGroup->sName);
+ pGroup->nCount = pBlock ? pBlock->GetCount() : 0;
+ pGroup->sLongNames.clear();
+ pGroup->sShortNames.clear();
+ if(pBlock)
+ pGroup->sTitle = pBlock->GetName();
+
+ for(sal_uInt16 j = 0; j < pGroup->nCount; j++)
+ {
+ pGroup->sLongNames += pBlock->GetLongName(j)
+ + OUStringChar(STRING_DELIM);
+ pGroup->sShortNames += pBlock->GetShortName(j)
+ + OUStringChar(STRING_DELIM);
+ }
+}
+
+// Give back all (not exceeding FIND_MAX_GLOS) found modules
+// with matching beginning.
+
+void SwGlossaryList::HasLongName(const std::vector<OUString>& rBeginCandidates,
+ std::vector<std::pair<OUString, sal_uInt16>>& rLongNames)
+{
+ if(!m_bFilled)
+ Update();
+ const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore();
+ // We store results for all candidate words in separate lists, so that later
+ // we can sort them according to the candidate position
+ std::vector<std::vector<OUString>> aResults(rBeginCandidates.size());
+
+ // We can't break after FIND_MAX_GLOS items found, since first items may have ended up in
+ // lower-priority lists, and those from higher-priority lists are yet to come. So process all.
+ for (const auto& pGroup : m_aGroupArr)
+ {
+ sal_Int32 nIdx{ 0 };
+ for(sal_uInt16 j = 0; j < pGroup->nCount; j++)
+ {
+ OUString sBlock = pGroup->sLongNames.getToken(0, STRING_DELIM, nIdx);
+ for (size_t i = 0; i < rBeginCandidates.size(); ++i)
+ {
+ const OUString& s = rBeginCandidates[i];
+ if (s.getLength() + 1 < sBlock.getLength()
+ && rSCmp.isEqual(sBlock.copy(0, s.getLength()), s))
+ {
+ aResults[i].push_back(sBlock);
+ }
+ }
+ }
+ }
+
+ std::vector<std::pair<OUString, sal_uInt16>> aAllResults;
+ // Sort and concatenate all result lists. See QuickHelpData::SortAndFilter
+ for (size_t i = 0; i < rBeginCandidates.size(); ++i)
+ {
+ std::sort(aResults[i].begin(), aResults[i].end(),
+ [origWord = rBeginCandidates[i]](const OUString& s1, const OUString& s2) {
+ int nRet = s1.compareToIgnoreAsciiCase(s2);
+ if (nRet == 0)
+ {
+ // fdo#61251 sort stuff that starts with the exact rOrigWord before
+ // another ignore-case candidate
+ int n1StartsWithOrig = s1.startsWith(origWord) ? 0 : 1;
+ int n2StartsWithOrig = s2.startsWith(origWord) ? 0 : 1;
+ return n1StartsWithOrig < n2StartsWithOrig;
+ }
+ return nRet < 0;
+ });
+ // All suggestions must be accompanied with length of the text they would replace
+ std::transform(aResults[i].begin(), aResults[i].end(), std::back_inserter(aAllResults),
+ [nLen = sal_uInt16(rBeginCandidates[i].getLength())](const OUString& s) {
+ return std::make_pair(s, nLen);
+ });
+ }
+
+ const auto& it = std::unique(
+ aAllResults.begin(), aAllResults.end(),
+ [](const std::pair<OUString, sal_uInt16>& s1, const std::pair<OUString, sal_uInt16>& s2) {
+ return s1.first.equalsIgnoreAsciiCase(s2.first);
+ });
+ if (const auto nCount = std::min<size_t>(std::distance(aAllResults.begin(), it), FIND_MAX_GLOS))
+ {
+ rLongNames.insert(rLongNames.end(), aAllResults.begin(), aAllResults.begin() + nCount);
+ }
+}
+
+void SwGlossaryList::ClearGroups()
+{
+ m_aGroupArr.clear();
+ m_bFilled = false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/utlui/gotodlg.cxx b/sw/source/uibase/utlui/gotodlg.cxx
new file mode 100644
index 0000000000..711717ee44
--- /dev/null
+++ b/sw/source/uibase/utlui/gotodlg.cxx
@@ -0,0 +1,105 @@
+/* -*- 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 <swmodule.hxx>
+#include <view.hxx>
+#include <wrtsh.hxx>
+#include <gotodlg.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/viewfrm.hxx>
+
+using namespace com::sun::star;
+
+SwGotoPageDlg::SwGotoPageDlg(weld::Window* pParent, SfxBindings& rBindings)
+ : GenericDialogController(pParent, "modules/swriter/ui/gotopagedialog.ui", "GotoPageDialog")
+ , m_pCreateView(nullptr)
+ , m_rBindings(rBindings)
+ , mnMaxPageCnt(1)
+ , mxMtrPageCtrl(m_xBuilder->weld_spin_button("page"))
+ , mxPageNumberLbl(m_xBuilder->weld_label("page_count"))
+{
+ sal_uInt16 nTotalPage = GetPageInfo();
+
+ if (nTotalPage)
+ {
+ OUString sStr = mxPageNumberLbl->get_label();
+ mxPageNumberLbl->set_label(sStr.replaceFirst("$1", OUString::number(nTotalPage)));
+ mnMaxPageCnt = nTotalPage;
+ }
+ mxMtrPageCtrl->connect_changed(LINK(this, SwGotoPageDlg, PageModifiedHdl));
+ mxMtrPageCtrl->set_position(-1);
+ mxMtrPageCtrl->select_region(0, -1);
+}
+
+IMPL_LINK_NOARG(SwGotoPageDlg, PageModifiedHdl, weld::Entry&, void)
+{
+ if (mxMtrPageCtrl->get_text().isEmpty())
+ return;
+
+ int page_value = mxMtrPageCtrl->get_text().toInt32();
+
+ if (page_value <= 0)
+ mxMtrPageCtrl->set_value(1);
+ else if (page_value > mnMaxPageCnt)
+ mxMtrPageCtrl->set_value(mnMaxPageCnt);
+ else
+ mxMtrPageCtrl->set_value(page_value);
+
+ mxMtrPageCtrl->set_position(-1);
+}
+
+SwView* SwGotoPageDlg::GetCreateView() const
+{
+ if (!m_pCreateView)
+ {
+ SwView* pView = SwModule::GetFirstView();
+ while (pView)
+ {
+ if (&pView->GetViewFrame().GetBindings() == &m_rBindings)
+ {
+ const_cast<SwGotoPageDlg*>(this)->m_pCreateView = pView;
+ break;
+ }
+ pView = SwModule::GetNextView(pView);
+ }
+ }
+
+ return m_pCreateView;
+}
+
+// If the page can be set here, the maximum is set.
+
+sal_uInt16 SwGotoPageDlg::GetPageInfo()
+{
+ SwView* pView = GetCreateView();
+ SwWrtShell* pSh = pView ? &pView->GetWrtShell() : nullptr;
+ mxMtrPageCtrl->set_value(1);
+ if (pSh)
+ {
+ const sal_uInt16 nPageCnt = pSh->GetPageCnt();
+ sal_uInt16 nPhyPage, nVirPage;
+ pSh->GetPageNum(nPhyPage, nVirPage);
+ mxMtrPageCtrl->set_max(nPageCnt);
+ mxMtrPageCtrl->set_value(nPhyPage);
+ return nPageCnt;
+ }
+ return 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/utlui/initui.cxx b/sw/source/uibase/utlui/initui.cxx
new file mode 100644
index 0000000000..f24cded867
--- /dev/null
+++ b/sw/source/uibase/utlui/initui.cxx
@@ -0,0 +1,311 @@
+/* -*- 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 <libxml/xmlwriter.h>
+
+#include <unotools/localedatawrapper.hxx>
+#include <viewsh.hxx>
+#include <initui.hxx>
+#include <edtwin.hxx>
+#include <shellres.hxx>
+#include <fldbas.hxx>
+#include <glosdoc.hxx>
+#include <gloslst.hxx>
+#include <comcore.hxx>
+#include <strings.hrc>
+#include <utlui.hrc>
+#include <authfld.hxx>
+#include <unotools/syslocale.hxx>
+
+// Global Pointer
+
+static std::unique_ptr<SwGlossaries> pGlossaries;
+
+// Provides all needed paths. Is initialized by UI.
+static SwGlossaryList* pGlossaryList = nullptr;
+
+namespace
+{
+OUString CurrGlosGroup;
+}
+
+const OUString& GetCurrGlosGroup()
+{
+ return CurrGlosGroup;
+}
+
+void SetCurrGlosGroup(const OUString& sStr)
+{
+ CurrGlosGroup = sStr;
+}
+
+namespace
+{
+
+std::vector<OUString>* pAuthFieldNameList = nullptr;
+std::vector<OUString>* pAuthFieldTypeList = nullptr;
+
+}
+
+// Finish UI
+
+void FinitUI()
+{
+ delete SwViewShell::GetShellRes();
+ SwViewShell::SetShellRes( nullptr );
+
+ SwEditWin::FinitStaticData();
+
+ pGlossaries.reset();
+
+ delete SwFieldType::s_pFieldNames;
+
+ delete pGlossaryList;
+ delete pAuthFieldNameList;
+ delete pAuthFieldTypeList;
+
+}
+
+// Initialise
+
+void InitUI()
+{
+ // ShellResource gives the CORE the possibility to work with resources.
+ SwViewShell::SetShellRes( new ShellResource );
+ SwEditWin::InitStaticData();
+}
+
+const TranslateId FLD_DOCINFO_ARY[] =
+{
+ FLD_DOCINFO_TITLE,
+ FLD_DOCINFO_SUBJECT,
+ FLD_DOCINFO_KEYS,
+ FLD_DOCINFO_COMMENT,
+ FLD_DOCINFO_CREATE,
+ FLD_DOCINFO_CHANGE,
+ FLD_DOCINFO_PRINT,
+ FLD_DOCINFO_DOCNO,
+ FLD_DOCINFO_EDIT
+};
+
+ShellResource::ShellResource()
+ : aPostItAuthor( SwResId( STR_POSTIT_AUTHOR ) ),
+ aPostItPage( SwResId( STR_POSTIT_PAGE ) ),
+ aPostItLine( SwResId( STR_POSTIT_LINE ) ),
+
+ aCalc_Syntax( SwResId( STR_CALC_SYNTAX ) ),
+ aCalc_ZeroDiv( SwResId( STR_CALC_ZERODIV ) ),
+ aCalc_Brack( SwResId( STR_CALC_BRACK ) ),
+ aCalc_Pow( SwResId( STR_CALC_POW ) ),
+ aCalc_Overflow( SwResId( STR_CALC_OVERFLOW ) ),
+ aCalc_Default( SwResId( STR_CALC_DEFAULT ) ),
+ aCalc_Error( SwResId( STR_CALC_ERROR ) ),
+
+ // #i81002#
+ aGetRefField_RefItemNotFound( SwResId( STR_GETREFFLD_REFITEMNOTFOUND ) ),
+ aStrNone( SwResId( STR_TEMPLATE_NONE )),
+ aFixedStr( SwResId( STR_FIELD_FIXED )),
+ sDurationFormat( SwResId( STR_DURATION_FORMAT )),
+
+ aTOXIndexName( SwResId(STR_TOI)),
+ aTOXUserName( SwResId(STR_TOU)),
+ aTOXContentName( SwResId(STR_TOC)),
+ aTOXIllustrationsName( SwResId(STR_TOX_ILL)),
+ aTOXObjectsName( SwResId(STR_TOX_OBJ)),
+ aTOXTablesName( SwResId(STR_TOX_TBL)),
+ aTOXAuthoritiesName( SwResId(STR_TOX_AUTH)),
+ aTOXCitationName( SwResId(STR_TOX_CITATION)),
+ sPageDescFirstName( SwResId(STR_PAGEDESC_FIRSTNAME)),
+ sPageDescFollowName( SwResId(STR_PAGEDESC_FOLLOWNAME)),
+ sPageDescName( SwResId(STR_PAGEDESC_NAME))
+{
+ for (auto const& aID : FLD_DOCINFO_ARY)
+ aDocInfoLst.push_back(SwResId(aID));
+}
+
+OUString ShellResource::GetPageDescName(sal_uInt16 nNo, PageNameMode eMode)
+{
+ OUString sRet;
+
+ switch (eMode)
+ {
+ case NORMAL_PAGE:
+ sRet = sPageDescName;
+ break;
+ case FIRST_PAGE:
+ sRet = sPageDescFirstName;
+ break;
+ case FOLLOW_PAGE:
+ sRet = sPageDescFollowName;
+ break;
+ }
+
+ return sRet.replaceFirst( "$(ARG1)", OUString::number( nNo ));
+}
+
+SwGlossaries* GetGlossaries()
+{
+ if (!pGlossaries)
+ pGlossaries.reset( new SwGlossaries );
+ return pGlossaries.get();
+}
+
+bool HasGlossaryList()
+{
+ return pGlossaryList != nullptr;
+}
+
+SwGlossaryList* GetGlossaryList()
+{
+ if(!pGlossaryList)
+ pGlossaryList = new SwGlossaryList();
+
+ return pGlossaryList;
+}
+
+void ShellResource::GetAutoFormatNameLst_() const
+{
+ assert(!mxAutoFormatNameLst);
+ mxAutoFormatNameLst.emplace();
+ mxAutoFormatNameLst->reserve(STR_AUTOFMTREDL_END);
+
+ static_assert(SAL_N_ELEMENTS(RID_SHELLRES_AUTOFMTSTRS) == STR_AUTOFMTREDL_END);
+ for (sal_uInt16 n = 0; n < STR_AUTOFMTREDL_END; ++n)
+ {
+ OUString p(SwResId(RID_SHELLRES_AUTOFMTSTRS[n]));
+ if (STR_AUTOFMTREDL_TYPO == n)
+ {
+ const SvtSysLocale aSysLocale;
+ const LocaleDataWrapper& rLclD = aSysLocale.GetLocaleData();
+ p = p.replaceFirst("%1", rLclD.getDoubleQuotationMarkStart());
+ p = p.replaceFirst("%2", rLclD.getDoubleQuotationMarkEnd());
+ }
+ mxAutoFormatNameLst->push_back(p);
+ }
+}
+
+namespace
+{
+ const TranslateId STR_AUTH_FIELD_ARY[] =
+ {
+ STR_AUTH_FIELD_IDENTIFIER,
+ STR_AUTH_FIELD_AUTHORITY_TYPE,
+ STR_AUTH_FIELD_ADDRESS,
+ STR_AUTH_FIELD_ANNOTE,
+ STR_AUTH_FIELD_AUTHOR,
+ STR_AUTH_FIELD_BOOKTITLE,
+ STR_AUTH_FIELD_CHAPTER,
+ STR_AUTH_FIELD_EDITION,
+ STR_AUTH_FIELD_EDITOR,
+ STR_AUTH_FIELD_HOWPUBLISHED,
+ STR_AUTH_FIELD_INSTITUTION,
+ STR_AUTH_FIELD_JOURNAL,
+ STR_AUTH_FIELD_MONTH,
+ STR_AUTH_FIELD_NOTE,
+ STR_AUTH_FIELD_NUMBER,
+ STR_AUTH_FIELD_ORGANIZATIONS,
+ STR_AUTH_FIELD_PAGES,
+ STR_AUTH_FIELD_PUBLISHER,
+ STR_AUTH_FIELD_SCHOOL,
+ STR_AUTH_FIELD_SERIES,
+ STR_AUTH_FIELD_TITLE,
+ STR_AUTH_FIELD_TYPE,
+ STR_AUTH_FIELD_VOLUME,
+ STR_AUTH_FIELD_YEAR,
+ STR_AUTH_FIELD_URL,
+ STR_AUTH_FIELD_CUSTOM1,
+ STR_AUTH_FIELD_CUSTOM2,
+ STR_AUTH_FIELD_CUSTOM3,
+ STR_AUTH_FIELD_CUSTOM4,
+ STR_AUTH_FIELD_CUSTOM5,
+ STR_AUTH_FIELD_ISBN,
+ STR_AUTH_FIELD_LOCAL_URL,
+ STR_AUTH_FIELD_TARGET_TYPE,
+ STR_AUTH_FIELD_TARGET_URL,
+ };
+}
+
+OUString const & SwAuthorityFieldType::GetAuthFieldName(ToxAuthorityField eType)
+{
+ if(!pAuthFieldNameList)
+ {
+ pAuthFieldNameList = new std::vector<OUString>;
+ pAuthFieldNameList->reserve(AUTH_FIELD_END);
+ for (sal_uInt16 i = 0; i < AUTH_FIELD_END; ++i)
+ pAuthFieldNameList->push_back(SwResId(STR_AUTH_FIELD_ARY[i]));
+ }
+ return (*pAuthFieldNameList)[static_cast< sal_uInt16 >(eType)];
+}
+
+const TranslateId STR_AUTH_TYPE_ARY[] =
+{
+ STR_AUTH_TYPE_ARTICLE,
+ STR_AUTH_TYPE_BOOK,
+ STR_AUTH_TYPE_BOOKLET,
+ STR_AUTH_TYPE_CONFERENCE,
+ STR_AUTH_TYPE_INBOOK,
+ STR_AUTH_TYPE_INCOLLECTION,
+ STR_AUTH_TYPE_INPROCEEDINGS,
+ STR_AUTH_TYPE_JOURNAL,
+ STR_AUTH_TYPE_MANUAL,
+ STR_AUTH_TYPE_MASTERSTHESIS,
+ STR_AUTH_TYPE_MISC,
+ STR_AUTH_TYPE_PHDTHESIS,
+ STR_AUTH_TYPE_PROCEEDINGS,
+ STR_AUTH_TYPE_TECHREPORT,
+ STR_AUTH_TYPE_UNPUBLISHED,
+ STR_AUTH_TYPE_EMAIL,
+ STR_AUTH_TYPE_WWW,
+ STR_AUTH_TYPE_CUSTOM1,
+ STR_AUTH_TYPE_CUSTOM2,
+ STR_AUTH_TYPE_CUSTOM3,
+ STR_AUTH_TYPE_CUSTOM4,
+ STR_AUTH_TYPE_CUSTOM5
+};
+
+OUString const & SwAuthorityFieldType::GetAuthTypeName(ToxAuthorityType eType)
+{
+ if(!pAuthFieldTypeList)
+ {
+ pAuthFieldTypeList = new std::vector<OUString>;
+ pAuthFieldTypeList->reserve(AUTH_TYPE_END);
+ for (sal_uInt16 i = 0; i < AUTH_TYPE_END; ++i)
+ pAuthFieldTypeList->push_back(SwResId(STR_AUTH_TYPE_ARY[i]));
+ }
+ return (*pAuthFieldTypeList)[static_cast< sal_uInt16 >(eType)];
+}
+
+void SwAuthorityFieldType::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwAuthorityFieldType"));
+ SwFieldType::dumpAsXml(pWriter);
+
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("DataArr"));
+ for (const auto& xAuthEntry : m_DataArr)
+ {
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("AuthEntry"));
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", xAuthEntry.get());
+ (void)xmlTextWriterEndElement(pWriter);
+ }
+ (void)xmlTextWriterEndElement(pWriter);
+
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/utlui/navicfg.cxx b/sw/source/uibase/utlui/navicfg.cxx
new file mode 100644
index 0000000000..dfda882729
--- /dev/null
+++ b/sw/source/uibase/utlui/navicfg.cxx
@@ -0,0 +1,196 @@
+/* -*- 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 <swtypes.hxx>
+#include <navicfg.hxx>
+#include <swcont.hxx>
+#include <o3tl/any.hxx>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <map>
+
+using namespace ::utl;
+using namespace ::com::sun::star::uno;
+
+namespace {
+ std::map<OUString, ContentTypeId> mPropNameToContentTypeId
+ {
+ {"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}
+ };
+}
+
+Sequence<OUString> SwNavigationConfig::GetPropertyNames()
+{
+ return css::uno::Sequence<OUString>{
+ OUString("RootType"),
+ OUString("SelectedPosition"),
+ OUString("OutlineLevel"),
+ OUString("InsertMode"),
+ OUString("ActiveBlock"),
+ OUString("ShowListBox"),
+ OUString("GlobalDocMode"),
+ OUString("OutlineTracking"),
+ OUString("TableTracking"),
+ OUString("SectionTracking"),
+ OUString("FrameTracking"),
+ OUString("ImageTracking"),
+ OUString("OLEobjectTracking"),
+ OUString("BookmarkTracking"),
+ OUString("HyperlinkTracking"),
+ OUString("ReferenceTracking"),
+ OUString("IndexTracking"),
+ OUString("CommentTracking"),
+ OUString("DrawingObjectTracking"),
+ OUString("FieldTracking"),
+ OUString("FootnoteTracking"),
+ OUString("EndnoteTracking"),
+ OUString("NavigateOnSelect"),
+ OUString("SortAlphabeticallyBlock")};
+}
+
+SwNavigationConfig::SwNavigationConfig() :
+ utl::ConfigItem("Office.Writer/Navigator"),
+ m_nRootType(ContentTypeId::UNKNOWN),
+ m_nSelectedPos(0),
+ m_nOutlineLevel(MAXLEVEL),
+ m_nRegionMode(RegionMode::NONE),
+ m_nActiveBlock(0),
+ m_bIsSmall(false),
+ m_bIsGlobalActive(true),
+ m_nOutlineTracking(1),
+ m_bIsNavigateOnSelect(false)
+{
+ Load();
+ EnableNotification(GetPropertyNames());
+}
+
+void SwNavigationConfig::Load()
+{
+ Sequence<OUString> aNames = GetPropertyNames();
+ Sequence<Any> aValues = GetProperties(aNames);
+ const Any* pValues = aValues.getConstArray();
+ OSL_ENSURE(aValues.getLength() == aNames.getLength(), "GetProperties failed");
+ if(aValues.getLength() != aNames.getLength())
+ return;
+
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ if(pValues[nProp].hasValue())
+ {
+ switch(nProp)
+ {
+ case 0:
+ {
+ sal_Int32 nTmp = {}; // spurious -Werror=maybe-uninitialized
+ if (pValues[nProp] >>= nTmp)
+ {
+ if (nTmp < sal_Int32(ContentTypeId::UNKNOWN)
+ || nTmp > sal_Int32(ContentTypeId::LAST))
+ {
+ SAL_WARN(
+ "sw",
+ "out-of-bounds ContentTypeId " << nTmp);
+ nTmp = sal_Int32(ContentTypeId::UNKNOWN);
+ }
+ m_nRootType = static_cast<ContentTypeId>(nTmp);
+ }
+ break;
+ }
+ case 1: pValues[nProp] >>= m_nSelectedPos; break;
+ case 2: pValues[nProp] >>= m_nOutlineLevel; break;
+ case 3:
+ {
+ sal_Int32 nTmp;
+ if (pValues[nProp] >>= nTmp)
+ m_nRegionMode = static_cast<RegionMode>(nTmp);
+ break;
+ }
+ case 4: pValues[nProp] >>= m_nActiveBlock; break;
+ case 5: m_bIsSmall = *o3tl::doAccess<bool>(pValues[nProp]); break;
+ case 6: m_bIsGlobalActive = *o3tl::doAccess<bool>(pValues[nProp]); break;
+ case 7: pValues[nProp] >>= m_nOutlineTracking; break;
+ case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16:
+ case 17: case 18: case 19: case 20: case 21:
+ {
+ mContentTypeTrack[mPropNameToContentTypeId[aNames[nProp]]] =
+ *o3tl::doAccess<bool>(pValues[nProp]);
+ break;
+ }
+ case 22: m_bIsNavigateOnSelect = *o3tl::doAccess<bool>(pValues[nProp]); break;
+ case 23: pValues[nProp] >>= m_nSortAlphabeticallyBlock; break;
+ }
+ }
+ }
+}
+
+SwNavigationConfig::~SwNavigationConfig()
+{
+}
+
+void SwNavigationConfig::ImplCommit()
+{
+ Sequence<OUString> aNames = GetPropertyNames();
+ Sequence<Any> aValues(aNames.getLength());
+ Any* pValues = aValues.getArray();
+
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ switch(nProp)
+ {
+ case 0: pValues[nProp] <<= static_cast<sal_Int32>(m_nRootType); break;
+ case 1: pValues[nProp] <<= m_nSelectedPos; break;
+ case 2: pValues[nProp] <<= m_nOutlineLevel; break;
+ case 3: pValues[nProp] <<= static_cast<sal_uInt16>(m_nRegionMode); break;
+ case 4: pValues[nProp] <<= m_nActiveBlock; break;
+ case 5: pValues[nProp] <<= m_bIsSmall; break;
+ case 6: pValues[nProp] <<= m_bIsGlobalActive; break;
+ case 7: pValues[nProp] <<= m_nOutlineTracking; break;
+ case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16:
+ case 17: case 18: case 19: case 20: case 21:
+ {
+ pValues[nProp] <<= mContentTypeTrack[mPropNameToContentTypeId[aNames[nProp]]];
+ break;
+ }
+ case 22: pValues[nProp] <<= m_bIsNavigateOnSelect; break;
+ case 23: pValues[nProp] <<= m_nSortAlphabeticallyBlock; break;
+ }
+ }
+ PutProperties(aNames, aValues);
+}
+
+void SwNavigationConfig::Notify( const css::uno::Sequence< OUString >& )
+{
+ Load();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/utlui/navipi.cxx b/sw/source/uibase/utlui/navipi.cxx
new file mode 100644
index 0000000000..3fd5b7f9b6
--- /dev/null
+++ b/sw/source/uibase/utlui/navipi.cxx
@@ -0,0 +1,1277 @@
+/* -*- 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/string.hxx>
+#include <svl/urlbmk.hxx>
+#include <svl/stritem.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <sot/formats.hxx>
+#include <sot/filelist.hxx>
+#include <sfx2/event.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <tools/urlobj.hxx>
+#include <osl/diagnose.h>
+#include <swtypes.hxx>
+#include <swmodule.hxx>
+#include <view.hxx>
+#include <navicfg.hxx>
+#include <wrtsh.hxx>
+#include <docsh.hxx>
+#include <navipi.hxx>
+#include <edtwin.hxx>
+#include <sfx2/app.hxx>
+#include <cmdid.h>
+#include <helpids.h>
+
+#include <strings.hrc>
+#include <bitmaps.hlst>
+
+#include <memory>
+
+#include <o3tl/enumrange.hxx>
+
+#include <workctrl.hxx>
+
+#include <comphelper/lok.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::frame;
+
+// Filter the control characters out of the Outline-Entry
+OUString SwNavigationPI::CleanEntry(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] == 9)
+ aEntry[i] = 0x20;
+
+ return aEntry.makeStringAndClear();
+}
+
+// Execution of the drag operation with and without the children.
+
+void SwNavigationPI::MoveOutline(SwOutlineNodes::size_type nSource, SwOutlineNodes::size_type nTarget)
+{
+ SwView *pView = GetCreateView();
+ SwWrtShell &rSh = pView->GetWrtShell();
+ if(nTarget < nSource || nTarget == SwOutlineNodes::npos)
+ nTarget ++;
+ if ( !rSh.IsOutlineMovable( nSource ))
+ return;
+
+ SwOutlineNodes::difference_type nMove = nTarget-nSource; //( nDir<0 ) ? 1 : 0 ;
+ rSh.GotoOutline(nSource);
+ rSh.MakeOutlineSel(nSource, nSource, true);
+ // While moving, the selected children does not counting.
+ const SwOutlineNodes::size_type nLastOutlinePos = rSh.GetOutlinePos(MAXLEVEL);
+ if(nMove > 1 && nLastOutlinePos < nTarget)
+ {
+ if(!rSh.IsCursorPtAtEnd())
+ rSh.SwapPam();
+ nMove -= nLastOutlinePos - nSource;
+ }
+ if( nMove < 1 || nLastOutlinePos < nTarget )
+ rSh.MoveOutlinePara( nMove );
+ rSh.ClearMark();
+ rSh.GotoOutline( nSource + nMove);
+
+}
+
+// After goto cancel the status frame selection
+static void lcl_UnSelectFrame(SwWrtShell *pSh)
+{
+ if (pSh->IsFrameSelected())
+ {
+ pSh->UnSelectFrame();
+ pSh->LeaveSelFrameMode();
+ }
+}
+
+// Select the document view
+IMPL_LINK(SwNavigationPI, DocListBoxSelectHdl, weld::ComboBox&, rBox, void)
+{
+ int nEntryIdx = rBox.get_active();
+ SwView *pView ;
+ pView = SwModule::GetFirstView();
+ while (nEntryIdx-- && pView)
+ {
+ pView = SwModule::GetNextView(pView);
+ }
+ if(!pView)
+ {
+ nEntryIdx == 0 ?
+ m_xContentTree->ShowHiddenShell():
+ m_xContentTree->ShowActualView();
+
+ }
+ else
+ {
+ m_xContentTree->SetConstantShell(pView->GetWrtShellPtr());
+ }
+}
+
+void SwNavigationPI::UpdateNavigateBy()
+{
+ if (!m_pNavigateByComboBox)
+ return;
+ SfxUInt32Item aParam(FN_NAV_ELEMENT, m_pNavigateByComboBox->get_active_id().toUInt32());
+ const SfxPoolItem* aArgs[2];
+ aArgs[0] = &aParam;
+ aArgs[1] = nullptr;
+ SfxDispatcher* pDispatcher = GetCreateView()->GetFrame()->GetDispatcher();
+ pDispatcher->Execute(FN_NAV_ELEMENT, SfxCallMode::SYNCHRON, aArgs);
+}
+
+IMPL_LINK(SwNavigationPI, NavigateByComboBoxSelectHdl, weld::ComboBox&, rComboBox, void)
+{
+ m_xContentTree->SelectContentType(rComboBox.get_active_text());
+ UpdateNavigateBy();
+}
+
+// Filling of the list box for outline view or documents
+// The PI will be set to full size
+void SwNavigationPI::FillBox()
+{
+ if(m_pContentWrtShell)
+ {
+ m_xContentTree->SetHiddenShell( m_pContentWrtShell );
+ m_xContentTree->Display( false );
+ }
+ else
+ {
+ SwView *pView = GetCreateView();
+ if(!pView)
+ {
+ m_xContentTree->SetActiveShell(nullptr);
+ }
+ else if( pView != m_pActContView)
+ {
+ SwWrtShell* pWrtShell = pView->GetWrtShellPtr();
+ m_xContentTree->SetActiveShell(pWrtShell);
+ }
+ else
+ m_xContentTree->Display( true );
+ m_pActContView = pView;
+ if (m_pActContView)
+ m_xContentTree->UpdateTracking();
+ }
+}
+
+void SwNavigationPI::UsePage()
+{
+ SwView *pView = GetCreateView();
+ SwWrtShell *pSh = pView ? &pView->GetWrtShell() : nullptr;
+ m_xEdit->set_value(1);
+ if (pSh)
+ {
+ const sal_uInt16 nPageCnt = pSh->GetPageCnt();
+ sal_uInt16 nPhyPage, nVirPage;
+ pSh->GetPageNum(nPhyPage, nVirPage);
+
+ m_xEdit->set_max(nPageCnt);
+ m_xEdit->set_width_chars(3);
+ m_xEdit->set_value(nPhyPage);
+ }
+}
+
+// Select handler of the toolboxes
+IMPL_LINK(SwNavigationPI, ToolBoxSelectHdl, const OUString&, rCommand, void)
+{
+ SwView *pView = GetCreateView();
+ if (!pView)
+ return;
+ SwWrtShell &rSh = pView->GetWrtShell();
+ // Get MouseModifier for Outline-Move
+
+ int nFuncId = 0;
+ bool bFocusToDoc = false;
+ if (rCommand == ".uno:ScrollToPrevious" || rCommand == ".uno:ScrollToNext")
+ {
+ bool *pbNext = new bool(true);
+ if (rCommand == ".uno:ScrollToPrevious")
+ *pbNext = false;
+ pView->MoveNavigationHdl(pbNext);
+ }
+ else if (rCommand == "root")
+ {
+ m_xContentTree->ToggleToRoot();
+ }
+ else if (rCommand == "listbox")
+ {
+ if (ParentIsFloatingWindow(m_xNavigatorDlg))
+ {
+ if (IsZoomedIn())
+ {
+ ZoomOut();
+ }
+ else
+ {
+ ZoomIn();
+ }
+ }
+ return;
+ }
+ // Functions that will trigger a direct action.
+ else if (rCommand == "footer")
+ {
+ rSh.MoveCursor();
+ const FrameTypeFlags eType = rSh.GetFrameType(nullptr,false);
+ if (eType & FrameTypeFlags::FOOTER)
+ {
+ if (rSh.EndPg())
+ nFuncId = FN_END_OF_PAGE;
+ }
+ else if (rSh.GotoFooterText())
+ nFuncId = FN_TO_FOOTER;
+ bFocusToDoc = true;
+ }
+ else if (rCommand == "header")
+ {
+ rSh.MoveCursor();
+ const FrameTypeFlags eType = rSh.GetFrameType(nullptr,false);
+ if (eType & FrameTypeFlags::HEADER)
+ {
+ if (rSh.SttPg())
+ nFuncId = FN_START_OF_PAGE;
+ }
+ else if (rSh.GotoHeaderText())
+ nFuncId = FN_TO_HEADER;
+ bFocusToDoc = true;
+ }
+ else if (rCommand == "anchor")
+ {
+ rSh.MoveCursor();
+ const FrameTypeFlags eFrameType = rSh.GetFrameType(nullptr,false);
+ // Jump from the footnote to the anchor.
+ if (eFrameType & FrameTypeFlags::FOOTNOTE)
+ {
+ if (rSh.GotoFootnoteAnchor())
+ nFuncId = FN_FOOTNOTE_TO_ANCHOR;
+ }
+ // Otherwise, jump to the first footnote text;
+ // go to the next footnote if this is not possible;
+ // if this is also not possible got to the footnote before.
+ else
+ {
+ if (rSh.GotoFootnoteText())
+ nFuncId = FN_FOOTNOTE_TO_ANCHOR;
+ else if (rSh.GotoNextFootnoteAnchor())
+ nFuncId = FN_NEXT_FOOTNOTE;
+ else if (rSh.GotoPrevFootnoteAnchor())
+ nFuncId = FN_PREV_FOOTNOTE;
+ }
+ bFocusToDoc = true;
+ }
+ else if (rCommand == "reminder")
+ {
+ rSh.GetView().GetViewFrame().GetDispatcher()->Execute(FN_SET_REMINDER, SfxCallMode::ASYNCHRON);
+ }
+ else if (rCommand == "chapterdown" ||
+ rCommand == "movedown" ||
+ rCommand == "chapterup" ||
+ rCommand == "moveup" ||
+ rCommand == "promote" ||
+ rCommand == "demote" ||
+ rCommand == "edit")
+ {
+ if (IsGlobalMode())
+ m_xGlobalTree->ExecCommand(rCommand);
+ else
+ {
+ // Standard: sublevels are taken
+ // do not take sublevels with Ctrl
+ bool bOutlineWithChildren = (KEY_MOD1 != m_xContent6ToolBox->get_modifier_state());
+ m_xContentTree->ExecCommand(rCommand, bOutlineWithChildren);
+ }
+ }
+ else if (rCommand == "contenttoggle" || rCommand == "globaltoggle")
+ {
+ ToggleTree();
+ bool bGlobalMode = IsGlobalMode();
+ m_pConfig->SetGlobalActive(bGlobalMode);
+ m_xGlobalToolBox->set_item_active("globaltoggle", bGlobalMode);
+ m_xContent1ToolBox->set_item_active("contenttoggle", bGlobalMode);
+ }
+ else if (rCommand == "save")
+ {
+ bool bSave = rSh.IsGlblDocSaveLinks();
+ rSh.SetGlblDocSaveLinks( !bSave );
+ m_xGlobalToolBox->set_item_active(rCommand, !bSave);
+ }
+ else if (rCommand == "dragmode")
+ m_xContent6ToolBox->set_menu_item_active("dragmode", !m_xContent6ToolBox->get_menu_item_active("dragmode"));
+ else if (rCommand == "headings")
+ m_xContent5ToolBox->set_menu_item_active("headings", !m_xContent5ToolBox->get_menu_item_active("headings"));
+ else if (rCommand == "update")
+ m_xGlobalToolBox->set_menu_item_active("update", !m_xGlobalToolBox->get_menu_item_active("update"));
+ else if (rCommand == "insert")
+ m_xGlobalToolBox->set_menu_item_active("insert", !m_xGlobalToolBox->get_menu_item_active("insert"));
+
+ if (nFuncId)
+ lcl_UnSelectFrame(&rSh);
+ if (bFocusToDoc)
+ pView->GetEditWin().GrabFocus();
+}
+
+// Click handler of the toolboxes
+IMPL_LINK(SwNavigationPI, ToolBoxClickHdl, const OUString&, rCommand, void)
+{
+ if (!m_xGlobalToolBox->get_menu_item_active(rCommand))
+ return;
+
+ if (rCommand == "update")
+ m_xGlobalTree->TbxMenuHdl(rCommand, *m_xUpdateMenu);
+ else if (rCommand == "insert")
+ m_xGlobalTree->TbxMenuHdl(rCommand, *m_xInsertMenu);
+}
+
+IMPL_LINK(SwNavigationPI, ToolBox6DropdownClickHdl, const OUString&, rCommand, void)
+{
+ if (!m_xContent6ToolBox->get_menu_item_active(rCommand))
+ return;
+
+ if (rCommand != "dragmode")
+ return;
+
+ switch (m_nRegionMode)
+ {
+ case RegionMode::NONE:
+ m_xDragModeMenu->set_active("hyperlink", true);
+ break;
+ case RegionMode::LINK:
+ m_xDragModeMenu->set_active("link", true);
+ break;
+ case RegionMode::EMBEDDED:
+ m_xDragModeMenu->set_active("copy", true);
+ break;
+ }
+}
+
+IMPL_LINK(SwNavigationPI, DropModeMenuSelectHdl, const OUString&, rIdent, void)
+{
+ if (rIdent == "hyperlink")
+ SetRegionDropMode(RegionMode::NONE);
+ else if (rIdent == "link")
+ SetRegionDropMode(RegionMode::LINK);
+ else if (rIdent == "copy")
+ SetRegionDropMode(RegionMode::EMBEDDED);
+}
+
+IMPL_LINK(SwNavigationPI, GlobalMenuSelectHdl, const OUString&, rIdent, void)
+{
+ m_xGlobalTree->ExecuteContextMenuAction(rIdent);
+}
+
+IMPL_LINK(SwNavigationPI, ToolBox5DropdownClickHdl, const OUString&, rCommand, void)
+{
+ if (!m_xContent5ToolBox->get_menu_item_active(rCommand))
+ return;
+
+ if (rCommand == "headings")
+ m_xHeadingsMenu->set_active(OUString::number(m_xContentTree->GetOutlineLevel()), true);
+}
+
+// Action-Handler Edit:
+// Switches to the page if the structure view is not turned on.
+bool SwNavigationPI::EditAction()
+{
+ SwView *pView = GetCreateView();
+ if (!pView)
+ return false;
+
+ if (m_aPageChgIdle.IsActive())
+ m_aPageChgIdle.Stop();
+
+ // if the user has clicked into the document, forget about changing the page
+ if (pView->GetEditWin().HasFocus())
+ return false;
+
+ if (m_xEdit->get_text().isEmpty())
+ return false;
+ sal_Int64 nNewPage = m_xEdit->get_text().toInt32();
+ SwWrtShell& rSh = m_pCreateView->GetWrtShell();
+ sal_Int64 max = rSh.GetPageCnt();
+ if (nNewPage <= 0)
+ nNewPage = 1;
+ else if (nNewPage > max)
+ nNewPage = max;
+ m_xEdit->set_value(nNewPage);
+ m_xEdit->set_position(-1);
+
+ rSh.GotoPage(nNewPage, true);
+ m_pCreateView->GetViewFrame().GetBindings().Invalidate(FN_STAT_PAGE);
+
+ return true;
+}
+
+void SwNavigationPI::ZoomOut()
+{
+ if (!IsZoomedIn())
+ return;
+ SfxNavigator* pNav = m_xNavigatorDlg.get();
+ if (!pNav)
+ return;
+ m_bIsZoomedIn = false;
+ FillBox();
+ if (IsGlobalMode())
+ {
+ m_xGlobalBox->show();
+ m_xGlobalTree->ShowTree();
+ }
+ else
+ {
+ m_xContentBox->show();
+ m_xContentTree->ShowTree();
+ m_xDocListBox->show();
+ }
+
+ pNav->InvalidateChildSizeCache();
+ Size aOptimalSize(pNav->GetOptimalSize());
+ Size aNewSize(pNav->GetOutputSizePixel());
+ aNewSize.setHeight( m_aExpandedSize.Height() );
+ pNav->SetMinOutputSizePixel(aOptimalSize);
+ pNav->SetOutputSizePixel(aNewSize);
+
+ m_xContentTree->Select(); // Enable toolbox
+ m_pConfig->SetSmall(false);
+ m_xContent6ToolBox->set_item_active("listbox", true);
+}
+
+void SwNavigationPI::ZoomIn()
+{
+ if (IsZoomedIn())
+ return;
+ SfxNavigator* pNav = m_xNavigatorDlg.get();
+ if (!pNav)
+ return;
+
+ m_aExpandedSize = m_xNavigatorDlg->GetSizePixel();
+
+ m_xContentBox->hide();
+ m_xContentTree->HideTree();
+ m_xGlobalBox->hide();
+ m_xGlobalTree->HideTree();
+ m_xDocListBox->hide();
+ m_bIsZoomedIn = true;
+
+ pNav->InvalidateChildSizeCache();
+ Size aOptimalSize(pNav->GetOptimalSize());
+ Size aNewSize(pNav->GetOutputSizePixel());
+ aNewSize.setHeight( aOptimalSize.Height() );
+ pNav->SetMinOutputSizePixel(aOptimalSize);
+ pNav->SetOutputSizePixel(aNewSize);
+
+ m_xContentTree->Select(); // Enable toolbox
+
+ m_pConfig->SetSmall(true);
+ m_xContent6ToolBox->set_item_active("listbox", false);
+}
+
+namespace {
+
+enum StatusIndex
+{
+ IDX_STR_HIDDEN = 0,
+ IDX_STR_ACTIVE = 1,
+ IDX_STR_INACTIVE = 2
+};
+
+}
+
+std::unique_ptr<PanelLayout> SwNavigationPI::Create(weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings)
+{
+ if( pParent == nullptr )
+ throw css::lang::IllegalArgumentException("no parent window given to SwNavigationPI::Create", nullptr, 0);
+ if( !rxFrame.is() )
+ throw css::lang::IllegalArgumentException("no XFrame given to SwNavigationPI::Create", nullptr, 0);
+ if( pBindings == nullptr )
+ throw css::lang::IllegalArgumentException("no SfxBindings given to SwNavigationPI::Create", nullptr, 0);
+ return std::make_unique<SwNavigationPI>(pParent, rxFrame, pBindings, nullptr);
+}
+
+IMPL_LINK_NOARG(SwNavigationPI, PageModifiedHdl, weld::Entry&, void)
+{
+ SwView* pView = GetCreateView();
+ if (!pView)
+ return;
+ if (m_xEdit->get_text().isEmpty())
+ return;
+ sal_Int64 page_value = m_xEdit->get_text().toInt32();
+ SwWrtShell& rSh = m_pCreateView->GetWrtShell();
+ sal_Int64 max = rSh.GetPageCnt();
+ if (page_value <= 0)
+ m_xEdit->set_value(1);
+ else if (page_value > max)
+ m_xEdit->set_value(max);
+ else
+ m_xEdit->set_value(page_value);
+ m_xEdit->set_position(-1);
+}
+
+SwNavigationPI::SwNavigationPI(weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* _pBindings, SfxNavigator* pNavigatorDlg)
+ : PanelLayout(pParent, "NavigatorPanel", "modules/swriter/ui/navigatorpanel.ui")
+ , m_aDocFullName(SID_DOCFULLNAME, *_pBindings, *this)
+ , m_aPageStats(FN_STAT_PAGE, *_pBindings, *this)
+ , m_xContent1ToolBox(m_xBuilder->weld_toolbar("content1"))
+ , m_xContent2ToolBox(m_xBuilder->weld_toolbar("content2"))
+ , m_xContent3ToolBox(m_xBuilder->weld_toolbar("content3"))
+ , m_xContent4ToolBox(m_xBuilder->weld_toolbar("content4"))
+ , m_xContent5ToolBox(m_xBuilder->weld_toolbar("content5"))
+ , m_xContent6ToolBox(m_xBuilder->weld_toolbar("content6"))
+ , m_xContent2Dispatch(new ToolbarUnoDispatcher(*m_xContent2ToolBox, *m_xBuilder, rxFrame))
+ , m_xContent3Dispatch(new ToolbarUnoDispatcher(*m_xContent3ToolBox, *m_xBuilder, rxFrame))
+ , m_xHeadingsMenu(m_xBuilder->weld_menu("headingsmenu"))
+ , m_xDragModeMenu(m_xBuilder->weld_menu("dragmodemenu"))
+ , m_xUpdateMenu(m_xBuilder->weld_menu("updatemenu"))
+ , m_xInsertMenu(m_xBuilder->weld_menu("insertmenu"))
+ , m_xGlobalToolBox(m_xBuilder->weld_toolbar("global"))
+ , m_xEdit(m_xBuilder->weld_spin_button("spinbutton"))
+ , m_xContentBox(m_xBuilder->weld_widget("contentbox"))
+ , m_xContentTree(new SwContentTree(m_xBuilder->weld_tree_view("contenttree"), this))
+ , m_xGlobalBox(m_xBuilder->weld_widget("globalbox"))
+ , m_xGlobalTree(new SwGlobalTree(m_xBuilder->weld_tree_view("globaltree"), this))
+ , m_xDocListBox(m_xBuilder->weld_combo_box("documents"))
+ , m_aPageChgIdle("SwNavigationPI m_aPageChgIdle")
+ , m_xNavigatorDlg(pNavigatorDlg)
+ , m_pContentView(nullptr)
+ , m_pContentWrtShell(nullptr)
+ , m_pActContView(nullptr)
+ , m_pCreateView(nullptr)
+ , m_pConfig(SW_MOD()->GetNavigationConfig())
+ , m_rBindings(*_pBindings)
+ , m_nRegionMode(RegionMode::NONE)
+ , m_bIsZoomedIn(false)
+ , m_bGlobalMode(false)
+{
+ m_xContainer->connect_container_focus_changed(LINK(this, SwNavigationPI, SetFocusChildHdl));
+
+ Reference<XToolbarController> xController =
+ m_xContent2Dispatch->GetControllerForCommand(".uno:NavElement");
+ NavElementToolBoxControl* pToolBoxControl =
+ dynamic_cast<NavElementToolBoxControl*>(xController.get());
+
+ // In case of LOK, the xController may not a NavElementToolBoxControl
+ if (comphelper::LibreOfficeKit::isActive() && !pToolBoxControl)
+ {
+ m_pNavigateByComboBox = nullptr;
+ }
+ else
+ {
+ assert(pToolBoxControl);
+ m_pNavigateByComboBox = pToolBoxControl->GetComboBox();
+ }
+
+ // Restore content tree settings before calling UpdateInitShow. UpdateInitShow calls Fillbox,
+ // which calls Display and UpdateTracking. Incorrect outline levels could be displayed and
+ // unexpected content tracking could occur if these content tree settings are not done before.
+ m_xContentTree->SetOutlineLevel(static_cast<sal_uInt8>(m_pConfig->GetOutlineLevel()));
+ m_xContentTree->SetOutlineTracking(static_cast<sal_uInt8>(m_pConfig->GetOutlineTracking()));
+ for (ContentTypeId eCntTypeId : o3tl::enumrange<ContentTypeId>())
+ {
+ if (eCntTypeId != ContentTypeId::OUTLINE)
+ m_xContentTree->SetContentTypeTracking(
+ eCntTypeId, m_pConfig->IsContentTypeTrack(eCntTypeId));
+ }
+
+ if (const ContentTypeId nRootType = m_pConfig->GetRootType();
+ nRootType != ContentTypeId::UNKNOWN)
+ {
+ m_xContentTree->SetRootType(nRootType);
+ m_xContent5ToolBox->set_item_active("root", true);
+ if (nRootType == ContentTypeId::OUTLINE || nRootType == ContentTypeId::DRAWOBJECT)
+ m_xContentTree->set_selection_mode(SelectionMode::Multiple);
+ else
+ m_xContentTree->set_selection_mode(SelectionMode::Single);
+ }
+ else
+ m_xContentTree->set_selection_mode(SelectionMode::Single);
+
+ UpdateInitShow();
+
+ GetCreateView();
+
+ m_xContent1ToolBox->set_help_id(HID_NAVIGATOR_TOOLBOX);
+ m_xContent2ToolBox->set_help_id(HID_NAVIGATOR_TOOLBOX);
+ m_xContent3ToolBox->set_help_id(HID_NAVIGATOR_TOOLBOX);
+ m_xContent4ToolBox->set_help_id(HID_NAVIGATOR_TOOLBOX);
+ m_xContent5ToolBox->set_help_id(HID_NAVIGATOR_TOOLBOX);
+ m_xContent6ToolBox->set_help_id(HID_NAVIGATOR_TOOLBOX);
+ m_xGlobalToolBox->set_help_id(HID_NAVIGATOR_GLOBAL_TOOLBOX);
+ m_xDocListBox->set_help_id(HID_NAVIGATOR_LISTBOX);
+ m_xDocListBox->set_size_request(42, -1); // set a nominal width so it takes width of surroundings
+
+ // Insert the numeric field in the toolbox.
+ m_xEdit->set_accessible_name(m_xEdit->get_tooltip_text());
+ m_xEdit->set_width_chars(3);
+ m_xEdit->connect_activate(LINK(this, SwNavigationPI, EditActionHdl));
+ m_xEdit->connect_value_changed(LINK(this, SwNavigationPI, PageEditModifyHdl));
+ m_xEdit->connect_changed(LINK(this, SwNavigationPI, PageModifiedHdl));
+ m_xEdit->set_help_id("modules/swriter/ui/navigatorpanel/numericfield");
+
+ if (!IsGlobalDoc())
+ {
+ m_xContent1ToolBox->set_item_visible("contenttoggle", false);
+ }
+
+ const TranslateId REGIONNAME_ARY[] =
+ {
+ STR_HYPERLINK,
+ STR_LINK_REGION,
+ STR_COPY_REGION
+ };
+
+ const TranslateId REGIONMODE_ARY[] =
+ {
+ STR_HIDDEN,
+ STR_ACTIVE,
+ STR_INACTIVE
+ };
+
+ static_assert(SAL_N_ELEMENTS(REGIONNAME_ARY) == SAL_N_ELEMENTS(REGIONMODE_ARY), "### unexpected size!");
+ static_assert(SAL_N_ELEMENTS(REGIONNAME_ARY) == static_cast<sal_uInt16>(RegionMode::EMBEDDED) + 1, "### unexpected size!");
+
+ for (sal_uInt16 i = 0; i <= static_cast<sal_uInt16>(RegionMode::EMBEDDED); ++i)
+ {
+ m_aStatusArr[i] = SwResId(REGIONMODE_ARY[i]);
+ }
+
+ m_aStatusArr[3] = SwResId(STR_ACTIVE_VIEW);
+
+ bool bFloatingNavigator = ParentIsFloatingWindow(m_xNavigatorDlg);
+
+ SetRegionDropMode(m_pConfig->GetRegionMode());
+
+ m_xContentTree->ShowTree();
+ m_xContent6ToolBox->set_item_active("listbox", true);
+ m_xContent6ToolBox->set_item_sensitive("listbox", bFloatingNavigator);
+
+// TreeListBox for global document
+ m_xGlobalTree->set_selection_mode(SelectionMode::Multiple);
+
+// Handler
+ Link<const OUString&, void> aLk = LINK(this, SwNavigationPI, ToolBoxSelectHdl);
+ m_xContent1ToolBox->connect_clicked(aLk);
+ m_xContent3ToolBox->connect_clicked(aLk);
+ m_xContent5ToolBox->connect_clicked(aLk);
+ m_xContent6ToolBox->connect_clicked(aLk);
+ m_xGlobalToolBox->connect_clicked(aLk);
+ m_xDocListBox->connect_changed(LINK(this, SwNavigationPI, DocListBoxSelectHdl));
+ m_xContent5ToolBox->set_item_menu("headings", m_xHeadingsMenu.get());
+ m_xHeadingsMenu->connect_activate(LINK(this, SwNavigationPI, HeadingsMenuSelectHdl));
+ m_xContent5ToolBox->connect_menu_toggled(LINK(this, SwNavigationPI, ToolBox5DropdownClickHdl));
+ m_xContent6ToolBox->set_item_menu("dragmode", m_xDragModeMenu.get());
+ m_xDragModeMenu->connect_activate(LINK(this, SwNavigationPI, DropModeMenuSelectHdl));
+ m_xContent6ToolBox->connect_menu_toggled(LINK(this, SwNavigationPI, ToolBox6DropdownClickHdl));
+ m_xGlobalToolBox->set_item_menu("update", m_xUpdateMenu.get());
+ m_xUpdateMenu->connect_activate(LINK(this, SwNavigationPI, GlobalMenuSelectHdl));
+ m_xGlobalToolBox->set_item_menu("insert", m_xInsertMenu.get());
+ m_xInsertMenu->connect_activate(LINK(this, SwNavigationPI, GlobalMenuSelectHdl));
+ m_xGlobalToolBox->connect_menu_toggled(LINK(this, SwNavigationPI, ToolBoxClickHdl));
+ m_xGlobalToolBox->set_item_active("globaltoggle", true);
+ if (m_pNavigateByComboBox)
+ m_pNavigateByComboBox->connect_changed(
+ LINK(this, SwNavigationPI, NavigateByComboBoxSelectHdl));
+
+// set toolbar of both modes to widest of each
+ m_xGlobalToolBox->set_size_request(m_xContent1ToolBox->get_preferred_size().Width() +
+ m_xContent2ToolBox->get_preferred_size().Width() +
+ m_xContent3ToolBox->get_preferred_size().Width() +
+ m_xContent4ToolBox->get_preferred_size().Width(), -1);
+
+ StartListening(*SfxGetpApp());
+
+ if(IsGlobalDoc())
+ {
+ SwView *pActView = GetCreateView();
+ if (pActView && pActView->GetWrtShellPtr())
+ m_xGlobalToolBox->set_item_active("save",
+ pActView->GetWrtShellPtr()->IsGlblDocSaveLinks());
+ if (m_pConfig->IsGlobalActive())
+ ToggleTree();
+ if (bFloatingNavigator)
+ m_xGlobalTree->grab_focus();
+ }
+ else if (bFloatingNavigator)
+ m_xContentTree->grab_focus();
+ UsePage();
+ m_aPageChgIdle.SetInvokeHandler(LINK(this, SwNavigationPI, ChangePageHdl));
+ m_aPageChgIdle.SetPriority(TaskPriority::LOWEST);
+
+ m_xContentTree->set_accessible_name(SwResId(STR_ACCESS_TL_CONTENT));
+ m_xGlobalTree->set_accessible_name(SwResId(STR_ACCESS_TL_GLOBAL));
+ m_xDocListBox->set_accessible_name(m_aStatusArr[3]);
+
+ m_aExpandedSize = m_xContainer->get_preferred_size();
+
+ if(comphelper::LibreOfficeKit::isActive())
+ {
+ m_xBuilder->weld_container("gridcontent16")->hide();
+ m_xDocListBox->hide();
+ m_xGlobalBox->hide();
+ m_xGlobalToolBox->hide();
+ m_xGlobalTree->HideTree();
+
+ //Open Headings by default
+ SwView *pView = GetCreateView();
+ if (pView->m_nNaviExpandedStatus < 0)
+ {
+ pView->m_nNaviExpandedStatus = 1;
+ m_xContentTree->ExpandAllHeadings();
+ }
+ }
+}
+
+weld::Window* SwNavigationPI::GetFrameWeld() const
+{
+ if (m_xNavigatorDlg)
+ return m_xNavigatorDlg->GetFrameWeld();
+ return PanelLayout::GetFrameWeld();
+}
+
+SwNavigationPI::~SwNavigationPI()
+{
+ if (IsGlobalDoc() && !IsGlobalMode())
+ {
+ SwView *pView = GetCreateView();
+ SwWrtShell &rSh = pView->GetWrtShell();
+ if (!rSh.IsAllProtect())
+ pView->GetDocShell()->SetReadOnlyUI(false);
+ }
+
+ EndListening(*SfxGetpApp());
+
+ if (m_oObjectShell)
+ {
+ if (m_oObjectShell->Is())
+ (*m_oObjectShell)->DoClose();
+ m_oObjectShell.reset();
+ }
+
+ m_xDocListBox.reset();
+ m_xGlobalTree.reset();
+ m_xGlobalBox.reset();
+ m_xContentTree.reset();
+ m_xContentBox.reset();
+ m_xGlobalToolBox.reset();
+ m_xEdit.reset();
+ m_xHeadingsMenu.reset();
+ m_xDragModeMenu.reset();
+ m_xUpdateMenu.reset();
+ m_xInsertMenu.reset();
+ m_xContent2Dispatch.reset();
+ m_xContent3Dispatch.reset();
+ m_xContent1ToolBox.reset();
+ m_xContent2ToolBox.reset();
+ m_xContent3ToolBox.reset();
+ m_xContent4ToolBox.reset();
+ m_xContent5ToolBox.reset();
+ m_xContent6ToolBox.reset();
+
+ m_aPageChgIdle.Stop();
+
+ m_aDocFullName.dispose();
+ m_aPageStats.dispose();
+}
+
+void SwNavigationPI::NotifyItemUpdate(sal_uInt16 nSID, SfxItemState /*eState*/,
+ const SfxPoolItem* /*pState*/)
+{
+ if (nSID == SID_DOCFULLNAME)
+ {
+ SwView *pActView = GetCreateView();
+ if(pActView)
+ {
+ SwWrtShell* pWrtShell = pActView->GetWrtShellPtr();
+ m_xContentTree->SetActiveShell(pWrtShell);
+ bool bGlobal = IsGlobalDoc();
+ m_xContent1ToolBox->set_item_visible("contenttoggle", bGlobal);
+ if ((!bGlobal && IsGlobalMode()) || (!IsGlobalMode() && m_pConfig->IsGlobalActive()))
+ {
+ ToggleTree();
+ }
+ if (bGlobal)
+ {
+ m_xGlobalToolBox->set_item_active("save", pWrtShell->IsGlblDocSaveLinks());
+ }
+ }
+ else
+ {
+ m_xContentTree->SetActiveShell(nullptr);
+ }
+ UpdateListBox();
+ }
+ else if (nSID == FN_STAT_PAGE)
+ {
+ if(!comphelper::LibreOfficeKit::isActive())
+ {
+ SwView *pActView = GetCreateView();
+ if(pActView)
+ {
+ SwWrtShell &rSh = pActView->GetWrtShell();
+ m_xEdit->set_max(rSh.GetPageCnt());
+ m_xEdit->set_width_chars(3);
+ }
+ }
+ }
+}
+
+void SwNavigationPI::UpdateInitShow()
+{
+ // if the parent isn't a float, then the navigator is displayed in
+ // the sidebar or is otherwise docked. While the navigator could change
+ // its size, the sidebar can not, and the navigator would just waste
+ // space. Therefore disable this button.
+ bool bParentIsFloatingWindow(ParentIsFloatingWindow(m_xNavigatorDlg));
+ m_xContent6ToolBox->set_item_sensitive("listbox", bParentIsFloatingWindow);
+ // show content if docked
+ if (!bParentIsFloatingWindow && IsZoomedIn())
+ ZoomOut();
+ if (!IsZoomedIn())
+ FillBox();
+}
+
+IMPL_LINK_NOARG(SwNavigationPI, SetFocusChildHdl, weld::Container&, void)
+{
+ // update documents listbox
+ UpdateListBox();
+}
+
+// Notification on modified DocInfo
+void SwNavigationPI::Notify( SfxBroadcaster& rBrdc, const SfxHint& rHint )
+{
+ if(&rBrdc == m_pCreateView)
+ {
+ if (rHint.GetId() == SfxHintId::Dying)
+ {
+ EndListening(*m_pCreateView);
+ m_pCreateView = nullptr;
+ m_xContentTree->SetActiveShell(nullptr);
+ }
+ }
+ else
+ {
+ if (rHint.GetId() == SfxHintId::ThisIsAnSfxEventHint)
+ {
+ SfxEventHintId eEventId = static_cast<const SfxEventHint&>(rHint).GetEventId();
+ if (eEventId == SfxEventHintId::OpenDoc)
+ {
+ SwView *pActView = GetCreateView();
+ if(pActView)
+ {
+ SwWrtShell* pWrtShell = pActView->GetWrtShellPtr();
+ m_xContentTree->SetActiveShell(pWrtShell);
+ if (m_xGlobalTree->get_visible())
+ {
+ bool bUpdateAll = m_xGlobalTree->Update(false);
+ // If no update is needed, then update the font colors
+ // at the entries of broken links.
+ m_xGlobalTree->Display(!bUpdateAll);
+ }
+ }
+ }
+ }
+ }
+}
+
+IMPL_LINK( SwNavigationPI, HeadingsMenuSelectHdl, const OUString&, rMenuId, void )
+{
+ if (!rMenuId.isEmpty())
+ m_xContentTree->SetOutlineLevel(rMenuId.toUInt32());
+}
+
+void SwNavigationPI::UpdateListBox()
+{
+ if (!m_xDocListBox) // disposed
+ return;
+
+ m_xDocListBox->freeze();
+ m_xDocListBox->clear();
+ SwView *pActView = GetCreateView();
+ bool bDisable = pActView == nullptr;
+ SwView *pView = SwModule::GetFirstView();
+ sal_Int32 nCount = 0;
+ sal_Int32 nAct = 0;
+ sal_Int32 nConstPos = 0;
+ const SwView* pConstView = m_xContentTree->IsConstantView() &&
+ m_xContentTree->GetActiveWrtShell() ?
+ &m_xContentTree->GetActiveWrtShell()->GetView():
+ nullptr;
+ while (pView)
+ {
+ SfxObjectShell* pDoc = pView->GetDocShell();
+ // #i53333# don't show help pages here
+ if ( !pDoc->IsHelpDocument() )
+ {
+ OUString sEntry = pDoc->GetTitle() + " (";
+ if (pView == pActView)
+ {
+ nAct = nCount;
+ sEntry += m_aStatusArr[IDX_STR_ACTIVE];
+ }
+ else
+ sEntry += m_aStatusArr[IDX_STR_INACTIVE];
+ sEntry += ")";
+ m_xDocListBox->append_text(sEntry);
+
+ if (pConstView && pView == pConstView)
+ nConstPos = nCount;
+
+ nCount++;
+ }
+ pView = SwModule::GetNextView(pView);
+ }
+ m_xDocListBox->append_text(m_aStatusArr[3]); // "Active Window"
+ nCount++;
+
+ if(m_xContentTree->GetHiddenWrtShell())
+ {
+ OUString sEntry = m_xContentTree->GetHiddenWrtShell()->GetView().
+ GetDocShell()->GetTitle() +
+ " (" +
+ m_aStatusArr[IDX_STR_HIDDEN] +
+ ")";
+ m_xDocListBox->append_text(sEntry);
+ bDisable = false;
+ }
+
+ m_xDocListBox->thaw();
+
+ if(m_xContentTree->IsActiveView())
+ {
+ //Either the name of the current Document or "Active Document".
+ m_xDocListBox->set_active(pActView ? nAct : --nCount);
+ }
+ else if(m_xContentTree->IsHiddenView())
+ {
+ m_xDocListBox->set_active(nCount);
+ }
+ else
+ m_xDocListBox->set_active(nConstPos);
+
+ m_xDocListBox->set_sensitive(!bDisable);
+}
+
+IMPL_LINK(SwNavigationPI, DoneLink, SfxPoolItem const *, pItem, void)
+{
+ const SfxViewFrameItem* pFrameItem = dynamic_cast<SfxViewFrameItem const *>( pItem );
+ if( !pFrameItem )
+ return;
+
+ SfxViewFrame* pFrame = pFrameItem->GetFrame();
+ if(pFrame)
+ {
+ m_xContentTree->clear();
+ m_pContentView = dynamic_cast<SwView*>( pFrame->GetViewShell() );
+ OSL_ENSURE(m_pContentView, "no SwView");
+ if(m_pContentView)
+ m_pContentWrtShell = m_pContentView->GetWrtShellPtr();
+ else
+ m_pContentWrtShell = nullptr;
+ m_oObjectShell.emplace( pFrame->GetObjectShell() );
+ FillBox();
+ }
+}
+
+OUString SwNavigationPI::CreateDropFileName( const TransferableDataHelper& rData )
+{
+ OUString sFileName;
+ SotClipboardFormatId nFormat;
+ if( rData.HasFormat( nFormat = SotClipboardFormatId::FILE_LIST ))
+ {
+ FileList aFileList;
+ rData.GetFileList( nFormat, aFileList );
+ sFileName = aFileList.GetFile( 0 );
+ }
+ else if( rData.HasFormat( nFormat = SotClipboardFormatId::STRING ) ||
+ rData.HasFormat( nFormat = SotClipboardFormatId::SIMPLE_FILE ) ||
+ rData.HasFormat( nFormat = SotClipboardFormatId::FILENAME ))
+ {
+ (void)rData.GetString(nFormat, sFileName);
+ }
+ else if( rData.HasFormat( nFormat = SotClipboardFormatId::SOLK ) ||
+ rData.HasFormat( nFormat = SotClipboardFormatId::NETSCAPE_BOOKMARK )||
+ rData.HasFormat( nFormat = SotClipboardFormatId::FILECONTENT ) ||
+ rData.HasFormat( nFormat = SotClipboardFormatId::FILEGRPDESCRIPTOR ) ||
+ rData.HasFormat( nFormat = SotClipboardFormatId::UNIFORMRESOURCELOCATOR ))
+ {
+ INetBookmark aBkmk { OUString(), OUString() };
+ if (rData.GetINetBookmark(nFormat, aBkmk))
+ sFileName = aBkmk.GetURL();
+ }
+ if( !sFileName.isEmpty() )
+ {
+ sFileName = INetURLObject( sFileName ).GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ }
+ return sFileName;
+}
+
+sal_Int8 SwNavigationPI::AcceptDrop()
+{
+ return ( !m_xContentTree->IsInDrag() &&
+ ( m_xContentTree->IsDropFormatSupported( SotClipboardFormatId::SIMPLE_FILE ) ||
+ m_xContentTree->IsDropFormatSupported( SotClipboardFormatId::STRING ) ||
+ m_xContentTree->IsDropFormatSupported( SotClipboardFormatId::SOLK ) ||
+ m_xContentTree->IsDropFormatSupported( SotClipboardFormatId::NETSCAPE_BOOKMARK )||
+ m_xContentTree->IsDropFormatSupported( SotClipboardFormatId::FILECONTENT ) ||
+ m_xContentTree->IsDropFormatSupported( SotClipboardFormatId::FILEGRPDESCRIPTOR ) ||
+ m_xContentTree->IsDropFormatSupported( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ) ||
+ m_xContentTree->IsDropFormatSupported( SotClipboardFormatId::FILENAME )))
+ ? DND_ACTION_COPY
+ : DND_ACTION_NONE;
+}
+
+sal_Int8 SwNavigationPI::ExecuteDrop( const ExecuteDropEvent& rEvt )
+{
+ TransferableDataHelper aData( rEvt.maDropEvent.Transferable );
+ sal_Int8 nRet = DND_ACTION_NONE;
+ if (m_xContentTree->IsInDrag())
+ return nRet;
+
+ OUString sFileName = SwNavigationPI::CreateDropFileName(aData);
+ if (sFileName.isEmpty())
+ return nRet;
+
+ INetURLObject aTemp(sFileName);
+ GraphicDescriptor aDesc(aTemp);
+ if (aDesc.Detect()) // accept no graphics
+ return nRet;
+
+ if (-1 != sFileName.indexOf('#'))
+ return nRet;
+
+ if (m_sContentFileName.isEmpty() || m_sContentFileName != sFileName)
+ {
+ nRet = rEvt.mnAction;
+ sFileName = comphelper::string::stripEnd(sFileName, 0);
+ m_sContentFileName = sFileName;
+ if(m_oObjectShell)
+ {
+ m_xContentTree->SetHiddenShell( nullptr );
+ (*m_oObjectShell)->DoClose();
+ m_oObjectShell.reset();
+ }
+ SfxStringItem aFileItem(SID_FILE_NAME, sFileName );
+ SfxStringItem aOptionsItem( SID_OPTIONS, "HRC" );
+ SfxLinkItem aLink( SID_DONELINK,
+ LINK( this, SwNavigationPI, DoneLink ) );
+ if (SwView* pView = GetActiveView())
+ pView->GetViewFrame().GetDispatcher()->ExecuteList(
+ SID_OPENDOC, SfxCallMode::ASYNCHRON,
+ { &aFileItem, &aOptionsItem, &aLink });
+ }
+ return nRet;
+}
+
+void SwNavigationPI::SetRegionDropMode(RegionMode nNewMode)
+{
+ m_nRegionMode = nNewMode;
+ m_pConfig->SetRegionMode( m_nRegionMode );
+
+ OUString sImageId;
+ switch (nNewMode)
+ {
+ case RegionMode::NONE:
+ sImageId = RID_BMP_DROP_REGION;
+ break;
+ case RegionMode::LINK:
+ sImageId = RID_BMP_DROP_LINK;
+ break;
+ case RegionMode::EMBEDDED:
+ sImageId = RID_BMP_DROP_COPY;
+ break;
+ }
+ m_xContent6ToolBox->set_item_icon_name("dragmode", sImageId);
+}
+
+void SwNavigationPI::ToggleTree()
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ m_xGlobalTree->HideTree();
+ return;
+ }
+
+ bool bGlobalDoc = IsGlobalDoc();
+ if (!IsGlobalMode() && bGlobalDoc)
+ {
+ if (IsZoomedIn())
+ ZoomOut();
+ m_xGlobalBox->show();
+ m_xGlobalTree->ShowTree();
+ m_xGlobalToolBox->show();
+ m_xContentBox->hide();
+ m_xContentTree->HideTree();
+ m_xContent1ToolBox->hide();
+ m_xContent2ToolBox->hide();
+ m_xContent3ToolBox->hide();
+ m_xContent4ToolBox->hide();
+ m_xContent5ToolBox->hide();
+ m_xContent6ToolBox->hide();
+ m_xDocListBox->hide();
+ SetGlobalMode(true);
+ }
+ else
+ {
+ m_xGlobalBox->hide();
+ m_xGlobalTree->HideTree();
+ m_xGlobalToolBox->hide();
+ if (!IsZoomedIn())
+ {
+ m_xContentBox->show();
+ m_xContentTree->ShowTree();
+ m_xContent1ToolBox->show();
+ m_xContent2ToolBox->show();
+ m_xContent3ToolBox->show();
+ m_xContent4ToolBox->show();
+ m_xContent5ToolBox->show();
+ m_xContent6ToolBox->show();
+ m_xDocListBox->show();
+ }
+ SetGlobalMode(false);
+ }
+}
+
+bool SwNavigationPI::IsGlobalDoc() const
+{
+ bool bRet = false;
+ SwView *pView = GetCreateView();
+ if (pView)
+ {
+ SwWrtShell &rSh = pView->GetWrtShell();
+ bRet = rSh.IsGlobalDoc();
+ }
+ return bRet;
+}
+
+IMPL_LINK_NOARG(SwNavigationPI, ChangePageHdl, Timer *, void)
+{
+ if (!m_xDocListBox) // disposed
+ return;
+ // tdf#134959 if the SpinButton changed value this Timer was launched, now
+ // change to the desired page, but we leave focus where it currently is,
+ // i.e. typically remaining in the spinbutton, or whatever other widget the
+ // user moved to in the meantime
+ EditAction();
+}
+
+void SwNavigationPI::SelectNavigateByContentType(const OUString& rContentTypeName)
+{
+ if (!m_pNavigateByComboBox)
+ return;
+ if (auto nPos = m_pNavigateByComboBox->find_text(rContentTypeName); nPos != -1)
+ {
+ m_pNavigateByComboBox->set_active(nPos);
+ UpdateNavigateBy();
+ }
+}
+
+IMPL_LINK_NOARG(SwNavigationPI, EditActionHdl, weld::Entry&, bool)
+{
+ // tdf#134959 if the user presses enter to activate the Entry
+ // go to the page, and on success we move focus to the document
+ if (EditAction())
+ m_pCreateView->GetEditWin().GrabFocus();
+ return true;
+}
+
+IMPL_LINK_NOARG(SwNavigationPI, PageEditModifyHdl, weld::SpinButton&, void)
+{
+ if (m_aPageChgIdle.IsActive())
+ m_aPageChgIdle.Stop();
+ m_aPageChgIdle.Start();
+}
+
+SwView* SwNavigationPI::GetCreateView() const
+{
+ if (!m_pCreateView)
+ {
+ SwView* pView = SwModule::GetFirstView();
+ while (pView)
+ {
+ if(&pView->GetViewFrame().GetBindings() == &m_rBindings)
+ {
+ const_cast<SwNavigationPI*>(this)->m_pCreateView = pView;
+ const_cast<SwNavigationPI*>(this)->StartListening(*m_pCreateView);
+ break;
+ }
+ pView = SwModule::GetNextView(pView);
+ }
+ }
+ return m_pCreateView;
+}
+
+class SwNavigatorWin : public SfxNavigator
+{
+private:
+ std::unique_ptr<SwNavigationPI> m_xNavi;
+public:
+ SwNavigatorWin(SfxBindings* _pBindings, SfxChildWindow* _pMgr,
+ vcl::Window* pParent, SfxChildWinInfo* pInfo);
+ virtual void StateChanged(StateChangedType nStateChange) override;
+ virtual void dispose() override
+ {
+ m_xNavi.reset();
+ SfxNavigator::dispose();
+ }
+ virtual ~SwNavigatorWin() override
+ {
+ disposeOnce();
+ }
+};
+
+SwNavigatorWin::SwNavigatorWin(SfxBindings* _pBindings, SfxChildWindow* _pMgr,
+ vcl::Window* pParent, SfxChildWinInfo* pInfo)
+ : SfxNavigator(_pBindings, _pMgr, pParent, pInfo)
+ , m_xNavi(std::make_unique<SwNavigationPI>(m_xContainer.get(), _pBindings->GetActiveFrame(), _pBindings, this))
+{
+ _pBindings->Invalidate(SID_NAVIGATOR);
+
+ SwNavigationConfig* pNaviConfig = SW_MOD()->GetNavigationConfig();
+
+ SetMinOutputSizePixel(GetOptimalSize());
+ if (pNaviConfig->IsSmall())
+ m_xNavi->ZoomIn();
+}
+
+void SwNavigatorWin::StateChanged(StateChangedType nStateChange)
+{
+ SfxNavigator::StateChanged(nStateChange);
+ if (nStateChange == StateChangedType::InitShow)
+ m_xNavi->UpdateInitShow();
+}
+
+SFX_IMPL_DOCKINGWINDOW(SwNavigatorWrapper, SID_NAVIGATOR);
+
+SwNavigatorWrapper::SwNavigatorWrapper(vcl::Window *_pParent, sal_uInt16 nId,
+ SfxBindings* pBindings, SfxChildWinInfo* pInfo)
+ : SfxNavigatorWrapper(_pParent, nId)
+{
+ SetWindow(VclPtr<SwNavigatorWin>::Create(pBindings, this, _pParent, pInfo));
+ Initialize();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/utlui/numfmtlb.cxx b/sw/source/uibase/utlui/numfmtlb.cxx
new file mode 100644
index 0000000000..4dffed15d2
--- /dev/null
+++ b/sw/source/uibase/utlui/numfmtlb.cxx
@@ -0,0 +1,470 @@
+/* -*- 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 <i18nlangtag/lang.h>
+#include <svl/numformat.hxx>
+#include <svl/zformat.hxx>
+#include <svl/eitem.hxx>
+#include <svx/svxids.hrc>
+#include <svx/numinf.hxx>
+#include <svx/flagsdef.hxx>
+#include <svl/itemset.hxx>
+#include <osl/diagnose.h>
+#include <docsh.hxx>
+#include <swtypes.hxx>
+#include <swmodule.hxx>
+#include <view.hxx>
+#include <wrtsh.hxx>
+#include <numfmtlb.hxx>
+#include <strings.hrc>
+#include <swabstdlg.hxx>
+#include <memory>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+
+/**
+ * Description:
+ * nFormatType: Display the formats of this Type
+ * nDefaultFormat: Select this format and possibly insert it
+ */
+
+namespace
+{
+
+bool lcl_isSystemFormat(sal_uInt32 nDefaultFormat, SvNumberFormatter* pFormatter, LanguageType eCurLanguage)
+{
+ const sal_uInt32 nSysNumFormat = pFormatter->GetFormatIndex(NF_NUMBER_SYSTEM, eCurLanguage);
+ if (nDefaultFormat == nSysNumFormat)
+ return true;
+ const sal_uInt32 nSysShortDateFormat = pFormatter->GetFormatIndex(NF_DATE_SYSTEM_SHORT, eCurLanguage);
+ if (nDefaultFormat == nSysShortDateFormat)
+ return true;
+ const sal_uInt32 nSysLongDateFormat = pFormatter->GetFormatIndex(NF_DATE_SYSTEM_LONG, eCurLanguage);
+ if (nDefaultFormat == nSysLongDateFormat)
+ return true;
+
+ if ( eCurLanguage != GetAppLanguage() )
+ return false;
+
+ if (nDefaultFormat == pFormatter->GetFormatForLanguageIfBuiltIn(nSysNumFormat, LANGUAGE_SYSTEM))
+ return true;
+ if (nDefaultFormat == pFormatter->GetFormatForLanguageIfBuiltIn(nSysShortDateFormat, LANGUAGE_SYSTEM))
+ return true;
+ if (nDefaultFormat == pFormatter->GetFormatForLanguageIfBuiltIn(nSysLongDateFormat, LANGUAGE_SYSTEM))
+ return true;
+
+ return false;
+}
+
+}
+
+double SwNumFormatBase::GetDefValue(const SvNumFormatType nFormatType)
+{
+ SvxNumValCategory nDefValue = SvxNumValCategory::Standard;
+
+ switch (nFormatType)
+ {
+ case SvNumFormatType::DATE:
+ case SvNumFormatType::DATE|SvNumFormatType::TIME:
+ nDefValue = SvxNumValCategory::Date;
+ break;
+
+ case SvNumFormatType::TIME:
+ nDefValue = SvxNumValCategory::Time;
+ break;
+
+ case SvNumFormatType::TEXT:
+ case SvNumFormatType::UNDEFINED:
+ nDefValue = SvxNumValCategory::Standard;
+ break;
+
+ case SvNumFormatType::CURRENCY:
+ nDefValue = SvxNumValCategory::Currency;
+ break;
+
+ case SvNumFormatType::PERCENT:
+ nDefValue = SvxNumValCategory::Percent;
+ break;
+
+ case SvNumFormatType::LOGICAL:
+ nDefValue = SvxNumValCategory::Boolean;
+ break;
+
+ default:
+ nDefValue = SvxNumValCategory::Standard;
+ break;
+ }
+
+ return fSvxNumValConst[nDefValue];
+}
+
+SwNumFormatBase::SwNumFormatBase()
+ : m_nStdEntry(0)
+ , m_nDefFormat(0)
+ , m_nCurrFormatType(SvNumFormatType::ALL)
+ , m_bOneArea(false)
+ , mbCurrFormatTypeNeedsInit(true)
+ , m_bShowLanguageControl(false)
+ , m_bUseAutomaticLanguage(true)
+{
+}
+
+NumFormatListBox::NumFormatListBox(std::unique_ptr<weld::ComboBox> xControl)
+ : mxControl(std::move(xControl))
+{
+ Init();
+}
+
+SwNumFormatTreeView::SwNumFormatTreeView(std::unique_ptr<weld::TreeView> xControl)
+ : mxControl(std::move(xControl))
+{
+ Init();
+}
+
+void SwNumFormatBase::Init()
+{
+ if (SwView *pView = GetActiveView())
+ m_eCurLanguage = pView->GetWrtShell().GetCurLang();
+ else
+ m_eCurLanguage = SvtSysLocale().GetLanguageTag().getLanguageType();
+
+ SetFormatType(SvNumFormatType::NUMBER);
+ SetDefFormat(m_nDefFormat);
+}
+
+void NumFormatListBox::Init()
+{
+ SwNumFormatBase::Init();
+
+ mxControl->connect_changed(LINK(this, NumFormatListBox, SelectHdl));
+}
+
+void SwNumFormatTreeView::Init()
+{
+ SwNumFormatBase::Init();
+
+ mxControl->connect_changed(LINK(this, SwNumFormatTreeView, SelectHdl));
+}
+
+void SwNumFormatBase::SetFormatType(const SvNumFormatType nFormatType)
+{
+ if (!mbCurrFormatTypeNeedsInit &&
+ (m_nCurrFormatType & nFormatType)) // there are mixed formats, like for example DateTime
+ return;
+
+ SwView *pView = GetActiveView();
+ if(!pView)
+ return;
+ SwWrtShell &rSh = pView->GetWrtShell();
+ SvNumberFormatter* pFormatter = rSh.GetNumberFormatter();
+
+ clear(); // Remove all entries from the Listbox
+
+ NfIndexTableOffset eOffsetStart = NF_NUMBER_START;
+ NfIndexTableOffset eOffsetEnd = NF_NUMBER_START;
+
+ switch( nFormatType )
+ {
+ case SvNumFormatType::NUMBER:
+ eOffsetStart=NF_NUMBER_START;
+ eOffsetEnd=NF_NUMBER_END;
+ break;
+
+ case SvNumFormatType::PERCENT:
+ eOffsetStart=NF_PERCENT_START;
+ eOffsetEnd=NF_PERCENT_END;
+ break;
+
+ case SvNumFormatType::CURRENCY:
+ eOffsetStart=NF_CURRENCY_START;
+ eOffsetEnd=NF_CURRENCY_END;
+ break;
+
+ case SvNumFormatType::DATETIME:
+ eOffsetStart=NF_DATE_START;
+ eOffsetEnd=NF_TIME_END;
+ break;
+
+ case SvNumFormatType::DATE:
+ eOffsetStart=NF_DATE_START;
+ eOffsetEnd=NF_DATE_END;
+ break;
+
+ case SvNumFormatType::TIME:
+ eOffsetStart=NF_TIME_START;
+ eOffsetEnd=NF_TIME_END;
+ break;
+
+ case SvNumFormatType::SCIENTIFIC:
+ eOffsetStart=NF_SCIENTIFIC_START;
+ eOffsetEnd=NF_SCIENTIFIC_END;
+ break;
+
+ case SvNumFormatType::FRACTION:
+ eOffsetStart=NF_FRACTION_START;
+ eOffsetEnd=NF_FRACTION_END;
+ break;
+
+ case SvNumFormatType::LOGICAL:
+ eOffsetStart=NF_BOOLEAN;
+ eOffsetEnd=NF_BOOLEAN;
+ break;
+
+ case SvNumFormatType::TEXT:
+ eOffsetStart=NF_TEXT;
+ eOffsetEnd=NF_TEXT;
+ break;
+
+ case SvNumFormatType::ALL:
+ eOffsetStart=NF_NUMERIC_START;
+ eOffsetEnd = NfIndexTableOffset( NF_INDEX_TABLE_ENTRIES - 1 );
+ break;
+
+ default:
+ OSL_FAIL("what a format?");
+ break;
+ }
+
+ const SvNumberformat* pFormat;
+ sal_Int32 i = 0;
+ const Color* pCol;
+ double fVal = SwNumFormatBase::GetDefValue(nFormatType);
+ OUString sValue;
+
+ const sal_uInt32 nSysNumFormat = pFormatter->GetFormatIndex(
+ NF_NUMBER_SYSTEM, m_eCurLanguage );
+ const sal_uInt32 nSysShortDateFormat = pFormatter->GetFormatIndex(
+ NF_DATE_SYSTEM_SHORT, m_eCurLanguage );
+ const sal_uInt32 nSysLongDateFormat = pFormatter->GetFormatIndex(
+ NF_DATE_SYSTEM_LONG, m_eCurLanguage );
+
+ for( tools::Long nIndex = eOffsetStart; nIndex <= eOffsetEnd; ++nIndex )
+ {
+ const sal_uInt32 nFormat = pFormatter->GetFormatIndex(
+ static_cast<NfIndexTableOffset>(nIndex), m_eCurLanguage );
+ pFormat = pFormatter->GetEntry( nFormat );
+
+ if( nFormat == pFormatter->GetFormatIndex( NF_NUMBER_STANDARD,
+ m_eCurLanguage )
+ || const_cast<SvNumberformat*>(pFormat)->GetOutputString( fVal, sValue, &pCol )
+ || nFormatType == SvNumFormatType::UNDEFINED )
+ {
+ sValue = pFormat->GetFormatstring();
+ }
+ else if( nFormatType == SvNumFormatType::TEXT )
+ {
+ pFormatter->GetOutputString( "\"ABC\"", nFormat, sValue, &pCol);
+ }
+
+ if (nFormat != nSysNumFormat &&
+ nFormat != nSysShortDateFormat &&
+ nFormat != nSysLongDateFormat)
+ {
+ append(OUString::number(nFormat), sValue);
+
+ if( nFormat == pFormatter->GetStandardFormat(
+ nFormatType, m_eCurLanguage ) )
+ m_nStdEntry = i;
+ ++i;
+ }
+ }
+
+ append_text(SwResId(STR_DEFINE_NUMBERFORMAT));
+
+ set_active(m_nStdEntry);
+
+ m_nCurrFormatType = nFormatType;
+ mbCurrFormatTypeNeedsInit = false;
+
+}
+
+void SwNumFormatBase::SetDefFormat(const sal_uInt32 nDefaultFormat)
+{
+ if (nDefaultFormat == NUMBERFORMAT_ENTRY_NOT_FOUND)
+ {
+ m_nDefFormat = nDefaultFormat;
+ return;
+ }
+
+ SwView *pView = GetActiveView();
+ if(!pView)
+ return;
+ SwWrtShell &rSh = pView->GetWrtShell();
+ SvNumberFormatter* pFormatter = rSh.GetNumberFormatter();
+
+ SvNumFormatType nType = pFormatter->GetType(nDefaultFormat);
+
+ SetFormatType(nType);
+
+ sal_uInt32 nFormat = pFormatter->GetFormatForLanguageIfBuiltIn(nDefaultFormat, m_eCurLanguage);
+
+ for (sal_Int32 i = 0, nCount = get_count(); i < nCount; ++i)
+ {
+ if (nFormat == get_id(i).toUInt32())
+ {
+ set_active(i);
+ m_nStdEntry = i;
+ m_nDefFormat = GetFormat();
+ return;
+ }
+ }
+
+ // No entry found:
+ OUString sValue;
+ const Color* pCol = nullptr;
+
+ if (nType == SvNumFormatType::TEXT)
+ {
+ pFormatter->GetOutputString("\"ABC\"", nDefaultFormat, sValue, &pCol);
+ }
+ else
+ {
+ pFormatter->GetOutputString(SwNumFormatBase::GetDefValue(nType), nDefaultFormat, sValue, &pCol);
+ }
+
+ sal_Int32 nPos = 0;
+ while (get_id(nPos).toUInt32() == NUMBERFORMAT_ENTRY_NOT_FOUND)
+ nPos++;
+
+ if ( lcl_isSystemFormat(nDefaultFormat, pFormatter, m_eCurLanguage) )
+ {
+ sValue += SwResId(RID_STR_SYSTEM);
+ }
+
+ insert_text(nPos, sValue); // Insert as first numeric entry
+ set_id(nPos, OUString::number(nDefaultFormat));
+ set_active(nPos);
+ m_nDefFormat = GetFormat();
+}
+
+sal_uInt32 NumFormatListBox::GetFormat() const
+{
+ return mxControl->get_active_id().toUInt32();
+}
+
+sal_uInt32 SwNumFormatTreeView::GetFormat() const
+{
+ return mxControl->get_selected_id().toUInt32();
+}
+
+void SwNumFormatBase::CallSelectHdl()
+{
+ const sal_Int32 nPos = get_active();
+ OUString sDefine(SwResId( STR_DEFINE_NUMBERFORMAT ));
+ SwView *pView = GetActiveView();
+
+ if (!pView || nPos != get_count() - 1 || get_text(nPos) != sDefine)
+ return;
+
+ SwWrtShell &rSh = pView->GetWrtShell();
+ SvNumberFormatter* pFormatter = rSh.GetNumberFormatter();
+
+ SfxItemSetFixed<
+ SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_INFO,
+ SID_ATTR_NUMBERFORMAT_ONE_AREA, SID_ATTR_NUMBERFORMAT_ONE_AREA,
+ SID_ATTR_NUMBERFORMAT_NOLANGUAGE,
+ SID_ATTR_NUMBERFORMAT_NOLANGUAGE,
+ SID_ATTR_NUMBERFORMAT_ADD_AUTO,
+ SID_ATTR_NUMBERFORMAT_ADD_AUTO> aCoreSet( rSh.GetAttrPool() );
+
+ double fValue = SwNumFormatBase::GetDefValue(m_nCurrFormatType);
+
+ sal_uInt32 nFormat = pFormatter->GetStandardFormat( m_nCurrFormatType, m_eCurLanguage);
+ aCoreSet.Put( SfxUInt32Item( SID_ATTR_NUMBERFORMAT_VALUE, nFormat ));
+
+ aCoreSet.Put( SvxNumberInfoItem( pFormatter, fValue,
+ SID_ATTR_NUMBERFORMAT_INFO ) );
+
+ if( (SvNumFormatType::DATE | SvNumFormatType::TIME) & m_nCurrFormatType )
+ aCoreSet.Put(SfxBoolItem(SID_ATTR_NUMBERFORMAT_ONE_AREA, m_bOneArea));
+
+ aCoreSet.Put(SfxBoolItem(SID_ATTR_NUMBERFORMAT_NOLANGUAGE, !m_bShowLanguageControl));
+ aCoreSet.Put(SfxBoolItem(SID_ATTR_NUMBERFORMAT_ADD_AUTO, m_bUseAutomaticLanguage));
+
+ // force deselect to break mouse lock on selected entry
+ set_active(-1);
+
+ SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractDialog> pDlg(pFact->CreateNumFormatDialog(&get_widget(), aCoreSet));
+
+ if (RET_OK == pDlg->Execute())
+ {
+ const SvxNumberInfoItem* pFormatInfoItem = pView->GetDocShell()->
+ GetItem( SID_ATTR_NUMBERFORMAT_INFO );
+
+ if( pFormatInfoItem )
+ {
+ for ( sal_uInt32 key : pFormatInfoItem->GetDelFormats() )
+ pFormatter->DeleteEntry( key );
+ }
+
+ const SfxItemSet* pOutSet = pDlg->GetOutputItemSet();
+ if( const SfxUInt32Item* pFormatValueItem = pOutSet->GetItemIfSet(
+ SID_ATTR_NUMBERFORMAT_VALUE, false ))
+ {
+ sal_uInt32 nNumberFormat = pFormatValueItem->GetValue();
+ // oj #105473# change order of calls
+ const SvNumberformat* pFormat = pFormatter->GetEntry(nNumberFormat);
+ if( pFormat )
+ m_eCurLanguage = pFormat->GetLanguage();
+ // SetDefFormat uses eCurLanguage to look for if this format already in the list
+ SetDefFormat(nNumberFormat);
+ }
+ const SfxBoolItem* pAddAutoItem;
+ if( m_bShowLanguageControl && (pAddAutoItem = pOutSet->GetItemIfSet(
+ SID_ATTR_NUMBERFORMAT_ADD_AUTO, false)))
+ {
+ m_bUseAutomaticLanguage = pAddAutoItem->GetValue();
+ }
+ }
+ else
+ SetDefFormat(nFormat);
+
+}
+
+IMPL_LINK_NOARG(NumFormatListBox, SelectHdl, weld::ComboBox&, void)
+{
+ CallSelectHdl();
+}
+
+IMPL_LINK_NOARG(SwNumFormatTreeView, SelectHdl, weld::TreeView&, void)
+{
+ CallSelectHdl();
+}
+
+void SwNumFormatBase::clear()
+{
+ mbCurrFormatTypeNeedsInit = true;
+ m_nCurrFormatType = SvNumFormatType::ALL;
+}
+
+void NumFormatListBox::clear()
+{
+ mxControl->clear();
+ SwNumFormatBase::clear();
+}
+
+void SwNumFormatTreeView::clear()
+{
+ mxControl->clear();
+ SwNumFormatBase::clear();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/utlui/prcntfld.cxx b/sw/source/uibase/utlui/prcntfld.cxx
new file mode 100644
index 0000000000..4c8eede661
--- /dev/null
+++ b/sw/source/uibase/utlui/prcntfld.cxx
@@ -0,0 +1,231 @@
+/* -*- 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 <prcntfld.hxx>
+#include <vcl/fieldvalues.hxx>
+
+SwPercentField::SwPercentField(std::unique_ptr<weld::MetricSpinButton> pControl)
+ : m_pField(std::move(pControl))
+ , m_nOldMax(0)
+ , m_nOldMin(0)
+ , m_nLastPercent(-1)
+ , m_nLastValue(-1)
+ , m_nOldDigits(m_pField->get_digits())
+ , m_eOldUnit(FieldUnit::NONE)
+ , m_bLockAutoCalculation(false)
+{
+ sal_Int64 nMin, nMax;
+ m_pField->get_range(nMin, nMax, FieldUnit::TWIP);
+ m_nRefValue = DenormalizePercent(nMax);
+ m_pField->get_increments(m_nOldSpinSize, m_nOldPageSize, FieldUnit::NONE);
+}
+
+void SwPercentField::SetRefValue(sal_Int64 nValue)
+{
+ sal_Int64 nRealValue = GetRealValue(m_eOldUnit);
+
+ m_nRefValue = nValue;
+
+ if (!m_bLockAutoCalculation && (m_pField->get_unit() == FieldUnit::PERCENT))
+ set_value(nRealValue, m_eOldUnit);
+}
+
+void SwPercentField::ShowPercent(bool bPercent)
+{
+ if ((bPercent && m_pField->get_unit() == FieldUnit::PERCENT)
+ || (!bPercent && m_pField->get_unit() != FieldUnit::PERCENT))
+ return;
+
+ sal_Int64 nOldValue;
+
+ if (bPercent)
+ {
+ nOldValue = get_value();
+
+ m_eOldUnit = m_pField->get_unit();
+ m_nOldDigits = m_pField->get_digits();
+ m_pField->get_range(m_nOldMin, m_nOldMax, FieldUnit::NONE);
+ m_pField->get_increments(m_nOldSpinSize, m_nOldPageSize, FieldUnit::NONE);
+ m_pField->set_unit(FieldUnit::PERCENT);
+ m_pField->set_digits(0);
+
+ sal_Int64 nCurrentWidth
+ = vcl::ConvertValue(m_nOldMin, 0, m_nOldDigits, m_eOldUnit, FieldUnit::TWIP);
+ // round to 0.5 percent
+ int nPercent = m_nRefValue ? (((nCurrentWidth * 10) / m_nRefValue + 5) / 10) : 0;
+
+ m_pField->set_range(std::max(1, nPercent), 100, FieldUnit::NONE);
+ m_pField->set_increments(5, 10, FieldUnit::NONE);
+ if (nOldValue != m_nLastValue)
+ {
+ nCurrentWidth
+ = vcl::ConvertValue(nOldValue, 0, m_nOldDigits, m_eOldUnit, FieldUnit::TWIP);
+ nPercent = m_nRefValue ? (((nCurrentWidth * 10) / m_nRefValue + 5) / 10) : 0;
+ m_pField->set_value(nPercent, FieldUnit::NONE);
+ m_nLastPercent = nPercent;
+ m_nLastValue = nOldValue;
+ }
+ else
+ m_pField->set_value(m_nLastPercent, FieldUnit::NONE);
+ }
+ else
+ {
+ sal_Int64 nOldPercent = get_value(FieldUnit::PERCENT);
+
+ nOldValue = Convert(get_value(), m_pField->get_unit(), m_eOldUnit);
+
+ m_pField->set_unit(m_eOldUnit);
+ m_pField->set_digits(m_nOldDigits);
+ m_pField->set_range(m_nOldMin, m_nOldMax, FieldUnit::NONE);
+ m_pField->set_increments(m_nOldSpinSize, m_nOldPageSize, FieldUnit::NONE);
+
+ if (nOldPercent != m_nLastPercent)
+ {
+ set_value(nOldValue, m_eOldUnit);
+ m_nLastPercent = nOldPercent;
+ m_nLastValue = nOldValue;
+ }
+ else
+ set_value(m_nLastValue, m_eOldUnit);
+ }
+}
+
+void SwPercentField::set_value(sal_Int64 nNewValue, FieldUnit eInUnit)
+{
+ if (m_pField->get_unit() != FieldUnit::PERCENT || eInUnit == FieldUnit::PERCENT)
+ m_pField->set_value(Convert(nNewValue, eInUnit, m_pField->get_unit()), FieldUnit::NONE);
+ else
+ {
+ // Overwrite output value, do not restore later
+ sal_Int64 nPercent, nCurrentWidth;
+ if (eInUnit == FieldUnit::TWIP)
+ {
+ nCurrentWidth
+ = vcl::ConvertValue(nNewValue, 0, m_nOldDigits, FieldUnit::TWIP, FieldUnit::TWIP);
+ }
+ else
+ {
+ sal_Int64 nValue = Convert(nNewValue, eInUnit, m_eOldUnit);
+ nCurrentWidth = vcl::ConvertValue(nValue, 0, m_nOldDigits, m_eOldUnit, FieldUnit::TWIP);
+ }
+ nPercent = m_nRefValue ? (((nCurrentWidth * 10) / m_nRefValue + 5) / 10) : 0;
+ m_pField->set_value(nPercent, FieldUnit::NONE);
+ }
+}
+
+sal_Int64 SwPercentField::get_value(FieldUnit eOutUnit)
+{
+ return Convert(m_pField->get_value(FieldUnit::NONE), m_pField->get_unit(), eOutUnit);
+}
+
+void SwPercentField::set_min(sal_Int64 nNewMin, FieldUnit eInUnit)
+{
+ if (m_pField->get_unit() != FieldUnit::PERCENT)
+ m_pField->set_min(nNewMin, eInUnit);
+ else
+ {
+ if (eInUnit == FieldUnit::NONE)
+ eInUnit = m_eOldUnit;
+ m_nOldMin = Convert(nNewMin, eInUnit, m_eOldUnit);
+
+ int nPercent = Convert(nNewMin, eInUnit, FieldUnit::PERCENT);
+ m_pField->set_min(std::max(1, nPercent), FieldUnit::NONE);
+ }
+}
+
+void SwPercentField::set_max(sal_Int64 nNewMax, FieldUnit eInUnit)
+{
+ if (m_pField->get_unit() != FieldUnit::PERCENT)
+ m_pField->set_max(nNewMax, eInUnit);
+}
+
+sal_Int64 SwPercentField::NormalizePercent(sal_Int64 nValue)
+{
+ if (m_pField->get_unit() != FieldUnit::PERCENT)
+ nValue = m_pField->normalize(nValue);
+ else
+ nValue = nValue * ImpPower10(m_nOldDigits);
+ return nValue;
+}
+
+sal_Int64 SwPercentField::DenormalizePercent(sal_Int64 nValue)
+{
+ if (m_pField->get_unit() != FieldUnit::PERCENT)
+ nValue = m_pField->denormalize(nValue);
+ else
+ {
+ int nFactor = ImpPower10(m_nOldDigits);
+ nValue = ((nValue + (nFactor / 2)) / nFactor);
+ }
+ return nValue;
+}
+
+int SwPercentField::ImpPower10(sal_uInt16 n)
+{
+ int nValue = 1;
+
+ for (sal_uInt16 i = 0; i < n; ++i)
+ nValue *= 10;
+
+ return nValue;
+}
+
+sal_Int64 SwPercentField::GetRealValue(FieldUnit eOutUnit)
+{
+ if (m_pField->get_unit() != FieldUnit::PERCENT)
+ return get_value(eOutUnit);
+ else
+ return Convert(get_value(), m_pField->get_unit(), eOutUnit);
+}
+
+sal_Int64 SwPercentField::Convert(sal_Int64 nValue, FieldUnit eInUnit, FieldUnit eOutUnit)
+{
+ if (eInUnit == eOutUnit || (eInUnit == FieldUnit::NONE && eOutUnit == m_pField->get_unit())
+ || (eOutUnit == FieldUnit::NONE && eInUnit == m_pField->get_unit()))
+ return nValue;
+
+ if (eInUnit == FieldUnit::PERCENT)
+ {
+ // Convert to metric
+ sal_Int64 nTwipValue = (m_nRefValue * nValue + 50) / 100;
+
+ if (eOutUnit == FieldUnit::TWIP) // Only convert if necessary
+ return NormalizePercent(nTwipValue);
+ else
+ return vcl::ConvertValue(NormalizePercent(nTwipValue), 0, m_nOldDigits, FieldUnit::TWIP,
+ eOutUnit);
+ }
+
+ if (eOutUnit == FieldUnit::PERCENT)
+ {
+ // Convert to percent
+ sal_Int64 nCurrentWidth;
+ nValue = DenormalizePercent(nValue);
+
+ if (eInUnit == FieldUnit::TWIP) // Only convert if necessary
+ nCurrentWidth = nValue;
+ else
+ nCurrentWidth = vcl::ConvertValue(nValue, 0, m_nOldDigits, eInUnit, FieldUnit::TWIP);
+ // Round to 0.5 percent
+ return m_nRefValue ? (((nCurrentWidth * 1000) / m_nRefValue + 5) / 10) : 0;
+ }
+
+ return vcl::ConvertValue(nValue, 0, m_nOldDigits, eInUnit, eOutUnit);
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/utlui/shdwcrsr.cxx b/sw/source/uibase/utlui/shdwcrsr.cxx
new file mode 100644
index 0000000000..f897878408
--- /dev/null
+++ b/sw/source/uibase/utlui/shdwcrsr.cxx
@@ -0,0 +1,56 @@
+/* -*- 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 <com/sun/star/text/HoriOrientation.hpp>
+#include <shdwcrsr.hxx>
+#include <vcl/ptrstyle.hxx>
+
+using namespace ::com::sun::star;
+
+SwShadowCursor::~SwShadowCursor()
+{
+ if( USHRT_MAX != m_nOldMode )
+ DrawCursor( m_nOldMode);
+}
+
+void SwShadowCursor::SetPos( const Point& rPt, tools::Long nHeight, sal_uInt16 nMode )
+{
+ Point aPt( m_pWin->LogicToPixel( rPt ));
+ nHeight = m_pWin->LogicToPixel( Size( 0, nHeight )).Height();
+ if( m_aOldPt != aPt || m_nOldHeight != nHeight || m_nOldMode != nMode )
+ {
+ if( USHRT_MAX != m_nOldMode )
+ DrawCursor( m_nOldMode);
+
+ DrawCursor( nMode);
+ m_nOldMode = nMode;
+ m_nOldHeight = nHeight;
+ m_aOldPt = aPt;
+ }
+}
+
+void SwShadowCursor::DrawCursor( sal_uInt16 nMode )
+{
+ if( text::HoriOrientation::LEFT == nMode ) // Arrow to the right
+ m_pWin->SetPointer(PointerStyle::AutoScrollE);
+ else // Arrow to the left
+ m_pWin->SetPointer(PointerStyle::AutoScrollW);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/utlui/tmplctrl.cxx b/sw/source/uibase/utlui/tmplctrl.cxx
new file mode 100644
index 0000000000..2b68905cf4
--- /dev/null
+++ b/sw/source/uibase/utlui/tmplctrl.cxx
@@ -0,0 +1,121 @@
+/* -*- 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 <svl/style.hxx>
+#include <svl/stritem.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/status.hxx>
+#include <vcl/weldutils.hxx>
+
+#include <swtypes.hxx>
+#include <strings.hrc>
+
+#include <wrtsh.hxx>
+#include <view.hxx>
+#include <swmodule.hxx>
+#include <cmdid.h>
+#include <docsh.hxx>
+#include <tmplctrl.hxx>
+
+SFX_IMPL_STATUSBAR_CONTROL( SwTemplateControl, SfxStringItem );
+
+SwTemplateControl::SwTemplateControl( sal_uInt16 _nSlotId,
+ sal_uInt16 _nId,
+ StatusBar& rStb ) :
+ SfxStatusBarControl( _nSlotId, _nId, rStb )
+{
+}
+
+SwTemplateControl::~SwTemplateControl()
+{
+}
+
+void SwTemplateControl::StateChangedAtStatusBarControl(
+ sal_uInt16 /*nSID*/, SfxItemState eState, const SfxPoolItem* pState )
+{
+ const SfxStringItem* pItem = nullptr;
+ if (SfxItemState::DEFAULT == eState && (pItem = dynamic_cast<const SfxStringItem*>(pState)))
+ {
+ m_sTemplate = pItem->GetValue();
+ GetStatusBar().SetItemText(GetId(), m_sTemplate);
+ GetStatusBar().SetQuickHelpText(GetId(), SwResId(STR_TMPLCTRL_HINT));
+ }
+ else
+ {
+ GetStatusBar().SetItemText(GetId(), OUString());
+ GetStatusBar().SetQuickHelpText(GetId(), u""_ustr);
+ }
+}
+
+void SwTemplateControl::Paint( const UserDrawEvent& )
+{
+}
+
+void SwTemplateControl::Command( const CommandEvent& rCEvt )
+{
+ if ( rCEvt.GetCommand() != CommandEventId::ContextMenu ||
+ GetStatusBar().GetItemText( GetId() ).isEmpty())
+ return;
+
+ {
+ SwView* pView = ::GetActiveView();
+ SwWrtShell *const pWrtShell(pView ? pView->GetWrtShellPtr() : nullptr);
+ if (nullptr != pWrtShell &&
+ !pWrtShell->SwCursorShell::HasSelection()&&
+ !pWrtShell->IsSelFrameMode() &&
+ !pWrtShell->IsObjSelected())
+ {
+ SfxStyleSheetBasePool* pPool = pView->GetDocShell()->
+ GetStyleSheetPool();
+ auto xIter = pPool->CreateIterator(SfxStyleFamily::Page);
+ if (xIter->Count() > 1)
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(nullptr, "modules/swriter/ui/pagestylemenu.ui"));
+ std::unique_ptr<weld::Menu> xPopup(xBuilder->weld_menu("menu"));
+
+ sal_uInt32 nCount = 0;
+ SfxStyleSheetBase* pStyle = xIter->First();
+ while( pStyle )
+ {
+ xPopup->append(OUString::number(++nCount), pStyle->GetName());
+ pStyle = xIter->Next();
+ }
+
+ ::tools::Rectangle aRect(rCEvt.GetMousePosPixel(), Size(1, 1));
+ weld::Window* pParent = weld::GetPopupParent(GetStatusBar(), aRect);
+ OUString sResult = xPopup->popup_at_rect(pParent, aRect);
+ if (!sResult.isEmpty())
+ {
+ sal_uInt32 nCurrId = sResult.toUInt32();
+ // looks a bit awkward, but another way is not possible
+ pStyle = xIter->operator[]( nCurrId - 1 );
+ SfxStringItem aStyle( FN_SET_PAGE_STYLE, pStyle->GetName() );
+ pWrtShell->GetView().GetViewFrame().GetDispatcher()->ExecuteList(
+ FN_SET_PAGE_STYLE,
+ SfxCallMode::SLOT|SfxCallMode::RECORD,
+ { &aStyle });
+ }
+ }
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/utlui/uiitems.cxx b/sw/source/uibase/utlui/uiitems.cxx
new file mode 100644
index 0000000000..b88751abdd
--- /dev/null
+++ b/sw/source/uibase/utlui/uiitems.cxx
@@ -0,0 +1,277 @@
+/* -*- 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/servicehelper.hxx>
+#include <editeng/itemtype.hxx>
+#include <tools/UnitConversion.hxx>
+#include <unosett.hxx>
+
+#include <swtypes.hxx>
+#include <cmdid.h>
+#include <uiitems.hxx>
+
+#include <strings.hrc>
+#include <unomid.h>
+#include <numrule.hxx>
+
+#include <editeng/eerdll.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+SwPageFootnoteInfoItem::SwPageFootnoteInfoItem( SwPageFootnoteInfo const & rInfo) :
+ SfxPoolItem( FN_PARAM_FTN_INFO ),
+ m_aFootnoteInfo(rInfo)
+{
+}
+
+SwPageFootnoteInfoItem::~SwPageFootnoteInfoItem()
+{
+}
+
+SwPageFootnoteInfoItem* SwPageFootnoteInfoItem::Clone( SfxItemPool * /*pPool*/ ) const
+{
+ return new SwPageFootnoteInfoItem( *this );
+}
+
+bool SwPageFootnoteInfoItem::operator==( const SfxPoolItem& rAttr ) const
+{
+ return SfxPoolItem::operator==(rAttr)
+ && m_aFootnoteInfo == static_cast<const SwPageFootnoteInfoItem&>(rAttr).m_aFootnoteInfo;
+}
+
+bool SwPageFootnoteInfoItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit eCoreUnit,
+ MapUnit ePresUnit,
+ OUString& rText,
+ const IntlWrapper& rIntl
+) const
+{
+ const SwTwips nHght = GetPageFootnoteInfo().GetHeight();
+ if ( nHght )
+ {
+ rText = SwResId( STR_MAX_FTN_HEIGHT ) + " " +
+ ::GetMetricText( nHght, eCoreUnit, ePresUnit, &rIntl ) + " " +
+ EditResId( ::GetMetricId( ePresUnit ) );
+ }
+ return true;
+}
+
+bool SwPageFootnoteInfoItem::QueryValue( Any& rVal, sal_uInt8 nMemberId ) const
+{
+ bool bRet = true;
+ switch(nMemberId & ~CONVERT_TWIPS)
+ {
+ case MID_FTN_HEIGHT : rVal <<= static_cast<sal_Int32>(convertTwipToMm100(m_aFootnoteInfo.GetHeight()));break;
+ case MID_LINE_WEIGHT : rVal <<= static_cast<sal_Int16>(convertTwipToMm100(m_aFootnoteInfo.GetLineWidth()));break;
+ case MID_LINE_COLOR : rVal <<= m_aFootnoteInfo.GetLineColor();break;
+ case MID_LINE_RELWIDTH :
+ {
+ Fraction aTmp( 100, 1 );
+ aTmp *= m_aFootnoteInfo.GetWidth();
+ rVal <<= static_cast<sal_Int8>(static_cast<tools::Long>(aTmp));
+ }
+ break;
+ case MID_LINE_ADJUST : rVal <<= static_cast<sal_Int16>(m_aFootnoteInfo.GetAdj());break;//text::HorizontalAdjust
+ case MID_LINE_TEXT_DIST : rVal <<= static_cast<sal_Int32>(convertTwipToMm100(m_aFootnoteInfo.GetTopDist()));break;
+ case MID_LINE_FOOTNOTE_DIST: rVal <<= static_cast<sal_Int32>(convertTwipToMm100(m_aFootnoteInfo.GetBottomDist()));break;
+ case MID_FTN_LINE_STYLE :
+ {
+ switch ( m_aFootnoteInfo.GetLineStyle( ) )
+ {
+ default:
+ case SvxBorderLineStyle::NONE : rVal <<= sal_Int8(0); break;
+ case SvxBorderLineStyle::SOLID: rVal <<= sal_Int8(1); break;
+ case SvxBorderLineStyle::DOTTED: rVal <<= sal_Int8(2); break;
+ case SvxBorderLineStyle::DASHED: rVal <<= sal_Int8(3); break;
+ }
+ break;
+ }
+ default:
+ bRet = false;
+ }
+ return bRet;
+}
+
+bool SwPageFootnoteInfoItem::PutValue(const Any& rVal, sal_uInt8 nMemberId)
+{
+ sal_Int32 nSet32 = 0;
+ Color aColor;
+ bool bRet = true;
+ switch(nMemberId & ~CONVERT_TWIPS)
+ {
+ case MID_LINE_COLOR :
+ rVal >>= aColor;
+ m_aFootnoteInfo.SetLineColor(aColor);
+ break;
+ case MID_FTN_HEIGHT:
+ case MID_LINE_TEXT_DIST :
+ case MID_LINE_FOOTNOTE_DIST:
+ rVal >>= nSet32;
+ if(nSet32 < 0)
+ bRet = false;
+ else
+ {
+ nSet32 = o3tl::toTwips(nSet32, o3tl::Length::mm100);
+ switch(nMemberId & ~CONVERT_TWIPS)
+ {
+ case MID_FTN_HEIGHT: m_aFootnoteInfo.SetHeight(nSet32); break;
+ case MID_LINE_TEXT_DIST: m_aFootnoteInfo.SetTopDist(nSet32);break;
+ case MID_LINE_FOOTNOTE_DIST: m_aFootnoteInfo.SetBottomDist(nSet32);break;
+ }
+ }
+ break;
+ case MID_LINE_WEIGHT :
+ {
+ sal_Int16 nSet = 0;
+ rVal >>= nSet;
+ if(nSet >= 0)
+ m_aFootnoteInfo.SetLineWidth(o3tl::toTwips(nSet, o3tl::Length::mm100));
+ else
+ bRet = false;
+ }
+ break;
+ case MID_LINE_RELWIDTH :
+ {
+ sal_Int8 nSet = 0;
+ rVal >>= nSet;
+ if(nSet < 0)
+ bRet = false;
+ else
+ m_aFootnoteInfo.SetWidth(Fraction(nSet, 100));
+ }
+ break;
+ case MID_LINE_ADJUST :
+ {
+ sal_Int16 nSet = 0;
+ rVal >>= nSet;
+ if(nSet >= 0 && nSet < 3) //text::HorizontalAdjust
+ m_aFootnoteInfo.SetAdj(static_cast<css::text::HorizontalAdjust>(nSet));
+ else
+ bRet = false;
+ }
+ break;
+ case MID_FTN_LINE_STYLE:
+ {
+ SvxBorderLineStyle eStyle = SvxBorderLineStyle::NONE;
+ sal_Int8 nSet = 0;
+ rVal >>= nSet;
+ switch ( nSet )
+ {
+ case 1: eStyle = SvxBorderLineStyle::SOLID; break;
+ case 2: eStyle = SvxBorderLineStyle::DOTTED; break;
+ case 3: eStyle = SvxBorderLineStyle::DASHED; break;
+ default: break;
+ }
+ m_aFootnoteInfo.SetLineStyle( eStyle );
+ }
+ break;
+ default:
+ bRet = false;
+ }
+ return bRet;
+}
+
+SwPtrItem::SwPtrItem( const sal_uInt16 nId, void* pPtr ) :
+ SfxPoolItem( nId ),
+ m_pMisc(pPtr)
+{
+}
+
+// Cloning
+
+SwPtrItem* SwPtrItem::Clone( SfxItemPool * /*pPool*/ ) const
+{
+ return new SwPtrItem( *this );
+}
+
+bool SwPtrItem::operator==( const SfxPoolItem& rAttr ) const
+{
+ return SfxPoolItem::operator==(rAttr)
+ && m_pMisc == static_cast<const SwPtrItem&>(rAttr).m_pMisc;
+}
+
+// SwUINumRuleItem for the NumTabPages of the FormatNumRule/Styleists
+
+SwUINumRuleItem::SwUINumRuleItem( const SwNumRule& rRul )
+ : SfxPoolItem( FN_PARAM_ACT_NUMBER ), m_pRule( new SwNumRule( rRul ) )
+{
+}
+
+SwUINumRuleItem::SwUINumRuleItem( const SwUINumRuleItem& rItem )
+ : SfxPoolItem( rItem ),
+ m_pRule( new SwNumRule( *rItem.m_pRule ))
+{
+}
+
+SwUINumRuleItem::~SwUINumRuleItem()
+{
+}
+
+SwUINumRuleItem* SwUINumRuleItem::Clone( SfxItemPool * /*pPool*/ ) const
+{
+ return new SwUINumRuleItem( *this );
+}
+
+bool SwUINumRuleItem::operator==( const SfxPoolItem& rAttr ) const
+{
+ return SfxPoolItem::operator==(rAttr)
+ && *m_pRule == *static_cast<const SwUINumRuleItem&>(rAttr).m_pRule;
+}
+
+bool SwUINumRuleItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/ ) const
+{
+ uno::Reference< container::XIndexReplace >xRules = new SwXNumberingRules(*m_pRule);
+ rVal <<= xRules;
+ return true;
+}
+bool SwUINumRuleItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/ )
+{
+ uno::Reference< container::XIndexReplace> xRulesRef;
+ if(rVal >>= xRulesRef)
+ {
+ auto pSwXRules = dynamic_cast<SwXNumberingRules*>(xRulesRef.get());
+ if(pSwXRules)
+ {
+ *m_pRule = *pSwXRules->GetNumRule();
+ }
+ }
+ return true;
+}
+
+SwPaMItem::SwPaMItem( const sal_uInt16 nId, SwPaM* pPaM ) :
+ SfxPoolItem( nId ),
+ m_pPaM(pPaM)
+{
+}
+
+SwPaMItem* SwPaMItem::Clone( SfxItemPool * /*pPool*/ ) const
+{
+ return new SwPaMItem( *this );
+}
+
+bool SwPaMItem::operator==( const SfxPoolItem& rAttr ) const
+{
+ return SfxPoolItem::operator==(rAttr)
+ && m_pPaM == static_cast<const SwPaMItem&>(rAttr).m_pPaM;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/utlui/uitool.cxx b/sw/source/uibase/utlui/uitool.cxx
new file mode 100644
index 0000000000..fd50bf6678
--- /dev/null
+++ b/sw/source/uibase/utlui/uitool.cxx
@@ -0,0 +1,921 @@
+/* -*- 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 <hintids.hxx>
+
+#include <osl/diagnose.h>
+#include <tools/datetime.hxx>
+#include <vcl/weld.hxx>
+#include <unotools/collatorwrapper.hxx>
+#include <svl/stritem.hxx>
+#include <svl/grabbagitem.hxx>
+#include <unotools/syslocale.hxx>
+#include <IDocumentStylePoolAccess.hxx>
+#include <editeng/pmdlitem.hxx>
+#include <editeng/tstpitem.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/sizeitem.hxx>
+#include <editeng/brushitem.hxx>
+#include <svx/pageitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <svl/style.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <com/sun/star/awt/XPopupMenu.hpp>
+#include <com/sun/star/frame/XDispatch.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <com/sun/star/util/XURLTransformer.hpp>
+#include <comphelper/processfactory.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/docfilt.hxx>
+#include <fmtornt.hxx>
+#include <tabcol.hxx>
+#include <fmtfsize.hxx>
+#include <fmthdft.hxx>
+#include <fmtpdsc.hxx>
+#include <uiitems.hxx>
+#include <docsh.hxx>
+#include <wrtsh.hxx>
+#include <swmodule.hxx>
+#include <view.hxx>
+#include <uitool.hxx>
+#include <frmatr.hxx>
+#include <paratr.hxx>
+#include <fmtcol.hxx>
+#include <usrpref.hxx>
+
+#include <cmdid.h>
+#include <doc.hxx>
+#include <charfmt.hxx>
+#include <SwStyleNameMapper.hxx>
+#include <strings.hrc>
+#include <docmodel/color/ComplexColor.hxx>
+
+// 50 cm 28350
+#define MAXHEIGHT 28350
+#define MAXWIDTH 28350
+
+using namespace ::com::sun::star;
+
+// General list of string pointer
+
+// Set boxinfo attribute
+
+void PrepareBoxInfo(SfxItemSet& rSet, const SwWrtShell& rSh)
+{
+ std::shared_ptr<SvxBoxInfoItem> aBoxInfo(std::make_shared<SvxBoxInfoItem>(SID_ATTR_BORDER_INNER));
+
+ if ( const SvxBoxInfoItem *pBoxInfo = rSet.GetItemIfSet( SID_ATTR_BORDER_INNER ))
+ {
+ aBoxInfo.reset(pBoxInfo->Clone());
+ }
+
+ // Table variant: If more than one table cells are selected
+ rSh.GetCursor(); //So that GetCursorCnt() returns the right thing
+ aBoxInfo->SetTable (rSh.IsTableMode() && rSh.GetCursorCnt() > 1);
+ // Always show the distance field
+ aBoxInfo->SetDist (true);
+ // Set minimal size in tables and paragraphs
+ aBoxInfo->SetMinDist (rSh.IsTableMode() || rSh.GetSelectionType() & (SelectionType::Text | SelectionType::Table));
+ // Set always the default distance
+ aBoxInfo->SetDefDist (MIN_BORDER_DIST);
+ // Single lines can have only in tables DontCare-Status
+ aBoxInfo->SetValid(SvxBoxInfoItemValidFlags::DISABLE, !rSh.IsTableMode());
+
+ rSet.Put(*aBoxInfo);
+}
+
+void ConvertAttrCharToGen(SfxItemSet& rSet, bool bIsPara)
+{
+ // Background / highlight
+ {
+ // Always use the visible background
+ if( const SvxBrushItem *pTmpBrush = rSet.GetItemIfSet( RES_CHRATR_HIGHLIGHT ) )
+ {
+ SvxBrushItem aTmpBrush( *pTmpBrush );
+ if( aTmpBrush.GetColor() != COL_TRANSPARENT )
+ {
+ aTmpBrush.SetWhich( RES_CHRATR_BACKGROUND );
+ rSet.Put( aTmpBrush );
+ }
+ }
+ }
+
+ if ( bIsPara )
+ return;
+
+ // Tell dialogs to use character-specific slots/whichIds
+ // tdf#126684: We use RES_PARATR_GRABBAG, because RES_CHRATR_GRABBAG may be overwritten later in
+ // SwDocStyleSheet::GetItemSet when applying attributes from char format
+ assert(SfxItemState::SET != rSet.GetItemState(RES_PARATR_GRABBAG, false));
+ SfxGrabBagItem aGrabBag(RES_PARATR_GRABBAG);
+ aGrabBag.GetGrabBag()["DialogUseCharAttr"] <<= true;
+ // Store initial ranges to allow restoring later
+ uno::Sequence<sal_uInt16> aOrigRanges(rSet.GetRanges().size() * 2 + 1);
+ int i = 0;
+ for (const auto& rPair : rSet.GetRanges())
+ {
+ aOrigRanges.getArray()[i++] = rPair.first;
+ aOrigRanges.getArray()[i++] = rPair.second;
+ }
+ aOrigRanges.getArray()[i++] = 0;
+ aGrabBag.GetGrabBag()["OrigItemSetRanges"] <<= aOrigRanges;
+ rSet.MergeRange(RES_PARATR_GRABBAG, RES_PARATR_GRABBAG);
+ rSet.Put(aGrabBag);
+}
+
+void ConvertAttrGenToChar(SfxItemSet& rSet, const SfxItemSet& rOrigSet, bool bIsPara)
+{
+ // Background / highlighting
+ if( SfxItemState::SET == rSet.GetItemState( RES_CHRATR_BACKGROUND, false ) )
+ {
+ // Highlight is an MS specific thing, so remove it at the first time when LO modifies
+ // this part of the imported document.
+ rSet.Put( SvxBrushItem(RES_CHRATR_HIGHLIGHT) );
+
+ // Remove shading marker
+ if (const SfxGrabBagItem* pGrabBagItem = rOrigSet.GetItemIfSet(RES_CHRATR_GRABBAG, false))
+ {
+ SfxGrabBagItem aGrabBag(*pGrabBagItem);
+ std::map<OUString, css::uno::Any>& rMap = aGrabBag.GetGrabBag();
+ auto aIterator = rMap.find("CharShadingMarker");
+ if( aIterator != rMap.end() )
+ {
+ aIterator->second <<= false;
+ }
+ rSet.Put( aGrabBag );
+ }
+ }
+
+ if ( bIsPara )
+ return;
+
+ rSet.ClearItem( RES_BACKGROUND );
+
+ if (const SfxGrabBagItem* pGrabBagItem = rOrigSet.GetItemIfSet(RES_PARATR_GRABBAG, false))
+ {
+ SfxGrabBagItem aGrabBag(*pGrabBagItem);
+ std::map<OUString, css::uno::Any>& rMap = aGrabBag.GetGrabBag();
+ auto aIterator = rMap.find("OrigItemSetRanges");
+ if (aIterator != rMap.end())
+ {
+ uno::Sequence<sal_uInt16> aOrigRanges;
+ if ( aIterator->second >>= aOrigRanges )
+ {
+ assert(aOrigRanges.getLength() % 2 == 1);
+ int numPairs = (aOrigRanges.getLength()-1)/2;
+ std::unique_ptr<WhichPair[]> xPairs(new WhichPair[numPairs]);
+ for(int i=0; i<aOrigRanges.getLength()-1; i += 2)
+ {
+ xPairs[i/2] = { aOrigRanges[i], aOrigRanges[i+1] };
+ }
+ rSet.SetRanges(WhichRangesContainer(std::move(xPairs), numPairs));
+ }
+ }
+ }
+ assert(SfxItemState::SET != rSet.GetItemState(RES_PARATR_GRABBAG, false));
+}
+
+void ApplyCharBackground(Color const& rBackgroundColor, model::ComplexColor const& rComplexColor, SwWrtShell& rShell)
+{
+ rShell.StartUndo(SwUndoId::INSATTR);
+
+ SfxItemSetFixed<RES_CHRATR_GRABBAG, RES_CHRATR_GRABBAG> aCoreSet(rShell.GetView().GetPool());
+
+ rShell.GetCurAttr(aCoreSet);
+
+ // Set char background
+ rShell.SetAttrItem(SvxBrushItem(rBackgroundColor, rComplexColor, RES_CHRATR_BACKGROUND));
+
+ // Highlight is an MS specific thing, so remove it at the first time when LO modifies
+ // this part of the imported document.
+ rShell.SetAttrItem(SvxBrushItem(RES_CHRATR_HIGHLIGHT));
+
+ // Remove shading marker
+ if (const SfxGrabBagItem* pGrabBagItem = aCoreSet.GetItemIfSet(RES_CHRATR_GRABBAG, false))
+ {
+ SfxGrabBagItem aGrabBag(*pGrabBagItem);
+ std::map<OUString, css::uno::Any>& rMap = aGrabBag.GetGrabBag();
+ auto aIterator = rMap.find("CharShadingMarker");
+ if (aIterator != rMap.end())
+ {
+ aIterator->second <<= false;
+ }
+ rShell.SetAttrItem(aGrabBag);
+ }
+
+ rShell.EndUndo(SwUndoId::INSATTR);
+}
+
+// Fill header footer
+
+static void FillHdFt(SwFrameFormat* pFormat, const SfxItemSet& rSet)
+{
+ SwAttrSet aSet(pFormat->GetAttrSet());
+ aSet.Put(rSet);
+
+ const SvxSizeItem& rSize = rSet.Get(SID_ATTR_PAGE_SIZE);
+ const SfxBoolItem& rDynamic = rSet.Get(SID_ATTR_PAGE_DYNAMIC);
+
+ // Convert size
+ SwFormatFrameSize aFrameSize(rDynamic.GetValue() ? SwFrameSize::Minimum : SwFrameSize::Fixed,
+ rSize.GetSize().Width(),
+ rSize.GetSize().Height());
+ aSet.Put(aFrameSize);
+ pFormat->SetFormatAttr(aSet);
+}
+
+/// Convert from UseOnPage to SvxPageUsage.
+static SvxPageUsage lcl_convertUseToSvx(UseOnPage nUse)
+{
+ SvxPageUsage nRet = SvxPageUsage::NONE;
+ if (nUse & UseOnPage::Left)
+ nRet = SvxPageUsage::Left;
+ if (nUse & UseOnPage::Right)
+ nRet = SvxPageUsage::Right;
+ if ((nUse & UseOnPage::All) == UseOnPage::All)
+ nRet = SvxPageUsage::All;
+ if ((nUse & UseOnPage::Mirror) == UseOnPage::Mirror)
+ nRet = SvxPageUsage::Mirror;
+ return nRet;
+}
+
+/// Convert from SvxPageUsage to UseOnPage.
+static UseOnPage lcl_convertUseFromSvx(SvxPageUsage nUse)
+{
+ UseOnPage nRet = UseOnPage::NONE;
+ if (nUse == SvxPageUsage::Left)
+ nRet = UseOnPage::Left;
+ else if (nUse == SvxPageUsage::Right)
+ nRet = UseOnPage::Right;
+ else if (nUse == SvxPageUsage::All)
+ nRet = UseOnPage::All;
+ else if (nUse == SvxPageUsage::Mirror)
+ nRet = UseOnPage::Mirror;
+ return nRet;
+}
+
+// PageDesc <-> convert into sets and back
+
+void ItemSetToPageDesc( const SfxItemSet& rSet, SwPageDesc& rPageDesc )
+{
+ SwFrameFormat& rMaster = rPageDesc.GetMaster();
+ bool bFirstShare = false;
+
+ // before SetFormatAttr() in case it contains RES_BACKGROUND_FULL_SIZE
+ // itself, as it does when called from SwXPageStyle
+ if (const SfxGrabBagItem* pGrabBag = rSet.GetItemIfSet(SID_ATTR_CHAR_GRABBAG))
+ {
+ bool bValue;
+ const auto pGrabBagInner = pGrabBag->GetGrabBag();
+ const auto iter = pGrabBagInner.find("BackgroundFullSize");
+ assert(iter != pGrabBagInner.end());
+ if (iter->second >>= bValue)
+ {
+ rMaster.SetFormatAttr(SfxBoolItem(RES_BACKGROUND_FULL_SIZE, bValue));
+ }
+ auto it = pGrabBagInner.find("RtlGutter");
+ if (it != pGrabBagInner.end() && (it->second >>= bValue))
+ {
+ rMaster.SetFormatAttr(SfxBoolItem(RES_RTL_GUTTER, bValue));
+ }
+ }
+
+ // Transfer all general frame attributes
+ rMaster.SetFormatAttr(rSet);
+
+ // PageData
+ if(rSet.GetItemState(SID_ATTR_PAGE) == SfxItemState::SET)
+ {
+ const SvxPageItem& rPageItem = rSet.Get(SID_ATTR_PAGE);
+
+ const SvxPageUsage nUse = rPageItem.GetPageUsage();
+ if(nUse != SvxPageUsage::NONE)
+ rPageDesc.SetUseOn( lcl_convertUseFromSvx(nUse) );
+ rPageDesc.SetLandscape(rPageItem.IsLandscape());
+ SvxNumberType aNumType;
+ aNumType.SetNumberingType( rPageItem.GetNumType() );
+ rPageDesc.SetNumType(aNumType);
+ }
+ // Size
+ if(rSet.GetItemState(SID_ATTR_PAGE_SIZE) == SfxItemState::SET)
+ {
+ const SvxSizeItem& rSizeItem = rSet.Get(SID_ATTR_PAGE_SIZE);
+ SwFormatFrameSize aSize(SwFrameSize::Fixed);
+ aSize.SetSize(rSizeItem.GetSize());
+ rMaster.SetFormatAttr(aSize);
+ }
+ // Evaluate header attributes
+ if( const SvxSetItem* pHeaderSetItem = rSet.GetItemIfSet( SID_ATTR_PAGE_HEADERSET,
+ false ) )
+ {
+ const SfxItemSet& rHeaderSet = pHeaderSetItem->GetItemSet();
+ const SfxBoolItem& rHeaderOn = rHeaderSet.Get(SID_ATTR_PAGE_ON);
+
+ if(rHeaderOn.GetValue())
+ {
+ // Take over values
+ if(!rMaster.GetHeader().IsActive())
+ rMaster.SetFormatAttr(SwFormatHeader(true));
+
+ // Pick out everything and adapt the header format
+ SwFormatHeader aHeaderFormat(rMaster.GetHeader());
+ SwFrameFormat *pHeaderFormat = aHeaderFormat.GetHeaderFormat();
+ OSL_ENSURE(pHeaderFormat != nullptr, "no header format");
+
+ ::FillHdFt(pHeaderFormat, rHeaderSet);
+
+ rPageDesc.ChgHeaderShare(rHeaderSet.Get(SID_ATTR_PAGE_SHARED).GetValue());
+ rPageDesc.ChgFirstShare(static_cast<const SfxBoolItem&>(
+ rHeaderSet.Get(SID_ATTR_PAGE_SHARED_FIRST)).GetValue());
+ bFirstShare = true;
+ }
+ else
+ {
+ // Disable header
+ if(rMaster.GetHeader().IsActive())
+ {
+ rMaster.SetFormatAttr(SwFormatHeader(false));
+ rPageDesc.ChgHeaderShare(false);
+ }
+ }
+ }
+
+ // Evaluate footer attributes
+ if( const SvxSetItem* pFooterSetItem = rSet.GetItemIfSet( SID_ATTR_PAGE_FOOTERSET,
+ false ) )
+ {
+ const SfxItemSet& rFooterSet = pFooterSetItem->GetItemSet();
+ const SfxBoolItem& rFooterOn = rFooterSet.Get(SID_ATTR_PAGE_ON);
+
+ if(rFooterOn.GetValue())
+ {
+ // Take over values
+ if(!rMaster.GetFooter().IsActive())
+ rMaster.SetFormatAttr(SwFormatFooter(true));
+
+ // Pick out everything and adapt the footer format
+ SwFormatFooter aFooterFormat(rMaster.GetFooter());
+ SwFrameFormat *pFooterFormat = aFooterFormat.GetFooterFormat();
+ OSL_ENSURE(pFooterFormat != nullptr, "no footer format");
+
+ ::FillHdFt(pFooterFormat, rFooterSet);
+
+ rPageDesc.ChgFooterShare(rFooterSet.Get(SID_ATTR_PAGE_SHARED).GetValue());
+ if (!bFirstShare)
+ {
+ rPageDesc.ChgFirstShare(static_cast<const SfxBoolItem&>(
+ rFooterSet.Get(SID_ATTR_PAGE_SHARED_FIRST)).GetValue());
+ }
+ }
+ else
+ {
+ // Disable footer
+ if(rMaster.GetFooter().IsActive())
+ {
+ rMaster.SetFormatAttr(SwFormatFooter(false));
+ rPageDesc.ChgFooterShare(false);
+ }
+ }
+ }
+
+ // Footnotes
+
+ if( const SwPageFootnoteInfoItem* pFootnoteItem = rSet.GetItemIfSet( FN_PARAM_FTN_INFO,
+ false ) )
+ rPageDesc.SetFootnoteInfo( pFootnoteItem->GetPageFootnoteInfo() );
+
+ // Columns
+
+ // Register compliant
+
+ const SfxBoolItem* pRegisterModeItem = rSet.GetItemIfSet(
+ SID_SWREGISTER_MODE, false);
+ if(!pRegisterModeItem)
+ return;
+
+ bool bSet = pRegisterModeItem->GetValue();
+ if(!bSet)
+ rPageDesc.SetRegisterFormatColl(nullptr);
+ else if(const SfxStringItem* pCollectionItem = rSet.GetItemIfSet(
+ SID_SWREGISTER_COLLECTION, false))
+ {
+ const OUString& rColl = pCollectionItem->GetValue();
+ SwDoc& rDoc = *rMaster.GetDoc();
+ SwTextFormatColl* pColl = rDoc.FindTextFormatCollByName( rColl );
+ if( !pColl )
+ {
+ const sal_uInt16 nId = SwStyleNameMapper::GetPoolIdFromUIName(
+ rColl, SwGetPoolIdFromName::TxtColl );
+ if( USHRT_MAX != nId )
+ pColl = rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool( nId );
+ else
+ pColl = rDoc.MakeTextFormatColl( rColl,
+ rDoc.GetDfltTextFormatColl() );
+ }
+ if( pColl )
+ pColl->SetFormatAttr( SwRegisterItem ( true ));
+ rPageDesc.SetRegisterFormatColl( pColl );
+ }
+}
+
+namespace
+{
+bool IsOwnFormat(const SwDoc& rDoc)
+{
+ const SwDocShell* pDocShell = rDoc.GetDocShell();
+ SfxMedium* pMedium = pDocShell->GetMedium();
+ if (!pMedium)
+ {
+ return false;
+ }
+
+ std::shared_ptr<const SfxFilter> pFilter = pMedium->GetFilter();
+ if (!pFilter)
+ {
+ return false;
+ }
+
+ return pFilter->IsOwnFormat();
+}
+}
+
+void PageDescToItemSet( const SwPageDesc& rPageDesc, SfxItemSet& rSet)
+{
+ const SwFrameFormat& rMaster = rPageDesc.GetMaster();
+
+ // Page data
+ SvxPageItem aPageItem(SID_ATTR_PAGE);
+ aPageItem.SetDescName(rPageDesc.GetName());
+ aPageItem.SetPageUsage(lcl_convertUseToSvx(rPageDesc.GetUseOn()));
+ aPageItem.SetLandscape(rPageDesc.GetLandscape());
+ aPageItem.SetNumType(rPageDesc.GetNumType().GetNumberingType());
+ rSet.Put(aPageItem);
+
+ // Size
+ SvxSizeItem aSizeItem(SID_ATTR_PAGE_SIZE, rMaster.GetFrameSize().GetSize());
+ rSet.Put(aSizeItem);
+
+ // Maximum size
+ SvxSizeItem aMaxSizeItem(SID_ATTR_PAGE_MAXSIZE, Size(MAXWIDTH, MAXHEIGHT));
+ rSet.Put(aMaxSizeItem);
+
+ // Margins, border and the other stuff.
+ rSet.Put(rMaster.GetAttrSet());
+
+ std::shared_ptr<SvxBoxInfoItem> aBoxInfo(std::make_shared<SvxBoxInfoItem>(SID_ATTR_BORDER_INNER));
+
+ if ( const SvxBoxInfoItem *pBoxInfo = rSet.GetItemIfSet( SID_ATTR_BORDER_INNER ) )
+ {
+ aBoxInfo.reset(pBoxInfo->Clone());
+ }
+
+ aBoxInfo->SetTable( false );
+ // Show always the distance field
+ aBoxInfo->SetDist( true);
+ // Set minimal size in tables and paragraphs
+ aBoxInfo->SetMinDist( false );
+ // Set always the default distance
+ aBoxInfo->SetDefDist( MIN_BORDER_DIST );
+ // Single lines can have only in tables DontCare-Status
+ aBoxInfo->SetValid( SvxBoxInfoItemValidFlags::DISABLE );
+ rSet.Put( *aBoxInfo );
+
+ SfxStringItem aFollow(SID_ATTR_PAGE_EXT1, OUString());
+ if(rPageDesc.GetFollow())
+ aFollow.SetValue(rPageDesc.GetFollow()->GetName());
+ rSet.Put(aFollow);
+
+ // Header
+ if(rMaster.GetHeader().IsActive())
+ {
+ const SwFormatHeader &rHeaderFormat = rMaster.GetHeader();
+ const SwFrameFormat *pHeaderFormat = rHeaderFormat.GetHeaderFormat();
+ OSL_ENSURE(pHeaderFormat != nullptr, "no header format");
+
+ // HeaderInfo, margins, background, border
+ SfxItemSetFixed<RES_FRMATR_BEGIN,RES_FRMATR_END - 1, // [82
+
+ // FillAttribute support
+ XATTR_FILL_FIRST, XATTR_FILL_LAST, // [1014
+
+ SID_ATTR_BORDER_INNER,SID_ATTR_BORDER_INNER, // [10023
+ SID_ATTR_PAGE_SIZE,SID_ATTR_PAGE_SIZE, // [10051
+ SID_ATTR_PAGE_ON,SID_ATTR_PAGE_SHARED, // [10060
+ SID_ATTR_PAGE_SHARED_FIRST,SID_ATTR_PAGE_SHARED_FIRST> aHeaderSet(*rSet.GetPool());
+
+ // set correct parent to get the XFILL_NONE FillStyle as needed
+ aHeaderSet.SetParent(&rMaster.GetDoc()->GetDfltFrameFormat()->GetAttrSet());
+
+ // Dynamic or fixed height
+ SfxBoolItem aOn(SID_ATTR_PAGE_ON, true);
+ aHeaderSet.Put(aOn);
+
+ const SwFormatFrameSize &rFrameSize = pHeaderFormat->GetFrameSize();
+ const SwFrameSize eSizeType = rFrameSize.GetHeightSizeType();
+ SfxBoolItem aDynamic(SID_ATTR_PAGE_DYNAMIC, eSizeType != SwFrameSize::Fixed);
+ aHeaderSet.Put(aDynamic);
+
+ // Left equal right
+ SfxBoolItem aShared(SID_ATTR_PAGE_SHARED, rPageDesc.IsHeaderShared());
+ aHeaderSet.Put(aShared);
+ SfxBoolItem aFirstShared(SID_ATTR_PAGE_SHARED_FIRST, rPageDesc.IsFirstShared());
+ aHeaderSet.Put(aFirstShared);
+
+ // Size
+ SvxSizeItem aSize(SID_ATTR_PAGE_SIZE, rFrameSize.GetSize());
+ aHeaderSet.Put(aSize);
+
+ // Shifting frame attributes
+ aHeaderSet.Put(pHeaderFormat->GetAttrSet());
+ aHeaderSet.Put( *aBoxInfo );
+
+ // Create SetItem
+ SvxSetItem aSetItem(SID_ATTR_PAGE_HEADERSET, aHeaderSet);
+ rSet.Put(aSetItem);
+ }
+
+ // Footer
+ if(rMaster.GetFooter().IsActive())
+ {
+ const SwFormatFooter &rFooterFormat = rMaster.GetFooter();
+ const SwFrameFormat *pFooterFormat = rFooterFormat.GetFooterFormat();
+ OSL_ENSURE(pFooterFormat != nullptr, "no footer format");
+
+ // FooterInfo, margins, background, border
+ SfxItemSetFixed<RES_FRMATR_BEGIN,RES_FRMATR_END - 1, // [82
+
+ // FillAttribute support
+ XATTR_FILL_FIRST, XATTR_FILL_LAST, // [1014
+
+ SID_ATTR_BORDER_INNER,SID_ATTR_BORDER_INNER, // [10023
+ SID_ATTR_PAGE_SIZE,SID_ATTR_PAGE_SIZE, // [10051
+ SID_ATTR_PAGE_ON,SID_ATTR_PAGE_SHARED, // [10060
+ SID_ATTR_PAGE_SHARED_FIRST,SID_ATTR_PAGE_SHARED_FIRST> aFooterSet(*rSet.GetPool());
+
+ // set correct parent to get the XFILL_NONE FillStyle as needed
+ aFooterSet.SetParent(&rMaster.GetDoc()->GetDfltFrameFormat()->GetAttrSet());
+
+ // Dynamic or fixed height
+ SfxBoolItem aOn(SID_ATTR_PAGE_ON, true);
+ aFooterSet.Put(aOn);
+
+ const SwFormatFrameSize &rFrameSize = pFooterFormat->GetFrameSize();
+ const SwFrameSize eSizeType = rFrameSize.GetHeightSizeType();
+ SfxBoolItem aDynamic(SID_ATTR_PAGE_DYNAMIC, eSizeType != SwFrameSize::Fixed);
+ aFooterSet.Put(aDynamic);
+
+ // Left equal right
+ SfxBoolItem aShared(SID_ATTR_PAGE_SHARED, rPageDesc.IsFooterShared());
+ aFooterSet.Put(aShared);
+ SfxBoolItem aFirstShared(SID_ATTR_PAGE_SHARED_FIRST, rPageDesc.IsFirstShared());
+ aFooterSet.Put(aFirstShared);
+
+ // Size
+ SvxSizeItem aSize(SID_ATTR_PAGE_SIZE, rFrameSize.GetSize());
+ aFooterSet.Put(aSize);
+
+ // Shifting Frame attributes
+ aFooterSet.Put(pFooterFormat->GetAttrSet());
+ aFooterSet.Put( *aBoxInfo );
+
+ // Create SetItem
+ SvxSetItem aSetItem(SID_ATTR_PAGE_FOOTERSET, aFooterSet);
+ rSet.Put(aSetItem);
+ }
+
+ // Integrate footnotes
+ SwPageFootnoteInfo& rInfo = const_cast<SwPageFootnoteInfo&>(rPageDesc.GetFootnoteInfo());
+ SwPageFootnoteInfoItem aFootnoteItem(rInfo);
+ rSet.Put(aFootnoteItem);
+
+ // Register compliant
+ const SwTextFormatColl* pCol = rPageDesc.GetRegisterFormatColl();
+ SwRegisterItem aReg(pCol != nullptr);
+ aReg.SetWhich(SID_SWREGISTER_MODE);
+ rSet.Put(aReg);
+ if(pCol)
+ rSet.Put(SfxStringItem(SID_SWREGISTER_COLLECTION, pCol->GetName()));
+
+ std::optional<SfxGrabBagItem> oGrabBag;
+ if (SfxGrabBagItem const* pItem = rSet.GetItemIfSet(SID_ATTR_CHAR_GRABBAG))
+ {
+ oGrabBag.emplace(*pItem);
+ }
+ else
+ {
+ oGrabBag.emplace(SID_ATTR_CHAR_GRABBAG);
+ }
+ oGrabBag->GetGrabBag()["BackgroundFullSize"] <<=
+ rMaster.GetAttrSet().GetItem<SfxBoolItem>(RES_BACKGROUND_FULL_SIZE)->GetValue();
+
+ if (IsOwnFormat(*rMaster.GetDoc()))
+ {
+ oGrabBag->GetGrabBag()["RtlGutter"]
+ <<= rMaster.GetAttrSet().GetItem<SfxBoolItem>(RES_RTL_GUTTER)->GetValue();
+ }
+
+ rSet.Put(*oGrabBag);
+}
+
+// Set DefaultTabs
+
+void MakeDefTabs(SwTwips nDefDist, SvxTabStopItem& rTabs)
+{
+ if( rTabs.Count() )
+ return;
+ {
+ SvxTabStop aSwTabStop( nDefDist, SvxTabAdjust::Default );
+ rTabs.Insert( aSwTabStop );
+ }
+}
+
+// Distance between two tabs
+
+SwTwips GetTabDist(const SvxTabStopItem& rTabs)
+{
+ return rTabs.Count() ? rTabs[0].GetTabPos() : 1134; // 1134 = 2 cm
+}
+
+// Inquire if in the set is a Sfx-PageDesc combination present and return it.
+void SfxToSwPageDescAttr( const SwWrtShell& rShell, SfxItemSet& rSet )
+{
+ const SfxPoolItem* pItem;
+ SwFormatPageDesc aPgDesc;
+
+ bool bChanged = false;
+ // Page number
+ switch (rSet.GetItemState(SID_ATTR_PARA_PAGENUM, false, &pItem))
+ {
+ case SfxItemState::SET:
+ {
+ aPgDesc.SetNumOffset(static_cast<const SfxUInt16Item*>(pItem)->GetValue());
+ bChanged = true;
+ break;
+ }
+ case SfxItemState::DISABLED:
+ {
+ bChanged = true; // default initialised aPgDesc clears the number
+ break;
+ }
+ case SfxItemState::UNKNOWN:
+ case SfxItemState::DEFAULT:
+ break;
+ default:
+ assert(false); // unexpected
+ break;
+ }
+ if( const SvxPageModelItem* pModelItem = rSet.GetItemIfSet( SID_ATTR_PARA_MODEL, false ))
+ {
+ const OUString& rDescName = pModelItem->GetValue();
+ if( !rDescName.isEmpty() ) // No name -> disable PageDesc!
+ {
+ // Delete only, if PageDesc will be enabled!
+ rSet.ClearItem( RES_BREAK );
+ SwPageDesc* pDesc = const_cast<SwWrtShell&>(rShell).FindPageDescByName(
+ rDescName, true );
+ if( pDesc )
+ aPgDesc.RegisterToPageDesc( *pDesc );
+ }
+ rSet.ClearItem( SID_ATTR_PARA_MODEL );
+ bChanged = true;
+ }
+ else
+ {
+ SfxItemSetFixed<RES_PAGEDESC, RES_PAGEDESC> aCoreSet(rShell.GetView().GetPool());
+ rShell.GetCurAttr( aCoreSet );
+ if(const SwFormatPageDesc* pPageDescItem = aCoreSet.GetItemIfSet( RES_PAGEDESC ) )
+ {
+ const SwPageDesc* pPageDesc = pPageDescItem->GetPageDesc();
+ if( pPageDesc )
+ {
+ aPgDesc.RegisterToPageDesc( *const_cast<SwPageDesc*>(pPageDesc) );
+ }
+ }
+ }
+
+ if(bChanged)
+ rSet.Put( aPgDesc );
+}
+
+// Inquire if in the set is a Sfx-PageDesc combination present and return it.
+void SwToSfxPageDescAttr( SfxItemSet& rCoreSet )
+{
+ const SwFormatPageDesc* pPageDescItem = nullptr;
+ OUString aName;
+ ::std::optional<sal_uInt16> oNumOffset;
+ bool bPut = true;
+ switch( rCoreSet.GetItemState( RES_PAGEDESC, true, &pPageDescItem ) )
+ {
+ case SfxItemState::SET:
+ {
+ if( pPageDescItem->GetPageDesc() )
+ {
+ aName = pPageDescItem->GetPageDesc()->GetName();
+ oNumOffset = pPageDescItem->GetNumOffset();
+ }
+ rCoreSet.ClearItem( RES_PAGEDESC );
+ // Page number
+ }
+ break;
+
+ case SfxItemState::DEFAULT:
+ break;
+
+ default:
+ bPut = false;
+ }
+
+ if (oNumOffset)
+ {
+ SfxUInt16Item aPageNum( SID_ATTR_PARA_PAGENUM, *oNumOffset );
+ rCoreSet.Put( aPageNum );
+ }
+
+ if(bPut)
+ rCoreSet.Put( SvxPageModelItem( aName, true, SID_ATTR_PARA_MODEL ) );
+}
+
+// Determine metric
+
+FieldUnit GetDfltMetric(bool bWeb)
+{
+ return SW_MOD()->GetUsrPref(bWeb)->GetMetric();
+}
+
+// Determine metric
+
+void SetDfltMetric( FieldUnit eMetric, bool bWeb )
+{
+ SW_MOD()->ApplyUserMetric(eMetric, bWeb);
+}
+
+void InsertStringSorted(const OUString& rId, const OUString& rEntry, weld::ComboBox& rToFill, int nOffset)
+{
+ CollatorWrapper& rCaseColl = ::GetAppCaseCollator();
+ const int nCount = rToFill.get_count();
+ while (nOffset < nCount)
+ {
+ if (0 < rCaseColl.compareString(rToFill.get_text(nOffset), rEntry))
+ break;
+ ++nOffset;
+ }
+ rToFill.insert(nOffset, rEntry, &rId, nullptr, nullptr);
+}
+
+void FillCharStyleListBox(weld::ComboBox& rToFill, SwDocShell* pDocSh, bool bSorted, bool bWithDefault)
+{
+ const int nOffset = rToFill.get_count() > 0 ? 1 : 0;
+ rToFill.freeze();
+ SfxStyleSheetBasePool* pPool = pDocSh->GetStyleSheetPool();
+ SwDoc* pDoc = pDocSh->GetDoc();
+ const SfxStyleSheetBase* pBase = pPool->First(SfxStyleFamily::Char);
+ const OUString sStandard(SwResId(STR_POOLCHR_STANDARD));
+ while(pBase)
+ {
+ if(bWithDefault || pBase->GetName() != sStandard)
+ {
+ sal_IntPtr nPoolId = SwStyleNameMapper::GetPoolIdFromUIName( pBase->GetName(), SwGetPoolIdFromName::ChrFmt );
+ OUString sId(OUString::number(nPoolId));
+ if (bSorted)
+ InsertStringSorted(sId, pBase->GetName(), rToFill, nOffset);
+ else
+ rToFill.append(sId, pBase->GetName());
+ }
+ pBase = pPool->Next();
+ }
+ // non-pool styles
+ const SwCharFormats* pFormats = pDoc->GetCharFormats();
+ for(size_t i = 0; i < pFormats->size(); ++i)
+ {
+ const SwCharFormat* pFormat = (*pFormats)[i];
+ if(pFormat->IsDefault())
+ continue;
+ const OUString& rName = pFormat->GetName();
+ if (rToFill.find_text(rName) == -1)
+ {
+ OUString sId(OUString::number(USHRT_MAX));
+ if (bSorted)
+ InsertStringSorted(sId, rName, rToFill, nOffset);
+ else
+ rToFill.append(sId, rName);
+ }
+ }
+ rToFill.thaw();
+};
+
+SwTwips GetTableWidth( SwFrameFormat const * pFormat, SwTabCols const & rCols, sal_uInt16 *pPercent,
+ SwWrtShell* pSh )
+{
+ // To get the width is slightly more complicated.
+ SwTwips nWidth = 0;
+ const sal_Int16 eOri = pFormat->GetHoriOrient().GetHoriOrient();
+ switch(eOri)
+ {
+ case text::HoriOrientation::FULL: nWidth = rCols.GetRight(); break;
+ case text::HoriOrientation::LEFT_AND_WIDTH:
+ case text::HoriOrientation::LEFT:
+ case text::HoriOrientation::RIGHT:
+ case text::HoriOrientation::CENTER:
+ nWidth = pFormat->GetFrameSize().GetWidth();
+ break;
+ default:
+ {
+ if(pSh)
+ {
+ if ( nullptr == pSh->GetFlyFrameFormat() )
+ {
+ nWidth = pSh->GetAnyCurRect(CurRectType::PagePrt).Width();
+ }
+ else
+ {
+ nWidth = pSh->GetAnyCurRect(CurRectType::FlyEmbeddedPrt).Width();
+ }
+ }
+ else
+ {
+ OSL_FAIL("where to get the actual width from?");
+ }
+ const SvxLRSpaceItem& rLRSpace = pFormat->GetLRSpace();
+ nWidth -= (rLRSpace.GetRight() + rLRSpace.GetLeft());
+ }
+ }
+ if (pPercent)
+ *pPercent = pFormat->GetFrameSize().GetWidthPercent();
+ return nWidth;
+}
+
+OUString GetAppLangDateTimeString( const DateTime& rDT )
+{
+ const SvtSysLocale aSysLocale;
+ const LocaleDataWrapper& rAppLclData = aSysLocale.GetLocaleData();
+ OUString sRet = rAppLclData.getDate( rDT ) + " " + rAppLclData.getTime( rDT );
+ return sRet;
+}
+
+// Add a new function which can get and set the current "SID_ATTR_APPLYCHARUNIT" value
+
+bool HasCharUnit( bool bWeb)
+{
+ return SW_MOD()->GetUsrPref(bWeb)->IsApplyCharUnit();
+}
+
+void SetApplyCharUnit(bool bApplyChar, bool bWeb)
+{
+ SW_MOD()->ApplyUserCharUnit(bApplyChar, bWeb);
+}
+
+bool ExecuteMenuCommand(const css::uno::Reference<css::awt::XPopupMenu>& rMenu, const SfxViewFrame& rViewFrame, sal_uInt16 nId)
+{
+ bool bRet = false;
+ const sal_uInt16 nItemCount = rMenu->getItemCount();
+ OUString sCommand;
+ for (sal_uInt16 nItem = 0; nItem < nItemCount; ++nItem)
+ {
+ sal_Int16 nItemId = rMenu->getItemId(nItem);
+ css::uno::Reference<css::awt::XPopupMenu> xPopup = rMenu->getPopupMenu(nItemId);
+ if (xPopup.is())
+ {
+ sCommand = xPopup->getCommand(nId);
+ if(!sCommand.isEmpty())
+ break;
+ }
+ }
+ if(!sCommand.isEmpty())
+ {
+ uno::Reference< frame::XFrame > xFrame = rViewFrame.GetFrame().GetFrameInterface();
+ uno::Reference < frame::XDispatchProvider > xProv( xFrame, uno::UNO_QUERY );
+ util::URL aURL;
+ aURL.Complete = sCommand;
+ uno::Reference < util::XURLTransformer > xTrans( util::URLTransformer::create(::comphelper::getProcessComponentContext() ) );
+ xTrans->parseStrict( aURL );
+ uno::Reference< frame::XDispatch > xDisp = xProv->queryDispatch( aURL, OUString(), 0 );
+ if( xDisp.is() )
+ {
+ uno::Sequence< beans::PropertyValue > aSeq;
+ xDisp->dispatch( aURL, aSeq );
+ bRet = true;
+ }
+ }
+ return bRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/utlui/unotools.cxx b/sw/source/uibase/utlui/unotools.cxx
new file mode 100644
index 0000000000..93edfaad30
--- /dev/null
+++ b/sw/source/uibase/utlui/unotools.cxx
@@ -0,0 +1,496 @@
+/* -*- 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 <sal/config.h>
+
+#include <string_view>
+
+#include <swtypes.hxx>
+
+#include <strings.hrc>
+#include <unotools.hxx>
+#include <unoprnms.hxx>
+#include <unotextcursor.hxx>
+#include <i18nutil/unicode.hxx>
+#include <o3tl/string_view.hxx>
+#include <rtl/string.h>
+#include <svtools/colorcfg.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/jobset.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/weld.hxx>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/text/XTextViewCursorSupplier.hpp>
+#include <com/sun/star/view/XScreenCursor.hpp>
+#include <com/sun/star/view/DocumentZoomType.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/style/XStyle.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <com/sun/star/awt/PosSize.hpp>
+#include <com/sun/star/view/XViewSettingsSupplier.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/frame/XLayoutManager.hpp>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/string.hxx>
+#include <docsh.hxx>
+#include <editsh.hxx>
+#include <wrtsh.hxx>
+#include <swmodule.hxx>
+#include <TextCursorHelper.hxx>
+#include <doc.hxx>
+
+using namespace ::com::sun::star;
+
+constexpr OUStringLiteral cFactory = u"private:factory/swriter";
+
+static void disableScrollBars(uno::Reference< beans::XPropertySet > const & xViewProps,
+ bool bEnableOnlineMode)
+{
+ //the scrollbar logic is kind of busted looking in writer, when the hori scrollbar
+ //property is changed then the hori scrollbar is enabled if the property is
+ //true or browse (online) mode is enabled. So...
+ //disable online mode
+ //turn off scrollbars
+ //turn back on online mode if that's what we want
+ //which subverts the (dodgy/buggy) scrollbar setting
+
+ //To reproduce this problem, in edit->autotext and click through
+ //the examples and see if the preview gets a horizontal scrollbar
+ uno::Any aFalseSet(uno::Any(false));
+ xViewProps->setPropertyValue(UNO_NAME_SHOW_ONLINE_LAYOUT, aFalseSet);
+
+ xViewProps->setPropertyValue(UNO_NAME_SHOW_HORI_SCROLL_BAR, aFalseSet);
+ xViewProps->setPropertyValue(UNO_NAME_SHOW_VERT_SCROLL_BAR, aFalseSet);
+
+ if (bEnableOnlineMode)
+ {
+ xViewProps->setPropertyValue(UNO_NAME_SHOW_ONLINE_LAYOUT, uno::Any(true));
+ }
+}
+
+SwOneExampleFrame::SwOneExampleFrame(sal_uInt32 nFlags,
+ const Link<SwOneExampleFrame&,void>* pInitializedLink,
+ const OUString* pURL)
+ : m_aLoadedIdle("sw uibase SwOneExampleFrame Loaded")
+ , m_pModuleView(SW_MOD()->GetView())
+ , m_nStyleFlags(nFlags)
+ , m_bIsInitialized(false)
+{
+ if (pURL && !pURL->isEmpty())
+ m_sArgumentURL = *pURL;
+
+ if( pInitializedLink )
+ m_aInitializedLink = *pInitializedLink;
+
+ // the controller is asynchronously set
+ m_aLoadedIdle.SetInvokeHandler(LINK(this, SwOneExampleFrame, TimeoutHdl));
+ m_aLoadedIdle.SetPriority(TaskPriority::HIGH_IDLE);
+}
+
+void SwOneExampleFrame::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ m_xVirDev = VclPtr<VirtualDevice>::Create();
+ Size aSize(m_xVirDev->LogicToPixel(Size(150, 188), MapMode(MapUnit::MapAppFont)));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ SetOutputSizePixel(aSize);
+ CreateControl();
+}
+
+bool SwOneExampleFrame::Command(const CommandEvent& rCEvt)
+{
+ switch (rCEvt.GetCommand())
+ {
+ case CommandEventId::ContextMenu:
+ {
+ //#125881# quickly clicking crashes because the control is not fully initialized
+ if (m_xController.is())
+ return CreatePopup(rCEvt.GetMousePosPixel());
+ }
+ break;
+ default:;
+ break;
+ }
+ return CustomWidgetController::Command(rCEvt);
+}
+
+void SwOneExampleFrame::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ Size aSize(GetOutputSizePixel());
+ // m_xVirDev instead of rRenderContext just to avoid overlays in writer re-triggering
+ // invalidate on rRenderContext if it is a vcl::Window, which is the "classic" gen mode
+ m_xVirDev->SetOutputSizePixel(aSize);
+
+ Color aBgColor = SW_MOD()->GetColorConfig().GetColorValue(::svtools::DOCCOLOR).nColor;
+ m_xVirDev->DrawWallpaper(tools::Rectangle(Point(), aSize), aBgColor);
+
+ if (m_xCursor)
+ {
+ uno::Reference<view::XViewSettingsSupplier> xSettings(m_xController, uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xViewProps = xSettings->getViewSettings();
+ uno::Any aZoom = xViewProps->getPropertyValue(UNO_NAME_ZOOM_VALUE);
+ sal_Int16 nZoom = 100;
+ aZoom >>= nZoom;
+
+ double fZoom = 100.0 / nZoom;
+
+ m_xVirDev->Push(vcl::PushFlags::ALL);
+ m_xVirDev->SetMapMode(MapMode(MapUnit::MapTwip));
+ SwDoc *pDoc = m_xCursor->GetDoc();
+ SwDocShell* pShell = pDoc->GetDocShell();
+ tools::Rectangle aRect(Point(), m_xVirDev->PixelToLogic(aSize));
+ pShell->SetVisArea(tools::Rectangle(Point(), Size(aRect.GetWidth() * fZoom,
+ aRect.GetHeight() * fZoom)));
+ pShell->DoDraw(m_xVirDev.get(), aRect.TopLeft(), aRect.GetSize(), JobSetup(), ASPECT_CONTENT, true);
+ m_xVirDev->Pop();
+ }
+
+ rRenderContext.DrawOutDev(Point(), aSize, Point(), aSize, *m_xVirDev);
+}
+
+SwOneExampleFrame::~SwOneExampleFrame()
+{
+ DisposeControl();
+}
+
+void SwOneExampleFrame::CreateControl()
+{
+ // create new doc
+ OUString sTempURL(cFactory);
+ if(!m_sArgumentURL.isEmpty())
+ sTempURL = m_sArgumentURL;
+
+ uno::Reference<frame::XDesktop2> xDesktop = frame::Desktop::create(::comphelper::getProcessComponentContext());
+ uno::Sequence<beans::PropertyValue> args( comphelper::InitPropertySequence({
+ { "DocumentService", uno::Any(OUString("com.sun.star.text.TextDocument")) },
+ { "OpenFlags", uno::Any(OUString("-RB")) },
+ { "Referer", uno::Any(OUString("private:user")) },
+ { "ReadOnly", uno::Any(true) },
+ { "Hidden", uno::Any(true) }
+ }));
+
+ m_xModel.set(xDesktop->loadComponentFromURL(sTempURL, "_blank", 0, args), uno::UNO_QUERY);
+
+ m_aLoadedIdle.Start();
+}
+
+void SwOneExampleFrame::DisposeControl()
+{
+ m_aLoadedIdle.Stop();
+ m_xCursor = nullptr;
+ if (m_xModel)
+ {
+ m_xModel->dispose();
+ m_xModel = nullptr;
+ }
+ m_xController = nullptr;
+}
+
+IMPL_LINK( SwOneExampleFrame, TimeoutHdl, Timer*, pTimer, void )
+{
+ if (!m_xModel.is())
+ return;
+
+ m_xController = m_xModel->getCurrentController();
+
+ if (m_xController.is())
+ {
+ uno::Reference<frame::XFrame> xFrame = m_xController->getFrame();
+ uno::Reference< beans::XPropertySet > xPropSet( xFrame, uno::UNO_QUERY );
+ if ( xPropSet.is() )
+ {
+ try
+ {
+ uno::Reference< frame::XLayoutManager > xLayoutManager;
+ uno::Any aValue = xPropSet->getPropertyValue("LayoutManager");
+ aValue >>= xLayoutManager;
+ if ( xLayoutManager.is() )
+ xLayoutManager->setVisible( false );
+ }
+ catch (const uno::Exception&)
+ {
+ }
+ }
+
+ //now the ViewOptions should be set properly
+ uno::Reference< view::XViewSettingsSupplier > xSettings(m_xController, uno::UNO_QUERY);
+ uno::Reference< beans::XPropertySet > xViewProps = xSettings->getViewSettings();
+
+ const uno::Any aTrueSet( true );
+ const uno::Any aFalseSet( false );
+
+ if( !m_bIsInitialized )
+ {
+ xViewProps->setPropertyValue(UNO_NAME_SHOW_BREAKS, aFalseSet);
+ xViewProps->setPropertyValue(UNO_NAME_SHOW_DRAWINGS, aTrueSet);
+ xViewProps->setPropertyValue(UNO_NAME_SHOW_FIELD_COMMANDS, aFalseSet);
+ xViewProps->setPropertyValue(UNO_NAME_SHOW_GRAPHICS, aTrueSet);
+ xViewProps->setPropertyValue(UNO_NAME_HIDE_WHITESPACE, aFalseSet);
+ xViewProps->setPropertyValue(UNO_NAME_SHOW_HIDDEN_PARAGRAPHS, aFalseSet);
+ xViewProps->setPropertyValue(UNO_NAME_SHOW_HIDDEN_TEXT, aFalseSet);
+ xViewProps->setPropertyValue(UNO_NAME_SHOW_HORI_RULER, aFalseSet);
+ xViewProps->setPropertyValue(UNO_NAME_SHOW_PARA_BREAKS, aFalseSet);
+ xViewProps->setPropertyValue(UNO_NAME_SHOW_PROTECTED_SPACES, aFalseSet);
+ xViewProps->setPropertyValue(UNO_NAME_SHOW_SOFT_HYPHENS, aFalseSet);
+ xViewProps->setPropertyValue(UNO_NAME_SHOW_SPACES, aFalseSet);
+ xViewProps->setPropertyValue(UNO_NAME_SHOW_TABLES, aTrueSet);
+ xViewProps->setPropertyValue(UNO_NAME_SHOW_TABSTOPS, aFalseSet);
+ xViewProps->setPropertyValue(UNO_NAME_SHOW_VERT_RULER, aFalseSet);
+
+ if(0 ==(m_nStyleFlags&EX_SHOW_ONLINE_LAYOUT))
+ {
+ uno::Any aZoom;
+ aZoom <<= sal_Int16(view::DocumentZoomType::PAGE_WIDTH_EXACT);
+ xViewProps->setPropertyValue(UNO_NAME_ZOOM_TYPE, aZoom);
+ }
+ else
+ {
+ uno::Any aZoom;
+ aZoom <<= sal_Int16(view::DocumentZoomType::BY_VALUE);
+ xViewProps->setPropertyValue(UNO_NAME_ZOOM_TYPE, aZoom);
+
+ sal_Int16 nZoomValue = 75;
+ if(EX_SHOW_BUSINESS_CARDS == m_nStyleFlags)
+ {
+ nZoomValue = 80;
+ }
+ aZoom <<= nZoomValue;
+ xViewProps->setPropertyValue(UNO_NAME_ZOOM_VALUE, aZoom);
+ }
+
+ // set onlinelayout property after setting the zoom
+ disableScrollBars(xViewProps, (m_nStyleFlags&EX_SHOW_ONLINE_LAYOUT) != 0);
+ m_bIsInitialized = true;
+ }
+
+ uno::Reference< text::XTextDocument > xDoc(m_xModel, uno::UNO_QUERY);
+ uno::Reference< text::XText > xText = xDoc->getText();
+ uno::Reference< text::XTextCursor > xTextCursor = xText->createTextCursor();
+ m_xCursor = dynamic_cast<SwXTextCursor*>(xTextCursor.get());
+ assert(bool(xTextCursor) == bool(m_xCursor) && "expect to get SwXTextCursor type here");
+
+ //From here, a cursor is defined, which goes through the template,
+ //and overwrites the template words where it is necessary.
+
+ SwDoc *pDoc = m_xCursor ? m_xCursor->GetDoc() : nullptr;
+ if (pDoc && (m_nStyleFlags & EX_LOCALIZE_TOC_STRINGS))
+ {
+ SwEditShell* pSh = pDoc->GetEditShell();
+
+ do
+ {
+ if (pSh->GetCurWord() == "HEADING1")
+ {
+ pSh->Overwrite(SwResId(STR_IDXEXAMPLE_IDXTXT_HEADING1));
+ }
+ else if (pSh->GetCurWord() == "ENTRY1")
+ {
+ pSh->Overwrite(SwResId(STR_IDXEXAMPLE_IDXTXT_ENTRY1));
+ }
+ else if (pSh->GetCurWord() == "HEADING11")
+ {
+ pSh->Overwrite(SwResId(STR_IDXEXAMPLE_IDXTXT_HEADING11));
+ }
+ else if (pSh->GetCurWord() == "ENTRY11")
+ {
+ pSh->Overwrite(SwResId(STR_IDXEXAMPLE_IDXTXT_ENTRY11));
+ }
+ else if (pSh->GetCurWord() == "HEADING12")
+ {
+ pSh->Overwrite(SwResId(STR_IDXEXAMPLE_IDXTXT_HEADING12));
+ }
+ else if (pSh->GetCurWord() == "ENTRY12")
+ {
+ pSh->Overwrite(SwResId(STR_IDXEXAMPLE_IDXTXT_ENTRY12));
+ }
+ else if (pSh->GetCurWord() == "TABLE1")
+ {
+ pSh->Overwrite(SwResId(STR_IDXEXAMPLE_IDXTXT_TABLE1));
+ }
+ else if (pSh->GetCurWord() == "IMAGE1")
+ {
+ pSh->Overwrite(SwResId(STR_IDXEXAMPLE_IDXTXT_IMAGE1));
+ }
+ }
+ while(pSh->Right(sal_uInt16(1), SwCursorSkipMode::Cells, true));
+
+ TOXTypes eTypes[] = { TOX_INDEX, TOX_USER, TOX_CONTENT };
+ for (auto eType : eTypes)
+ {
+ const SwTOXType* pTOXType = pDoc->GetTOXType(eType, 0);
+ SwTOXMarks aMarks;
+ pTOXType->CollectTextMarks(aMarks);
+ for (auto pMark : aMarks)
+ {
+ if (pMark->GetAlternativeText() == "Chapter")
+ pMark->SetAlternativeText(SwResId(STR_IDXEXAMPLE_IDXMARK_CHAPTER));
+ else if (pMark->GetAlternativeText() == "Keyword")
+ pMark->SetAlternativeText(SwResId(STR_IDXEXAMPLE_IDXMARK_KEYWORD));
+ else if (pMark->GetAlternativeText() == "this")
+ pMark->SetAlternativeText(SwResId(STR_IDXEXAMPLE_IDXMARK_THIS));
+ else if (pMark->GetAlternativeText() == "User Directory Entry")
+ pMark->SetAlternativeText(SwResId(STR_IDXEXAMPLE_IDXMARK_USER_DIR_ENTRY));
+ else if (pMark->GetAlternativeText() == "Entry")
+ pMark->SetAlternativeText(SwResId(STR_IDXEXAMPLE_IDXMARK_ENTRY));
+
+ if (pMark->GetPrimaryKey() == "Primary key")
+ pMark->SetPrimaryKey(SwResId(STR_IDXEXAMPLE_IDXMARK_PRIMARY_KEY));
+
+ if (pMark->GetSecondaryKey() == "Secondary key")
+ pMark->SetSecondaryKey(SwResId(STR_IDXEXAMPLE_IDXMARK_SECONDARY_KEY));
+ }
+ }
+ }
+
+ uno::Any aPageStyle = m_xCursor->getPropertyValue(UNO_NAME_PAGE_STYLE_NAME);
+ OUString sPageStyle;
+ aPageStyle >>= sPageStyle;
+
+ uno::Reference< style::XStyleFamiliesSupplier > xSSupp( xDoc, uno::UNO_QUERY);
+ uno::Reference< container::XNameAccess > xStyles = xSSupp->getStyleFamilies();
+ uno::Any aPFamily = xStyles->getByName( "PageStyles" );
+ uno::Reference< container::XNameContainer > xPFamily;
+
+ if( EX_SHOW_DEFAULT_PAGE != m_nStyleFlags
+ && (aPFamily >>= xPFamily) && !sPageStyle.isEmpty() )
+ {
+ uno::Any aPStyle = xPFamily->getByName( sPageStyle );
+ uno::Reference< style::XStyle > xPStyle;
+ aPStyle >>= xPStyle;
+ uno::Reference< beans::XPropertySet > xPProp(xPStyle, uno::UNO_QUERY);
+ uno::Any aSize = xPProp->getPropertyValue(UNO_NAME_SIZE);
+ awt::Size aPSize;
+ aSize >>= aPSize;
+ //TODO: set page width to card width
+ aPSize.Width = 10000;
+ aSize <<= aPSize;
+ xPProp->setPropertyValue(UNO_NAME_SIZE, aSize);
+
+ uno::Any aZero; aZero <<= sal_Int32(0);
+ xPProp->setPropertyValue(UNO_NAME_LEFT_MARGIN, aZero);
+ xPProp->setPropertyValue(UNO_NAME_RIGHT_MARGIN, aZero);
+ }
+
+ uno::Reference<awt::XWindow> xWin = xFrame->getContainerWindow();
+ Size aWinSize(GetOutputSizePixel());
+ xWin->setPosSize(0, 0, aWinSize.Width(), aWinSize.Height(), awt::PosSize::SIZE);
+
+ // can only be done here - the SFX changes the ScrollBar values
+ disableScrollBars(xViewProps, (m_nStyleFlags&EX_SHOW_ONLINE_LAYOUT) != 0);
+
+ m_aInitializedLink.Call(*this);
+
+ uno::Reference< text::XTextViewCursorSupplier > xCursorSupp(m_xController, uno::UNO_QUERY);
+ uno::Reference< view::XScreenCursor > xScrCursor(xCursorSupp->getViewCursor(), uno::UNO_QUERY);
+ if(xScrCursor.is())
+ xScrCursor->screenUp();
+
+ if (pDoc)
+ {
+ SwEditShell* pSh = pDoc->GetEditShell();
+ if( pSh->ActionCount() )
+ {
+ pSh->EndAllAction();
+ pSh->UnlockPaint();
+ }
+ }
+
+ SW_MOD()->SetView(m_pModuleView);
+
+ Invalidate();
+ }
+ else
+ pTimer->Start();
+}
+
+void SwOneExampleFrame::ClearDocument()
+{
+ if( !m_xCursor )
+ return;
+
+ SwDoc* pDoc = m_xCursor->GetDoc();
+ SwEditShell* pSh = pDoc->GetEditShell();
+ pSh->LockPaint(LockPaintReason::ExampleFrame);
+ pSh->StartAllAction();
+ pSh->KillPams();
+ pSh->ClearMark();
+ pDoc->ClearDoc();
+ pSh->ClearUpCursors();
+
+ if( m_aLoadedIdle.IsActive())
+ {
+ pSh->EndAllAction();
+ pSh->UnlockPaint();
+ }
+ m_aLoadedIdle.Start();
+}
+
+bool SwOneExampleFrame::CreatePopup(const Point& rPt)
+{
+ if (EX_SHOW_ONLINE_LAYOUT != m_nStyleFlags)
+ return false;
+
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(nullptr, "modules/swriter/ui/previewmenu.ui"));
+ std::unique_ptr<weld::Menu> xPop(xBuilder->weld_menu("previewmenu"));
+
+ uno::Reference< view::XViewSettingsSupplier > xSettings(m_xController, uno::UNO_QUERY);
+ uno::Reference< beans::XPropertySet > xViewProps = xSettings->getViewSettings();
+
+ uno::Any aZoom = xViewProps->getPropertyValue(UNO_NAME_ZOOM_VALUE);
+ sal_Int16 nZoom = 0;
+ aZoom >>= nZoom;
+
+ for (auto const nZoomPreset : { 20, 40, 50, 75, 100 })
+ {
+ OUString sTemp = unicode::formatPercent(nZoomPreset,
+ Application::GetSettings().GetUILanguageTag());
+ OUString sIdent = "zoom" + OUString::number(nZoomPreset);
+ xPop->set_label(sIdent, sTemp);
+ if (nZoom == nZoomPreset)
+ xPop->set_active(sIdent, true);
+ }
+
+ PopupHdl(xPop->popup_at_rect(GetDrawingArea(), tools::Rectangle(rPt, Size(1, 1))));
+
+ return true;
+}
+
+void SwOneExampleFrame::PopupHdl(std::u16string_view rId)
+{
+ std::u16string_view sZoomValue;
+ if (o3tl::starts_with(rId, u"zoom", &sZoomValue))
+ {
+ sal_Int16 nZoom = o3tl::toInt32(sZoomValue);
+ uno::Reference< view::XViewSettingsSupplier > xSettings(m_xController, uno::UNO_QUERY);
+ uno::Reference< beans::XPropertySet > xViewProps = xSettings->getViewSettings();
+
+ uno::Any aZoom;
+ aZoom <<= nZoom;
+ xViewProps->setPropertyValue(UNO_NAME_ZOOM_VALUE, aZoom);
+ aZoom <<= sal_Int16(view::DocumentZoomType::BY_VALUE);
+ xViewProps->setPropertyValue(UNO_NAME_ZOOM_TYPE, aZoom);
+ }
+ Invalidate();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/utlui/viewlayoutctrl.cxx b/sw/source/uibase/utlui/viewlayoutctrl.cxx
new file mode 100644
index 0000000000..89dcc30175
--- /dev/null
+++ b/sw/source/uibase/utlui/viewlayoutctrl.cxx
@@ -0,0 +1,213 @@
+/* -*- 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 <viewlayoutctrl.hxx>
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+#include <comphelper/propertyvalue.hxx>
+#include <vcl/event.hxx>
+#include <vcl/status.hxx>
+#include <vcl/image.hxx>
+#include <svx/viewlayoutitem.hxx>
+#include <strings.hrc>
+#include <bitmaps.hlst>
+#include <swtypes.hxx>
+
+SFX_IMPL_STATUSBAR_CONTROL( SwViewLayoutControl, SvxViewLayoutItem );
+
+struct SwViewLayoutControl::SwViewLayoutControl_Impl
+{
+ sal_uInt16 mnState; // 0 = auto, 1= single, 2 = book, 3 = none, 4 = off
+ Image maImageSingleColumn;
+ Image maImageSingleColumn_Active;
+ Image maImageAutomatic;
+ Image maImageAutomatic_Active;
+ Image maImageBookMode;
+ Image maImageBookMode_Active;
+};
+
+SwViewLayoutControl::SwViewLayoutControl( sal_uInt16 _nSlotId, sal_uInt16 _nId, StatusBar& rStatusBar ) :
+ SfxStatusBarControl( _nSlotId, _nId, rStatusBar ),
+ mpImpl( new SwViewLayoutControl_Impl )
+{
+ mpImpl->mnState = 1;
+
+ mpImpl->maImageSingleColumn = Image(StockImage::Yes, RID_BMP_VIEWLAYOUT_SINGLECOLUMN);
+ mpImpl->maImageSingleColumn_Active = Image(StockImage::Yes, RID_BMP_VIEWLAYOUT_SINGLECOLUMN_ACTIVE);
+ mpImpl->maImageAutomatic = Image(StockImage::Yes, RID_BMP_VIEWLAYOUT_AUTOMATIC);
+ mpImpl->maImageAutomatic_Active = Image(StockImage::Yes, RID_BMP_VIEWLAYOUT_AUTOMATIC_ACTIVE);
+ mpImpl->maImageBookMode = Image(StockImage::Yes, RID_BMP_VIEWLAYOUT_BOOKMODE);
+ mpImpl->maImageBookMode_Active = Image(StockImage::Yes, RID_BMP_VIEWLAYOUT_BOOKMODE_ACTIVE);
+}
+
+SwViewLayoutControl::~SwViewLayoutControl()
+{
+}
+
+void SwViewLayoutControl::StateChangedAtStatusBarControl( sal_uInt16 /*nSID*/, SfxItemState eState, const SfxPoolItem* pState )
+{
+ if (SfxItemState::DEFAULT != eState || SfxItemState::DISABLED == eState)
+ {
+ GetStatusBar().SetItemText( GetId(), OUString() );
+ mpImpl->mnState = 4; //tdf#148441 switch off, if disabled
+ }
+ else
+ {
+ assert( dynamic_cast< const SvxViewLayoutItem *>( pState ) && "invalid item type" );
+ const sal_uInt16 nColumns = static_cast<const SvxViewLayoutItem*>( pState )->GetValue();
+ const bool bBookMode = static_cast<const SvxViewLayoutItem*>( pState )->IsBookMode();
+
+ // SingleColumn Mode
+ if ( 1 == nColumns )
+ mpImpl->mnState = 0;
+ // Automatic Mode
+ else if ( 0 == nColumns )
+ mpImpl->mnState = 1;
+ // Book Mode
+ else if ( bBookMode && 2 == nColumns )
+ mpImpl->mnState = 2;
+ else
+ mpImpl->mnState = 3;
+ }
+
+ GetStatusBar().SetItemData( GetId(), nullptr ); // force repaint
+}
+
+void SwViewLayoutControl::Paint( const UserDrawEvent& rUsrEvt )
+{
+ vcl::RenderContext* pDev = rUsrEvt.GetRenderContext();
+ tools::Rectangle aRect(rUsrEvt.GetRect());
+
+ const tools::Rectangle aControlRect = getControlRect();
+
+ if (mpImpl->mnState < 4)
+ {
+ const bool bSingleColumn = 0 == mpImpl->mnState;
+ const bool bAutomatic = 1 == mpImpl->mnState;
+ const bool bBookMode = 2 == mpImpl->mnState;
+ const int nDistance = 6;
+
+ const tools::Long nImageWidthSum = mpImpl->maImageSingleColumn.GetSizePixel().Width() +
+ mpImpl->maImageAutomatic.GetSizePixel().Width() +
+ mpImpl->maImageBookMode.GetSizePixel().Width();
+
+ const tools::Long nXOffset = (aRect.GetWidth() - nImageWidthSum - (2* nDistance)) / 2;
+ const tools::Long nYOffset = (aControlRect.GetHeight() - mpImpl->maImageSingleColumn.GetSizePixel().Height()) / 2;
+
+ aRect.AdjustLeft( nXOffset );
+ aRect.AdjustTop( nYOffset );
+
+ // draw single column image:
+ pDev->DrawImage( aRect.TopLeft(), bSingleColumn ? mpImpl->maImageSingleColumn_Active : mpImpl->maImageSingleColumn );
+
+ // draw automatic image:
+ aRect.AdjustLeft(mpImpl->maImageSingleColumn.GetSizePixel().Width() + nDistance);
+ pDev->DrawImage( aRect.TopLeft(), bAutomatic ? mpImpl->maImageAutomatic_Active : mpImpl->maImageAutomatic );
+
+ // draw bookmode image:
+ aRect.AdjustLeft(mpImpl->maImageAutomatic.GetSizePixel().Width() + nDistance);
+ pDev->DrawImage( aRect.TopLeft(), bBookMode ? mpImpl->maImageBookMode_Active : mpImpl->maImageBookMode );
+ }
+ else
+ {
+ pDev->DrawRect( aControlRect );
+ }
+}
+
+bool SwViewLayoutControl::MouseButtonDown( const MouseEvent & rEvt )
+{
+ if (mpImpl->mnState < 4)
+ {
+ const tools::Rectangle aRect = getControlRect();
+ const Point aPoint = rEvt.GetPosPixel();
+ const tools::Long nXDiff = aPoint.X() - aRect.Left();
+
+ sal_uInt16 nColumns = 1;
+ bool bBookMode = false;
+
+ const tools::Long nImageWidthSingle = mpImpl->maImageSingleColumn.GetSizePixel().Width();
+ const tools::Long nImageWidthAuto = mpImpl->maImageAutomatic.GetSizePixel().Width();
+ const tools::Long nImageWidthBook = mpImpl->maImageBookMode.GetSizePixel().Width();
+ const tools::Long nImageWidthSum = nImageWidthSingle + nImageWidthAuto + nImageWidthBook;
+
+ const tools::Long nXOffset = (aRect.GetWidth() - nImageWidthSum)/2;
+
+ if ( nXDiff < nXOffset + nImageWidthSingle )
+ {
+ mpImpl->mnState = 0; // single
+ nColumns = 1;
+ }
+ else if ( nXDiff < nXOffset + nImageWidthSingle + nImageWidthAuto )
+ {
+ mpImpl->mnState = 1; // auto
+ nColumns = 0;
+ }
+ else
+ {
+ mpImpl->mnState = 2; // book
+ nColumns = 2;
+ bBookMode = true;
+ }
+
+ // commit state change
+ SvxViewLayoutItem aViewLayout( nColumns, bBookMode );
+
+ css::uno::Any a;
+ aViewLayout.QueryValue( a );
+
+ css::uno::Sequence< css::beans::PropertyValue > aArgs{ comphelper::makePropertyValue("ViewLayout",
+ a) };
+ execute( aArgs );
+ }
+ return true;
+}
+
+bool SwViewLayoutControl::MouseMove( const MouseEvent & rEvt )
+{
+ if (mpImpl->mnState < 4)
+ {
+ const tools::Rectangle aRect = getControlRect();
+ const Point aPoint = rEvt.GetPosPixel();
+ const tools::Long nXDiff = aPoint.X() - aRect.Left();
+
+ const tools::Long nImageWidthSingle = mpImpl->maImageSingleColumn.GetSizePixel().Width();
+ const tools::Long nImageWidthAuto = mpImpl->maImageAutomatic.GetSizePixel().Width();
+ const tools::Long nImageWidthBook = mpImpl->maImageBookMode.GetSizePixel().Width();
+ const tools::Long nImageWidthSum = nImageWidthSingle + nImageWidthAuto + nImageWidthBook;
+
+ const tools::Long nXOffset = (aRect.GetWidth() - nImageWidthSum)/2;
+
+ if ( nXDiff < nXOffset + nImageWidthSingle )
+ {
+ GetStatusBar().SetQuickHelpText(GetId(), SwResId(STR_VIEWLAYOUT_ONE));
+ }
+ else if ( nXDiff < nXOffset + nImageWidthSingle + nImageWidthAuto )
+ {
+ GetStatusBar().SetQuickHelpText(GetId(), SwResId(STR_VIEWLAYOUT_MULTI));
+ }
+ else
+ {
+ GetStatusBar().SetQuickHelpText(GetId(), SwResId(STR_VIEWLAYOUT_BOOK));
+ }
+ }
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/utlui/wordcountctrl.cxx b/sw/source/uibase/utlui/wordcountctrl.cxx
new file mode 100644
index 0000000000..4185969189
--- /dev/null
+++ b/sw/source/uibase/utlui/wordcountctrl.cxx
@@ -0,0 +1,45 @@
+/* -*- 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/.
+ */
+
+#include <swtypes.hxx>
+#include <strings.hrc>
+#include <wordcountctrl.hxx>
+#include <svl/stritem.hxx>
+#include <vcl/status.hxx>
+
+SFX_IMPL_STATUSBAR_CONTROL(SwWordCountStatusBarControl, SfxStringItem);
+
+SwWordCountStatusBarControl::SwWordCountStatusBarControl(
+ sal_uInt16 _nSlotId,
+ sal_uInt16 _nId,
+ StatusBar& rStb) :
+ SfxStatusBarControl(_nSlotId, _nId, rStb)
+{
+}
+
+SwWordCountStatusBarControl::~SwWordCountStatusBarControl()
+{
+}
+
+void SwWordCountStatusBarControl::StateChangedAtStatusBarControl(
+ sal_uInt16 /*nSID*/, SfxItemState eState, const SfxPoolItem* pState )
+{
+ if (eState == SfxItemState::DEFAULT) // Can access pState
+ {
+ GetStatusBar().SetItemText( GetId(), static_cast<const SfxStringItem*>(pState)->GetValue() );
+ GetStatusBar().SetQuickHelpText(GetId(), SwResId(STR_WORDCOUNT_HINT));
+ }
+ else
+ {
+ GetStatusBar().SetItemText(GetId(), u""_ustr);
+ GetStatusBar().SetQuickHelpText(GetId(), u""_ustr);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/utlui/zoomctrl.cxx b/sw/source/uibase/utlui/zoomctrl.cxx
new file mode 100644
index 0000000000..4489432464
--- /dev/null
+++ b/sw/source/uibase/utlui/zoomctrl.cxx
@@ -0,0 +1,65 @@
+/* -*- 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 <vcl/status.hxx>
+#include <svl/stritem.hxx>
+#include <sfx2/zoomitem.hxx>
+
+#include <zoomctrl.hxx>
+
+SFX_IMPL_STATUSBAR_CONTROL( SwZoomControl, SvxZoomItem );
+
+SwZoomControl::SwZoomControl( sal_uInt16 _nSlotId,
+ sal_uInt16 _nId,
+ StatusBar& rStb ) :
+ SvxZoomStatusBarControl( _nSlotId, _nId, rStb )
+{
+}
+
+SwZoomControl::~SwZoomControl()
+{
+}
+
+void SwZoomControl::StateChangedAtStatusBarControl( sal_uInt16 nSID, SfxItemState eState,
+ const SfxPoolItem* pState )
+{
+ const SfxStringItem* pItem = nullptr;
+ if (SfxItemState::DEFAULT == eState && (pItem = dynamic_cast<const SfxStringItem*>(pState)))
+ {
+ m_sPreviewZoom = pItem->GetValue();
+ GetStatusBar().SetItemText(GetId(), m_sPreviewZoom);
+ }
+ else
+ {
+ m_sPreviewZoom.clear();
+ SvxZoomStatusBarControl::StateChangedAtStatusBarControl(nSID, eState, pState);
+ }
+}
+
+void SwZoomControl::Paint( const UserDrawEvent& )
+{
+}
+
+void SwZoomControl::Command( const CommandEvent& rCEvt )
+{
+ if (m_sPreviewZoom.isEmpty())
+ SvxZoomStatusBarControl::Command(rCEvt);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */