sw/inc/fesh.hxx                      |    4 +-
 sw/source/core/doc/doclay.cxx        |    1 
 sw/source/core/frmedt/fecopy.cxx     |   15 +++++++--
 sw/source/uibase/dochdl/swdtflvr.cxx |   58 ++++++++++++++++++++++-------------
 sw/source/uibase/inc/swdtflvr.hxx    |   10 ++++--
 5 files changed, 62 insertions(+), 26 deletions(-)

New commits:
commit d072b5e09e1c7f759c797b7ba1ee89a3bfef8858
Author:     Michael Stahl <[email protected]>
AuthorDate: Fri Oct 10 13:41:22 2025 +0200
Commit:     Michael Stahl <[email protected]>
CommitDate: Fri Oct 10 15:36:01 2025 +0200

    tdf#51850 sw: AutoCaption for a single pasted image
    
    AutoCaption mostly isn't enabled for clipboard paste, except for one
    special case.
    
    For the case when the source is outside LO, let
    SwTransferable::PasteGrf() set a flag that the caption should be
    inserted (the SwPasteSdr::Insert case), which can then be handled at the
    end.
    
    PasteFileList() appears to be used when an image file is copied from
    Nautilus.
    
    For internal paste, it gets more complicated because SwFEShell::Paste()
    knows what was inserted, but caption can only be added later, outside of
    any StartAction()/EndAction(), because if an action is pending,
    SwWrtShell::GetSelectionType() does not return useful results, and the
    lcl_InsertLabel() ends up erroneously inserting a text node next to the
    SwGrfNode.
    
    Change-Id: I3e16f407fd409a0f315be139376ad9e5f0b526cd
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/192165
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <[email protected]>

diff --git a/sw/inc/fesh.hxx b/sw/inc/fesh.hxx
index ae25ec87b3ab..1aaa5cd0dd25 100644
--- a/sw/inc/fesh.hxx
+++ b/sw/inc/fesh.hxx
@@ -258,7 +258,9 @@ public:
     /// Copy and Paste methods for internal clipboard.
     /// bDeleteRedlines: if content inside a delete redline should be stripped 
away in rClpDoc.
     SW_DLLPUBLIC void Copy( SwDoc& rClpDoc, const OUString* pNewClpText = 
nullptr, bool bDeleteRedlines = true );
-    SW_DLLPUBLIC bool Paste( SwDoc& rClpDoc, bool bNestedTable = false );
+    // @return possibly a pasted fly frame to be captioned
+    SW_DLLPUBLIC ::std::pair<bool, SwFrameFormat const*>
+        Paste(SwDoc& rClpDoc, bool bNestedTable = false);
 
     /// Paste some pages into another doc - used in mailmerge.
     SW_DLLPUBLIC void PastePages( SwFEShell& rToFill, sal_uInt16 nStartPage, 
sal_uInt16 nEndPage);
diff --git a/sw/source/core/doc/doclay.cxx b/sw/source/core/doc/doclay.cxx
index b6ceedb74674..fdef5c76f427 100644
--- a/sw/source/core/doc/doclay.cxx
+++ b/sw/source/core/doc/doclay.cxx
@@ -685,6 +685,7 @@ lcl_InsertLabel(SwDoc & rDoc, SwTextFormatColls *const 
pTextFormatCollTable,
             {
                 SwStartNode *pSttNd = rDoc.GetNodes()[nNdIdx]->GetStartNode();
                 assert(pSttNd && "No StartNode in InsertLabel.");
+                assert(!rDoc.GetNodes()[nNdIdx+1]->IsGrfNode() && 
!rDoc.GetNodes()[nNdIdx+1]->IsOLENode()); // these need to be 
SwLabelType::Object
                 SwNodeOffset nNode;
                 if( bBefore )
                 {
diff --git a/sw/source/core/frmedt/fecopy.cxx b/sw/source/core/frmedt/fecopy.cxx
index 174e60b3187a..c0ee3c3f6e1c 100644
--- a/sw/source/core/frmedt/fecopy.cxx
+++ b/sw/source/core/frmedt/fecopy.cxx
@@ -844,7 +844,8 @@ namespace {
     }
 }
 
-bool SwFEShell::Paste(SwDoc& rClpDoc, bool bNestedTable)
+::std::pair<bool, SwFrameFormat const*>
+SwFEShell::Paste(SwDoc& rClpDoc, bool const bNestedTable)
 {
     CurrShell aCurr( this );
     // then till end of the nodes array
@@ -864,6 +865,8 @@ bool SwFEShell::Paste(SwDoc& rClpDoc, bool bNestedTable)
     SwTableNode *const pSrcNd = aCpyPam.GetMarkNode().GetTableNode();
 
     bool bRet = true;
+    SwFrameFormat const* pNewFlyToCaption{nullptr};
+
     StartAllAction();
     GetDoc()->GetIDocumentUndoRedo().StartUndo( SwUndoId::INSGLOSSARY, nullptr 
);
     GetDoc()->getIDocumentFieldsAccess().LockExpFields();
@@ -1076,6 +1079,14 @@ bool SwFEShell::Paste(SwDoc& rClpDoc, bool bNestedTable)
                 {
                     lcl_InitSelectFlyOrDrawFormat(pFlyFormat, *this, isSelect);
                 }
+                if (isSelect && inserted.size() == 1)
+                {
+                    if (inserted.front()->Which() == RES_FLYFRMFMT
+                        && 
GetDoc()->GetNodes()[inserted.front()->GetContent().GetContentIdx()->GetIndex() 
+ 1]->IsGrfNode())
+                    {
+                        pNewFlyToCaption = inserted.front();
+                    }
+                }
             }
             else
             {
@@ -1166,7 +1177,7 @@ bool SwFEShell::Paste(SwDoc& rClpDoc, bool bNestedTable)
     GetDoc()->getIDocumentFieldsAccess().UpdateFields(false);
     EndAllAction();
 
-    return bRet;
+    return {bRet, pNewFlyToCaption};
 }
 
 void SwFEShell::PastePages( SwFEShell& rToFill, sal_uInt16 nStartPage, 
sal_uInt16 nEndPage)
diff --git a/sw/source/uibase/dochdl/swdtflvr.cxx 
b/sw/source/uibase/dochdl/swdtflvr.cxx
index 9b9bf0574496..0167b7e6f42e 100644
--- a/sw/source/uibase/dochdl/swdtflvr.cxx
+++ b/sw/source/uibase/dochdl/swdtflvr.cxx
@@ -1907,7 +1907,8 @@ bool SwTransferable::PasteData( const 
TransferableDataHelper& rData,
             case SotClipboardFormatId::GDIMETAFILE:
                 bRet = SwTransferable::PasteGrf( rData, rSh, nFormat,
                                                 SwPasteSdr::Insert,pPt,
-                                                nActionFlags, nDropAction, 
bNeedToSelectBeforePaste);
+                        nActionFlags, nDropAction, bNeedToSelectBeforePaste,
+                        &bCallAutoCaption);
                 break;
 
             case SotClipboardFormatId::XFORMS:
@@ -1926,14 +1927,14 @@ bool SwTransferable::PasteData( const 
TransferableDataHelper& rData,
                                     : EXCHG_IN_ACTION_LINK == nAction
                                         ? SwPasteSdr::SetAttr
                                         : SwPasteSdr::Insert),
-                                pPt, nActionFlags, nullptr );
+                        pPt, nActionFlags, &bCallAutoCaption);
                 break;
 
             case SotClipboardFormatId::FILE_LIST:
                 // then insert as graphics only
                 bRet = SwTransferable::PasteFileList( rData, rSh,
                                     EXCHG_IN_ACTION_LINK == nAction,
-                                    pPt, bMsg );
+                                    pPt, bMsg, &bCallAutoCaption );
                 break;
 
             case SotClipboardFormatId::SONLK:
@@ -1963,13 +1964,10 @@ bool SwTransferable::PasteData( const 
TransferableDataHelper& rData,
 
         case EXCHG_OUT_ACTION_INSERT_FILE:
             {
-                bool graphicInserted;
                 bRet = SwTransferable::PasteFileName( rData, rSh, nFormat,
                                             SwPasteSdr::Insert, pPt,
                                             nActionFlags,
-                                            &graphicInserted );
-                if( graphicInserted )
-                    bCallAutoCaption = true;
+                                            &bCallAutoCaption);
             }
             break;
 
@@ -2035,7 +2033,8 @@ bool SwTransferable::PasteData( const 
TransferableDataHelper& rData,
             case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
                 bRet = SwTransferable::PasteGrf( rData, rSh, nFormat,
                                                 SwPasteSdr::SetAttr, pPt,
-                                                nActionFlags, nDropAction, 
bNeedToSelectBeforePaste);
+                        nActionFlags, nDropAction, bNeedToSelectBeforePaste,
+                        nullptr/*no caption?*/);
                 break;
             default:
                 OSL_FAIL( "unknown format" );
@@ -2054,7 +2053,8 @@ bool SwTransferable::PasteData( const 
TransferableDataHelper& rData,
         case EXCHG_OUT_ACTION_INSERT_GRAPH:
             bRet = SwTransferable::PasteGrf( rData, rSh, nFormat,
                                                 SwPasteSdr::Insert, pPt,
-                                                nActionFlags, nDropAction, 
bNeedToSelectBeforePaste, nAnchorType );
+                    nActionFlags, nDropAction, bNeedToSelectBeforePaste,
+                    &bCallAutoCaption, nAnchorType);
             break;
 
         case EXCHG_OUT_ACTION_REPLACE_DRAWOBJ:
@@ -2069,7 +2069,8 @@ bool SwTransferable::PasteData( const 
TransferableDataHelper& rData,
         case EXCHG_OUT_ACTION_REPLACE_GRAPH:
             bRet = SwTransferable::PasteGrf( rData, rSh, nFormat,
                                                 SwPasteSdr::Replace,pPt,
-                                                nActionFlags, nDropAction, 
bNeedToSelectBeforePaste);
+                    nActionFlags, nDropAction, bNeedToSelectBeforePaste,
+                    nullptr/*no caption for replace?*/);
             break;
 
         case EXCHG_OUT_ACTION_INSERT_INTERACTIVE:
@@ -2876,7 +2877,9 @@ bool SwTransferable::PasteSdrFormat(  const 
TransferableDataHelper& rData,
 
 bool SwTransferable::PasteGrf( const TransferableDataHelper& rData, 
SwWrtShell& rSh,
                                 SotClipboardFormatId nFormat, SwPasteSdr 
nAction, const Point* pPt,
-                                SotExchangeActionFlags nActionFlags, sal_Int8 
nDropAction, bool bNeedToSelectBeforePaste, RndStdIds nAnchorType )
+        SotExchangeActionFlags const nActionFlags, sal_Int8 const nDropAction,
+        bool const bNeedToSelectBeforePaste, bool *const pbCallAutoCaption,
+        RndStdIds const nAnchorType)
 {
     bool bRet = false;
 
@@ -3094,6 +3097,10 @@ bool SwTransferable::PasteGrf( const 
TransferableDataHelper& rData, SwWrtShell&
             else
             {
                 rSh.Pop(SwCursorShell::PopMode::DeleteStack);
+                if (pbCallAutoCaption)
+                {   // only possible if selected
+                    *pbCallAutoCaption = true;
+                }
             }
         }
     }
@@ -3196,13 +3203,10 @@ bool SwTransferable::PasteFileName( const 
TransferableDataHelper& rData,
                                     SwWrtShell& rSh, SotClipboardFormatId 
nFormat,
                                     SwPasteSdr nAction, const Point* pPt,
                                     SotExchangeActionFlags nActionFlags,
-                                    bool * graphicInserted)
+                                    bool *const pbCallAutoCaption)
 {
     bool bRet = SwTransferable::PasteGrf( rData, rSh, nFormat, nAction,
-                                            pPt, nActionFlags, 0, false);
-    if (graphicInserted != nullptr) {
-        *graphicInserted = bRet;
-    }
+                    pPt, nActionFlags, 0, false, pbCallAutoCaption);
     if( !bRet )
     {
         OUString sFile, sDesc;
@@ -3395,7 +3399,8 @@ bool SwTransferable::PasteDBData( const 
TransferableDataHelper& rData,
 
 bool SwTransferable::PasteFileList( const TransferableDataHelper& rData,
                                     SwWrtShell& rSh, bool bLink,
-                                    const Point* pPt, bool bMsg )
+                                    const Point* pPt, bool bMsg,
+                                    bool *const pbCallAutoCaption)
 {
     bool bRet = false;
     FileList aFileList;
@@ -3412,7 +3417,9 @@ bool SwTransferable::PasteFileList( const 
TransferableDataHelper& rData,
             TransferableDataHelper aData( pHlp );
 
             if( SwTransferable::PasteFileName( aData, rSh, 
SotClipboardFormatId::SIMPLE_FILE, nAct,
-                                            pPt, SotExchangeActionFlags::NONE, 
nullptr ))
+                    pPt, SotExchangeActionFlags::NONE,
+                    // only caption a single image (PasteGrf only sets true 
for Insert)
+                    aFileList.Count() == 1 ? pbCallAutoCaption : nullptr))
             {
                 if( bLink )
                 {
@@ -3897,7 +3904,7 @@ bool SwTransferable::PrivatePaste(SwWrtShell& rShell, 
SwPasteContext* pContext,
 
     const SelectionType nSelection = rShell.GetSelectionType();
 
-    SwTrnsfrActionAndUndo aAction( &rShell );
+    ::std::optional<SwTrnsfrActionAndUndo> oAction(&rShell);
 
     bool bKillPaMs = false;
 
@@ -3953,9 +3960,13 @@ bool SwTransferable::PrivatePaste(SwWrtShell& rShell, 
SwPasteContext* pContext,
     }
 
     bool bRet = true;
+    SwFrameFormat const* pNewFlyToCaption{nullptr};
     // m_pWrtShell is nullptr when the source document is closed already.
     if (!m_pWrtShell || lcl_checkClassification(m_pWrtShell->GetDoc(), 
rShell.GetDoc()))
-        bRet = rShell.Paste(m_pClpDocFac->GetDoc(), ePasteTable == 
PasteTableType::PASTE_TABLE);
+    {
+        ::std::tie(bRet, pNewFlyToCaption) = rShell.Paste(
+            m_pClpDocFac->GetDoc(), ePasteTable == 
PasteTableType::PASTE_TABLE);
+    }
 
     if( bKillPaMs )
         rShell.KillPams();
@@ -3964,6 +3975,13 @@ bool SwTransferable::PrivatePaste(SwWrtShell& rShell, 
SwPasteContext* pContext,
     if( bRet && bSmart && ((bInWrd && !bEndWrd )|| bSttWrd) )
         rShell.SwEditShell::Insert(' ');
 
+    oAction.reset(); // inserting caption does not work when ActionPend()
+
+    if (pNewFlyToCaption)
+    {
+        rShell.GetView().AutoCaption(GRAPHIC_CAP);
+    }
+
     return bRet;
 }
 
diff --git a/sw/source/uibase/inc/swdtflvr.hxx 
b/sw/source/uibase/inc/swdtflvr.hxx
index 9c6c00561050..2301d783ba02 100644
--- a/sw/source/uibase/inc/swdtflvr.hxx
+++ b/sw/source/uibase/inc/swdtflvr.hxx
@@ -126,7 +126,9 @@ class SAL_DLLPUBLIC_RTTI SwTransferable final : public 
TransferableHelper
 
     static bool PasteGrf( const TransferableDataHelper& rData, SwWrtShell& rSh,
                                 SotClipboardFormatId nFormat, SwPasteSdr 
nAction, const Point* pPt,
-                                SotExchangeActionFlags nActionFlags, sal_Int8 
nDropAction, bool bNeedToSelectBeforePaste, RndStdIds nAnchorType = 
RndStdIds::FLY_AT_PARA );
+                                SotExchangeActionFlags nActionFlags, sal_Int8 
nDropAction,
+                                bool bNeedToSelectBeforePaste, bool * 
pbCallAutoCaption,
+                                RndStdIds nAnchorType = 
RndStdIds::FLY_AT_PARA);
 
     static bool PasteImageMap( const TransferableDataHelper& rData,
                                     SwWrtShell& rSh );
@@ -136,7 +138,8 @@ class SAL_DLLPUBLIC_RTTI SwTransferable final : public 
TransferableHelper
 
     static bool PasteFileName( const TransferableDataHelper& rData,
                             SwWrtShell& rSh, SotClipboardFormatId nFormat, 
SwPasteSdr nAction,
-                            const Point* pPt, SotExchangeActionFlags 
nActionFlags, bool * graphicInserted );
+                            const Point* pPt, SotExchangeActionFlags 
nActionFlags,
+                            bool * pbCallAutoCaption);
 
     static bool PasteDBData( const TransferableDataHelper& rData, SwWrtShell& 
rSh,
                             SotClipboardFormatId nFormat, bool bLink, const 
Point* pDragPt,
@@ -144,7 +147,8 @@ class SAL_DLLPUBLIC_RTTI SwTransferable final : public 
TransferableHelper
 
     static bool PasteFileList( const TransferableDataHelper& rData,
                                 SwWrtShell& rSh, bool bLink,
-                                const Point* pPt, bool bMsg );
+                                const Point* pPt, bool bMsg,
+                                bool * pbCallAutoCaption);
 
     bool PrivatePaste( SwWrtShell& rShell, SwPasteContext* pContext = nullptr, 
PasteTableType ePasteTable = PasteTableType::PASTE_DEFAULT );
 

Reply via email to