[Libreoffice-commits] core.git: Branch 'distro/lhm/libreoffice-6-1+backports' - sw/inc sw/source

Michael Stahl (via logerrit) logerrit at kemper.freedesktop.org
Tue Apr 9 10:53:04 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                |  359 +++++++++++++--------------
 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            |   38 ++
 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, 360 insertions(+), 188 deletions(-)

New commits:
commit 950ac8be42ae2f05c16789f09b3e4506a9d05bf5
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: Tue Apr 9 12:52:39 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.
    
    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>
    (cherry picked from commit 742baabbe4d077e1ba913a7989300908f4637ac7)
    
    Change-Id: I45c471703f102ebcb04b8567f9d76c17d5a063e7
    Reviewed-on: https://gerrit.libreoffice.org/70455
    Reviewed-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>
    Tested-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>

diff --git a/sw/inc/crsrsh.hxx b/sw/inc/crsrsh.hxx
index 7e4301cc9c60..a77bb5a2b9cb 100644
--- a/sw/inc/crsrsh.hxx
+++ b/sw/inc/crsrsh.hxx
@@ -706,6 +706,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 212ebfee6079..01ee1e0ae0e2 100644
--- a/sw/source/core/crsr/crstrvl.cxx
+++ b/sw/source/core/crsr/crstrvl.cxx
@@ -840,11 +840,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
@@ -856,13 +856,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();
@@ -888,7 +898,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 1659773e292e..238e4ba71cf0 100644
--- a/sw/source/core/doc/DocumentFieldsManager.cxx
+++ b/sw/source/core/doc/DocumentFieldsManager.cxx
@@ -54,6 +54,7 @@
 #include <ndindex.hxx>
 #include <pam.hxx>
 #include <unotools/transliterationwrapper.hxx>
+#include <comphelper/scopeguard.hxx>
 #include <com/sun/star/uno/Any.hxx>
 
 using namespace ::com::sun::star::uno;
@@ -1248,7 +1249,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 &m_rDoc one is updated
         {
@@ -1390,7 +1410,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 bcaf1a554670..a5e7376f786f 100644
--- a/sw/source/core/doc/docfld.cxx
+++ b/sw/source/core/doc/docfld.cxx
@@ -442,53 +442,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() ));
                 SAL_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
@@ -598,57 +601,59 @@ 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);
 
-        SwFormatField* pFormatField = const_cast<SwFormatField*>(static_cast<const SwFormatField*>(pItem));
-        SwTextField* pTextField = pFormatField->GetTextField();
-        if( !pTextField || !pTextField->GetTextNode().GetNodes().IsDocNodes() )
-            continue;
+        for (sal_uInt32 n = 0; n < nMaxItems; ++n)
+        {
+            const SfxPoolItem* pItem = GetAttrPool().GetItem2(nWhichHint, n);
+            if (!pItem)
+                continue;
 
-        SwField* pField = pFormatField->GetField();
-        bool bExpand = false;
+            SwFormatField* pFormatField = const_cast<SwFormatField*>(static_cast<const SwFormatField*>(pItem));
+            SwTextField* pTextField = pFormatField->GetTextField();
+            if (!pTextField || !pTextField->GetTextNode().GetNodes().IsDocNodes())
+                continue;
 
-        switch( pField->GetTyp()->Which() )
-        {
-            case SwFieldIds::Database:
+            SwField* pField = pFormatField->GetField();
+            bool bExpand = false;
+
+            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);
@@ -660,17 +665,18 @@ void SwDoc::ChangeDBFields( const std::vector<OUString>& rOldNames,
                 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
@@ -882,113 +888,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 3311439fd862..0d7ac627f853 100644
--- a/sw/source/core/edit/edfld.cxx
+++ b/sw/source/core/edit/edfld.cxx
@@ -172,7 +172,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 4bd0c9654f6a..6a3bd6efb9e2 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 21fced4726e3..e32003ae1ba4 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)->SetFormatField(*this);
+        SwSetExpField *const pSetField(static_cast<SwSetExpField *>(mpField));
+        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 )
     {
@@ -104,8 +113,16 @@ SwFormatField::SwFormatField( const SwFormatField& rAttr )
         }
         else if (mpField->GetTyp()->Which() == SwFieldIds::SetExp)
         {
+            SwSetExpField *const pSetField(static_cast<SwSetExpField *>(mpField));
+            if (pSetField->GetInputFlag()
+                && (static_cast<SwSetExpFieldType*>(pSetField->GetTyp())->GetType()
+                    & nsSwGetSetExpType::GSE_STRING))
+            {
+                SetWhich( RES_TXTATR_INPUTFIELD );
+            }
             // see SwWrtShell::StartInputFieldDlg
-            static_cast<SwSetExpField *>(mpField)->SetFormatField(*this);
+
+            pSetField->SetFormatField(*this);
         }
         else if ( mpField->GetTyp()->Which() == SwFieldIds::Postit )
         {
@@ -549,6 +566,7 @@ SwTextInputField::~SwTextInputField()
 
 void SwTextInputField::LockNotifyContentChange()
 {
+    assert(!m_bLockNotifyContentChange); // not nestable
     m_bLockNotifyContentChange = true;
 }
 
@@ -588,9 +606,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);
 
-        const SwInputField* pInputField = dynamic_cast<const SwInputField*>(GetFormatField().GetField());
-        assert(pInputField != nullptr);
-        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 94f5813a550d..b4889e389a4c 100644
--- a/sw/source/core/unocore/unofield.cxx
+++ b/sw/source/core/unocore/unofield.cxx
@@ -1242,6 +1242,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)
 {
@@ -1951,6 +2011,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;
     if (m_pImpl->m_FieldTypeClient.GetRegisteredIn())
     {
diff --git a/sw/source/ui/fldui/fldedt.cxx b/sw/source/ui/fldui/fldedt.cxx
index cb2d682fa97a..7c857a51c4d1 100644
--- a/sw/source/ui/fldui/fldedt.cxx
+++ b/sw/source/ui/fldui/fldedt.cxx
@@ -54,6 +54,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 b23727c789e3..ee4e9510a269 100644
--- a/sw/source/uibase/docvw/edtwin.cxx
+++ b/sw/source/uibase/docvw/edtwin.cxx
@@ -3324,6 +3324,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 9d89701232a1..e38610819f0b 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>
@@ -189,7 +190,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