officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu | 11 +++ sw/inc/cmdid.h | 1 sw/inc/fesh.hxx | 6 + sw/inc/view.hxx | 1 sw/sdi/_basesh.sdi | 7 ++ sw/sdi/swriter.sdi | 18 +++++ sw/source/core/frmedt/fecopy.cxx | 4 - sw/source/uibase/dochdl/swdtflvr.cxx | 32 +++++++--- sw/source/uibase/inc/swdtflvr.hxx | 8 +- sw/source/uibase/shells/basesh.cxx | 17 +++++ sw/source/uibase/uiview/view.cxx | 16 ++++- sw/uiconfig/swriter/menubar/menubar.xml | 1 sw/uiconfig/swriter/popupmenu/table.xml | 1 13 files changed, 107 insertions(+), 16 deletions(-)
New commits: commit d53cd7d7e229568b0c9597bc89d973e0d1050b44 Author: László Németh <nem...@numbertext.org> AuthorDate: Wed Dec 11 15:38:05 2019 +0100 Commit: László Németh <nem...@numbertext.org> CommitDate: Sat Dec 14 22:30:52 2019 +0100 tdf#37156 Writer menu: Paste as Nested table Paste table data in Writer tables overwrites the content of the existing cells, when the cursor is there in an empty cell or at the beginning of the first paragraph of a table cell. Using the new Paste Special option "As Nested Table" of table popup (local) menu and Edit->Paste Special, (based on the new .uno:PasteNestedTable command), clipboard content (including native tables or tables copied from Calc or other spreadsheets) are inserted as nested tables in empty cells and at cell starting cursor positions. Change-Id: I32807200883651e492ae280efce7bf9806f22283 Reviewed-on: https://gerrit.libreoffice.org/85094 Tested-by: Jenkins Reviewed-by: László Németh <nem...@numbertext.org> (cherry picked from commit 1e278d1d0cfb1d5375195aa764739f00633f21e8) Reviewed-on: https://gerrit.libreoffice.org/85145 diff --git a/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu b/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu index ce664af0e1bd..ac60dc4e32ca 100644 --- a/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu +++ b/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu @@ -1523,6 +1523,17 @@ <value>1</value> </prop> </node> + <node oor:name=".uno:PasteNestedTable" oor:op="replace"> + <prop oor:name="Label" oor:type="xs:string"> + <value xml:lang="en-US">Paste as Nested Table</value> + </prop> + <prop oor:name="PopupLabel" oor:type="xs:string"> + <value xml:lang="en-US">As Nested Table</value> + </prop> + <prop oor:name="Properties" oor:type="xs:int"> + <value>1</value> + </prop> + </node> <node oor:name=".uno:DeleteRows" oor:op="replace"> <prop oor:name="Label" oor:type="xs:string"> <value xml:lang="en-US">Delete Rows</value> diff --git a/sw/inc/cmdid.h b/sw/inc/cmdid.h index 6b49d5a91e51..6aba5e4d72d4 100644 --- a/sw/inc/cmdid.h +++ b/sw/inc/cmdid.h @@ -343,6 +343,7 @@ #define FN_TABLE_SELECT_ALL (FN_FORMAT + 115) /* */ #define FN_TABLE_INSERT_COL_AFTER (FN_FORMAT + 116) /* */ #define FN_TABLE_SET_READ_ONLY_CELLS (FN_FORMAT + 117) /* protect table cells */ +#define FN_PASTE_NESTED_TABLE (FN_FORMAT + 118) /* instead of the cell-by-cell copy between source and target tables */ #define FN_TABLE_UNSET_READ_ONLY_CELLS (FN_FORMAT + 119) /* undo table cell protection */ #define FN_TABLE_HEADLINE_REPEAT (FN_FORMAT + 120) /* also used in SwXTextTable*/ #define FN_TABLE_ADJUST_CELLS (FN_FORMAT + 121) /* */ diff --git a/sw/inc/fesh.hxx b/sw/inc/fesh.hxx index f60f92cff44e..b928420ea824 100644 --- a/sw/inc/fesh.hxx +++ b/sw/inc/fesh.hxx @@ -252,7 +252,7 @@ public: /// Copy and Paste methods for internal clipboard. void Copy( SwDoc* pClpDoc, const OUString* pNewClpText = nullptr ); - bool Paste( SwDoc* pClpDoc ); + bool Paste( SwDoc* pClpDoc, bool bNestedTable = false ); /// Paste some pages into another doc - used in mailmerge. void PastePages( SwFEShell& rToFill, sal_uInt16 nStartPage, sal_uInt16 nEndPage); @@ -643,6 +643,10 @@ public: SwTable::SearchType m_eTableInsertMode; SwTable::SearchType GetTableInsertMode() const { return m_eTableInsertMode; } void SetTableInsertMode( SwTable::SearchType eFlag ) { m_eTableInsertMode = eFlag; } + /// table copied to the clipboard by the last private copy + bool bTableCopied; + bool GetTableCopied() { return bTableCopied; } + void SetTableCopied( bool bCopied ) { bTableCopied = bCopied; } bool DeleteTableSel(); ///< Current selection, may be whole table. diff --git a/sw/inc/view.hxx b/sw/inc/view.hxx index 13f73dc09123..1ce11c33bda6 100644 --- a/sw/inc/view.hxx +++ b/sw/inc/view.hxx @@ -589,6 +589,7 @@ public: // Status changes now notified from the clipboard. bool IsPasteAllowed(); bool IsPasteSpecialAllowed(); + bool IsPasteSpreadsheet(bool bHasOwnTableCopied); // Enable mail merge - mail merge field dialog enabled void EnableMailMerge(); diff --git a/sw/sdi/_basesh.sdi b/sw/sdi/_basesh.sdi index 472198cdc922..886ae2863a9f 100644 --- a/sw/sdi/_basesh.sdi +++ b/sw/sdi/_basesh.sdi @@ -115,6 +115,13 @@ interface BaseTextSelection DisableFlags="SfxDisableFlags::SwOnProtectedCursor"; ] + FN_PASTE_NESTED_TABLE // status(final|play) + [ + ExecMethod = ExecClpbrd ; + StateMethod = StateClpbrd ; + DisableFlags="SfxDisableFlags::SwOnProtectedCursor"; + ] + FN_REPAGINATE // status(final|play) [ ExecMethod = Execute ; diff --git a/sw/sdi/swriter.sdi b/sw/sdi/swriter.sdi index 78dfda33e744..321804cda1bf 100644 --- a/sw/sdi/swriter.sdi +++ b/sw/sdi/swriter.sdi @@ -2681,6 +2681,24 @@ SfxVoidItem InsertColumnsAfter FN_TABLE_INSERT_COL_AFTER GroupId = SfxGroupId::Table; ] +SfxVoidItem PasteNestedTable FN_PASTE_NESTED_TABLE +() +[ + AutoUpdate = FALSE, + FastCall = TRUE, + ReadOnlyDoc = FALSE, + Toggle = FALSE, + Container = FALSE, + RecordAbsolute = FALSE, + RecordPerSet; + Asynchron; + + AccelConfig = FALSE, + MenuConfig = TRUE, + ToolBoxConfig = TRUE, + GroupId = SfxGroupId::Edit; +] + SfxUInt16Item InsertSection FN_INSERT_REGION (SfxUInt16Item Columns SID_ATTR_COLUMNS,SfxStringItem RegionName FN_PARAM_REGION_NAME,SfxStringItem RegionCondition FN_PARAM_REGION_CONDITION,SfxBoolItem RegionHidden FN_PARAM_REGION_HIDDEN,SfxBoolItem RegionProtect FN_PARAM_REGION_PROTECT,SfxStringItem LinkName FN_PARAM_1,SfxStringItem FilterName FN_PARAM_2,SfxStringItem SubRegion FN_PARAM_3) [ diff --git a/sw/source/core/frmedt/fecopy.cxx b/sw/source/core/frmedt/fecopy.cxx index cd6a9ba15c79..b3fffee8b22f 100644 --- a/sw/source/core/frmedt/fecopy.cxx +++ b/sw/source/core/frmedt/fecopy.cxx @@ -680,7 +680,7 @@ namespace { } } -bool SwFEShell::Paste( SwDoc* pClpDoc ) +bool SwFEShell::Paste( SwDoc* pClpDoc, bool bNestedTable ) { SET_CURR_SHELL( this ); OSL_ENSURE( pClpDoc, "no clipboard document" ); @@ -826,6 +826,8 @@ bool SwFEShell::Paste( SwDoc* pClpDoc ) SwTableNode *const pDestNd(GetDoc()->IsIdxInTable(rPaM.GetPoint()->nNode)); if (pSrcNd && nullptr != pDestNd && + // not a forced nested table insertion + !bNestedTable && // are we at the beginning of the cell? (if not, we will insert a nested table) // first paragraph of the cell? rPaM.GetNode().GetIndex() == rPaM.GetNode().FindTableBoxStartNode()->GetIndex()+1 && diff --git a/sw/source/uibase/dochdl/swdtflvr.cxx b/sw/source/uibase/dochdl/swdtflvr.cxx index b05bfb2f229b..e5824e43546f 100644 --- a/sw/source/uibase/dochdl/swdtflvr.cxx +++ b/sw/source/uibase/dochdl/swdtflvr.cxx @@ -885,6 +885,9 @@ int SwTransferable::PrepareForCopy( bool bIsCut ) if ( m_pWrtShell->GetTableInsertMode() != SwTable::SEARCH_NONE ) m_pWrtShell->SetTableInsertMode( SwTable::SEARCH_NONE ); + if ( m_pWrtShell->GetTableCopied() ) + m_pWrtShell->SetTableCopied( false ); + OUString sGrfNm; const SelectionType nSelection = m_pWrtShell->GetSelectionType(); if( nSelection == SelectionType::Graphic ) @@ -1017,6 +1020,8 @@ int SwTransferable::PrepareForCopy( bool bIsCut ) m_eBufferType = TransferBufferType::Table | m_eBufferType; bDDELink = m_pWrtShell->HasWholeTabSelection(); + m_pWrtShell->SetTableCopied(true); + if ( bIsCut && (SelectionType::TableRow | SelectionType::TableCol) & nSelection ) m_pWrtShell->SetTableInsertMode( (SelectionType::TableRow & nSelection) ? SwTable::SEARCH_ROW : SwTable::SEARCH_COL ); } @@ -1352,7 +1357,7 @@ bool SwTransferable::IsPaste( const SwWrtShell& rSh, return bIsPaste; } -bool SwTransferable::Paste(SwWrtShell& rSh, TransferableDataHelper& rData, RndStdIds nAnchorType, bool bIgnoreComments) +bool SwTransferable::Paste(SwWrtShell& rSh, TransferableDataHelper& rData, RndStdIds nAnchorType, bool bIgnoreComments, bool bNestedTable) { SwPasteContext aPasteContext(rSh); @@ -1424,14 +1429,17 @@ bool SwTransferable::Paste(SwWrtShell& rSh, TransferableDataHelper& rData, RndSt nLevel++; } while (rSh.GetDoc()->IsIdxInTable(rSh.GetCursor()->GetNode()) != nullptr); if ( SwTransferable::PasteData( rData, rSh, EXCHG_OUT_ACTION_INSERT_STRING, nActionFlags, SotClipboardFormatId::HTML, - nDestination, false, false, nullptr, 0, false, nAnchorType, bIgnoreComments, &aPasteContext )) + nDestination, false, false, nullptr, 0, false, nAnchorType, bIgnoreComments, &aPasteContext, bNestedTable )) { pDispatch->Execute(FN_CHAR_LEFT, SfxCallMode::SYNCHRON); pDispatch->Execute(FN_TABLE_SELECT_ALL, SfxCallMode::SYNCHRON); pDispatch->Execute(SID_COPY, SfxCallMode::SYNCHRON); for(sal_uInt32 a = 0; a < 1 + (nLevel * 2); a++) pDispatch->Execute(SID_UNDO, SfxCallMode::SYNCHRON); - pDispatch->Execute(SID_PASTE, SfxCallMode::SYNCHRON); + if (bNestedTable) + pDispatch->Execute(FN_PASTE_NESTED_TABLE, SfxCallMode::SYNCHRON); + else + pDispatch->Execute(SID_PASTE, SfxCallMode::SYNCHRON); return true; } else { for(sal_uInt32 a = 0; a < (nLevel * 2); a++) @@ -1494,7 +1502,7 @@ bool SwTransferable::Paste(SwWrtShell& rSh, TransferableDataHelper& rData, RndSt // paste rows bool bResult = SwTransferable::PasteData( rData, rSh, nAction, nActionFlags, nFormat, - nDestination, false, false, nullptr, 0, false, nAnchorType, bIgnoreComments, &aPasteContext ); + nDestination, false, false, nullptr, 0, false, nAnchorType, bIgnoreComments, &aPasteContext, bNestedTable ); // restore cursor position if (pMark != nullptr) @@ -1526,7 +1534,7 @@ bool SwTransferable::Paste(SwWrtShell& rSh, TransferableDataHelper& rData, RndSt return EXCHG_INOUT_ACTION_NONE != nAction && SwTransferable::PasteData( rData, rSh, nAction, nActionFlags, nFormat, - nDestination, false, false, nullptr, 0, false, nAnchorType, bIgnoreComments, &aPasteContext ); + nDestination, false, false, nullptr, 0, false, nAnchorType, bIgnoreComments, &aPasteContext, bNestedTable ); } bool SwTransferable::PasteData( TransferableDataHelper& rData, @@ -1537,7 +1545,8 @@ bool SwTransferable::PasteData( TransferableDataHelper& rData, const Point* pPt, sal_Int8 nDropAction, bool bPasteSelection, RndStdIds nAnchorType, bool bIgnoreComments, - SwPasteContext* pContext ) + SwPasteContext* pContext, + bool bNestedTable ) { SwWait aWait( *rSh.GetView().GetDocShell(), false ); std::unique_ptr<SwTrnsfrActionAndUndo, o3tl::default_delete<SwTrnsfrActionAndUndo>> pAction; @@ -1643,7 +1652,7 @@ bool SwTransferable::PasteData( TransferableDataHelper& rData, EXCHG_OUT_ACTION_INSERT_PRIVATE == nAction ) { // then internal paste - bRet = pTunneledTrans->PrivatePaste(rSh, pContext); + bRet = pTunneledTrans->PrivatePaste(rSh, pContext, bNestedTable); } else if( EXCHG_INOUT_ACTION_NONE != nAction ) { @@ -3189,6 +3198,11 @@ bool SwTransferable::IsPasteSpecial( const SwWrtShell& rWrtShell, return aClipboardFormatItem.Count() > 0; } +bool SwTransferable::IsPasteOwnFormat( const TransferableDataHelper& rData ) +{ + return ( GetSwTransferable( rData ) != nullptr ); +} + bool SwTransferable::PasteFormat( SwWrtShell& rSh, TransferableDataHelper& rData, SotClipboardFormatId nFormat ) @@ -3613,7 +3627,7 @@ bool lcl_checkClassification(SwDoc* pSourceDoc, SwDoc* pDestinationDoc) } -bool SwTransferable::PrivatePaste(SwWrtShell& rShell, SwPasteContext* pContext) +bool SwTransferable::PrivatePaste(SwWrtShell& rShell, SwPasteContext* pContext, bool bNestedTable) { // first, ask for the SelectionType, then action-bracketing !!!! // (otherwise it's not pasted into a TableSelection!!!) @@ -3675,7 +3689,7 @@ bool SwTransferable::PrivatePaste(SwWrtShell& rShell, SwPasteContext* pContext) bool bRet = true; // 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()); + bRet = rShell.Paste(m_pClpDocFac->GetDoc(), bNestedTable); if( bKillPaMs ) rShell.KillPams(); diff --git a/sw/source/uibase/inc/swdtflvr.hxx b/sw/source/uibase/inc/swdtflvr.hxx index 680e808767b8..c63b1987afc4 100644 --- a/sw/source/uibase/inc/swdtflvr.hxx +++ b/sw/source/uibase/inc/swdtflvr.hxx @@ -138,7 +138,7 @@ class SW_DLLPUBLIC SwTransferable : public TransferableHelper bool PrivateDrop( SwWrtShell& rSh, const Point& rDragPt, bool bMove, bool bIsXSelection ); - bool PrivatePaste( SwWrtShell& rShell, SwPasteContext* pContext = nullptr ); + bool PrivatePaste( SwWrtShell& rShell, SwPasteContext* pContext = nullptr, bool bNestedTable = false ); void SetDataForDragAndDrop( const Point& rSttPos ); @@ -180,7 +180,7 @@ public: // paste - methods and helper methods for the paste static bool IsPaste( const SwWrtShell&, const TransferableDataHelper& ); - static bool Paste( SwWrtShell&, TransferableDataHelper&, RndStdIds nAnchorType = RndStdIds::FLY_AT_PARA, bool bIgnoreComments = false ); + static bool Paste( SwWrtShell&, TransferableDataHelper&, RndStdIds nAnchorType = RndStdIds::FLY_AT_PARA, bool bIgnoreComments = false, bool bTableInCell = false ); static bool PasteData( TransferableDataHelper& rData, SwWrtShell& rSh, sal_uInt8 nAction, SotExchangeActionFlags nActionFlags, SotClipboardFormatId nFormat, @@ -189,10 +189,12 @@ public: const Point* pDDPos = nullptr, sal_Int8 nDropAction = 0, bool bPasteSelection = false, RndStdIds nAnchorType = RndStdIds::FLY_AT_PARA, bool bIgnoreComments = false, - SwPasteContext* pContext = nullptr ); + SwPasteContext* pContext = nullptr, + bool bNestedTable = false ); static bool IsPasteSpecial( const SwWrtShell& rWrtShell, const TransferableDataHelper& ); + static bool IsPasteOwnFormat( const TransferableDataHelper& ); static bool PasteUnformatted( SwWrtShell& rSh, TransferableDataHelper& ); /** * @brief PrePasteSpecial Prepares the given dialog without actually running it diff --git a/sw/source/uibase/shells/basesh.cxx b/sw/source/uibase/shells/basesh.cxx index e65149b15995..d4be48231771 100644 --- a/sw/source/uibase/shells/basesh.cxx +++ b/sw/source/uibase/shells/basesh.cxx @@ -258,6 +258,7 @@ void SwBaseShell::ExecClpbrd(SfxRequest &rReq) SwWrtShell &rSh = GetShell(); sal_uInt16 nId = rReq.GetSlot(); bool bIgnore = false; + bool bPasteNestedTable = false; switch( nId ) { case SID_CUT: @@ -280,6 +281,9 @@ void SwBaseShell::ExecClpbrd(SfxRequest &rReq) } return; + case FN_PASTE_NESTED_TABLE: + bPasteNestedTable = true; + [[fallthrough]]; case SID_PASTE: { TransferableDataHelper aDataHelper( @@ -299,7 +303,7 @@ void SwBaseShell::ExecClpbrd(SfxRequest &rReq) const SfxBoolItem* pIgnoreComments = rReq.GetArg<SfxBoolItem>(FN_PARAM_2); if (pIgnoreComments) bIgnoreComments = pIgnoreComments->GetValue(); - SwTransferable::Paste(rSh, aDataHelper, nAnchorType, bIgnoreComments); + SwTransferable::Paste(rSh, aDataHelper, nAnchorType, bIgnoreComments, bPasteNestedTable); if( rSh.IsFrameSelected() || rSh.IsObjSelected() ) rSh.EnterSelFrameMode(); @@ -466,6 +470,17 @@ void SwBaseShell::StateClpbrd(SfxItemSet &rSet) rSet.DisableItem( nWhich ); break; + case FN_PASTE_NESTED_TABLE: + if( !rSh.IsCursorInTable() + || !GetView().IsPasteSpecialAllowed() + || rSh.CursorInsideInputField() + // disable if not a native Writer table and not a spreadsheet format + || !GetView().IsPasteSpreadsheet(rSh.GetTableCopied()) ) + { + rSet.DisableItem( nWhich ); + } + break; + case SID_PASTE: if( !GetView().IsPasteAllowed() ) { diff --git a/sw/source/uibase/uiview/view.cxx b/sw/source/uibase/uiview/view.cxx index ec013052dc75..3e0f7303729b 100644 --- a/sw/source/uibase/uiview/view.cxx +++ b/sw/source/uibase/uiview/view.cxx @@ -594,7 +594,7 @@ void SwView::CheckReadonlyState() SID_DELETE, FN_BACKSPACE, FN_SHIFT_BACKSPACE, SID_UNDO, SID_REDO, SID_REPEAT, SID_PASTE, - SID_PASTE_UNFORMATTED, + SID_PASTE_UNFORMATTED, FN_PASTE_NESTED_TABLE, SID_PASTE_SPECIAL, SID_SBA_BRW_INSERT, SID_BACKGROUND_COLOR, FN_INSERT_BOOKMARK, SID_CHARMAP_CONTROL, SID_CHARMAP, SID_EMOJI_CONTROL, FN_INSERT_SOFT_HYPHEN, @@ -1848,6 +1848,20 @@ bool SwView::IsPasteSpecialAllowed() return m_bPasteSpecialState; } +bool SwView::IsPasteSpreadsheet(bool bHasOwnTableCopied) +{ + TransferableDataHelper aDataHelper( + TransferableDataHelper::CreateFromSystemClipboard( + &GetEditWin()) ); + if( aDataHelper.GetXTransferable().is() ) + { + if (bHasOwnTableCopied && SwTransferable::IsPasteOwnFormat( aDataHelper )) + return true; + return aDataHelper.HasFormat( SotClipboardFormatId::SYLK ) || aDataHelper.HasFormat( SotClipboardFormatId::SYLK_BIGCAPS ); + } + return false; +} + void SwView::NotifyDBChanged() { GetViewImpl()->GetUNOObject_Impl()->NotifyDBChanged(); diff --git a/sw/uiconfig/swriter/menubar/menubar.xml b/sw/uiconfig/swriter/menubar/menubar.xml index bd57b91564da..77e1ebae5f57 100644 --- a/sw/uiconfig/swriter/menubar/menubar.xml +++ b/sw/uiconfig/swriter/menubar/menubar.xml @@ -105,6 +105,7 @@ <menu:menupopup> <menu:menuitem menu:id=".uno:PasteUnformatted"/> <menu:menuitem menu:id=".uno:PasteSpecial"/> + <menu:menuitem menu:id=".uno:PasteNestedTable"/> </menu:menupopup> </menu:menu> <menu:menuseparator/> diff --git a/sw/uiconfig/swriter/popupmenu/table.xml b/sw/uiconfig/swriter/popupmenu/table.xml index 09470cab6d34..4baf20af019d 100644 --- a/sw/uiconfig/swriter/popupmenu/table.xml +++ b/sw/uiconfig/swriter/popupmenu/table.xml @@ -13,6 +13,7 @@ <menu:menuitem menu:id=".uno:Paste"/> <menu:menu menu:id=".uno:PasteSpecialMenu"> <menu:menupopup> + <menu:menuitem menu:id=".uno:PasteNestedTable"/> <menu:menuitem menu:id=".uno:PasteUnformatted"/> <menu:menuitem menu:id=".uno:PasteSpecial"/> </menu:menupopup> _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits