filter/source/config/fragments/types/MS_Excel_2007_Binary.xcu | 2 include/sot/formats.hxx | 3 include/svtools/strings.hrc | 1 sc/source/core/data/drwlayer.cxx | 2 sc/source/ui/docshell/docsh.cxx | 5 sc/source/ui/inc/docsh.hxx | 1 sc/source/ui/inc/viewfunc.hxx | 3 sc/source/ui/view/cellsh.cxx | 1 sc/source/ui/view/gridwin.cxx | 2 sc/source/ui/view/viewfun3.cxx | 10 sc/source/ui/view/viewfun5.cxx | 106 ++++++---- sot/source/base/exchange.cxx | 1 sot/source/base/formats.cxx | 2 svtools/source/dialogs/insdlg.cxx | 1 vcl/win/dtrans/ftransl.cxx | 1 15 files changed, 97 insertions(+), 44 deletions(-)
New commits: commit ba49c9249fcfec8891ef7d53dc8c9db1715df020 Author: Laurent Balland <[email protected]> AuthorDate: Fri Aug 22 17:59:30 2025 +0200 Commit: Mike Kaganski <[email protected]> CommitDate: Sun Nov 16 16:05:34 2025 +0100 tdf#127675 Treat Biff12 when pasting Prior to Biff8, Biff12 is tested as format for pasting. The new format is read using SfxObjectShell::DoLoad. Since the import must be to an ScDocument in SCDOCMODE_CLIP mode, a new ctor was added for SfxObjectShell, that initializes the document with needed mode. The change in MS_Excel_2007_Binary.xcu enables GetFilter4ClipBoardId to return the correct filter. Since clipboard documents don't have a chart listener collection, we must not call SetChartListenerCollectionNeedsUpdate from SetChanged; otherwise, ScDocument::UpdateChartListenerCollection would crash. Change-Id: If57b1ffb9a2f8d0573cf77b9eb82f81aa4250b5e Co-authored-by: Mike Kaganski <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190077 Tested-by: Jenkins Reviewed-by: Mike Kaganski <[email protected]> diff --git a/filter/source/config/fragments/types/MS_Excel_2007_Binary.xcu b/filter/source/config/fragments/types/MS_Excel_2007_Binary.xcu index 14a03a846288..525eac266c94 100644 --- a/filter/source/config/fragments/types/MS_Excel_2007_Binary.xcu +++ b/filter/source/config/fragments/types/MS_Excel_2007_Binary.xcu @@ -23,5 +23,5 @@ <prop oor:name="Preferred"><value>false</value></prop> <prop oor:name="PreferredFilter"><value>Calc MS Excel 2007 Binary</value></prop> <prop oor:name="UIName"><value xml:lang="en-US">Microsoft Excel 2007 Binary</value></prop> - <prop oor:name="ClipboardFormat"/> + <prop oor:name="ClipboardFormat"><value>Biff12</value></prop> </node> diff --git a/include/sot/formats.hxx b/include/sot/formats.hxx index 6b662b4698af..2986f6ed7d90 100644 --- a/include/sot/formats.hxx +++ b/include/sot/formats.hxx @@ -180,8 +180,9 @@ enum class SotClipboardFormatId : sal_uInt32 PDF = 147, SVG = 148, MARKDOWN = 149, + BIFF_12 = 150, // the point at which we start allocating "runtime" format IDs - USER_END = MARKDOWN + USER_END = BIFF_12 }; /** Make it easier to iterate over format IDs */ diff --git a/include/svtools/strings.hrc b/include/svtools/strings.hrc index e7beb572a342..7da89c263edc 100644 --- a/include/svtools/strings.hrc +++ b/include/svtools/strings.hrc @@ -71,6 +71,7 @@ #define STR_FORMAT_ID_MARKDOWN NC_("STR_FORMAT_ID_MARKDOWN", "Markdown") #define STR_FORMAT_ID_BIFF_5 NC_("STR_FORMAT_ID_BIFF_5", "Microsoft Excel Binary Interchange Format 5.0/95 (Biff5)") #define STR_FORMAT_ID_BIFF_8 NC_("STR_FORMAT_ID_BIFF_8", "Microsoft Excel Binary Interchange Format 97/2000/XP/2003 (Biff8)") +#define STR_FORMAT_ID_BIFF_12 NC_("STR_FORMAT_ID_BIFF_12", "Microsoft Excel Binary Interchange Format 2007 (Biff12)") #define STR_FORMAT_ID_SYLK NC_("STR_FORMAT_ID_SYLK", "Sylk") #define STR_FORMAT_ID_LINK NC_("STR_FORMAT_ID_LINK", "Dynamic Data Exchange (DDE link)" ) #define STR_FORMAT_ID_DIF NC_("STR_FORMAT_ID_DIF", "Data Interchange Format (DIF)") diff --git a/sc/source/core/data/drwlayer.cxx b/sc/source/core/data/drwlayer.cxx index 2867ec1c6e71..05baec03ead6 100644 --- a/sc/source/core/data/drwlayer.cxx +++ b/sc/source/core/data/drwlayer.cxx @@ -2917,7 +2917,7 @@ void ScDrawLayer::SetGlobalDrawPersist(SfxObjectShell* pPersist) void ScDrawLayer::SetChanged( bool bFlg /* = true */ ) { - if ( bFlg && pDoc ) + if (bFlg && pDoc && pDoc->GetChartListenerCollection()) // clip documents don't have it pDoc->SetChartListenerCollectionNeedsUpdate( true ); FmFormModel::SetChanged( bFlg ); } diff --git a/sc/source/ui/docshell/docsh.cxx b/sc/source/ui/docshell/docsh.cxx index 8af4475f5151..b97eba39e676 100644 --- a/sc/source/ui/docshell/docsh.cxx +++ b/sc/source/ui/docshell/docsh.cxx @@ -2966,6 +2966,11 @@ std::unique_ptr<ScDocFunc> ScDocShell::CreateDocFunc() return std::make_unique<ScDocFuncDirect>( *this ); } +ScDocShell::ScDocShell(const SfxModelFlags i_nSfxCreationFlags, ScDocumentMode docMode) + : ScDocShell(i_nSfxCreationFlags, std::make_shared<ScDocument>(docMode, this)) +{ +} + ScDocShell::ScDocShell( const SfxModelFlags i_nSfxCreationFlags, const std::shared_ptr<ScDocument>& pDoc ) : SfxObjectShell( i_nSfxCreationFlags ), m_pDocument ( pDoc ? pDoc : std::make_shared<ScDocument>( SCDOCMODE_DOCUMENT, this )), diff --git a/sc/source/ui/inc/docsh.hxx b/sc/source/ui/inc/docsh.hxx index 88174b4312ef..622d89fc2d92 100644 --- a/sc/source/ui/inc/docsh.hxx +++ b/sc/source/ui/inc/docsh.hxx @@ -171,6 +171,7 @@ private: public: explicit ScDocShell( const ScDocShell& rDocShell ) = delete; SC_DLLPUBLIC explicit ScDocShell( const SfxModelFlags i_nSfxCreationFlags = SfxModelFlags::EMBEDDED_OBJECT, const std::shared_ptr<ScDocument>& pDoc = {} ); + explicit ScDocShell(const SfxModelFlags i_nSfxCreationFlags, ScDocumentMode); virtual ~ScDocShell() override; SC_DLLPUBLIC virtual SfxUndoManager* GetUndoManager() override; diff --git a/sc/source/ui/inc/viewfunc.hxx b/sc/source/ui/inc/viewfunc.hxx index 4520b9eb03a4..85fb6af0e3d3 100644 --- a/sc/source/ui/inc/viewfunc.hxx +++ b/sc/source/ui/inc/viewfunc.hxx @@ -418,6 +418,9 @@ private: SCCOL nEndCol, SCROW nEndRow, sal_uLong nCount ); bool CheckSheetViewProtection(sc::Operation eOperation); + + void PasteFromExcelClip(ScDocument& rClipDoc, SCTAB nSrcTab, SCCOL nPosX, SCROW nPosY, + const Point* pLogicPos, bool bAllowDialogs); }; extern bool bPasteIsMove; diff --git a/sc/source/ui/view/cellsh.cxx b/sc/source/ui/view/cellsh.cxx index fa646cc67896..7092fc64e4c9 100644 --- a/sc/source/ui/view/cellsh.cxx +++ b/sc/source/ui/view/cellsh.cxx @@ -492,6 +492,7 @@ void ScCellShell::GetPossibleClipboardFormats( SvxClipboardFormatItem& rFormats lcl_TestFormat( rFormats, aDataHelper, SotClipboardFormatId::RICHTEXT ); lcl_TestFormat( rFormats, aDataHelper, SotClipboardFormatId::HTML ); lcl_TestFormat( rFormats, aDataHelper, SotClipboardFormatId::HTML_SIMPLE ); + lcl_TestFormat( rFormats, aDataHelper, SotClipboardFormatId::BIFF_12 ); lcl_TestFormat( rFormats, aDataHelper, SotClipboardFormatId::BIFF_8 ); lcl_TestFormat( rFormats, aDataHelper, SotClipboardFormatId::BIFF_5 ); } diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx index cbf6a586a949..7a763279006d 100644 --- a/sc/source/ui/view/gridwin.cxx +++ b/sc/source/ui/view/gridwin.cxx @@ -4466,6 +4466,8 @@ static SotClipboardFormatId lcl_GetDropFormatId( const uno::Reference<datatransf nFormatId = SotClipboardFormatId::SBA_DATAEXCHANGE; else if ( aDataHelper.HasFormat( SotClipboardFormatId::SBA_FIELDDATAEXCHANGE ) ) nFormatId = SotClipboardFormatId::SBA_FIELDDATAEXCHANGE; + else if ( aDataHelper.HasFormat( SotClipboardFormatId::BIFF_12 ) ) + nFormatId = SotClipboardFormatId::BIFF_12; else if ( aDataHelper.HasFormat( SotClipboardFormatId::BIFF_8 ) ) nFormatId = SotClipboardFormatId::BIFF_8; else if ( aDataHelper.HasFormat( SotClipboardFormatId::BIFF_5 ) ) diff --git a/sc/source/ui/view/viewfun3.cxx b/sc/source/ui/view/viewfun3.cxx index 3aa58ac19bad..31a901b87d4a 100644 --- a/sc/source/ui/view/viewfun3.cxx +++ b/sc/source/ui/view/viewfun3.cxx @@ -517,6 +517,7 @@ void ScViewFunc::PasteFromSystem(bool useSavedPrefs) TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( pWin ) ); { + SotClipboardFormatId nBiff12= SotExchange::RegisterFormatName(u"Biff12"_ustr); SotClipboardFormatId nBiff8 = SotExchange::RegisterFormatName(u"Biff8"_ustr); SotClipboardFormatId nBiff5 = SotExchange::RegisterFormatName(u"Biff5"_ustr); @@ -602,7 +603,9 @@ void ScViewFunc::PasteFromSystem(bool useSavedPrefs) else if (aDataHelper.HasFormat( SotClipboardFormatId::EMBEDDED_OBJ_OLE )) PasteFromSystem( SotClipboardFormatId::EMBEDDED_OBJ_OLE ); // SotClipboardFormatId::PRIVATE no longer here (can't work if pOwnClip is NULL) - else if (aDataHelper.HasFormat(nBiff8)) // before xxx_OLE formats + else if (aDataHelper.HasFormat(nBiff12)) // before xxx_OLE formats + PasteFromSystem(nBiff12); + else if (aDataHelper.HasFormat(nBiff8)) PasteFromSystem(nBiff8); else if (aDataHelper.HasFormat(nBiff5)) PasteFromSystem(nBiff5); @@ -656,6 +659,7 @@ void ScViewFunc::PasteFromTransferable( const uno::Reference<datatransfer::XTran else { TransferableDataHelper aDataHelper( rxTransferable ); + SotClipboardFormatId nBiff12 = SotExchange::RegisterFormatName(u"Biff12"_ustr); SotClipboardFormatId nBiff8 = SotExchange::RegisterFormatName(u"Biff8"_ustr); SotClipboardFormatId nBiff5 = SotExchange::RegisterFormatName(u"Biff5"_ustr); SotClipboardFormatId nFormatId = SotClipboardFormatId::NONE; @@ -688,7 +692,9 @@ void ScViewFunc::PasteFromTransferable( const uno::Reference<datatransfer::XTran else if (aDataHelper.HasFormat( SotClipboardFormatId::EMBEDDED_OBJ_OLE )) nFormatId = SotClipboardFormatId::EMBEDDED_OBJ_OLE; // SotClipboardFormatId::PRIVATE no longer here (can't work if pOwnClip is NULL) - else if (aDataHelper.HasFormat(nBiff8)) // before xxx_OLE formats + else if (aDataHelper.HasFormat(nBiff12)) // before xxx_OLE formats + nFormatId = nBiff12; + else if (aDataHelper.HasFormat(nBiff8)) nFormatId = nBiff8; else if (aDataHelper.HasFormat(nBiff5)) nFormatId = nBiff5; diff --git a/sc/source/ui/view/viewfun5.cxx b/sc/source/ui/view/viewfun5.cxx index ddd23c51019b..9cc85001a137 100644 --- a/sc/source/ui/view/viewfun5.cxx +++ b/sc/source/ui/view/viewfun5.cxx @@ -39,6 +39,7 @@ #include <svx/GenericDropDownFieldDialog.hxx> #include <sfx2/dispatch.hxx> #include <sfx2/docfile.hxx> +#include <sfx2/fcontnr.hxx> #include <comphelper/classids.hxx> #include <sot/formats.hxx> #include <sot/filelist.hxx> @@ -83,6 +84,48 @@ using namespace com::sun::star; +void ScViewFunc::PasteFromExcelClip(ScDocument& rClipDoc, SCTAB nSrcTab, SCCOL nPosX, SCROW nPosY, + const Point* pLogicPos, bool bAllowDialogs) +{ + ScRange aSource; + const ScExtDocOptions* pExtOpt = rClipDoc.GetExtDocOptions(); + const ScExtTabSettings* pTabSett = pExtOpt ? pExtOpt->GetTabSettings(nSrcTab) : nullptr; + if (pTabSett && pTabSett->maUsedArea.IsValid()) + { + aSource = pTabSett->maUsedArea; + // ensure correct sheet indexes + aSource.aStart.SetTab(nSrcTab); + aSource.aEnd.SetTab(nSrcTab); + // don't use selection area: if cursor is moved in Excel after Copy, selection + // represents the new cursor position and not the copied area + } + else + { + // Biff12 goes here + SCCOL nFirstCol, nLastCol; + SCROW nFirstRow, nLastRow; + if (rClipDoc.GetDataStart(nSrcTab, nFirstCol, nFirstRow)) + rClipDoc.GetCellArea(nSrcTab, nLastCol, nLastRow); + else + { + nFirstCol = nLastCol = 0; + nFirstRow = nLastRow = 0; + } + aSource = ScRange(nFirstCol, nFirstRow, nSrcTab, nLastCol, nLastRow, nSrcTab); + } + + if (pLogicPos) + { + // position specified (Drag&Drop) - change selection + MoveCursorAbs(nPosX, nPosY, SC_FOLLOW_NONE, false, false); + Unmark(); + } + + rClipDoc.SetClipArea(aSource); + PasteFromClip(InsertDeleteFlags::ALL, &rClipDoc, ScPasteFunc::NONE, false, + false, false, INS_NONE, InsertDeleteFlags::NONE, bAllowDialogs); +} + bool ScViewFunc::PasteDataFormat( SotClipboardFormatId nFormatId, const uno::Reference<datatransfer::XTransferable>& rxTransferable, SCCOL nPosX, SCROW nPosY, const Point* pLogicPos, bool bLink, bool bAllowDialogs, bool useSavedPrefs ) @@ -290,6 +333,29 @@ bool ScViewFunc::PasteDataFormat( SotClipboardFormatId nFormatId, bRet = true; } } + else if (nFormatId == SotClipboardFormatId::BIFF_12) + { + if (auto xStm = aDataHelper.GetInputStream(nFormatId, {})) + { + SfxFilterMatcher aMatcher(ScDocShell::Factory().GetFilterContainer()->GetName()); + if (auto pFilter = aMatcher.GetFilter4ClipBoardId(SotClipboardFormatId::BIFF_12)) + { + ScDocShellRef pClipShell(new ScDocShell(SfxModelFlags::NONE, SCDOCMODE_CLIP)); + SCTAB nSrcTab = 0; + pClipShell->GetDocument().ResetClip(&rDoc, nSrcTab); + SfxMedium aMed; + aMed.GetItemSet().Put(SfxUnoAnyItem(SID_INPUTSTREAM, uno::Any(xStm))); + aMed.SetFilter(pFilter); + + if (pClipShell->DoLoad(&aMed)) + { + PasteFromExcelClip(pClipShell->GetDocument(), nSrcTab, nPosX, nPosY, pLogicPos, + bAllowDialogs); + bRet = true; + } + } + } + } else if ( (nFormatId == SotClipboardFormatId::BIFF_5) || (nFormatId == SotClipboardFormatId::BIFF_8) ) { // do excel import into a clipboard document @@ -306,45 +372,7 @@ bool ScViewFunc::PasteDataFormat( SotClipboardFormatId nFormatId, ErrCode eErr = ScFormatFilter::Get().ScImportExcel( aMed, &aInsDoc, EIF_AUTO ); if ( eErr == ERRCODE_NONE ) { - ScRange aSource; - const ScExtDocOptions* pExtOpt = aInsDoc.GetExtDocOptions(); - const ScExtTabSettings* pTabSett = pExtOpt ? pExtOpt->GetTabSettings( nSrcTab ) : nullptr; - if( pTabSett && pTabSett->maUsedArea.IsValid() ) - { - aSource = pTabSett->maUsedArea; - // ensure correct sheet indexes - aSource.aStart.SetTab( nSrcTab ); - aSource.aEnd.SetTab( nSrcTab ); -// don't use selection area: if cursor is moved in Excel after Copy, selection -// represents the new cursor position and not the copied area - } - else - { - OSL_FAIL("no dimension"); //! possible? - SCCOL nFirstCol, nLastCol; - SCROW nFirstRow, nLastRow; - if ( aInsDoc.GetDataStart( nSrcTab, nFirstCol, nFirstRow ) ) - aInsDoc.GetCellArea( nSrcTab, nLastCol, nLastRow ); - else - { - nFirstCol = nLastCol = 0; - nFirstRow = nLastRow = 0; - } - aSource = ScRange( nFirstCol, nFirstRow, nSrcTab, - nLastCol, nLastRow, nSrcTab ); - } - - if ( pLogicPos ) - { - // position specified (Drag&Drop) - change selection - MoveCursorAbs( nPosX, nPosY, SC_FOLLOW_NONE, false, false ); - Unmark(); - } - - aInsDoc.SetClipArea( aSource ); - PasteFromClip( InsertDeleteFlags::ALL, &aInsDoc, - ScPasteFunc::NONE, false, false, false, INS_NONE, InsertDeleteFlags::NONE, - bAllowDialogs ); + PasteFromExcelClip(aInsDoc, nSrcTab, nPosX, nPosY, pLogicPos, bAllowDialogs); bRet = true; } } diff --git a/sot/source/base/exchange.cxx b/sot/source/base/exchange.cxx index a9f741d4bfdd..0ef2a148c4d4 100644 --- a/sot/source/base/exchange.cxx +++ b/sot/source/base/exchange.cxx @@ -198,6 +198,7 @@ const DataFlavor* FormatArray_Impl() /*147 PDF*/ { u"application/pdf"_ustr, u"PDF Document"_ustr, cppu::UnoType<Sequence<sal_Int8>>::get() }, /*148 SVG*/ { u"image/svg+xml;windows_formatname=\"image/svg+xml\""_ustr, u"SVG"_ustr, cppu::UnoType<Sequence<sal_Int8>>::get() }, /*149 MARKDOWN*/ { u"text/markdown"_ustr, u"Markdown"_ustr, cppu::UnoType<Sequence<sal_Int8>>::get() }, + /*150 BIFF_12*/ { u"application/x-openoffice-biff-12;windows_formatname=\"Biff12\""_ustr, u"Biff12"_ustr, cppu::UnoType<Sequence<sal_Int8>>::get() }, }; assert(std::size(aInstance) == size_t(SotClipboardFormatId::USER_END) + 1); return &aInstance[0]; diff --git a/sot/source/base/formats.cxx b/sot/source/base/formats.cxx index c927a79366db..ff2722339b1c 100644 --- a/sot/source/base/formats.cxx +++ b/sot/source/base/formats.cxx @@ -1017,6 +1017,7 @@ SotAction_Impl const aEXCHG_DEST_SCDOC_FREE_AREA_Move[] = { SotClipboardFormatId::LINK, EXCHG_OUT_ACTION_INSERT_DDE, SotExchangeActionFlags::InsertTargetUrl, 0 }, { SotClipboardFormatId::SVIM, EXCHG_OUT_ACTION_INSERT_IMAGEMAP, SotExchangeActionFlags::InsertTargetUrl, 0 }, { SotClipboardFormatId::BIFF_8, EXCHG_IN_ACTION_MOVE, SotExchangeActionFlags::InsertTargetUrl, 0 }, + { SotClipboardFormatId::BIFF_12, EXCHG_IN_ACTION_MOVE, SotExchangeActionFlags::InsertTargetUrl, 0 }, }; SotAction_Impl const aEXCHG_DEST_SCDOC_FREE_AREA_Copy[] = { @@ -1045,6 +1046,7 @@ SotAction_Impl const aEXCHG_DEST_SCDOC_FREE_AREA_Copy[] = { SotClipboardFormatId::LINK, EXCHG_OUT_ACTION_INSERT_DDE, SotExchangeActionFlags::InsertTargetUrl, 0 }, { SotClipboardFormatId::SVIM, EXCHG_OUT_ACTION_INSERT_IMAGEMAP, SotExchangeActionFlags::InsertTargetUrl, 0 }, { SotClipboardFormatId::BIFF_8, EXCHG_IN_ACTION_COPY, SotExchangeActionFlags::InsertTargetUrl, 0 }, + { SotClipboardFormatId::BIFF_12, EXCHG_IN_ACTION_COPY, SotExchangeActionFlags::InsertTargetUrl, 0 }, }; SotAction_Impl const aEXCHG_DEST_SCDOC_FREE_AREA_Link[] = { diff --git a/svtools/source/dialogs/insdlg.cxx b/svtools/source/dialogs/insdlg.cxx index 85f47709f54a..fdec3a29ec58 100644 --- a/svtools/source/dialogs/insdlg.cxx +++ b/svtools/source/dialogs/insdlg.cxx @@ -208,6 +208,7 @@ OUString SvPasteObjectHelper::GetSotFormatUIName( SotClipboardFormatId nId ) { SotClipboardFormatId::HTML_SIMPLE, STR_FORMAT_ID_HTML_SIMPLE }, { SotClipboardFormatId::BIFF_5, STR_FORMAT_ID_BIFF_5 }, { SotClipboardFormatId::BIFF_8, STR_FORMAT_ID_BIFF_8 }, + { SotClipboardFormatId::BIFF_12, STR_FORMAT_ID_BIFF_12 }, { SotClipboardFormatId::SYLK, STR_FORMAT_ID_SYLK }, { SotClipboardFormatId::LINK, STR_FORMAT_ID_LINK }, { SotClipboardFormatId::DIF, STR_FORMAT_ID_DIF }, diff --git a/vcl/win/dtrans/ftransl.cxx b/vcl/win/dtrans/ftransl.cxx index cf5d7ef35839..573b76b64b1f 100644 --- a/vcl/win/dtrans/ftransl.cxx +++ b/vcl/win/dtrans/ftransl.cxx @@ -177,6 +177,7 @@ auto initTranslTable() FormatEntry(xFactory, SotClipboardFormatId::BIFF_5), FormatEntry(xFactory, SotClipboardFormatId::BIFF__5), FormatEntry(xFactory, SotClipboardFormatId::BIFF_8), + FormatEntry(xFactory, SotClipboardFormatId::BIFF_12), FormatEntry(xFactory, SotClipboardFormatId::SYLK_BIGCAPS), FormatEntry(xFactory, SotClipboardFormatId::LINK), FormatEntry(xFactory, SotClipboardFormatId::STARDRAW_TABBAR),
