summaryrefslogtreecommitdiffstats
path: root/sc/source/core/tool/editutil.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/core/tool/editutil.cxx')
-rw-r--r--sc/source/core/tool/editutil.cxx935
1 files changed, 935 insertions, 0 deletions
diff --git a/sc/source/core/tool/editutil.cxx b/sc/source/core/tool/editutil.cxx
new file mode 100644
index 000000000..c7e0c0cb6
--- /dev/null
+++ b/sc/source/core/tool/editutil.cxx
@@ -0,0 +1,935 @@
+/* -*- 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 <scitems.hxx>
+#include <comphelper/processfactory.hxx>
+#include <editeng/eeitem.hxx>
+
+#include <svx/algitem.hxx>
+#include <svtools/colorcfg.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/flditem.hxx>
+#include <editeng/numitem.hxx>
+#include <editeng/justifyitem.hxx>
+#include <editeng/editobj.hxx>
+#include <vcl/outdev.hxx>
+#include <svl/numformat.hxx>
+#include <svl/inethist.hxx>
+#include <sfx2/objsh.hxx>
+#include <comphelper/lok.hxx>
+#include <osl/diagnose.h>
+
+#include <com/sun/star/text/textfield/Type.hpp>
+#include <com/sun/star/document/XDocumentProperties.hpp>
+
+#include <editutil.hxx>
+#include <global.hxx>
+#include <attrib.hxx>
+#include <document.hxx>
+#include <docpool.hxx>
+#include <patattr.hxx>
+#include <scmod.hxx>
+#include <inputopt.hxx>
+#include <compiler.hxx>
+#include <mutex>
+
+using namespace com::sun::star;
+
+// delimiters additionally to EditEngine default:
+
+ScEditUtil::ScEditUtil( ScDocument* pDocument, SCCOL nX, SCROW nY, SCTAB nZ,
+ const Point& rCellPos,
+ OutputDevice* pDevice, double nScaleX, double nScaleY,
+ const Fraction& rX, const Fraction& rY, bool bPrintTwips ) :
+ pDoc(pDocument),nCol(nX),nRow(nY),nTab(nZ),
+ aCellPos(rCellPos),pDev(pDevice),
+ nPPTX(nScaleX),nPPTY(nScaleY),aZoomX(rX),aZoomY(rY),
+ bInPrintTwips(bPrintTwips) {}
+
+OUString ScEditUtil::ModifyDelimiters( const OUString& rOld )
+{
+ // underscore is used in function argument names
+ OUString aRet = rOld.replaceAll("_", "") +
+ "=()+-*/^&<>" +
+ ScCompiler::GetNativeSymbol(ocSep); // argument separator is localized.
+ return aRet;
+}
+
+static OUString lcl_GetDelimitedString( const EditEngine& rEngine, const char c )
+{
+ sal_Int32 nParCount = rEngine.GetParagraphCount();
+ // avoid creating a new string if possible
+ if (nParCount == 0)
+ return OUString();
+ else if (nParCount == 1)
+ return rEngine.GetText(0);
+ OUStringBuffer aRet( nParCount * 80 );
+ for (sal_Int32 nPar=0; nPar<nParCount; nPar++)
+ {
+ if (nPar > 0)
+ aRet.append(c);
+ aRet.append( rEngine.GetText( nPar ));
+ }
+ return aRet.makeStringAndClear();
+}
+
+static OUString lcl_GetDelimitedString( const EditTextObject& rEdit, const char c )
+{
+ sal_Int32 nParCount = rEdit.GetParagraphCount();
+ OUStringBuffer aRet( nParCount * 80 );
+ for (sal_Int32 nPar=0; nPar<nParCount; nPar++)
+ {
+ if (nPar > 0)
+ aRet.append(c);
+ aRet.append( rEdit.GetText( nPar ));
+ }
+ return aRet.makeStringAndClear();
+}
+
+OUString ScEditUtil::GetSpaceDelimitedString( const EditEngine& rEngine )
+{
+ return lcl_GetDelimitedString(rEngine, ' ');
+}
+OUString ScEditUtil::GetMultilineString( const EditEngine& rEngine )
+{
+ return lcl_GetDelimitedString(rEngine, '\n');
+}
+
+OUString ScEditUtil::GetMultilineString( const EditTextObject& rEdit )
+{
+ return lcl_GetDelimitedString(rEdit, '\n');
+}
+
+OUString ScEditUtil::GetString( const EditTextObject& rEditText, const ScDocument* pDoc )
+{
+ if( !rEditText.HasField())
+ return GetMultilineString( rEditText );
+
+ static std::mutex aMutex;
+ std::scoped_lock aGuard( aMutex);
+ // ScFieldEditEngine is needed to resolve field contents.
+ if (pDoc)
+ {
+ /* TODO: make ScDocument::GetEditEngine() const? Most likely it's only
+ * not const because of the pointer assignment, make that mutable, and
+ * then remove the ugly const_cast here. */
+ EditEngine& rEE = const_cast<ScDocument*>(pDoc)->GetEditEngine();
+ rEE.SetText( rEditText);
+ return GetMultilineString( rEE);
+ }
+ else
+ {
+ EditEngine& rEE = ScGlobal::GetStaticFieldEditEngine();
+ rEE.SetText( rEditText);
+ return GetMultilineString( rEE);
+ }
+}
+
+std::unique_ptr<EditTextObject> ScEditUtil::CreateURLObjectFromURL( ScDocument& rDoc, const OUString& rURL, const OUString& rText )
+{
+ SvxURLField aUrlField( rURL, rText, SvxURLFormat::AppDefault);
+ EditEngine& rEE = rDoc.GetEditEngine();
+ rEE.SetText( OUString() );
+ rEE.QuickInsertField( SvxFieldItem( aUrlField, EE_FEATURE_FIELD ),
+ ESelection( EE_PARA_MAX_COUNT, EE_TEXTPOS_MAX_COUNT ) );
+
+ return rEE.CreateTextObject();
+}
+
+void ScEditUtil::RemoveCharAttribs( EditTextObject& rEditText, const ScPatternAttr& rAttr )
+{
+ static const struct {
+ sal_uInt16 nAttrType;
+ sal_uInt16 nCharType;
+ } AttrTypeMap[] = {
+ { ATTR_FONT, EE_CHAR_FONTINFO },
+ { ATTR_CJK_FONT, EE_CHAR_FONTINFO_CJK },
+ { ATTR_CTL_FONT, EE_CHAR_FONTINFO_CTL },
+ { ATTR_FONT_HEIGHT, EE_CHAR_FONTHEIGHT },
+ { ATTR_CJK_FONT_HEIGHT, EE_CHAR_FONTHEIGHT_CJK },
+ { ATTR_CTL_FONT_HEIGHT, EE_CHAR_FONTHEIGHT_CTL },
+ { ATTR_FONT_WEIGHT, EE_CHAR_WEIGHT },
+ { ATTR_CJK_FONT_WEIGHT, EE_CHAR_WEIGHT_CJK },
+ { ATTR_CTL_FONT_WEIGHT, EE_CHAR_WEIGHT_CTL },
+ { ATTR_FONT_POSTURE, EE_CHAR_ITALIC },
+ { ATTR_CJK_FONT_POSTURE, EE_CHAR_ITALIC_CJK },
+ { ATTR_CTL_FONT_POSTURE, EE_CHAR_ITALIC_CTL },
+ { ATTR_FONT_COLOR, EE_CHAR_COLOR },
+ { ATTR_FONT_UNDERLINE, EE_CHAR_UNDERLINE },
+ { ATTR_FONT_CROSSEDOUT, EE_CHAR_STRIKEOUT },
+ { ATTR_FONT_CONTOUR, EE_CHAR_OUTLINE },
+ { ATTR_FONT_SHADOWED, EE_CHAR_SHADOW }
+ };
+
+ const SfxItemSet& rSet = rAttr.GetItemSet();
+ const SfxPoolItem* pItem;
+ for (size_t i = 0; i < SAL_N_ELEMENTS(AttrTypeMap); ++i)
+ {
+ if ( rSet.GetItemState(AttrTypeMap[i].nAttrType, false, &pItem) == SfxItemState::SET )
+ rEditText.RemoveCharAttribs(AttrTypeMap[i].nCharType);
+ }
+}
+
+std::unique_ptr<EditTextObject> ScEditUtil::Clone( const EditTextObject& rObj, ScDocument& rDestDoc )
+{
+ std::unique_ptr<EditTextObject> pNew;
+
+ EditEngine& rEngine = rDestDoc.GetEditEngine();
+ if (rObj.HasOnlineSpellErrors())
+ {
+ EEControlBits nControl = rEngine.GetControlWord();
+ const EEControlBits nSpellControl = EEControlBits::ONLINESPELLING | EEControlBits::ALLOWBIGOBJS;
+ bool bNewControl = ( (nControl & nSpellControl) != nSpellControl );
+ if (bNewControl)
+ rEngine.SetControlWord(nControl | nSpellControl);
+ rEngine.SetText(rObj);
+ pNew = rEngine.CreateTextObject();
+ if (bNewControl)
+ rEngine.SetControlWord(nControl);
+ }
+ else
+ {
+ rEngine.SetText(rObj);
+ pNew = rEngine.CreateTextObject();
+ }
+
+ return pNew;
+}
+
+OUString ScEditUtil::GetCellFieldValue(
+ const SvxFieldData& rFieldData, const ScDocument* pDoc, std::optional<Color>* ppTextColor )
+{
+ OUString aRet;
+ switch (rFieldData.GetClassId())
+ {
+ case text::textfield::Type::URL:
+ {
+ const SvxURLField& rField = static_cast<const SvxURLField&>(rFieldData);
+ const OUString& aURL = rField.GetURL();
+
+ switch (rField.GetFormat())
+ {
+ case SvxURLFormat::AppDefault: //TODO: configurable with App???
+ case SvxURLFormat::Repr:
+ aRet = rField.GetRepresentation();
+ break;
+ case SvxURLFormat::Url:
+ aRet = aURL;
+ break;
+ default:
+ ;
+ }
+
+ svtools::ColorConfigEntry eEntry =
+ INetURLHistory::GetOrCreate()->QueryUrl(aURL) ? svtools::LINKSVISITED : svtools::LINKS;
+
+ if (ppTextColor)
+ *ppTextColor = SC_MOD()->GetColorConfig().GetColorValue(eEntry).nColor;
+ }
+ break;
+ case text::textfield::Type::EXTENDED_TIME:
+ {
+ const SvxExtTimeField& rField = static_cast<const SvxExtTimeField&>(rFieldData);
+ if (pDoc)
+ aRet = rField.GetFormatted(*pDoc->GetFormatTable(), ScGlobal::eLnge);
+ else
+ {
+ /* TODO: quite expensive, we could have a global formatter? */
+ SvNumberFormatter aFormatter( comphelper::getProcessComponentContext(), ScGlobal::eLnge );
+ aRet = rField.GetFormatted(aFormatter, ScGlobal::eLnge);
+ }
+ }
+ break;
+ case text::textfield::Type::DATE:
+ {
+ Date aDate(Date::SYSTEM);
+ aRet = ScGlobal::getLocaleData().getDate(aDate);
+ }
+ break;
+ case text::textfield::Type::DOCINFO_TITLE:
+ {
+ if (pDoc)
+ {
+ SfxObjectShell* pDocShell = pDoc->GetDocumentShell();
+ if (pDocShell)
+ {
+ aRet = pDocShell->getDocProperties()->getTitle();
+ if (aRet.isEmpty())
+ aRet = pDocShell->GetTitle();
+ }
+ }
+ if (aRet.isEmpty())
+ aRet = "?";
+ }
+ break;
+ case text::textfield::Type::TABLE:
+ {
+ const SvxTableField& rField = static_cast<const SvxTableField&>(rFieldData);
+ SCTAB nTab = rField.GetTab();
+ OUString aName;
+ if (pDoc && pDoc->GetName(nTab, aName))
+ aRet = aName;
+ else
+ aRet = "?";
+ }
+ break;
+ default:
+ aRet = "?";
+ }
+
+ if (aRet.isEmpty()) // empty is yuck
+ aRet = " "; // space is default of EditEngine
+
+ return aRet;
+}
+
+tools::Long ScEditUtil::GetIndent(const ScPatternAttr* pPattern) const
+{
+ if (!pPattern)
+ pPattern = pDoc->GetPattern( nCol, nRow, nTab );
+
+ if ( pPattern->GetItem(ATTR_HOR_JUSTIFY).GetValue() ==
+ SvxCellHorJustify::Left )
+ {
+ tools::Long nIndent = pPattern->GetItem(ATTR_INDENT).GetValue();
+ if (!bInPrintTwips)
+ nIndent = static_cast<tools::Long>(nIndent * nPPTX);
+ return nIndent;
+ }
+
+ return 0;
+}
+
+void ScEditUtil::GetMargins(const ScPatternAttr* pPattern, tools::Long& nLeftMargin, tools::Long& nTopMargin,
+ tools::Long& nRightMargin, tools::Long& nBottomMargin) const
+{
+ if (!pPattern)
+ pPattern = pDoc->GetPattern( nCol, nRow, nTab );
+
+ const SvxMarginItem* pMargin = &pPattern->GetItem(ATTR_MARGIN);
+ if (!pMargin)
+ return;
+
+ nLeftMargin = bInPrintTwips ? pMargin->GetLeftMargin() : static_cast<tools::Long>(pMargin->GetLeftMargin() * nPPTX);
+ nRightMargin = bInPrintTwips ? pMargin->GetRightMargin() : static_cast<tools::Long>(pMargin->GetRightMargin() * nPPTX);
+ nTopMargin = bInPrintTwips ? pMargin->GetTopMargin() : static_cast<tools::Long>(pMargin->GetTopMargin() * nPPTY);
+ nBottomMargin = bInPrintTwips ? pMargin->GetBottomMargin() : static_cast<tools::Long>(pMargin->GetBottomMargin() * nPPTY);
+}
+
+tools::Rectangle ScEditUtil::GetEditArea( const ScPatternAttr* pPattern, bool bForceToTop )
+{
+ // bForceToTop = always align to top, for editing
+ // (sal_False for querying URLs etc.)
+
+ if (!pPattern)
+ pPattern = pDoc->GetPattern( nCol, nRow, nTab );
+
+ Point aStartPos = aCellPos;
+ bool bIsTiledRendering = comphelper::LibreOfficeKit::isActive();
+
+ bool bLayoutRTL = pDoc->IsLayoutRTL( nTab );
+ tools::Long nLayoutSign = (bLayoutRTL && !bIsTiledRendering) ? -1 : 1;
+
+ const ScMergeAttr* pMerge = &pPattern->GetItem(ATTR_MERGE);
+ tools::Long nCellX = pDoc->GetColWidth(nCol,nTab);
+ if (!bInPrintTwips)
+ nCellX = static_cast<tools::Long>( nCellX * nPPTX );
+ if ( pMerge->GetColMerge() > 1 )
+ {
+ SCCOL nCountX = pMerge->GetColMerge();
+ for (SCCOL i=1; i<nCountX; i++)
+ {
+ tools::Long nColWidth = pDoc->GetColWidth(nCol+i,nTab);
+ nCellX += (bInPrintTwips ? nColWidth : static_cast<tools::Long>( nColWidth * nPPTX ));
+ }
+ }
+ tools::Long nCellY = pDoc->GetRowHeight(nRow,nTab);
+ if (!bInPrintTwips)
+ nCellY = static_cast<tools::Long>( nCellY * nPPTY );
+ if ( pMerge->GetRowMerge() > 1 )
+ {
+ SCROW nCountY = pMerge->GetRowMerge();
+ if (bInPrintTwips)
+ nCellY += pDoc->GetRowHeight(nRow + 1, nRow + nCountY - 1, nTab);
+ else
+ nCellY += pDoc->GetScaledRowHeight( nRow+1, nRow+nCountY-1, nTab, nPPTY);
+ }
+
+ tools::Long nRightMargin = 0;
+ tools::Long nTopMargin = 0;
+ tools::Long nBottomMargin = 0;
+ tools::Long nDifX = 0;
+ {
+ tools::Long nLeftMargin = 0;
+ bool bInPrintTwipsOrig = bInPrintTwips;
+ bInPrintTwips = true;
+ tools::Long nIndent = GetIndent(pPattern);
+ GetMargins(pPattern, nLeftMargin, nTopMargin, nRightMargin, nBottomMargin);
+ bInPrintTwips = bInPrintTwipsOrig;
+ // Here rounding may be done only on the sum, ie nDifX,
+ // so need to get margin and indent in twips.
+ nDifX = nLeftMargin + nIndent;
+ if (!bInPrintTwips)
+ {
+ nDifX = static_cast<tools::Long>(nDifX * nPPTX);
+ nRightMargin = static_cast<tools::Long>(nRightMargin * nPPTX);
+ nTopMargin = static_cast<tools::Long>(nTopMargin * nPPTY);
+ nBottomMargin = static_cast<tools::Long>(nBottomMargin * nPPTY);
+ }
+ }
+
+
+ aStartPos.AdjustX(nDifX * nLayoutSign );
+ nCellX -= nDifX + nRightMargin; // due to line feed, etc.
+
+ // align vertical position to the one in the table
+
+ tools::Long nDifY;
+ SvxCellVerJustify eJust = pPattern->GetItem(ATTR_VER_JUSTIFY).GetValue();
+
+ // asian vertical is always edited top-aligned
+ bool bAsianVertical = pPattern->GetItem( ATTR_STACKED ).GetValue() &&
+ pPattern->GetItem( ATTR_VERTICAL_ASIAN ).GetValue();
+
+ if ( eJust == SvxCellVerJustify::Top ||
+ ( bForceToTop && ( SC_MOD()->GetInputOptions().GetTextWysiwyg() || bAsianVertical ) ) )
+ nDifY = nTopMargin;
+ else
+ {
+ MapMode aMode = pDev->GetMapMode();
+ pDev->SetMapMode(MapMode(bInPrintTwips ? MapUnit::MapTwip : MapUnit::MapPixel));
+
+ tools::Long nTextHeight = pDoc->GetNeededSize( nCol, nRow, nTab,
+ pDev, nPPTX, nPPTY, aZoomX, aZoomY, false /* bWidth */,
+ false /* bTotalSize */, bInPrintTwips );
+ if (!nTextHeight)
+ { // empty cell
+ vcl::Font aFont;
+ // font color doesn't matter here
+ pPattern->GetFont( aFont, SC_AUTOCOL_BLACK, pDev, &aZoomY );
+ pDev->SetFont(aFont);
+ nTextHeight = pDev->GetTextHeight() + nTopMargin + nBottomMargin;
+ }
+
+ pDev->SetMapMode(aMode);
+
+ if ( nTextHeight > nCellY + nTopMargin || bForceToTop )
+ nDifY = 0; // too large -> begin at the top
+ else
+ {
+ if ( eJust == SvxCellVerJustify::Center )
+ nDifY = nTopMargin + ( nCellY - nTextHeight ) / 2;
+ else
+ nDifY = nCellY - nTextHeight + nTopMargin; // JUSTIFY_BOTTOM
+ }
+ }
+
+ aStartPos.AdjustY(nDifY );
+ nCellY -= nDifY;
+
+ if ( bLayoutRTL && !bIsTiledRendering )
+ aStartPos.AdjustX( -(nCellX - 2) ); // excluding grid on both sides
+
+ // -1 -> don't overwrite grid
+ return tools::Rectangle( aStartPos, Size(nCellX-1,nCellY-1) );
+}
+
+ScEditAttrTester::ScEditAttrTester( ScEditEngineDefaulter* pEngine ) :
+ bNeedsObject( false ),
+ bNeedsCellAttr( false )
+{
+ if ( pEngine->GetParagraphCount() > 1 )
+ {
+ bNeedsObject = true; //TODO: find cell attributes ?
+ }
+ else
+ {
+ const SfxPoolItem* pItem = nullptr;
+ pEditAttrs.reset( new SfxItemSet( pEngine->GetAttribs(
+ ESelection(0,0,0,pEngine->GetTextLen(0)), EditEngineAttribs::OnlyHard ) ) );
+ const SfxItemSet& rEditDefaults = pEngine->GetDefaults();
+
+ for (sal_uInt16 nId = EE_CHAR_START; nId <= EE_CHAR_END && !bNeedsObject; nId++)
+ {
+ SfxItemState eState = pEditAttrs->GetItemState( nId, false, &pItem );
+ if (eState == SfxItemState::DONTCARE)
+ bNeedsObject = true;
+ else if (eState == SfxItemState::SET)
+ {
+ if ( nId == EE_CHAR_ESCAPEMENT || nId == EE_CHAR_PAIRKERNING ||
+ nId == EE_CHAR_KERNING || nId == EE_CHAR_XMLATTRIBS )
+ {
+ // Escapement and kerning are kept in EditEngine because there are no
+ // corresponding cell format items. User defined attributes are kept in
+ // EditEngine because "user attributes applied to all the text" is different
+ // from "user attributes applied to the cell".
+
+ if ( *pItem != rEditDefaults.Get(nId) )
+ bNeedsObject = true;
+ }
+ else
+ if (!bNeedsCellAttr)
+ if ( *pItem != rEditDefaults.Get(nId) )
+ bNeedsCellAttr = true;
+ // rEditDefaults contains the defaults from the cell format
+ }
+ }
+
+ // contains field commands?
+
+ SfxItemState eFieldState = pEditAttrs->GetItemState( EE_FEATURE_FIELD, false );
+ if ( eFieldState == SfxItemState::DONTCARE || eFieldState == SfxItemState::SET )
+ bNeedsObject = true;
+
+ // not converted characters?
+
+ SfxItemState eConvState = pEditAttrs->GetItemState( EE_FEATURE_NOTCONV, false );
+ if ( eConvState == SfxItemState::DONTCARE || eConvState == SfxItemState::SET )
+ bNeedsObject = true;
+ }
+}
+
+ScEditAttrTester::~ScEditAttrTester()
+{
+}
+
+ScEnginePoolHelper::ScEnginePoolHelper( SfxItemPool* pEnginePoolP,
+ bool bDeleteEnginePoolP )
+ :
+ pEnginePool( pEnginePoolP ),
+ pDefaults( nullptr ),
+ bDeleteEnginePool( bDeleteEnginePoolP ),
+ bDeleteDefaults( false )
+{
+}
+
+ScEnginePoolHelper::ScEnginePoolHelper( const ScEnginePoolHelper& rOrg )
+ :
+ pEnginePool( rOrg.bDeleteEnginePool ? rOrg.pEnginePool->Clone() : rOrg.pEnginePool ),
+ pDefaults( nullptr ),
+ bDeleteEnginePool( rOrg.bDeleteEnginePool ),
+ bDeleteDefaults( false )
+{
+}
+
+ScEnginePoolHelper::~ScEnginePoolHelper()
+{
+ if ( bDeleteDefaults )
+ delete pDefaults;
+}
+
+ScEditEngineDefaulter::ScEditEngineDefaulter( SfxItemPool* pEnginePoolP,
+ bool bDeleteEnginePoolP )
+ :
+ ScEnginePoolHelper( pEnginePoolP, bDeleteEnginePoolP ),
+ EditEngine( pEnginePoolP )
+{
+ // All EditEngines use ScGlobal::GetEditDefaultLanguage as DefaultLanguage.
+ // DefaultLanguage for InputHandler's EditEngine is updated later.
+
+ SetDefaultLanguage( ScGlobal::GetEditDefaultLanguage() );
+}
+
+ScEditEngineDefaulter::ScEditEngineDefaulter( const ScEditEngineDefaulter& rOrg )
+ :
+ ScEnginePoolHelper( rOrg ),
+ EditEngine( pEnginePool.get() )
+{
+ SetDefaultLanguage( ScGlobal::GetEditDefaultLanguage() );
+}
+
+ScEditEngineDefaulter::~ScEditEngineDefaulter()
+{
+}
+
+void ScEditEngineDefaulter::SetDefaults( const SfxItemSet& rSet, bool bRememberCopy )
+{
+ if ( bRememberCopy )
+ {
+ if ( bDeleteDefaults )
+ delete pDefaults;
+ pDefaults = new SfxItemSet( rSet );
+ bDeleteDefaults = true;
+ }
+ const SfxItemSet& rNewSet = bRememberCopy ? *pDefaults : rSet;
+ bool bUndo = IsUndoEnabled();
+ EnableUndo( false );
+ bool bUpdateMode = SetUpdateLayout( false );
+ sal_Int32 nPara = GetParagraphCount();
+ for ( sal_Int32 j=0; j<nPara; j++ )
+ {
+ SetParaAttribs( j, rNewSet );
+ }
+ if ( bUpdateMode )
+ SetUpdateLayout( true );
+ if ( bUndo )
+ EnableUndo( true );
+}
+
+void ScEditEngineDefaulter::SetDefaults( std::unique_ptr<SfxItemSet> pSet )
+{
+ if ( bDeleteDefaults )
+ delete pDefaults;
+ pDefaults = pSet.release();
+ bDeleteDefaults = true;
+ if ( pDefaults )
+ SetDefaults( *pDefaults, false );
+}
+
+void ScEditEngineDefaulter::SetDefaultItem( const SfxPoolItem& rItem )
+{
+ if ( !pDefaults )
+ {
+ pDefaults = new SfxItemSet( GetEmptyItemSet() );
+ bDeleteDefaults = true;
+ }
+ pDefaults->Put( rItem );
+ SetDefaults( *pDefaults, false );
+}
+
+const SfxItemSet& ScEditEngineDefaulter::GetDefaults()
+{
+ if ( !pDefaults )
+ {
+ pDefaults = new SfxItemSet( GetEmptyItemSet() );
+ bDeleteDefaults = true;
+ }
+ return *pDefaults;
+}
+
+void ScEditEngineDefaulter::SetTextCurrentDefaults( const EditTextObject& rTextObject )
+{
+ bool bUpdateMode = SetUpdateLayout( false );
+ SetText( rTextObject );
+ if ( pDefaults )
+ SetDefaults( *pDefaults, false );
+ if ( bUpdateMode )
+ SetUpdateLayout( true );
+}
+
+void ScEditEngineDefaulter::SetTextNewDefaults( const EditTextObject& rTextObject,
+ const SfxItemSet& rSet, bool bRememberCopy )
+{
+ bool bUpdateMode = SetUpdateLayout( false );
+ SetText( rTextObject );
+ SetDefaults( rSet, bRememberCopy );
+ if ( bUpdateMode )
+ SetUpdateLayout( true );
+}
+
+void ScEditEngineDefaulter::SetTextCurrentDefaults( const OUString& rText )
+{
+ bool bUpdateMode = SetUpdateLayout( false );
+ SetText( rText );
+ if ( pDefaults )
+ SetDefaults( *pDefaults, false );
+ if ( bUpdateMode )
+ SetUpdateLayout( true );
+}
+
+void ScEditEngineDefaulter::SetTextNewDefaults( const OUString& rText,
+ const SfxItemSet& rSet )
+{
+ bool bUpdateMode = SetUpdateLayout( false );
+ SetText( rText );
+ SetDefaults( rSet );
+ if ( bUpdateMode )
+ SetUpdateLayout( true );
+}
+
+void ScEditEngineDefaulter::RepeatDefaults()
+{
+ if ( pDefaults )
+ {
+ sal_Int32 nPara = GetParagraphCount();
+ for ( sal_Int32 j=0; j<nPara; j++ )
+ SetParaAttribs( j, *pDefaults );
+ }
+}
+
+void ScEditEngineDefaulter::RemoveParaAttribs()
+{
+ std::optional<SfxItemSet> pCharItems;
+ bool bUpdateMode = SetUpdateLayout( false );
+ sal_Int32 nParCount = GetParagraphCount();
+ for (sal_Int32 nPar=0; nPar<nParCount; nPar++)
+ {
+ const SfxItemSet& rParaAttribs = GetParaAttribs( nPar );
+ sal_uInt16 nWhich;
+ for (nWhich = EE_CHAR_START; nWhich <= EE_CHAR_END; nWhich ++)
+ {
+ const SfxPoolItem* pParaItem;
+ if ( rParaAttribs.GetItemState( nWhich, false, &pParaItem ) == SfxItemState::SET )
+ {
+ // if defaults are set, use only items that are different from default
+ if ( !pDefaults || *pParaItem != pDefaults->Get(nWhich) )
+ {
+ if (!pCharItems)
+ pCharItems.emplace( GetEmptyItemSet() );
+ pCharItems->Put( *pParaItem );
+ }
+ }
+ }
+
+ if ( pCharItems )
+ {
+ std::vector<sal_Int32> aPortions;
+ GetPortions( nPar, aPortions );
+
+ // loop through the portions of the paragraph, and set only those items
+ // that are not overridden by existing character attributes
+
+ sal_Int32 nStart = 0;
+ for ( const sal_Int32 nEnd : aPortions )
+ {
+ ESelection aSel( nPar, nStart, nPar, nEnd );
+ SfxItemSet aOldCharAttrs = GetAttribs( aSel );
+ SfxItemSet aNewCharAttrs = *pCharItems;
+ for (nWhich = EE_CHAR_START; nWhich <= EE_CHAR_END; nWhich ++)
+ {
+ // Clear those items that are different from existing character attributes.
+ // Where no character attributes are set, GetAttribs returns the paragraph attributes.
+ const SfxPoolItem* pItem;
+ if ( aNewCharAttrs.GetItemState( nWhich, false, &pItem ) == SfxItemState::SET &&
+ *pItem != aOldCharAttrs.Get(nWhich) )
+ {
+ aNewCharAttrs.ClearItem(nWhich);
+ }
+ }
+ if ( aNewCharAttrs.Count() )
+ QuickSetAttribs( aNewCharAttrs, aSel );
+
+ nStart = nEnd;
+ }
+
+ pCharItems.reset();
+ }
+
+ if ( rParaAttribs.Count() )
+ {
+ // clear all paragraph attributes (including defaults),
+ // so they are not contained in resulting EditTextObjects
+
+ SetParaAttribs( nPar, SfxItemSet( *rParaAttribs.GetPool(), rParaAttribs.GetRanges() ) );
+ }
+ }
+ if ( bUpdateMode )
+ SetUpdateLayout( true );
+}
+
+ScTabEditEngine::ScTabEditEngine( ScDocument* pDoc )
+ : ScFieldEditEngine( pDoc, pDoc->GetEnginePool() )
+{
+ SetEditTextObjectPool( pDoc->GetEditPool() );
+ Init(pDoc->GetPool()->GetDefaultItem(ATTR_PATTERN));
+}
+
+ScTabEditEngine::ScTabEditEngine( const ScPatternAttr& rPattern,
+ SfxItemPool* pEngineItemPool, ScDocument* pDoc, SfxItemPool* pTextObjectPool )
+ : ScFieldEditEngine( pDoc, pEngineItemPool, pTextObjectPool )
+{
+ if ( pTextObjectPool )
+ SetEditTextObjectPool( pTextObjectPool );
+ Init( rPattern );
+}
+
+void ScTabEditEngine::Init( const ScPatternAttr& rPattern )
+{
+ SetRefMapMode(MapMode(MapUnit::Map100thMM));
+ auto pEditDefaults = std::make_unique<SfxItemSet>( GetEmptyItemSet() );
+ rPattern.FillEditItemSet( pEditDefaults.get() );
+ SetDefaults( std::move(pEditDefaults) );
+ // we have no StyleSheets for text
+ SetControlWord( GetControlWord() & ~EEControlBits::RTFSTYLESHEETS );
+}
+
+// field commands for header and footer
+
+// numbers from \sw\source\core\doc\numbers.cxx
+
+static OUString lcl_GetCharStr( sal_Int32 nNo )
+{
+ OSL_ENSURE( nNo, "0 is an invalid number !!" );
+ OUString aStr;
+
+ const sal_Int32 coDiff = 'Z' - 'A' +1;
+ sal_Int32 nCalc;
+
+ do {
+ nCalc = nNo % coDiff;
+ if( !nCalc )
+ nCalc = coDiff;
+ aStr = OUStringChar( sal_Unicode('a' - 1 + nCalc) ) + aStr;
+ nNo = sal::static_int_cast<sal_Int32>( nNo - nCalc );
+ if( nNo )
+ nNo /= coDiff;
+ } while( nNo );
+ return aStr;
+}
+
+static OUString lcl_GetNumStr(sal_Int32 nNo, SvxNumType eType)
+{
+ OUString aTmpStr('0');
+ if( nNo )
+ {
+ switch( eType )
+ {
+ case css::style::NumberingType::CHARS_UPPER_LETTER:
+ case css::style::NumberingType::CHARS_LOWER_LETTER:
+ aTmpStr = lcl_GetCharStr( nNo );
+ break;
+
+ case css::style::NumberingType::ROMAN_UPPER:
+ case css::style::NumberingType::ROMAN_LOWER:
+ if( nNo < 4000 )
+ aTmpStr = SvxNumberFormat::CreateRomanString( nNo, ( eType == css::style::NumberingType::ROMAN_UPPER ) );
+ else
+ aTmpStr.clear();
+ break;
+
+ case css::style::NumberingType::NUMBER_NONE:
+ aTmpStr.clear();
+ break;
+
+// CHAR_SPECIAL:
+// ????
+
+// case ARABIC: is default now
+ default:
+ aTmpStr = OUString::number(nNo);
+ break;
+ }
+
+ if( css::style::NumberingType::CHARS_UPPER_LETTER == eType )
+ aTmpStr = aTmpStr.toAsciiUpperCase();
+ }
+ return aTmpStr;
+}
+
+ScHeaderFieldData::ScHeaderFieldData()
+ : aDateTime ( DateTime::EMPTY )
+{
+ nPageNo = nTotalPages = 0;
+ eNumType = SVX_NUM_ARABIC;
+}
+
+ScHeaderEditEngine::ScHeaderEditEngine( SfxItemPool* pEnginePoolP )
+ : ScEditEngineDefaulter( pEnginePoolP,true/*bDeleteEnginePoolP*/ )
+{
+}
+
+OUString ScHeaderEditEngine::CalcFieldValue( const SvxFieldItem& rField,
+ sal_Int32 /* nPara */, sal_Int32 /* nPos */,
+ std::optional<Color>& /* rTxtColor */, std::optional<Color>& /* rFldColor */ )
+{
+ const SvxFieldData* pFieldData = rField.GetField();
+ if (!pFieldData)
+ return "?";
+
+ OUString aRet;
+ sal_Int32 nClsId = pFieldData->GetClassId();
+ switch (nClsId)
+ {
+ case text::textfield::Type::PAGE:
+ aRet = lcl_GetNumStr( aData.nPageNo,aData.eNumType );
+ break;
+ case text::textfield::Type::PAGES:
+ aRet = lcl_GetNumStr( aData.nTotalPages,aData.eNumType );
+ break;
+ case text::textfield::Type::EXTENDED_TIME:
+ case text::textfield::Type::TIME:
+ // For now, time field in the header / footer is always dynamic.
+ aRet = ScGlobal::getLocaleData().getTime(aData.aDateTime);
+ break;
+ case text::textfield::Type::DOCINFO_TITLE:
+ aRet = aData.aTitle;
+ break;
+ case text::textfield::Type::EXTENDED_FILE:
+ {
+ switch (static_cast<const SvxExtFileField*>(pFieldData)->GetFormat())
+ {
+ case SvxFileFormat::PathFull :
+ aRet = aData.aLongDocName;
+ break;
+ default:
+ aRet = aData.aShortDocName;
+ }
+ }
+ break;
+ case text::textfield::Type::TABLE:
+ aRet = aData.aTabName;
+ break;
+ case text::textfield::Type::DATE:
+ aRet = ScGlobal::getLocaleData().getDate(aData.aDateTime);
+ break;
+ default:
+ aRet = "?";
+ }
+
+ return aRet;
+}
+
+// field data
+
+ScFieldEditEngine::ScFieldEditEngine(
+ ScDocument* pDoc, SfxItemPool* pEnginePoolP,
+ SfxItemPool* pTextObjectPool, bool bDeleteEnginePoolP) :
+ ScEditEngineDefaulter( pEnginePoolP, bDeleteEnginePoolP ),
+ mpDoc(pDoc), bExecuteURL(true)
+{
+ if ( pTextObjectPool )
+ SetEditTextObjectPool( pTextObjectPool );
+ SetControlWord( EEControlBits(GetControlWord() | EEControlBits::MARKFIELDS) & ~EEControlBits::RTFSTYLESHEETS );
+}
+
+OUString ScFieldEditEngine::CalcFieldValue( const SvxFieldItem& rField,
+ sal_Int32 /* nPara */, sal_Int32 /* nPos */,
+ std::optional<Color>& rTxtColor, std::optional<Color>& /* rFldColor */ )
+{
+ const SvxFieldData* pFieldData = rField.GetField();
+
+ if (!pFieldData)
+ return " ";
+
+ return ScEditUtil::GetCellFieldValue(*pFieldData, mpDoc, &rTxtColor);
+}
+
+bool ScFieldEditEngine::FieldClicked( const SvxFieldItem& rField )
+{
+ if (!bExecuteURL)
+ return false;
+
+ if (const SvxURLField* pURLField = dynamic_cast<const SvxURLField*>(rField.GetField()))
+ {
+ ScGlobal::OpenURL(pURLField->GetURL(), pURLField->GetTargetFrame());
+ return true;
+ }
+ return false;
+}
+
+ScNoteEditEngine::ScNoteEditEngine( SfxItemPool* pEnginePoolP,
+ SfxItemPool* pTextObjectPool ) :
+ ScEditEngineDefaulter( pEnginePoolP, false/*bDeleteEnginePoolP*/ )
+{
+ if ( pTextObjectPool )
+ SetEditTextObjectPool( pTextObjectPool );
+ SetControlWord( EEControlBits(GetControlWord() | EEControlBits::MARKFIELDS) & ~EEControlBits::RTFSTYLESHEETS );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */