[Libreoffice-commits] core.git: sw/inc sw/source

Michael Stahl (via logerrit) logerrit at kemper.freedesktop.org
Mon Apr 8 14:08:36 UTC 2019


 sw/inc/crsrsh.hxx                            |    3 
 sw/source/core/crsr/crstrvl.cxx              |   18 -
 sw/source/core/doc/DocumentFieldsManager.cxx |   25 +
 sw/source/core/doc/docfld.cxx                |  379 +++++++++++++--------------
 sw/source/core/edit/edfld.cxx                |    6 
 sw/source/core/fields/expfld.cxx             |   16 +
 sw/source/core/inc/unofield.hxx              |    2 
 sw/source/core/txtnode/atrfld.cxx            |   37 ++
 sw/source/core/unocore/unofield.cxx          |   62 ++++
 sw/source/ui/fldui/fldedt.cxx                |   13 
 sw/source/uibase/docvw/edtwin.cxx            |    1 
 sw/source/uibase/shells/textfld.cxx          |    5 
 12 files changed, 369 insertions(+), 198 deletions(-)

New commits:
commit 742baabbe4d077e1ba913a7989300908f4637ac7
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Tue Mar 19 12:29:09 2019 +0100
Commit:     Thorsten Behrens <Thorsten.Behrens at CIB.de>
CommitDate: Mon Apr 8 16:08:11 2019 +0200

    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 at cib.de>
    Reviewed-on: https://gerrit.libreoffice.org/69414
    Tested-by: Jenkins
    Reviewed-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>

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(


More information about the Libreoffice-commits mailing list