943 lines
32 KiB
C++
943 lines
32 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <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 <docsh.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();
|
|
if (nParCount == 0)
|
|
return u""_ustr;
|
|
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::AtEnd());
|
|
|
|
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, std::optional<FontLineStyle>* ppFldLineStyle )
|
|
{
|
|
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 = ScModule::get()->GetColorConfig().GetColorValue(eEntry).nColor;
|
|
if (comphelper::LibreOfficeKit::isActive())
|
|
ScModule::IsLOKViewInDarkMode() ? *ppTextColor = Color(0x1D99F3) : *ppTextColor = Color(0x000080);
|
|
}
|
|
|
|
if (ppFldLineStyle)
|
|
*ppFldLineStyle = FontLineStyle::LINESTYLE_SINGLE;
|
|
}
|
|
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)
|
|
{
|
|
ScDocShell* 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 && ( ScModule::get()->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->fillFontOnly(aFont, 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::INVALID)
|
|
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::INVALID || eFieldState == SfxItemState::SET )
|
|
bNeedsObject = true;
|
|
|
|
// not converted characters?
|
|
|
|
SfxItemState eConvState = pEditAttrs->GetItemState( EE_FEATURE_NOTCONV, false );
|
|
if ( eConvState == SfxItemState::INVALID || eConvState == SfxItemState::SET )
|
|
bNeedsObject = true;
|
|
}
|
|
}
|
|
|
|
ScEditAttrTester::~ScEditAttrTester()
|
|
{
|
|
}
|
|
|
|
ScEnginePoolHelper::ScEnginePoolHelper( SfxItemPool* pEnginePoolP,
|
|
bool bDeleteEnginePoolP )
|
|
:
|
|
m_pEnginePool( pEnginePoolP ),
|
|
m_bDeleteEnginePool( bDeleteEnginePoolP )
|
|
{
|
|
}
|
|
|
|
ScEnginePoolHelper::ScEnginePoolHelper( const ScEnginePoolHelper& rOrg )
|
|
:
|
|
m_pEnginePool( rOrg.m_bDeleteEnginePool ? rOrg.m_pEnginePool->Clone() : rOrg.m_pEnginePool ),
|
|
m_bDeleteEnginePool( rOrg.m_bDeleteEnginePool )
|
|
{
|
|
}
|
|
|
|
ScEnginePoolHelper::~ScEnginePoolHelper()
|
|
{
|
|
}
|
|
|
|
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( m_pEnginePool.get() )
|
|
{
|
|
SetDefaultLanguage( ScGlobal::GetEditDefaultLanguage() );
|
|
}
|
|
|
|
ScEditEngineDefaulter::~ScEditEngineDefaulter()
|
|
{
|
|
}
|
|
|
|
void ScEditEngineDefaulter::ApplyDefaults(const SfxItemSet& rNewSet)
|
|
{
|
|
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(const SfxItemSet& rSet)
|
|
{
|
|
SetDefaults(std::make_unique<SfxItemSet>(rSet));
|
|
}
|
|
|
|
void ScEditEngineDefaulter::SetDefaults( std::unique_ptr<SfxItemSet> pSet )
|
|
{
|
|
m_pDefaults = std::move(pSet);
|
|
if ( m_pDefaults )
|
|
ApplyDefaults(*m_pDefaults);
|
|
}
|
|
|
|
void ScEditEngineDefaulter::SetDefaultItem( const SfxPoolItem& rItem )
|
|
{
|
|
if ( !m_pDefaults )
|
|
{
|
|
m_pDefaults = std::make_unique<SfxItemSet>( GetEmptyItemSet() );
|
|
}
|
|
m_pDefaults->Put( rItem );
|
|
ApplyDefaults(*m_pDefaults);
|
|
}
|
|
|
|
const SfxItemSet& ScEditEngineDefaulter::GetDefaults()
|
|
{
|
|
if ( !m_pDefaults )
|
|
{
|
|
m_pDefaults = std::make_unique<SfxItemSet>( GetEmptyItemSet() );
|
|
}
|
|
return *m_pDefaults;
|
|
}
|
|
|
|
void ScEditEngineDefaulter::SetTextCurrentDefaults( const EditTextObject& rTextObject )
|
|
{
|
|
bool bUpdateMode = SetUpdateLayout( false );
|
|
SetText( rTextObject );
|
|
if ( m_pDefaults )
|
|
ApplyDefaults(*m_pDefaults);
|
|
if ( bUpdateMode )
|
|
SetUpdateLayout( true );
|
|
}
|
|
|
|
void ScEditEngineDefaulter::SetTextNewDefaults(const EditTextObject& rTextObject,
|
|
std::unique_ptr<SfxItemSet> pDefaults)
|
|
{
|
|
bool bUpdateMode = SetUpdateLayout( false );
|
|
SetText( rTextObject );
|
|
SetDefaults(std::move(pDefaults));
|
|
if ( bUpdateMode )
|
|
SetUpdateLayout( true );
|
|
}
|
|
|
|
void ScEditEngineDefaulter::SetTextTempDefaults(const EditTextObject& rTextObject,
|
|
const SfxItemSet& rSet)
|
|
{
|
|
bool bUpdateMode = SetUpdateLayout( false );
|
|
SetText( rTextObject );
|
|
ApplyDefaults(rSet);
|
|
if ( bUpdateMode )
|
|
SetUpdateLayout( true );
|
|
}
|
|
|
|
void ScEditEngineDefaulter::SetTextCurrentDefaults( const OUString& rText )
|
|
{
|
|
bool bUpdateMode = SetUpdateLayout( false );
|
|
SetText( rText );
|
|
if ( m_pDefaults )
|
|
ApplyDefaults(*m_pDefaults);
|
|
if ( bUpdateMode )
|
|
SetUpdateLayout( true );
|
|
}
|
|
|
|
void ScEditEngineDefaulter::SetTextNewDefaults( const OUString& rText,
|
|
std::unique_ptr<SfxItemSet> pDefaults )
|
|
{
|
|
bool bUpdateMode = SetUpdateLayout( false );
|
|
SetText( rText );
|
|
SetDefaults(std::move(pDefaults));
|
|
if ( bUpdateMode )
|
|
SetUpdateLayout( true );
|
|
}
|
|
|
|
void ScEditEngineDefaulter::RepeatDefaults()
|
|
{
|
|
if ( m_pDefaults )
|
|
{
|
|
sal_Int32 nPara = GetParagraphCount();
|
|
for ( sal_Int32 j=0; j<nPara; j++ )
|
|
SetParaAttribs( j, *m_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 ( !m_pDefaults || *pParaItem != m_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() );
|
|
const ScPatternAttr& rScPatternAttr(pDoc->getCellAttributeHelper().getDefaultCellAttribute());
|
|
Init(rScPatternAttr);
|
|
}
|
|
|
|
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 */,
|
|
std::optional<FontLineStyle>& /*rFldLineStyle*/ )
|
|
{
|
|
const SvxFieldData* pFieldData = rField.GetField();
|
|
if (!pFieldData)
|
|
return u"?"_ustr;
|
|
|
|
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 */,
|
|
std::optional<FontLineStyle>& rFldLineStyle )
|
|
{
|
|
const SvxFieldData* pFieldData = rField.GetField();
|
|
|
|
if (!pFieldData)
|
|
return u" "_ustr;
|
|
|
|
return ScEditUtil::GetCellFieldValue(*pFieldData, mpDoc, &rTxtColor, &rFldLineStyle);
|
|
}
|
|
|
|
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: */
|