/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <sal/config.h>
#include <algorithm>
#include <memory>
#include <unofield.hxx>
#include <unofieldcoll.hxx>
#include <unobookmark.hxx>
#include <swtypes.hxx>
#include <cmdid.h>
#include <doc.hxx>
#include <IDocumentFieldsAccess.hxx>
#include <IDocumentStatistics.hxx>
#include <IDocumentStylePoolAccess.hxx>
#include <IDocumentLayoutAccess.hxx>
#include <IDocumentState.hxx>
#include <fmtfld.hxx>
#include <txtfld.hxx>
#include <ndtxt.hxx>
#include <unomap.hxx>
#include <unoprnms.hxx>
#include <unotextrange.hxx>
#include <unotextcursor.hxx>
#include <unocoll.hxx>
#include <sfx2/linkmgr.hxx>
#include <editsh.hxx>
#include <viewsh.hxx>
#include <comphelper/interfacecontainer4.hxx>
#include <comphelper/servicehelper.hxx>
#include <comphelper/string.hxx>
#include <cppuhelper/supportsservice.hxx>
#include <com/sun/star/util/DateTime.hpp>
#include <com/sun/star/util/Date.hpp>
#include <com/sun/star/beans/PropertyAttribute.hpp>
//undef to prevent error (from sfx2/docfile.cxx)
#undef SEQUENCE
#include <com/sun/star/text/SetVariableType.hpp>
#include <com/sun/star/text/WrapTextMode.hpp>
#include <com/sun/star/text/TextContentAnchorType.hpp>
#include <authfld.hxx>
#include <flddat.hxx>
#include <dbfld.hxx>
#include <usrfld.hxx>
#include <docufld.hxx>
#include <expfld.hxx>
#include <chpfld.hxx>
#include <flddropdown.hxx>
#include <poolfmt.hxx>
#include <strings.hrc>
#include <pagedesc.hxx>
#include <docary.hxx>
#include <reffld.hxx>
#include <ddefld.hxx>
#include <SwStyleNameMapper.hxx>
#include <swunohelper.hxx>
#include <unofldmid.h>
#include <scriptinfo.hxx>
#include <tools/datetime.hxx>
#include <tools/urlobj.hxx>
#include <svl/itemprop.hxx>
#include <svl/listener.hxx>
#include <svx/dataaccessdescriptor.hxx>
#include <o3tl/any.hxx>
#include <o3tl/safeint.hxx>
#include <mutex>
#include <vcl/svapp.hxx>
#include <textapi.hxx>
#include <fmtmeta.hxx>
#include <annotationmark.hxx>
#include <names.hxx>
#include <vector>
using namespace ::com::sun::star;
using namespace nsSwDocInfoSubType;
// case-corrected version of the first part for the service names (see #i67811)
constexpr OUString COM_TEXT_FLDMASTER_CC = u
"com.sun.star.text.fieldmaster."_ustr;
// note: this thing is indexed as an array, so do not insert/remove entries!
const sal_uInt16 aDocInfoSubTypeFromService[] =
{
DI_CHANGE | DI_SUB_AUTHOR,
//PROPERTY_MAP_FLDTYP_DOCINFO_CHANGE_AUTHOR
DI_CHANGE | DI_SUB_DATE,
//PROPERTY_MAP_FLDTYP_DOCINFO_CHANGE_DATE_TIME
DI_EDIT | DI_SUB_TIME,
//PROPERTY_MAP_FLDTYP_DOCINFO_EDIT_TIME
DI_COMMENT,
//PROPERTY_MAP_FLDTYP_DOCINFO_DESCRIPTION
DI_CREATE | DI_SUB_AUTHOR,
//PROPERTY_MAP_FLDTYP_DOCINFO_CREATE_AUTHOR
DI_CREATE | DI_SUB_DATE,
//PROPERTY_MAP_FLDTYP_DOCINFO_CREATE_DATE_TIME
0,
//DUMMY
0,
//DUMMY
0,
//DUMMY
0,
//DUMMY
DI_CUSTOM,
//PROPERTY_MAP_FLDTYP_DOCINFO_CUSTOM
DI_PRINT | DI_SUB_AUTHOR,
//PROPERTY_MAP_FLDTYP_DOCINFO_PRINT_AUTHOR
DI_PRINT | DI_SUB_DATE,
//PROPERTY_MAP_FLDTYP_DOCINFO_PRINT_DATE_TIME
DI_KEYS,
//PROPERTY_MAP_FLDTYP_DOCINFO_KEY_WORDS
DI_SUBJECT,
//PROPERTY_MAP_FLDTYP_DOCINFO_SUBJECT
DI_TITLE,
//PROPERTY_MAP_FLDTYP_DOCINFO_TITLE
DI_DOCNO
//PROPERTY_MAP_FLDTYP_DOCINFO_REVISION
};
namespace {
struct ServiceIdResId
{
SwFieldIds nResId;
SwServiceType nServiceId;
};
}
const ServiceIdResId aServiceToRes[] =
{
{SwFieldIds::DateTime, SwServiceType::FieldTypeDateTime },
{SwFieldIds::User, SwServiceType::FieldTypeUser },
{SwFieldIds::SetExp, SwServiceType::FieldTypeSetExp },
{SwFieldIds::GetExp, SwServiceType::FieldTypeGetExp },
{SwFieldIds::Filename, SwServiceType::FieldTypeFileName },
{SwFieldIds::PageNumber, SwServiceType::FieldTypePageNum },
{SwFieldIds::Author, SwServiceType::FieldTypeAuthor },
{SwFieldIds::Chapter, SwServiceType::FieldTypeChapter },
{SwFieldIds::GetRef, SwServiceType::FieldTypeGetReference },
{SwFieldIds::HiddenText, SwServiceType::FieldTypeConditionedText },
{SwFieldIds::Postit, SwServiceType::FieldTypeAnnotation },
{SwFieldIds::Input, SwServiceType::FieldTypeInput },
{SwFieldIds::Macro, SwServiceType::FieldTypeMacro },
{SwFieldIds::Dde, SwServiceType::FieldTypeDDE },
{SwFieldIds::HiddenPara, SwServiceType::FieldTypeHiddenPara },
{SwFieldIds::DocInfo, SwServiceType::FieldTypeDocInfo },
{SwFieldIds::TemplateName, SwServiceType::FieldTypeTemplateName },
{SwFieldIds::ExtUser, SwServiceType::FieldTypeUserExt },
{SwFieldIds::RefPageSet, SwServiceType::FieldTypeRefPageSet },
{SwFieldIds::RefPageGet, SwServiceType::FieldTypeRefPageGet },
{SwFieldIds::JumpEdit, SwServiceType::FieldTypeJumpEdit },
{SwFieldIds::Script, SwServiceType::FieldTypeScript },
{SwFieldIds::DbNextSet, SwServiceType::FieldTypeDatabaseNextSet },
{SwFieldIds::DbNumSet, SwServiceType::FieldTypeDatabaseNumSet },
{SwFieldIds::DbSetNumber, SwServiceType::FieldTypeDatabaseSetNum },
{SwFieldIds::Database, SwServiceType::FieldTypeDatabase },
{SwFieldIds::DatabaseName, SwServiceType::FieldTypeDatabaseName },
{SwFieldIds::DocStat, SwServiceType::FieldTypePageCount },
{SwFieldIds::DocStat, SwServiceType::FieldTypePageCountRange },
{SwFieldIds::DocStat, SwServiceType::FieldTypeParagraphCount },
{SwFieldIds::DocStat, SwServiceType::FieldTypeWordCount },
{SwFieldIds::DocStat, SwServiceType::FieldTypeCharacterCount },
{SwFieldIds::DocStat, SwServiceType::FieldTypeTableCount },
{SwFieldIds::DocStat, SwServiceType::FieldTypeGraphicObjectCount },
{SwFieldIds::DocStat, SwServiceType::FieldTypeEmbeddedObjectCount },
{SwFieldIds::DocInfo, SwServiceType::FieldTypeDocInfoChangeAuthor },
{SwFieldIds::DocInfo, SwServiceType::FieldTypeDocInfoChangeDateTime },
{SwFieldIds::DocInfo, SwServiceType::FieldTypeDocInfoEditTime },
{SwFieldIds::DocInfo, SwServiceType::FieldTypeDocInfoDescription },
{SwFieldIds::DocInfo, SwServiceType::FieldTypeDocInfoCreateAuthor },
{SwFieldIds::DocInfo, SwServiceType::FieldTypeDocInfoCreateDateTime },
{SwFieldIds::DocInfo, SwServiceType::FieldTypeDocInfoCustom },
{SwFieldIds::DocInfo, SwServiceType::FieldTypeDocInfoPrintAuthor },
{SwFieldIds::DocInfo, SwServiceType::FieldTypeDocInfoPrintDateTime },
{SwFieldIds::DocInfo, SwServiceType::FieldTypeDocInfoKeywords },
{SwFieldIds::DocInfo, SwServiceType::FieldTypeDocInfoSubject },
{SwFieldIds::DocInfo, SwServiceType::FieldTypeDocInfoTitle },
{SwFieldIds::Input, SwServiceType::FieldTypeInputUser },
{SwFieldIds::HiddenText, SwServiceType::FieldTypeHiddenText },
{SwFieldIds::TableOfAuthorities, SwServiceType::FieldTypeBibliography },
{SwFieldIds::CombinedChars, SwServiceType::FieldTypeCombinedCharacters },
{SwFieldIds::Dropdown, SwServiceType::FieldTypeDropdown },
{SwFieldIds::Table, SwServiceType::FieldTypeTableFormula }
};
static SwFieldIds lcl_ServiceIdToResId(SwServiceType nServiceId)
{
for (
auto const& aEntry : aServiceToRes)
if (aEntry.nServiceId == nServiceId)
return aEntry.nResId;
#if OSL_DEBUG_LEVEL > 0
OSL_FAIL(
"service id not found");
#endif
return SwFieldIds::Unknown;
}
static SwServiceType lcl_GetServiceForField(
const SwField& rField )
{
const SwFieldIds nWhich = rField.Which();
SwServiceType nSrvId = SwServiceType::Invalid;
//special handling for some fields
switch( nWhich )
{
case SwFieldIds::Input:
if( INP_USR == (rField.GetSubType() & 0x00ff) )
nSrvId = SwServiceType::FieldTypeInputUser;
break;
case SwFieldIds::DocInfo:
{
const sal_uInt16 nSubType = rField.GetSubType();
switch( nSubType & 0xff )
{
case DI_CHANGE:
nSrvId = ((nSubType&0x300) == DI_SUB_AUTHOR)
? SwServiceType::FieldTypeDocInfoChangeAuthor
: SwServiceType::FieldTypeDocInfoChangeDateTime;
break;
case DI_CREATE:
nSrvId = ((nSubType&0x300) == DI_SUB_AUTHOR)
? SwServiceType::FieldTypeDocInfoCreateAuthor
: SwServiceType::FieldTypeDocInfoCreateDateTime;
break;
case DI_PRINT:
nSrvId = ((nSubType&0x300) == DI_SUB_AUTHOR)
? SwServiceType::FieldTypeDocInfoPrintAuthor
: SwServiceType::FieldTypeDocInfoPrintDateTime;
break;
case DI_EDIT: nSrvId = SwServiceType::FieldTypeDocInfoEditTime;
break;
case DI_COMMENT:nSrvId = SwServiceType::FieldTypeDocInfoDescription;
break;
case DI_KEYS: nSrvId = SwServiceType::FieldTypeDocInfoKeywords;
break;
case DI_SUBJECT:nSrvId = SwServiceType::FieldTypeDocInfoSubject;
break;
case DI_TITLE: nSrvId = SwServiceType::FieldTypeDocInfoTitle;
break;
case DI_DOCNO: nSrvId = SwServiceType::FieldTypeDocInfoRevision;
break;
case DI_CUSTOM: nSrvId = SwServiceType::FieldTypeDocInfoCustom;
break;
}
}
break;
case SwFieldIds::HiddenText:
nSrvId = SwFieldTypesEnum::ConditionalText ==
static_cast<SwFieldTypesEnum>(rField.Get
SubType())
? SwServiceType::FieldTypeConditionedText
: SwServiceType::FieldTypeHiddenText;
break;
case SwFieldIds::DocStat:
{
switch( rField.GetSubType() )
{
case DS_PAGE_RANGE:nSrvId = SwServiceType::FieldTypePageCountRange; break;
case DS_PAGE: nSrvId = SwServiceType::FieldTypePageCount; break;
case DS_PARA: nSrvId = SwServiceType::FieldTypeParagraphCount; break;
case DS_WORD: nSrvId = SwServiceType::FieldTypeWordCount ; break;
case DS_CHAR: nSrvId = SwServiceType::FieldTypeCharacterCount; break;
case DS_TBL: nSrvId = SwServiceType::FieldTypeTableCount ; break;
case DS_GRF: nSrvId = SwServiceType::FieldTypeGraphicObjectCount; break;
case DS_OLE: nSrvId = SwServiceType::FieldTypeEmbeddedObjectCount; break;
}
}
break;
default: break;
}
if( SwServiceType::Invalid == nSrvId )
{
for( const ServiceIdResId* pMap = aServiceToRes;
SwFieldIds::Unknown != pMap->nResId; ++pMap )
if( nWhich == pMap->nResId )
{
nSrvId = pMap->nServiceId;
break;
}
}
#if OSL_DEBUG_LEVEL > 0
if( SwServiceType::Invalid == nSrvId )
OSL_FAIL("resid not found");
#endif
return nSrvId;
}
static sal_uInt16 lcl_GetPropMapIdForFieldType( SwFieldIds nWhich )
{
sal_uInt16 nId;
switch( nWhich )
{
case SwFieldIds::User: nId = PROPERTY_MAP_FLDMSTR_USER; break;
case SwFieldIds::Database: nId = PROPERTY_MAP_FLDMSTR_DATABASE; break;
case SwFieldIds::SetExp: nId = PROPERTY_MAP_FLDMSTR_SET_EXP; break;
case SwFieldIds::Dde: nId = PROPERTY_MAP_FLDMSTR_DDE; break;
case SwFieldIds::TableOfAuthorities:
nId = PROPERTY_MAP_FLDMSTR_BIBLIOGRAPHY; break;
default: nId = PROPERTY_MAP_FLDMSTR_DUMMY0;
}
return nId;
}
static sal_Int32 lcl_PropName2TokenPos(std::u16string_view rPropertyName)
{
if (rPropertyName == UNO_NAME_DDE_COMMAND_TYPE)
return 0;
if (rPropertyName == UNO_NAME_DDE_COMMAND_FILE)
return 1;
if (rPropertyName == UNO_NAME_DDE_COMMAND_ELEMENT)
return 2;
if (rPropertyName == UNO_NAME_IS_AUTOMATIC_UPDATE)
return 3;
return SAL_MAX_INT32;
}
static sal_uInt16 GetFieldTypeMId( std::u16string_view rProperty, const SwFieldType& rTyp )
{
sal_uInt16 nId = lcl_GetPropMapIdForFieldType( rTyp.Which() );
const SfxItemPropertySet* pSet = aSwMapProvider.GetPropertySet( nId );
if( !pSet )
nId = USHRT_MAX;
else
{
const SfxItemPropertyMapEntry* pEntry = pSet->getPropertyMap().getByName(rProperty);
nId = pEntry ? pEntry->nWID : USHRT_MAX;
}
return nId;
}
static sal_uInt16 lcl_GetPropertyMapOfService( SwServiceType nServiceId )
{
sal_uInt16 nRet;
switch ( nServiceId)
{
case SwServiceType::FieldTypeDateTime: nRet = PROPERTY_MAP_FLDTYP_DATETIME; break;
case SwServiceType::FieldTypeUser: nRet = PROPERTY_MAP_FLDTYP_USER; break;
case SwServiceType::FieldTypeSetExp: nRet = PROPERTY_MAP_FLDTYP_SET_EXP; break;
case SwServiceType::FieldTypeGetExp: nRet = PROPERTY_MAP_FLDTYP_GET_EXP; break;
case SwServiceType::FieldTypeFileName: nRet = PROPERTY_MAP_FLDTYP_FILE_NAME; break;
case SwServiceType::FieldTypePageNum: nRet = PROPERTY_MAP_FLDTYP_PAGE_NUM; break;
case SwServiceType::FieldTypeAuthor: nRet = PROPERTY_MAP_FLDTYP_AUTHOR; break;
case SwServiceType::FieldTypeChapter: nRet = PROPERTY_MAP_FLDTYP_CHAPTER; break;
case SwServiceType::FieldTypeGetReference: nRet = PROPERTY_MAP_FLDTYP_GET_REFERENCE; break;
case SwServiceType::FieldTypeConditionedText: nRet = PROPERTY_MAP_FLDTYP_CONDITIONED_TEXT; break;
case SwServiceType::FieldTypeAnnotation: nRet = PROPERTY_MAP_FLDTYP_ANNOTATION; break;
case SwServiceType::FieldTypeInputUser:
case SwServiceType::FieldTypeInput: nRet = PROPERTY_MAP_FLDTYP_INPUT; break;
case SwServiceType::FieldTypeMacro: nRet = PROPERTY_MAP_FLDTYP_MACRO; break;
case SwServiceType::FieldTypeDDE: nRet = PROPERTY_MAP_FLDTYP_DDE; break;
case SwServiceType::FieldTypeHiddenPara: nRet = PROPERTY_MAP_FLDTYP_HIDDEN_PARA; break;
case SwServiceType::FieldTypeDocInfo: nRet = PROPERTY_MAP_FLDTYP_DOC_INFO; break;
case SwServiceType::FieldTypeTemplateName: nRet = PROPERTY_MAP_FLDTYP_TEMPLATE_NAME; break;
case SwServiceType::FieldTypeUserExt: nRet = PROPERTY_MAP_FLDTYP_USER_EXT; break;
case SwServiceType::FieldTypeRefPageSet: nRet = PROPERTY_MAP_FLDTYP_REF_PAGE_SET; break;
case SwServiceType::FieldTypeRefPageGet: nRet = PROPERTY_MAP_FLDTYP_REF_PAGE_GET; break;
case SwServiceType::FieldTypeJumpEdit: nRet = PROPERTY_MAP_FLDTYP_JUMP_EDIT; break;
case SwServiceType::FieldTypeScript: nRet = PROPERTY_MAP_FLDTYP_SCRIPT; break;
case SwServiceType::FieldTypeDatabaseNextSet: nRet = PROPERTY_MAP_FLDTYP_DATABASE_NEXT_SET; break;
case SwServiceType::FieldTypeDatabaseNumSet: nRet = PROPERTY_MAP_FLDTYP_DATABASE_NUM_SET; break;
case SwServiceType::FieldTypeDatabaseSetNum: nRet = PROPERTY_MAP_FLDTYP_DATABASE_SET_NUM; break;
case SwServiceType::FieldTypeDatabase: nRet = PROPERTY_MAP_FLDTYP_DATABASE; break;
case SwServiceType::FieldTypeDatabaseName: nRet = PROPERTY_MAP_FLDTYP_DATABASE_NAME; break;
case SwServiceType::FieldTypeTableFormula: nRet = PROPERTY_MAP_FLDTYP_TABLE_FORMULA; break;
case SwServiceType::FieldTypePageCountRange:
case SwServiceType::FieldTypePageCount:
case SwServiceType::FieldTypeParagraphCount:
case SwServiceType::FieldTypeWordCount:
case SwServiceType::FieldTypeCharacterCount:
case SwServiceType::FieldTypeTableCount:
case SwServiceType::FieldTypeGraphicObjectCount:
case SwServiceType::FieldTypeEmbeddedObjectCount: nRet = PROPERTY_MAP_FLDTYP_DOCSTAT; break;
case SwServiceType::FieldTypeDocInfoChangeAuthor:
case SwServiceType::FieldTypeDocInfoCreateAuthor:
case SwServiceType::FieldTypeDocInfoPrintAuthor: nRet = PROPERTY_MAP_FLDTYP_DOCINFO_AUTHOR; break;
case SwServiceType::FieldTypeDocInfoChangeDateTime:
case SwServiceType::FieldTypeDocInfoCreateDateTime:
case SwServiceType::FieldTypeDocInfoPrintDateTime: nRet = PROPERTY_MAP_FLDTYP_DOCINFO_DATE_TIME; break;
case SwServiceType::FieldTypeDocInfoEditTime: nRet = PROPERTY_MAP_FLDTYP_DOCINFO_EDIT_TIME; break;
case SwServiceType::FieldTypeDocInfoCustom: nRet = PROPERTY_MAP_FLDTYP_DOCINFO_CUSTOM; break;
case SwServiceType::FieldTypeDocInfoDescription:
case SwServiceType::FieldTypeDocInfoKeywords:
case SwServiceType::FieldTypeDocInfoSubject:
case SwServiceType::FieldTypeDocInfoTitle: nRet = PROPERTY_MAP_FLDTYP_DOCINFO_MISC; break;
case SwServiceType::FieldTypeDocInfoRevision: nRet = PROPERTY_MAP_FLDTYP_DOCINFO_REVISION; break;
case SwServiceType::FieldTypeBibliography: nRet = PROPERTY_MAP_FLDTYP_BIBLIOGRAPHY; break;
case SwServiceType::FieldTypeDummy0:
case SwServiceType::FieldTypeCombinedCharacters: nRet = PROPERTY_MAP_FLDTYP_COMBINED_CHARACTERS; break;
case SwServiceType::FieldTypeDropdown: nRet = PROPERTY_MAP_FLDTYP_DROPDOWN; break;
case SwServiceType::FieldTypeDummy4:
case SwServiceType::FieldTypeDummy5:
case SwServiceType::FieldTypeDummy6:
case SwServiceType::FieldTypeDummy7:
nRet = PROPERTY_MAP_FLDTYP_DUMMY_0; break;
case SwServiceType::FieldMasterUser: nRet = PROPERTY_MAP_FLDMSTR_USER; break;
case SwServiceType::FieldMasterDDE: nRet = PROPERTY_MAP_FLDMSTR_DDE; break;
case SwServiceType::FieldMasterSetExp: nRet = PROPERTY_MAP_FLDMSTR_SET_EXP; break;
case SwServiceType::FieldMasterDatabase: nRet = PROPERTY_MAP_FLDMSTR_DATABASE; break;
case SwServiceType::FieldMasterBibliography: nRet = PROPERTY_MAP_FLDMSTR_BIBLIOGRAPHY; break;
case SwServiceType::FieldMasterDummy2:
case SwServiceType::FieldMasterDummy3:
case SwServiceType::FieldMasterDummy4:
case SwServiceType::FieldMasterDummy5: nRet = PROPERTY_MAP_FLDMSTR_DUMMY0; break;
case SwServiceType::FieldTypeHiddenText: nRet = PROPERTY_MAP_FLDTYP_HIDDEN_TEXT; break;
default:
nRet = USHRT_MAX;
}
assert(nRet != USHRT_MAX && "wrong service id");
return nRet;
}
class SwXFieldMaster::Impl
: public SvtListener
{
public:
std::mutex m_Mutex; // just for OInterfaceContainerHelper4
unotools::WeakReference<SwXFieldMaster> m_wThis;
::comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> m_EventListeners;
SwDoc* m_pDoc;
SwFieldType* m_pType;
SwFieldIds m_nResTypeId;
OUString m_sParam1; // Content / Database / NumberingSeparator
OUString m_sParam2; // - /DataTablename
OUString m_sParam3; // - /DataFieldName
OUString m_sParam5; // - /DataBaseURL
double m_fParam1; // Value / -
sal_Int8 m_nParam1; // ChapterNumberingLevel
bool m_bParam1; // IsExpression
sal_Int32 m_nParam2;
Impl(SwPageDesc* const pPageDesc, SwDoc* pDoc, SwFieldIds nResId)
: m_pDoc(pDoc)
, m_pType(nullptr)
, m_nResTypeId(nResId)
, m_fParam1(0.0)
, m_nParam1(-1)
, m_bParam1(false)
, m_nParam2(0)
{
StartListening(pPageDesc->GetNotifier());
}
Impl(SwFieldType* const pType, SwDoc* pDoc, SwFieldIds nResId)
: m_pDoc(pDoc)
, m_pType(pType)
, m_nResTypeId(nResId)
, m_fParam1(0.0)
, m_nParam1(-1)
, m_bParam1(false)
, m_nParam2(0)
{
StartListening(m_pType->GetNotifier());
}
void SetFieldType(SwFieldType* pType)
{
EndListeningAll();
m_pType = pType;
StartListening(m_pType->GetNotifier());
}
protected:
virtual void Notify(const SfxHint& rHint) override;
};
OUString SAL_CALL
SwXFieldMaster::getImplementationName()
{
return u"SwXFieldMaster"_ustr;
}
namespace
{
OUString getServiceName(const SwFieldIds aId)
{
const char* pEntry;
switch (aId)
{
case SwFieldIds::User:
pEntry = "User";
break;
case SwFieldIds::Database:
pEntry = "Database";
break;
case SwFieldIds::SetExp:
pEntry = "SetExpression";
break;
case SwFieldIds::Dde:
pEntry = "DDE";
break;
case SwFieldIds::TableOfAuthorities:
pEntry = "Bibliography";
break;
default:
return OUString();
}
return "com.sun.star.text.fieldmaster." + OUString::createFromAscii(pEntry);
}
}
sal_Bool SAL_CALL SwXFieldMaster::supportsService(const OUString& rServiceName)
{
return cppu::supportsService(this, rServiceName);
}
uno::Sequence< OUString > SAL_CALL
SwXFieldMaster::getSupportedServiceNames()
{
return { u"com.sun.star.text.TextFieldMaster"_ustr, getServiceName(m_pImpl->m_nResTypeId) };
}
SwXFieldMaster::SwXFieldMaster(SwDoc& rDoc, SwFieldIds const nResId)
: m_pImpl(new Impl(rDoc.getIDocumentStylePoolAccess().GetPageDescFromPool(RES_POOLPAGE_STANDARD), &rDoc, nResId))
{
}
SwXFieldMaster::SwXFieldMaster(SwFieldType& rType, SwDoc * pDoc)
: m_pImpl(new Impl(&rType, pDoc, rType.Which()))
{
}
SwXFieldMaster::~SwXFieldMaster()
{
}
rtl::Reference<SwXFieldMaster>
SwXFieldMaster::CreateXFieldMaster(SwDoc * pDoc, SwFieldType *const pType,
SwFieldIds nResId)
{
// re-use existing SwXFieldMaster
rtl::Reference<SwXFieldMaster> xFM;
if (pType)
{
xFM = pType->GetXObject().get();
}
if (!xFM.is())
{
SwXFieldMaster *const pFM( pType
? new SwXFieldMaster(*pType, pDoc)
: new SwXFieldMaster(*pDoc, nResId));
xFM.set(pFM);
if (pType)
{
pType->SetXObject(xFM);
}
// need a permanent Reference to initialize m_wThis
pFM->m_pImpl->m_wThis = xFM.get();
}
return xFM;
}
uno::Reference<beans::XPropertySetInfo> SAL_CALL
SwXFieldMaster::getPropertySetInfo()
{
SolarMutexGuard aGuard;
rtl::Reference< SfxItemPropertySetInfo > aRef =
aSwMapProvider.GetPropertySet(
lcl_GetPropMapIdForFieldType(m_pImpl->m_nResTypeId))->getPropertySetInfo();
return aRef;
}
void SAL_CALL SwXFieldMaster::setPropertyValue(
const OUString& rPropertyName, const uno::Any& rValue)
{
SolarMutexGuard aGuard;
SwFieldType* pType = GetFieldType(true);
if(pType)
{
bool bSetValue = true;
if( rPropertyName == UNO_NAME_SUB_TYPE )
{
const std::vector<OUString>& rExtraArr(
SwStyleNameMapper::GetExtraUINameArray());
const OUString sTypeName = pType->GetName().toString();
static sal_uInt16 nIds[] =
{
RES_POOLCOLL_LABEL_DRAWING - RES_POOLCOLL_EXTRA_BEGIN,
RES_POOLCOLL_LABEL_ABB - RES_POOLCOLL_EXTRA_BEGIN,
RES_POOLCOLL_LABEL_TABLE - RES_POOLCOLL_EXTRA_BEGIN,
RES_POOLCOLL_LABEL_FRAME- RES_POOLCOLL_EXTRA_BEGIN,
RES_POOLCOLL_LABEL_FIGURE - RES_POOLCOLL_EXTRA_BEGIN,
0
};
for(const sal_uInt16 * pIds = nIds; *pIds; ++pIds)
{
if(sTypeName == rExtraArr[ *pIds ] )
{
bSetValue = false;
break;
}
}
}
if ( bSetValue )
{
// nothing special to be done here for the properties
// UNO_NAME_DATA_BASE_NAME and UNO_NAME_DATA_BASE_URL.
// We just call PutValue (empty string is allowed).
// Thus the last property set will be used as Data Source.
const sal_uInt16 nMemberValueId = GetFieldTypeMId( rPropertyName, *pType );
if ( USHRT_MAX == nMemberValueId )
{
throw beans::UnknownPropertyException(
"Unknown property: " + rPropertyName,
getXWeak() );
}
pType->PutValue( rValue, nMemberValueId );
if ( pType->Which() == SwFieldIds::User )
{
// trigger update of User field in order to get depending Input Fields updated.
pType->UpdateFields();
}
}
}
else if (m_pImpl->m_pDoc && rPropertyName == UNO_NAME_NAME)
{
OUString sTypeName;
rValue >>= sTypeName;
SwFieldType * pType2 = m_pImpl->m_pDoc->getIDocumentFieldsAccess().GetFieldType(
m_pImpl->m_nResTypeId, sTypeName, false);
if(pType2 ||
(SwFieldIds::SetExp == m_pImpl->m_nResTypeId &&
( sTypeName == SwResId(STR_POOLCOLL_LABEL_TABLE) ||
sTypeName == SwResId(STR_POOLCOLL_LABEL_DRAWING) ||
sTypeName == SwResId(STR_POOLCOLL_LABEL_FRAME) ||
sTypeName == SwResId(STR_POOLCOLL_LABEL_ABB) ||
sTypeName == SwResId(STR_POOLCOLL_LABEL_FIGURE) )))
{
throw lang::IllegalArgumentException();
}
switch (m_pImpl->m_nResTypeId)
{
case SwFieldIds::User :
{
SwUserFieldType aType(m_pImpl->m_pDoc, UIName(sTypeName));
pType2 = m_pImpl->m_pDoc->getIDocumentFieldsAccess().InsertFieldType(aType);
static_cast<SwUserFieldType*>(pType2)->SetContent(m_pImpl->m_sParam1);
static_cast<SwUserFieldType*>(pType2)->SetValue(m_pImpl->m_fParam1);
static_cast<SwUserFieldType*>(pType2)->SetType(m_pImpl->m_bParam1
? nsSwGetSetExpType::GSE_EXPR : nsSwGetSetExpType::GSE_STRING);
}
break;
case SwFieldIds::Dde :
{
SwDDEFieldType aType(UIName(sTypeName), m_pImpl->m_sParam1,
m_pImpl->m_bParam1 ? SfxLinkUpdateMode::ALWAYS : SfxLinkUpdateMode::ONCALL);
pType2 = m_pImpl->m_pDoc->getIDocumentFieldsAccess().InsertFieldType(aType);
}
break;
case SwFieldIds::SetExp :
{
SwSetExpFieldType aType(m_pImpl->m_pDoc, UIName(sTypeName));
if (!m_pImpl->m_sParam1.isEmpty())
aType.SetDelimiter(OUString(m_pImpl->m_sParam1[0]));
if (m_pImpl->m_nParam1 > -1 && m_pImpl->m_nParam1 < MAXLEVEL)
aType.SetOutlineLvl(m_pImpl->m_nParam1);
pType2 = m_pImpl->m_pDoc->getIDocumentFieldsAccess().InsertFieldType(aType);
}
break;
case SwFieldIds::Database :
{
rValue >>= m_pImpl->m_sParam3;
pType2 = GetFieldType();
}
break;
default: break;
}
if (!pType2)
{
throw uno::RuntimeException(u"no field type found!"_ustr, *this);
}
m_pImpl->SetFieldType(pType2);
}
else
{
switch (m_pImpl->m_nResTypeId)
{
case SwFieldIds::User:
if(rPropertyName == UNO_NAME_CONTENT)
rValue >>= m_pImpl->m_sParam1;
else if(rPropertyName == UNO_NAME_VALUE)
{
if(rValue.getValueType() != ::cppu::UnoType<double>::get())
throw lang::IllegalArgumentException();
rValue >>= m_pImpl->m_fParam1;
}
else if(rPropertyName == UNO_NAME_IS_EXPRESSION)
{
if(rValue.getValueType() != cppu::UnoType<bool>::get())
throw lang::IllegalArgumentException();
rValue >>= m_pImpl->m_bParam1;
}
break;
case SwFieldIds::Database:
if(rPropertyName == UNO_NAME_DATA_BASE_NAME)
rValue >>= m_pImpl->m_sParam1;
else if(rPropertyName == UNO_NAME_DATA_TABLE_NAME)
rValue >>= m_pImpl->m_sParam2;
else if(rPropertyName == UNO_NAME_DATA_COLUMN_NAME)
rValue >>= m_pImpl->m_sParam3;
else if(rPropertyName == UNO_NAME_DATA_COMMAND_TYPE)
rValue >>= m_pImpl->m_nParam2;
if(rPropertyName == UNO_NAME_DATA_BASE_URL)
rValue >>= m_pImpl->m_sParam5;
if ( ( !m_pImpl->m_sParam1.isEmpty()
|| !m_pImpl->m_sParam5.isEmpty())
&& !m_pImpl->m_sParam2.isEmpty()
&& !m_pImpl->m_sParam3.isEmpty())
{
GetFieldType();
}
break;
case SwFieldIds::SetExp:
if(rPropertyName == UNO_NAME_NUMBERING_SEPARATOR)
rValue >>= m_pImpl->m_sParam1;
else if(rPropertyName == UNO_NAME_CHAPTER_NUMBERING_LEVEL)
rValue >>= m_pImpl->m_nParam1;
break;
case SwFieldIds::Dde:
{
sal_Int32 nPart = lcl_PropName2TokenPos(rPropertyName);
if(nPart < 3 )
{
if (m_pImpl->m_sParam1.isEmpty())
{
m_pImpl->m_sParam1
= OUStringChar(sfx2::cTokenSeparator)
+ OUStringChar(sfx2::cTokenSeparator);
}
OUString sTmp;
rValue >>= sTmp;
sal_Int32 nIndex(0);
sal_Int32 nStart(0);
while (nIndex < m_pImpl->m_sParam1.getLength())
{
if (m_pImpl->m_sParam1[nIndex] == sfx2::cTokenSeparator)
{
if (0 == nPart)
break;
nStart = nIndex + 1;
--nPart;
}
++nIndex;
}
assert(0 == nPart);
m_pImpl->m_sParam1 = m_pImpl->m_sParam1.replaceAt(
nStart, nIndex - nStart, sTmp);
}
else if(3 == nPart)
{
rValue >>= m_pImpl->m_bParam1;
}
}
break;
default:
throw beans::UnknownPropertyException( "Unknown property: " + rPropertyName, getXWeak() );
}
}
}
SwFieldType* SwXFieldMaster::GetFieldType(bool const bDontCreate) const
{
if (!bDontCreate && SwFieldIds::Database == m_pImpl->m_nResTypeId
&& !m_pImpl->m_pType && m_pImpl->m_pDoc)
{
SwDBData aData;
// set DataSource
svx::ODataAccessDescriptor aAcc;
if (!m_pImpl->m_sParam1.isEmpty())
aAcc[svx::DataAccessDescriptorProperty::DataSource] <<= m_pImpl->m_sParam1; // DataBaseName
else if (!m_pImpl->m_sParam5.isEmpty())
aAcc[svx::DataAccessDescriptorProperty::DatabaseLocation] <<= m_pImpl->m_sParam5; // DataBaseURL
aData.sDataSource = aAcc.getDataSource();
aData.sCommand = m_pImpl->m_sParam2;
aData.nCommandType = m_pImpl->m_nParam2;
SwDBFieldType aType(m_pImpl->m_pDoc, m_pImpl->m_sParam3, std::move(aData));
SwFieldType *const pType = m_pImpl->m_pDoc->getIDocumentFieldsAccess().InsertFieldType(aType);
m_pImpl->SetFieldType(pType);
}
return m_pImpl->m_pType;
}
uno::Any SAL_CALL
SwXFieldMaster::getPropertyValue(const OUString& rPropertyName)
{
SolarMutexGuard aGuard;
uno::Any aRet;
SwFieldType* pType = GetFieldType(true);
if( rPropertyName == UNO_NAME_INSTANCE_NAME )
{
OUString sName;
if(pType)
SwXTextFieldMasters::getInstanceName(*pType, sName);
aRet <<= sName;
}
else if(pType)
{
if(rPropertyName == UNO_NAME_NAME)
{
aRet <<= SwXFieldMaster::GetProgrammaticName(*pType, *m_pImpl->m_pDoc).toString();
}
else if(rPropertyName == UNO_NAME_DEPENDENT_TEXT_FIELDS)
{
//fill all text fields into a sequence
std::vector<SwFormatField*> vpFields;
pType->GatherFields(vpFields);
uno::Sequence<uno::Reference <text::XDependentTextField> > aSeq(vpFields.size());
std::transform(vpFields.begin(), vpFields.end(), aSeq.getArray(),
[this](SwFormatField* pF) { return uno::Reference<text::XDependentTextField>(SwXTextField::CreateXTextField(m_pImpl->m_pDoc, pF)); });
aRet <<= aSeq;
}
else
{
//TODO: add properties for the other field types
const sal_uInt16 nMId = GetFieldTypeMId( rPropertyName, *pType );
if (USHRT_MAX == nMId)
{
throw beans::UnknownPropertyException(
"Unknown property: " + rPropertyName,
getXWeak());
}
pType->QueryValue( aRet, nMId );
if (rPropertyName == UNO_NAME_DATA_BASE_NAME ||
rPropertyName == UNO_NAME_DATA_BASE_URL)
{
OUString aDataSource;
aRet >>= aDataSource;
aRet <<= OUString();
OUString *pStr = nullptr; // only one of this properties will return
// a non-empty string.
INetURLObject aObj;
aObj.SetURL( aDataSource );
bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid;
if (bIsURL && rPropertyName == UNO_NAME_DATA_BASE_URL)
pStr = &aDataSource; // DataBaseURL
else if (!bIsURL && rPropertyName == UNO_NAME_DATA_BASE_NAME)
pStr = &aDataSource; // DataBaseName
if (pStr)
aRet <<= *pStr;
}
}
}
else
{
if(rPropertyName == UNO_NAME_DATA_COMMAND_TYPE)
aRet <<= m_pImpl->m_nParam2;
else if(rPropertyName == UNO_NAME_DEPENDENT_TEXT_FIELDS )
{
uno::Sequence<uno::Reference <text::XDependentTextField> > aRetSeq(0);
aRet <<= aRetSeq;
}
else
{
switch (m_pImpl->m_nResTypeId)
{
case SwFieldIds::User:
if( rPropertyName == UNO_NAME_CONTENT )
aRet <<= m_pImpl->m_sParam1;
else if(rPropertyName == UNO_NAME_VALUE)
aRet <<= m_pImpl->m_fParam1;
else if(rPropertyName == UNO_NAME_IS_EXPRESSION)
aRet <<= m_pImpl->m_bParam1;
break;
case SwFieldIds::Database:
if(rPropertyName == UNO_NAME_DATA_BASE_NAME ||
rPropertyName == UNO_NAME_DATA_BASE_URL)
{
// only one of these properties returns a non-empty string.
INetURLObject aObj;
aObj.SetURL(m_pImpl->m_sParam5); // SetSmartURL
bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid;
if (bIsURL && rPropertyName == UNO_NAME_DATA_BASE_URL)
aRet <<= m_pImpl->m_sParam5; // DataBaseURL
else if ( rPropertyName == UNO_NAME_DATA_BASE_NAME)
aRet <<= m_pImpl->m_sParam1; // DataBaseName
}
else if(rPropertyName == UNO_NAME_DATA_TABLE_NAME)
aRet <<= m_pImpl->m_sParam2;
else if(rPropertyName == UNO_NAME_DATA_COLUMN_NAME)
aRet <<= m_pImpl->m_sParam3;
break;
case SwFieldIds::SetExp:
if(rPropertyName == UNO_NAME_NUMBERING_SEPARATOR)
aRet <<= m_pImpl->m_sParam1;
else if(rPropertyName == UNO_NAME_CHAPTER_NUMBERING_LEVEL)
aRet <<= m_pImpl->m_nParam1;
break;
case SwFieldIds::Dde:
{
const sal_Int32 nPart = lcl_PropName2TokenPos(rPropertyName);
if(nPart < 3 )
aRet <<= m_pImpl->m_sParam1.getToken(nPart, sfx2::cTokenSeparator);
else if(3 == nPart)
aRet <<= m_pImpl->m_bParam1;
}
break;
default:
throw beans::UnknownPropertyException( "Unknown property: " + rPropertyName, getXWeak() );
}
}
}
return aRet;
}
void SwXFieldMaster::addPropertyChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/)
{
OSL_FAIL("not implemented");
}
void SwXFieldMaster::removePropertyChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/)
{
OSL_FAIL("not implemented");
}
void SwXFieldMaster::addVetoableChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/)
{
OSL_FAIL("not implemented");
}
void SwXFieldMaster::removeVetoableChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/)
{
OSL_FAIL("not implemented");
}
void SAL_CALL SwXFieldMaster::dispose()
{
SolarMutexGuard aGuard;
SwFieldType *const pFieldType = GetFieldType(true);
if (!pFieldType)
throw uno::RuntimeException();
size_t nTypeIdx = SIZE_MAX;
const SwFieldTypes* pTypes = m_pImpl->m_pDoc->getIDocumentFieldsAccess().GetFieldTypes();
for( size_t i = 0; i < pTypes->size(); i++ )
{
if((*pTypes)[i].get()== pFieldType)
nTypeIdx = i;
}
// first delete all fields
std::vector<SwFormatField*> vpFields;
pFieldType->GatherFields(vpFields);
for(auto pField : vpFields)
SwTextField::DeleteTextField(*pField->GetTextField());
// then delete FieldType
m_pImpl->m_pDoc->getIDocumentFieldsAccess().RemoveFieldType(nTypeIdx);
}
void SAL_CALL SwXFieldMaster::addEventListener(
const uno::Reference<lang::XEventListener> & xListener)
{
std::unique_lock aGuard(m_pImpl->m_Mutex);
m_pImpl->m_EventListeners.addInterface(aGuard, xListener);
}
void SAL_CALL SwXFieldMaster::removeEventListener(
const uno::Reference<lang::XEventListener> & xListener)
{
std::unique_lock aGuard(m_pImpl->m_Mutex);
m_pImpl->m_EventListeners.removeInterface(aGuard, xListener);
}
void SwXFieldMaster::Impl::Notify(const SfxHint& rHint)
{
if(rHint.GetId() == SfxHintId::Dying)
{
m_pDoc = nullptr;
m_pType = nullptr;
uno::Reference<uno::XInterface> const xThis(m_wThis);
if (!xThis.is())
{ // fdo#72695: if UNO object is already dead, don't revive it with event
return;
}
lang::EventObject const ev(xThis);
std::unique_lock aGuard(m_Mutex);
m_EventListeners.disposeAndClear(aGuard, ev);
}
}
ProgName SwXFieldMaster::GetProgrammaticName(const SwFieldType& rType, SwDoc& rDoc)
{
const UIName sName(rType.GetName());
if(SwFieldIds::SetExp == rType.Which())
{
const SwFieldTypes* pTypes = rDoc.getIDocumentFieldsAccess().GetFieldTypes();
for( size_t i = 0; i <= o3tl::make_unsigned(INIT_FLDTYPES); i++ )
{
if((*pTypes)[i].get() == &rType)
{
return SwStyleNameMapper::GetProgName( sName, SwGetPoolIdFromName::TxtColl );
}
}
}
return ProgName(sName.toString());
}
OUString SwXFieldMaster::LocalizeFormula(
const SwSetExpField& rField,
const OUString& rFormula,
bool bQuery)
{
const UIName sTypeName(rField.GetTyp()->GetName());
const ProgName sProgName(
SwStyleNameMapper::GetProgName(sTypeName, SwGetPoolIdFromName::TxtColl ));
if(sProgName.toString() != sTypeName.toString())
{
const OUString sSource = bQuery ? sTypeName.toString() : sProgName.toString();
const OUString sDest = bQuery ? sProgName.toString() : sTypeName.toString();
if(rFormula.startsWith(sSource))
{
return sDest + rFormula.subView(sSource.getLength());
}
}
return rFormula;
}
namespace {
struct SwFieldProperties_Impl
{
OUString sPar1;
OUString sPar2;
OUString sPar3;
OUString sPar4;
OUString sPar5;
OUString sPar6;
OUString sPar7;
Date aDate;
double fDouble;
uno::Sequence<beans::PropertyValue> aPropSeq;
uno::Sequence<OUString> aStrings;
std::unique_ptr<util::DateTime> pDateTime;
sal_Int32 nSubType;
sal_Int32 nFormat;
sal_uInt16 nUSHORT1;
sal_uInt16 nUSHORT2;
sal_uInt16 nUSHORT3;
sal_Int16 nSHORT1;
sal_Int8 nByte1;
bool bFormatIsDefault;
bool bBool1;
bool bBool2;
bool bBool3;
bool bBool4;
SwFieldProperties_Impl():
aDate( Date::EMPTY ),
fDouble(0.),
nSubType(0),
nFormat(0),
nUSHORT1(0),
nUSHORT2(0),
nUSHORT3(0),
nSHORT1(0),
nByte1(0),
bFormatIsDefault(true),
bBool1(false),
bBool2(false),
bBool3(false),
bBool4(true) //Automatic language
{}
};
}
class SwXTextField::Impl
: public SvtListener
{
public:
std::mutex m_Mutex; // just for OInterfaceContainerHelper4
SwFieldType* m_pFieldType;
SwFormatField* m_pFormatField;
unotools::WeakReference<SwXTextField> m_wThis;
::comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> m_EventListeners;
SwDoc* m_pDoc;
rtl::Reference<SwTextAPIObject> m_xTextObject;
bool m_bIsDescriptor;
bool m_bCallUpdate;
SwServiceType m_nServiceId;
UIName m_sTypeName;
std::unique_ptr<SwFieldProperties_Impl> m_pProps;
Impl(SwDoc *const pDoc, SwFormatField *const pFormat, SwServiceType nServiceId)
: m_pFieldType(nullptr)
, m_pFormatField(pFormat)
, m_pDoc(pDoc)
, m_bIsDescriptor(pFormat == nullptr)
, m_bCallUpdate(false)
, m_nServiceId(pFormat
? lcl_GetServiceForField(*pFormat->GetField())
: nServiceId)
, m_pProps(pFormat ? nullptr : new SwFieldProperties_Impl)
{
}
virtual ~Impl() override
{
if (m_xTextObject.is())
{
m_xTextObject->DisposeEditSource();
}
}
void SetFormatField(SwFormatField* pFormatField, SwDoc* pDoc)
{
m_pFormatField = pFormatField;
m_pDoc = pDoc;
if(m_pFormatField)
{
EndListeningAll();
}
}
SwFormatField* GetFormatField()
{
return m_pFormatField;
}
bool IsDescriptor() const
{
// ideally should be: !m_pFormatField && m_pDoc
// but: SwXServiceProvider::MakeInstance() passes nullptr SwDoc, see comment there
return m_bIsDescriptor;
}
void Invalidate();
const SwField* GetField() const;
SwFieldType* GetFieldType() const
{
if(!m_pDoc && !IsDescriptor())
throw uno::RuntimeException();
else if (IsDescriptor())
return m_pFieldType;
return m_pFormatField->GetField()->GetTyp();
}
void SetFieldType(SwFieldType& rType)
{
EndListeningAll();
m_pFieldType = &rType;
StartListening(m_pFieldType->GetNotifier());
}
void ClearFieldType()
{
SvtListener::EndListeningAll();
m_pFieldType = nullptr;
}
virtual void Notify(const SfxHint&) override;
};
SwXTextField::SwXTextField(
SwServiceType nServiceId,
SwDoc* pDoc)
: m_pImpl(new Impl(pDoc, nullptr, nServiceId))
{
//Set visible as default!
if ( SwServiceType::FieldTypeSetExp == nServiceId
|| SwServiceType::FieldTypeDatabaseSetNum == nServiceId
|| SwServiceType::FieldTypeDatabase == nServiceId
|| SwServiceType::FieldTypeDatabaseName == nServiceId )
{
m_pImpl->m_pProps->bBool2 = true;
}
else if(SwServiceType::FieldTypeTableFormula == nServiceId)
{
m_pImpl->m_pProps->bBool1 = true;
}
if(SwServiceType::FieldTypeSetExp == nServiceId)
{
m_pImpl->m_pProps->nUSHORT2 = USHRT_MAX;
}
}
SwXTextField::SwXTextField(SwFormatField& rFormat, SwDoc & rDoc)
: m_pImpl(new Impl(&rDoc, &rFormat, SwServiceType::Invalid))
{
}
SwXTextField::~SwXTextField()
{
}
rtl::Reference<SwXTextField>
SwXTextField::CreateXTextField(SwDoc *const pDoc, SwFormatField const* pFormat,
SwServiceType nServiceId)
{
assert(!pFormat || pDoc);
assert(pFormat || nServiceId != SwServiceType::Invalid);
// re-use existing SwXTextField
rtl::Reference<SwXTextField> xField;
if (pFormat)
{
xField = pFormat->GetXTextField();
}
if (!xField.is())
{
SwXTextField *const pField( pFormat
? new SwXTextField(const_cast<SwFormatField&>(*pFormat), *pDoc)
: new SwXTextField(nServiceId, pDoc));
xField.set(pField);
if (pFormat)
{
const_cast<SwFormatField *>(pFormat)->SetXTextField(xField);
}
// need a permanent Reference to initialize m_wThis
pField->m_pImpl->m_wThis = xField.get();
}
return xField;
}
SwServiceType SwXTextField::GetServiceId() const
{
return m_pImpl->m_nServiceId;
}
/** Convert between SwSetExpField with InputFlag false and InputFlag true.
Unfortunately the InputFlag is exposed in the API as "Input" property
and is mutable; in the UI and in ODF these are 2 different types of
fields, so the API design is very questionable.
In order to keep the mutable property, the whole thing has to be
reconstructed from scratch, to replace the SwTextField hint with
SwTextInputField or vice versa.
The SwFormatField will be replaced - it must be, because the Which
changes - but the SwXTextField *must not* be disposed in the operation,
it has to be disconnected first and at the end connected to the
new instance!
*/
void SwXTextField::TransmuteLeadToInputField(SwSetExpField & rField,
sal_uInt16 const*const pSubType)
{
#ifndef NDEBUG
auto const oldWhich(
(pSubType ? (rField.GetSubType() & nsSwGetSetExpType::GSE_STRING) != 0 : rField.GetInputFlag())
? RES_TXTATR_INPUTFIELD : RES_TXTATR_FIELD);
auto const newWhich(oldWhich == RES_TXTATR_FIELD ? RES_TXTATR_INPUTFIELD : RES_TXTATR_FIELD);
#endif
assert(rField.GetFormatField()->Which() == oldWhich);
rtl::Reference<SwXTextField> const pXField(
rField.GetFormatField()->GetXTextField());
if (pXField)
pXField->m_pImpl->SetFormatField(nullptr, nullptr);
SwTextField *const pOldAttr(rField.GetFormatField()->GetTextField());
SwSetExpField tempField(rField);
if (pSubType)
{
tempField.SetSubType(*pSubType);
}
else
{
tempField.SetInputFlag(!rField.GetInputFlag());
}
SwFormatField tempFormat(tempField);
assert(tempFormat.GetField() != &rField);
assert(tempFormat.GetField() != &tempField); // this copies it again?
assert(tempFormat.Which() == newWhich);
SwTextNode & rNode(pOldAttr->GetTextNode());
std::shared_ptr<SwPaM> pPamForTextField;
IDocumentContentOperations & rIDCO(rNode.GetDoc().getIDocumentContentOperations());
SwTextField::GetPamForTextField(*pOldAttr, pPamForTextField);
assert(pPamForTextField);
sal_Int32 const nStart(pPamForTextField->Start()->GetContentIndex());
rIDCO.DeleteAndJoin(*pPamForTextField);
// ATTENTION: rField is dead now! hope nobody accesses it...
bool bSuccess = rIDCO.InsertPoolItem(*pPamForTextField, tempFormat);
assert(bSuccess);
(void) bSuccess;
SwTextField const* pNewAttr(rNode.GetFieldTextAttrAt(nStart, ::sw::GetTextAttrMode::Default));
assert(pNewAttr);
SwFormatField const& rNewFormat(pNewAttr->GetFormatField());
assert(rNewFormat.Which() == newWhich);
assert((dynamic_cast<SwTextInputField const*>(pNewAttr) != nullptr)
== ((static_cast<SwSetExpField const*>(rNewFormat.GetField())->GetSubType() & nsSwGetSetExpType::GSE_STRING)
&& static_cast<SwSetExpField const*>(rNewFormat.GetField())->GetInputFlag()));
if (pXField)
{
pXField->m_pImpl->SetFormatField(const_cast<SwFormatField*>(&rNewFormat), &rNode.GetDoc());
const_cast<SwFormatField&>(rNewFormat).SetXTextField(pXField);
}
}
void SAL_CALL SwXTextField::attachTextFieldMaster(
const uno::Reference< beans::XPropertySet > & xFieldMaster)
{
SolarMutexGuard aGuard;
if (!m_pImpl->IsDescriptor())
throw uno::RuntimeException();
SwXFieldMaster* pMaster = dynamic_cast<SwXFieldMaster*>(xFieldMaster.get());
SwFieldType* pFieldType = pMaster ? pMaster->GetFieldType() : nullptr;
if (!pFieldType ||
pFieldType->Which() != lcl_ServiceIdToResId(m_pImpl->m_nServiceId))
{
throw lang::IllegalArgumentException();
}
m_pImpl->m_sTypeName = pFieldType->GetName();
m_pImpl->SetFieldType(*pFieldType);
}
uno::Reference< beans::XPropertySet > SAL_CALL
SwXTextField::getTextFieldMaster()
{
SolarMutexGuard aGuard;
SwFieldType* pType = m_pImpl->GetFieldType();
if (!pType && !m_pImpl->m_pDoc) // tdf#152619
return nullptr;
rtl::Reference<SwXFieldMaster> const xRet(
SwXFieldMaster::CreateXFieldMaster(m_pImpl->m_pDoc, pType));
return xRet;
}
OUString SAL_CALL SwXTextField::getPresentation(sal_Bool bShowCommand)
{
SolarMutexGuard aGuard;
SwField const*const pField = m_pImpl->GetField();
if (!pField)
{
throw uno::RuntimeException();
}
return bShowCommand ? pField->GetFieldName() : pField->ExpandField(true, nullptr);
}
void SAL_CALL SwXTextField::attach(
const uno::Reference< text::XTextRange > & xTextRange)
{
SolarMutexGuard aGuard;
if (m_pImpl->IsDescriptor())
{
SwXTextRange* pRange = dynamic_cast<SwXTextRange*>(xTextRange.get());
OTextCursorHelper* pCursor = dynamic_cast<OTextCursorHelper*>(xTextRange.get());
SwDoc* pDoc = pRange ? &pRange->GetDoc() : pCursor ? pCursor->GetDoc() : nullptr;
// if a FieldMaster was attached, then the document is already fixed!
// NOTE: sw.SwXAutoTextEntry unoapi test depends on m_pDoc = 0 being valid
if (!pDoc || (m_pImpl->m_pDoc && m_pImpl->m_pDoc != pDoc))
throw lang::IllegalArgumentException();
SwUnoInternalPaM aPam(*pDoc);
// this now needs to return TRUE
::sw::XTextRangeToSwPaM(aPam, xTextRange);
std::unique_ptr<SwField> xField;
switch (m_pImpl->m_nServiceId)
{
case SwServiceType::FieldTypeAnnotation:
{
SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::Postit);
DateTime aDateTime( DateTime::EMPTY );
if (m_pImpl->m_pProps->pDateTime)
{
aDateTime = *(m_pImpl->m_pProps->pDateTime);
}
sal_uInt32 nImportedId = 0;
if (!m_pImpl->m_pProps->sPar6.isEmpty())
nImportedId = m_pImpl->m_pProps->sPar6.toInt32(16);
sal_uInt32 nParentId = 0;
if (!m_pImpl->m_pProps->sPar5.isEmpty())
nParentId = m_pImpl->m_pProps->sPar5.toInt32(16);
SwPostItField* pPostItField = new SwPostItField(
static_cast<SwPostItFieldType*>(pFieldType),
m_pImpl->m_pProps->sPar1, // author
m_pImpl->m_pProps->sPar2, // content
m_pImpl->m_pProps->sPar3, // author's initials
SwMarkName(m_pImpl->m_pProps->sPar4), // name
aDateTime,
m_pImpl->m_pProps->bBool1, // resolvedflag
0, // id
nParentId, // parent id
nImportedId, // imported para id
0, // PostIt Parent ID.
SwMarkName(m_pImpl->m_pProps->sPar7)
);
if ( m_pImpl->m_xTextObject.is() )
{
pPostItField->SetTextObject( m_pImpl->m_xTextObject->CreateText() );
pPostItField->SetPar2(m_pImpl->m_xTextObject->GetText());
}
xField.reset(pPostItField);
}
break;
case SwServiceType::FieldTypeScript:
{
SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::Script);
xField.reset(new SwScriptField(static_cast<SwScriptFieldType*>(pFieldType),
m_pImpl->m_pProps->sPar1, m_pImpl->m_pProps->sPar2,
m_pImpl->m_pProps->bBool1));
}
break;
case SwServiceType::FieldTypeDateTime:
{
sal_uInt16 nSub = 0;
if (m_pImpl->m_pProps->bBool1)
nSub |= FIXEDFLD;
if (m_pImpl->m_pProps->bBool2)
nSub |= DATEFLD;
else
nSub |= TIMEFLD;
SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::DateTime);
SwDateTimeField *const pDTField = new SwDateTimeField(
static_cast<SwDateTimeFieldType*>(pFieldType),
nSub, m_pImpl->m_pProps->nFormat);
xField.reset(pDTField);
if (m_pImpl->m_pProps->fDouble > 0.)
{
pDTField->SetValue(m_pImpl->m_pProps->fDouble);
}
if (m_pImpl->m_pProps->pDateTime)
{
uno::Any aVal; aVal <<= *m_pImpl->m_pProps->pDateTime;
xField->PutValue( aVal, FIELD_PROP_DATE_TIME );
}
pDTField->SetOffset(m_pImpl->m_pProps->nSubType);
}
break;
case SwServiceType::FieldTypeFileName:
{
SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::Filename);
sal_Int32 nFormat = m_pImpl->m_pProps->nFormat;
if (m_pImpl->m_pProps->bBool2)
nFormat |= FF_FIXED;
SwFileNameField *const pFNField = new SwFileNameField(
static_cast<SwFileNameFieldType*>(pFieldType), nFormat);
xField.reset(pFNField);
if (!m_pImpl->m_pProps->sPar3.isEmpty())
pFNField->SetExpansion(m_pImpl->m_pProps->sPar3);
uno::Any aFormat;
aFormat <<= m_pImpl->m_pProps->nFormat;
xField->PutValue( aFormat, FIELD_PROP_FORMAT );
}
break;
case SwServiceType::FieldTypeTemplateName:
{
SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::TemplateName);
xField.reset(new SwTemplNameField(static_cast<SwTemplNameFieldType*>(pFieldType),
m_pImpl->m_pProps->nFormat));
uno::Any aFormat;
aFormat <<= m_pImpl->m_pProps->nFormat;
xField->PutValue(aFormat, FIELD_PROP_FORMAT);
}
break;
case SwServiceType::FieldTypeChapter:
{
SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::Chapter);
SwChapterField *const pChapterField = new SwChapterField(
static_cast<SwChapterFieldType*>(pFieldType),
m_pImpl->m_pProps->nUSHORT1);
xField.reset(pChapterField);
pChapterField->SetLevel(m_pImpl->m_pProps->nByte1);
uno::Any aVal;
aVal <<= static_cast<sal_Int16>(m_pImpl->m_pProps->nUSHORT1);
xField->PutValue(aVal, FIELD_PROP_USHORT1 );
}
break;
case SwServiceType::FieldTypeAuthor:
{
tools::Long nFormat = m_pImpl->m_pProps->bBool1 ? AF_NAME : AF_SHORTCUT;
if (m_pImpl->m_pProps->bBool2)
nFormat |= AF_FIXED;
SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::Author);
SwAuthorField *const pAuthorField = new SwAuthorField(
static_cast<SwAuthorFieldType*>(pFieldType), nFormat);
xField.reset(pAuthorField);
pAuthorField->SetExpansion(m_pImpl->m_pProps->sPar1);
}
break;
case SwServiceType::FieldTypeConditionedText:
case SwServiceType::FieldTypeHiddenText:
{
SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::HiddenText);
SwHiddenTextField *const pHTField = new SwHiddenTextField(
static_cast<SwHiddenTextFieldType*>(pFieldType),
m_pImpl->m_pProps->sPar1,
m_pImpl->m_pProps->sPar2, m_pImpl->m_pProps->sPar3,
SwServiceType::FieldTypeHiddenText == m_pImpl->m_nServiceId ?
SwFieldTypesEnum::HiddenText : SwFieldTypesEnum::ConditionalText);
xField.reset(pHTField);
pHTField->SetValue(m_pImpl->m_pProps->bBool1);
uno::Any aVal;
aVal <<= m_pImpl->m_pProps->sPar4;
xField->PutValue(aVal, FIELD_PROP_PAR4 );
}
break;
case SwServiceType::FieldTypeHiddenPara:
{
SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::HiddenPara);
SwHiddenParaField *const pHPField = new SwHiddenParaField(
static_cast<SwHiddenParaFieldType*>(pFieldType),
m_pImpl->m_pProps->sPar1);
xField.reset(pHPField);
pHPField->SetHidden(m_pImpl->m_pProps->bBool1);
}
break;
case SwServiceType::FieldTypeGetReference:
{
SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::GetRef);
// tdf#159549 tdf#166850: if nUSHORT2 is ReferenceFieldSource::STYLE,
// sPar1 needs to be converted from ProgName to UIName - this
// is done when setting the FIELD_PROP_USHORT2 below
xField.reset(new SwGetRefField(static_cast<SwGetRefFieldType*>(pFieldType),
SwMarkName(m_pImpl->m_pProps->sPar1),
m_pImpl->m_pProps->sPar4,
0,
0,
0,
0));
if (!m_pImpl->m_pProps->sPar3.isEmpty())
static_cast<SwGetRefField*>(xField.get())->SetExpand(m_pImpl->m_pProps->sPar3);
uno::Any aVal;
aVal <<= static_cast<sal_Int16>(m_pImpl->m_pProps->nUSHORT1);
xField->PutValue(aVal, FIELD_PROP_USHORT1 );
aVal <<= static_cast<sal_Int16>(m_pImpl->m_pProps->nUSHORT2);
xField->PutValue(aVal, FIELD_PROP_USHORT2 );
aVal <<= static_cast<sal_Int16>(m_pImpl->m_pProps->nUSHORT3);
xField->PutValue(aVal, FIELD_PROP_USHORT3 );
aVal <<= m_pImpl->m_pProps->nSHORT1;
xField->PutValue(aVal, FIELD_PROP_SHORT1 );
}
break;
case SwServiceType::FieldTypeJumpEdit:
{
SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::JumpEdit);
xField.reset(new SwJumpEditField(static_cast<SwJumpEditFieldType*>(pFieldType),
m_pImpl->m_pProps->nUSHORT1, m_pImpl->m_pProps->sPar2,
m_pImpl->m_pProps->sPar1));
}
break;
case SwServiceType::FieldTypeDocInfoChangeAuthor:
case SwServiceType::FieldTypeDocInfoChangeDateTime:
case SwServiceType::FieldTypeDocInfoEditTime:
case SwServiceType::FieldTypeDocInfoDescription:
case SwServiceType::FieldTypeDocInfoCreateAuthor:
case SwServiceType::FieldTypeDocInfoCreateDateTime:
case SwServiceType::FieldTypeDocInfoCustom:
case SwServiceType::FieldTypeDocInfoPrintAuthor:
case SwServiceType::FieldTypeDocInfoPrintDateTime:
case SwServiceType::FieldTypeDocInfoKeywords:
case SwServiceType::FieldTypeDocInfoSubject:
case SwServiceType::FieldTypeDocInfoTitle:
case SwServiceType::FieldTypeDocInfoRevision:
case SwServiceType::FieldTypeDocInfo:
{
SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::DocInfo);
sal_uInt16 nSubType = aDocInfoSubTypeFromService[
static_cast<sal_uInt16>(m_pImpl->m_nServiceId) - sal_uInt16(SwServiceType::FieldTypeDocInfoChangeAuthor)];
if (SwServiceType::FieldTypeDocInfoChangeDateTime == m_pImpl->m_nServiceId ||
SwServiceType::FieldTypeDocInfoCreateDateTime == m_pImpl->m_nServiceId ||
SwServiceType::FieldTypeDocInfoPrintDateTime == m_pImpl->m_nServiceId ||
SwServiceType::FieldTypeDocInfoEditTime == m_pImpl->m_nServiceId)
{
if (m_pImpl->m_pProps->bBool2) //IsDate
{
nSubType &= 0xf0ff;
nSubType |= DI_SUB_DATE;
}
else
{
nSubType &= 0xf0ff;
nSubType |= DI_SUB_TIME;
}
}
if (m_pImpl->m_pProps->bBool1)
nSubType |= DI_SUB_FIXED;
xField.reset(new SwDocInfoField(
static_cast<SwDocInfoFieldType*>(pFieldType), nSubType,
m_pImpl->m_pProps->sPar4, m_pImpl->m_pProps->nFormat));
if (!m_pImpl->m_pProps->sPar3.isEmpty())
static_cast<SwDocInfoField*>(xField.get())->SetExpansion(m_pImpl->m_pProps->sPar3);
}
break;
case SwServiceType::FieldTypeUserExt:
{
sal_Int32 nFormat = 0;
if (m_pImpl->m_pProps->bBool1)
nFormat = AF_FIXED;
SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::ExtUser);
SwExtUserField *const pEUField = new SwExtUserField(
static_cast<SwExtUserFieldType*>(pFieldType),
m_pImpl->m_pProps->nUSHORT1, nFormat);
xField.reset(pEUField);
pEUField->SetExpansion(m_pImpl->m_pProps->sPar1);
}
break;
case SwServiceType::FieldTypeUser:
{
SwFieldType* pFieldType =
pDoc->getIDocumentFieldsAccess().GetFieldType(SwFieldIds::User, m_pImpl->m_sTypeName.toString(), true);
if (!pFieldType)
--> --------------------
--> maximum size reached
--> --------------------