diff options
Diffstat (limited to '')
-rw-r--r-- | sw/source/uibase/utlui/attrdesc.cxx | 844 | ||||
-rw-r--r-- | sw/source/uibase/utlui/bookctrl.cxx | 141 | ||||
-rw-r--r-- | sw/source/uibase/utlui/condedit.cxx | 84 | ||||
-rw-r--r-- | sw/source/uibase/utlui/content.cxx | 4033 | ||||
-rw-r--r-- | sw/source/uibase/utlui/glbltree.cxx | 1088 | ||||
-rw-r--r-- | sw/source/uibase/utlui/gloslst.cxx | 441 | ||||
-rw-r--r-- | sw/source/uibase/utlui/gotodlg.cxx | 102 | ||||
-rw-r--r-- | sw/source/uibase/utlui/initui.cxx | 289 | ||||
-rw-r--r-- | sw/source/uibase/utlui/navicfg.cxx | 128 | ||||
-rw-r--r-- | sw/source/uibase/utlui/navipi.cxx | 1128 | ||||
-rw-r--r-- | sw/source/uibase/utlui/numfmtlb.cxx | 473 | ||||
-rw-r--r-- | sw/source/uibase/utlui/prcntfld.cxx | 228 | ||||
-rw-r--r-- | sw/source/uibase/utlui/shdwcrsr.cxx | 119 | ||||
-rw-r--r-- | sw/source/uibase/utlui/tmplctrl.cxx | 142 | ||||
-rw-r--r-- | sw/source/uibase/utlui/uiitems.cxx | 275 | ||||
-rw-r--r-- | sw/source/uibase/utlui/uitool.cxx | 848 | ||||
-rw-r--r-- | sw/source/uibase/utlui/unotools.cxx | 510 | ||||
-rw-r--r-- | sw/source/uibase/utlui/viewlayoutctrl.cxx | 197 | ||||
-rw-r--r-- | sw/source/uibase/utlui/wordcountctrl.cxx | 39 | ||||
-rw-r--r-- | sw/source/uibase/utlui/zoomctrl.cxx | 65 |
20 files changed, 11174 insertions, 0 deletions
diff --git a/sw/source/uibase/utlui/attrdesc.cxx b/sw/source/uibase/utlui/attrdesc.cxx new file mode 100644 index 000000000..a839c436f --- /dev/null +++ b/sw/source/uibase/utlui/attrdesc.cxx @@ -0,0 +1,844 @@ +/* -*- 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/GraphicObject.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() ) + { + 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 +{ + const char* 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 ) + + "(" + GetValue() + ")"; + else + rText = SwResId( STR_NUMRULE_OFF ); + return true; +} + +bool SwParaConnectBorderItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, + OUString& rText, + const IntlWrapper& /*rIntl*/ +) const +{ + const char* 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() ) + { + const char* 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 +{ + const char* 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 +{ + const char* 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 +{ + const char* pId = nullptr; + 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 +{ + const char* pId = nullptr; + 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 +{ + const char* pId = nullptr; + 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 +{ + const char* pId = nullptr; + 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_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 long nWdth = static_cast<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 +{ + xmlTextWriterStartElement(pWriter, BAD_CAST("SwFormatEditInReadonly")); + xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr())); + xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), BAD_CAST(OString::boolean(GetValue()).getStr())); + 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 +{ + const char* pId = nullptr; + + 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 +{ + const char* 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: pId = nullptr; 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( 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 ) + { + const char* 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: pId = nullptr; 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 ) + { + const char* 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 ) + { + const char* 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 ) + { + const char* pId = GetValue() ? STR_FOLLOW_TEXT_FLOW : STR_DONT_FOLLOW_TEXT_FLOW; + rText = SwResId(pId); + } + return true; +} + +void SwFormatFollowTextFlow::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + xmlTextWriterStartElement(pWriter, BAD_CAST("SwFormatFollowTextFlow")); + xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr())); + xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), BAD_CAST(OString::boolean(GetValue()).getStr())); + 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 000000000..ea9c1d742 --- /dev/null +++ b/sw/source/uibase/utlui/bookctrl.cxx @@ -0,0 +1,141 @@ +/* -*- 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 <strings.hrc> + +#include <svl/intitem.hxx> +#include <svl/stritem.hxx> +#include <svl/eitem.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/viewfrm.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/event.hxx> +#include <vcl/status.hxx> +#include <vcl/menu.hxx> +#include <cmdid.h> +#include <swmodule.hxx> +#include <wrtsh.hxx> +#include <IMark.hxx> +#include <bookctrl.hxx> +#include <map> + +SFX_IMPL_STATUSBAR_CONTROL( SwBookmarkControl, SfxStringItem ); + +namespace { + +class BookmarkPopup_Impl : public PopupMenu +{ +public: + BookmarkPopup_Impl(); + + sal_uInt16 GetCurId() const { return nCurId; } + +private: + sal_uInt16 nCurId; + + virtual void Select() override; +}; + +} + +BookmarkPopup_Impl::BookmarkPopup_Impl() : + PopupMenu(), + nCurId(USHRT_MAX) +{ +} + +void BookmarkPopup_Impl::Select() +{ + nCurId = GetCurItemId(); +} + +SwBookmarkControl::SwBookmarkControl( sal_uInt16 _nSlotId, + sal_uInt16 _nId, + StatusBar& rStb ) : + SfxStatusBarControl( _nSlotId, _nId, rStb ) +{ +} + +SwBookmarkControl::~SwBookmarkControl() +{ +} + +void SwBookmarkControl::StateChanged( + sal_uInt16 /*nSID*/, SfxItemState eState, const SfxPoolItem* pState ) +{ + if( eState != SfxItemState::DEFAULT || pState->IsVoidItem() ) + GetStatusBar().SetItemText( GetId(), OUString() ); + else if (const SfxStringItem* pStringItem = dynamic_cast<const SfxStringItem*>(pState)) + { + sPageNumber = pStringItem->GetValue(); + GetStatusBar().SetItemText(GetId(), sPageNumber); + } + else if (const SfxBoolItem* pBoolItem = dynamic_cast<const SfxBoolItem*>(pState)) + { + if (pBoolItem->GetValue()) // Indicates whether to show extended tooltip + GetStatusBar().SetQuickHelpText(GetId(), SwResId(STR_BOOKCTRL_HINT_EXTENDED)); + else + GetStatusBar().SetQuickHelpText(GetId(), SwResId(STR_BOOKCTRL_HINT)); + } + +} + +void SwBookmarkControl::Paint( const UserDrawEvent& ) +{ +} + +void SwBookmarkControl::Command( const CommandEvent& rCEvt ) +{ + if ( rCEvt.GetCommand() == CommandEventId::ContextMenu && + !GetStatusBar().GetItemText( GetId() ).isEmpty() ) + { + ScopedVclPtrInstance<BookmarkPopup_Impl> aPop; + SwWrtShell* pWrtShell = ::GetActiveWrtShell(); + if( pWrtShell && pWrtShell->getIDocumentMarkAccess()->getAllMarksCount() > 0 ) + { + IDocumentMarkAccess* const pMarkAccess = pWrtShell->getIDocumentMarkAccess(); + IDocumentMarkAccess::const_iterator_t ppBookmarkStart = pMarkAccess->getBookmarksBegin(); + sal_uInt16 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)) + { + aPop->InsertItem( nPopupId, (*ppBookmark)->GetName() ); + aBookmarkIdx[nPopupId] = static_cast<sal_uInt16>(ppBookmark - ppBookmarkStart); + nPopupId++; + } + } + aPop->Execute( &GetStatusBar(), rCEvt.GetMousePosPixel()); + sal_uInt16 nCurrId = aPop->GetCurId(); + if( nCurrId != USHRT_MAX) + { + SfxUInt16Item aBookmark( FN_STAT_BOOKMARK, aBookmarkIdx[nCurrId] ); + SfxViewFrame::Current()->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 000000000..df50c63ac --- /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) + , bBrackets(true) + , 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 000000000..4729818da --- /dev/null +++ b/sw/source/uibase/utlui/content.cxx @@ -0,0 +1,4033 @@ +/* -*- 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 <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 <vcl/commandevent.hxx> +#include <vcl/help.hxx> +#include <vcl/settings.hxx> +#include <vcl/weldutils.hxx> +#include <sot/formats.hxx> +#include <uiitems.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 <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 <dcontact.hxx> +#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 <navmgr.hxx> +#include <AnnotationWin.hxx> +#include <memory> + +#include <fmtcntnt.hxx> +#include <docstat.hxx> + +#define CTYPE_CNT 0 +#define CTYPE_CTT 1 + +using namespace ::std; +using namespace ::com::sun::star; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; + +namespace { + +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 +{ + bool lcl_IsContent(const weld::TreeIter& rEntry, const weld::TreeView& rTreeView) + { + return reinterpret_cast<const SwTypeNumber*>(rTreeView.get_id(rEntry).toInt64())->GetTypeId() == CTYPE_CNT; + } + + bool lcl_IsContentType(const weld::TreeIter& rEntry, const weld::TreeView& rTreeView) + { + return reinterpret_cast<const SwTypeNumber*>(rTreeView.get_id(rEntry).toInt64())->GetTypeId() == CTYPE_CTT; + } + + 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; + } + + size_t lcl_InsertURLFieldContent( + SwContentArr *pMember, + SwWrtShell* pWrtShell, + const SwContentType *pCntType) + { + SwGetINetAttrs aArr; + pWrtShell->GetINetAttrs( aArr ); + const SwGetINetAttrs::size_type nCount {aArr.size()}; + for( SwGetINetAttrs::size_type n = 0; n < nCount; ++n ) + { + SwGetINetAttr* p = &aArr[ n ]; + std::unique_ptr<SwURLFieldContent> pCnt(new SwURLFieldContent( + pCntType, + p->sText, + INetURLObject::decode( + p->rINetAttr.GetINetFormat().GetValue(), + INetURLObject::DecodeMechanism::Unambiguous ), + &p->rINetAttr, + n )); + pMember->insert( std::move(pCnt) ); + } + return nCount; + } +} + +// Content, contains names and reference at the content type. + +SwContent::SwContent(const SwContentType* pCnt, const OUString& rName, long nYPos) : + SwTypeNumber(CTYPE_CNT), + pParent(pCnt), + sContentName(rName), + nYPosition(nYPos), + bInvisible(false) +{ +} + + +SwTypeNumber::~SwTypeNumber() +{ +} + +bool SwContent::IsProtect() const +{ + return false; +} + +bool SwPostItContent::IsProtect() const +{ + return pField->IsProtect(); +} + +bool SwURLFieldContent::IsProtect() const +{ + return pINetAttr->IsProtect(); +} + +SwGraphicContent::~SwGraphicContent() +{ +} + +SwTOXBaseContent::~SwTOXBaseContent() +{ +} + +static const char* 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 +}; + +static const char* 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 +}; + +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; + } +} // 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) +{ + Init(); +} + +void SwContentType::Init(bool* pbInvalidateWindow) +{ + // if the MemberCount is changing ... + size_t nOldMemberCount = m_nMemberCount; + m_nMemberCount = 0; + switch(m_nContentType) + { + case ContentTypeId::OUTLINE : + { + m_sTypeToken = "outline"; + m_nMemberCount = m_pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineNodesCount(); + if (m_nMemberCount < MAXLEVEL) + { + const size_t nOutlineCount = m_nMemberCount; + for(size_t j = 0; j < nOutlineCount; ++j) + { + if (m_pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineLevel(j) > m_nOutlineLevel + || !m_pWrtShell->getIDocumentOutlineNodesAccess()->isOutlineInLayout(j, *m_pWrtShell->GetLayout())) + { + m_nMemberCount --; + } + } + } + } + break; + + case ContentTypeId::TABLE : + m_sTypeToken = "table"; + m_nMemberCount = m_pWrtShell->GetTableFrameFormatCount(true); + m_bEdit = true; + break; + + case ContentTypeId::FRAME : + case ContentTypeId::GRAPHIC : + case ContentTypeId::OLE : + { + FlyCntType eType = FLYCNTTYPE_FRM; + m_sTypeToken = "frame"; + if(m_nContentType == ContentTypeId::OLE) + { + eType = FLYCNTTYPE_OLE; + m_sTypeToken = "ole"; + } + else if(m_nContentType == ContentTypeId::GRAPHIC) + { + eType = FLYCNTTYPE_GRF; + m_sTypeToken = "graphic"; + } + m_nMemberCount = m_pWrtShell->GetFlyCount(eType, /*bIgnoreTextBoxes=*/true); + m_bEdit = true; + } + break; + case ContentTypeId::BOOKMARK: + { + IDocumentMarkAccess* const pMarkAccess = m_pWrtShell->getIDocumentMarkAccess(); + m_nMemberCount = count_if( + pMarkAccess->getBookmarksBegin(), + pMarkAccess->getBookmarksEnd(), + &lcl_IsUiVisibleBookmark); + m_sTypeToken.clear(); + const bool bProtectedBM = m_pWrtShell->getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_BOOKMARKS); + m_bEdit = !bProtectedBM; + m_bDelete = !bProtectedBM; + } + break; + case ContentTypeId::REGION : + { + std::unique_ptr<SwContentArr> pOldMember; + if(!m_pMember) + m_pMember.reset( new SwContentArr ); + else if(!m_pMember->empty()) + { + pOldMember = std::move(m_pMember); + m_pMember.reset( new SwContentArr ); + } + const Point aNullPt; + m_nMemberCount = m_pWrtShell->GetSectionFormatCount(); + for(size_t i = 0; i < m_nMemberCount; ++i) + { + const SwSectionFormat* pFormat; + SectionType eTmpType; + if( (pFormat = &m_pWrtShell->GetSectionFormat(i))->IsInNodesArr() && + (eTmpType = pFormat->GetSection()->GetType()) != SectionType::ToxContent + && SectionType::ToxHeader != eTmpType ) + { + const OUString& rSectionName = + pFormat->GetSection()->GetSectionName(); + sal_uInt8 nLevel = 0; + SwSectionFormat* pParentFormat = pFormat->GetParent(); + while(pParentFormat) + { + nLevel++; + pParentFormat = pParentFormat->GetParent(); + } + + std::unique_ptr<SwContent> pCnt(new SwRegionContent(this, rSectionName, + nLevel, + pFormat->FindLayoutRect( false, &aNullPt ).Top())); + + SwPtrMsgPoolItem aAskItem( RES_CONTENT_VISIBLE, nullptr ); + if( !pFormat->GetInfo( aAskItem ) && + !aAskItem.pObject ) // not visible + pCnt->SetInvisible(); + m_pMember->insert(std::move(pCnt)); + } + } + m_nMemberCount = m_pMember->size(); + m_sTypeToken = "region"; + m_bEdit = true; + m_bDelete = false; + if(pOldMember) + { + if(nullptr != pbInvalidateWindow) + { + // 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) + *pbInvalidateWindow = checkVisibilityChanged( + *pOldMember, + *m_pMember); + } + } + } + break; + case ContentTypeId::INDEX: + { + m_nMemberCount = m_pWrtShell->GetTOXCount(); + m_bEdit = true; + m_bDelete = false; + } + break; + case ContentTypeId::REFERENCE: + { + m_nMemberCount = m_pWrtShell->GetRefMarks(); + m_bDelete = false; + } + break; + case ContentTypeId::URLFIELD: + { + m_nMemberCount = 0; + if(!m_pMember) + m_pMember.reset( new SwContentArr ); + else + m_pMember->clear(); + + m_nMemberCount = lcl_InsertURLFieldContent(m_pMember.get(), m_pWrtShell, this); + + m_bEdit = true; + nOldMemberCount = m_nMemberCount; + m_bDelete = true; + } + break; + case ContentTypeId::POSTIT: + { + m_nMemberCount = 0; + if(!m_pMember) + m_pMember.reset( new SwContentArr ); + else + m_pMember->clear(); + + SwPostItMgr* aMgr = m_pWrtShell->GetView().GetPostItMgr(); + if (aMgr) + { + 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() && + (*i)->mLayoutStatus!=SwPostItHelper::INVISIBLE ) + { + OUString sEntry = pFormatField->GetField()->GetPar2(); + sEntry = RemoveNewline(sEntry); + std::unique_ptr<SwPostItContent> pCnt(new SwPostItContent( + this, + sEntry, + pFormatField, + m_nMemberCount)); + m_pMember->insert(std::move(pCnt)); + m_nMemberCount++; + } + } + } + } + m_sTypeToken.clear(); + m_bEdit = true; + nOldMemberCount = m_nMemberCount; + } + break; + case ContentTypeId::DRAWOBJECT: + { + m_sTypeToken.clear(); + m_bEdit = true; + m_nMemberCount = 0; + SwDrawModel* pModel = m_pWrtShell->getIDocumentDrawModelAccess().GetDrawModel(); + if(pModel) + { + SdrPage* pPage = pModel->GetPage(0); + const size_t nCount = pPage->GetObjCount(); + for( size_t i=0; i<nCount; ++i ) + { + SdrObject* pTemp = pPage->GetObj(i); + // #i51726# - all drawing objects can be named now + if (!pTemp->GetName().isEmpty()) + m_nMemberCount++; + } + } + } + break; + default: break; + } + // ... then, the data can also no longer be valid, + // apart from those which have already been corrected, + // then nOldMemberCount is nevertheless not so old. + if( nOldMemberCount != m_nMemberCount ) + m_bDataValid = false; +} + +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* pbLevelOrVisibilityChanged) +{ + std::unique_ptr<SwContentArr> pOldMember; + size_t nOldMemberCount = 0; + SwPtrMsgPoolItem aAskItem( RES_CONTENT_VISIBLE, nullptr ); + if(m_pMember && pbLevelOrVisibilityChanged) + { + pOldMember = std::move(m_pMember); + nOldMemberCount = pOldMember->size(); + m_pMember.reset( new SwContentArr ); + *pbLevelOrVisibilityChanged = false; + } + else if(!m_pMember) + m_pMember.reset( new SwContentArr ); + else + m_pMember->clear(); + switch(m_nContentType) + { + case ContentTypeId::OUTLINE : + { + const size_t nOutlineCount = m_nMemberCount = + m_pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineNodesCount(); + + size_t nPos = 0; + for (size_t i = 0; i < nOutlineCount; ++i) + { + const sal_uInt8 nLevel = m_pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineLevel(i); + if(nLevel >= m_nOutlineLevel ) + m_nMemberCount--; + else + { + if (!m_pWrtShell->getIDocumentOutlineNodesAccess()->isOutlineInLayout(i, *m_pWrtShell->GetLayout())) + { + --m_nMemberCount; + continue; // don't hide it, just skip it + } + OUString aEntry(comphelper::string::stripStart( + m_pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineText(i, m_pWrtShell->GetLayout()), ' ')); + aEntry = SwNavigationPI::CleanEntry(aEntry); + std::unique_ptr<SwOutlineContent> pCnt(new SwOutlineContent(this, aEntry, i, nLevel, + m_pWrtShell->IsOutlineMovable( i ), nPos )); + m_pMember->insert(std::move(pCnt)); + // with the same number and existing "pOldMember" the + // old one is compared with the new OutlinePos. + if (nOldMemberCount > nPos && static_cast<SwOutlineContent*>((*pOldMember)[nPos].get())->GetOutlineLevel() != nLevel) + *pbLevelOrVisibilityChanged = true; + + nPos++; + } + } + + } + break; + + case ContentTypeId::TABLE : + { + const size_t nCount = m_pWrtShell->GetTableFrameFormatCount(true); + OSL_ENSURE(m_nMemberCount == nCount, "MemberCount differs"); + Point aNullPt; + m_nMemberCount = nCount; + for(size_t i = 0; i < m_nMemberCount; ++i) + { + const SwFrameFormat& rTableFormat = m_pWrtShell->GetTableFrameFormat(i, true); + const OUString& sTableName( rTableFormat.GetName() ); + + SwContent* pCnt = new SwContent(this, sTableName, + rTableFormat.FindLayoutRect(false, &aNullPt).Top() ); + if( !rTableFormat.GetInfo( aAskItem ) && + !aAskItem.pObject ) // not visible + pCnt->SetInvisible(); + + m_pMember->insert(std::unique_ptr<SwContent>(pCnt)); + + if(nOldMemberCount > i && + (*pOldMember)[i]->IsInvisible() != pCnt->IsInvisible()) + *pbLevelOrVisibilityChanged = true; + } + } + 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; + m_nMemberCount = m_pWrtShell->GetFlyCount(eType, /*bIgnoreTextBoxes=*/true); + std::vector<SwFrameFormat const*> formats(m_pWrtShell->GetFlyFrameFormats(eType, /*bIgnoreTextBoxes=*/true)); + SAL_WARN_IF(m_nMemberCount != formats.size(), "sw.ui", "MemberCount differs"); + m_nMemberCount = formats.size(); + for (size_t i = 0; i < m_nMemberCount; ++i) + { + SwFrameFormat const*const pFrameFormat = formats[i]; + const OUString sFrameName = pFrameFormat->GetName(); + + SwContent* pCnt; + 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 ), + pFrameFormat->FindLayoutRect(false, &aNullPt).Top()); + } + else + { + pCnt = new SwContent(this, sFrameName, + pFrameFormat->FindLayoutRect(false, &aNullPt).Top() ); + } + if( !pFrameFormat->GetInfo( aAskItem ) && + !aAskItem.pObject ) // not visible + pCnt->SetInvisible(); + m_pMember->insert(std::unique_ptr<SwContent>(pCnt)); + if (nOldMemberCount > i && + (*pOldMember)[i]->IsInvisible() != pCnt->IsInvisible()) + *pbLevelOrVisibilityChanged = true; + } + } + break; + case ContentTypeId::BOOKMARK: + { + 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 + std::unique_ptr<SwContent> pCnt(new SwContent(this, rBkmName, 0)); + m_pMember->insert(std::move(pCnt)); + } + } + } + break; + case ContentTypeId::REGION : + { + const Point aNullPt; + m_nMemberCount = m_pWrtShell->GetSectionFormatCount(); + for(size_t i = 0; i < m_nMemberCount; ++i) + { + const SwSectionFormat* pFormat; + SectionType eTmpType; + if( (pFormat = &m_pWrtShell->GetSectionFormat(i))->IsInNodesArr() && + (eTmpType = pFormat->GetSection()->GetType()) != SectionType::ToxContent + && SectionType::ToxHeader != eTmpType ) + { + OUString sSectionName = pFormat->GetSection()->GetSectionName(); + + sal_uInt8 nLevel = 0; + SwSectionFormat* pParentFormat = pFormat->GetParent(); + while(pParentFormat) + { + nLevel++; + pParentFormat = pParentFormat->GetParent(); + } + + std::unique_ptr<SwContent> pCnt(new SwRegionContent(this, sSectionName, + nLevel, + pFormat->FindLayoutRect( false, &aNullPt ).Top())); + if( !pFormat->GetInfo( aAskItem ) && + !aAskItem.pObject ) // not visible + pCnt->SetInvisible(); + m_pMember->insert(std::move(pCnt)); + } + + if(nullptr != pbLevelOrVisibilityChanged) + { + assert(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) + *pbLevelOrVisibilityChanged = checkVisibilityChanged( + *pOldMember, + *m_pMember); + } + } + m_nMemberCount = m_pMember->size(); + } + break; + case ContentTypeId::REFERENCE: + { + std::vector<OUString> aRefMarks; + m_nMemberCount = m_pWrtShell->GetRefMarks( &aRefMarks ); + + for (const auto& rRefMark : aRefMarks) + { + // References sorted alphabetically + m_pMember->insert(std::make_unique<SwContent>(this, rRefMark, 0)); + } + } + break; + case ContentTypeId::URLFIELD: + m_nMemberCount = lcl_InsertURLFieldContent(m_pMember.get(), m_pWrtShell, this); + break; + case ContentTypeId::INDEX: + { + + const sal_uInt16 nCount = m_pWrtShell->GetTOXCount(); + m_nMemberCount = nCount; + 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, nTox, *pBase); + + if( !pBase->GetInfo( aAskItem ) && + !aAskItem.pObject ) // not visible + pCnt->SetInvisible(); + + m_pMember->insert( std::unique_ptr<SwContent>(pCnt) ); + const size_t nPos = m_pMember->size() - 1; + if(nOldMemberCount > nPos && + (*pOldMember)[nPos]->IsInvisible() + != pCnt->IsInvisible()) + *pbLevelOrVisibilityChanged = true; + } + } + break; + case ContentTypeId::POSTIT: + { + m_nMemberCount = 0; + m_pMember->clear(); + SwPostItMgr* aMgr = m_pWrtShell->GetView().GetPostItMgr(); + if (aMgr) + { + 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() && + (*i)->mLayoutStatus!=SwPostItHelper::INVISIBLE ) + { + OUString sEntry = pFormatField->GetField()->GetPar2(); + sEntry = RemoveNewline(sEntry); + std::unique_ptr<SwPostItContent> pCnt(new SwPostItContent( + this, + sEntry, + pFormatField, + m_nMemberCount)); + m_pMember->insert(std::move(pCnt)); + m_nMemberCount++; + } + } + } + } + } + break; + case ContentTypeId::DRAWOBJECT: + { + m_nMemberCount = 0; + m_pMember->clear(); + + IDocumentDrawModelAccess& rIDDMA = m_pWrtShell->getIDocumentDrawModelAccess(); + SwDrawModel* pModel = rIDDMA.GetDrawModel(); + if(pModel) + { + SdrPage* pPage = pModel->GetPage(0); + const size_t nCount = pPage->GetObjCount(); + for( size_t i=0; i<nCount; ++i ) + { + SdrObject* pTemp = pPage->GetObj(i); + // #i51726# - all drawing objects can be named now + if (!pTemp->GetName().isEmpty()) + { + SwContact* pContact = static_cast<SwContact*>(pTemp->GetUserCall()); + long nYPos = 0; + const Point aNullPt; + if(pContact && pContact->GetFormat()) + nYPos = pContact->GetFormat()->FindLayoutRect(false, &aNullPt).Top(); + SwContent* pCnt = new SwContent( + this, + pTemp->GetName(), + nYPos); + if(!rIDDMA.IsVisibleLayerId(pTemp->GetLayer())) + pCnt->SetInvisible(); + m_pMember->insert(std::unique_ptr<SwContent>(pCnt)); + m_nMemberCount++; + if (nOldMemberCount > i && + (*pOldMember)[i]->IsInvisible() != pCnt->IsInvisible() ) + *pbLevelOrVisibilityChanged = true; + } + } + } + } + break; + default: break; + } + 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 +}; + +} + +static const char* 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_xDialog(pDialog) + , m_sSpace(OUString(" ")) + , 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) +{ + Size aSize(m_xDialog->LogicToPixel(Size(110, 112), MapMode(MapUnit::MapAppFont))); + m_xTreeView->set_size_request(aSize.Width(), aSize.Height()); + + 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, FocusHdl)); + 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)); + + for (ContentTypeId i : o3tl::enumrange<ContentTypeId>()) + { + 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(); + m_aUpdTimer.SetInvokeHandler(LINK(this, SwContentTree, TimerUpdate)); + m_aUpdTimer.SetTimeout(1000); +} + +SwContentTree::~SwContentTree() +{ + clear(); // If applicable erase content types previously. + m_aUpdTimer.Stop(); + SetActiveShell(nullptr); + m_xDialog.clear(); +} + +// 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); + } + + return nAccept; +} + +bool SwContentTree::IsInDrag() const +{ + return m_xTreeView->get_drag_source() == m_xTreeView.get(); +} + +// 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())) + xDropEntry.reset(); + + if (m_nRootType == ContentTypeId::OUTLINE) + { + if (xDropEntry && lcl_IsContent(*xDropEntry, *m_xTreeView)) + { + assert(dynamic_cast<SwContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xDropEntry).toInt64()))); + SwOutlineContent* pOutlineContent = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xDropEntry).toInt64()); + 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*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xDropEntry).toInt64()))); + nTargetPos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xDropEntry).toInt64())->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*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xNext).toInt64()))); + nTargetPos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xNext).toInt64())->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(weld::TreeView& rContentTree, weld::TreeIter& rEntry, weld::Menu& rPop) +{ + if (rContentTree.iter_has_child(rEntry) || rContentTree.get_children_on_demand(rEntry)) + { + rPop.set_label(OString::number(800), IsAllExpanded(rContentTree, rEntry) ? SwResId(STR_COLLAPSEALL) : SwResId(STR_EXPANDALL)); + return false; + } + return true; +} + +IMPL_LINK(SwContentTree, CommandHdl, const CommandEvent&, rCEvt, bool) +{ + if (rCEvt.GetCommand() != CommandEventId::ContextMenu) + return false; + + 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"); + + for(int i = 1; i <= 3; ++i) + xSubPopOutlineTracking->append_radio(OUString::number(i + 10), m_aContextStrings[IDX_STR_OUTLINE_TRACKING + i]); + xSubPopOutlineTracking->set_active(OString::number(10 + m_nOutlineTracking), true); + + for (int i = 1; i <= MAXLEVEL; ++i) + xSubPop1->append_radio(OUString::number(i + 100), OUString::number(i)); + xSubPop1->set_active(OString::number(100 + m_nOutlineLevel), true); + + for (int i=0; i < 3; ++i) + xSubPop2->append_radio(OUString::number(i + 201), m_aContextStrings[IDX_STR_HYPERLINK + i]); + xSubPop2->set_active(OString::number(201 + static_cast<int>(GetParentWindow()->GetRegionDropMode())), true); + + // Insert the list of the open files + sal_uInt16 nId = 301; + const SwView* pActiveView = ::GetActiveView(); + SwView *pView = SwModule::GetFirstView(); + while (pView) + { + OUString sInsert = pView->GetDocShell()->GetTitle(); + if (pView == pActiveView) + { + sInsert += "(" + + m_aContextStrings[IDX_STR_ACTIVE] + + ")"; + } + xSubPop3->append_radio(OUString::number(nId), sInsert); + if (State::CONSTANT == m_eState && m_pActiveShell == &pView->GetWrtShell()) + xSubPop3->set_active(OString::number(nId), true); + pView = SwModule::GetNextView(pView); + nId++; + } + xSubPop3->append_radio(OUString::number(nId++), m_aContextStrings[IDX_STR_ACTIVE_VIEW]); + if (m_pHiddenShell) + { + OUString sHiddenEntry = m_pHiddenShell->GetView().GetDocShell()->GetTitle() + + " ( " + + m_aContextStrings[IDX_STR_HIDDEN] + + " )"; + xSubPop3->append_radio(OUString::number(nId), sHiddenEntry); + } + + if (State::ACTIVE == m_eState) + xSubPop3->set_active(OString::number(--nId), true); + else if (State::HIDDEN == m_eState) + xSubPop3->set_active(OString::number(nId), true); + + std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator()); + if (!m_xTreeView->get_selected(xEntry.get())) + xEntry.reset(); + + if (!xEntry || !lcl_IsContent(*xEntry, *m_xTreeView)) + xPop->remove(OString::number(900)); // go to + + bool bRemovePostItEntries = true; + bool bRemoveIndexEntries = true; + bool bRemoveEditEntry = true; + bool bRemoveUnprotectEntry = true; + bool bRemoveDeleteEntry = true; + bool bRemoveRenameEntry = true; + bool bRemoveSelectEntry = true; + bool bRemoveToggleExpandEntry = true; + bool bRemoveChapterEntries = true; + bool bRemoveSendOutlineEntry = true; + + // Edit only if the shown content is coming from the current view. + if ((State::ACTIVE == m_eState || m_pActiveShell == pActiveView->GetWrtShellPtr()) + && xEntry && lcl_IsContent(*xEntry, *m_xTreeView)) + { + assert(dynamic_cast<SwContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64()))); + const SwContentType* pContType = reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetParent(); + const ContentTypeId nContentType = pContType->GetType(); + const bool bReadonly = m_pActiveShell->GetView().GetDocShell()->IsReadOnly(); + const bool bVisible = !reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xEntry).toInt64())->IsInvisible(); + const bool bProtected = reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xEntry).toInt64())->IsProtect(); + const bool bProtectBM = (ContentTypeId::BOOKMARK == nContentType) + && m_pActiveShell->getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_BOOKMARKS); + const bool bEditable = pContType->IsEditable() && + ((bVisible && !bProtected && !bProtectBM) || ContentTypeId::REGION == nContentType); + const bool bDeletable = pContType->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); + + if (!bReadonly && (bEditable || bDeletable)) + { + if(ContentTypeId::INDEX == nContentType) + { + bRemoveIndexEntries = false; + + const SwTOXBase* pBase = reinterpret_cast<SwTOXBaseContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetTOXBase(); + if (!pBase->IsTOXBaseInReadonly()) + bRemoveEditEntry = false; + + xPop->set_active(OString::number(405), SwEditShell::IsTOXBaseReadonly(*pBase)); + bRemoveDeleteEntry = false; + } + else if(ContentTypeId::TABLE == nContentType) + { + bRemoveSelectEntry = false; + bRemoveEditEntry = false; + bRemoveUnprotectEntry = false; + bool bFull = false; + OUString sTableName = reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetName(); + bool bProt = m_pActiveShell->HasTableAnyProtection( &sTableName, &bFull ); + xPop->set_sensitive(OString::number(403), !bFull); + xPop->set_sensitive(OString::number(404), bProt); + bRemoveDeleteEntry = false; + } + else if(ContentTypeId::OUTLINE == nContentType) + { + bOutline = true; + bRemoveToggleExpandEntry = lcl_InsertExpandCollapseAllItem(*m_xTreeView, *xEntry, *xPop); + bRemoveSelectEntry = false; + bRemoveChapterEntries = false; + } + else if(ContentTypeId::DRAWOBJECT == nContentType) + { + bRemoveDeleteEntry = false; + } + else if(ContentTypeId::REGION == nContentType) + { + bRemoveSelectEntry = false; + bRemoveEditEntry = false; + } + else + { + if (bEditable && bDeletable) + { + bRemoveEditEntry = false; + bRemoveDeleteEntry = false; + } + else if (bEditable) + bRemoveEditEntry = false; + else if (bDeletable) + { + bRemoveDeleteEntry = false; + } + } + //Rename object + if (bRenamable) + bRemoveRenameEntry = false; + } + } + else if (xEntry) + { + assert(dynamic_cast<SwContentType*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64()))); + SwContentType* pType = reinterpret_cast<SwContentType*>(m_xTreeView->get_id(*xEntry).toInt64()); + if (ContentTypeId::OUTLINE == pType->GetType()) + { + bOutline = true; + bRemoveToggleExpandEntry = lcl_InsertExpandCollapseAllItem(*m_xTreeView, *xEntry, *xPop); + bRemoveSendOutlineEntry = false; + } + if ( (pType->GetType() == ContentTypeId::POSTIT) && (!m_pActiveShell->GetView().GetDocShell()->IsReadOnly()) && ( pType->GetMemberCount() > 0) ) + bRemovePostItEntries = false; + } + + if (bRemoveToggleExpandEntry) + { + xPop->remove("separator3"); + xPop->remove(OString::number(800)); + } + + if (bRemoveSelectEntry) + xPop->remove(OString::number(805)); + + if (bRemoveChapterEntries) + { + xPop->remove("separator2"); + xPop->remove(OString::number(806)); + xPop->remove(OString::number(801)); + xPop->remove(OString::number(802)); + xPop->remove(OString::number(803)); + xPop->remove(OString::number(804)); + } + + if (bRemoveSendOutlineEntry) + xPop->remove(OString::number(700)); + + if (bRemovePostItEntries) + { + xPop->remove(OString::number(600)); + xPop->remove(OString::number(601)); + xPop->remove(OString::number(602)); + } + + if (bRemoveDeleteEntry) + xPop->remove(OString::number(501)); + + if (bRemoveRenameEntry) + xPop->remove(OString::number(502)); + + if (bRemoveIndexEntries) + { + xPop->remove(OString::number(401)); + xPop->remove(OString::number(402)); + xPop->remove(OString::number(405)); + } + + if (bRemoveUnprotectEntry) + xPop->remove(OString::number(404)); + + if (bRemoveEditEntry) + xPop->remove(OString::number(403)); + + if (bRemoveToggleExpandEntry && + bRemoveSelectEntry && + bRemoveChapterEntries && + bRemoveSendOutlineEntry && + bRemovePostItEntries && + bRemoveDeleteEntry && + bRemoveRenameEntry && + bRemoveIndexEntries && + bRemoveUnprotectEntry && + bRemoveEditEntry) + { + xPop->remove("separator1"); + } + + if (!bOutline) + { + xSubPop1.reset(); + xPop->remove(OString::number(1)); // outline level menu + xSubPopOutlineTracking.reset(); + xPop->remove(OString::number(4)); // outline tracking menu + } + + OString sCommand = xPop->popup_at_rect(m_xTreeView.get(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1))); + if (!sCommand.isEmpty()) + ExecuteContextMenuAction(sCommand); + + return true; +} + +void SwContentTree::insert(const weld::TreeIter* pParent, const OUString& rStr, const OUString& rId, + const OUString* pExpanderName, bool bChildrenOnDemand, weld::TreeIter* pRet) +{ + m_xTreeView->insert(pParent, -1, &rStr, &rId, nullptr, nullptr, pExpanderName, 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) +{ + bool bChild = m_xTreeView->iter_has_child(rParent); + if (bChild || !m_xTreeView->get_children_on_demand(rParent)) + return bChild; + + // 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*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(rParent).toInt64()))); + SwContentType* pCntType = reinterpret_cast<SwContentType*>(m_xTreeView->get_id(rParent).toInt64()); + + const size_t nCount = pCntType->GetMemberCount(); + // Add for outline plus/minus + if (pCntType->GetType() == ContentTypeId::OUTLINE) + { + 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(OUString::number(reinterpret_cast<sal_Int64>(pCnt))); + if (!bChild || (nLevel == 0)) + { + insert(&rParent, sEntry, sId, nullptr, 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)); + bChild = true; + } + else + { + //back search parent. + if(static_cast<const SwOutlineContent*>(pCntType->GetMember(i-1))->GetOutlineLevel() < nLevel) + { + insert(xChild.get(), sEntry, sId, nullptr, 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)); + bChild = true; + } + else + { + bChild = m_xTreeView->iter_previous(*xChild); + assert(!bChild || lcl_IsContentType(*xChild, *m_xTreeView) || dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xChild).toInt64()))); + while (bChild && + lcl_IsContent(*xChild, *m_xTreeView) && + (reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xChild).toInt64())->GetOutlineLevel() >= nLevel) + ) + { + bChild = m_xTreeView->iter_previous(*xChild); + } + if (bChild) + { + insert(xChild.get(), sEntry, sId, nullptr, 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)); + } + } + } + } + } + } + else + { + bool bRegion = pCntType->GetType() == ContentTypeId::REGION; + for(size_t i = 0; i < nCount; ++i) + { + const SwContent* pCnt = pCntType->GetMember(i); + if (pCnt) + { + OUString sEntry = pCnt->GetName(); + if (sEntry.isEmpty()) + sEntry = m_sSpace; + OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pCnt))); + insert(&rParent, sEntry, sId, nullptr, false, xChild.get()); + m_xTreeView->set_sensitive(*xChild, !pCnt->IsInvisible()); + if (bRegion) + m_xTreeView->set_extra_row_indent(*xChild, static_cast<const SwRegionContent*>(pCnt)->GetRegionLevel()); + bChild = true; + } + } + } + } + + return bChild; +} + +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); + const size_t nCount = pPage->GetObjCount(); + + for( size_t i=0; i<nCount; ++i ) + { + SdrObject* pTemp = pPage->GetObj(i); + if( pTemp->GetName() == pCnt->GetName()) + { + pRetObj = pTemp; + 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; + + if (!m_bIsRoot + || (lcl_IsContentType(rParent, *m_xTreeView) && + reinterpret_cast<SwContentType*>(m_xTreeView->get_id(rParent).toInt64())->GetType() == ContentTypeId::OUTLINE) + || (m_nRootType == ContentTypeId::OUTLINE)) + { + if (lcl_IsContentType(rParent, *m_xTreeView)) + { + SwContentType* pCntType = reinterpret_cast<SwContentType*>(m_xTreeView->get_id(rParent).toInt64()); + const sal_Int32 nOr = 1 << static_cast<int>(pCntType->GetType()); //linear -> Bitposition + if (State::HIDDEN != m_eState) + { + m_nActiveBlock |= nOr; + m_pConfig->SetActiveBlock(m_nActiveBlock); + } + else + m_nHiddenBlock |= nOr; + if (pCntType->GetType() == ContentTypeId::OUTLINE) + { + std::map< void*, bool > aCurrOutLineNodeMap; + + SwWrtShell* pShell = GetWrtShell(); + bool bParentHasChild = RequestingChildren(rParent); + if (pNodesToExpand) + pNodesToExpand->emplace_back(m_xTreeView->make_iterator(&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*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xChild).toInt64()))); + auto const nPos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xChild).toInt64())->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 + { + if (lcl_IsContent(rParent, *m_xTreeView)) + { + SwWrtShell* pShell = GetWrtShell(); + // paranoid assert now that outline type is checked + assert(dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(rParent).toInt64()))); + auto const nPos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(rParent).toInt64())->GetOutlinePos(); + void* key = static_cast<void*>(pShell->getIDocumentOutlineNodesAccess()->getOutlineNode( nPos )); + mOutLineNodeMap[key] = true; + } + } + } + + RequestingChildren(rParent); + if (pNodesToExpand) + pNodesToExpand->emplace_back(m_xTreeView->make_iterator(&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 + } + SwContentType* pCntType = reinterpret_cast<SwContentType*>(m_xTreeView->get_id(rParent).toInt64()); + const sal_Int32 nAnd = ~(1 << static_cast<int>(pCntType->GetType())); + if (State::HIDDEN != m_eState) + { + m_nActiveBlock &= nAnd; + m_pConfig->SetActiveBlock(m_nActiveBlock); + } + else + m_nHiddenBlock &= nAnd; + } + else if (lcl_IsContent(rParent, *m_xTreeView)) + { + SwWrtShell* pShell = GetWrtShell(); + assert(dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(rParent).toInt64()))); + auto const nPos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(rParent).toInt64())->GetOutlinePos(); + void* key = static_cast<void*>(pShell->getIDocumentOutlineNodesAccess()->getOutlineNode( nPos )); + mOutLineNodeMap[key] = false; + } + + return true; +} + +// Also on double click will be initially opened only. +IMPL_LINK_NOARG(SwContentTree, ContentDoubleClickHdl, weld::TreeView&, bool) +{ + bool bConsumed = false; + + 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)) + { + if (State::CONSTANT == m_eState) + { + m_pActiveShell->GetView().GetViewFrame()->GetWindow().ToTop(); + } + //Jump to content type: + assert(dynamic_cast<SwContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64()))); + SwContent* pCnt = reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xEntry).toInt64()); + assert(pCnt && "no UserData"); + GotoContent(pCnt); + const ContentTypeId nActType = pCnt->GetParent()->GetType(); + if (nActType == ContentTypeId::FRAME) + m_pActiveShell->EnterStdMode(); + // fdo#36308 don't expand outlines on double-click + bConsumed = nActType == ContentTypeId::OUTLINE; + } + } + + return bConsumed; // false/true == allow/disallow more to be done, i.e. expand/collapse children +} + +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::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 sEntryName; // Name of the entry + size_t nEntryRelPos = 0; // relative position to their parent + size_t nOldEntryCount = GetEntryCount(); + sal_Int32 nOldScrollPos = 0; + if (xOldSelEntry) + { + UpdateLastSelType(); + + nOldScrollPos = m_xTreeView->vadjustment_get_value(); + sEntryName = m_xTreeView->get_text(*xOldSelEntry); + 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_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_xContent3ToolBox->set_item_sensitive("chapterup", !bDisable); + pNavi->m_xContent3ToolBox->set_item_sensitive("chapterdown", !bDisable); + pNavi->m_xContent3ToolBox->set_item_sensitive("promote", !bDisable); + pNavi->m_xContent3ToolBox->set_item_sensitive("demote", !bDisable); + pNavi->m_xContent2ToolBox->set_item_sensitive("reminder", !bDisable); + } + + if (pShell) + { + std::unique_ptr<weld::TreeIter> xEntry = m_xTreeView->make_iterator(); + std::unique_ptr<weld::TreeIter> xSelEntry; + // all content navigation view + if(m_nRootType == ContentTypeId::UNKNOWN) + { + m_xTreeView->freeze(); + + std::vector<std::unique_ptr<weld::TreeIter>> aNodesToExpand; + + 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 sEntry = rpContentT->GetName(); + OUString aImage(GetImageIdForContentTypeId(nCntType)); + bool bChOnDemand = 0 != rpContentT->GetMemberCount(); + OUString sId(OUString::number(reinterpret_cast<sal_Int64>(rpContentT.get()))); + insert(nullptr, sEntry, sId, &aImage, bChOnDemand, xEntry.get()); + + m_xTreeView->set_sensitive(*xEntry, bChOnDemand); + + if (nCntType == m_nLastSelType) + xSelEntry = 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); + + (void)m_xTreeView->get_iter_first(*xEntry); + for (ContentTypeId nCntType : o3tl::enumrange<ContentTypeId>()) + { + sal_Int32 nExpandOptions = (State::HIDDEN == m_eState) + ? m_nHiddenBlock + : m_nActiveBlock; + if (nExpandOptions & (1 << static_cast<int>(nCntType))) + { + if (nEntryRelPos && nCntType == m_nLastSelType) + { + // reselect the entry + std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(xEntry.get())); + std::unique_ptr<weld::TreeIter> xTemp; + sal_uLong nPos = 1; + while (m_xTreeView->iter_next(*xChild)) + { + // The old text will be slightly favored + if (sEntryName == m_xTreeView->get_text(*xChild) || + nPos == nEntryRelPos) + { + m_xTreeView->copy_iterator(*xChild, *xSelEntry); + break; + } + xTemp = m_xTreeView->make_iterator(xChild.get()); + nPos++; + } + if (!xSelEntry || lcl_IsContentType(*xSelEntry, *m_xTreeView)) + xSelEntry = std::move(xTemp); + } + } + + (void)m_xTreeView->iter_next_sibling(*xEntry); + } + + if (!xSelEntry) + { + nOldScrollPos = 0; + xSelEntry = m_xTreeView->make_iterator(); + if (!m_xTreeView->get_iter_first(*xSelEntry)) + xSelEntry.reset(); + } + + if (xSelEntry) + { + m_xTreeView->set_cursor(*xSelEntry); + Select(); + } + } + // 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; + OUString sId(OUString::number(reinterpret_cast<sal_Int64>(rpRootContentT.get()))); + insert(nullptr, rpRootContentT->GetName(), sId, &aImage, bChOnDemand, xEntry.get()); + + if (!bChOnDemand) + { + bool bRegion = rpRootContentT->GetType() == ContentTypeId::REGION; + + std::unique_ptr<weld::TreeIter> xChild = m_xTreeView->make_iterator(); + for (size_t i = 0; i < rpRootContentT->GetMemberCount(); ++i) + { + const SwContent* pCnt = rpRootContentT->GetMember(i); + if (pCnt) + { + OUString sEntry = pCnt->GetName(); + if(sEntry.isEmpty()) + sEntry = m_sSpace; + OUString sSubId(OUString::number(reinterpret_cast<sal_Int64>(pCnt))); + insert(xEntry.get(), sEntry, sSubId, nullptr, false, xChild.get()); + m_xTreeView->set_sensitive(*xChild, !pCnt->IsInvisible()); + if (bRegion) + m_xTreeView->set_extra_row_indent(*xChild, static_cast<const SwRegionContent*>(pCnt)->GetRegionLevel()); + } + } + } + else + { + RequestingChildren(*xEntry); + m_xTreeView->set_children_on_demand(*xEntry, false); + } + + m_xTreeView->set_sensitive(*xEntry, m_xTreeView->iter_has_child(*xEntry)); + + m_xTreeView->thaw(); + + m_xTreeView->expand_row(*xEntry); + + // reselect the entry + if (nEntryRelPos) + { + std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(xEntry.get())); + sal_uLong nPos = 1; + while (m_xTreeView->iter_next(*xChild)) + { + // The old text will be slightly favored + if (sEntryName == m_xTreeView->get_text(*xChild) || nPos == nEntryRelPos) + { + xSelEntry = std::move(xChild); + break; + } + nPos++; + } + if (xSelEntry) + { + m_xTreeView->set_cursor(*xSelEntry); // unselect all entries, make pSelEntry visible, and select + Select(); + } + } + else + { + m_xTreeView->set_cursor(*xEntry); + Select(); + } + } + } + + if (!m_bIsInPromoteDemote && 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*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64()))); + SwContent* pCnt = reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xEntry).toInt64()); + + 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 : + // 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()); + const SwContentType* pCntType; + if (bEntry) + { + if (lcl_IsContentType(*xEntry, *m_xTreeView)) + { + assert(dynamic_cast<SwContentType*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64()))); + pCntType = reinterpret_cast<SwContentType*>(m_xTreeView->get_id(*xEntry).toInt64()); + } + else + { + assert(dynamic_cast<SwContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64()))); + pCntType = reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetParent(); + } + m_nRootType = pCntType->GetType(); + m_bIsRoot = true; + Display(State::HIDDEN != m_eState); + if (m_nRootType == ContentTypeId::OUTLINE) + { + m_xTreeView->set_selection_mode(SelectionMode::Multiple); + } + } + } + else + { + m_xTreeView->set_selection_mode(SelectionMode::Single); + m_nRootType = ContentTypeId::UNKNOWN; + m_bIsRoot = false; + FindActiveTypeAndRemoveUserData(); + Display(State::HIDDEN != m_eState); + } + m_pConfig->SetRootType( m_nRootType ); + weld::Toolbar* pBox = GetParentWindow()->m_xContent2ToolBox.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. + + // bVisibilityChanged gets set to true if some element, like a section, + // changed visibility and should have its name rerendered with a new + // grayed-out state + bool bVisibilityChanged = false; + + if (State::HIDDEN == m_eState) + { + for(ContentTypeId i : o3tl::enumrange<ContentTypeId>()) + { + if(m_aActiveContentArr[i]) + m_aActiveContentArr[i]->Invalidate(); + } + } + // root content navigation view + else if(m_bIsRoot) + { + std::unique_ptr<weld::TreeIter> xRootEntry(m_xTreeView->make_iterator()); + if (!m_xTreeView->get_iter_first(*xRootEntry)) + bContentChanged = true; + else + { + assert(dynamic_cast<SwContentType*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xRootEntry).toInt64()))); + const ContentTypeId nType = reinterpret_cast<SwContentType*>(m_xTreeView->get_id(*xRootEntry).toInt64())->GetType(); + SwContentType* pArrType = m_aActiveContentArr[nType].get(); + if (!pArrType) + bContentChanged = true; + else + { + // start check if first selected outline level has changed + bool bCheckChanged = m_nRootType == ContentTypeId::OUTLINE && !m_xTreeView->has_focus(); + if (bCheckChanged) + { + std::unique_ptr<weld::TreeIter> xFirstSel(m_xTreeView->make_iterator()); + bool bFirstSel = m_xTreeView->get_selected(xFirstSel.get()); + if (bFirstSel && lcl_IsContent(*xFirstSel, *m_xTreeView)) + { + assert(dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xFirstSel).toInt64()))); + const auto nSelLevel = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xFirstSel).toInt64())->GetOutlineLevel(); + SwWrtShell* pSh = GetWrtShell(); + const SwOutlineNodes::size_type nOutlinePos = pSh->GetOutlinePos(MAXLEVEL); + if (nOutlinePos != SwOutlineNodes::npos && pSh->getIDocumentOutlineNodesAccess()->getOutlineLevel(nOutlinePos) != nSelLevel) + bContentChanged = true; + } + } + // end check if first selected outline level has changed + + pArrType->Init(&bVisibilityChanged); + pArrType->FillMemberList(); + OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pArrType))); + m_xTreeView->set_id(*xRootEntry, sId); + if (!bContentChanged) + { + const size_t nChildCount = GetChildCount(*xRootEntry); + if (nChildCount != pArrType->GetMemberCount()) + bContentChanged = true; + else + { + std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(xRootEntry.get())); + for (size_t j = 0; j < nChildCount; ++j) + { + m_xTreeView->iter_next(*xEntry); + const SwContent* pCnt = pArrType->GetMember(j); + OUString sSubId(OUString::number(reinterpret_cast<sal_Int64>(pCnt))); + m_xTreeView->set_id(*xEntry, sSubId); + OUString sEntryText = m_xTreeView->get_text(*xEntry); + if( sEntryText != pCnt->GetName() && + !(sEntryText == m_sSpace && pCnt->GetName().isEmpty())) + bContentChanged = true; + } + } + } + } + } + } + // all content navigation view + else + { + std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator()); + bool bEntry = m_xTreeView->get_iter_first(*xEntry); + while (bEntry) + { + bool bNext = true; // at least a next must be + assert(dynamic_cast<SwContentType*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64()))); + SwContentType* pCntType = reinterpret_cast<SwContentType*>(m_xTreeView->get_id(*xEntry).toInt64()); + const size_t nCntCount = pCntType->GetMemberCount(); + const ContentTypeId nType = pCntType->GetType(); + SwContentType* pArrType = m_aActiveContentArr[nType].get(); + if (!pArrType) + bContentChanged = true; + else + { + pArrType->Init(&bVisibilityChanged); + OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pArrType))); + m_xTreeView->set_id(*xEntry, sId); + if (m_xTreeView->get_row_expanded(*xEntry)) + { + bool bLevelOrVisibilityChanged = false; + // bLevelOrVisibilityChanged is set if outlines have changed their level + // or if the visibility of objects (frames, sections, tables) has changed + // i.e. in header/footer + pArrType->FillMemberList(&bLevelOrVisibilityChanged); + const size_t nChildCount = GetChildCount(*xEntry); + if (bLevelOrVisibilityChanged) + { + if (nType == ContentTypeId::OUTLINE) + bContentChanged = true; + else + bVisibilityChanged = true; + } + + if(nChildCount != pArrType->GetMemberCount()) + bContentChanged = true; + else + { + for(size_t j = 0; j < nChildCount; ++j) + { + bEntry = m_xTreeView->iter_next(*xEntry); + bNext = false; + const SwContent* pCnt = pArrType->GetMember(j); + OUString sSubId(OUString::number(reinterpret_cast<sal_Int64>(pCnt))); + m_xTreeView->set_id(*xEntry, sSubId); + OUString sEntryText = m_xTreeView->get_text(*xEntry); + if( sEntryText != pCnt->GetName() && + !(sEntryText == m_sSpace && pCnt->GetName().isEmpty())) + bContentChanged = true; + } + } + } + // not expanded and has children + else if (m_xTreeView->iter_has_child(*xEntry)) + { + // was the entry once opened, then must also the + // invisible records be examined. + // At least the user data must be updated. + bool bLevelOrVisibilityChanged = false; + // bLevelOrVisibilityChanged is set if outlines have changed their level + // or if the visibility of objects (frames, sections, tables) has changed + // i.e. in header/footer + pArrType->FillMemberList(&bLevelOrVisibilityChanged); + 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(OUString::number(reinterpret_cast<sal_Int64>(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; + } + } + // The Root-Entry has to be found now + while (bEntry && (bNext || m_xTreeView->get_iter_depth(*xEntry))) + { + bEntry = m_xTreeView->iter_next(*xEntry); + bNext = false; + } + } + } + + if (!bContentChanged && bVisibilityChanged) + m_aUpdTimer.Start(); + + return bContentChanged || bVisibilityChanged; +} + +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); + sal_Int64 nId = m_xTreeView->get_id(*xEntry).toInt64(); + if (nId && lcl_IsContentType(*xEntry, *m_xTreeView)) + { + assert(dynamic_cast<SwContentType*>(reinterpret_cast<SwTypeNumber*>(nId))); + m_nLastSelType = reinterpret_cast<SwContentType*>(nId)->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) + { + if (m_pActiveShell) + EndListening(*m_pActiveShell->GetView().GetDocShell()); + m_pActiveShell = pSh; + FindActiveTypeAndRemoveUserData(); + clear(); + } + else if (State::CONSTANT == m_eState) + { + if (m_pActiveShell) + EndListening(*m_pActiveShell->GetView().GetDocShell()); + m_pActiveShell = pSh; + m_eState = State::ACTIVE; + bClear = true; + } + // 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) +{ + if (m_pActiveShell) + EndListening(*m_pActiveShell->GetView().GetDocShell()); + 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::DocChanged: + if (!m_bIsInPromoteDemote) + { + m_bViewHasChanged = 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; + } +} + +void SwContentTree::ExecCommand(const OString& rCmd, bool bOutlineWithChildren) +{ + const bool bUp = rCmd == "chapterup"; + const bool bUpDown = bUp || rCmd == "chapterdown"; + const bool bLeft = rCmd == "promote"; + const bool bLeftRight = bLeft || rCmd == "demote"; + if (!bUpDown && !bLeftRight) + return; + if (GetWrtShell()->GetView().GetDocShell()->IsReadOnly() || + (State::ACTIVE != m_eState && + (State::CONSTANT != m_eState || m_pActiveShell != GetParentWindow()->GetCreateView()->GetWrtShellPtr()))) + { + return; + } + + m_bIsInPromoteDemote = true; + + SwWrtShell *const pShell = GetWrtShell(); + sal_Int8 nActOutlineLevel = m_nOutlineLevel; + SwOutlineNodes::size_type nActPos = pShell->GetOutlinePos(nActOutlineLevel); + + std::vector<SwTextNode*> selectedOutlineNodes; + std::vector<std::unique_ptr<weld::TreeIter>> selected; + + m_xTreeView->selected_foreach([this, pShell, &bLeftRight, &bOutlineWithChildren, &selected, &selectedOutlineNodes](weld::TreeIter& rEntry){ + // it's possible to select the root node too which is a really bad idea + bool bSkip = lcl_IsContentType(rEntry, *m_xTreeView); + // 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) + { + bSkip = true; + break; + } + } + } + if (!bSkip) + { + selected.emplace_back(m_xTreeView->make_iterator(&rEntry)); + const SwNodes& rNodes = pShell->GetNodes(); + const size_t nPos = GetAbsPos(rEntry) - 1; + if (nPos < rNodes.GetOutLineNds().size()) + { + SwNode* pNode = rNodes.GetOutLineNds()[ nPos ]; + if (pNode) + { + selectedOutlineNodes.push_back(pNode->GetTextNode()); + } + } + } + return false; + }); + + if (bUpDown && !bUp) + { // to move down, start at the end! + std::reverse(selected.begin(), selected.end()); + } + + SwOutlineNodes::difference_type nDirLast = bUp ? -1 : 1; + bool bStartedAction = false; + for (auto const& pCurrentEntry : selected) + { + assert(pCurrentEntry && lcl_IsContent(*pCurrentEntry, *m_xTreeView)); + if (lcl_IsContent(*pCurrentEntry, *m_xTreeView)) + { + assert(dynamic_cast<SwContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*pCurrentEntry).toInt64()))); + if ((m_bIsRoot && m_nRootType == ContentTypeId::OUTLINE) || + reinterpret_cast<SwContent*>(m_xTreeView->get_id(*pCurrentEntry).toInt64())->GetParent()->GetType() + == ContentTypeId::OUTLINE) + { + nActPos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*pCurrentEntry).toInt64())->GetOutlinePos(); + } + } + if (nActPos == SwOutlineNodes::npos || (bUpDown && !pShell->IsOutlineMovable(nActPos))) + { + 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(); + pShell->MakeOutlineSel(nActPos, nActPos, bOutlineWithChildren); + if (bUpDown) + { + const size_t nEntryAbsPos(GetAbsPos(*pCurrentEntry)); + SwOutlineNodes::difference_type nDir = bUp ? -1 : 1; + if (!bOutlineWithChildren && ((nDir == -1 && nActPos > 0) || + (nDir == 1 && nEntryAbsPos < GetEntryCount() - 2))) + { + pShell->MoveOutlinePara( nDir ); + // Set cursor back to the current position + pShell->GotoOutline( nActPos + nDir); + } + else if (bOutlineWithChildren) + { + SwOutlineNodes::size_type nActEndPos = nActPos; + std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(pCurrentEntry.get())); + assert(dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*pCurrentEntry).toInt64()))); + const auto nActLevel = reinterpret_cast<SwOutlineContent*>( + m_xTreeView->get_id(*pCurrentEntry).toInt64())->GetOutlineLevel(); + bool bEntry = m_xTreeView->iter_next(*xEntry); + while (bEntry && lcl_IsContent(*xEntry, *m_xTreeView)) + { + assert(dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64()))); + if (nActLevel >= reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetOutlineLevel()) + break; + nActEndPos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetOutlinePos(); + bEntry = m_xTreeView->iter_next(*xEntry); + } + if (nDir == 1) // move down + { + std::unique_ptr<weld::TreeIter> xNextSibling(m_xTreeView->make_iterator(pCurrentEntry.get())); + if (m_xTreeView->iter_next_sibling(*xNextSibling) && m_xTreeView->is_selected(*xNextSibling)) + nDir = nDirLast; + else + { + // If the last entry is to be moved we're done + if (bEntry && lcl_IsContent(*xEntry, *m_xTreeView)) + { + // xEntry now points to the entry following the last + // selected entry. + SwOutlineNodes::size_type nDest = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetOutlinePos(); + // here needs to found the next entry after next. + // The selection must be inserted in front of that. + while (bEntry) + { + bEntry = m_xTreeView->iter_next(*xEntry); + assert(!bEntry || !lcl_IsContent(*xEntry, *m_xTreeView)|| + dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64()))); + // nDest++ may only executed if bEntry + if (bEntry) + { + if (!lcl_IsContent(*xEntry, *m_xTreeView)) + break; + else if (nActLevel >= reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetOutlineLevel()) + { + // nDest needs adjusted if there are selected entries (including ancestral lineage) + // immediately before the current moved entry. + std::unique_ptr<weld::TreeIter> xTmp(m_xTreeView->make_iterator(xEntry.get())); + bool bTmp = m_xTreeView->iter_previous(*xTmp); + while (bTmp && lcl_IsContent(*xTmp, *m_xTreeView) && + nActLevel < reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xTmp).toInt64())->GetOutlineLevel()) + { + while (bTmp && lcl_IsContent(*xTmp, *m_xTreeView) && !m_xTreeView->is_selected(*xTmp) && + nActLevel < reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xTmp).toInt64())->GetOutlineLevel()) + { + bTmp = m_xTreeView->iter_parent(*xTmp); + } + if (!bTmp || !m_xTreeView->is_selected(*xTmp)) + break; + bTmp = m_xTreeView->iter_previous(*xTmp); + nDest = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xTmp).toInt64())->GetOutlinePos(); + } + std::unique_ptr<weld::TreeIter> xPrevSibling(m_xTreeView->make_iterator(xEntry.get())); + if (!m_xTreeView->iter_previous_sibling(*xPrevSibling) || !m_xTreeView->is_selected(*xPrevSibling)) + break; + } + else + { + nDest = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetOutlinePos(); + } + } + } + nDirLast = nDir = nDest - nActEndPos; + // If no entry was found that allows insertion before + // it, we just move it to the end. + } + else + nDirLast = nDir = 0; + } + } + else // move up + { + std::unique_ptr<weld::TreeIter> xPrevSibling(m_xTreeView->make_iterator(pCurrentEntry.get())); + if (m_xTreeView->iter_previous_sibling(*xPrevSibling) && m_xTreeView->is_selected(*xPrevSibling)) + nDir = nDirLast; + else + { + SwOutlineNodes::size_type nDest = nActPos; + bEntry = true; + m_xTreeView->copy_iterator(*pCurrentEntry, *xEntry); + while (bEntry && nDest) + { + bEntry = m_xTreeView->iter_previous(*xEntry); + assert(!bEntry || !lcl_IsContent(*xEntry, *m_xTreeView) || + dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64()))); + if (bEntry && lcl_IsContent(*xEntry, *m_xTreeView)) + { + nDest = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetOutlinePos(); + } + else + { + nDest = 0; // presumably? + } + if (bEntry) + { + if (!lcl_IsContent(*xEntry, *m_xTreeView)) + break; + else if (nActLevel >= reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetOutlineLevel()) + { + // nDest needs adjusted if there are selected entries immediately + // after the level change. + std::unique_ptr<weld::TreeIter> xTmp(m_xTreeView->make_iterator(xEntry.get())); + bool bTmp = m_xTreeView->iter_next(*xTmp); + while (bTmp && lcl_IsContent(*xTmp, *m_xTreeView) && + nActLevel < reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xTmp).toInt64())->GetOutlineLevel() && + m_xTreeView->is_selected(*xTmp)) + { + nDest = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xTmp).toInt64())->GetOutlinePos(); + const auto nLevel = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xTmp).toInt64())->GetOutlineLevel(); + // account for selected entries' descendent lineage + bTmp = m_xTreeView->iter_next(*xTmp); + while (bTmp && lcl_IsContent(*xTmp, *m_xTreeView) && + nLevel < reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xTmp).toInt64())->GetOutlineLevel()) + { + nDest = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xTmp).toInt64())->GetOutlinePos(); + bTmp = m_xTreeView->iter_next(*xTmp); + } + } + break; + } + } + } + nDirLast = nDir = nDest - nActPos; + } + } + if (nDir) + { + pShell->MoveOutlinePara( nDir ); + // Set cursor back to the current position + pShell->GotoOutline(nActPos + nDir); + } + } + } + else + { + if (!pShell->IsProtectedOutlinePara()) + pShell->OutlineUpDown(bLeft ? -1 : 1); + } + + pShell->ClearMark(); + 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(); + + // clear all selections to prevent the Display function from trying to reselect selected entries + m_xTreeView->unselect_all(); + Display(true); + + // reselect entries + const SwOutlineNodes::size_type nCurrPos = pShell->GetOutlinePos(MAXLEVEL); + std::unique_ptr<weld::TreeIter> xListEntry(m_xTreeView->make_iterator()); + bool bListEntry = m_xTreeView->get_iter_first(*xListEntry); + while ((bListEntry = m_xTreeView->iter_next(*xListEntry)) && lcl_IsContent(*xListEntry, *m_xTreeView)) + { + assert(dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xListEntry).toInt64()))); + if (reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xListEntry).toInt64())->GetOutlinePos() == nCurrPos) + { + std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(xListEntry.get())); + if (m_xTreeView->iter_parent(*xParent) && !m_xTreeView->get_row_expanded(*xParent)) + m_xTreeView->expand_row(*xParent); + m_xTreeView->set_cursor(*xListEntry); // unselect all entries, make entry visible, set focus, and select + Select(); + break; + } + } + + if (m_bIsRoot) + { + const SwOutlineNodes& rOutLineNds = pShell->GetNodes().GetOutLineNds(); + for (SwTextNode* pNode : selectedOutlineNodes) + { + SwOutlineNodes::const_iterator aFndIt = rOutLineNds.find(pNode); + if(aFndIt == rOutLineNds.end()) + continue; + const size_t nFndPos = aFndIt - rOutLineNds.begin(); + std::unique_ptr<weld::TreeIter> xEntry = GetEntryAtAbsPos(nFndPos + 1); + if (xEntry) + { + m_xTreeView->select(*xEntry); + std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(xEntry.get())); + if (m_xTreeView->iter_parent(*xParent) && !m_xTreeView->get_row_expanded(*xParent)) + m_xTreeView->expand_row(*xParent); + } + } + } + } + m_bIsInPromoteDemote = 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(); +} + +/** No idle with focus or while dragging */ +IMPL_LINK_NOARG(SwContentTree, TimerUpdate, Timer *, void) +{ + // 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(); + if(pView && pView->GetWrtShellPtr() && pView->GetWrtShellPtr()->GetWin() && + (pView->GetWrtShellPtr()->GetWin()->HasFocus() || m_bViewHasChanged) && + !IsInDrag() && !pView->GetWrtShellPtr()->ActionPend()) + { + m_bViewHasChanged = false; + m_bIsIdleClear = false; + SwWrtShell* pActShell = pView->GetWrtShellPtr(); + 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); + } + + // track document outline position at cursor + if (m_nOutlineTracking == 3) // no outline tracking + return; + + const SwOutlineNodes::size_type nActPos = GetWrtShell()->GetOutlinePos(MAXLEVEL); // find out where the cursor is + if (nActPos == SwOutlineNodes::npos) + return; + + // only track if selection is already an outline + std::unique_ptr<weld::TreeIter> xFirstSelected(m_xTreeView->make_iterator()); + if (!m_xTreeView->get_selected(xFirstSelected.get())) + xFirstSelected.reset(); + if (xFirstSelected && lcl_IsContent(*xFirstSelected, *m_xTreeView) && + reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xFirstSelected).toInt64())->GetParent()->GetType() != ContentTypeId::OUTLINE) + return; + if (xFirstSelected && lcl_IsContentType(*xFirstSelected, *m_xTreeView) && + reinterpret_cast<SwContentType*>(m_xTreeView->get_id(*xFirstSelected).toInt64())->GetType() != ContentTypeId::OUTLINE) + return; + + int nSelectedRows = m_xTreeView->count_selected_rows(); + + // find the outline in the tree and select it + m_xTreeView->all_foreach([this, nSelectedRows, nActPos, &xFirstSelected](weld::TreeIter& rEntry){ + bool bRet = false; + + if (lcl_IsContent(rEntry, *m_xTreeView) && + reinterpret_cast<SwContent*>(m_xTreeView->get_id(rEntry).toInt64())->GetParent()->GetType() == ContentTypeId::OUTLINE) + { + // might have been scrolled out of view by the user so leave it that way + if (reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(rEntry).toInt64())->GetOutlinePos() == nActPos) + { + // only select if not already selected or tree has multiple entries selected + if (nSelectedRows != 1 || 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 (reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xChildEntry).toInt64())->GetParent()->GetType() == ContentTypeId::OUTLINE) + m_xTreeView->collapse_row(*xChildEntry); + else + break; + } + while (m_xTreeView->iter_next(*xChildEntry)); + } + } + m_xTreeView->set_cursor(rEntry); // unselect all entries, make pEntry visible, and select + Select(); + } + bRet = true; + } + } + else + { + // use of this break assumes outline content type is first in tree + if (lcl_IsContentType(rEntry, *m_xTreeView) && + reinterpret_cast<SwContentType*>(m_xTreeView->get_id(rEntry).toInt64())->GetType() != ContentTypeId::OUTLINE) + bRet = true; + } + + return bRet; + }); + } + else if (!pView && State::ACTIVE == m_eState && !m_bIsIdleClear) + { + if(m_pActiveShell) + { + SetActiveShell(nullptr); + } + clear(); + m_bIsIdleClear = true; + } +} + +void SwContentTree::MoveOutline(SwOutlineNodes::size_type nTargetPos) +{ + 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 = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*source).toInt64())->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, FocusHdl, 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); + else if ((State::ACTIVE == m_eState || (State::CONSTANT == m_eState && pActShell == GetWrtShell())) && + HasContentChanged()) + { + Display(true); + } + } + 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; + } + } + } + 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*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64()))); + if (reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xEntry).toInt64())->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*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64())); + + 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); + const size_t nCount = pPage->GetObjCount(); + 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( size_t i=0; i<nCount; ++i ) + { + SdrObject* pTemp = pPage->GetObj(i); + bool bMark = pDrawView->IsObjMarked(pTemp); + switch( pTemp->GetObjIdentifier() ) + { + case OBJ_GRUP: + case OBJ_TEXT: + case OBJ_LINE: + case OBJ_RECT: + case OBJ_CIRC: + case OBJ_SECT: + case OBJ_CARC: + case OBJ_CCUT: + case OBJ_POLY: + case OBJ_PLIN: + case OBJ_PATHLINE: + case OBJ_PATHFILL: + case OBJ_FREELINE: + case OBJ_FREEFILL: + case OBJ_PATHPOLY: + case OBJ_PATHPLIN: + case OBJ_CAPTION: + case OBJ_CUSTOMSHAPE: + if( bMark ) + hasObjectMarked = true; + break; + default: + if ( bMark ) + { + SdrPageView* pPV = pDrawView->GetSdrPageView/*GetPageViewPvNum*/(/*0*/); + if (pPV) + { + pDrawView->MarkObj(pTemp, 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*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64())); + 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("promote", !aCode.IsShift()); + else if (aCode.GetCode() == KEY_RIGHT) + ExecCommand("demote", !aCode.IsShift()); + else if (aCode.GetCode() == KEY_UP) + ExecCommand("chapterup", !aCode.IsShift()); + else if (aCode.GetCode() == KEY_DOWN) + ExecCommand("chapterdown", !aCode.IsShift()); + 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 = reinterpret_cast<void*>(m_xTreeView->get_id(rEntry).toInt64()); + 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, *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; + default: break; + } + if(static_cast<SwContent*>(pUserData)->IsInvisible()) + { + if(!sEntry.isEmpty()) + sEntry += ", "; + sEntry += m_sInvisible; + } + } + else + { + const 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 OString& rSelectedPopupEntry) +{ + std::unique_ptr<weld::TreeIter> xFirst(m_xTreeView->make_iterator()); + if (!m_xTreeView->get_selected(xFirst.get())) + xFirst.reset(); + + auto nSelectedPopupEntry = rSelectedPopupEntry.toUInt32(); + switch (nSelectedPopupEntry) + { + case 11: + case 12: + case 13: + nSelectedPopupEntry -= 10; + if(m_nOutlineTracking != nSelectedPopupEntry) + m_nOutlineTracking = 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 = reinterpret_cast<SwTOXBaseContent*>(m_xTreeView->get_id(*xFirst).toInt64()) + ->GetTOXBase(); + m_pActiveShell->SetTOXBaseReadonly(*pBase, !SwEditShell::IsTOXBaseReadonly(*pBase)); + } + break; + case 4: + break; + case 501: + EditEntry(*xFirst, EditEntryMode::DELETE); + 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("chapterup", true); + break; + case 802: + ExecCommand("chapterdown", true); + break; + case 803: + ExecCommand("promote", true); + break; + case 804: + ExecCommand("demote", true); + break; + case 805: + { + m_pActiveShell->KillPams(); + m_pActiveShell->ClearMark(); + m_pActiveShell->EnterAddMode(); + SwContent* pCnt = reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xFirst).toInt64()); + const ContentTypeId eTypeId = pCnt->GetParent()->GetType(); + if (eTypeId == ContentTypeId::OUTLINE) + { + m_xTreeView->selected_foreach([this](weld::TreeIter& rEntry){ + m_pActiveShell->SttSelect(); + SwOutlineNodes::size_type nActPos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(rEntry).toInt64())->GetOutlinePos(); + m_pActiveShell->MakeOutlineSel(nActPos, nActPos, !m_xTreeView->get_row_expanded(rEntry), false); // select children if not expanded + m_pActiveShell->EndSelect(); + return false; + }); + } + else if (eTypeId == ContentTypeId::TABLE) + { + m_pActiveShell->GotoTable(pCnt->GetName()); + m_pActiveShell->SelAll(); + } + 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 806: + // Delete outline selections + EditEntry(*xFirst, EditEntryMode::DELETE); + break; + case 900: + { + SwContent* pCnt = reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xFirst).toInt64()); + 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() +{ + m_pActiveShell->StartAction(); + m_pActiveShell->EnterAddMode(); + auto nChapters(0); + + m_xTreeView->selected_foreach([this, &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); + } + m_pActiveShell->SttSelect(); + SwOutlineNodes::size_type nActPos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(rEntry).toInt64())->GetOutlinePos(); + m_pActiveShell->MakeOutlineSel(nActPos, nActPos, !m_xTreeView->get_row_expanded(rEntry), false); // select children if not expanded + 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->SetTextFormatColl(nullptr); + m_pActiveShell->Delete(); + m_pActiveShell->ClearMark(); + m_pActiveShell->EndUndo(); + m_pActiveShell->EndAction(); +} + +void SwContentTree::SetOutlineLevel(sal_uInt8 nSet) +{ + 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->Init(); + } + Display(State::ACTIVE == m_eState); +} + +// 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) +{ + Select(); +} + +// 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) && + reinterpret_cast<SwContentType*>(m_xTreeView->get_id(*xParentEntry).toInt64())->GetType() == ContentTypeId::OUTLINE)) + { + bEnable = true; + } + } + } + SwNavigationPI* pNavi = GetParentWindow(); + pNavi->m_xContent3ToolBox->set_item_sensitive("chapterup", bEnable); + pNavi->m_xContent3ToolBox->set_item_sensitive("chapterdown", bEnable); + pNavi->m_xContent3ToolBox->set_item_sensitive("promote", bEnable); + pNavi->m_xContent3ToolBox->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 = reinterpret_cast<SwContent*>(m_xTreeView->get_id(rEntry).toInt64()); + GotoContent(pCnt); + const ContentTypeId nType = pCnt->GetParent()->GetType(); + sal_uInt16 nSlot = 0; + + 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 : + assert(!m_pActiveShell->getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_BOOKMARKS)); + if(nMode == EditEntryMode::DELETE) + { + IDocumentMarkAccess* const pMarkAccess = m_pActiveShell->getIDocumentMarkAccess(); + pMarkAccess->deleteMark( pMarkAccess->findMark(pCnt->GetName()) ); + } + else if(nMode == EditEntryMode::RENAME) + { + uno::Reference< frame::XModel > xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel(); + uno::Reference< text::XBookmarksSupplier > xBkms(xModel, uno::UNO_QUERY); + xNameAccess = xBkms->getBookmarks(); + } + else + nSlot = FN_INSERT_BOOKMARK; + break; + + case ContentTypeId::REGION : + 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: + nSlot = FN_EDIT_FIELD; + break; + + case ContentTypeId::POSTIT: + m_pActiveShell->GetView().GetPostItMgr()->AssureStdModeAtShell(); + if(nMode == EditEntryMode::DELETE) + { + m_pActiveShell->GetView().GetPostItMgr()->SetActiveSidebarWin(nullptr); + 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; + break; + default: break; + } + if(nSlot) + m_pActiveShell->GetView().GetViewFrame()-> + GetDispatcher()->Execute(nSlot, SfxCallMode::ASYNCHRON); + 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(GetParentWindow()->GetFrameWeld(), 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) + { + m_bViewHasChanged = true; + GetParentWindow()->UpdateListBox(); + TimerUpdate(&m_aUpdTimer); + grab_focus(); + } +} + +void SwContentTree::GotoContent(const SwContent* pCnt) +{ + m_pActiveShell->EnterStdMode(); + + bool bSel = false; + switch(pCnt->GetParent()->GetType()) + { + case ContentTypeId::OUTLINE : + { + m_pActiveShell->GotoOutline(static_cast<const SwOutlineContent*>(pCnt)->GetOutlinePos()); + } + break; + case ContentTypeId::TABLE : + { + m_pActiveShell->GotoTable(pCnt->GetName()); + } + break; + case ContentTypeId::FRAME : + case ContentTypeId::GRAPHIC : + case ContentTypeId::OLE : + { + if(m_pActiveShell->GotoFly(pCnt->GetName())) + bSel = true; + } + break; + case ContentTypeId::BOOKMARK: + { + m_pActiveShell->GotoMark(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( CRSR_SKIP_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->GetView().GetPostItMgr()->AssureStdModeAtShell(); + m_pActiveShell->GotoFormatField(*static_cast<const SwPostItContent*>(pCnt)->GetPostIt()); + break; + case ContentTypeId::DRAWOBJECT: + { + SwPosition aPos = *m_pActiveShell->GetCursor()->GetPoint(); + SdrView* pDrawView = m_pActiveShell->GetDrawView(); + if (pDrawView) + { + pDrawView->SdrEndTextEdit(); + pDrawView->UnmarkAll(); + SwDrawModel* _pModel = m_pActiveShell->getIDocumentDrawModelAccess().GetDrawModel(); + SdrPage* pPage = _pModel->GetPage(0); + const size_t nCount = pPage->GetObjCount(); + for( size_t i=0; i<nCount; ++i ) + { + SdrObject* pTemp = pPage->GetObj(i); + if (pTemp->GetName() == pCnt->GetName()) + { + SdrPageView* pPV = pDrawView->GetSdrPageView(); + if( pPV ) + { + pDrawView->MarkObj( pTemp, pPV ); + } + } + } + m_pActiveShell->GetNavigationMgr().addEntry(aPos); + m_pActiveShell->EnterStdMode(); + bSel = true; + } + } + break; + default: break; + } + if(bSel) + { + m_pActiveShell->HideCursor(); + m_pActiveShell->EnterSelFrameMode(); + } + SwView& rView = m_pActiveShell->GetView(); + rView.StopShellTimer(); + rView.GetPostItMgr()->SetActiveSidebarWin(nullptr); + rView.GetEditWin().GrabFocus(); + + // force scroll to cursor position when navigating to inactive document + if(!bSel) + { + Point rPoint = m_pActiveShell->GetCursorDocPos(); + rPoint.setX(0); + rView.SetVisArea(rPoint); + } +} + +// Now even the matching text::Bookmark +NaviContentBookmark::NaviContentBookmark() + : + nDocSh(0), + nDefDrag( RegionMode::NONE ) +{ +} + +NaviContentBookmark::NaviContentBookmark( const OUString &rUrl, + const OUString& rDesc, + RegionMode nDragType, + const SwDocShell* pDocSh ) : + aUrl( rUrl ), + aDescr(rDesc), + nDocSh(reinterpret_cast<sal_IntPtr>(pDocSh)), + nDefDrag( nDragType ) +{ +} + +void NaviContentBookmark::Copy( TransferDataContainer& rData ) const +{ + rtl_TextEncoding eSysCSet = osl_getThreadTextEncoding(); + + OString sStrBuf(OUStringToOString(aUrl, eSysCSet) + OStringChar(NAVI_BOOKMARK_DELIM) + + OUStringToOString(aDescr, eSysCSet) + OStringChar(NAVI_BOOKMARK_DELIM) + + OString::number(static_cast<int>(nDefDrag)) + OStringChar(NAVI_BOOKMARK_DELIM) + + OString::number(nDocSh)); + rData.CopyByteString(SotClipboardFormatId::SONLK, sStrBuf); +} + +bool NaviContentBookmark::Paste( TransferableDataHelper& rData ) +{ + OUString sStr; + bool bRet = rData.GetString( SotClipboardFormatId::SONLK, sStr ); + if( bRet ) + { + sal_Int32 nPos = 0; + aUrl = sStr.getToken(0, NAVI_BOOKMARK_DELIM, nPos ); + aDescr = sStr.getToken(0, NAVI_BOOKMARK_DELIM, nPos ); + nDefDrag= static_cast<RegionMode>( sStr.getToken(0, NAVI_BOOKMARK_DELIM, nPos ).toInt32() ); + nDocSh = sStr.getToken(0, NAVI_BOOKMARK_DELIM, nPos ).toInt32(); + } + return bRet; +} + +SwNavigationPI* SwContentTree::GetParentWindow() +{ + return m_xDialog; +} + +/* 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 000000000..3261050f3 --- /dev/null +++ b/sw/source/uibase/utlui/glbltree.cxx @@ -0,0 +1,1088 @@ +/* -*- 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 <vcl/help.hxx> +#include <sot/filelist.hxx> +#include <svl/eitem.hxx> +#include <vcl/graphicfilter.hxx> +#include <vcl/settings.hxx> + +#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> + +using namespace ::com::sun::star::uno; + +#define GLOBAL_UPDATE_TIMEOUT 2000 + +const SfxObjectShell* SwGlobalTree::pShowShell = nullptr; + +namespace { + +class SwGlobalFrameListener_Impl : public SfxListener +{ + bool bValid; +public: + explicit SwGlobalFrameListener_Impl(SfxViewFrame& rFrame) + : bValid(true) + { + StartListening(rFrame); + } + + virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override; + + bool IsValid() const {return bValid;} +}; + +} + +void SwGlobalFrameListener_Impl::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint ) +{ + if( rHint.GetId() == SfxHintId::Dying) + 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 +}; + +} + +static const char* 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_xDialog(pDialog) + , m_pActiveShell(nullptr) +{ + Size aSize(m_xDialog->LogicToPixel(Size(110, 112), MapMode(MapUnit::MapAppFont)));; + m_xTreeView->set_size_request(aSize.Width(), aSize.Height()); + + 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(); + m_xDialog.clear(); +} + +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())) + 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 ? + reinterpret_cast<const SwGlblDocContent*>(rWidget.get_id(*xDropEntry).toInt64()) : + nullptr; + if( aData.HasFormat( SotClipboardFormatId::FILE_LIST )) + { + nRet = rEvt.mnAction; + std::unique_ptr<SwGlblDocContents> pTempContents(new SwGlblDocContents); + 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) + { + m_rTreeView.GetActiveWrtShell()->GetGlobalDocContent(*pTempContents); + // If the file was successfully inserted, + // then the next content must also be fetched. + if(nEntryCount < pTempContents->size()) + { + nEntryCount++; + nAbsContPos++; + pCnt = (*pTempContents)[ 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); + + 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"); + + const MenuEnableFlags nEnableFlags = GetEnableFlags(); + + xPopup->set_sensitive("updatesel", bool(nEnableFlags & MenuEnableFlags::UpdateSel)); + + xPopup->set_sensitive("editlink", bool(nEnableFlags & MenuEnableFlags::EditLink)); + + //disabling if applicable + xPopup->set_sensitive("insertindex", bool(nEnableFlags & MenuEnableFlags::InsertIdx )); + xPopup->set_sensitive("insertfile", bool(nEnableFlags & MenuEnableFlags::InsertFile)); + xPopup->set_sensitive("insertnewfile", bool(nEnableFlags & MenuEnableFlags::InsertFile)); + xPopup->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)); + + OString sCommand = xPopup->popup_at_rect(m_xTreeView.get(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1))); + if (!sCommand.isEmpty()) + ExecuteContextMenuAction(sCommand); + } + return bPop; +} + +void SwGlobalTree::TbxMenuHdl(const OString& rCommand, weld::Menu& rMenu) +{ + const MenuEnableFlags nEnableFlags = GetEnableFlags(); + if (rCommand == "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 == "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()); + + sal_uLong 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 && reinterpret_cast<SwGlblDocContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetType() != GLBLDOC_UNKNOWN && + (!bPrevEntry || reinterpret_cast<SwGlblDocContent*>(m_xTreeView->get_id(*xPrevEntry).toInt64())->GetType() != GLBLDOC_UNKNOWN)) + nRet |= MenuEnableFlags::InsertText; + if (bEntry && GLBLDOC_SECTION == reinterpret_cast<SwGlblDocContent*>(m_xTreeView->get_id(*xEntry).toInt64())->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 = reinterpret_cast<const SwGlblDocContent*>(m_xTreeView->get_id(rIter).toInt64()); + 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(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(OUString::number(reinterpret_cast<sal_Int64>(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(); + if (!m_pSwGlblDocContents) + Update( false ); + + int nSelEntry = -1; + for (size_t i = 0; i < nCount; ++i) + { + const SwGlblDocContent* pCont = (*m_pSwGlblDocContents)[i].get(); + + OUString sId(OUString::number(reinterpret_cast<sal_Int64>(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 ) + { + m_pDocInserter.reset(new ::sfx2::DocumentInserter(GetParentWindow()->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 ); + aFileNames.getArray()[0] = aFileName.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + 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(const OString& rSelectedPopupEntry) +{ + bool bUpdateHard = false; + + int nEntry = m_xTreeView->get_selected_index(); + SwGlblDocContent* pCont = nEntry != -1 ? reinterpret_cast<SwGlblDocContent*>(m_xTreeView->get_id(nEntry).toInt64()) : 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::unique_ptr<SwGlblDocContent> pContCopy; + if(pCont) + pContCopy.reset(new SwGlblDocContent(pCont->GetDocPos())); + SfxDispatcher& rDispatch = *m_pActiveShell->GetView().GetViewFrame()->GetDispatcher(); + sal_uInt16 nSlot = 0; + if (rSelectedPopupEntry == "updatesel") + { + // Two passes: first update the areas, then the directories. + m_xTreeView->selected_foreach([this](weld::TreeIter& rSelEntry){ + SwGlblDocContent* pContent = reinterpret_cast<SwGlblDocContent*>(m_xTreeView->get_id(rSelEntry).toInt64()); + 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 = reinterpret_cast<SwGlblDocContent*>(m_xTreeView->get_id(rSelEntry).toInt64()); + if (GLBLDOC_TOXBASE == pContent->GetType()) + m_pActiveShell->UpdateTableOf(*pContent->GetTOX()); + return false; + }); + + bUpdateHard = true; + } + else if (rSelectedPopupEntry == "updateindex") + { + nSlot = FN_UPDATE_TOX; + bUpdateHard = true; + } + else if (rSelectedPopupEntry == "updatelinks" || rSelectedPopupEntry == "updateall") + { + m_pActiveShell->GetLinkManager().UpdateAllLinks(true, false, nullptr); + if (rSelectedPopupEntry == "updateall") + nSlot = FN_UPDATE_TOX; + pCont = nullptr; + bUpdateHard = true; + } + else if (rSelectedPopupEntry == "edit") + { + OSL_ENSURE(pCont, "edit without entry ? " ); + if (pCont) + { + EditContent(pCont); + } + } + else if (rSelectedPopupEntry == "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 == "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 == "insertindex") + { + if(pContCopy) + { + SfxItemSet aSet( + m_pActiveShell->GetView().GetPool(), + svl::Items< + 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>{}); + + SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create(); + ScopedVclPtr<AbstractMultiTOXTabDialog> pDlg(pFact->CreateMultiTOXTabDialog( + m_xDialog->GetFrameWeld(), 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( *pContCopy, *pToInsert ); + } + pCont = nullptr; + } + } + else if (rSelectedPopupEntry == "insertfile") + { + m_pDocContent = std::move(pContCopy); + InsertRegion( m_pDocContent.get() ); + pCont = nullptr; + } + else if (rSelectedPopupEntry == "insertnewfile") + { + SfxViewFrame* pGlobFrame = m_pActiveShell->GetView().GetViewFrame(); + SwGlobalFrameListener_Impl aFrameListener(*pGlobFrame); + + // Creating a new doc + SfxStringItem aFactory(SID_NEWDOCDIRECT, + SwDocShell::Factory().GetFilterContainer()->GetName()); + + const SfxFrameItem* pItem = static_cast<const SfxFrameItem*>( + rDispatch.ExecuteList(SID_NEWDOCDIRECT, + SfxCallMode::SYNCHRON, { &aFactory })); + + // save at + SfxFrame* pFrame = pItem ? pItem->GetFrame() : nullptr; + SfxViewFrame* pViewFrame = pFrame ? pFrame->GetCurrentViewFrame() : nullptr; + if (pViewFrame) + { + const SfxBoolItem* pBool = static_cast<const SfxBoolItem*>( + pViewFrame->GetDispatcher()->Execute( + SID_SAVEASDOC, SfxCallMode::SYNCHRON )); + 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()) + { + pGlobFrame->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 ? reinterpret_cast<SwGlblDocContent*>(m_xTreeView->get_id(nEntry).toInt64()) : 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 == "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 == "update") + pCont = nullptr; + + if (pCont) + GotoContent(pCont); + if (nSlot) + rDispatch.Execute(nSlot); + if (Update(bUpdateHard)) + Display(); +} + +IMPL_LINK_NOARG(SwGlobalTree, Timeout, Timer *, void) +{ + if (!m_xTreeView->has_focus() && Update(false)) + Display(); +} + +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(); +} + +void SwGlobalTree::HideTree() +{ + m_aUpdateTimer.Stop(); + m_xTreeView->hide(); +} + +void SwGlobalTree::ExecCommand(const OString &rCmd) +{ + int nEntry = m_xTreeView->get_selected_index(); + if (nEntry == -1) + return; + if (rCmd == "edit") + { + const SwGlblDocContent* pCont = reinterpret_cast<const SwGlblDocContent*>( + m_xTreeView->get_id(nEntry).toInt64()); + EditContent(pCont); + } + else + { + if (m_xTreeView->count_selected_rows() == 1) + { + bool bMove = false; + sal_uLong nSource = nEntry; + sal_uLong nDest = nSource; + if (rCmd == "movedown") + { + size_t nEntryCount = m_xTreeView->n_children(); + bMove = nEntryCount > nSource + 1; + nDest+= 2; + } + else if (rCmd == "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(!m_pSwGlblDocContents) + { + m_pSwGlblDocContents.reset(new SwGlblDocContents); + bRet = true; + m_pActiveShell->GetGlobalDocContent(*m_pSwGlblDocContents); + } + else + { + bool bCopy = false; + std::unique_ptr<SwGlblDocContents> pTempContents(new SwGlblDocContents); + m_pActiveShell->GetGlobalDocContent(*pTempContents); + size_t nChildren = m_xTreeView->n_children(); + if (pTempContents->size() != m_pSwGlblDocContents->size() || + pTempContents->size() != nChildren) + { + bRet = true; + bCopy = true; + } + else + { + for(size_t i = 0; i < pTempContents->size() && !bCopy; i++) + { + SwGlblDocContent* pLeft = (*pTempContents)[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( *pTempContents ); + 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 = reinterpret_cast<SwGlblDocContent*>(m_xTreeView->get_id(nEntry).toInt64()); + if (pCont->GetType() == GLBLDOC_SECTION) + OpenDoc(pCont); + else + { + GotoContent(pCont); + m_pActiveShell->GetView().GetEditWin().GrabFocus(); + } + return false; +} + +SwNavigationPI* SwGlobalTree::GetParentWindow() +{ + return m_xDialog; +} + +IMPL_STATIC_LINK_NOARG(SwGlobalTree, ShowFrameHdl, void*, void) +{ + SfxViewFrame* pFirst = pShowShell ? SfxViewFrame::GetFirst(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() ) + { + Sequence< OUString >aFileNames( aMedList.size() ); + OUString* pFileNames = aFileNames.getArray(); + sal_Int32 nPos = 0; + for (const std::unique_ptr<SfxMedium>& pMed : aMedList) + { + OUString sFileName = pMed->GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ) + + OUStringChar(sfx2::cTokenSeparator) + + pMed->GetFilter()->GetFilterName() + + OUStringChar(sfx2::cTokenSeparator); + pFileNames[nPos++] = sFileName; + } + InsertRegion( m_pDocContent.get(), aFileNames ); + m_pDocContent.reset(); + } +} + +/* 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 000000000..b58335850 --- /dev/null +++ b/sw/source/uibase/utlui/gloslst.cxx @@ -0,0 +1,441 @@ +/* -*- 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 <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() : + bFilled(false) +{ + SvtPathOptions aPathOpt; + 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(const OUString& rLongName, + OUString& rShortName, OUString& rGroupName ) +{ + if(!bFilled) + Update(); + + std::vector<TripleString> aTripleStrings; + + size_t nCount = aGroupArr.size(); + for(size_t i = 0; i < nCount; i++ ) + { + AutoTextGroup* pGroup = 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(); + SwGlossDecideDlg aDlg(pView ? pView->GetFrameWeld() : nullptr); + 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(!bFilled) + Update(); + return aGroupArr.size(); +} + +OUString SwGlossaryList::GetGroupName(size_t nPos) +{ + OSL_ENSURE(aGroupArr.size() > nPos, "group not available"); + if(nPos < aGroupArr.size()) + { + AutoTextGroup* pGroup = aGroupArr[nPos].get(); + OUString sRet = pGroup->sName; + return sRet; + } + return OUString(); +} + +OUString SwGlossaryList::GetGroupTitle(size_t nPos) +{ + OSL_ENSURE(aGroupArr.size() > nPos, "group not available"); + if(nPos < aGroupArr.size()) + { + AutoTextGroup* pGroup = aGroupArr[nPos].get(); + return pGroup->sTitle; + } + return OUString(); +} + +sal_uInt16 SwGlossaryList::GetBlockCount(size_t nGroup) +{ + OSL_ENSURE(aGroupArr.size() > nGroup, "group not available"); + if(nGroup < aGroupArr.size()) + { + AutoTextGroup* pGroup = aGroupArr[nGroup].get(); + return pGroup->nCount; + } + return 0; +} + +OUString SwGlossaryList::GetBlockLongName(size_t nGroup, sal_uInt16 nBlock) +{ + OSL_ENSURE(aGroupArr.size() > nGroup, "group not available"); + if(nGroup < aGroupArr.size()) + { + AutoTextGroup* pGroup = aGroupArr[nGroup].get(); + return pGroup->sLongNames.getToken(nBlock, STRING_DELIM); + } + return OUString(); +} + +OUString SwGlossaryList::GetBlockShortName(size_t nGroup, sal_uInt16 nBlock) +{ + OSL_ENSURE(aGroupArr.size() > nGroup, "group not available"); + if(nGroup < aGroupArr.size()) + { + AutoTextGroup* pGroup = 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 != sPath) + { + sPath = sTemp; + bFilled = false; + ClearGroups(); + } + SwGlossaries* pGlossaries = ::GetGlossaries(); + const std::vector<OUString> & rPathArr = pGlossaries->GetPathArray(); + const OUString sExt( SwGlossaries::GetExtension() ); + if(!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>( + sGrpName.getToken(1, GLOS_DELIM).toInt32()); + if( nPath < rPathArr.size() ) + { + std::unique_ptr<AutoTextGroup> pGroup(new AutoTextGroup); + pGroup->sName = sGrpName; + + FillGroup(pGroup.get(), pGlossaries); + OUString sName = rPathArr[nPath] + "/" + + pGroup->sName.getToken(0, GLOS_DELIM) + sExt; + FStatHelper::GetModifiedDateTimeOfFile( sName, + &pGroup->aDateModified, + &pGroup->aDateModified ); + + aGroupArr.insert( aGroupArr.begin(), std::move(pGroup) ); + } + } + 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( static_cast<sal_uInt16>(nPath) ); + AutoTextGroup* pFound = FindGroup( sName ); + if( !pFound ) + { + pFound = new AutoTextGroup; + pFound->sName = sName; + FillGroup( pFound, pGlossaries ); + pFound->aDateModified = rDT; + + aGroupArr.push_back(std::unique_ptr<AutoTextGroup>(pFound)); + } + else if( pFound->aDateModified < rDT ) + { + FillGroup(pFound, pGlossaries); + pFound->aDateModified = rDT; + } + } + + for( size_t i = aGroupArr.size(); i>0; ) + { + --i; + // maybe remove deleted groups + AutoTextGroup* pGroup = aGroupArr[i].get(); + const size_t nGroupPath = static_cast<size_t>( + pGroup->sName.getToken( 1, GLOS_DELIM).toInt32()); + // Only the groups will be checked which are registered + // for the current subpath. + if( nGroupPath == nPath ) + { + OUString sCompareGroup = pGroup->sName.getToken(0, GLOS_DELIM); + bool bFound = std::any_of(aFoundGroupNames.begin(), aFoundGroupNames.end(), + [&sCompareGroup](const OUString& rGroupName) { return sCompareGroup == rGroupName; }); + + if(!bFound) + { + aGroupArr.erase(aGroupArr.begin() + i); + } + } + } + } + } +} + +void SwGlossaryList::Invoke() +{ + // Only update automatically if a SwView has the focus. + if(::GetActiveView()) + Update(); +} + +AutoTextGroup* SwGlossaryList::FindGroup(const OUString& rGroupName) +{ + for(const auto & pRet : 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(!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 : 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() +{ + aGroupArr.clear(); + 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 000000000..63e7c424c --- /dev/null +++ b/sw/source/uibase/utlui/gotodlg.cxx @@ -0,0 +1,102 @@ +/* -*- 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* _pBindings) + : GenericDialogController(pParent, "modules/swriter/ui/gotopagedialog.ui", "GotoPageDialog") + , m_pCreateView(nullptr) + , m_rBindings(_pBindings) + , mnMaxPageCnt(1) + , mxMtrPageCtrl(m_xBuilder->weld_entry("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()) + { + int page_value = mxMtrPageCtrl->get_text().toInt32(); + + if (page_value <= 0) + mxMtrPageCtrl->set_text(OUString::number(1)); + else if(page_value > mnMaxPageCnt) + mxMtrPageCtrl->set_text(OUString::number(mnMaxPageCnt)); + + 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_text(OUString::number(1)); + if (pSh) + { + const sal_uInt16 nPageCnt = pSh->GetPageCnt(); + sal_uInt16 nPhyPage, nVirPage; + pSh->GetPageNum(nPhyPage, nVirPage); + mxMtrPageCtrl->set_text(OUString::number(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 000000000..f9567ec4a --- /dev/null +++ b/sw/source/uibase/utlui/initui.cxx @@ -0,0 +1,289 @@ +/* -*- 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 <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(); +} + +static const char* 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 (size_t i = 0; i < SAL_N_ELEMENTS(FLD_DOCINFO_ARY); ++i) + aDocInfoLst.push_back(SwResId(FLD_DOCINFO_ARY[i])); +} + +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(!pAutoFormatNameLst); + pAutoFormatNameLst.reset( new std::vector<OUString> ); + pAutoFormatNameLst->reserve(STR_AUTOFMTREDL_END); + + 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()); + } + pAutoFormatNameLst->push_back(p); + } +} + +namespace +{ + const char* 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 + }; +} + +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)]; +} + +static const char* 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)]; +} + +/* 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 000000000..f1b4f3983 --- /dev/null +++ b/sw/source/uibase/utlui/navicfg.cxx @@ -0,0 +1,128 @@ +/* -*- 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> + +using namespace ::utl; +using namespace ::com::sun::star::uno; + +Sequence<OUString> SwNavigationConfig::GetPropertyNames() +{ + return css::uno::Sequence<OUString>{ + OUString("RootType"), + OUString("SelectedPosition"), + OUString("OutlineLevel"), + OUString("InsertMode"), + OUString("ActiveBlock"), + OUString("ShowListBox"), + OUString("GlobalDocMode")}; +} + +SwNavigationConfig::SwNavigationConfig() : + utl::ConfigItem("Office.Writer/Navigator"), + nRootType(ContentTypeId::UNKNOWN), + nSelectedPos(0), + nOutlineLevel(MAXLEVEL), + nRegionMode(RegionMode::NONE), + nActiveBlock(0), + bIsSmall(false), + bIsGlobalActive(true) +{ + 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()) + { + 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); + } + nRootType = static_cast<ContentTypeId>(nTmp); + } + break; + } + case 1: pValues[nProp] >>= nSelectedPos; break; + case 2: pValues[nProp] >>= nOutlineLevel; break; + case 3: + { + sal_uInt16 nTmp; + if (pValues[nProp] >>= nTmp) + nRegionMode = static_cast<RegionMode>(nTmp); + break; + } + case 4: pValues[nProp] >>= nActiveBlock; break; + case 5: bIsSmall = *o3tl::doAccess<bool>(pValues[nProp]); break; + case 6: bIsGlobalActive = *o3tl::doAccess<bool>(pValues[nProp]); 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>(nRootType); break; + case 1: pValues[nProp] <<= nSelectedPos; break; + case 2: pValues[nProp] <<= nOutlineLevel; break; + case 3: pValues[nProp] <<= static_cast<sal_uInt16>(nRegionMode); break; + case 4: pValues[nProp] <<= nActiveBlock; break; + case 5: pValues[nProp] <<= bIsSmall; break; + case 6: pValues[nProp] <<= bIsGlobalActive; break; + } + } + PutProperties(aNames, aValues); +} + +void SwNavigationConfig::Notify( const css::uno::Sequence< OUString >& ) {} + +/* 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 000000000..577aba8fc --- /dev/null +++ b/sw/source/uibase/utlui/navipi.cxx @@ -0,0 +1,1128 @@ +/* -*- 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/navigat.hxx> +#include <sfx2/viewfrm.hxx> +#include <tools/urlobj.hxx> +#include <vcl/toolbox.hxx> +#include <swtypes.hxx> +#include <swmodule.hxx> +#include <view.hxx> +#include <navicfg.hxx> +#include <wrtsh.hxx> +#include <docsh.hxx> +#include <navipi.hxx> +#include <workctrl.hxx> +#include <edtwin.hxx> +#include <sfx2/app.hxx> +#include <cmdid.h> +#include <helpids.h> + +#include <strings.hrc> +#include <bitmaps.hlst> + +#include <memory> + +#include <uiobject.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::frame; + +//! soon obsolete ! +std::unique_ptr<SfxChildWindowContext> SwNavigationChild::CreateImpl( vcl::Window *pParent, + SfxBindings *pBindings, SfxChildWinInfo* /*pInfo*/ ) +{ + return std::make_unique<SwNavigationChild>(pParent, + /* cast is safe here! */static_cast< sal_uInt16 >(SwView::GetInterfaceId()), + pBindings); +} +void SwNavigationChild::RegisterChildWindowContext(SfxModule* pMod) +{ + auto pFact = std::make_unique<SfxChildWinContextFactory>( + SwNavigationChild::CreateImpl, + /* cast is safe here! */static_cast< sal_uInt16 >(SwView::GetInterfaceId()) ); + SfxChildWindowContext::RegisterChildWindowContext(pMod, SID_NAVIGATOR, std::move(pFact)); +} + + +// 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 )) + { + + 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()); + } +} + +// 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; + } +} + +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 OString&, 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") + { + rSh.GetView().GetViewFrame()->GetDispatcher()->Execute(FN_SCROLL_PREV, SfxCallMode::ASYNCHRON); + } + else if (rCommand == ".uno:ScrollToNext") + { + rSh.GetView().GetViewFrame()->GetDispatcher()->Execute(FN_SCROLL_NEXT, SfxCallMode::ASYNCHRON); + } + else if (rCommand == "root") + { + m_xContentTree->ToggleToRoot(); + } + else if (rCommand == "listbox") + { + if (SfxChildWindowContext::GetFloatingWindow(GetParent())) + { + 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_xContent3ToolBox->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_xContent3ToolBox->set_menu_item_active("dragmode", !m_xContent3ToolBox->get_menu_item_active("dragmode")); + else if (rCommand == "headings") + m_xContent2ToolBox->set_menu_item_active("headings", !m_xContent2ToolBox->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 OString&, 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, ToolBox3DropdownClickHdl, const OString&, rCommand, void) +{ + if (!m_xContent3ToolBox->get_menu_item_active(rCommand)) + return; + + if (rCommand == "dragmode") + { + 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 OString&, 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 OString&, rIdent, void) +{ + m_xGlobalTree->ExecuteContextMenuAction(rIdent); +} + +IMPL_LINK(SwNavigationPI, ToolBox2DropdownClickHdl, const OString&, rCommand, void) +{ + if (!m_xContent2ToolBox->get_menu_item_active(rCommand)) + return; + + if (rCommand == "headings") + m_xHeadingsMenu->set_active(OString::number(m_xContentTree->GetOutlineLevel()), true); +} + +FactoryFunction SwNavigationPI::GetUITestFactory() const +{ + return SwNavigationPIUIObject::create; +} + +// 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; + + SwWrtShell &rSh = m_pCreateView->GetWrtShell(); + sal_uInt16 nNewPage = m_xEdit->get_value(); + + rSh.GotoPage(nNewPage, true); + m_pCreateView->GetViewFrame()->GetBindings().Invalidate(FN_STAT_PAGE); + + return true; +} + +void SwNavigationPI::ZoomOut() +{ + if (!IsZoomedIn()) + return; + SfxNavigator* pNav = dynamic_cast<SfxNavigator*>(GetParent()); + 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(); + } + + Size aOptimalSize(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_xContent3ToolBox->set_item_active("listbox", true); +} + +void SwNavigationPI::ZoomIn() +{ + if (IsZoomedIn()) + return; + SfxNavigator* pNav = dynamic_cast<SfxNavigator*>(GetParent()); + if (!pNav) + return; + + m_aExpandedSize = GetSizePixel(); + + m_xContentBox->hide(); + m_xContentTree->HideTree(); + m_xGlobalBox->hide(); + m_xGlobalTree->HideTree(); + m_xDocListBox->hide(); + m_bIsZoomedIn = true; + + Size aOptimalSize(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_xContent3ToolBox->set_item_active("listbox", false); +} + +namespace { + +enum StatusIndex +{ + IDX_STR_HIDDEN = 0, + IDX_STR_ACTIVE = 1, + IDX_STR_INACTIVE = 2 +}; + +} + +VclPtr<vcl::Window> SwNavigationPI::Create(vcl::Window* 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 VclPtr<SwNavigationPI>::Create(pParent, rxFrame, pBindings); +} + +SwNavigationPI::SwNavigationPI(vcl::Window* pParent, + const css::uno::Reference<css::frame::XFrame>& rxFrame, + SfxBindings* _pBindings) + : PanelLayout(pParent, "NavigatorPanel", "modules/swriter/ui/navigatorpanel.ui", rxFrame) + , 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_xContent1Dispatch(new ToolbarUnoDispatcher(*m_xContent1ToolBox, *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_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) +{ + set_id("NavigatorPanelParent"); // for uitest/writer_tests5/tdf114724.py + + 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_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->set_help_id("modules/swriter/ui/navigatorpanel/numericfield"); + + if (!IsGlobalDoc()) + { + m_xContent1ToolBox->set_item_visible("contenttoggle", false); + } + + const char* REGIONNAME_ARY[] = + { + STR_HYPERLINK, + STR_LINK_REGION, + STR_COPY_REGION + }; + + const char* 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 = SfxChildWindowContext::GetFloatingWindow(GetParent()) != nullptr; + + m_xContentTree->set_selection_mode(SelectionMode::Single); + m_xContentTree->ShowTree(); + m_xContent3ToolBox->set_item_active("listbox", true); + m_xContent3ToolBox->set_item_sensitive("listbox", bFloatingNavigator); + +// TreeListBox for global document + m_xGlobalTree->set_selection_mode(SelectionMode::Multiple); + +// Handler + Link<const OString&, void> aLk = LINK(this, SwNavigationPI, ToolBoxSelectHdl); + m_xContent1ToolBox->connect_clicked(aLk); + m_xContent2ToolBox->connect_clicked(aLk); + m_xContent3ToolBox->connect_clicked(aLk); + m_xGlobalToolBox->connect_clicked(aLk); + m_xDocListBox->connect_changed(LINK(this, SwNavigationPI, DocListBoxSelectHdl)); + m_xContent2ToolBox->set_item_menu("headings", m_xHeadingsMenu.get()); + m_xHeadingsMenu->connect_activate(LINK(this, SwNavigationPI, HeadingsMenuSelectHdl)); + m_xContent2ToolBox->connect_menu_toggled(LINK(this, SwNavigationPI, ToolBox2DropdownClickHdl)); + m_xContent3ToolBox->set_item_menu("dragmode", m_xDragModeMenu.get()); + m_xDragModeMenu->connect_activate(LINK(this, SwNavigationPI, DropModeMenuSelectHdl)); + m_xContent3ToolBox->connect_menu_toggled(LINK(this, SwNavigationPI, ToolBox3DropdownClickHdl)); + 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); + +// set toolbar of both modes to widest of each + m_xGlobalToolBox->set_size_request(m_xContent1ToolBox->get_preferred_size().Width(), -1); + + StartListening(*SfxGetpApp()); + + if(IsGlobalDoc()) + { + SwView *pActView = GetCreateView(); + 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 = GetOptimalSize(); +} + +SwNavigationPI::~SwNavigationPI() +{ + disposeOnce(); +} + +void SwNavigationPI::dispose() +{ + if (IsGlobalDoc() && !IsGlobalMode()) + { + SwView *pView = GetCreateView(); + SwWrtShell &rSh = pView->GetWrtShell(); + if (!rSh.IsAllProtect()) + pView->GetDocShell()->SetReadOnlyUI(false); + } + + EndListening(*SfxGetpApp()); + + if (m_pxObjectShell) + { + if (m_pxObjectShell->Is()) + (*m_pxObjectShell)->DoClose(); + m_pxObjectShell.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_xContent1Dispatch.reset(); + m_xContent1ToolBox.reset(); + m_xContent2ToolBox.reset(); + m_xContent3ToolBox.reset(); + + m_aPageChgIdle.Stop(); + + m_aDocFullName.dispose(); + m_aPageStats.dispose(); + + PanelLayout::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) + { + SwView *pActView = GetCreateView(); + if(pActView) + { + SwWrtShell &rSh = pActView->GetWrtShell(); + m_xEdit->set_max(rSh.GetPageCnt()); + m_xEdit->set_width_chars(3); + } + } +} + +void SwNavigationPI::StateChanged(StateChangedType nStateChange) +{ + PanelLayout::StateChanged(nStateChange); + if (nStateChange == StateChangedType::InitShow) + { + // 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. + m_xContent3ToolBox->set_item_sensitive("listbox", SfxChildWindowContext::GetFloatingWindow(GetParent()) != nullptr); + // show content if docked + if (SfxChildWindowContext::GetFloatingWindow(GetParent()) == nullptr && IsZoomedIn()) + ZoomOut(); + } + else if (nStateChange == StateChangedType::ControlFocus) + { + if (m_xContentTree) + { + // 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; + } + } + else + { + if (const SfxEventHint* pHint = dynamic_cast<const SfxEventHint*>(&rHint)) + { + SfxEventHintId eEventId = pHint->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 OString&, rMenuId, void ) +{ + if (!rMenuId.isEmpty()) + m_xContentTree->SetOutlineLevel(rMenuId.toUInt32()); +} + +void SwNavigationPI::UpdateListBox() +{ + if (isDisposed()) + 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 ) + { + 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_pxObjectShell.reset( new SfxObjectShellLock(pFrame->GetObjectShell()) ); + FillBox(); + } + } +} + +OUString SwNavigationPI::CreateDropFileName( 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_pxObjectShell) + { + m_xContentTree->SetHiddenShell( nullptr ); + (*m_pxObjectShell)->DoClose(); + m_pxObjectShell.reset(); + } + SfxStringItem aFileItem(SID_FILE_NAME, sFileName ); + SfxStringItem aOptionsItem( SID_OPTIONS, "HRC" ); + SfxLinkItem aLink( SID_DONELINK, + LINK( this, SwNavigationPI, DoneLink ) ); + GetActiveView()->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_xContent3ToolBox->set_item_icon_name("dragmode", sImageId); +} + +void SwNavigationPI::ToggleTree() +{ + bool bGlobalDoc = IsGlobalDoc(); + if (!IsGlobalMode() && bGlobalDoc) + { + SetUpdateMode(false); + 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_xDocListBox->hide(); + SetGlobalMode(true); + SetUpdateMode(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_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 (IsDisposed()) + 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(); +} + +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; +} + +SwNavigationChild::SwNavigationChild( vcl::Window* pParent, + sal_uInt16 nId, + SfxBindings* _pBindings ) + : SfxChildWindowContext( nId ) +{ + Reference< XFrame > xFrame = _pBindings->GetActiveFrame(); + VclPtr< SwNavigationPI > pNavi = VclPtr< SwNavigationPI >::Create( pParent, xFrame, _pBindings ); + _pBindings->Invalidate(SID_NAVIGATOR); + + SwNavigationConfig* pNaviConfig = SW_MOD()->GetNavigationConfig(); + + const ContentTypeId nRootType = pNaviConfig->GetRootType(); + if( nRootType != ContentTypeId::UNKNOWN ) + { + pNavi->m_xContentTree->SetRootType(nRootType); + pNavi->m_xContent2ToolBox->set_item_active("root", true); + if (nRootType == ContentTypeId::OUTLINE) + { + pNavi->m_xContentTree->set_selection_mode(SelectionMode::Multiple); + } + } + pNavi->m_xContentTree->SetOutlineLevel( static_cast< sal_uInt8 >( pNaviConfig->GetOutlineLevel() ) ); + pNavi->SetRegionDropMode( pNaviConfig->GetRegionMode() ); + + if (SfxNavigator* pNav = dynamic_cast<SfxNavigator*>(pParent)) + { + pNav->SetMinOutputSizePixel(pNavi->GetOptimalSize()); + if (pNaviConfig->IsSmall()) + pNavi->ZoomIn(); + } + + SetWindow(pNavi); +} + +/* 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 000000000..4b4b6acb7 --- /dev/null +++ b/sw/source/uibase/utlui/numfmtlb.cxx @@ -0,0 +1,473 @@ +/* -*- 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/zformat.hxx> +#include <svl/eitem.hxx> +#include <svx/svxids.hrc> +#include <svx/numinf.hxx> +#include <svx/flagsdef.hxx> +#include <svl/itemset.hxx> +#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() + : nCurrFormatType(SvNumFormatType::ALL) + , mbCurrFormatTypeNeedsInit(true) + , nStdEntry(0) + , bOneArea(false) + , nDefFormat(0) + , bShowLanguageControl(false) + , 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() +{ + SwView *pView = GetActiveView(); + + if (pView) + eCurLanguage = pView->GetWrtShell().GetCurLang(); + else + eCurLanguage = SvtSysLocale().GetLanguageTag().getLanguageType(); + + SetFormatType(SvNumFormatType::NUMBER); + SetDefFormat(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 && + (nCurrFormatType & nFormatType)) // there are mixed formats, like for example DateTime + return; + + SwView *pView = GetActiveView(); + OSL_ENSURE(pView, "no view found"); + 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; + Color* pCol; + double fVal = SwNumFormatBase::GetDefValue(nFormatType); + OUString sValue; + + const sal_uInt32 nSysNumFormat = pFormatter->GetFormatIndex( + NF_NUMBER_SYSTEM, eCurLanguage ); + const sal_uInt32 nSysShortDateFormat = pFormatter->GetFormatIndex( + NF_DATE_SYSTEM_SHORT, eCurLanguage ); + const sal_uInt32 nSysLongDateFormat = pFormatter->GetFormatIndex( + NF_DATE_SYSTEM_LONG, eCurLanguage ); + + for( long nIndex = eOffsetStart; nIndex <= eOffsetEnd; ++nIndex ) + { + const sal_uInt32 nFormat = pFormatter->GetFormatIndex( + static_cast<NfIndexTableOffset>(nIndex), eCurLanguage ); + pFormat = pFormatter->GetEntry( nFormat ); + + if( nFormat == pFormatter->GetFormatIndex( NF_NUMBER_STANDARD, + 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, eCurLanguage ) ) + nStdEntry = i; + ++i; + } + } + + append_text(SwResId(STR_DEFINE_NUMBERFORMAT)); + + set_active(nStdEntry); + + nCurrFormatType = nFormatType; + mbCurrFormatTypeNeedsInit = false; + +} + +void SwNumFormatBase::SetDefFormat(const sal_uInt32 nDefaultFormat) +{ + if (nDefaultFormat == NUMBERFORMAT_ENTRY_NOT_FOUND) + { + nDefFormat = nDefaultFormat; + return; + } + + SwView *pView = GetActiveView(); + OSL_ENSURE(pView, "no view found"); + if(!pView) + return; + SwWrtShell &rSh = pView->GetWrtShell(); + SvNumberFormatter* pFormatter = rSh.GetNumberFormatter(); + + SvNumFormatType nType = pFormatter->GetType(nDefaultFormat); + + SetFormatType(nType); + + sal_uInt32 nFormat = pFormatter->GetFormatForLanguageIfBuiltIn(nDefaultFormat, eCurLanguage); + + for (sal_Int32 i = 0, nCount = get_count(); i < nCount; ++i) + { + if (nFormat == get_id(i).toUInt32()) + { + set_active(i); + nStdEntry = i; + nDefFormat = GetFormat(); + return; + } + } + + // No entry found: + OUString sValue; + 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, eCurLanguage) ) + { + sValue += SwResId(RID_STR_SYSTEM); + } + + insert_text(nPos, sValue); // Insert as first numeric entry + set_id(nPos, OUString::number(nDefaultFormat)); + set_active(nPos); + 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(); + + SfxItemSet aCoreSet( + rSh.GetAttrPool(), + svl::Items< + 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>{}); + + double fValue = SwNumFormatBase::GetDefValue(nCurrFormatType); + + sal_uInt32 nFormat = pFormatter->GetStandardFormat( nCurrFormatType, eCurLanguage); + aCoreSet.Put( SfxUInt32Item( SID_ATTR_NUMBERFORMAT_VALUE, nFormat )); + + aCoreSet.Put( SvxNumberInfoItem( pFormatter, fValue, + SID_ATTR_NUMBERFORMAT_INFO ) ); + + if( (SvNumFormatType::DATE | SvNumFormatType::TIME) & nCurrFormatType ) + aCoreSet.Put(SfxBoolItem(SID_ATTR_NUMBERFORMAT_ONE_AREA, bOneArea)); + + aCoreSet.Put(SfxBoolItem(SID_ATTR_NUMBERFORMAT_NOLANGUAGE, !bShowLanguageControl)); + aCoreSet.Put(SfxBoolItem(SID_ATTR_NUMBERFORMAT_ADD_AUTO, 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 SfxPoolItem* pItem = pView->GetDocShell()-> + GetItem( SID_ATTR_NUMBERFORMAT_INFO ); + + if( pItem ) + { + for ( sal_uInt32 key : static_cast<const SvxNumberInfoItem*>(pItem)->GetDelFormats() ) + pFormatter->DeleteEntry( key ); + } + + const SfxItemSet* pOutSet = pDlg->GetOutputItemSet(); + if( SfxItemState::SET == pOutSet->GetItemState( + SID_ATTR_NUMBERFORMAT_VALUE, false, &pItem )) + { + sal_uInt32 nNumberFormat = static_cast<const SfxUInt32Item*>(pItem)->GetValue(); + // oj #105473# change order of calls + const SvNumberformat* pFormat = pFormatter->GetEntry(nNumberFormat); + if( pFormat ) + eCurLanguage = pFormat->GetLanguage(); + // SetDefFormat uses eCurLanguage to look for if this format already in the list + SetDefFormat(nNumberFormat); + } + if( bShowLanguageControl && SfxItemState::SET == pOutSet->GetItemState( + SID_ATTR_NUMBERFORMAT_ADD_AUTO, false, &pItem )) + { + bUseAutomaticLanguage = static_cast<const SfxBoolItem*>(pItem)->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; + 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 000000000..2cefdc4ff --- /dev/null +++ b/sw/source/uibase/utlui/prcntfld.cxx @@ -0,0 +1,228 @@ +/* -*- 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)) + , nOldMax(0) + , nOldMin(0) + , nLastPercent(-1) + , nLastValue(-1) + , nOldDigits(m_pField->get_digits()) + , eOldUnit(FieldUnit::NONE) + , bLockAutoCalculation(false) +{ + int nMin, nMax; + m_pField->get_range(nMin, nMax, FieldUnit::TWIP); + nRefValue = DenormalizePercent(nMax); + m_pField->get_increments(nOldSpinSize, nOldPageSize, FieldUnit::NONE); +} + +void SwPercentField::SetRefValue(int nValue) +{ + int nRealValue = GetRealValue(eOldUnit); + + nRefValue = nValue; + + if (!bLockAutoCalculation && (m_pField->get_unit() == FieldUnit::PERCENT)) + set_value(nRealValue, eOldUnit); +} + +void SwPercentField::ShowPercent(bool bPercent) +{ + if ((bPercent && m_pField->get_unit() == FieldUnit::PERCENT) || + (!bPercent && m_pField->get_unit() != FieldUnit::PERCENT)) + return; + + int nOldValue; + + if (bPercent) + { + nOldValue = get_value(); + + eOldUnit = m_pField->get_unit(); + nOldDigits = m_pField->get_digits(); + m_pField->get_range(nOldMin, nOldMax, FieldUnit::NONE); + m_pField->get_increments(nOldSpinSize, nOldPageSize, FieldUnit::NONE); + m_pField->set_unit(FieldUnit::PERCENT); + m_pField->set_digits(0); + + int nCurrentWidth = vcl::ConvertValue(nOldMin, 0, nOldDigits, eOldUnit, FieldUnit::TWIP); + // round to 0.5 percent + int nPercent = nRefValue ? (((nCurrentWidth * 10) / 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 != nLastValue) + { + nCurrentWidth = vcl::ConvertValue(nOldValue, 0, nOldDigits, eOldUnit, FieldUnit::TWIP); + nPercent = nRefValue ? (((nCurrentWidth * 10) / nRefValue + 5) / 10) : 0; + m_pField->set_value(nPercent, FieldUnit::NONE); + nLastPercent = nPercent; + nLastValue = nOldValue; + } + else + m_pField->set_value(nLastPercent, FieldUnit::NONE); + } + else + { + int nOldPercent = get_value(FieldUnit::PERCENT); + + nOldValue = Convert(get_value(), m_pField->get_unit(), eOldUnit); + + m_pField->set_unit(eOldUnit); + m_pField->set_digits(nOldDigits); + m_pField->set_range(nOldMin, nOldMax, FieldUnit::NONE); + m_pField->set_increments(nOldSpinSize, nOldPageSize, FieldUnit::NONE); + + if (nOldPercent != nLastPercent) + { + set_value(nOldValue, eOldUnit); + nLastPercent = nOldPercent; + nLastValue = nOldValue; + } + else + set_value(nLastValue, eOldUnit); + } +} + +void SwPercentField::set_value(int 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 + int nPercent, nCurrentWidth; + if(eInUnit == FieldUnit::TWIP) + { + nCurrentWidth = vcl::ConvertValue(nNewValue, 0, nOldDigits, FieldUnit::TWIP, FieldUnit::TWIP); + } + else + { + int nValue = Convert(nNewValue, eInUnit, eOldUnit); + nCurrentWidth = vcl::ConvertValue(nValue, 0, nOldDigits, eOldUnit, FieldUnit::TWIP); + } + nPercent = nRefValue ? (((nCurrentWidth * 10) / nRefValue + 5) / 10) : 0; + m_pField->set_value(nPercent, FieldUnit::NONE); + } +} + +int SwPercentField::get_value(FieldUnit eOutUnit) +{ + return Convert(m_pField->get_value(FieldUnit::NONE), m_pField->get_unit(), eOutUnit); +} + +void SwPercentField::set_min(int nNewMin, FieldUnit eInUnit) +{ + if (m_pField->get_unit() != FieldUnit::PERCENT) + m_pField->set_min(nNewMin, eInUnit); + else + { + if (eInUnit == FieldUnit::NONE) + eInUnit = eOldUnit; + nOldMin = Convert(nNewMin, eInUnit, eOldUnit); + + int nPercent = Convert(nNewMin, eInUnit, FieldUnit::PERCENT); + m_pField->set_min(std::max(1, nPercent), FieldUnit::NONE); + } +} + +void SwPercentField::set_max(int nNewMax, FieldUnit eInUnit) +{ + if (m_pField->get_unit() != FieldUnit::PERCENT) + m_pField->set_max(nNewMax, eInUnit); +} + +int SwPercentField::NormalizePercent(int nValue) +{ + if (m_pField->get_unit() != FieldUnit::PERCENT) + nValue = m_pField->normalize(nValue); + else + nValue = nValue * ImpPower10(nOldDigits); + return nValue; +} + +int SwPercentField::DenormalizePercent(int nValue) +{ + if (m_pField->get_unit() != FieldUnit::PERCENT) + nValue = m_pField->denormalize(nValue); + else + { + int nFactor = ImpPower10(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; +} + +int 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); +} + +int SwPercentField::Convert(int 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 + int nTwipValue = (nRefValue * nValue + 50) / 100; + + if (eOutUnit == FieldUnit::TWIP) // Only convert if necessary + return NormalizePercent(nTwipValue); + else + return vcl::ConvertValue(NormalizePercent(nTwipValue), 0, nOldDigits, FieldUnit::TWIP, eOutUnit); + } + + if (eOutUnit == FieldUnit::PERCENT) + { + // Convert to percent + int nCurrentWidth; + nValue = DenormalizePercent(nValue); + + if (eInUnit == FieldUnit::TWIP) // Only convert if necessary + nCurrentWidth = nValue; + else + nCurrentWidth = vcl::ConvertValue(nValue, 0, nOldDigits, eInUnit, FieldUnit::TWIP); + // Round to 0.5 percent + return nRefValue ? (((nCurrentWidth * 1000) / nRefValue + 5) / 10) : 0; + } + + return vcl::ConvertValue(nValue, 0, 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 000000000..dbdf78b49 --- /dev/null +++ b/sw/source/uibase/utlui/shdwcrsr.cxx @@ -0,0 +1,119 @@ +/* -*- 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 <vcl/window.hxx> +#include <shdwcrsr.hxx> + +using namespace ::com::sun::star; + +SwShadowCursor::~SwShadowCursor() +{ + if( USHRT_MAX != nOldMode ) + DrawCursor( aOldPt, nOldHeight, nOldMode ); +} + +void SwShadowCursor::SetPos( const Point& rPt, long nHeight, sal_uInt16 nMode ) +{ + Point aPt( pWin->LogicToPixel( rPt )); + nHeight = pWin->LogicToPixel( Size( 0, nHeight )).Height(); + if( aOldPt != aPt || nOldHeight != nHeight || nOldMode != nMode ) + { + if( USHRT_MAX != nOldMode ) + DrawCursor( aOldPt, nOldHeight, nOldMode ); + + DrawCursor( aPt, nHeight, nMode ); + nOldMode = nMode; + nOldHeight = nHeight; + aOldPt = aPt; + } +} + +void SwShadowCursor::DrawTri( const Point& rPt, long nHeight, bool bLeft ) +{ + long nLineDiff = nHeight / 2; + long nLineDiffHalf = nLineDiff / 2; + + // Dot above + Point aPt1( (bLeft ? rPt.X() - 3 : rPt.X() + 3), + rPt.Y() + nLineDiffHalf ); + // Dot below + Point aPt2( aPt1.X(), aPt1.Y() + nHeight - nLineDiff - 1 ); + long nDiff = bLeft ? -1 : 1; + while( aPt1.Y() <= aPt2.Y() ) + { + pWin->DrawLine( aPt1, aPt2 ); + aPt1.AdjustY( 1 ); + aPt2.AdjustY( -1 ); + aPt2.setX( aPt1.AdjustX(nDiff ) ); + } +} + +void SwShadowCursor::DrawCursor( const Point& rPt, long nHeight, sal_uInt16 nMode ) +{ + nHeight = (((nHeight / 4)+1) * 4) + 1; + + pWin->Push(); + + pWin->SetMapMode(MapMode(MapUnit::MapPixel)); + pWin->SetRasterOp( RasterOp::Xor ); + + pWin->SetLineColor( Color( sal_uInt32(aCol) ^ sal_uInt32(COL_WHITE) ) ); + + // 1. The Line: + pWin->DrawLine( Point( rPt.X(), rPt.Y() + 1), + Point( rPt.X(), rPt.Y() - 2 + nHeight )); + + // 2. The Triangle + if( text::HoriOrientation::LEFT == nMode || text::HoriOrientation::CENTER == nMode ) // Arrow to the right + DrawTri( rPt, nHeight, false ); + if( text::HoriOrientation::RIGHT == nMode || text::HoriOrientation::CENTER == nMode ) // Arrow to the left + DrawTri( rPt, nHeight, true ); + + pWin->Pop(); +} + +void SwShadowCursor::Paint() +{ + if( USHRT_MAX != nOldMode ) + DrawCursor( aOldPt, nOldHeight, nOldMode ); +} + +tools::Rectangle SwShadowCursor::GetRect() const +{ + long nH = nOldHeight; + Point aPt( aOldPt ); + + nH = (((nH / 4)+1) * 4) + 1; + long nWidth = nH / 4 + 3 + 1; + + Size aSz( nWidth, nH ); + + if( text::HoriOrientation::RIGHT == nOldMode ) + aPt.AdjustX( -(aSz.Width()) ); + else if( text::HoriOrientation::CENTER == nOldMode ) + { + aPt.AdjustX( -(aSz.Width()) ); + aSz.setWidth( aSz.Width() * 2 ); + } + + return pWin->PixelToLogic( tools::Rectangle( aPt, aSz ) ); +} + +/* 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 000000000..2220c776e --- /dev/null +++ b/sw/source/uibase/utlui/tmplctrl.cxx @@ -0,0 +1,142 @@ +/* -*- 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 <vcl/menu.hxx> +#include <svl/stritem.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/viewfrm.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/status.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 ); + +namespace { + +class SwTemplatePopup_Impl : public PopupMenu +{ +public: + SwTemplatePopup_Impl(); + + sal_uInt16 GetCurId() const { return nCurId; } + +private: + sal_uInt16 nCurId; + + virtual void Select() override; +}; + +} + +SwTemplatePopup_Impl::SwTemplatePopup_Impl() : + PopupMenu(), + nCurId(USHRT_MAX) +{ +} + +void SwTemplatePopup_Impl::Select() +{ + nCurId = GetCurItemId(); +} + +SwTemplateControl::SwTemplateControl( sal_uInt16 _nSlotId, + sal_uInt16 _nId, + StatusBar& rStb ) : + SfxStatusBarControl( _nSlotId, _nId, rStb ) +{ + GetStatusBar().SetQuickHelpText(GetId(), SwResId(STR_TMPLCTRL_HINT)); +} + +SwTemplateControl::~SwTemplateControl() +{ +} + +void SwTemplateControl::StateChanged( + sal_uInt16 /*nSID*/, SfxItemState eState, const SfxPoolItem* pState ) +{ + const SfxStringItem* pItem = nullptr; + if (SfxItemState::DEFAULT == eState && (pItem = dynamic_cast<const SfxStringItem*>(pState))) + { + sTemplate = pItem->GetValue(); + GetStatusBar().SetItemText(GetId(), sTemplate); + } + else + GetStatusBar().SetItemText(GetId(), OUString()); +} + +void SwTemplateControl::Paint( const UserDrawEvent& ) +{ +} + +void SwTemplateControl::Command( const CommandEvent& rCEvt ) +{ + if ( rCEvt.GetCommand() == CommandEventId::ContextMenu && + !GetStatusBar().GetItemText( GetId() ).isEmpty() ) + { + ScopedVclPtrInstance<SwTemplatePopup_Impl> aPop; + { + 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) + { + sal_uInt16 nCount = 0; + SfxStyleSheetBase* pStyle = xIter->First(); + while( pStyle ) + { + aPop->InsertItem( ++nCount, pStyle->GetName() ); + pStyle = xIter->Next(); + } + + aPop->Execute( &GetStatusBar(), rCEvt.GetMousePosPixel()); + const sal_uInt16 nCurrId = aPop->GetCurId(); + if( nCurrId != USHRT_MAX) + { + // 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 000000000..e6673587c --- /dev/null +++ b/sw/source/uibase/utlui/uiitems.cxx @@ -0,0 +1,275 @@ +/* -*- 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 <editeng/itemtype.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 ), + 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) + && aFootnoteInfo == static_cast<const SwPageFootnoteInfoItem&>(rAttr).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(aFootnoteInfo.GetHeight()));break; + case MID_LINE_WEIGHT : rVal <<= static_cast<sal_Int16>(convertTwipToMm100(aFootnoteInfo.GetLineWidth()));break; + case MID_LINE_COLOR : rVal <<= aFootnoteInfo.GetLineColor();break; + case MID_LINE_RELWIDTH : + { + Fraction aTmp( 100, 1 ); + aTmp *= aFootnoteInfo.GetWidth(); + rVal <<= static_cast<sal_Int8>(static_cast<long>(aTmp)); + } + break; + case MID_LINE_ADJUST : rVal <<= static_cast<sal_Int16>(aFootnoteInfo.GetAdj());break;//text::HorizontalAdjust + case MID_LINE_TEXT_DIST : rVal <<= static_cast<sal_Int32>(convertTwipToMm100(aFootnoteInfo.GetTopDist()));break; + case MID_LINE_FOOTNOTE_DIST: rVal <<= static_cast<sal_Int32>(convertTwipToMm100(aFootnoteInfo.GetBottomDist()));break; + case MID_FTN_LINE_STYLE : + { + switch ( 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; + 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 = convertMm100ToTwip(nSet32); + switch(nMemberId & ~CONVERT_TWIPS) + { + case MID_FTN_HEIGHT: aFootnoteInfo.SetHeight(nSet32); break; + case MID_LINE_TEXT_DIST: aFootnoteInfo.SetTopDist(nSet32);break; + case MID_LINE_FOOTNOTE_DIST: aFootnoteInfo.SetBottomDist(nSet32);break; + } + } + break; + case MID_LINE_WEIGHT : + { + sal_Int16 nSet = 0; + rVal >>= nSet; + if(nSet >= 0) + aFootnoteInfo.SetLineWidth(convertMm100ToTwip(nSet)); + else + bRet = false; + } + break; + case MID_LINE_RELWIDTH : + { + sal_Int8 nSet = 0; + rVal >>= nSet; + if(nSet < 0) + bRet = false; + else + aFootnoteInfo.SetWidth(Fraction(nSet, 100)); + } + break; + case MID_LINE_ADJUST : + { + sal_Int16 nSet = 0; + rVal >>= nSet; + if(nSet >= 0 && nSet < 3) //text::HorizontalAdjust + 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; + } + aFootnoteInfo.SetLineStyle( eStyle ); + } + break; + default: + bRet = false; + } + return bRet; +} + +SwPtrItem::SwPtrItem( const sal_uInt16 nId, void* pPtr ) : + SfxPoolItem( nId ), + pMisc(pPtr) +{ +} + +// Cloning + +SwPtrItem* SwPtrItem::Clone( SfxItemPool * /*pPool*/ ) const +{ + return new SwPtrItem( *this ); +} + +bool SwPtrItem::operator==( const SfxPoolItem& rAttr ) const +{ + return SfxPoolItem::operator==(rAttr) + && pMisc == static_cast<const SwPtrItem&>(rAttr).pMisc; +} + +// SwUINumRuleItem for the NumTabPages of the FormatNumRule/Styleists + +SwUINumRuleItem::SwUINumRuleItem( const SwNumRule& rRul ) + : SfxPoolItem( FN_PARAM_ACT_NUMBER ), pRule( new SwNumRule( rRul ) ) +{ +} + +SwUINumRuleItem::SwUINumRuleItem( const SwUINumRuleItem& rItem ) + : SfxPoolItem( rItem ), + pRule( new SwNumRule( *rItem.pRule )) +{ +} + +SwUINumRuleItem::~SwUINumRuleItem() +{ +} + +SwUINumRuleItem* SwUINumRuleItem::Clone( SfxItemPool * /*pPool*/ ) const +{ + return new SwUINumRuleItem( *this ); +} + +bool SwUINumRuleItem::operator==( const SfxPoolItem& rAttr ) const +{ + return SfxPoolItem::operator==(rAttr) + && *pRule == *static_cast<const SwUINumRuleItem&>(rAttr).pRule; +} + +bool SwUINumRuleItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/ ) const +{ + uno::Reference< container::XIndexReplace >xRules = new SwXNumberingRules(*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 = comphelper::getUnoTunnelImplementation<SwXNumberingRules>(xRulesRef); + if(pSwXRules) + { + *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 000000000..fb41aaa6f --- /dev/null +++ b/sw/source/uibase/utlui/uitool.cxx @@ -0,0 +1,848 @@ +/* -*- 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/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 <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 <poolfmt.hxx> +#include <usrpref.hxx> + +#include <cmdid.h> +#include <doc.hxx> +#include <docary.hxx> +#include <charfmt.hxx> +#include <SwStyleNameMapper.hxx> +#include <strings.hrc> +// 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)); + const SfxPoolItem *pBoxInfo; + + if ( SfxItemState::SET == rSet.GetItemState( SID_ATTR_BORDER_INNER, true, &pBoxInfo)) + { + aBoxInfo.reset(static_cast<SvxBoxInfoItem*>(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) +{ + // Background / highlight + { + // Always use the visible background + const SfxPoolItem *pTmpBrush; + if( SfxItemState::SET == rSet.GetItemState( RES_CHRATR_HIGHLIGHT, true, &pTmpBrush ) ) + { + SvxBrushItem aTmpBrush( *static_cast<const SvxBrushItem*>(pTmpBrush) ); + if( aTmpBrush.GetColor() != COL_TRANSPARENT ) + { + aTmpBrush.SetWhich( RES_CHRATR_BACKGROUND ); + rSet.Put( aTmpBrush ); + } + } + } + + // 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 + const sal_uInt16* pRanges = rSet.GetRanges(); + const sal_uInt16* pEnd = pRanges; + while (*pEnd) + ++pEnd; + const uno::Sequence<sal_uInt16> aOrigRanges(pRanges, pEnd - pRanges + 1); + aGrabBag.GetGrabBag()["OrigItemSetRanges"] <<= aOrigRanges; + rSet.MergeRange(RES_PARATR_GRABBAG, RES_PARATR_GRABBAG); + rSet.Put(aGrabBag); +} + +void ConvertAttrGenToChar(SfxItemSet& rSet, const SfxItemSet& rOrigSet) +{ + // Background / highlighting + const SfxPoolItem *pTmpItem; + if( SfxItemState::SET == rSet.GetItemState( RES_CHRATR_BACKGROUND, false, &pTmpItem ) ) + { + // 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 (SfxItemState::SET == rOrigSet.GetItemState(RES_CHRATR_GRABBAG, false, &pTmpItem)) + { + SfxGrabBagItem aGrabBag(*static_cast<const SfxGrabBagItem*>(pTmpItem)); + std::map<OUString, css::uno::Any>& rMap = aGrabBag.GetGrabBag(); + auto aIterator = rMap.find("CharShadingMarker"); + if( aIterator != rMap.end() ) + { + aIterator->second <<= false; + } + rSet.Put( aGrabBag ); + } + } + rSet.ClearItem( RES_BACKGROUND ); + + if (SfxItemState::SET == rOrigSet.GetItemState(RES_PARATR_GRABBAG, false, &pTmpItem)) + { + SfxGrabBagItem aGrabBag(*static_cast<const SfxGrabBagItem*>(pTmpItem)); + std::map<OUString, css::uno::Any>& rMap = aGrabBag.GetGrabBag(); + auto aIterator = rMap.find("OrigItemSetRanges"); + if (aIterator != rMap.end()) + { + if (uno::Sequence<sal_uInt16> aOrigRanges; (aIterator->second >>= aOrigRanges) + && aOrigRanges.getLength() % 2 == 1 + && *(std::cend(aOrigRanges) - 1) == 0) + rSet.SetRanges(aOrigRanges.getConstArray()); + } + } + assert(SfxItemState::SET != rSet.GetItemState(RES_PARATR_GRABBAG, false)); +} + +void ApplyCharBackground(const Color& rBackgroundColor, SwWrtShell& rShell) +{ + rShell.StartUndo(SwUndoId::INSATTR); + + SfxItemSet aCoreSet(rShell.GetView().GetPool(), svl::Items< + RES_CHRATR_GRABBAG, RES_CHRATR_GRABBAG>{}); + + rShell.GetCurAttr(aCoreSet); + + // Set char background + rShell.SetAttrItem(SvxBrushItem(rBackgroundColor, 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 + const SfxPoolItem *pTmpItem; + if (SfxItemState::SET == aCoreSet.GetItemState(RES_CHRATR_GRABBAG, false, &pTmpItem)) + { + SfxGrabBagItem aGrabBag(*static_cast<const SfxGrabBagItem*>(pTmpItem)); + 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; + + // 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 + const SfxPoolItem* pItem; + if( SfxItemState::SET == rSet.GetItemState( SID_ATTR_PAGE_HEADERSET, + false, &pItem ) ) + { + const SfxItemSet& rHeaderSet = static_cast<const SvxSetItem*>(pItem)->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( SfxItemState::SET == rSet.GetItemState( SID_ATTR_PAGE_FOOTERSET, + false, &pItem ) ) + { + const SfxItemSet& rFooterSet = static_cast<const SvxSetItem*>(pItem)->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( SfxItemState::SET == rSet.GetItemState( FN_PARAM_FTN_INFO, + false, &pItem ) ) + rPageDesc.SetFootnoteInfo( static_cast<const SwPageFootnoteInfoItem*>(pItem)->GetPageFootnoteInfo() ); + + // Columns + + // Register compliant + + if(SfxItemState::SET == rSet.GetItemState( + SID_SWREGISTER_MODE, false, &pItem)) + { + bool bSet = static_cast<const SfxBoolItem*>(pItem)->GetValue(); + if(!bSet) + rPageDesc.SetRegisterFormatColl(nullptr); + else if(SfxItemState::SET == rSet.GetItemState( + SID_SWREGISTER_COLLECTION, false, &pItem)) + { + const OUString& rColl = static_cast<const SfxStringItem*>(pItem)->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 ); + } + } +} + +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)); + const SfxPoolItem *pBoxInfo; + + if ( SfxItemState::SET == rSet.GetItemState( SID_ATTR_BORDER_INNER, true, &pBoxInfo) ) + { + aBoxInfo.reset(static_cast<SvxBoxInfoItem*>(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 + SfxItemSet aHeaderSet(*rSet.GetPool(), + svl::Items<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>{}); + + // 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 + SfxItemSet aFooterSet(*rSet.GetPool(), + svl::Items<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>{}); + + // 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())); + +} + +// 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( SfxItemState::SET == rSet.GetItemState( SID_ATTR_PARA_MODEL, false, &pItem )) + { + const OUString& rDescName = static_cast<const SvxPageModelItem*>(pItem)->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 + { + SfxItemSet aCoreSet(rShell.GetView().GetPool(), svl::Items<RES_PAGEDESC, RES_PAGEDESC>{} ); + rShell.GetCurAttr( aCoreSet ); + if(SfxItemState::SET == aCoreSet.GetItemState( RES_PAGEDESC, true, &pItem ) ) + { + if( static_cast<const SwFormatPageDesc*>(pItem)->GetPageDesc() ) + { + aPgDesc.RegisterToPageDesc( *const_cast<SwFormatPageDesc*>(static_cast<const SwFormatPageDesc*>(pItem))->GetPageDesc() ); + } + } + } + + if(bChanged) + rSet.Put( aPgDesc ); +} + +// Inquire if in the set is a Sfx-PageDesc combination present and return it. +void SwToSfxPageDescAttr( SfxItemSet& rCoreSet ) +{ + const SfxPoolItem* pItem = nullptr; + OUString aName; + ::std::optional<sal_uInt16> oNumOffset; + bool bPut = true; + switch( rCoreSet.GetItemState( RES_PAGEDESC, true, &pItem ) ) + { + case SfxItemState::SET: + { + if( static_cast<const SwFormatPageDesc*>(pItem)->GetPageDesc() ) + { + aName = static_cast<const SwFormatPageDesc*>(pItem)->GetPageDesc()->GetName(); + oNumOffset = static_cast<const SwFormatPageDesc*>(pItem)->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( PopupMenu const & rMenu, SfxViewFrame const & rViewFrame, sal_uInt16 nId ) +{ + bool bRet = false; + const sal_uInt16 nItemCount = rMenu.GetItemCount(); + OUString sCommand; + for( sal_uInt16 nItem = 0; nItem < nItemCount; ++nItem) + { + PopupMenu* pPopup = rMenu.GetPopupMenu( rMenu.GetItemId( nItem ) ); + if(pPopup) + { + sCommand = pPopup->GetItemCommand(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 000000000..fbad314f1 --- /dev/null +++ b/sw/source/uibase/utlui/unotools.cxx @@ -0,0 +1,510 @@ +/* -*- 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 <strings.hrc> +#include <unotools.hxx> +#include <unoprnms.hxx> +#include <i18nutil/unicode.hxx> +#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 <docsh.hxx> +#include <editsh.hxx> +#include <swmodule.hxx> +#include <TextCursorHelper.hxx> +#include <doc.hxx> + +using namespace ::com::sun::star; + +const char cFactory[] = "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::makeAny(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::makeAny(true)); + } +} + +static const sal_Int16 nZoomValues[] = +{ + 20, + 40, + 50, + 75, + 100 +}; + +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); + + auto pCursor = comphelper::getUnoTunnelImplementation<OTextCursorHelper>(m_xCursor); + if (pCursor) + { + 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(PushFlags::ALL); + m_xVirDev->SetMapMode(MapMode(MapUnit::MapTwip)); + SwDoc *pDoc = pCursor->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); + 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(); + m_xCursor = xText->createTextCursor(); + + //From here, a cursor is defined, which goes through the template, + //and overwrites the template words where it is necessary. + + auto pCursor = comphelper::getUnoTunnelImplementation<OTextCursorHelper>(m_xCursor); + + SwDoc *pDoc = pCursor ? pCursor->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), sal_uInt16(1), true)); + + TOXTypes eTypes[] = { TOX_INDEX, TOX_USER, TOX_CONTENT }; + for (auto eType : eTypes) + { + const SwTOXType* pTOXType = pDoc->GetTOXType(eType, 0); + SwTOXMarks aMarks; + SwTOXMark::InsertTOXMarks(aMarks, *pTOXType); + 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::Reference< beans::XPropertySet > xCursorProp(m_xCursor, uno::UNO_QUERY); + uno::Any aPageStyle = xCursorProp->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() +{ + uno::Reference< lang::XUnoTunnel> xTunnel( m_xCursor, uno::UNO_QUERY); + if( xTunnel.is() ) + { + OTextCursorHelper* pCursor = reinterpret_cast<OTextCursorHelper*>(xTunnel->getSomething( + OTextCursorHelper::getUnoTunnelId()) ); + if( pCursor ) + { + SwDoc* pDoc = pCursor->GetDoc(); + SwEditShell* pSh = pDoc->GetEditShell(); + pSh->LockPaint(); + pSh->StartAllAction(); + pSh->KillPams(); + pSh->ClearMark(); + pDoc->ClearDoc(); + pSh->ClearUpCursors(); + + if( m_aLoadedIdle.IsActive()) + { + pSh->EndAllAction(); + pSh->UnlockPaint(); + } + m_aLoadedIdle.Start(); + } + else + { + m_xCursor->gotoStart(false); + m_xCursor->gotoEnd(true); + m_xCursor->setString(OUString()); + } + } +} + +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 (size_t i = 0; i < SAL_N_ELEMENTS(nZoomValues); ++i) + { + OUString sTemp = unicode::formatPercent(nZoomValues[i], + Application::GetSettings().GetUILanguageTag()); + OString sIdent = "zoom" + OString::number(nZoomValues[i]); + xPop->set_label(sIdent, sTemp); + if (nZoom == nZoomValues[i]) + xPop->set_active(sIdent, true); + } + + PopupHdl(xPop->popup_at_rect(GetDrawingArea(), tools::Rectangle(rPt, Size(1, 1)))); + + return true; +} + +void SwOneExampleFrame::PopupHdl(const OString& rId) +{ + OString sZoomValue; + if (rId.startsWith("zoom", &sZoomValue)) + { + sal_Int16 nZoom = sZoomValue.toInt32(); + 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 000000000..bdb18bbb3 --- /dev/null +++ b/sw/source/uibase/utlui/viewlayoutctrl.cxx @@ -0,0 +1,197 @@ +/* -*- 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 <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 + 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::StateChanged( sal_uInt16 /*nSID*/, SfxItemState eState, const SfxPoolItem* pState ) +{ + if ( SfxItemState::DEFAULT != eState || pState->IsVoidItem() ) + GetStatusBar().SetItemText( GetId(), OUString() ); + else + { + OSL_ENSURE( dynamic_cast< const SvxViewLayoutItem *>( pState ) != nullptr, "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(); + + const bool bSingleColumn = 0 == mpImpl->mnState; + const bool bAutomatic = 1 == mpImpl->mnState; + const bool bBookMode = 2 == mpImpl->mnState; + + const long nImageWidthSum = mpImpl->maImageSingleColumn.GetSizePixel().Width() + + mpImpl->maImageAutomatic.GetSizePixel().Width() + + mpImpl->maImageBookMode.GetSizePixel().Width(); + + const long nXOffset = (aRect.GetWidth() - nImageWidthSum) / 2; + const 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() ); + pDev->DrawImage( aRect.TopLeft(), bAutomatic ? mpImpl->maImageAutomatic_Active : mpImpl->maImageAutomatic ); + + // draw bookmode image: + aRect.AdjustLeft(mpImpl->maImageAutomatic.GetSizePixel().Width() ); + pDev->DrawImage( aRect.TopLeft(), bBookMode ? mpImpl->maImageBookMode_Active : mpImpl->maImageBookMode ); +} + +bool SwViewLayoutControl::MouseButtonDown( const MouseEvent & rEvt ) +{ + const tools::Rectangle aRect = getControlRect(); + const Point aPoint = rEvt.GetPosPixel(); + const long nXDiff = aPoint.X() - aRect.Left(); + + sal_uInt16 nColumns = 1; + bool bBookMode = false; + + const long nImageWidthSingle = mpImpl->maImageSingleColumn.GetSizePixel().Width(); + const long nImageWidthAuto = mpImpl->maImageAutomatic.GetSizePixel().Width(); + const long nImageWidthBook = mpImpl->maImageBookMode.GetSizePixel().Width(); + const long nImageWidthSum = nImageWidthSingle + nImageWidthAuto + nImageWidthBook; + + const 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( 1 ); + aArgs[0].Name = "ViewLayout"; + aArgs[0].Value = a; + + execute( aArgs ); + + return true; +} + +bool SwViewLayoutControl::MouseMove( const MouseEvent & rEvt ) +{ + const tools::Rectangle aRect = getControlRect(); + const Point aPoint = rEvt.GetPosPixel(); + const long nXDiff = aPoint.X() - aRect.Left(); + + const long nImageWidthSingle = mpImpl->maImageSingleColumn.GetSizePixel().Width(); + const long nImageWidthAuto = mpImpl->maImageAutomatic.GetSizePixel().Width(); + const long nImageWidthBook = mpImpl->maImageBookMode.GetSizePixel().Width(); + const long nImageWidthSum = nImageWidthSingle + nImageWidthAuto + nImageWidthBook; + + const 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 000000000..93eba3c73 --- /dev/null +++ b/sw/source/uibase/utlui/wordcountctrl.cxx @@ -0,0 +1,39 @@ +/* -*- 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::StateChanged( + 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)); +} + +/* 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 000000000..493b2f9b7 --- /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::StateChanged( sal_uInt16 nSID, SfxItemState eState, + const SfxPoolItem* pState ) +{ + const SfxStringItem* pItem = nullptr; + if (SfxItemState::DEFAULT == eState && (pItem = dynamic_cast<const SfxStringItem*>(pState))) + { + sPreviewZoom = pItem->GetValue(); + GetStatusBar().SetItemText(GetId(), sPreviewZoom); + } + else + { + sPreviewZoom.clear(); + SvxZoomStatusBarControl::StateChanged(nSID, eState, pState); + } +} + +void SwZoomControl::Paint( const UserDrawEvent& ) +{ +} + +void SwZoomControl::Command( const CommandEvent& rCEvt ) +{ + if (sPreviewZoom.isEmpty()) + SvxZoomStatusBarControl::Command(rCEvt); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |