diff options
author | Michael Stahl <Michael.Stahl@cib.de> | 2019-03-19 12:29:09 +0100 |
---|---|---|
committer | Thorsten Behrens <Thorsten.Behrens@CIB.de> | 2019-04-08 16:08:11 +0200 |
commit | 742baabbe4d077e1ba913a7989300908f4637ac7 (patch) | |
tree | da1ccd9ea18d95c6aa77d74197de1140e00c4b64 /sw | |
parent | a3881a66b8ffda4a8a89ecfc4347555e34193665 (diff) |
tdf#123968 sw: use inline editing for input fields for variables
* set these to RES_TXTATR_INPUTFIELD so they get a SwTextInputField
* only for string fields, the numeric ones break when editing
* SwCursorShell::CursorInsideInputField() must check type of the hint,
not type of the field
* DocumentFieldsManager::UpdateExpFieldsImpl() is called with one field
when it is inserted, and must expand the field into the SwTextNode then,
and it's called when the user edits inside the field, and must *not*
expand the field into the SwTextNode then
* SwDocUpdateField::MakeFieldList_() must iterate RES_TXTATR_INPUTFIELD
* SwEditWin::MouseButtonDown() must still pop up the edit dialog on
double-click
* SetFieldsDirty() should check RES_TXTATR_INPUTFIELD because SwGetExp
may depend on them
* a very odd API design: SwSetExpField::PutValue() allows to change the
"InputFlag", which is actually used by the ODF import!
This needs some alchemy to convert between SwTextField and
SwTextInputField hints, see SwXTextField::TransmuteLeadToInputField().
* etc.
Change-Id: I45c471703f102ebcb04b8567f9d76c17d5a063e7
Co-authored-by: Samuel Mehrbrodt <Samuel.Mehrbrodt@cib.de>
Reviewed-on: https://gerrit.libreoffice.org/69414
Tested-by: Jenkins
Reviewed-by: Thorsten Behrens <Thorsten.Behrens@CIB.de>
Diffstat (limited to 'sw')
-rw-r--r-- | sw/inc/crsrsh.hxx | 3 | ||||
-rw-r--r-- | sw/source/core/crsr/crstrvl.cxx | 18 | ||||
-rw-r--r-- | sw/source/core/doc/DocumentFieldsManager.cxx | 25 | ||||
-rw-r--r-- | sw/source/core/doc/docfld.cxx | 379 | ||||
-rw-r--r-- | sw/source/core/edit/edfld.cxx | 6 | ||||
-rw-r--r-- | sw/source/core/fields/expfld.cxx | 16 | ||||
-rw-r--r-- | sw/source/core/inc/unofield.hxx | 2 | ||||
-rw-r--r-- | sw/source/core/txtnode/atrfld.cxx | 37 | ||||
-rw-r--r-- | sw/source/core/unocore/unofield.cxx | 62 | ||||
-rw-r--r-- | sw/source/ui/fldui/fldedt.cxx | 13 | ||||
-rw-r--r-- | sw/source/uibase/docvw/edtwin.cxx | 1 | ||||
-rw-r--r-- | sw/source/uibase/shells/textfld.cxx | 5 |
12 files changed, 369 insertions, 198 deletions
diff --git a/sw/inc/crsrsh.hxx b/sw/inc/crsrsh.hxx index cfe9ef023cd0..fb105b00e524 100644 --- a/sw/inc/crsrsh.hxx +++ b/sw/inc/crsrsh.hxx @@ -701,6 +701,9 @@ public: static SwTextField* GetTextFieldAtPos( const SwPosition* pPos, const bool bIncludeInputFieldAtStart ); + static SwTextField* GetTextFieldAtCursor( + const SwPaM* pCursor, + const bool bIncludeInputFieldAtStart ); static SwField* GetFieldAtCursor( const SwPaM* pCursor, const bool bIncludeInputFieldAtStart ); diff --git a/sw/source/core/crsr/crstrvl.cxx b/sw/source/core/crsr/crstrvl.cxx index bf45898fd82f..a2c13b838f4d 100644 --- a/sw/source/core/crsr/crstrvl.cxx +++ b/sw/source/core/crsr/crstrvl.cxx @@ -893,11 +893,11 @@ SwTextField * SwCursorShell::GetTextFieldAtPos( return pTextField; } -SwField* SwCursorShell::GetFieldAtCursor( +SwTextField* SwCursorShell::GetTextFieldAtCursor( const SwPaM* pCursor, const bool bIncludeInputFieldAtStart ) { - SwField* pFieldAtCursor = nullptr; + SwTextField* pFieldAtCursor = nullptr; SwTextField* pTextField = GetTextFieldAtPos( pCursor->Start(), bIncludeInputFieldAtStart ); if ( pTextField != nullptr @@ -909,13 +909,23 @@ SwField* SwCursorShell::GetFieldAtCursor( : 1; if ( ( pCursor->End()->nContent.GetIndex() - pCursor->Start()->nContent.GetIndex() ) <= nTextFieldLength ) { - pFieldAtCursor = const_cast<SwField*>(pTextField->GetFormatField().GetField()); + pFieldAtCursor = pTextField; } } return pFieldAtCursor; } +SwField* SwCursorShell::GetFieldAtCursor( + const SwPaM *const pCursor, + const bool bIncludeInputFieldAtStart) +{ + SwTextField *const pField(GetTextFieldAtCursor(pCursor, bIncludeInputFieldAtStart)); + return pField + ? const_cast<SwField*>(pField->GetFormatField().GetField()) + : nullptr; +} + SwField* SwCursorShell::GetCurField( const bool bIncludeInputFieldAtStart ) const { SwPaM* pCursor = GetCursor(); @@ -941,7 +951,7 @@ bool SwCursorShell::CursorInsideInputField() const { for(SwPaM& rCursor : GetCursor()->GetRingContainer()) { - if(dynamic_cast<const SwInputField*>(GetFieldAtCursor( &rCursor, false ))) + if (dynamic_cast<const SwTextInputField*>(GetTextFieldAtCursor(&rCursor, false))) return true; } return false; diff --git a/sw/source/core/doc/DocumentFieldsManager.cxx b/sw/source/core/doc/DocumentFieldsManager.cxx index bbb8b0d03ba8..9f05f74f2785 100644 --- a/sw/source/core/doc/DocumentFieldsManager.cxx +++ b/sw/source/core/doc/DocumentFieldsManager.cxx @@ -55,6 +55,7 @@ #include <pam.hxx> #include <o3tl/deleter.hxx> #include <unotools/transliterationwrapper.hxx> +#include <comphelper/scopeguard.hxx> #include <com/sun/star/uno/Any.hxx> using namespace ::com::sun::star::uno; @@ -1265,7 +1266,26 @@ void DocumentFieldsManager::UpdateExpFieldsImpl( default: break; } // switch - pFormatField->ModifyNotification( nullptr, nullptr ); // trigger formatting + { + // avoid calling ReplaceText() for input fields, it is pointless + // here and moves the cursor if it's inside the field ... + SwTextInputField *const pInputField( + pUpdateField == pTextField // ... except once, when the dialog + ? nullptr // is used to change content via UpdateOneField() + : dynamic_cast<SwTextInputField *>(pTextField)); + if (pInputField) + { + pInputField->LockNotifyContentChange(); + } + ::comphelper::ScopeGuard g([pInputField]() + { + if (pInputField) + { + pInputField->UnlockNotifyContentChange(); + } + }); + pFormatField->ModifyNotification(nullptr, nullptr); // trigger formatting + } if (pUpdateField == pTextField) // if only this one is updated { @@ -1407,7 +1427,8 @@ bool DocumentFieldsManager::SetFieldsDirty( bool b, const SwNode* pChk, sal_uLon for( size_t n = 0 ; n < nEnd; ++n ) { const SwTextAttr* pAttr = pTNd->GetSwpHints().Get(n); - if ( pAttr->Which() == RES_TXTATR_FIELD ) + if ( pAttr->Which() == RES_TXTATR_FIELD + || pAttr->Which() == RES_TXTATR_INPUTFIELD) { b = true; break; diff --git a/sw/source/core/doc/docfld.cxx b/sw/source/core/doc/docfld.cxx index f9327a782996..a9c3f251849e 100644 --- a/sw/source/core/doc/docfld.cxx +++ b/sw/source/core/doc/docfld.cxx @@ -450,53 +450,56 @@ void SwDoc::GetAllUsedDB( std::vector<OUString>& rDBNameList, } } - sal_uInt32 nMaxItems = GetAttrPool().GetItemCount2( RES_TXTATR_FIELD ); - for (sal_uInt32 n = 0; n < nMaxItems; ++n) + for (sal_uInt16 const nWhichHint : { RES_TXTATR_FIELD, RES_TXTATR_INPUTFIELD }) { - const SfxPoolItem* pItem; - if( nullptr == (pItem = GetAttrPool().GetItem2( RES_TXTATR_FIELD, n ) )) - continue; + sal_uInt32 nMaxItems = GetAttrPool().GetItemCount2(nWhichHint); + for (sal_uInt32 n = 0; n < nMaxItems; ++n) + { + const SfxPoolItem *const pItem(GetAttrPool().GetItem2(nWhichHint, n)); + if (nullptr == pItem) + continue; - const SwFormatField* pFormatField = static_cast<const SwFormatField*>(pItem); - const SwTextField* pTextField = pFormatField->GetTextField(); - if( !pTextField || !pTextField->GetTextNode().GetNodes().IsDocNodes() ) - continue; + const SwFormatField* pFormatField = static_cast<const SwFormatField*>(pItem); + const SwTextField* pTextField = pFormatField->GetTextField(); + if (!pTextField || !pTextField->GetTextNode().GetNodes().IsDocNodes()) + continue; - const SwField* pField = pFormatField->GetField(); - switch( pField->GetTyp()->Which() ) - { - case SwFieldIds::Database: - AddUsedDBToList( rDBNameList, + const SwField* pField = pFormatField->GetField(); + switch (pField->GetTyp()->Which()) + { + case SwFieldIds::Database: + AddUsedDBToList( rDBNameList, lcl_DBDataToString(static_cast<const SwDBField*>(pField)->GetDBData() )); - break; + break; - case SwFieldIds::DbSetNumber: - case SwFieldIds::DatabaseName: - AddUsedDBToList( rDBNameList, + case SwFieldIds::DbSetNumber: + case SwFieldIds::DatabaseName: + AddUsedDBToList( rDBNameList, lcl_DBDataToString(static_cast<const SwDBNameInfField*>(pField)->GetRealDBData() )); - break; + break; - case SwFieldIds::DbNumSet: - case SwFieldIds::DbNextSet: - AddUsedDBToList( rDBNameList, + case SwFieldIds::DbNumSet: + case SwFieldIds::DbNextSet: + AddUsedDBToList( rDBNameList, lcl_DBDataToString(static_cast<const SwDBNameInfField*>(pField)->GetRealDBData() )); - [[fallthrough]]; // JP: is that right like that? + [[fallthrough]]; // JP: is that right like that? - case SwFieldIds::HiddenText: - case SwFieldIds::HiddenPara: - AddUsedDBToList(rDBNameList, FindUsedDBs( *pAllDBNames, + case SwFieldIds::HiddenText: + case SwFieldIds::HiddenPara: + AddUsedDBToList(rDBNameList, FindUsedDBs( *pAllDBNames, pField->GetPar1(), aUsedDBNames )); - aUsedDBNames.clear(); - break; + aUsedDBNames.clear(); + break; - case SwFieldIds::SetExp: - case SwFieldIds::GetExp: - case SwFieldIds::Table: - AddUsedDBToList(rDBNameList, FindUsedDBs( *pAllDBNames, + case SwFieldIds::SetExp: + case SwFieldIds::GetExp: + case SwFieldIds::Table: + AddUsedDBToList(rDBNameList, FindUsedDBs( *pAllDBNames, pField->GetFormula(), aUsedDBNames )); - aUsedDBNames.clear(); - break; - default: break; + aUsedDBNames.clear(); + break; + default: break; + } } } #endif @@ -608,79 +611,82 @@ void SwDoc::ChangeDBFields( const std::vector<OUString>& rOldNames, } } - sal_uInt32 nMaxItems = GetAttrPool().GetItemCount2( RES_TXTATR_FIELD ); - - for (sal_uInt32 n = 0; n < nMaxItems; ++n ) + for (sal_uInt16 const nWhichHint : { RES_TXTATR_FIELD, RES_TXTATR_INPUTFIELD }) { - const SfxPoolItem* pItem = GetAttrPool().GetItem2( RES_TXTATR_FIELD, n ); - if( !pItem ) - continue; + sal_uInt32 nMaxItems = GetAttrPool().GetItemCount2(nWhichHint); + + for (sal_uInt32 n = 0; n < nMaxItems; ++n) + { + const SfxPoolItem* pItem = GetAttrPool().GetItem2(nWhichHint, n); + if (!pItem) + continue; - SwFormatField* pFormatField = const_cast<SwFormatField*>(static_cast<const SwFormatField*>(pItem)); - SwTextField* pTextField = pFormatField->GetTextField(); - if( !pTextField || !pTextField->GetTextNode().GetNodes().IsDocNodes() ) - continue; + SwFormatField* pFormatField = const_cast<SwFormatField*>(static_cast<const SwFormatField*>(pItem)); + SwTextField* pTextField = pFormatField->GetTextField(); + if (!pTextField || !pTextField->GetTextNode().GetNodes().IsDocNodes()) + continue; - SwField* pField = pFormatField->GetField(); - bool bExpand = false; + SwField* pField = pFormatField->GetField(); + bool bExpand = false; - switch( pField->GetTyp()->Which() ) - { - case SwFieldIds::Database: + switch( pField->GetTyp()->Which() ) + { + case SwFieldIds::Database: #if HAVE_FEATURE_DBCONNECTIVITY - if( IsNameInArray( rOldNames, lcl_DBDataToString(static_cast<SwDBField*>(pField)->GetDBData()))) - { - SwDBFieldType* pOldTyp = static_cast<SwDBFieldType*>(pField->GetTyp()); + if (IsNameInArray(rOldNames, lcl_DBDataToString(static_cast<SwDBField*>(pField)->GetDBData()))) + { + SwDBFieldType* pOldTyp = static_cast<SwDBFieldType*>(pField->GetTyp()); - SwDBFieldType* pTyp = static_cast<SwDBFieldType*>(getIDocumentFieldsAccess().InsertFieldType( + SwDBFieldType* pTyp = static_cast<SwDBFieldType*>(getIDocumentFieldsAccess().InsertFieldType( SwDBFieldType(this, pOldTyp->GetColumnName(), aNewDBData))); - pFormatField->RegisterToFieldType( *pTyp ); - pField->ChgTyp(pTyp); + pFormatField->RegisterToFieldType( *pTyp ); + pField->ChgTyp(pTyp); - static_cast<SwDBField*>(pField)->ClearInitialized(); - static_cast<SwDBField*>(pField)->InitContent(); + static_cast<SwDBField*>(pField)->ClearInitialized(); + static_cast<SwDBField*>(pField)->InitContent(); - bExpand = true; - } + bExpand = true; + } #endif - break; + break; - case SwFieldIds::DbSetNumber: - case SwFieldIds::DatabaseName: - if( IsNameInArray( rOldNames, + case SwFieldIds::DbSetNumber: + case SwFieldIds::DatabaseName: + if (IsNameInArray(rOldNames, lcl_DBDataToString(static_cast<SwDBNameInfField*>(pField)->GetRealDBData()))) - { - static_cast<SwDBNameInfField*>(pField)->SetDBData(aNewDBData); - bExpand = true; - } - break; + { + static_cast<SwDBNameInfField*>(pField)->SetDBData(aNewDBData); + bExpand = true; + } + break; - case SwFieldIds::DbNumSet: - case SwFieldIds::DbNextSet: - if( IsNameInArray( rOldNames, + case SwFieldIds::DbNumSet: + case SwFieldIds::DbNextSet: + if (IsNameInArray(rOldNames, lcl_DBDataToString(static_cast<SwDBNameInfField*>(pField)->GetRealDBData()))) - { - static_cast<SwDBNameInfField*>(pField)->SetDBData(aNewDBData); - } - [[fallthrough]]; - case SwFieldIds::HiddenText: - case SwFieldIds::HiddenPara: - pField->SetPar1( ReplaceUsedDBs(rOldNames, rNewName, pField->GetPar1()) ); - bExpand = true; - break; + { + static_cast<SwDBNameInfField*>(pField)->SetDBData(aNewDBData); + } + [[fallthrough]]; + case SwFieldIds::HiddenText: + case SwFieldIds::HiddenPara: + pField->SetPar1( ReplaceUsedDBs(rOldNames, rNewName, pField->GetPar1()) ); + bExpand = true; + break; - case SwFieldIds::SetExp: - case SwFieldIds::GetExp: - case SwFieldIds::Table: - pField->SetPar2( ReplaceUsedDBs(rOldNames, rNewName, pField->GetFormula()) ); - bExpand = true; - break; - default: break; - } + case SwFieldIds::SetExp: + case SwFieldIds::GetExp: + case SwFieldIds::Table: + pField->SetPar2( ReplaceUsedDBs(rOldNames, rNewName, pField->GetFormula()) ); + bExpand = true; + break; + default: break; + } - if (bExpand) - pTextField->ExpandTextField( true ); + if (bExpand) + pTextField->ExpandTextField( true ); + } } getIDocumentState().SetModified(); #endif @@ -891,113 +897,118 @@ void SwDocUpdateField::MakeFieldList_( SwDoc& rDoc, int eGetMode ) bool bIsDBManager = nullptr != rDoc.GetDBManager(); #endif - const sal_uInt32 nMaxItems = rDoc.GetAttrPool().GetItemCount2( RES_TXTATR_FIELD ); - for( sal_uInt32 n = 0; n < nMaxItems; ++n ) + for (sal_uInt16 const nWhichHint : { RES_TXTATR_FIELD, RES_TXTATR_INPUTFIELD }) { - const SfxPoolItem* pItem = rDoc.GetAttrPool().GetItem2( RES_TXTATR_FIELD, n ); - if( !pItem ) - continue; - - const SwFormatField* pFormatField = static_cast<const SwFormatField*>(pItem); - const SwTextField* pTextField = pFormatField->GetTextField(); - if( !pTextField || !pTextField->GetTextNode().GetNodes().IsDocNodes() ) - continue; - - OUString sFormula; - const SwField* pField = pFormatField->GetField(); - const SwFieldIds nWhich = pField->GetTyp()->Which(); - switch( nWhich ) + const sal_uInt32 nMaxItems = rDoc.GetAttrPool().GetItemCount2(nWhichHint); + for (sal_uInt32 n = 0; n < nMaxItems; ++n) { - case SwFieldIds::DbSetNumber: - case SwFieldIds::GetExp: - if( GETFLD_ALL == eGetMode ) - sFormula = sTrue; - break; + const SfxPoolItem* pItem = rDoc.GetAttrPool().GetItem2(nWhichHint, n); + if (!pItem) + continue; + + const SwFormatField* pFormatField = static_cast<const SwFormatField*>(pItem); + const SwTextField* pTextField = pFormatField->GetTextField(); + if (!pTextField || !pTextField->GetTextNode().GetNodes().IsDocNodes()) + continue; + + OUString sFormula; + const SwField* pField = pFormatField->GetField(); + const SwFieldIds nWhich = pField->GetTyp()->Which(); + switch (nWhich) + { + case SwFieldIds::DbSetNumber: + case SwFieldIds::GetExp: + if (GETFLD_ALL == eGetMode) + sFormula = sTrue; + break; - case SwFieldIds::Database: - if( GETFLD_EXPAND & eGetMode ) - sFormula = sTrue; - break; + case SwFieldIds::Database: + if (GETFLD_EXPAND & eGetMode) + sFormula = sTrue; + break; - case SwFieldIds::SetExp: - if ( (eGetMode != GETFLD_EXPAND) || - (nsSwGetSetExpType::GSE_STRING & pField->GetSubType()) ) - { - sFormula = sTrue; - } - break; + case SwFieldIds::SetExp: + if ((eGetMode != GETFLD_EXPAND) || + (nsSwGetSetExpType::GSE_STRING & pField->GetSubType())) + { + sFormula = sTrue; + } + break; - case SwFieldIds::HiddenPara: - if( GETFLD_ALL == eGetMode ) - { - sFormula = pField->GetPar1(); - if (sFormula.isEmpty() || sFormula==sFalse) - const_cast<SwHiddenParaField*>(static_cast<const SwHiddenParaField*>(pField))->SetHidden( false ); - else if (sFormula==sTrue) - const_cast<SwHiddenParaField*>(static_cast<const SwHiddenParaField*>(pField))->SetHidden( true ); - else - break; - - sFormula.clear(); - // trigger formatting - const_cast<SwFormatField*>(pFormatField)->ModifyNotification( nullptr, nullptr ); - } - break; + case SwFieldIds::HiddenPara: + if (GETFLD_ALL == eGetMode) + { + sFormula = pField->GetPar1(); + if (sFormula.isEmpty() || sFormula==sFalse) + const_cast<SwHiddenParaField*>(static_cast<const SwHiddenParaField*>(pField))->SetHidden( false ); + else if (sFormula==sTrue) + const_cast<SwHiddenParaField*>(static_cast<const SwHiddenParaField*>(pField))->SetHidden( true ); + else + break; + + sFormula.clear(); + // trigger formatting + const_cast<SwFormatField*>(pFormatField)->ModifyNotification( nullptr, nullptr ); + } + break; - case SwFieldIds::HiddenText: - if( GETFLD_ALL == eGetMode ) - { - sFormula = pField->GetPar1(); - if (sFormula.isEmpty() || sFormula==sFalse) - const_cast<SwHiddenTextField*>(static_cast<const SwHiddenTextField*>(pField))->SetValue( true ); - else if (sFormula==sTrue) - const_cast<SwHiddenTextField*>(static_cast<const SwHiddenTextField*>(pField))->SetValue( false ); - else - break; - - sFormula.clear(); - - // evaluate field - const_cast<SwHiddenTextField*>(static_cast<const SwHiddenTextField*>(pField))->Evaluate(&rDoc); - // trigger formatting - const_cast<SwFormatField*>(pFormatField)->ModifyNotification( nullptr, nullptr ); - } - break; + case SwFieldIds::HiddenText: + if (GETFLD_ALL == eGetMode) + { + sFormula = pField->GetPar1(); + if (sFormula.isEmpty() || sFormula==sFalse) + const_cast<SwHiddenTextField*>(static_cast<const SwHiddenTextField*>(pField))->SetValue( true ); + else if (sFormula==sTrue) + const_cast<SwHiddenTextField*>(static_cast<const SwHiddenTextField*>(pField))->SetValue( false ); + else + break; + + sFormula.clear(); + + // evaluate field + const_cast<SwHiddenTextField*>(static_cast<const SwHiddenTextField*>(pField))->Evaluate(&rDoc); + // trigger formatting + const_cast<SwFormatField*>(pFormatField)->ModifyNotification( nullptr, nullptr ); + } + break; #if HAVE_FEATURE_DBCONNECTIVITY - case SwFieldIds::DbNumSet: - { - SwDBData aDBData(const_cast<SwDBNumSetField*>(static_cast<const SwDBNumSetField*>(pField))->GetDBData(&rDoc)); - - if ( - (bIsDBManager && rDoc.GetDBManager()->OpenDataSource(aDBData.sDataSource, aDBData.sCommand)) && - (GETFLD_ALL == eGetMode || (GETFLD_CALC & eGetMode && static_cast<const SwDBNumSetField*>(pField)->IsCondValid())) - ) + case SwFieldIds::DbNumSet: { - sFormula = pField->GetPar1(); - } - } - break; - case SwFieldIds::DbNextSet: - { - SwDBData aDBData(const_cast<SwDBNextSetField*>(static_cast<const SwDBNextSetField*>(pField))->GetDBData(&rDoc)); + SwDBData aDBData(const_cast<SwDBNumSetField*>(static_cast<const SwDBNumSetField*>(pField))->GetDBData(&rDoc)); - if ( - (bIsDBManager && rDoc.GetDBManager()->OpenDataSource(aDBData.sDataSource, aDBData.sCommand)) && - (GETFLD_ALL == eGetMode || (GETFLD_CALC & eGetMode && static_cast<const SwDBNextSetField*>(pField)->IsCondValid())) - ) + if ( (bIsDBManager && rDoc.GetDBManager()->OpenDataSource(aDBData.sDataSource, aDBData.sCommand)) + && (GETFLD_ALL == eGetMode + || (GETFLD_CALC & eGetMode + && static_cast<const SwDBNumSetField*>(pField)->IsCondValid())) + ) + { + sFormula = pField->GetPar1(); + } + } + break; + case SwFieldIds::DbNextSet: { - sFormula = pField->GetPar1(); + SwDBData aDBData(const_cast<SwDBNextSetField*>(static_cast<const SwDBNextSetField*>(pField))->GetDBData(&rDoc)); + + if ( (bIsDBManager && rDoc.GetDBManager()->OpenDataSource(aDBData.sDataSource, aDBData.sCommand)) + && (GETFLD_ALL == eGetMode + || (GETFLD_CALC & eGetMode + && static_cast<const SwDBNextSetField*>(pField)->IsCondValid())) + ) + { + sFormula = pField->GetPar1(); + } } - } - break; + break; #endif - default: break; - } + default: break; + } - if (!sFormula.isEmpty()) - { - GetBodyNode( *pTextField, nWhich ); + if (!sFormula.isEmpty()) + { + GetBodyNode( *pTextField, nWhich ); + } } } m_nFieldListGetMode = eGetMode; diff --git a/sw/source/core/edit/edfld.cxx b/sw/source/core/edit/edfld.cxx index 787eb13c02a6..8b744bfd33b6 100644 --- a/sw/source/core/edit/edfld.cxx +++ b/sw/source/core/edit/edfld.cxx @@ -173,7 +173,11 @@ static SwTextField* lcl_FindInputField( SwDoc* pDoc, SwField& rField ) { // Search field via its address. For input fields this needs to be done in protected fields. SwTextField* pTField = nullptr; - if( SwFieldIds::Input == rField.Which() ) + if (SwFieldIds::Input == rField.Which() + || (SwFieldIds::SetExp == rField.Which() + && static_cast<SwSetExpField&>(rField).GetInputFlag() + && (static_cast<SwSetExpFieldType*>(rField.GetTyp())->GetType() + & nsSwGetSetExpType::GSE_STRING))) { const sal_uInt32 nMaxItems = pDoc->GetAttrPool().GetItemCount2( RES_TXTATR_INPUTFIELD ); diff --git a/sw/source/core/fields/expfld.cxx b/sw/source/core/fields/expfld.cxx index b12ae69cdfc7..7bcfd443c027 100644 --- a/sw/source/core/fields/expfld.cxx +++ b/sw/source/core/fields/expfld.cxx @@ -1128,7 +1128,21 @@ bool SwSetExpField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId ) mnSubType &= (~nsSwExtendedSubType::SUB_CMD); break; case FIELD_PROP_BOOL1: - SetInputFlag(*o3tl::doAccess<bool>(rAny)); + { + bool newInput(*o3tl::doAccess<bool>(rAny)); + if (newInput != GetInputFlag()) + { + if (static_cast<SwSetExpFieldType*>(GetTyp())->GetType() + & nsSwGetSetExpType::GSE_STRING) + { + SwXTextField::TransmuteLeadToInputField(*this); + } + else + { + SetInputFlag(newInput); + } + } + } break; case FIELD_PROP_PAR4: { diff --git a/sw/source/core/inc/unofield.hxx b/sw/source/core/inc/unofield.hxx index b54480c97c3b..723b954e0dad 100644 --- a/sw/source/core/inc/unofield.hxx +++ b/sw/source/core/inc/unofield.hxx @@ -139,6 +139,8 @@ private: public: SwServiceType GetServiceId() const; + static void TransmuteLeadToInputField(SwSetExpField & rField); + /// @return an SwXTextField, either an already existing one or a new one static css::uno::Reference< css::text::XTextField> CreateXTextField(SwDoc * pDoc, SwFormatField const* pFormat, diff --git a/sw/source/core/txtnode/atrfld.cxx b/sw/source/core/txtnode/atrfld.cxx index 87d6ca5a4ae2..66ccc2670f73 100644 --- a/sw/source/core/txtnode/atrfld.cxx +++ b/sw/source/core/txtnode/atrfld.cxx @@ -69,7 +69,16 @@ SwFormatField::SwFormatField( const SwField &rField ) else if (mpField->GetTyp()->Which() == SwFieldIds::SetExp) { // see SwWrtShell::StartInputFieldDlg - static_cast<SwSetExpField *>(mpField.get())->SetFormatField(*this); + SwSetExpField *const pSetField(static_cast<SwSetExpField *>(mpField.get())); + if (pSetField->GetInputFlag() + // only for string fields for now - inline editing of number fields + // tends to produce error messages... + && (static_cast<SwSetExpFieldType*>(pSetField->GetTyp())->GetType() + & nsSwGetSetExpType::GSE_STRING)) + { + SetWhich( RES_TXTATR_INPUTFIELD ); + } + pSetField->SetFormatField(*this); } else if ( mpField->GetTyp()->Which() == SwFieldIds::Postit ) { @@ -103,8 +112,15 @@ SwFormatField::SwFormatField( const SwFormatField& rAttr ) } else if (mpField->GetTyp()->Which() == SwFieldIds::SetExp) { + SwSetExpField *const pSetField(static_cast<SwSetExpField *>(mpField.get())); + if (pSetField->GetInputFlag() + && (static_cast<SwSetExpFieldType*>(pSetField->GetTyp())->GetType() + & nsSwGetSetExpType::GSE_STRING)) + { + SetWhich( RES_TXTATR_INPUTFIELD ); + } // see SwWrtShell::StartInputFieldDlg - static_cast<SwSetExpField *>(mpField.get())->SetFormatField(*this); + pSetField->SetFormatField(*this); } else if ( mpField->GetTyp()->Which() == SwFieldIds::Postit ) { @@ -543,6 +559,7 @@ SwTextInputField::~SwTextInputField() void SwTextInputField::LockNotifyContentChange() { + assert(!m_bLockNotifyContentChange); // not nestable m_bLockNotifyContentChange = true; } @@ -582,9 +599,19 @@ void SwTextInputField::UpdateFieldContent() const sal_Int32 nLen = static_cast<sal_Int32>(std::max<sal_Int32>( 0, ( (*End()) - 1 - nIdx ) )); const OUString aNewFieldContent = GetTextNode().GetExpandText(nullptr, nIdx, nLen); - auto pInputField = dynamic_cast<const SwInputField*>(GetFormatField().GetField()); - assert(pInputField); - const_cast<SwInputField*>(pInputField)->applyFieldContent( aNewFieldContent ); + const SwField* pField = GetFormatField().GetField(); + const SwInputField* pInputField = dynamic_cast<const SwInputField*>(pField); + if (pInputField) + const_cast<SwInputField*>(pInputField)->applyFieldContent( aNewFieldContent ); + + const SwSetExpField* pExpField = dynamic_cast<const SwSetExpField*>(pField); + if (pExpField) + { + assert(pExpField->GetInputFlag()); + const_cast<SwSetExpField*>(pExpField)->SetPar2(aNewFieldContent); + } + assert(pInputField || pExpField); + // trigger update of fields for scenarios in which the Input Field's content is part of e.g. a table formula GetTextNode().GetDoc()->getIDocumentFieldsAccess().GetUpdateFields().SetFieldsDirty(true); } diff --git a/sw/source/core/unocore/unofield.cxx b/sw/source/core/unocore/unofield.cxx index 5bf539324d0b..4bb314c5a4bd 100644 --- a/sw/source/core/unocore/unofield.cxx +++ b/sw/source/core/unocore/unofield.cxx @@ -1269,6 +1269,66 @@ 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) +{ + assert(rField.GetFormatField()->Which() == (rField.GetInputFlag() ? RES_TXTATR_INPUTFIELD : RES_TXTATR_FIELD)); + uno::Reference<text::XTextField> const xField( + rField.GetFormatField()->GetXTextField()); + SwXTextField *const pXField = xField.is() + ? reinterpret_cast<SwXTextField*>( + sal::static_int_cast<sal_IntPtr>( + uno::Reference<lang::XUnoTunnel>(xField, uno::UNO_QUERY_THROW) + ->getSomething(getUnoTunnelId()))) + : nullptr; + if (xField.is()) + { + assert(pXField->m_pImpl->m_pFormatField == rField.GetFormatField()); + rField.GetFormatField()->Remove(pXField->m_pImpl.get()); + pXField->m_pImpl->m_pFormatField = nullptr; + } + SwTextField *const pOldAttr(rField.GetFormatField()->GetTextField()); + SwSetExpField tempField(rField); + tempField.SetInputFlag(!rField.GetInputFlag()); + SwFormatField tempFormat(tempField); + assert(tempFormat.GetField() != &rField); + assert(tempFormat.GetField() != &tempField); // this copies it again? + assert(tempFormat.Which() == (static_cast<SwSetExpField const*>(tempFormat.GetField())->GetInputFlag() ? RES_TXTATR_INPUTFIELD : RES_TXTATR_FIELD)); + 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()->nContent.GetIndex()); + 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, true)); + assert(pNewAttr); + SwFormatField const& rNewFormat(pNewAttr->GetFormatField()); + assert(rNewFormat.Which() == (static_cast<SwSetExpField const*>(rNewFormat.GetField())->GetInputFlag() ? RES_TXTATR_INPUTFIELD : RES_TXTATR_FIELD)); + assert(static_cast<SwSetExpField const*>(rNewFormat.GetField())->GetInputFlag() == (dynamic_cast<SwTextInputField const*>(pNewAttr) != nullptr)); + if (xField.is()) + { + pXField->m_pImpl->m_pFormatField = &rNewFormat; + const_cast<SwFormatField&>(rNewFormat).Add(pXField->m_pImpl.get()); + const_cast<SwFormatField&>(rNewFormat).SetXTextField(xField); + } +} + void SAL_CALL SwXTextField::attachTextFieldMaster( const uno::Reference< beans::XPropertySet > & xFieldMaster) { @@ -1965,6 +2025,8 @@ void SAL_CALL SwXTextField::attach( assert(m_pImpl->m_pFormatField); m_pImpl->m_pDoc = pDoc; const_cast<SwFormatField *>(m_pImpl->m_pFormatField)->Add(m_pImpl.get()); + const_cast<SwFormatField *>(m_pImpl->m_pFormatField)->SetXTextField(this); + m_pImpl->m_wThis = *this; m_pImpl->m_bIsDescriptor = false; m_pImpl->ClearFieldType(); m_pImpl->m_pProps.reset(); diff --git a/sw/source/ui/fldui/fldedt.cxx b/sw/source/ui/fldui/fldedt.cxx index f94aef325372..d4108ef3b7f0 100644 --- a/sw/source/ui/fldui/fldedt.cxx +++ b/sw/source/ui/fldui/fldedt.cxx @@ -57,6 +57,19 @@ void SwFieldEditDlg::EnsureSelection(SwField *pCurField, SwFieldMgr &rMgr) { pSh->GotoField( *(pInputField->GetFormatField()) ); } + else + { + SwSetExpField *const pSetField(dynamic_cast<SwSetExpField*>(pCurField)); + if (pSetField) + { + assert(pSetField->GetFormatField()); + pSh->GotoField( *(pSetField->GetFormatField()) ); + } + else + { + assert(!"what input field is this"); + } + } } /* Only create selection if there is none already. diff --git a/sw/source/uibase/docvw/edtwin.cxx b/sw/source/uibase/docvw/edtwin.cxx index 59b0114e5707..4d932c8de1ae 100644 --- a/sw/source/uibase/docvw/edtwin.cxx +++ b/sw/source/uibase/docvw/edtwin.cxx @@ -3337,6 +3337,7 @@ void SwEditWin::MouseButtonDown(const MouseEvent& _rMEvt) break; case TYP_INPUTFLD: case TYP_DROPDOWN: + case TYP_SETINPFLD: pVFrame->GetBindings().Execute(FN_UPDATE_INPUTFIELDS); break; default: diff --git a/sw/source/uibase/shells/textfld.cxx b/sw/source/uibase/shells/textfld.cxx index 9f809738f12e..ec6d8b5f6449 100644 --- a/sw/source/uibase/shells/textfld.cxx +++ b/sw/source/uibase/shells/textfld.cxx @@ -27,6 +27,7 @@ #include <editeng/outliner.hxx> #include <sfx2/lnkbase.hxx> #include <fmtfld.hxx> +#include <txtfld.hxx> #include <svl/itempool.hxx> #include <unotools/useroptions.hxx> #include <svl/whiter.hxx> @@ -186,7 +187,9 @@ void SwTextShell::ExecField(SfxRequest &rReq) bAddSetExpressionFields ) ) { rSh.ClearMark(); - if ( dynamic_cast<SwInputField*>(rSh.GetCurField( true )) != nullptr ) + if (!rSh.IsMultiSelection() + && (nullptr != dynamic_cast<const SwTextInputField*>( + SwCursorShell::GetTextFieldAtCursor(rSh.GetCursor(), true)))) { rSh.SttSelect(); rSh.SelectText( |