summaryrefslogtreecommitdiffstats
path: root/sw/source/uibase/dochdl
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
commit267c6f2ac71f92999e969232431ba04678e7437e (patch)
tree358c9467650e1d0a1d7227a21dac2e3d08b622b2 /sw/source/uibase/dochdl
parentInitial commit. (diff)
downloadlibreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz
libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sw/source/uibase/dochdl')
-rw-r--r--sw/source/uibase/dochdl/gloshdl.cxx725
-rw-r--r--sw/source/uibase/dochdl/swdtflvr.cxx4597
2 files changed, 5322 insertions, 0 deletions
diff --git a/sw/source/uibase/dochdl/gloshdl.cxx b/sw/source/uibase/dochdl/gloshdl.cxx
new file mode 100644
index 0000000000..e70ed7ffc4
--- /dev/null
+++ b/sw/source/uibase/dochdl/gloshdl.cxx
@@ -0,0 +1,725 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <utility>
+#include <vcl/errinf.hxx>
+#include <vcl/weld.hxx>
+#include <svl/macitem.hxx>
+#include <sfx2/fcontnr.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/docfilt.hxx>
+#include <unotools/transliterationwrapper.hxx>
+#include <o3tl/string_view.hxx>
+#include <docsh.hxx>
+#include <wrtsh.hxx>
+#include <view.hxx>
+#include <gloshdl.hxx>
+#include <glosdoc.hxx>
+#include <shellio.hxx>
+#include <swundo.hxx>
+#include <expfld.hxx>
+#include <initui.hxx>
+#include <gloslst.hxx>
+#include <swdtflvr.hxx>
+
+#include <strings.hrc>
+#include <vcl/svapp.hxx>
+#include <osl/diagnose.h>
+
+#include <editeng/acorrcfg.hxx>
+#include <sfx2/event.hxx>
+#include <swabstdlg.hxx>
+
+#include <memory>
+
+using namespace ::com::sun::star;
+
+const short RET_EDIT = 100;
+
+namespace {
+
+struct TextBlockInfo_Impl
+{
+ OUString sTitle;
+ OUString sLongName;
+ OUString sGroupName;
+ TextBlockInfo_Impl(OUString aTitle, OUString aLongName, OUString aGroupName)
+ : sTitle(std::move(aTitle)), sLongName(std::move(aLongName)), sGroupName(std::move(aGroupName)) {}
+};
+
+}
+
+// Dialog for edit templates
+void SwGlossaryHdl::GlossaryDlg()
+{
+ SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractGlossaryDlg> pDlg(pFact->CreateGlossaryDlg(m_rViewFrame, this, m_pWrtShell));
+ OUString sName;
+ OUString sShortName;
+
+ if( RET_EDIT == pDlg->Execute() )
+ {
+ sName = pDlg->GetCurrGrpName();
+ sShortName = pDlg->GetCurrShortName();
+ }
+
+ pDlg.disposeAndClear();
+ m_pCurGrp.reset();
+ if(HasGlossaryList())
+ {
+ GetGlossaryList()->ClearGroups();
+ }
+
+ if( !sName.isEmpty() || !sShortName.isEmpty() )
+ m_rStatGlossaries.EditGroupDoc( sName, sShortName );
+}
+
+// set the default group; if called from the dialog
+// the group is created temporarily for faster access
+void SwGlossaryHdl::SetCurGroup(const OUString &rGrp, bool bApi, bool bAlwaysCreateNew )
+{
+ OUString sGroup(rGrp);
+ if (sGroup.indexOf(GLOS_DELIM)<0 && !FindGroupName(sGroup))
+ {
+ sGroup += OUStringChar(GLOS_DELIM) + "0";
+ }
+ if(m_pCurGrp)
+ {
+ bool bPathEqual = false;
+ if(!bAlwaysCreateNew)
+ {
+ INetURLObject aTemp( m_pCurGrp->GetFileName() );
+ const OUString sCurBase = aTemp.getBase();
+ aTemp.removeSegment();
+ const OUString sCurEntryPath = aTemp.GetMainURL(INetURLObject::DecodeMechanism::NONE);
+ const std::vector<OUString> & rPathArr = m_rStatGlossaries.GetPathArray();
+ sal_uInt16 nCurrentPath = USHRT_MAX;
+ for (size_t nPath = 0; nPath < rPathArr.size(); ++nPath)
+ {
+ if (sCurEntryPath == rPathArr[nPath])
+ {
+ nCurrentPath = o3tl::narrowing<sal_uInt16>(nPath);
+ break;
+ }
+ }
+ const std::u16string_view sPath = o3tl::getToken(sGroup, 1, GLOS_DELIM);
+ sal_uInt16 nComparePath = o3tl::narrowing<sal_uInt16>(o3tl::toInt32(sPath));
+ if(nCurrentPath == nComparePath &&
+ o3tl::getToken(sGroup, 0, GLOS_DELIM) == sCurBase)
+ bPathEqual = true;
+ }
+
+ // When path changed, the name is not reliable
+ if(!bAlwaysCreateNew && bPathEqual)
+ return;
+ }
+ m_aCurGrp = sGroup;
+ if(!bApi)
+ {
+ m_pCurGrp = m_rStatGlossaries.GetGroupDoc(m_aCurGrp, true);
+ }
+}
+
+size_t SwGlossaryHdl::GetGroupCnt() const
+{
+ return m_rStatGlossaries.GetGroupCnt();
+}
+
+OUString SwGlossaryHdl::GetGroupName( size_t nId, OUString* pTitle )
+{
+ OUString sRet = m_rStatGlossaries.GetGroupName(nId);
+ if(pTitle)
+ {
+ std::unique_ptr<SwTextBlocks> pGroup = m_rStatGlossaries.GetGroupDoc(sRet);
+ if (pGroup && !pGroup->GetError())
+ {
+ *pTitle = pGroup->GetName();
+ if (pTitle->isEmpty())
+ {
+ *pTitle = sRet.getToken(0, GLOS_DELIM);
+ pGroup->SetName(*pTitle);
+ }
+ }
+ else
+ {
+ sRet.clear();
+ }
+ }
+ return sRet;
+}
+
+void SwGlossaryHdl::NewGroup(OUString &rGrpName, const OUString& rTitle)
+{
+ if (rGrpName.indexOf(GLOS_DELIM)<0)
+ FindGroupName(rGrpName);
+ m_rStatGlossaries.NewGroupDoc(rGrpName, rTitle);
+}
+
+void SwGlossaryHdl::RenameGroup(const OUString& rOld, OUString& rNew, const OUString& rNewTitle)
+{
+ OUString sOldGroup(rOld);
+ if (rOld.indexOf(GLOS_DELIM)<0)
+ FindGroupName(sOldGroup);
+ if(rOld == rNew)
+ {
+ std::unique_ptr<SwTextBlocks> pGroup = m_rStatGlossaries.GetGroupDoc(sOldGroup);
+ if(pGroup)
+ {
+ pGroup->SetName(rNewTitle);
+ }
+ }
+ else
+ {
+ OUString sNewGroup(rNew);
+ if (sNewGroup.indexOf(GLOS_DELIM)<0)
+ {
+ sNewGroup += OUStringChar(GLOS_DELIM) + "0";
+ }
+ m_rStatGlossaries.RenameGroupDoc(sOldGroup, sNewGroup, rNewTitle);
+ rNew = sNewGroup;
+ }
+}
+
+bool SwGlossaryHdl::CopyOrMove(const OUString& rSourceGroupName, OUString& rSourceShortName,
+ const OUString& rDestGroupName, const OUString& rLongName, bool bMove)
+{
+ std::unique_ptr<SwTextBlocks> pSourceGroup = m_rStatGlossaries.GetGroupDoc(rSourceGroupName);
+ std::unique_ptr<SwTextBlocks> pDestGroup = m_rStatGlossaries.GetGroupDoc(rDestGroupName);
+ if (pDestGroup->IsReadOnly() || (bMove && pSourceGroup->IsReadOnly()) )
+ {
+ return false;
+ }
+
+ //The index must be determined here because rSourceShortName maybe changed in CopyBlock
+ sal_uInt16 nDeleteIdx = pSourceGroup->GetIndex( rSourceShortName );
+ OSL_ENSURE(USHRT_MAX != nDeleteIdx, "entry not found");
+ ErrCode nRet = pSourceGroup->CopyBlock( *pDestGroup, rSourceShortName, rLongName );
+ if(!nRet && bMove)
+ {
+ // the index must be existing
+ nRet = pSourceGroup->Delete( nDeleteIdx ) ? ERRCODE_NONE : ErrCode(1);
+ }
+ return !nRet;
+}
+
+// delete an autotext-file-group
+bool SwGlossaryHdl::DelGroup(const OUString &rGrpName)
+{
+ OUString sGroup(rGrpName);
+ if (sGroup.indexOf(GLOS_DELIM)<0)
+ FindGroupName(sGroup);
+ if( m_rStatGlossaries.DelGroupDoc(sGroup) )
+ {
+ if(m_pCurGrp)
+ {
+ if (m_pCurGrp->GetName() == sGroup)
+ m_pCurGrp.reset();
+ }
+ return true;
+ }
+ return false;
+}
+
+// ask for number of autotexts
+sal_uInt16 SwGlossaryHdl::GetGlossaryCnt() const
+{
+ return m_pCurGrp ? m_pCurGrp->GetCount() : 0;
+}
+
+OUString SwGlossaryHdl::GetGlossaryName( sal_uInt16 nId )
+{
+ OSL_ENSURE(nId < GetGlossaryCnt(), "Text building block array over-indexed.");
+ return m_pCurGrp->GetLongName( nId );
+}
+
+OUString SwGlossaryHdl::GetGlossaryShortName(sal_uInt16 nId)
+{
+ OSL_ENSURE(nId < GetGlossaryCnt(), "Text building block array over-indexed.");
+ return m_pCurGrp->GetShortName( nId );
+}
+
+// ask for short name
+OUString SwGlossaryHdl::GetGlossaryShortName(std::u16string_view aName)
+{
+ OUString sReturn;
+ SwTextBlocks *pTmp =
+ m_pCurGrp ? m_pCurGrp.get() : m_rStatGlossaries.GetGroupDoc( m_aCurGrp ).release();
+ if(pTmp)
+ {
+ sal_uInt16 nIdx = pTmp->GetLongIndex( aName );
+ if( nIdx != sal_uInt16(-1) )
+ sReturn = pTmp->GetShortName( nIdx );
+ if( !m_pCurGrp )
+ delete pTmp;
+ }
+ return sReturn;
+}
+
+// short name for autotext already used?
+bool SwGlossaryHdl::HasShortName(const OUString& rShortName) const
+{
+ SwTextBlocks *pBlock = m_pCurGrp ? m_pCurGrp.get()
+ : m_rStatGlossaries.GetGroupDoc( m_aCurGrp ).release();
+ bool bRet = pBlock->GetIndex( rShortName ) != sal_uInt16(-1);
+ if( !m_pCurGrp )
+ delete pBlock;
+ return bRet;
+}
+
+// Create autotext
+bool SwGlossaryHdl::NewGlossary(const OUString& rName, const OUString& rShortName,
+ bool bCreateGroup, bool bNoAttr)
+{
+ SwTextBlocks *pTmp =
+ m_pCurGrp ? m_pCurGrp.get() : m_rStatGlossaries.GetGroupDoc( m_aCurGrp, bCreateGroup ).release();
+ //pTmp == 0 if the AutoText path setting is wrong
+ if(!pTmp)
+ {
+ if (!m_pCurGrp)
+ delete pTmp;
+ return false;
+ }
+
+ OUString sOnlyText;
+ OUString* pOnlyText = nullptr;
+ if( bNoAttr )
+ {
+ m_pWrtShell->GetSelectedText( sOnlyText, ParaBreakType::ToOnlyCR );
+ pOnlyText = &sOnlyText;
+ }
+
+ const SvxAutoCorrCfg& rCfg = SvxAutoCorrCfg::Get();
+
+ const sal_uInt16 nSuccess = m_pWrtShell->MakeGlossary( *pTmp, rName, rShortName,
+ rCfg.IsSaveRelFile(), pOnlyText );
+ if(nSuccess == sal_uInt16(-1) )
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_pWrtShell->GetView().GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok, SwResId(STR_ERR_INSERT_GLOS)));
+ xBox->run();
+ }
+ if( !m_pCurGrp )
+ delete pTmp;
+ return nSuccess != sal_uInt16(-1);
+}
+
+// Delete an autotext
+bool SwGlossaryHdl::DelGlossary(const OUString &rShortName)
+{
+ SwTextBlocks *pGlossary = m_pCurGrp ? m_pCurGrp.get()
+ : m_rStatGlossaries.GetGroupDoc(m_aCurGrp).release();
+ //pTmp == 0 if the AutoText path setting is wrong
+ if(!pGlossary)
+ {
+ if( !m_pCurGrp )
+ delete pGlossary;
+ return false;
+ }
+
+ sal_uInt16 nIdx = pGlossary->GetIndex( rShortName );
+ if( nIdx != sal_uInt16(-1) )
+ pGlossary->Delete( nIdx );
+ if( !m_pCurGrp )
+ delete pGlossary;
+ return true;
+}
+
+// expand short name
+bool SwGlossaryHdl::ExpandGlossary(weld::Window* pParent)
+{
+ OSL_ENSURE(m_pWrtShell->CanInsert(), "illegal");
+ SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
+ ::GlossaryGetCurrGroup fnGetCurrGroup = pFact->GetGlossaryCurrGroupFunc();
+ OUString sGroupName( (*fnGetCurrGroup)() );
+ if (sGroupName.indexOf(GLOS_DELIM)<0)
+ FindGroupName(sGroupName);
+ std::unique_ptr<SwTextBlocks> pGlossary = m_rStatGlossaries.GetGroupDoc(sGroupName);
+
+ OUString aShortName;
+
+ // use this at text selection
+ if(m_pWrtShell->SwCursorShell::HasSelection() && !m_pWrtShell->IsBlockMode())
+ {
+ aShortName = m_pWrtShell->GetSelText();
+ }
+ else
+ {
+ if(m_pWrtShell->IsAddMode())
+ m_pWrtShell->LeaveAddMode();
+ else if(m_pWrtShell->IsBlockMode())
+ m_pWrtShell->LeaveBlockMode();
+ else if(m_pWrtShell->IsExtMode())
+ m_pWrtShell->LeaveExtMode();
+ // select word (tdf#126589: part to the left of cursor)
+ if (m_pWrtShell->IsInWord() || m_pWrtShell->IsEndWrd())
+ m_pWrtShell->PrvWrd(true);
+ // ask for word
+ if(m_pWrtShell->IsSelection())
+ aShortName = m_pWrtShell->GetSelText();
+ }
+ return pGlossary && Expand(pParent, aShortName, &m_rStatGlossaries, std::move(pGlossary));
+}
+
+bool SwGlossaryHdl::Expand(weld::Window* pParent, const OUString& rShortName,
+ SwGlossaries *pGlossaries,
+ std::unique_ptr<SwTextBlocks> pGlossary)
+{
+ std::vector<TextBlockInfo_Impl> aFoundArr;
+ OUString aShortName( rShortName );
+ bool bCancel = false;
+ // search for text block
+ // - don't prefer current group depending on configuration setting
+ const SvxAutoCorrCfg& rCfg = SvxAutoCorrCfg::Get();
+ sal_uInt16 nFound = !rCfg.IsSearchInAllCategories() ? pGlossary->GetIndex( aShortName ) : -1;
+ // if not found then search in all groups
+ if( nFound == sal_uInt16(-1) )
+ {
+ const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore();
+ SwGlossaryList* pGlossaryList = ::GetGlossaryList();
+ const size_t nGroupCount = pGlossaryList->GetGroupCount();
+ for(size_t i = 0; i < nGroupCount; ++i)
+ {
+ // get group name with path-extension
+ const OUString sGroupName = pGlossaryList->GetGroupName(i);
+ if(sGroupName == pGlossary->GetName())
+ continue;
+ const sal_uInt16 nBlockCount = pGlossaryList->GetBlockCount(i);
+ if(nBlockCount)
+ {
+ const OUString sTitle = pGlossaryList->GetGroupTitle(i);
+ for(sal_uInt16 j = 0; j < nBlockCount; j++)
+ {
+ const OUString sLongName(pGlossaryList->GetBlockLongName(i, j));
+ const OUString sShortName(pGlossaryList->GetBlockShortName(i, j));
+ if( rSCmp.isEqual( rShortName, sShortName ))
+ {
+ aFoundArr.emplace_back(sTitle, sLongName, sGroupName);
+ }
+ }
+ }
+ }
+ if( !aFoundArr.empty() ) // one was found
+ {
+ pGlossary.reset();
+ if (1 == aFoundArr.size())
+ {
+ TextBlockInfo_Impl& rData = aFoundArr.front();
+ pGlossary = pGlossaries->GetGroupDoc(rData.sGroupName);
+ nFound = pGlossary->GetIndex( aShortName );
+ }
+ else
+ {
+ SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractSwSelGlossaryDlg> pDlg(pFact->CreateSwSelGlossaryDlg(pParent, aShortName));
+ for(const TextBlockInfo_Impl & i : aFoundArr)
+ {
+ pDlg->InsertGlos(i.sTitle, i.sLongName);
+ }
+ pDlg->SelectEntryPos(0);
+ const sal_Int32 nRet = RET_OK == pDlg->Execute() ?
+ pDlg->GetSelectedIdx() :
+ -1;
+ pDlg.disposeAndClear();
+ if (nRet != -1)
+ {
+ TextBlockInfo_Impl& rData = aFoundArr[nRet];
+ pGlossary = pGlossaries->GetGroupDoc(rData.sGroupName);
+ nFound = pGlossary->GetIndex( aShortName );
+ }
+ else
+ {
+ nFound = sal_uInt16(-1);
+ bCancel = true;
+ }
+ }
+ }
+ }
+
+ // not found
+ if( nFound == sal_uInt16(-1) )
+ {
+ if( !bCancel )
+ {
+ pGlossary.reset();
+
+ const sal_Int32 nMaxLen = 50;
+ if(m_pWrtShell->IsSelection() && aShortName.getLength() > nMaxLen)
+ {
+ aShortName = OUString::Concat(aShortName.subView(0, nMaxLen)) + " ...";
+ }
+ OUString aTmp( SwResId(STR_NOGLOS));
+ aTmp = aTmp.replaceFirst("%1", aShortName);
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(m_pWrtShell->GetView().GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ aTmp));
+ xInfoBox->run();
+ }
+
+ return false;
+ }
+ else
+ {
+ SvxMacro aStartMacro(OUString(), OUString(), STARBASIC);
+ SvxMacro aEndMacro(OUString(), OUString(), STARBASIC);
+ GetMacros( aShortName, aStartMacro, aEndMacro, pGlossary.get() );
+
+ // StartAction must not be before HasSelection and DelRight,
+ // otherwise the possible Shell change gets delayed and
+ // API-programs would hang.
+ // Moreover the event macro must also not be called in an action
+ m_pWrtShell->StartUndo(SwUndoId::INSGLOSSARY);
+ if( aStartMacro.HasMacro() )
+ m_pWrtShell->ExecMacro( aStartMacro );
+ if(m_pWrtShell->HasSelection())
+ m_pWrtShell->DelLeft();
+ m_pWrtShell->StartAllAction();
+
+ // cache all InputFields
+ SwInputFieldList aFieldLst( m_pWrtShell, true );
+
+ m_pWrtShell->InsertGlossary(*pGlossary, aShortName);
+ m_pWrtShell->EndAllAction();
+ if( aEndMacro.HasMacro() )
+ {
+ m_pWrtShell->ExecMacro( aEndMacro );
+ }
+ m_pWrtShell->EndUndo(SwUndoId::INSGLOSSARY);
+
+ // demand input for all new InputFields
+ if( aFieldLst.BuildSortLst() )
+ m_pWrtShell->UpdateInputFields( &aFieldLst );
+ }
+ return true;
+}
+
+// add autotext
+bool SwGlossaryHdl::InsertGlossary(const OUString &rName)
+{
+ OSL_ENSURE(m_pWrtShell->CanInsert(), "illegal");
+
+ SwTextBlocks *pGlos =
+ m_pCurGrp ? m_pCurGrp.get() : m_rStatGlossaries.GetGroupDoc(m_aCurGrp).release();
+
+ if (!pGlos)
+ {
+ if (!m_pCurGrp)
+ delete pGlos;
+ return false;
+ }
+
+ SvxMacro aStartMacro(OUString(), OUString(), STARBASIC);
+ SvxMacro aEndMacro(OUString(), OUString(), STARBASIC);
+ GetMacros( rName, aStartMacro, aEndMacro, pGlos );
+
+ // StartAction must not be before HasSelection and DelRight,
+ // otherwise the possible Shell change gets delayed and
+ // API-programs would hang.
+ // Moreover the event macro must also not be called in an action
+ if( aStartMacro.HasMacro() )
+ m_pWrtShell->ExecMacro( aStartMacro );
+ if( m_pWrtShell->HasSelection() )
+ m_pWrtShell->DelRight();
+ m_pWrtShell->StartAllAction();
+
+ // cache all InputFields
+ SwInputFieldList aFieldLst( m_pWrtShell, true );
+
+ m_pWrtShell->InsertGlossary(*pGlos, rName);
+ m_pWrtShell->EndAllAction();
+ if( aEndMacro.HasMacro() )
+ {
+ m_pWrtShell->ExecMacro( aEndMacro );
+ }
+
+ // demand input for all new InputFields
+ if( aFieldLst.BuildSortLst() )
+ m_pWrtShell->UpdateInputFields( &aFieldLst );
+
+ if(!m_pCurGrp)
+ delete pGlos;
+ return true;
+}
+
+// set / ask for macro
+void SwGlossaryHdl::SetMacros(const OUString& rShortName,
+ const SvxMacro* pStart,
+ const SvxMacro* pEnd,
+ SwTextBlocks *pGlossary )
+{
+ SwTextBlocks *pGlos = pGlossary ? pGlossary :
+ m_pCurGrp ? m_pCurGrp.get()
+ : m_rStatGlossaries.GetGroupDoc( m_aCurGrp ).release();
+ SvxMacroTableDtor aMacroTable;
+ if( pStart )
+ aMacroTable.Insert( SvMacroItemId::SwStartInsGlossary, *pStart);
+ if( pEnd )
+ aMacroTable.Insert( SvMacroItemId::SwEndInsGlossary, *pEnd);
+ sal_uInt16 nIdx = pGlos->GetIndex( rShortName );
+ if( !pGlos->SetMacroTable( nIdx, aMacroTable ) && pGlos->GetError() )
+ ErrorHandler::HandleError( pGlos->GetError() );
+
+ if(!m_pCurGrp && !pGlossary)
+ delete pGlos;
+}
+
+void SwGlossaryHdl::GetMacros( const OUString &rShortName,
+ SvxMacro& rStart,
+ SvxMacro& rEnd,
+ SwTextBlocks *pGlossary )
+{
+ SwTextBlocks *pGlos = pGlossary ? pGlossary
+ : m_pCurGrp ? m_pCurGrp.get()
+ : m_rStatGlossaries.GetGroupDoc(m_aCurGrp).release();
+ sal_uInt16 nIndex = pGlos->GetIndex( rShortName );
+ if( nIndex != USHRT_MAX )
+ {
+ SvxMacroTableDtor aMacroTable;
+ if( pGlos->GetMacroTable( nIndex, aMacroTable ) )
+ {
+ SvxMacro *pMacro = aMacroTable.Get( SvMacroItemId::SwStartInsGlossary );
+ if( pMacro )
+ rStart = *pMacro;
+
+ pMacro = aMacroTable.Get( SvMacroItemId::SwEndInsGlossary );
+ if( pMacro )
+ rEnd = *pMacro;
+ }
+ }
+
+ if( !m_pCurGrp && !pGlossary )
+ delete pGlos;
+}
+
+// ctor, dtor
+SwGlossaryHdl::SwGlossaryHdl(SfxViewFrame& rVwFrame, SwWrtShell *pSh)
+ : m_rStatGlossaries( *::GetGlossaries() ),
+ m_aCurGrp( SwGlossaries::GetDefName() ),
+ m_rViewFrame(rVwFrame),
+ m_pWrtShell( pSh )
+{
+}
+
+SwGlossaryHdl::~SwGlossaryHdl()
+{
+}
+
+// rename an autotext
+bool SwGlossaryHdl::Rename(const OUString& rOldShort, const OUString& rNewShortName,
+ const OUString& rNewName )
+{
+ bool bRet = false;
+ SwTextBlocks *pGlossary = m_pCurGrp ? m_pCurGrp.get()
+ : m_rStatGlossaries.GetGroupDoc(m_aCurGrp).release();
+ if(pGlossary)
+ {
+ sal_uInt16 nIdx = pGlossary->GetIndex( rOldShort );
+ sal_uInt16 nOldLongIdx = pGlossary->GetLongIndex( rNewName );
+ sal_uInt16 nOldIdx = pGlossary->GetIndex( rNewShortName );
+
+ if( nIdx != USHRT_MAX &&
+ (nOldLongIdx == USHRT_MAX || nOldLongIdx == nIdx )&&
+ (nOldIdx == USHRT_MAX || nOldIdx == nIdx ))
+ {
+ pGlossary->Rename( nIdx, &rNewShortName, &rNewName );
+ bRet = pGlossary->GetError() == ERRCODE_NONE;
+ }
+ if( !m_pCurGrp )
+ delete pGlossary;
+ }
+ return bRet;
+}
+
+bool SwGlossaryHdl::IsReadOnly( const OUString* pGrpNm ) const
+{
+ SwTextBlocks *pGlossary = nullptr;
+
+ if (pGrpNm)
+ pGlossary = m_rStatGlossaries.GetGroupDoc( *pGrpNm ).release();
+ else if (m_pCurGrp)
+ pGlossary = m_pCurGrp.get();
+ else
+ pGlossary = m_rStatGlossaries.GetGroupDoc(m_aCurGrp).release();
+
+ const bool bRet = !pGlossary || pGlossary->IsReadOnly();
+ if( pGrpNm || !m_pCurGrp )
+ delete pGlossary;
+ return bRet;
+}
+
+bool SwGlossaryHdl::IsOld() const
+{
+ if( !m_pCurGrp )
+ m_rStatGlossaries.GetGroupDoc(m_aCurGrp).reset();
+ return false;
+}
+
+// find group without path index
+bool SwGlossaryHdl::FindGroupName(OUString& rGroup)
+{
+ return m_rStatGlossaries.FindGroupName(rGroup);
+}
+
+bool SwGlossaryHdl::CopyToClipboard(SwWrtShell& rSh, const OUString& rShortName)
+{
+ SwTextBlocks *pGlossary = m_pCurGrp ? m_pCurGrp.get()
+ : m_rStatGlossaries.GetGroupDoc(m_aCurGrp).release();
+
+ rtl::Reference<SwTransferable> pTransfer = new SwTransferable( rSh );
+
+ bool bRet = pTransfer->CopyGlossary( *pGlossary, rShortName );
+ if( !m_pCurGrp )
+ delete pGlossary;
+ return bRet;
+}
+
+bool SwGlossaryHdl::ImportGlossaries( const OUString& rName )
+{
+ bool bRet = false;
+ if( !rName.isEmpty() )
+ {
+ std::shared_ptr<const SfxFilter> pFilter;
+ SfxMedium aMed( rName, StreamMode::READ, nullptr, nullptr );
+ SfxFilterMatcher aMatcher( "swriter" );
+ aMed.UseInteractionHandler( true );
+ if (aMatcher.GuessFilter(aMed, pFilter, SfxFilterFlags::NONE) == ERRCODE_NONE)
+ {
+ assert(pFilter && "success means pFilter was set");
+ SwTextBlocks *pGlossary = nullptr;
+ aMed.SetFilter( pFilter );
+ Reader* pR = SwReaderWriter::GetReader( pFilter->GetUserData() );
+ if( pR && nullptr != ( pGlossary = m_pCurGrp ? m_pCurGrp.get()
+ : m_rStatGlossaries.GetGroupDoc(m_aCurGrp).release()) )
+ {
+ SwReader aReader( aMed, rName );
+ if( aReader.HasGlossaries( *pR ) )
+ {
+ const SvxAutoCorrCfg& rCfg = SvxAutoCorrCfg::Get();
+ bRet = aReader.ReadGlossaries( *pR, *pGlossary,
+ rCfg.IsSaveRelFile() );
+ }
+
+ if (!m_pCurGrp)
+ delete pGlossary;
+ }
+ }
+ }
+ return bRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/dochdl/swdtflvr.cxx b/sw/source/uibase/dochdl/swdtflvr.cxx
new file mode 100644
index 0000000000..cb96c08527
--- /dev/null
+++ b/sw/source/uibase/dochdl/swdtflvr.cxx
@@ -0,0 +1,4597 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#include <com/sun/star/embed/XTransactedObject.hpp>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <com/sun/star/embed/XEmbedObjectClipboardCreator.hpp>
+#include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
+#include <com/sun/star/embed/MSOLEObjectSystemCreator.hpp>
+#include <com/sun/star/text/XPasteListener.hpp>
+
+#include <svtools/embedtransfer.hxx>
+#include <svtools/insdlg.hxx>
+#include <unotools/tempfile.hxx>
+#include <comphelper/fileformat.h>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/string.hxx>
+#include <o3tl/deleter.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <sot/filelist.hxx>
+#include <svx/svxdlg.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <osl/endian.h>
+#include <sfx2/linkmgr.hxx>
+#include <tools/urlobj.hxx>
+#include <vcl/weld.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/stritem.hxx>
+#include <vcl/imap.hxx>
+#include <sot/storage.hxx>
+#include <vcl/graph.hxx>
+#include <svl/urihelper.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/xmlexchg.hxx>
+#include <svx/dbaexchange.hxx>
+#include <svx/clipfmtitem.hxx>
+#include <sfx2/mieclip.hxx>
+#include <svl/urlbmk.hxx>
+#include <vcl/inetimg.hxx>
+#include <svx/fmview.hxx>
+#include <sfx2/docfilt.hxx>
+#include <vcl/imapobj.hxx>
+#include <sfx2/docfile.hxx>
+#include <unotools/transliterationwrapper.hxx>
+#include <unotools/streamwrap.hxx>
+#include <vcl/graphicfilter.hxx>
+
+#ifdef _WIN32
+#include <prewin.h>
+#include <postwin.h>
+#include <o3tl/char16_t2wchar_t.hxx>
+#include <osl/file.hxx>
+#endif
+
+#include <svx/unomodel.hxx>
+#include <fmturl.hxx>
+#include <fmtinfmt.hxx>
+#include <swdtflvr.hxx>
+#include <shellio.hxx>
+#include <ddefld.hxx>
+#include <doc.hxx>
+#include <IDocumentUndoRedo.hxx>
+#include <IDocumentDrawModelAccess.hxx>
+#include <IDocumentFieldsAccess.hxx>
+#include <IDocumentRedlineAccess.hxx>
+#include <IDocumentState.hxx>
+#include <IMark.hxx>
+#include <section.hxx>
+#include <ndtxt.hxx>
+#include <edtdd.hxx>
+#include <edtwin.hxx>
+#include <navicont.hxx>
+#include <swcont.hxx>
+#include <wrtsh.hxx>
+#include <swmodule.hxx>
+#include <view.hxx>
+#include <docsh.hxx>
+#include <wdocsh.hxx>
+#include <fldbas.hxx>
+#include <swundo.hxx>
+#include <pam.hxx>
+#include <ndole.hxx>
+#include <swwait.hxx>
+#include <viewopt.hxx>
+#include <SwCapObjType.hxx>
+#include <cmdid.h>
+#include <strings.hrc>
+#include <svx/svditer.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/prntitem.hxx>
+#include <svx/svdpage.hxx>
+#include <avmedia/mediawindow.hxx>
+#include <swcrsr.hxx>
+#include <SwRewriter.hxx>
+#include <vcl/svapp.hxx>
+#include <swserv.hxx>
+#include <fmtmeta.hxx>
+#include <itabenum.hxx>
+#include <iodetect.hxx>
+#include <unotextrange.hxx>
+#include <unoframe.hxx>
+#include <txatbase.hxx>
+#include <vcl/uitest/logger.hxx>
+#include <vcl/uitest/eventdescription.hxx>
+
+#include <vcl/GraphicNativeTransform.hxx>
+#include <vcl/GraphicNativeMetadata.hxx>
+#include <vcl/TypeSerializer.hxx>
+#include <comphelper/lok.hxx>
+#include <sfx2/classificationhelper.hxx>
+#include <sfx2/sfxdlg.hxx>
+#include <comphelper/classids.hxx>
+#include <osl/diagnose.h>
+
+#include <memory>
+
+/* default (A4 format) width of 210mm - 2 * border size (border on both sides) */
+constexpr tools::Long constOleWidthInMm = 210 - 2 * lMinBorderInMm;
+
+constexpr Size constOleSize100mm(
+ constOleWidthInMm * 100, // convert from mm to 100mm
+ 3000 // 3 cm
+);
+
+constexpr Size constOleSizeTwip = o3tl::convert(constOleSize100mm, o3tl::Length::mm100, o3tl::Length::twip);
+
+constexpr sal_uInt32 SWTRANSFER_OBJECTTYPE_DRAWMODEL = 0x00000001;
+constexpr sal_uInt32 SWTRANSFER_OBJECTTYPE_HTML = 0x00000002;
+constexpr sal_uInt32 SWTRANSFER_OBJECTTYPE_RTF = 0x00000004;
+constexpr sal_uInt32 SWTRANSFER_OBJECTTYPE_STRING = 0x00000008;
+constexpr sal_uInt32 SWTRANSFER_OBJECTTYPE_SWOLE = 0x00000010;
+constexpr sal_uInt32 SWTRANSFER_OBJECTTYPE_DDE = 0x00000020;
+constexpr sal_uInt32 SWTRANSFER_OBJECTTYPE_RICHTEXT = 0x00000040;
+
+using namespace ::svx;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::datatransfer;
+namespace {
+
+void collectUIInformation(const OUString& rAction, const OUString& aParameters)
+{
+ EventDescription aDescription;
+ aDescription.aAction = rAction;
+ aDescription.aParameters = {{"parameters", aParameters}};
+ aDescription.aID = "writer_edit";
+ aDescription.aKeyWord = "SwEditWinUIObject";
+ aDescription.aParent = "MainWindow";
+ UITestLogger::getInstance().logEvent(aDescription);
+}
+
+}
+
+class SwTransferDdeLink : public ::sfx2::SvBaseLink
+{
+ OUString m_sName;
+ ::sfx2::SvLinkSourceRef m_xRefObj;
+ SwTransferable& m_rTransfer;
+ SwDocShell* m_pDocShell;
+ sal_uLong m_nOldTimeOut;
+ bool m_bDelBookmark : 1;
+ bool m_bInDisconnect : 1;
+
+ bool FindDocShell();
+
+ using sfx2::SvBaseLink::Disconnect;
+
+protected:
+ virtual ~SwTransferDdeLink() override;
+
+public:
+ SwTransferDdeLink( SwTransferable& rTrans, SwWrtShell& rSh );
+
+ virtual ::sfx2::SvBaseLink::UpdateResult DataChanged(
+ const OUString& rMimeType, const css::uno::Any & rValue ) override;
+ virtual void Closed() override;
+
+ bool WriteData( SvStream& rStrm );
+
+ void Disconnect( bool bRemoveDataAdvise );
+};
+
+/// Tracks the boundaries of pasted content and notifies listeners.
+class SwPasteContext
+{
+public:
+ SwPasteContext(SwWrtShell& rWrtShell);
+ ~SwPasteContext();
+
+ void remember();
+ void forget();
+
+private:
+ SwWrtShell& m_rWrtShell;
+ std::optional<SwPaM> m_oPaM;
+ sal_Int32 m_nStartContent = 0;
+};
+
+namespace {
+
+// helper class for Action and Undo enclosing
+class SwTrnsfrActionAndUndo
+{
+ SwWrtShell *pSh;
+public:
+ SwTrnsfrActionAndUndo( SwWrtShell *pS, bool bDelSel = false, SwPasteContext* pContext = nullptr)
+ : pSh( pS )
+ {
+ pSh->StartUndo( SwUndoId::PASTE_CLIPBOARD );
+ if( bDelSel )
+ {
+ if (pContext)
+ pContext->forget();
+ pSh->DelRight();
+ if (pContext)
+ pContext->remember();
+ }
+ pSh->StartAllAction();
+ }
+ ~SwTrnsfrActionAndUndo() COVERITY_NOEXCEPT_FALSE
+ {
+ pSh->EndUndo();
+ pSh->EndAllAction();
+ }
+};
+
+}
+
+SwTransferable::SwTransferable( SwWrtShell& rSh )
+ : m_pWrtShell( &rSh ),
+ m_pCreatorView( nullptr ),
+ m_pOrigGraphic( nullptr ),
+ m_eBufferType( TransferBufferType::NONE ),
+ m_bOldIdle(false),
+ m_bCleanUp(false)
+{
+ rSh.GetView().AddTransferable(*this);
+ SwDocShell* pDShell = rSh.GetDoc()->GetDocShell();
+ if( !pDShell )
+ return;
+
+ pDShell->FillTransferableObjectDescriptor( m_aObjDesc );
+ if( pDShell->GetMedium() )
+ {
+ const INetURLObject& rURLObj = pDShell->GetMedium()->GetURLObject();
+ m_aObjDesc.maDisplayName = URIHelper::removePassword(
+ rURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ),
+ INetURLObject::EncodeMechanism::WasEncoded,
+ INetURLObject::DecodeMechanism::Unambiguous );
+ }
+
+ PrepareOLE( m_aObjDesc );
+}
+
+SwTransferable::~SwTransferable()
+{
+ SolarMutexGuard aSolarGuard;
+
+ // the DDELink still needs the WrtShell!
+ DisconnectDDE();
+
+ m_pWrtShell = nullptr;
+
+ // release reference to the document so that aDocShellRef will delete
+ // it (if aDocShellRef is set). Otherwise, the OLE nodes keep references
+ // to their sub-storage when the storage is already dead.
+ m_pClpDocFac.reset();
+
+ // first close, then the Ref. can be cleared as well, so that
+ // the DocShell really gets deleted!
+ if( m_aDocShellRef.Is() )
+ {
+ SfxObjectShell * pObj = m_aDocShellRef;
+ SwDocShell* pDocSh = static_cast<SwDocShell*>(pObj);
+ pDocSh->DoClose();
+ }
+ m_aDocShellRef.Clear();
+
+ SwModule* pMod = SW_MOD();
+ if(pMod)
+ {
+ if ( pMod->m_pDragDrop == this )
+ pMod->m_pDragDrop = nullptr;
+ else if ( pMod->m_pXSelection == this )
+ pMod->m_pXSelection = nullptr;
+ }
+
+ m_eBufferType = TransferBufferType::NONE;
+}
+
+static SwDoc& lcl_GetDoc(SwDocFac & rDocFac)
+{
+ SwDoc& rDoc = rDocFac.GetDoc();
+ rDoc.SetClipBoard( true );
+ return rDoc;
+}
+
+void SwTransferable::ObjectReleased()
+{
+ SwModule *pMod = SW_MOD();
+ if (!pMod)
+ return;
+ if( this == pMod->m_pDragDrop )
+ pMod->m_pDragDrop = nullptr;
+ else if( this == pMod->m_pXSelection )
+ pMod->m_pXSelection = nullptr;
+}
+
+void SwTransferable::AddSupportedFormats()
+{
+ // only need if we are the current XSelection Object
+ SwModule *pMod = SW_MOD();
+ if( this == pMod->m_pXSelection || comphelper::LibreOfficeKit::isActive())
+ {
+ SetDataForDragAndDrop( Point( 0,0) );
+ }
+}
+
+void SwTransferable::InitOle( SfxObjectShell* pDoc )
+{
+ //set OleVisArea. Upper left corner of the page and size of
+ //RealSize in Twips.
+ const Size aSz(constOleSizeTwip);
+ SwRect aVis( Point( DOCUMENTBORDER, DOCUMENTBORDER ), aSz );
+ pDoc->SetVisArea( aVis.SVRect() );
+}
+
+uno::Reference < embed::XEmbeddedObject > SwTransferable::FindOLEObj( sal_Int64& nAspect ) const
+{
+ uno::Reference < embed::XEmbeddedObject > xObj;
+ if( m_pClpDocFac )
+ {
+ SwIterator<SwContentNode,SwFormatColl> aIter( *m_pClpDocFac->GetDoc().GetDfltGrfFormatColl() );
+ for( SwContentNode* pNd = aIter.First(); pNd; pNd = aIter.Next() )
+ if( SwNodeType::Ole == pNd->GetNodeType() )
+ {
+ xObj = static_cast<SwOLENode*>(pNd)->GetOLEObj().GetOleRef();
+ nAspect = static_cast<SwOLENode*>(pNd)->GetAspect();
+ break;
+ }
+ }
+ return xObj;
+}
+
+const Graphic* SwTransferable::FindOLEReplacementGraphic() const
+{
+ if( m_pClpDocFac )
+ {
+ SwIterator<SwContentNode,SwFormatColl> aIter( *m_pClpDocFac->GetDoc().GetDfltGrfFormatColl() );
+ for( SwContentNode* pNd = aIter.First(); pNd; pNd = aIter.Next() )
+ if( SwNodeType::Ole == pNd->GetNodeType() )
+ {
+ return static_cast<SwOLENode*>(pNd)->GetGraphic();
+ }
+ }
+
+ return nullptr;
+}
+
+void SwTransferable::RemoveDDELinkFormat(vcl::Window& rWin)
+{
+ RemoveFormat( SotClipboardFormatId::LINK );
+ CopyToClipboard(&rWin);
+}
+
+void SwTransferable::DisconnectDDE()
+{
+ if( m_xDdeLink.is() )
+ {
+ m_xDdeLink->Disconnect( true );
+ m_xDdeLink.clear();
+ }
+}
+
+namespace
+{
+ //Resolves: fdo#40717 surely when we create a clipboard document we should
+ //overwrite the clipboard documents styles and settings with that of the
+ //source, so that we can WYSIWYG paste. If we want that the destinations
+ //styles are used over the source styles, that's a matter of the
+ //destination paste code to handle, not the source paste code.
+ void lclOverWriteDoc(SwWrtShell &rSrcWrtShell, SwDoc &rDest)
+ {
+ const SwDoc &rSrc = *rSrcWrtShell.GetDoc();
+
+ rDest.ReplaceCompatibilityOptions(rSrc);
+ rDest.ReplaceDefaults(rSrc);
+
+ //It would probably make most sense here to only insert the styles used
+ //by the selection, e.g. apply SwDoc::IsUsed on styles ?
+ rDest.ReplaceStyles(rSrc, false);
+
+ rSrcWrtShell.Copy(rDest);
+
+ rDest.GetMetaFieldManager().copyDocumentProperties(rSrc);
+ }
+
+ void lclCheckAndPerformRotation(Graphic& aGraphic)
+ {
+ GraphicNativeMetadata aMetadata;
+ if ( !aMetadata.read(aGraphic) )
+ return;
+
+ Degree10 aRotation = aMetadata.getRotation();
+ if (aRotation)
+ {
+ GraphicNativeTransform aTransform( aGraphic );
+ aTransform.rotate( aRotation );
+ }
+ }
+}
+
+sal_Bool SAL_CALL SwTransferable::isComplex()
+{
+ sal_Int32 nTextLength = 0;
+ SwNodes& aNodes = m_pWrtShell->GetDoc()->GetNodes();
+ for (SwPaM& rPaM : m_pWrtShell->GetCursor()->GetRingContainer())
+ {
+ for (SwNodeOffset nIndex = rPaM.GetMark()->GetNodeIndex();
+ nIndex <= rPaM.GetPoint()->GetNodeIndex(); ++nIndex)
+ {
+ SwNode& rNd = *aNodes[nIndex];
+
+ SwTextNode* pTextNode = rNd.GetTextNode();
+ if (pTextNode)
+ {
+ if (pTextNode->HasHints())
+ {
+ for (size_t nHint = 0; nHint < pTextNode->GetSwpHints().Count(); ++nHint)
+ {
+ SwTextAttr* pHint = pTextNode->GetSwpHints().Get(nHint);
+ if (pHint->Which() == RES_TXTATR_FLYCNT)
+ {
+ return true; // Complex
+ }
+ }
+ }
+
+ nTextLength += pTextNode->GetText().getLength();
+ if (nTextLength >= 1024 * 512)
+ return true; // Complex
+ }
+ }
+ }
+
+ if (m_pWrtShell->GetSelectionType() == SelectionType::DrawObject)
+ return true; // Complex
+
+ // Simple
+ return false;
+}
+
+bool SwTransferable::GetData( const DataFlavor& rFlavor, const OUString& rDestDoc )
+{
+ SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor );
+
+ // we can only fulfil the request if
+ // 1) we have data for this format
+ // 2) we have either a clipboard document (pClpDocFac), or
+ // we have a SwWrtShell (so we can generate a new clipboard document)
+ if( !HasFormat( nFormat ) || ( m_pClpDocFac == nullptr && m_pWrtShell == nullptr ) )
+ return false;
+
+ if( !m_pClpDocFac )
+ {
+ SelectionType nSelectionType = m_pWrtShell->GetSelectionType();
+
+ // when pending we will not get the correct type, but SelectionType::Text
+ // as fallback. This *happens* during D&D, so we need to check if we are in
+ // the fallback and just try to get a graphic
+ const bool bPending(m_pWrtShell->ActionPend());
+
+ // SEL_GRF is from ContentType of editsh
+ if(bPending || ((SelectionType::Graphic | SelectionType::DrawObject | SelectionType::DbForm) & nSelectionType))
+ {
+ m_oClpGraphic.emplace();
+ if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::GDIMETAFILE, *m_oClpGraphic ))
+ m_pOrigGraphic = &*m_oClpGraphic;
+ m_oClpBitmap.emplace();
+ if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::BITMAP, *m_oClpBitmap ))
+ m_pOrigGraphic = &*m_oClpBitmap;
+
+ // is it a URL-Button ?
+ OUString sURL;
+ OUString sDesc;
+ if( m_pWrtShell->GetURLFromButton( sURL, sDesc ) )
+ {
+ m_oBookmark.emplace( sURL, sDesc );
+ m_eBufferType = TransferBufferType::InetField;
+ }
+ }
+
+ m_pClpDocFac.reset(new SwDocFac);
+ SwDoc& rTmpDoc = lcl_GetDoc(*m_pClpDocFac);
+
+ rTmpDoc.getIDocumentFieldsAccess().LockExpFields(); // never update fields - leave text as it is
+ lclOverWriteDoc(*m_pWrtShell, rTmpDoc);
+
+ // in CORE a new one was created (OLE-objects copied!)
+ m_aDocShellRef = rTmpDoc.GetTmpDocShell();
+ if( m_aDocShellRef.Is() )
+ SwTransferable::InitOle( m_aDocShellRef );
+ rTmpDoc.SetTmpDocShell( nullptr );
+
+ if( nSelectionType & SelectionType::Text && !m_pWrtShell->HasMark() )
+ {
+ SwContentAtPos aContentAtPos( IsAttrAtPos::InetAttr );
+
+ Point aPos( SwEditWin::GetDDStartPosX(), SwEditWin::GetDDStartPosY());
+
+ bool bSelect = g_bExecuteDrag &&
+ m_pWrtShell->GetView().GetDocShell() &&
+ !m_pWrtShell->GetView().GetDocShell()->IsReadOnly();
+ if( m_pWrtShell->GetContentAtPos( aPos, aContentAtPos, bSelect ) )
+ {
+ m_oBookmark.emplace(
+ static_cast<const SwFormatINetFormat*>(aContentAtPos.aFnd.pAttr)->GetValue(),
+ aContentAtPos.sStr );
+ m_eBufferType = TransferBufferType::InetField;
+ if( bSelect )
+ m_pWrtShell->SelectTextAttr( RES_TXTATR_INETFMT );
+ }
+ }
+ if( m_pWrtShell->IsFrameSelected() )
+ {
+ SfxItemSetFixed<RES_URL, RES_URL> aSet( m_pWrtShell->GetAttrPool() );
+ m_pWrtShell->GetFlyFrameAttr( aSet );
+ const SwFormatURL& rURL = aSet.Get( RES_URL );
+ if( rURL.GetMap() )
+ m_pImageMap.reset(new ImageMap( *rURL.GetMap() ));
+ else if( !rURL.GetURL().isEmpty() )
+ m_pTargetURL.reset(new INetImage(OUString(), rURL.GetURL(),
+ rURL.GetTargetFrameName() ));
+ }
+ }
+
+ bool bOK = false;
+ if( TransferBufferType::Ole == m_eBufferType )
+ {
+ //TODO/MBA: testing - is this the "single OLE object" case?!
+ // get OLE-Object from ClipDoc and get the data from that.
+ sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT; // will be set in the next statement
+ uno::Reference < embed::XEmbeddedObject > xObj = FindOLEObj( nAspect );
+ const Graphic* pOLEGraph = FindOLEReplacementGraphic();
+ if( xObj.is() )
+ {
+ TransferableDataHelper aD( new SvEmbedTransferHelper( xObj, pOLEGraph, nAspect ) );
+ uno::Any aAny = aD.GetAny(rFlavor, rDestDoc);
+ if( aAny.hasValue() )
+ bOK = SetAny( aAny );
+ }
+
+ // the following solution will be used in the case when the object can not generate the image
+ // TODO/LATER: in future the transferhelper must probably be created based on object and the replacement stream
+ // TODO: Block not required now, SvEmbedTransferHelper should be able to handle GDIMetaFile format
+ if ( nFormat == SotClipboardFormatId::GDIMETAFILE )
+ {
+ pOLEGraph = FindOLEReplacementGraphic();
+ if ( pOLEGraph )
+ bOK = SetGDIMetaFile( pOLEGraph->GetGDIMetaFile() );
+ }
+ }
+ else
+ {
+ switch( nFormat )
+ {
+ case SotClipboardFormatId::LINK:
+ if( m_xDdeLink.is() )
+ bOK = SetObject( m_xDdeLink.get(), SWTRANSFER_OBJECTTYPE_DDE, rFlavor );
+ break;
+
+ case SotClipboardFormatId::OBJECTDESCRIPTOR:
+ case SotClipboardFormatId::LINKSRCDESCRIPTOR:
+ bOK = SetTransferableObjectDescriptor( m_aObjDesc );
+ break;
+
+ case SotClipboardFormatId::DRAWING:
+ {
+ SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
+ bOK = SetObject( rDoc.getIDocumentDrawModelAccess().GetDrawModel(),
+ SWTRANSFER_OBJECTTYPE_DRAWMODEL, rFlavor );
+ }
+ break;
+
+ case SotClipboardFormatId::STRING:
+ {
+ SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
+ bOK = SetObject( &rDoc, SWTRANSFER_OBJECTTYPE_STRING, rFlavor );
+ }
+ break;
+ case SotClipboardFormatId::RTF:
+ {
+ SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
+ bOK = SetObject( &rDoc, SWTRANSFER_OBJECTTYPE_RTF, rFlavor );
+ }
+ break;
+ case SotClipboardFormatId::RICHTEXT:
+ {
+ SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
+ bOK = SetObject( &rDoc, SWTRANSFER_OBJECTTYPE_RICHTEXT, rFlavor );
+ }
+ break;
+
+ case SotClipboardFormatId::HTML:
+ {
+ SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
+ bOK = SetObject( &rDoc, SWTRANSFER_OBJECTTYPE_HTML, rFlavor );
+ }
+ break;
+
+ case SotClipboardFormatId::SVXB:
+ if( m_eBufferType & TransferBufferType::Graphic && m_pOrigGraphic )
+ bOK = SetGraphic( *m_pOrigGraphic );
+ break;
+
+ case SotClipboardFormatId::GDIMETAFILE:
+ if( m_eBufferType & TransferBufferType::Graphic )
+ bOK = SetGDIMetaFile( m_oClpGraphic->GetGDIMetaFile() );
+ break;
+ case SotClipboardFormatId::BITMAP:
+ case SotClipboardFormatId::PNG:
+ // Neither pClpBitmap nor pClpGraphic are necessarily set
+ if( (m_eBufferType & TransferBufferType::Graphic) && (m_oClpBitmap || m_oClpGraphic))
+ bOK = SetBitmapEx( (m_oClpBitmap ? m_oClpBitmap : m_oClpGraphic)->GetBitmapEx(), rFlavor );
+ break;
+
+ case SotClipboardFormatId::SVIM:
+ if( m_pImageMap )
+ bOK = SetImageMap( *m_pImageMap );
+ break;
+
+ case SotClipboardFormatId::INET_IMAGE:
+ if( m_pTargetURL )
+ bOK = SetINetImage( *m_pTargetURL, rFlavor );
+ break;
+
+ case SotClipboardFormatId::SOLK:
+ case SotClipboardFormatId::NETSCAPE_BOOKMARK:
+ case SotClipboardFormatId::FILEGRPDESCRIPTOR:
+ case SotClipboardFormatId::FILECONTENT:
+ case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
+ case SotClipboardFormatId::SIMPLE_FILE:
+ if( (TransferBufferType::InetField & m_eBufferType) && m_oBookmark )
+ bOK = SetINetBookmark( *m_oBookmark, rFlavor );
+ break;
+
+ case SotClipboardFormatId::EMBED_SOURCE:
+ if( !m_aDocShellRef.Is() )
+ {
+ SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
+ SwDocShell* pNewDocSh = new SwDocShell( rDoc,
+ SfxObjectCreateMode::EMBEDDED );
+ m_aDocShellRef = pNewDocSh;
+ m_aDocShellRef->DoInitNew();
+ SwTransferable::InitOle( m_aDocShellRef );
+ }
+ bOK = SetObject( &m_aDocShellRef, SWTRANSFER_OBJECTTYPE_SWOLE,
+ rFlavor );
+ break;
+ default: break;
+ }
+ }
+ return bOK;
+}
+
+bool SwTransferable::WriteObject( tools::SvRef<SotTempStream>& xStream,
+ void* pObject, sal_uInt32 nObjectType,
+ const DataFlavor& /*rFlavor*/ )
+{
+ bool bRet = false;
+ WriterRef xWrt;
+
+ switch( nObjectType )
+ {
+ case SWTRANSFER_OBJECTTYPE_DRAWMODEL:
+ {
+ // don't change the sequence of commands
+ SdrModel *pModel = static_cast<SdrModel*>(pObject);
+ xStream->SetBufferSize( 16348 );
+
+ // for the changed pool defaults from drawing layer pool set those
+ // attributes as hard attributes to preserve them for saving
+ const SfxItemPool& rItemPool = pModel->GetItemPool();
+ const SvxFontHeightItem& rDefaultFontHeight = rItemPool.GetDefaultItem(EE_CHAR_FONTHEIGHT);
+
+ // SW should have no MasterPages
+ OSL_ENSURE(0 == pModel->GetMasterPageCount(), "SW with MasterPages (!)");
+
+ for(sal_uInt16 a(0); a < pModel->GetPageCount(); a++)
+ {
+ const SdrPage* pPage = pModel->GetPage(a);
+ SdrObjListIter aIter(pPage, SdrIterMode::DeepNoGroups);
+
+ while(aIter.IsMore())
+ {
+ SdrObject* pObj = aIter.Next();
+ const SvxFontHeightItem& rItem = pObj->GetMergedItem(EE_CHAR_FONTHEIGHT);
+
+ if(rItem.GetHeight() == rDefaultFontHeight.GetHeight())
+ {
+ pObj->SetMergedItem(rDefaultFontHeight);
+ }
+ }
+ }
+
+ {
+ uno::Reference<io::XOutputStream> xDocOut( new utl::OOutputStreamWrapper( *xStream ) );
+ SvxDrawingLayerExport( pModel, xDocOut );
+ }
+
+ bRet = ERRCODE_NONE == xStream->GetError();
+ }
+ break;
+
+ case SWTRANSFER_OBJECTTYPE_SWOLE:
+ {
+ SfxObjectShell* pEmbObj = static_cast<SfxObjectShell*>(pObject);
+ try
+ {
+ ::utl::TempFileFast aTempFile;
+ SvStream* pTempStream = aTempFile.GetStream(StreamMode::READWRITE);
+ uno::Reference< embed::XStorage > xWorkStore =
+ ::comphelper::OStorageHelper::GetStorageFromStream( new utl::OStreamWrapper(*pTempStream), embed::ElementModes::READWRITE );
+
+ // write document storage
+ pEmbObj->SetupStorage( xWorkStore, SOFFICE_FILEFORMAT_CURRENT, false );
+ // mba: no BaseURL for clipboard
+ SfxMedium aMedium( xWorkStore, OUString() );
+ pEmbObj->DoSaveObjectAs( aMedium, false );
+ pEmbObj->DoSaveCompleted();
+
+ uno::Reference< embed::XTransactedObject > xTransact( xWorkStore, uno::UNO_QUERY );
+ if ( xTransact.is() )
+ xTransact->commit();
+
+ xStream->SetBufferSize( 0xff00 );
+ xStream->WriteStream( *pTempStream );
+
+ xWorkStore->dispose();
+ xWorkStore.clear();
+ }
+ catch (const uno::Exception&)
+ {
+ }
+
+ bRet = ( xStream->GetError() == ERRCODE_NONE );
+ }
+ break;
+
+ case SWTRANSFER_OBJECTTYPE_DDE:
+ {
+ xStream->SetBufferSize( 1024 );
+ SwTransferDdeLink* pDdeLnk = static_cast<SwTransferDdeLink*>(pObject);
+ if( pDdeLnk->WriteData( *xStream ) )
+ {
+ bRet = ERRCODE_NONE == xStream->GetError();
+ }
+ }
+ break;
+
+ case SWTRANSFER_OBJECTTYPE_HTML:
+ {
+ // LOK is interested in getting images embedded for copy/paste support.
+ GetHTMLWriter( comphelper::LibreOfficeKit::isActive() ? OUString("EmbedImages;NoPrettyPrint") : OUString(), OUString(), xWrt );
+ break;
+ }
+
+ case SWTRANSFER_OBJECTTYPE_RTF:
+ case SWTRANSFER_OBJECTTYPE_RICHTEXT:
+ GetRTFWriter(std::u16string_view(), OUString(), xWrt);
+ break;
+
+ case SWTRANSFER_OBJECTTYPE_STRING:
+ GetASCWriter(std::u16string_view(), OUString(), xWrt);
+ if( xWrt.is() )
+ {
+ SwAsciiOptions aAOpt;
+ aAOpt.SetCharSet( RTL_TEXTENCODING_UTF8 );
+ xWrt->SetAsciiOptions( aAOpt );
+
+ // no start char for clipboard
+ xWrt->m_bUCS2_WithStartChar = false;
+ }
+ break;
+ default: break;
+ }
+
+ if( xWrt.is() )
+ {
+ SwDoc* pDoc = static_cast<SwDoc*>(pObject);
+ xWrt->m_bWriteClipboardDoc = true;
+ xWrt->m_bWriteOnlyFirstTable = bool(TransferBufferType::Table & m_eBufferType);
+ xWrt->SetShowProgress(false);
+
+#if defined(DEBUGPASTE)
+ SvFileStream aPasteDebug(OUString(
+ "PASTEBUFFER.debug"), StreamMode::WRITE|StreamMode::TRUNC);
+ SwWriter aDbgWrt( aPasteDebug, *pDoc );
+ aDbgWrt.Write( xWrt );
+#endif
+
+ SwWriter aWrt( *xStream, *pDoc );
+ if( ! aWrt.Write( xWrt ).IsError() )
+ {
+ xStream->WriteChar( '\0' ); // terminate with a zero
+ bRet = true;
+ }
+ }
+
+ return bRet;
+}
+
+int SwTransferable::Cut()
+{
+ int nRet = Copy( true );
+ if( nRet )
+ DeleteSelection();
+ collectUIInformation("CUT", "parameter");
+ return nRet;
+}
+
+void SwTransferable::DeleteSelection()
+{
+ if(!m_pWrtShell)
+ return;
+ // ask for type of selection before action-bracketing
+ const SelectionType nSelection = m_pWrtShell->GetSelectionType();
+ // cut rows or columns selected by enhanced table selection and wholly selected tables
+ bool bCutMode = ( SelectionType::TableCell & nSelection ) && ( (SelectionType::TableRow | SelectionType::TableCol) & nSelection ||
+ m_pWrtShell->HasWholeTabSelection() );
+
+ m_pWrtShell->StartUndo( SwUndoId::START );
+ if( bCutMode )
+ {
+ if( !(SelectionType::TableCol & nSelection) )
+ m_pWrtShell->DeleteTable();
+ else
+ {
+ SfxDispatcher* pDispatch = m_pWrtShell->GetView().GetViewFrame().GetDispatcher();
+ pDispatch->Execute(FN_TABLE_DELETE_COL, SfxCallMode::SYNCHRON);
+ }
+ }
+ else
+ {
+ if( ( SelectionType::Text | SelectionType::Table ) & nSelection )
+ m_pWrtShell->IntelligentCut( nSelection );
+ m_pWrtShell->DelRight();
+ }
+ m_pWrtShell->EndUndo( SwUndoId::END );
+}
+
+static void DeleteDDEMarks(SwDoc & rDest)
+{
+ IDocumentMarkAccess *const pMarkAccess = rDest.getIDocumentMarkAccess();
+ std::vector< ::sw::mark::IMark* > vDdeMarks;
+ // find all DDE-Bookmarks
+ for (IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->getAllMarksBegin();
+ ppMark != pMarkAccess->getAllMarksEnd();
+ ++ppMark)
+ {
+ if (IDocumentMarkAccess::MarkType::DDE_BOOKMARK == IDocumentMarkAccess::GetType(**ppMark))
+ {
+ vDdeMarks.push_back(*ppMark);
+ }
+ }
+ // remove all DDE-Bookmarks, they are invalid inside the clipdoc!
+ for (const auto& rpMark : vDdeMarks)
+ {
+ pMarkAccess->deleteMark(rpMark);
+ }
+}
+
+void SwTransferable::PrepareForCopyTextRange(SwPaM & rPaM)
+{
+ std::optional<SwWait> oWait;
+ if (m_pWrtShell->ShouldWait())
+ {
+ oWait.emplace( *m_pWrtShell->GetView().GetDocShell(), true );
+ }
+
+ m_pClpDocFac.reset(new SwDocFac);
+
+ SwDoc& rDest(lcl_GetDoc(*m_pClpDocFac));
+ rDest.getIDocumentFieldsAccess().LockExpFields(); // Never update fields - leave text as is
+ {
+ SwDoc const& rSrc(*m_pWrtShell->GetDoc());
+ assert(&rSrc == &rPaM.GetDoc());
+
+ rDest.ReplaceCompatibilityOptions(rSrc);
+ rDest.ReplaceDefaults(rSrc);
+
+ //It would probably make most sense here to only insert the styles used
+ //by the selection, e.g. apply SwDoc::IsUsed on styles ?
+ rDest.ReplaceStyles(rSrc, false);
+
+ // relevant bits of rSrcWrtShell.Copy(rDest);
+ rDest.GetIDocumentUndoRedo().DoUndo(false); // always false!
+ rDest.getIDocumentRedlineAccess().SetRedlineFlags_intern( RedlineFlags::DeleteRedlines );
+
+ SwNodeIndex const aIdx(rDest.GetNodes().GetEndOfContent(), -1);
+ SwContentNode *const pContentNode(aIdx.GetNode().GetContentNode());
+ SwPosition aPos(aIdx, pContentNode, pContentNode ? pContentNode->Len() : 0);
+
+ rSrc.getIDocumentContentOperations().CopyRange(rPaM, aPos, SwCopyFlags::CheckPosInFly);
+
+ rDest.getIDocumentRedlineAccess().SetRedlineFlags_intern( RedlineFlags::NONE );
+
+ rDest.GetMetaFieldManager().copyDocumentProperties(rSrc);
+ }
+
+ DeleteDDEMarks(rDest);
+
+ // a new one was created in core (OLE objects copied!)
+ m_aDocShellRef = rDest.GetTmpDocShell();
+ if (m_aDocShellRef.Is())
+ SwTransferable::InitOle( m_aDocShellRef );
+ rDest.SetTmpDocShell( nullptr );
+
+ // let's add some formats
+ AddFormat( SotClipboardFormatId::EMBED_SOURCE );
+ AddFormat( SotClipboardFormatId::RTF );
+#if HAVE_FEATURE_DESKTOP
+ AddFormat( SotClipboardFormatId::RICHTEXT );
+ AddFormat( SotClipboardFormatId::HTML );
+#endif
+ AddFormat( SotClipboardFormatId::STRING );
+}
+
+int SwTransferable::PrepareForCopy( bool bIsCut )
+{
+ int nRet = 1;
+ if(!m_pWrtShell)
+ return 0;
+
+ 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 )
+ {
+ m_oClpGraphic.emplace();
+ if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::GDIMETAFILE, *m_oClpGraphic ))
+ m_pOrigGraphic = &*m_oClpGraphic;
+ m_oClpBitmap.emplace();
+ if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::BITMAP, *m_oClpBitmap ))
+ m_pOrigGraphic = &*m_oClpBitmap;
+
+ m_pClpDocFac.reset(new SwDocFac);
+ SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
+ m_pWrtShell->Copy(rDoc);
+
+#if HAVE_FEATURE_DESKTOP
+ if (m_pOrigGraphic && !m_pOrigGraphic->GetBitmapEx().IsEmpty())
+ AddFormat( SotClipboardFormatId::SVXB );
+#endif
+
+ PrepareOLE( m_aObjDesc );
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+
+ const Graphic* pGrf = m_pWrtShell->GetGraphic();
+ if( pGrf && pGrf->IsSupportedGraphic() )
+ {
+ AddFormat( SotClipboardFormatId::PNG );
+#if HAVE_FEATURE_DESKTOP
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ AddFormat( SotClipboardFormatId::BITMAP );
+#endif
+ }
+ m_eBufferType = TransferBufferType::Graphic;
+ m_pWrtShell->GetGrfNms( &sGrfNm, nullptr );
+ }
+ else if ( nSelection == SelectionType::Ole )
+ {
+ m_pClpDocFac.reset(new SwDocFac);
+ SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
+ m_aDocShellRef = new SwDocShell(rDoc, SfxObjectCreateMode::EMBEDDED);
+ m_aDocShellRef->DoInitNew();
+ m_pWrtShell->Copy(rDoc);
+
+ AddFormat( SotClipboardFormatId::EMBED_SOURCE );
+
+ // --> OD #i98753#
+ // set size of embedded object at the object description structure
+ m_aObjDesc.maSize = o3tl::convert(m_pWrtShell->GetObjSize(), o3tl::Length::twip, o3tl::Length::mm100);
+
+ // <--
+ PrepareOLE( m_aObjDesc );
+
+#if HAVE_FEATURE_DESKTOP
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+
+ // Fetch the formats supported via embedtransferhelper as well
+ sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT;
+ uno::Reference < embed::XEmbeddedObject > xObj = FindOLEObj( nAspect );
+ const Graphic* pOLEGraph = FindOLEReplacementGraphic();
+ if( xObj.is() )
+ {
+ TransferableDataHelper aD( new SvEmbedTransferHelper( xObj, pOLEGraph, nAspect ) );
+ if ( aD.GetTransferable().is() )
+ {
+ DataFlavorExVector aVector( aD.GetDataFlavorExVector() );
+
+ for( const auto& rItem : aVector )
+ AddFormat( rItem );
+ }
+ }
+#endif
+ m_eBufferType = TransferBufferType::Ole;
+ }
+ // Is there anything to provide anyway?
+ else if ( m_pWrtShell->IsSelection() || m_pWrtShell->IsFrameSelected() ||
+ m_pWrtShell->IsObjSelected() )
+ {
+ std::optional<SwWait> oWait;
+ if( m_pWrtShell->ShouldWait() )
+ oWait.emplace( *m_pWrtShell->GetView().GetDocShell(), true );
+
+ m_pClpDocFac.reset(new SwDocFac);
+
+ // create additional cursor so that equal treatment of keyboard
+ // and mouse selection is possible.
+ // In AddMode with keyboard selection, the new cursor is not created
+ // before the cursor is moved after end of selection.
+ if( m_pWrtShell->IsAddMode() && m_pWrtShell->SwCursorShell::HasSelection() )
+ m_pWrtShell->CreateCursor();
+
+ SwDoc& rTmpDoc = lcl_GetDoc(*m_pClpDocFac);
+
+ rTmpDoc.getIDocumentFieldsAccess().LockExpFields(); // Never update fields - leave text as is
+ lclOverWriteDoc(*m_pWrtShell, rTmpDoc);
+
+ DeleteDDEMarks(rTmpDoc);
+
+ // a new one was created in CORE (OLE objects copied!)
+ m_aDocShellRef = rTmpDoc.GetTmpDocShell();
+ if( m_aDocShellRef.Is() )
+ SwTransferable::InitOle( m_aDocShellRef );
+ rTmpDoc.SetTmpDocShell( nullptr );
+
+ if( m_pWrtShell->IsObjSelected() )
+ m_eBufferType = TransferBufferType::Drawing;
+ else
+ {
+ m_eBufferType = TransferBufferType::Document;
+ if (m_pWrtShell->IntelligentCut(nSelection, false) != SwWrtShell::NO_WORD)
+ m_eBufferType = TransferBufferType::DocumentWord | m_eBufferType;
+ }
+
+ bool bDDELink = m_pWrtShell->IsSelection();
+ if( nSelection & SelectionType::TableCell )
+ {
+ 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 );
+ }
+
+#if HAVE_FEATURE_DESKTOP
+ //When someone needs it, we 'OLE' him something
+ AddFormat( SotClipboardFormatId::EMBED_SOURCE );
+#endif
+
+ //put RTF ahead of the OLE's Metafile to have less loss
+ if( !m_pWrtShell->IsObjSelected() )
+ {
+ AddFormat( SotClipboardFormatId::RTF );
+#if HAVE_FEATURE_DESKTOP
+ AddFormat( SotClipboardFormatId::RICHTEXT );
+ AddFormat( SotClipboardFormatId::HTML );
+#endif
+ }
+ if( m_pWrtShell->IsSelection() )
+ AddFormat( SotClipboardFormatId::STRING );
+
+ if( nSelection & ( SelectionType::DrawObject | SelectionType::DbForm ))
+ {
+ AddFormat( SotClipboardFormatId::DRAWING );
+ if ( nSelection & SelectionType::DrawObject )
+ {
+#if HAVE_FEATURE_DESKTOP
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ AddFormat( SotClipboardFormatId::BITMAP );
+#endif
+ AddFormat( SotClipboardFormatId::PNG );
+ }
+ m_eBufferType = static_cast<TransferBufferType>( TransferBufferType::Graphic | m_eBufferType );
+
+ m_oClpGraphic.emplace();
+ if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::GDIMETAFILE, *m_oClpGraphic ))
+ m_pOrigGraphic = &*m_oClpGraphic;
+ m_oClpBitmap.emplace();
+ if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::BITMAP, *m_oClpBitmap ))
+ m_pOrigGraphic = &*m_oClpBitmap;
+
+ // is it a URL-Button ?
+ OUString sURL;
+ OUString sDesc;
+ if( m_pWrtShell->GetURLFromButton( sURL, sDesc ) )
+ {
+ AddFormat( SotClipboardFormatId::STRING );
+#if HAVE_FEATURE_DESKTOP
+ AddFormat( SotClipboardFormatId::SOLK );
+ AddFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK );
+ AddFormat( SotClipboardFormatId::FILECONTENT );
+ AddFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR );
+#endif
+ AddFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR );
+ m_eBufferType = TransferBufferType::InetField | m_eBufferType;
+ nRet = 1;
+ }
+ }
+
+ // at Cut, DDE-Link doesn't make sense!!
+ SwDocShell* pDShell;
+ if( !bIsCut && bDDELink &&
+ nullptr != ( pDShell = m_pWrtShell->GetDoc()->GetDocShell()) &&
+ SfxObjectCreateMode::STANDARD == pDShell->GetCreateMode() )
+ {
+#if HAVE_FEATURE_DESKTOP
+ AddFormat( SotClipboardFormatId::LINK );
+#endif
+ m_xDdeLink = new SwTransferDdeLink( *this, *m_pWrtShell );
+ }
+
+ //ObjectDescriptor was already filly from the old DocShell.
+ //Now adjust it. Thus in GetData the first query can still
+ //be answered with delayed rendering.
+ m_aObjDesc.maSize = constOleSize100mm;
+
+ PrepareOLE( m_aObjDesc );
+#if HAVE_FEATURE_DESKTOP
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+#endif
+ }
+ else
+ nRet = 0;
+
+ if( m_pWrtShell->IsFrameSelected() )
+ {
+ SfxItemSetFixed<RES_URL, RES_URL> aSet( m_pWrtShell->GetAttrPool() );
+ m_pWrtShell->GetFlyFrameAttr( aSet );
+ const SwFormatURL& rURL = aSet.Get( RES_URL );
+ if( rURL.GetMap() )
+ {
+ m_pImageMap.reset( new ImageMap( *rURL.GetMap() ) );
+ AddFormat( SotClipboardFormatId::SVIM );
+ }
+ else if( !rURL.GetURL().isEmpty() )
+ {
+ m_pTargetURL.reset(new INetImage( sGrfNm, rURL.GetURL(),
+ rURL.GetTargetFrameName() ));
+ AddFormat( SotClipboardFormatId::INET_IMAGE );
+ }
+ }
+
+ return nRet;
+}
+
+int SwTransferable::Copy( bool bIsCut )
+{
+ if (m_pWrtShell->GetView().GetObjectShell()->isContentExtractionLocked())
+ return 0;
+
+ int nRet = PrepareForCopy( bIsCut );
+ if ( nRet )
+ {
+ CopyToClipboard( &m_pWrtShell->GetView().GetEditWin() );
+ }
+
+ if( !bIsCut ){
+ collectUIInformation("COPY", "parameter");
+ }
+
+ return nRet;
+}
+
+void SwTransferable::CalculateAndCopy()
+{
+ if(!m_pWrtShell)
+ return;
+ SwWait aWait( *m_pWrtShell->GetView().GetDocShell(), true );
+
+ OUString aStr( m_pWrtShell->Calculate() );
+
+ m_pClpDocFac.reset(new SwDocFac);
+ SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
+ m_pWrtShell->Copy(rDoc, &aStr);
+ m_eBufferType = TransferBufferType::Document;
+ AddFormat( SotClipboardFormatId::STRING );
+
+ CopyToClipboard( &m_pWrtShell->GetView().GetEditWin() );
+}
+
+bool SwTransferable::CopyGlossary( SwTextBlocks& rGlossary, const OUString& rStr )
+{
+ if(!m_pWrtShell)
+ return false;
+ SwWait aWait( *m_pWrtShell->GetView().GetDocShell(), true );
+
+ m_pClpDocFac.reset(new SwDocFac);
+ SwDoc& rCDoc = lcl_GetDoc(*m_pClpDocFac);
+
+ SwNodes& rNds = rCDoc.GetNodes();
+ SwNodeIndex aNodeIdx( *rNds.GetEndOfContent().StartOfSectionNode() );
+ SwContentNode* pCNd = rNds.GoNext( &aNodeIdx ); // go to 1st ContentNode
+ SwPaM aPam( *pCNd );
+
+ rCDoc.getIDocumentFieldsAccess().LockExpFields(); // never update fields - leave text as it is
+
+ rCDoc.InsertGlossary( rGlossary, rStr, aPam );
+
+ // a new one was created in CORE (OLE-Objects copied!)
+ m_aDocShellRef = rCDoc.GetTmpDocShell();
+ if( m_aDocShellRef.Is() )
+ SwTransferable::InitOle( m_aDocShellRef );
+ rCDoc.SetTmpDocShell( nullptr );
+
+ m_eBufferType = TransferBufferType::Document;
+
+ //When someone needs it, we 'OLE' her something.
+ AddFormat( SotClipboardFormatId::EMBED_SOURCE );
+ AddFormat( SotClipboardFormatId::RTF );
+ AddFormat( SotClipboardFormatId::RICHTEXT );
+ AddFormat( SotClipboardFormatId::HTML );
+ AddFormat( SotClipboardFormatId::STRING );
+
+ //ObjectDescriptor was already filled from the old DocShell.
+ //Now adjust it. Thus in GetData the first query can still
+ //be answered with delayed rendering.
+ m_aObjDesc.maSize = constOleSize100mm;
+
+ PrepareOLE( m_aObjDesc );
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+
+ CopyToClipboard( &m_pWrtShell->GetView().GetEditWin() );
+
+ return true;
+}
+
+static uno::Reference < XTransferable > * lcl_getTransferPointer ( uno::Reference < XTransferable > &xRef )
+{
+ return &xRef;
+}
+
+SwPasteContext::SwPasteContext(SwWrtShell& rWrtShell)
+ : m_rWrtShell(rWrtShell)
+{
+ remember();
+}
+
+void SwPasteContext::remember()
+{
+ if (m_rWrtShell.GetPasteListeners().getLength() == 0)
+ return;
+
+ SwPaM* pCursor = m_rWrtShell.GetCursor();
+ if (!pCursor)
+ return;
+
+ // Set point to the previous node, so it is not moved.
+ const SwNode& rNode = pCursor->GetPoint()->GetNode();
+ m_oPaM.emplace(rNode, rNode, SwNodeOffset(0), SwNodeOffset(-1));
+ m_nStartContent = pCursor->GetPoint()->GetContentIndex();
+}
+
+void SwPasteContext::forget() { m_oPaM.reset(); }
+
+SwPasteContext::~SwPasteContext()
+{
+ try
+ {
+ if (m_rWrtShell.GetPasteListeners().getLength() == 0)
+ return;
+
+ beans::PropertyValue aPropertyValue;
+
+ switch (m_rWrtShell.GetView().GetShellMode())
+ {
+ case ShellMode::Graphic:
+ {
+ SwFrameFormat* pFormat = m_rWrtShell.GetFlyFrameFormat();
+ if (!pFormat)
+ return;
+
+ aPropertyValue.Name = "TextGraphicObject";
+ aPropertyValue.Value
+ <<= uno::Reference<text::XTextContent>(SwXTextGraphicObject::CreateXTextGraphicObject(*pFormat->GetDoc(), pFormat));
+ break;
+ }
+
+ default:
+ {
+ if (!m_oPaM)
+ return;
+
+ SwPaM* pCursor = m_rWrtShell.GetCursor();
+ if (!pCursor)
+ return;
+
+ if (!pCursor->GetPoint()->GetNode().IsTextNode())
+ // Non-text was pasted.
+ return;
+
+ // Update mark after paste.
+ *m_oPaM->GetMark() = *pCursor->GetPoint();
+
+ // Restore point.
+ m_oPaM->GetPoint()->Adjust(SwNodeOffset(1));
+ SwNode& rNode = m_oPaM->GetPointNode();
+ if (!rNode.IsTextNode())
+ // Starting point is no longer text.
+ return;
+
+ m_oPaM->GetPoint()->SetContent(m_nStartContent);
+
+ aPropertyValue.Name = "TextRange";
+ const rtl::Reference<SwXTextRange> xTextRange = SwXTextRange::CreateXTextRange(
+ m_oPaM->GetDoc(), *m_oPaM->GetPoint(), m_oPaM->GetMark());
+ aPropertyValue.Value <<= uno::Reference<text::XTextRange>(xTextRange);
+ break;
+ }
+ }
+
+ if (aPropertyValue.Name.isEmpty())
+ return;
+
+ // Invoke the listeners.
+ uno::Sequence<beans::PropertyValue> aEvent{ aPropertyValue };
+ m_rWrtShell.GetPasteListeners().notifyEach( &css::text::XPasteListener::notifyPasteEvent, aEvent );
+ }
+ catch (const uno::Exception& rException)
+ {
+ SAL_WARN("sw",
+ "SwPasteContext::~SwPasteContext: uncaught exception: " << rException.Message);
+ }
+}
+
+bool SwTransferable::IsPaste( const SwWrtShell& rSh,
+ const TransferableDataHelper& rData )
+{
+ // Check the common case first: We can always paste our own data!
+ // If _only_ the internal format can be pasted, this check will
+ // yield 'true', while the one below would give a (wrong) result 'false'.
+
+ bool bIsPaste = ( GetSwTransferable( rData ) != nullptr );
+
+ // if it's not our own data, we need to have a closer look:
+ if( ! bIsPaste )
+ {
+ // determine the proper paste action, and return true if we find one
+ uno::Reference<XTransferable> xTransferable( rData.GetXTransferable() );
+
+ SotExchangeDest nDestination = SwTransferable::GetSotDestination( rSh );
+ sal_uInt16 nSourceOptions =
+ (( SotExchangeDest::DOC_TEXTFRAME == nDestination ||
+ SotExchangeDest::SWDOC_FREE_AREA == nDestination ||
+ SotExchangeDest::DOC_TEXTFRAME_WEB == nDestination ||
+ SotExchangeDest::SWDOC_FREE_AREA_WEB == nDestination )
+ ? EXCHG_IN_ACTION_COPY
+ : EXCHG_IN_ACTION_MOVE);
+
+ SotClipboardFormatId nFormat; // output param for GetExchangeAction
+ sal_uInt8 nEventAction; // output param for GetExchangeAction
+ sal_uInt8 nAction = SotExchange::GetExchangeAction(
+ rData.GetDataFlavorExVector(),
+ nDestination,
+ nSourceOptions, /* ?? */
+ EXCHG_IN_ACTION_DEFAULT, /* ?? */
+ nFormat, nEventAction, SotClipboardFormatId::NONE,
+ lcl_getTransferPointer ( xTransferable ) );
+
+ // if we find a suitable action, we can paste!
+ bIsPaste = (EXCHG_INOUT_ACTION_NONE != nAction);
+ }
+
+ return bIsPaste;
+}
+
+void SwTransferable::SelectPasteFormat(TransferableDataHelper& rData, sal_uInt8& nAction,
+ SotClipboardFormatId& nFormat)
+{
+ if (nFormat != SotClipboardFormatId::RICHTEXT)
+ {
+ return;
+ }
+
+ if (!rData.HasFormat(SotClipboardFormatId::EMBED_SOURCE))
+ {
+ return;
+ }
+
+ if (!rData.HasFormat(SotClipboardFormatId::OBJECTDESCRIPTOR))
+ {
+ return;
+ }
+
+ TransferableObjectDescriptor aObjDesc;
+ if (!rData.GetTransferableObjectDescriptor(SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDesc))
+ {
+ return;
+ }
+
+ if (aObjDesc.maClassName != SvGlobalName(SO3_SW_CLASSID))
+ {
+ return;
+ }
+
+ // At this point we know that we paste from Writer to Writer and the clipboard has the content
+ // in both RTF and ODF formats. Prefer ODF in this case.
+ nAction = EXCHG_OUT_ACTION_INSERT_OLE;
+ nFormat = SotClipboardFormatId::EMBED_SOURCE;
+}
+
+// get HTML indentation level by counting tabulator characters before the index
+// (also index value -1 returns with 0)
+static sal_Int32 lcl_getLevel(OUString& sText, sal_Int32 nIdx)
+{
+ sal_Int32 nRet = 0;
+ while ( nIdx-- > 0 && sText[nIdx] == '\t' )
+ {
+ nRet++;
+ }
+ return nRet;
+}
+
+bool SwTransferable::Paste(SwWrtShell& rSh, TransferableDataHelper& rData, RndStdIds nAnchorType, bool bIgnoreComments, PasteTableType ePasteTable)
+{
+ SwPasteContext aPasteContext(rSh);
+
+ sal_uInt8 nAction=0;
+ SotExchangeDest nDestination = SwTransferable::GetSotDestination( rSh );
+ SotClipboardFormatId nFormat = SotClipboardFormatId::NONE;
+ SotExchangeActionFlags nActionFlags = SotExchangeActionFlags::NONE;
+ bool bSingleCellTable = false;
+
+ if( GetSwTransferable( rData ) )
+ {
+ nAction = EXCHG_OUT_ACTION_INSERT_PRIVATE;
+ }
+ else
+ {
+ sal_uInt16 nSourceOptions =
+ (( SotExchangeDest::DOC_TEXTFRAME == nDestination ||
+ SotExchangeDest::SWDOC_FREE_AREA == nDestination ||
+ SotExchangeDest::DOC_TEXTFRAME_WEB == nDestination ||
+ SotExchangeDest::SWDOC_FREE_AREA_WEB == nDestination )
+ ? EXCHG_IN_ACTION_COPY
+ : EXCHG_IN_ACTION_MOVE);
+ uno::Reference<XTransferable> xTransferable( rData.GetXTransferable() );
+ sal_uInt8 nEventAction;
+ nAction = SotExchange::GetExchangeAction(
+ rData.GetDataFlavorExVector(),
+ nDestination,
+ nSourceOptions, /* ?? */
+ EXCHG_IN_ACTION_DEFAULT, /* ?? */
+ nFormat, nEventAction, SotClipboardFormatId::NONE,
+ lcl_getTransferPointer ( xTransferable ),
+ &nActionFlags );
+ }
+
+ // when HTML is just an image don't generate new section
+ if (rData.HasFormat(SotClipboardFormatId::HTML_SIMPLE) && rData.HasFormat(SotClipboardFormatId::HTML_NO_COMMENT)
+ && rData.HasFormat(SotClipboardFormatId::BITMAP) && nFormat == SotClipboardFormatId::FILE_LIST)
+ nFormat = SotClipboardFormatId::BITMAP;
+
+ // tdf#37223 avoid non-native insertion of Calc worksheets in the following cases:
+ // content of 1-cell worksheets are inserted as simple text using RTF format,
+ // bigger worksheets within native (Writer) table cells are inserted as native tables,
+ // ie. cell by cell instead of embedding the worksheet in a single cell of the Writer table
+ if ( EXCHG_IN_ACTION_COPY == nAction && ( rData.HasFormat( SotClipboardFormatId::SYLK ) ||
+ rData.HasFormat( SotClipboardFormatId::SYLK_BIGCAPS ) ) )
+ {
+ // is it a 1-cell worksheet?
+ OUString aExpand;
+ if( rData.GetString( SotClipboardFormatId::STRING, aExpand ))
+ {
+ const sal_Int32 nNewlines{comphelper::string::getTokenCount(aExpand, '\n')};
+ const sal_Int32 nRows = nNewlines ? nNewlines-1 : 0;
+ if ( nRows == 1 )
+ {
+ const sal_Int32 nCols = comphelper::string::getTokenCount(o3tl::getToken(aExpand, 0, '\n'), '\t');
+ if (nCols == 1)
+ bSingleCellTable = true;
+ }
+ }
+
+ // convert the worksheet to a temporary native table using HTML format, and copy that into the original native table
+ if (!bSingleCellTable && rData.HasFormat( SotClipboardFormatId::HTML ) &&
+ SwDoc::IsInTable(rSh.GetCursor()->GetPointNode()) != nullptr && rSh.DoesUndo())
+ {
+ SfxDispatcher* pDispatch = rSh.GetView().GetViewFrame().GetDispatcher();
+ sal_uInt32 nLevel = 0;
+
+ // within Writer table cells, inserting worksheets using HTML format results only plain text, not a native table,
+ // so remove all outer nested tables temporary to get a working insertion point
+ // (RTF format has no such problem, but that inserts the hidden rows of the original Calc worksheet, too)
+
+ // For this, switch off change tracking temporarily, if needed
+ RedlineFlags eOld = rSh.GetDoc()->getIDocumentRedlineAccess().GetRedlineFlags();
+ if ( eOld & RedlineFlags::On )
+ rSh.GetDoc()->getIDocumentRedlineAccess().SetRedlineFlags( eOld & ~RedlineFlags::On );
+
+ OUString sPreviousTableName;
+ do
+ {
+ // tdf#152245 add a limit to the loop, if it's not possible to delete the table
+ const SwTableNode* pNode = rSh.GetCursor()->GetPointNode().FindTableNode();
+ const OUString sTableName = pNode->GetTable().GetFrameFormat()->GetName();
+ if ( sTableName == sPreviousTableName )
+ break;
+ sPreviousTableName = sTableName;
+ // insert a random character to redo the place of the insertion at the end
+ pDispatch->Execute(FN_INSERT_NNBSP, SfxCallMode::SYNCHRON);
+ pDispatch->Execute(FN_TABLE_DELETE_TABLE, SfxCallMode::SYNCHRON);
+ nLevel++;
+ } while (SwDoc::IsInTable(rSh.GetCursor()->GetPointNode()) != nullptr);
+
+ // restore change tracking settings
+ if ( eOld & RedlineFlags::On )
+ rSh.GetDoc()->getIDocumentRedlineAccess().SetRedlineFlags( eOld );
+
+ if ( SwTransferable::PasteData( rData, rSh, EXCHG_OUT_ACTION_INSERT_STRING, nActionFlags, SotClipboardFormatId::HTML,
+ nDestination, false, false, nullptr, 0, false, nAnchorType, bIgnoreComments, &aPasteContext, ePasteTable) )
+ {
+ bool bFoundTemporaryTable = false;
+ pDispatch->Execute(FN_LINE_UP, SfxCallMode::SYNCHRON);
+ if (SwDoc::IsInTable(rSh.GetCursor()->GetPointNode()) != nullptr)
+ {
+ bFoundTemporaryTable = true;
+ 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);
+ // clipboard content hasn't changed (limit potential infinite
+ // recursion with the same non-native table, as was in tdf#138688)
+ if (!bFoundTemporaryTable)
+ return false;
+ if (ePasteTable == PasteTableType::PASTE_TABLE)
+ pDispatch->Execute(FN_PASTE_NESTED_TABLE, SfxCallMode::SYNCHRON);
+ else if (ePasteTable == PasteTableType::PASTE_ROW)
+ pDispatch->Execute(FN_TABLE_PASTE_ROW_BEFORE, SfxCallMode::SYNCHRON);
+ else if (ePasteTable == PasteTableType::PASTE_COLUMN)
+ pDispatch->Execute(FN_TABLE_PASTE_COL_BEFORE, SfxCallMode::SYNCHRON);
+ else
+ pDispatch->Execute(SID_PASTE, SfxCallMode::SYNCHRON);
+ return true;
+ } else {
+ for(sal_uInt32 a = 0; a < (nLevel * 2); a++)
+ pDispatch->Execute(SID_UNDO, SfxCallMode::SYNCHRON);
+ }
+ }
+ }
+ // insert clipboard content as new table rows/columns before the actual row/column instead of overwriting it
+ else if ( (rSh.GetTableInsertMode() != SwTable::SEARCH_NONE || ePasteTable == PasteTableType::PASTE_ROW || ePasteTable == PasteTableType::PASTE_COLUMN) &&
+ rData.HasFormat( SotClipboardFormatId::HTML ) &&
+ SwDoc::IsInTable(rSh.GetCursor()->GetPointNode()) != nullptr )
+ {
+ OUString aExpand;
+ sal_Int32 nIdx;
+ bool bRowMode = rSh.GetTableInsertMode() == SwTable::SEARCH_ROW || ePasteTable == PasteTableType::PASTE_ROW;
+ if( rData.GetString( SotClipboardFormatId::HTML, aExpand ) && (nIdx = aExpand.indexOf("<table")) > -1 )
+ {
+ // calculate table row/column count by analysing indentation of the HTML table extract
+
+ // calculate indentation level of <table>, which is the base of the next calculations
+ // (tdf#148791 table alignment can enlarge it using first level <center>, <div> or <dl>)
+ sal_Int32 nTableLevel = lcl_getLevel(aExpand, nIdx);
+ // table rows repeated heading use extra indentation, too:
+ // <thead> is always used here, and the first table with <thead> is not nested,
+ // if its indentation level is greater only by 1, than indentation level of the table
+ bool bShifted = lcl_getLevel(aExpand, aExpand.indexOf("<thead")) == nTableLevel + 1;
+ // calculate count of selected rows or columns
+ sal_Int32 nSelectedRowsOrCols = 0;
+ const OUString sSearchRowOrCol = bRowMode ? OUString("</tr>") : OUString("<col ");
+ while((nIdx = aExpand.indexOf(sSearchRowOrCol, nIdx)) > -1)
+ {
+ // skip rows/columns of nested tables, based on HTML indentation
+ if ( lcl_getLevel(aExpand, nIdx) == nTableLevel + (bShifted ? 2 : 1) &&
+ // skip also strange hidden empty rows <tr></tr>
+ !aExpand.match("<tr></tr>", nIdx - 4) )
+ {
+ ++nSelectedRowsOrCols;
+ }
+ ++nIdx;
+ }
+ // are we at the beginning of the cell?
+ bool bStartTableBoxNode =
+ // first paragraph of the cell?
+ rSh.GetCursor()->GetPointNode().GetIndex() == rSh.GetCursor()->GetPointNode().FindTableBoxStartNode()->GetIndex()+1 &&
+ // beginning of the paragraph?
+ !rSh.GetCursor()->GetPoint()->GetContentIndex();
+ SfxDispatcher* pDispatch = rSh.GetView().GetViewFrame().GetDispatcher();
+
+ // go start of the cell
+ if (!bStartTableBoxNode)
+ pDispatch->Execute(FN_START_OF_DOCUMENT, SfxCallMode::SYNCHRON);
+
+ // store cursor position in row mode
+ ::sw::mark::IMark* pMark = (!bRowMode || nSelectedRowsOrCols == 0) ? nullptr : rSh.SetBookmark(
+ vcl::KeyCode(),
+ OUString(),
+ IDocumentMarkAccess::MarkType::UNO_BOOKMARK );
+
+ // add a new empty row/column before the actual table row/column and go there
+ const sal_uInt16 nDispatchSlot = bRowMode ? FN_TABLE_INSERT_ROW_BEFORE : FN_TABLE_INSERT_COL_BEFORE;
+ pDispatch->Execute(nDispatchSlot, SfxCallMode::SYNCHRON);
+ pDispatch->Execute(bRowMode ? FN_LINE_UP : FN_CHAR_LEFT, SfxCallMode::SYNCHRON);
+
+ // add the other new empty rows/columns after the actual table row/column
+ if ( nSelectedRowsOrCols > 1 )
+ {
+ SfxInt16Item aCountItem( nDispatchSlot, nSelectedRowsOrCols-1 );
+ SfxBoolItem aAfter( FN_PARAM_INSERT_AFTER, true );
+ pDispatch->ExecuteList(nDispatchSlot,
+ SfxCallMode::SYNCHRON|SfxCallMode::RECORD,
+ { &aCountItem, &aAfter });
+ }
+
+ // paste rows
+ bool bResult = SwTransferable::PasteData( rData, rSh, nAction, nActionFlags, nFormat,
+ nDestination, false, false, nullptr, 0, false, nAnchorType, bIgnoreComments, &aPasteContext );
+
+ // restore cursor position
+ if (pMark != nullptr)
+ {
+ rSh.GotoMark( pMark );
+ rSh.getIDocumentMarkAccess()->deleteMark( pMark );
+ }
+
+ return bResult;
+ }
+ }
+
+ // special case for tables from draw application or 1-cell tables
+ if( EXCHG_OUT_ACTION_INSERT_DRAWOBJ == nAction || bSingleCellTable )
+ {
+ if( rData.HasFormat( SotClipboardFormatId::RTF ) )
+ {
+ nAction = EXCHG_OUT_ACTION_INSERT_STRING;
+ nFormat = SotClipboardFormatId::RTF;
+ }
+ else if( rData.HasFormat( SotClipboardFormatId::RICHTEXT ) )
+ {
+ nAction = EXCHG_OUT_ACTION_INSERT_STRING;
+ nFormat = SotClipboardFormatId::RICHTEXT;
+ }
+ }
+
+ // Tweak the format if necessary: the source application can be considered in this context,
+ // while not in sot/ code.
+ SwTransferable::SelectPasteFormat(rData, nAction, nFormat);
+
+ collectUIInformation("PASTE", "parameter");
+
+ return EXCHG_INOUT_ACTION_NONE != nAction &&
+ SwTransferable::PasteData( rData, rSh, nAction, nActionFlags, nFormat,
+ nDestination, false, false, nullptr, 0, false, nAnchorType, bIgnoreComments, &aPasteContext, ePasteTable);
+}
+
+bool SwTransferable::PasteData( TransferableDataHelper& rData,
+ SwWrtShell& rSh, sal_uInt8 nAction, SotExchangeActionFlags nActionFlags,
+ SotClipboardFormatId nFormat,
+ SotExchangeDest nDestination, bool bIsPasteFormat,
+ bool bIsDefault,
+ const Point* pPt, sal_Int8 nDropAction,
+ bool bPasteSelection, RndStdIds nAnchorType,
+ bool bIgnoreComments,
+ SwPasteContext* pContext,
+ PasteTableType ePasteTable )
+{
+ SwWait aWait( *rSh.GetView().GetDocShell(), false );
+ std::unique_ptr<SwTrnsfrActionAndUndo, o3tl::default_delete<SwTrnsfrActionAndUndo>> pAction;
+ SwModule* pMod = SW_MOD();
+
+ bool bRet = false;
+ bool bCallAutoCaption = false;
+
+ if( pPt )
+ {
+ // external Drop
+ if ((bPasteSelection ? !pMod->m_pXSelection : !pMod->m_pDragDrop) &&
+ // The following condition is used for tdf#156111 to prevent a selection from being
+ // cleared by the default case of the nDestination switch.
+ !(rSh.GetCursorCnt() == 1 && rSh.TestCurrPam(*pPt) &&
+ nDestination == SotExchangeDest::SWDOC_FREE_AREA &&
+ nFormat == SotClipboardFormatId::SONLK))
+ {
+ switch( nDestination )
+ {
+ case SotExchangeDest::DOC_LNKD_GRAPH_W_IMAP:
+ case SotExchangeDest::DOC_LNKD_GRAPHOBJ:
+ case SotExchangeDest::DOC_GRAPH_W_IMAP:
+ case SotExchangeDest::DOC_GRAPHOBJ:
+ case SotExchangeDest::DOC_OLEOBJ:
+ case SotExchangeDest::DOC_DRAWOBJ:
+ case SotExchangeDest::DOC_URLBUTTON:
+ case SotExchangeDest::DOC_GROUPOBJ:
+ // select frames/objects
+ SwTransferable::SetSelInShell( rSh, true, pPt );
+ break;
+
+ default:
+ SwTransferable::SetSelInShell( rSh, false, pPt );
+ break;
+ }
+ }
+ }
+ else if( ( !GetSwTransferable( rData ) || bIsPasteFormat ) &&
+ !rSh.IsTableMode() && rSh.HasSelection() )
+ {
+ // then delete the selections
+
+ //don't delete selected content
+ // - at table-selection
+ // - at ReRead of a graphic/DDEData
+ // - at D&D, for the right selection was taken care of
+ // in Drop-Handler
+ bool bDelSel = false;
+ switch( nDestination )
+ {
+ case SotExchangeDest::DOC_TEXTFRAME:
+ case SotExchangeDest::SWDOC_FREE_AREA:
+ case SotExchangeDest::DOC_TEXTFRAME_WEB:
+ case SotExchangeDest::SWDOC_FREE_AREA_WEB:
+ bDelSel = true;
+ break;
+ default:
+ break;
+ }
+
+ if( bDelSel )
+ // #i34830#
+ pAction.reset(new SwTrnsfrActionAndUndo(&rSh, true, pContext));
+ }
+
+ SwTransferable *pTrans=nullptr, *pTunneledTrans=GetSwTransferable( rData );
+
+ // check for private drop
+ bool bPrivateDrop(pPt);
+ if (bPrivateDrop)
+ {
+ if (bPasteSelection)
+ pTrans = pMod->m_pXSelection;
+ else
+ pTrans = pMod->m_pDragDrop;
+ bPrivateDrop = nullptr != pTrans;
+ }
+ bool bNeedToSelectBeforePaste(false);
+
+ if(bPrivateDrop && DND_ACTION_LINK == nDropAction)
+ {
+ // internal drop on object, suppress bPrivateDrop to change internal fill
+ bPrivateDrop = false;
+ bNeedToSelectBeforePaste = true;
+ }
+
+ if(bPrivateDrop && pPt && DND_ACTION_MOVE == nDropAction)
+ {
+ // check if dragged over a useful target. If yes, use as content exchange
+ // drop as if from external
+ const SwFrameFormat* pSwFrameFormat = rSh.GetFormatFromObj(*pPt);
+
+ if(dynamic_cast< const SwDrawFrameFormat* >(pSwFrameFormat))
+ {
+ bPrivateDrop = false;
+ bNeedToSelectBeforePaste = true;
+ }
+ }
+
+ if(bPrivateDrop)
+ {
+ // then internal Drag & Drop or XSelection
+ bRet = pTrans->PrivateDrop( rSh, *pPt, DND_ACTION_MOVE == nDropAction,
+ bPasteSelection );
+ }
+ else if( !pPt && pTunneledTrans &&
+ EXCHG_OUT_ACTION_INSERT_PRIVATE == nAction )
+ {
+ // then internal paste
+ bRet = pTunneledTrans->PrivatePaste(rSh, pContext, ePasteTable);
+ }
+ else if( EXCHG_INOUT_ACTION_NONE != nAction )
+ {
+ if( !pAction )
+ {
+ pAction.reset(new SwTrnsfrActionAndUndo( &rSh ));
+ }
+
+ // in Drag&Drop MessageBoxes must not be showed
+ bool bMsg = nullptr == pPt;
+
+ // delete selections
+
+ switch( nAction )
+ {
+ case EXCHG_OUT_ACTION_INSERT_PRIVATE:
+ OSL_ENSURE( pPt, "EXCHG_OUT_ACTION_INSERT_PRIVATE: what should happen here?" );
+ break;
+
+ case EXCHG_OUT_ACTION_MOVE_PRIVATE:
+ OSL_ENSURE( pPt, "EXCHG_OUT_ACTION_MOVE_PRIVATE: what should happen here?" );
+ break;
+
+ case EXCHG_IN_ACTION_MOVE:
+ case EXCHG_IN_ACTION_COPY:
+ case EXCHG_IN_ACTION_LINK:
+ case EXCHG_OUT_ACTION_INSERT_HTML:
+ case EXCHG_OUT_ACTION_INSERT_STRING:
+ case EXCHG_OUT_ACTION_INSERT_IMAGEMAP:
+ case EXCHG_OUT_ACTION_REPLACE_IMAGEMAP:
+
+ // then we have to use the format
+ switch( nFormat )
+ {
+ case SotClipboardFormatId::DRAWING:
+ bRet = SwTransferable::PasteSdrFormat( rData, rSh,
+ SwPasteSdr::Insert, pPt,
+ nActionFlags, bNeedToSelectBeforePaste);
+ break;
+
+ case SotClipboardFormatId::HTML:
+ case SotClipboardFormatId::HTML_SIMPLE:
+ case SotClipboardFormatId::HTML_NO_COMMENT:
+ case SotClipboardFormatId::RTF:
+ case SotClipboardFormatId::RICHTEXT:
+ case SotClipboardFormatId::STRING:
+ bRet = SwTransferable::PasteFileContent( rData, rSh,
+ nFormat, bMsg, bIgnoreComments );
+ break;
+
+ case SotClipboardFormatId::NETSCAPE_BOOKMARK:
+ {
+ INetBookmark aBkmk;
+ if( rData.GetINetBookmark( nFormat, aBkmk ) )
+ {
+ SwFormatINetFormat aFormat( aBkmk.GetURL(), OUString() );
+ rSh.InsertURL( aFormat, aBkmk.GetDescription() );
+ bRet = true;
+ }
+ }
+ break;
+
+ case SotClipboardFormatId::SD_OLE:
+ bRet = SwTransferable::PasteOLE( rData, rSh, nFormat,
+ nActionFlags, bMsg );
+ break;
+
+ case SotClipboardFormatId::SVIM:
+ bRet = SwTransferable::PasteImageMap( rData, rSh );
+ break;
+
+ case SotClipboardFormatId::SVXB:
+ case SotClipboardFormatId::BITMAP:
+ case SotClipboardFormatId::PNG:
+ case SotClipboardFormatId::GDIMETAFILE:
+ bRet = SwTransferable::PasteGrf( rData, rSh, nFormat,
+ SwPasteSdr::Insert,pPt,
+ nActionFlags, nDropAction, bNeedToSelectBeforePaste);
+ break;
+
+ case SotClipboardFormatId::XFORMS:
+ case SotClipboardFormatId::SBA_FIELDDATAEXCHANGE:
+ case SotClipboardFormatId::SBA_DATAEXCHANGE:
+ case SotClipboardFormatId::SBA_CTRLDATAEXCHANGE:
+ bRet = SwTransferable::PasteDBData( rData, rSh, nFormat,
+ EXCHG_IN_ACTION_LINK == nAction,
+ pPt, bMsg );
+ break;
+
+ case SotClipboardFormatId::SIMPLE_FILE:
+ bRet = SwTransferable::PasteFileName( rData, rSh, nFormat,
+ ( EXCHG_IN_ACTION_MOVE == nAction
+ ? SwPasteSdr::Replace
+ : EXCHG_IN_ACTION_LINK == nAction
+ ? SwPasteSdr::SetAttr
+ : SwPasteSdr::Insert),
+ pPt, nActionFlags, nullptr );
+ break;
+
+ case SotClipboardFormatId::FILE_LIST:
+ // then insert as graphics only
+ bRet = SwTransferable::PasteFileList( rData, rSh,
+ EXCHG_IN_ACTION_LINK == nAction,
+ pPt, bMsg );
+ break;
+
+ case SotClipboardFormatId::SONLK:
+ if( pPt )
+ {
+ NaviContentBookmark aBkmk;
+ if (aBkmk.Paste(rData, rSh.GetSelText()))
+ {
+ if(bIsDefault)
+ {
+ switch(aBkmk.GetDefaultDragType())
+ {
+ case RegionMode::NONE: nAction = EXCHG_IN_ACTION_COPY; break;
+ case RegionMode::EMBEDDED: nAction = EXCHG_IN_ACTION_MOVE; break;
+ case RegionMode::LINK: nAction = EXCHG_IN_ACTION_LINK; break;
+ }
+ }
+ rSh.NavigatorPaste( aBkmk, nAction );
+ bRet = true;
+ }
+ }
+ break;
+
+ case SotClipboardFormatId::INET_IMAGE:
+ case SotClipboardFormatId::NETSCAPE_IMAGE:
+ bRet = SwTransferable::PasteTargetURL( rData, rSh,
+ SwPasteSdr::Insert,
+ pPt, true );
+ break;
+
+ default:
+ OSL_ENSURE( pPt, "unknown format" );
+ }
+ break;
+
+ case EXCHG_OUT_ACTION_INSERT_FILE:
+ {
+ bool graphicInserted;
+ bRet = SwTransferable::PasteFileName( rData, rSh, nFormat,
+ SwPasteSdr::Insert, pPt,
+ nActionFlags,
+ &graphicInserted );
+ if( graphicInserted )
+ bCallAutoCaption = true;
+ }
+ break;
+
+ case EXCHG_OUT_ACTION_INSERT_OLE:
+ bRet = SwTransferable::PasteOLE( rData, rSh, nFormat,
+ nActionFlags,bMsg );
+ break;
+
+ case EXCHG_OUT_ACTION_INSERT_DDE:
+ {
+ bool bReRead = 0 != CNT_HasGrf( rSh.GetCntType() );
+ bRet = SwTransferable::PasteDDE( rData, rSh, bReRead, bMsg );
+ }
+ break;
+
+ case EXCHG_OUT_ACTION_INSERT_HYPERLINK:
+ {
+ OUString sURL, sDesc;
+ if( SotClipboardFormatId::SIMPLE_FILE == nFormat )
+ {
+ if( rData.GetString( nFormat, sURL ) && !sURL.isEmpty() )
+ {
+ SwTransferable::CheckForURLOrLNKFile( rData, sURL, &sDesc );
+ if( sDesc.isEmpty() )
+ sDesc = sURL;
+ bRet = true;
+ }
+ }
+ else
+ {
+ INetBookmark aBkmk;
+ if( rData.GetINetBookmark( nFormat, aBkmk ) )
+ {
+ sURL = aBkmk.GetURL();
+ sDesc = aBkmk.GetDescription();
+ bRet = true;
+ }
+ }
+
+ if( bRet )
+ {
+ SwFormatINetFormat aFormat( sURL, OUString() );
+ rSh.InsertURL( aFormat, sDesc );
+ }
+ }
+ break;
+
+ case EXCHG_OUT_ACTION_GET_ATTRIBUTES:
+ switch( nFormat )
+ {
+ case SotClipboardFormatId::DRAWING:
+ bRet = SwTransferable::PasteSdrFormat( rData, rSh,
+ SwPasteSdr::SetAttr, pPt,
+ nActionFlags, bNeedToSelectBeforePaste);
+ break;
+ case SotClipboardFormatId::SVXB:
+ case SotClipboardFormatId::GDIMETAFILE:
+ case SotClipboardFormatId::BITMAP:
+ case SotClipboardFormatId::PNG:
+ case SotClipboardFormatId::NETSCAPE_BOOKMARK:
+ case SotClipboardFormatId::SIMPLE_FILE:
+ case SotClipboardFormatId::FILEGRPDESCRIPTOR:
+ case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
+ bRet = SwTransferable::PasteGrf( rData, rSh, nFormat,
+ SwPasteSdr::SetAttr, pPt,
+ nActionFlags, nDropAction, bNeedToSelectBeforePaste);
+ break;
+ default:
+ OSL_FAIL( "unknown format" );
+ }
+
+ break;
+
+ case EXCHG_OUT_ACTION_INSERT_DRAWOBJ:
+ bRet = SwTransferable::PasteSdrFormat( rData, rSh,
+ SwPasteSdr::Insert, pPt,
+ nActionFlags, bNeedToSelectBeforePaste);
+ break;
+ case EXCHG_OUT_ACTION_INSERT_SVXB:
+ case EXCHG_OUT_ACTION_INSERT_GDIMETAFILE:
+ case EXCHG_OUT_ACTION_INSERT_BITMAP:
+ case EXCHG_OUT_ACTION_INSERT_GRAPH:
+ bRet = SwTransferable::PasteGrf( rData, rSh, nFormat,
+ SwPasteSdr::Insert, pPt,
+ nActionFlags, nDropAction, bNeedToSelectBeforePaste, nAnchorType );
+ break;
+
+ case EXCHG_OUT_ACTION_REPLACE_DRAWOBJ:
+ bRet = SwTransferable::PasteSdrFormat( rData, rSh,
+ SwPasteSdr::Replace, pPt,
+ nActionFlags, bNeedToSelectBeforePaste);
+ break;
+
+ case EXCHG_OUT_ACTION_REPLACE_SVXB:
+ case EXCHG_OUT_ACTION_REPLACE_GDIMETAFILE:
+ case EXCHG_OUT_ACTION_REPLACE_BITMAP:
+ case EXCHG_OUT_ACTION_REPLACE_GRAPH:
+ bRet = SwTransferable::PasteGrf( rData, rSh, nFormat,
+ SwPasteSdr::Replace,pPt,
+ nActionFlags, nDropAction, bNeedToSelectBeforePaste);
+ break;
+
+ case EXCHG_OUT_ACTION_INSERT_INTERACTIVE:
+ bRet = SwTransferable::PasteAsHyperlink( rData, rSh, nFormat );
+ break;
+
+ default:
+ OSL_FAIL("unknown action" );
+ }
+ }
+
+ if( !bPasteSelection && rSh.IsFrameSelected() )
+ {
+ rSh.EnterSelFrameMode();
+ //force ::SelectShell
+ rSh.GetView().StopShellTimer();
+ }
+
+ pAction.reset();
+ if( bCallAutoCaption )
+ rSh.GetView().AutoCaption( GRAPHIC_CAP );
+
+ return bRet;
+}
+
+SotExchangeDest SwTransferable::GetSotDestination( const SwWrtShell& rSh )
+{
+ SotExchangeDest nRet = SotExchangeDest::NONE;
+
+ ObjCntType eOType = rSh.GetObjCntTypeOfSelection();
+
+ switch( eOType )
+ {
+ case OBJCNT_GRF:
+ {
+ bool bIMap, bLink;
+ bIMap = nullptr != rSh.GetFlyFrameFormat()->GetURL().GetMap();
+ OUString aDummy;
+ rSh.GetGrfNms( &aDummy, nullptr );
+ bLink = !aDummy.isEmpty();
+
+ if( bLink && bIMap )
+ nRet = SotExchangeDest::DOC_LNKD_GRAPH_W_IMAP;
+ else if( bLink )
+ nRet = SotExchangeDest::DOC_LNKD_GRAPHOBJ;
+ else if( bIMap )
+ nRet = SotExchangeDest::DOC_GRAPH_W_IMAP;
+ else
+ nRet = SotExchangeDest::DOC_GRAPHOBJ;
+ }
+ break;
+
+ case OBJCNT_FLY:
+ if( dynamic_cast< const SwWebDocShell *>( rSh.GetView().GetDocShell() ) != nullptr )
+ nRet = SotExchangeDest::DOC_TEXTFRAME_WEB;
+ else
+ nRet = SotExchangeDest::DOC_TEXTFRAME;
+ break;
+ case OBJCNT_OLE: nRet = SotExchangeDest::DOC_OLEOBJ; break;
+
+ case OBJCNT_CONTROL: /* no Action avail */
+ case OBJCNT_SIMPLE: nRet = SotExchangeDest::DOC_DRAWOBJ; break;
+ case OBJCNT_URLBUTTON: nRet = SotExchangeDest::DOC_URLBUTTON; break;
+ case OBJCNT_GROUPOBJ: nRet = SotExchangeDest::DOC_GROUPOBJ; break;
+
+ // what do we do at multiple selections???
+ default:
+ {
+ if( dynamic_cast< const SwWebDocShell *>( rSh.GetView().GetDocShell() ) != nullptr )
+ nRet = SotExchangeDest::SWDOC_FREE_AREA_WEB;
+ else
+ nRet = SotExchangeDest::SWDOC_FREE_AREA;
+ }
+ }
+
+ return nRet;
+}
+
+bool SwTransferable::PasteFileContent( const TransferableDataHelper& rData,
+ SwWrtShell& rSh, SotClipboardFormatId nFormat, bool bMsg, bool bIgnoreComments )
+{
+ TranslateId pResId = STR_CLPBRD_FORMAT_ERROR;
+ bool bRet = false;
+
+ MSE40HTMLClipFormatObj aMSE40ClpObj;
+
+ tools::SvRef<SotTempStream> xStrm;
+ SvStream* pStream = nullptr;
+ Reader* pRead = nullptr;
+ OUString sData;
+ switch( nFormat )
+ {
+ case SotClipboardFormatId::STRING:
+ {
+ pRead = ReadAscii;
+ if( rData.GetString( nFormat, sData ) )
+ {
+ pStream = new SvMemoryStream( const_cast<sal_Unicode *>(sData.getStr()),
+ sData.getLength() * sizeof( sal_Unicode ),
+ StreamMode::READ );
+#ifdef OSL_BIGENDIAN
+ pStream->SetEndian( SvStreamEndian::BIG );
+#else
+ pStream->SetEndian( SvStreamEndian::LITTLE );
+#endif
+
+ SwAsciiOptions aAOpt;
+ aAOpt.SetCharSet( RTL_TEXTENCODING_UCS2 );
+ pRead->GetReaderOpt().SetASCIIOpts( aAOpt );
+ break;
+ }
+ }
+ [[fallthrough]]; // because then test if we get a stream
+
+ default:
+ if( rData.GetSotStorageStream( nFormat, xStrm ) )
+ {
+ if( ( SotClipboardFormatId::HTML_SIMPLE == nFormat ) ||
+ ( SotClipboardFormatId::HTML_NO_COMMENT == nFormat ) )
+ {
+ pStream = aMSE40ClpObj.IsValid( *xStrm );
+ pRead = ReadHTML;
+ pRead->SetReadUTF8( true );
+
+ bool bNoComments =
+ ( nFormat == SotClipboardFormatId::HTML_NO_COMMENT );
+ pRead->SetIgnoreHTMLComments( bNoComments );
+ }
+ else
+ {
+ pStream = xStrm.get();
+ if( SotClipboardFormatId::RTF == nFormat || SotClipboardFormatId::RICHTEXT == nFormat)
+ pRead = SwReaderWriter::GetRtfReader();
+ else if( !pRead )
+ {
+ pRead = ReadHTML;
+ pRead->SetReadUTF8( true );
+ }
+ }
+ }
+ break;
+ }
+
+ if( pStream && pRead )
+ {
+ Link<LinkParamNone*,void> aOldLink( rSh.GetChgLnk() );
+ rSh.SetChgLnk( Link<LinkParamNone*,void>() );
+
+ const SwPosition& rInsPos = *rSh.GetCursor()->Start();
+ SwReader aReader(*pStream, OUString(), OUString(), *rSh.GetCursor());
+ rSh.SaveTableBoxContent( &rInsPos );
+
+ if (bIgnoreComments)
+ pRead->SetIgnoreHTMLComments(true);
+
+ if( aReader.Read( *pRead ).IsError() )
+ pResId = STR_ERROR_CLPBRD_READ;
+ else
+ {
+ pResId = TranslateId();
+ bRet = true;
+ }
+
+ rSh.SetChgLnk( aOldLink );
+ if( bRet )
+ rSh.CallChgLnk();
+ }
+ else
+ pResId = STR_CLPBRD_FORMAT_ERROR;
+
+ // Exist a SvMemoryStream? (data in the OUString and xStrm is empty)
+ if( pStream && !xStrm.is() )
+ delete pStream;
+
+ if (bMsg && pResId)
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
+ VclMessageType::Info, VclButtonsType::Ok,
+ SwResId(pResId)));
+ xBox->run();
+ }
+ return bRet;
+}
+
+bool SwTransferable::PasteOLE( TransferableDataHelper& rData, SwWrtShell& rSh,
+ SotClipboardFormatId nFormat, SotExchangeActionFlags nActionFlags, bool bMsg )
+{
+ bool bRet = false;
+ TransferableObjectDescriptor aObjDesc;
+ uno::Reference < io::XInputStream > xStrm;
+ uno::Reference < embed::XStorage > xStore;
+ Reader* pRead = nullptr;
+
+ // Get the preferred format
+ SotClipboardFormatId nId;
+ if( rData.HasFormat( SotClipboardFormatId::EMBEDDED_OBJ ) )
+ nId = SotClipboardFormatId::EMBEDDED_OBJ;
+ else if( rData.HasFormat( SotClipboardFormatId::EMBED_SOURCE ) &&
+ rData.HasFormat( SotClipboardFormatId::OBJECTDESCRIPTOR ))
+ nId = SotClipboardFormatId::EMBED_SOURCE;
+ else
+ nId = SotClipboardFormatId::NONE;
+
+ if (nId != SotClipboardFormatId::NONE)
+ {
+ SwDocShell* pDocSh = rSh.GetDoc()->GetDocShell();
+ xStrm = rData.GetInputStream(nId, SfxObjectShell::CreateShellID(pDocSh));
+ }
+
+ if (xStrm.is())
+ {
+ // if there is an embedded object, first try if it's a writer object
+ // this will be inserted into the document by using a Reader
+ try
+ {
+ xStore = comphelper::OStorageHelper::GetStorageFromInputStream( xStrm );
+ switch( SotStorage::GetFormatID( xStore ) )
+ {
+ case SotClipboardFormatId::STARWRITER_60:
+ case SotClipboardFormatId::STARWRITERWEB_60:
+ case SotClipboardFormatId::STARWRITERGLOB_60:
+ case SotClipboardFormatId::STARWRITER_8:
+ case SotClipboardFormatId::STARWRITERWEB_8:
+ case SotClipboardFormatId::STARWRITERGLOB_8:
+ pRead = ReadXML;
+ break;
+ default:
+ try
+ {
+ xStore->dispose();
+ xStore = nullptr;
+ }
+ catch (const uno::Exception&)
+ {
+ }
+
+ break;
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ // it wasn't a storage, but maybe it's a useful stream
+ }
+ }
+
+ if( pRead )
+ {
+ SwPaM &rPAM = *rSh.GetCursor();
+ SwReader aReader(xStore, OUString(), rPAM);
+ if( ! aReader.Read( *pRead ).IsError() )
+ bRet = true;
+ else if( bMsg )
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
+ VclMessageType::Info, VclButtonsType::Ok,
+ SwResId(STR_ERROR_CLPBRD_READ)));
+ xBox->run();
+ }
+ }
+ else
+ {
+ // temporary storage until the object is inserted
+ uno::Reference< embed::XStorage > xTmpStor;
+ uno::Reference < embed::XEmbeddedObject > xObj;
+ OUString aName;
+ comphelper::EmbeddedObjectContainer aCnt;
+
+ if ( xStrm.is() )
+ {
+ if ( !rData.GetTransferableObjectDescriptor( SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDesc ) )
+ {
+ OSL_ENSURE( !xStrm.is(), "An object without descriptor in clipboard!");
+ }
+ }
+ else
+ {
+ if( rData.HasFormat( SotClipboardFormatId::OBJECTDESCRIPTOR_OLE ) && rData.GetTransferableObjectDescriptor( nFormat, aObjDesc ) )
+ {
+ xStrm = rData.GetInputStream(SotClipboardFormatId::EMBED_SOURCE_OLE, OUString());
+ if (!xStrm.is())
+ xStrm = rData.GetInputStream(SotClipboardFormatId::EMBEDDED_OBJ_OLE, OUString());
+
+ if ( !xStrm.is() )
+ {
+ // This is MSOLE object that should be created by direct using of system clipboard
+ try
+ {
+ xTmpStor = ::comphelper::OStorageHelper::GetTemporaryStorage();
+ uno::Reference < embed::XEmbedObjectClipboardCreator > xClipboardCreator =
+ embed::MSOLEObjectSystemCreator::create( ::comphelper::getProcessComponentContext() );
+
+ embed::InsertedObjectInfo aInfo = xClipboardCreator->createInstanceInitFromClipboard(
+ xTmpStor,
+ "DummyName",
+ uno::Sequence< beans::PropertyValue >() );
+
+ // TODO/LATER: in future InsertedObjectInfo will be used to get container related information
+ // for example whether the object should be an iconified one
+ xObj = aInfo.Object;
+ }
+ catch (const uno::Exception&)
+ {
+ }
+ }
+ }
+ else if (rData.HasFormat(SotClipboardFormatId::SIMPLE_FILE))
+ {
+ OUString sFile;
+ if (rData.GetString(nFormat, sFile) && !sFile.isEmpty())
+ {
+ // Copied from sd::View::DropInsertFileHdl
+ uno::Sequence< beans::PropertyValue > aMedium{ comphelper::makePropertyValue(
+ "URL", sFile) };
+ SwDocShell* pDocSh = rSh.GetDoc()->GetDocShell();
+ xObj = pDocSh->GetEmbeddedObjectContainer().InsertEmbeddedObject(aMedium, aName);
+ }
+ }
+ }
+
+ if ( xStrm.is() && !xObj.is() )
+ xObj = aCnt.InsertEmbeddedObject( xStrm, aName );
+
+ if( xObj.is() )
+ {
+ svt::EmbeddedObjectRef xObjRef( xObj, aObjDesc.mnViewAspect );
+
+ // try to get the replacement image from the clipboard
+ Graphic aGraphic;
+ SotClipboardFormatId nGrFormat = SotClipboardFormatId::NONE;
+
+ // limit the size of the preview metafile to 100000 actions
+ GDIMetaFile aMetafile;
+ if (rData.GetGDIMetaFile(SotClipboardFormatId::GDIMETAFILE, aMetafile, 100000))
+ {
+ nGrFormat = SotClipboardFormatId::GDIMETAFILE;
+ aGraphic = aMetafile;
+ }
+
+ // insert replacement image ( if there is one ) into the object helper
+ if ( nGrFormat != SotClipboardFormatId::NONE )
+ {
+ DataFlavor aDataFlavor;
+ SotExchange::GetFormatDataFlavor( nGrFormat, aDataFlavor );
+ xObjRef.SetGraphic( aGraphic, aDataFlavor.MimeType );
+ }
+ else if ( aObjDesc.mnViewAspect == embed::Aspects::MSOLE_ICON )
+ {
+ // it is important to have an icon, let an empty graphic be used
+ // if no other graphic is provided
+ // TODO/LATER: in future a default bitmap could be used
+ MapMode aMapMode( MapUnit::Map100thMM );
+ aGraphic.SetPrefSize( Size( 2500, 2500 ) );
+ aGraphic.SetPrefMapMode( aMapMode );
+ xObjRef.SetGraphic( aGraphic, OUString() );
+ }
+
+ //set size. This is a hack because of handing over, size should be
+ //passed to the InsertOle!!!!!!!!!!
+ Size aSize;
+ if ( aObjDesc.mnViewAspect == embed::Aspects::MSOLE_ICON )
+ {
+ if( aObjDesc.maSize.Width() && aObjDesc.maSize.Height() )
+ aSize = aObjDesc.maSize;
+ else
+ {
+ MapMode aMapMode( MapUnit::Map100thMM );
+ aSize = xObjRef.GetSize( &aMapMode );
+ }
+ }
+ else if( aObjDesc.maSize.Width() && aObjDesc.maSize.Height() )
+ {
+ aSize = aObjDesc.maSize; //always 100TH_MM
+ MapUnit aUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( aObjDesc.mnViewAspect ) );
+ aSize = OutputDevice::LogicToLogic(aSize, MapMode(MapUnit::Map100thMM), MapMode(aUnit));
+ awt::Size aSz;
+ try
+ {
+ aSz = xObj->getVisualAreaSize( aObjDesc.mnViewAspect );
+ }
+ catch (const embed::NoVisualAreaSizeException&)
+ {
+ // in this case the provided size is used
+ }
+
+ if ( aSz.Width != aSize.Width() || aSz.Height != aSize.Height() )
+ {
+ aSz.Width = aSize.Width();
+ aSz.Height = aSize.Height();
+ xObj->setVisualAreaSize( aObjDesc.mnViewAspect, aSz );
+ }
+ }
+ else
+ {
+ // the descriptor contains the wrong object size
+ // the following call will let the MSOLE objects cache the size if it is possible
+ // it should be done while the object is running
+ try
+ {
+ xObj->getVisualAreaSize( aObjDesc.mnViewAspect );
+ }
+ catch (const uno::Exception&)
+ {
+ }
+ }
+ //End of Hack!
+
+ rSh.InsertOleObject( xObjRef );
+ bRet = true;
+
+ if( bRet && ( nActionFlags & SotExchangeActionFlags::InsertTargetUrl) )
+ SwTransferable::PasteTargetURL( rData, rSh, SwPasteSdr::NONE, nullptr, false );
+
+ // let the object be unloaded if possible
+ SwOLEObj::UnloadObject( xObj, rSh.GetDoc(), embed::Aspects::MSOLE_CONTENT );
+ }
+ }
+ return bRet;
+}
+
+bool SwTransferable::PasteTargetURL( const TransferableDataHelper& rData,
+ SwWrtShell& rSh, SwPasteSdr nAction,
+ const Point* pPt, bool bInsertGRF )
+{
+ bool bRet = false;
+ INetImage aINetImg;
+ if( ( rData.HasFormat( SotClipboardFormatId::INET_IMAGE ) &&
+ rData.GetINetImage( SotClipboardFormatId::INET_IMAGE, aINetImg )) ||
+ ( rData.HasFormat( SotClipboardFormatId::NETSCAPE_IMAGE ) &&
+ rData.GetINetImage( SotClipboardFormatId::NETSCAPE_IMAGE, aINetImg )) )
+ {
+ if( !aINetImg.GetImageURL().isEmpty() && bInsertGRF )
+ {
+ OUString sURL( aINetImg.GetImageURL() );
+ SwTransferable::CheckForURLOrLNKFile( rData, sURL );
+
+ //!!! check at FileSystem - only then it makes sense to test graphics !!!
+ Graphic aGraphic;
+ GraphicFilter &rFlt = GraphicFilter::GetGraphicFilter();
+ bRet = ERRCODE_NONE == GraphicFilter::LoadGraphic(sURL, OUString(), aGraphic, &rFlt);
+
+ if( bRet )
+ {
+ //Check and Perform rotation if needed
+ lclCheckAndPerformRotation(aGraphic);
+
+ switch( nAction )
+ {
+ case SwPasteSdr::Insert:
+ SwTransferable::SetSelInShell( rSh, false, pPt );
+ rSh.InsertGraphic(sURL, OUString(), aGraphic);
+ break;
+
+ case SwPasteSdr::Replace:
+ if( rSh.IsObjSelected() )
+ {
+ rSh.ReplaceSdrObj( sURL, &aGraphic );
+ Point aPt( pPt ? *pPt : rSh.GetCursorDocPos() );
+ SwTransferable::SetSelInShell( rSh, true, &aPt );
+ }
+ else
+ rSh.ReRead(sURL, OUString(), &aGraphic);
+ break;
+
+ case SwPasteSdr::SetAttr:
+ if( rSh.IsObjSelected() )
+ rSh.Paste( aGraphic, OUString() );
+ else if( OBJCNT_GRF == rSh.GetObjCntTypeOfSelection() )
+ rSh.ReRead(sURL, OUString(), &aGraphic);
+ else
+ {
+ SwTransferable::SetSelInShell( rSh, false, pPt );
+ rSh.InsertGraphic(sURL, OUString(), aGraphic);
+ }
+ break;
+ default:
+ bRet = false;
+ }
+ }
+ }
+ else
+ bRet = true;
+ }
+
+ if( bRet )
+ {
+ SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
+ rSh.GetFlyFrameAttr( aSet );
+ SwFormatURL aURL( aSet.Get( RES_URL ) );
+
+ if( aURL.GetURL() != aINetImg.GetTargetURL() ||
+ aURL.GetTargetFrameName() != aINetImg.GetTargetFrame() )
+ {
+ aURL.SetURL( aINetImg.GetTargetURL(), false );
+ aURL.SetTargetFrameName( aINetImg.GetTargetFrame() );
+ aSet.Put( aURL );
+ rSh.SetFlyFrameAttr( aSet );
+ }
+ }
+ return bRet;
+}
+
+void SwTransferable::SetSelInShell( SwWrtShell& rSh, bool bSelectFrame,
+ const Point* pPt )
+{
+ if( bSelectFrame )
+ {
+ // select frames/objects
+ if( pPt && !rSh.GetView().GetViewFrame().GetDispatcher()->IsLocked() )
+ {
+ rSh.GetView().NoRotate();
+ if( rSh.SelectObj( *pPt ))
+ {
+ rSh.HideCursor();
+ rSh.EnterSelFrameMode( pPt );
+ g_bFrameDrag = true;
+ }
+ }
+ }
+ else
+ {
+ if( rSh.IsFrameSelected() || rSh.IsObjSelected() )
+ {
+ rSh.UnSelectFrame();
+ rSh.LeaveSelFrameMode();
+ rSh.GetView().GetEditWin().StopInsFrame();
+ g_bFrameDrag = false;
+ }
+ else if( rSh.GetView().GetDrawFuncPtr() )
+ rSh.GetView().GetEditWin().StopInsFrame();
+
+ rSh.EnterStdMode();
+ if( pPt )
+ rSh.SwCursorShell::SetCursor( *pPt, true );
+ }
+}
+
+bool SwTransferable::PasteDDE( const TransferableDataHelper& rData,
+ SwWrtShell& rWrtShell, bool bReReadGrf,
+ bool bMsg )
+{
+ // data from Clipboardformat
+ OUString aApp, aTopic, aItem;
+
+ {
+ tools::SvRef<SotTempStream> xStrm;
+ if( !rData.GetSotStorageStream( SotClipboardFormatId::LINK, xStrm ))
+ {
+ OSL_ENSURE( false, "DDE Data not found." );
+ return false;
+ } // report useful error!!
+
+ rtl_TextEncoding eEncoding = osl_getThreadTextEncoding();
+ aApp = read_zeroTerminated_uInt8s_ToOUString(*xStrm, eEncoding);
+ aTopic = read_zeroTerminated_uInt8s_ToOUString(*xStrm, eEncoding);
+ aItem = read_zeroTerminated_uInt8s_ToOUString(*xStrm, eEncoding);
+ }
+
+ OUString aCmd;
+ sfx2::MakeLnkName( aCmd, &aApp, aTopic, aItem );
+
+ // do we want to read in a graphic now?
+ SotClipboardFormatId nFormat;
+ if( !rData.HasFormat( SotClipboardFormatId::RTF ) &&
+ !rData.HasFormat( SotClipboardFormatId::RICHTEXT ) &&
+ !rData.HasFormat( SotClipboardFormatId::HTML ) &&
+ !rData.HasFormat( SotClipboardFormatId::STRING ) &&
+ (rData.HasFormat( nFormat = SotClipboardFormatId::GDIMETAFILE ) ||
+ rData.HasFormat( nFormat = SotClipboardFormatId::BITMAP )) )
+ {
+ Graphic aGrf;
+ bool bRet = rData.GetGraphic( nFormat, aGrf );
+ if( bRet )
+ {
+ OUString sLnkTyp("DDE");
+ if ( bReReadGrf )
+ rWrtShell.ReRead( aCmd, sLnkTyp, &aGrf );
+ else
+ rWrtShell.InsertGraphic( aCmd, sLnkTyp, aGrf );
+ }
+ return bRet;
+ }
+
+ SwFieldType* pTyp = nullptr;
+ size_t i = 1;
+ size_t j;
+ OUString aName;
+ bool bDoublePaste = false;
+ const size_t nSize = rWrtShell.GetFieldTypeCount();
+ const ::utl::TransliterationWrapper& rColl = ::GetAppCmpStrIgnore();
+
+ do {
+ aName = aApp + OUString::number( i );
+ for( j = INIT_FLDTYPES; j < nSize; j++ )
+ {
+ pTyp = rWrtShell.GetFieldType( j );
+ if( SwFieldIds::Dde == pTyp->Which() )
+ {
+ if( rColl.isEqual( static_cast<SwDDEFieldType*>(pTyp)->GetCmd(), aCmd ) &&
+ SfxLinkUpdateMode::ALWAYS == static_cast<SwDDEFieldType*>(pTyp)->GetType() )
+ {
+ aName = pTyp->GetName();
+ bDoublePaste = true;
+ break;
+ }
+ else if( rColl.isEqual( aName, pTyp->GetName() ) )
+ break;
+ }
+ }
+ if( j == nSize )
+ break;
+ ++i;
+ }
+ while( !bDoublePaste );
+
+ if( !bDoublePaste )
+ {
+ SwDDEFieldType aType( aName, aCmd, SfxLinkUpdateMode::ALWAYS );
+ pTyp = rWrtShell.InsertFieldType( aType );
+ }
+
+ SwDDEFieldType* pDDETyp = static_cast<SwDDEFieldType*>(pTyp);
+
+ OUString aExpand;
+ if( rData.GetString( SotClipboardFormatId::STRING, aExpand ))
+ {
+ do { // middle checked loop
+
+ const sal_Int32 nNewlines{comphelper::string::getTokenCount(aExpand, '\n')};
+ // When data comes from a spreadsheet, we add a DDE-table
+ if( !aExpand.isEmpty() &&
+ ( rData.HasFormat( SotClipboardFormatId::SYLK ) ||
+ rData.HasFormat( SotClipboardFormatId::SYLK_BIGCAPS ) ) )
+ {
+ sal_Int32 nRows = nNewlines ? nNewlines-1 : 0;
+ if (!aExpand.endsWith("\n"))
+ ++nRows; // last row has no newline, e.g. one single cell
+ const sal_Int32 nCols = comphelper::string::getTokenCount(o3tl::getToken(aExpand, 0, '\n'), '\t');
+
+ // don't try to insert tables that are too large for writer
+ if (nRows > SAL_MAX_UINT16 || nCols > SAL_MAX_UINT16)
+ {
+ if( bMsg )
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
+ VclMessageType::Info, VclButtonsType::Ok,
+ SwResId(STR_TABLE_TOO_LARGE)));
+ xBox->run();
+ }
+ pDDETyp = nullptr;
+ break;
+ }
+
+ // at least one column & row must be there
+ if( !nRows || !nCols )
+ {
+ if( bMsg )
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
+ VclMessageType::Info, VclButtonsType::Ok,
+ SwResId(STR_NO_TABLE)));
+ xBox->run();
+ }
+ pDDETyp = nullptr;
+ break;
+ }
+
+ rWrtShell.InsertDDETable(
+ SwInsertTableOptions( SwInsertTableFlags::SplitLayout, 1 ), // TODO MULTIHEADER
+ pDDETyp, nRows, nCols );
+ }
+ else if( nNewlines > 1 )
+ {
+ // multiple paragraphs -> insert a protected section
+ if( rWrtShell.HasSelection() )
+ rWrtShell.DelRight();
+
+ SwSectionData aSect( SectionType::DdeLink, aName );
+ aSect.SetLinkFileName( aCmd );
+ aSect.SetProtectFlag(true);
+ rWrtShell.InsertSection( aSect );
+
+ pDDETyp = nullptr; // remove FieldTypes again
+ }
+ else
+ {
+ // insert
+ SwDDEField aSwDDEField( pDDETyp );
+ rWrtShell.InsertField2( aSwDDEField );
+ }
+
+ } while( false );
+ }
+ else
+ pDDETyp = nullptr; // remove FieldTypes again
+
+ if( !pDDETyp && !bDoublePaste )
+ {
+ // remove FieldType again - error occurred!
+ for( j = nSize; j >= INIT_FLDTYPES; --j )
+ if( pTyp == rWrtShell.GetFieldType( j ) )
+ {
+ rWrtShell.RemoveFieldType( j );
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool SwTransferable::PasteSdrFormat( const TransferableDataHelper& rData,
+ SwWrtShell& rSh, SwPasteSdr nAction,
+ const Point* pPt, SotExchangeActionFlags nActionFlags, bool bNeedToSelectBeforePaste)
+{
+ bool bRet = false;
+ tools::SvRef<SotTempStream> xStrm;
+ if( rData.GetSotStorageStream( SotClipboardFormatId::DRAWING, xStrm ))
+ {
+ xStrm->SetVersion( SOFFICE_FILEFORMAT_50 );
+
+ if(bNeedToSelectBeforePaste && pPt)
+ {
+ // if this is an internal drag, need to set the target right (select it), else
+ // still the source will be selected
+ SwTransferable::SetSelInShell( rSh, true, pPt );
+ }
+
+ rSh.Paste( *xStrm, nAction, pPt );
+ bRet = true;
+
+ if( bRet && ( nActionFlags & SotExchangeActionFlags::InsertTargetUrl ))
+ SwTransferable::PasteTargetURL( rData, rSh, SwPasteSdr::NONE, nullptr, false );
+ }
+ return bRet;
+}
+
+bool SwTransferable::PasteGrf( const TransferableDataHelper& rData, SwWrtShell& rSh,
+ SotClipboardFormatId nFormat, SwPasteSdr nAction, const Point* pPt,
+ SotExchangeActionFlags nActionFlags, sal_Int8 nDropAction, bool bNeedToSelectBeforePaste, RndStdIds nAnchorType )
+{
+ bool bRet = false;
+
+ Graphic aGraphic;
+ INetBookmark aBkmk;
+ bool bCheckForGrf = false, bCheckForImageMap = false;
+
+ switch( nFormat )
+ {
+ case SotClipboardFormatId::BITMAP:
+ case SotClipboardFormatId::PNG:
+ case SotClipboardFormatId::GDIMETAFILE:
+ bRet = rData.GetGraphic( nFormat, aGraphic );
+ break;
+
+ case SotClipboardFormatId::SVXB:
+ {
+ tools::SvRef<SotTempStream> xStm;
+
+ if(rData.GetSotStorageStream(SotClipboardFormatId::SVXB, xStm))
+ {
+ TypeSerializer aSerializer(*xStm);
+ aSerializer.readGraphic(aGraphic);
+ bRet = (GraphicType::NONE != aGraphic.GetType() && GraphicType::Default != aGraphic.GetType());
+ }
+
+ break;
+ }
+
+ case SotClipboardFormatId::NETSCAPE_BOOKMARK:
+ case SotClipboardFormatId::FILEGRPDESCRIPTOR:
+ case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
+ bRet = rData.GetINetBookmark( nFormat, aBkmk );
+ if( bRet )
+ {
+ if( SwPasteSdr::SetAttr == nAction )
+ nFormat = SotClipboardFormatId::NETSCAPE_BOOKMARK;
+ else
+ bCheckForGrf = true;
+ }
+ break;
+
+ case SotClipboardFormatId::SIMPLE_FILE:
+ {
+ OUString sText;
+ bRet = rData.GetString( nFormat, sText );
+ if( bRet )
+ {
+ OUString sDesc;
+ SwTransferable::CheckForURLOrLNKFile( rData, sText, &sDesc );
+
+ sText = URIHelper::SmartRel2Abs(INetURLObject(), sText, Link<OUString*, bool>(),
+ false);
+
+#ifdef _WIN32
+ // Now that the path could be modified after SwTransferable::CheckForURLOrLNKFile,
+ // where it could have been converted to URL, and made sure it's actually converted
+ // to URL in URIHelper::SmartRel2Abs, we can finally convert file: URL back to
+ // system path to make sure we don't use short path.
+ // It looks not optimal, when we could apply GetLongPathNameW right to the original
+ // pasted filename. But I don't know if (1) all arriving strings are system paths;
+ // and (2) if SwTransferable::CheckForURLOrLNKFile could result in a different short
+ // path, so taking a safe route.
+ if (sText.startsWithIgnoreAsciiCase("file:"))
+ {
+ // tdf#124500: Convert short path to long path which should be used in links
+ OUString sSysPath;
+ osl::FileBase::getSystemPathFromFileURL(sText, sSysPath);
+ std::unique_ptr<sal_Unicode[]> aBuf(new sal_Unicode[32767]);
+ DWORD nCopied = GetLongPathNameW(o3tl::toW(sSysPath.getStr()),
+ o3tl::toW(aBuf.get()), 32767);
+ if (nCopied && nCopied < 32767)
+ sText = URIHelper::SmartRel2Abs(INetURLObject(), OUString(aBuf.get()),
+ Link<OUString*, bool>(), false);
+ }
+#endif
+
+ aBkmk = INetBookmark(sText, sDesc);
+ bCheckForGrf = true;
+ bCheckForImageMap = SwPasteSdr::Replace == nAction;
+ }
+ }
+ break;
+
+ default:
+ bRet = rData.GetGraphic( nFormat, aGraphic );
+ break;
+ }
+
+ if( bCheckForGrf )
+ {
+ //!!! check at FileSystem - only then it makes sense to test the graphics !!!
+ GraphicFilter &rFlt = GraphicFilter::GetGraphicFilter();
+ bRet = ERRCODE_NONE == GraphicFilter::LoadGraphic(aBkmk.GetURL(), OUString(),
+ aGraphic, &rFlt );
+
+ if( !bRet && SwPasteSdr::SetAttr == nAction &&
+ SotClipboardFormatId::SIMPLE_FILE == nFormat &&
+ // only at frame selection
+ rSh.IsFrameSelected() )
+ {
+ // then set as hyperlink after the graphic
+ nFormat = SotClipboardFormatId::NETSCAPE_BOOKMARK;
+ bRet = true;
+ }
+ }
+
+ if(pPt && bNeedToSelectBeforePaste)
+ {
+ // when using internal D&Ds, still the source object is selected and
+ // this is necessary to get the correct source data which is also
+ // dependent from selection. After receiving the drag data it is
+ // now time to select the correct target object
+ SwTransferable::SetSelInShell( rSh, true, pPt );
+ }
+
+ if( bRet )
+ {
+ //Check and Perform rotation if needed
+ lclCheckAndPerformRotation(aGraphic);
+
+ OUString sURL;
+ if( dynamic_cast< const SwWebDocShell *>( rSh.GetView().GetDocShell() ) != nullptr
+ // #i123922# if link action is noted, also take URL
+ || DND_ACTION_LINK == nDropAction)
+ {
+ sURL = aBkmk.GetURL();
+ }
+
+ switch( nAction )
+ {
+ case SwPasteSdr::Insert:
+ {
+ SwTransferable::SetSelInShell( rSh, false, pPt );
+ rSh.InsertGraphic(sURL, OUString(), aGraphic, nullptr, nAnchorType);
+ break;
+ }
+
+ case SwPasteSdr::Replace:
+ {
+ if( rSh.IsObjSelected() )
+ {
+ // #i123922# for D&D on draw objects, do for now the same for
+ // SwPasteSdr::Replace (D&D) as for SwPasteSdr::SetAttr (D&D and
+ // CTRL+SHIFT). The code below replaces the draw object with
+ // a writer graphic; maybe this is an option later again if wanted
+ rSh.Paste( aGraphic, sURL );
+
+ // rSh.ReplaceSdrObj(sURL, OUString(), &aGraphic);
+ // Point aPt( pPt ? *pPt : rSh.GetCursorDocPos() );
+ // SwTransferable::SetSelInShell( rSh, true, &aPt );
+ }
+ else
+ {
+ // set graphic at writer graphic without link
+ rSh.ReRead(sURL, OUString(), &aGraphic);
+ }
+
+ break;
+ }
+
+ case SwPasteSdr::SetAttr:
+ {
+ if( SotClipboardFormatId::NETSCAPE_BOOKMARK == nFormat )
+ {
+ if( rSh.IsFrameSelected() )
+ {
+ SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
+ rSh.GetFlyFrameAttr( aSet );
+ SwFormatURL aURL( aSet.Get( RES_URL ) );
+ aURL.SetURL( aBkmk.GetURL(), false );
+ aSet.Put( aURL );
+ rSh.SetFlyFrameAttr( aSet );
+ }
+ }
+ else if( rSh.IsObjSelected() )
+ {
+ // set as attribute at DrawObject
+ rSh.Paste( aGraphic, sURL );
+ }
+ else if( OBJCNT_GRF == rSh.GetObjCntTypeOfSelection() )
+ {
+ // set as linked graphic at writer graphic frame
+ rSh.ReRead(sURL, OUString(), &aGraphic);
+ }
+ else
+ {
+ SwTransferable::SetSelInShell( rSh, false, pPt );
+ rSh.InsertGraphic(aBkmk.GetURL(), OUString(), aGraphic);
+ }
+ break;
+ }
+ default:
+ {
+ bRet = false;
+ break;
+ }
+ }
+ }
+
+ if( bRet )
+ {
+
+ if( nActionFlags &
+ ( SotExchangeActionFlags::InsertImageMap | SotExchangeActionFlags::ReplaceImageMap ) )
+ SwTransferable::PasteImageMap( rData, rSh );
+
+ if( nActionFlags & SotExchangeActionFlags::InsertTargetUrl )
+ SwTransferable::PasteTargetURL( rData, rSh, SwPasteSdr::NONE, nullptr, false );
+ }
+ else if( bCheckForImageMap )
+ {
+ // or should the file be an ImageMap-File?
+ ImageMap aMap;
+ SfxMedium aMed( INetURLObject(aBkmk.GetURL()).GetFull(),
+ StreamMode::STD_READ );
+ SvStream* pStream = aMed.GetInStream();
+ if( pStream != nullptr &&
+ !pStream->GetError() &&
+ // mba: no BaseURL for clipboard functionality
+ aMap.Read( *pStream, IMapFormat::Detect ) == IMAP_ERR_OK &&
+ aMap.GetIMapObjectCount() )
+ {
+ SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
+ rSh.GetFlyFrameAttr( aSet );
+ SwFormatURL aURL( aSet.Get( RES_URL ) );
+ aURL.SetMap( &aMap );
+ aSet.Put( aURL );
+ rSh.SetFlyFrameAttr( aSet );
+ bRet = true;
+ }
+ }
+
+ return bRet;
+}
+
+bool SwTransferable::PasteImageMap( const TransferableDataHelper& rData,
+ SwWrtShell& rSh )
+{
+ bool bRet = false;
+ if( rData.HasFormat( SotClipboardFormatId::SVIM ))
+ {
+ SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
+ rSh.GetFlyFrameAttr( aSet );
+ SwFormatURL aURL( aSet.Get( RES_URL ) );
+ const ImageMap* pOld = aURL.GetMap();
+
+ // set or replace, that is the question
+ ImageMap aImageMap;
+ if( rData.GetImageMap( SotClipboardFormatId::SVIM, aImageMap ) &&
+ ( !pOld || aImageMap != *pOld ))
+ {
+ aURL.SetMap( &aImageMap );
+ aSet.Put( aURL );
+ rSh.SetFlyFrameAttr( aSet );
+ }
+ bRet = true;
+ }
+ return bRet;
+}
+
+bool SwTransferable::PasteAsHyperlink( const TransferableDataHelper& rData,
+ SwWrtShell& rSh, SotClipboardFormatId nFormat )
+{
+ bool bRet = false;
+ OUString sFile;
+ if( rData.GetString( nFormat, sFile ) && !sFile.isEmpty() )
+ {
+ OUString sDesc;
+ SwTransferable::CheckForURLOrLNKFile( rData, sFile, &sDesc );
+
+ // first, make the URL absolute
+ INetURLObject aURL;
+ aURL.SetSmartProtocol( INetProtocol::File );
+ aURL.SetSmartURL( sFile );
+ sFile = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+ switch( rSh.GetObjCntTypeOfSelection() )
+ {
+ case OBJCNT_FLY:
+ case OBJCNT_GRF:
+ case OBJCNT_OLE:
+ {
+ SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
+ rSh.GetFlyFrameAttr( aSet );
+ SwFormatURL aURL2( aSet.Get( RES_URL ) );
+ aURL2.SetURL( sFile, false );
+ if( aURL2.GetName().isEmpty() )
+ aURL2.SetName( sFile );
+ aSet.Put( aURL2 );
+ rSh.SetFlyFrameAttr( aSet );
+ }
+ break;
+
+ default:
+ {
+ rSh.InsertURL( SwFormatINetFormat( sFile, OUString() ),
+ sDesc.isEmpty() ? sFile : sDesc);
+ }
+ }
+ bRet = true;
+ }
+ return bRet;
+}
+
+bool SwTransferable::PasteFileName( TransferableDataHelper& rData,
+ SwWrtShell& rSh, SotClipboardFormatId nFormat,
+ SwPasteSdr nAction, const Point* pPt,
+ SotExchangeActionFlags nActionFlags,
+ bool * graphicInserted)
+{
+ bool bRet = SwTransferable::PasteGrf( rData, rSh, nFormat, nAction,
+ pPt, nActionFlags, 0, false);
+ if (graphicInserted != nullptr) {
+ *graphicInserted = bRet;
+ }
+ if( !bRet )
+ {
+ OUString sFile, sDesc;
+ if( rData.GetString( nFormat, sFile ) && !sFile.isEmpty() )
+ {
+#if HAVE_FEATURE_AVMEDIA
+ INetURLObject aMediaURL;
+
+ aMediaURL.SetSmartURL( sFile );
+ const OUString aMediaURLStr( aMediaURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+
+ if( ::avmedia::MediaWindow::isMediaURL( aMediaURLStr, ""/*TODO?*/ ) )
+ {
+ const SfxStringItem aMediaURLItem( SID_INSERT_AVMEDIA, aMediaURLStr );
+ rSh.GetView().GetViewFrame().GetDispatcher()->ExecuteList(
+ SID_INSERT_AVMEDIA, SfxCallMode::SYNCHRON,
+ { &aMediaURLItem });
+ }
+#else
+ if (false)
+ {
+ }
+#endif
+ else
+ {
+ bool bIsURLFile = SwTransferable::CheckForURLOrLNKFile( rData, sFile, &sDesc );
+
+ //Own FileFormat? --> insert, not for StarWriter/Web
+ OUString sFileURL = URIHelper::SmartRel2Abs(INetURLObject(), sFile, Link<OUString *, bool>(), false );
+ std::shared_ptr<const SfxFilter> pFlt = SwPasteSdr::SetAttr == nAction
+ ? nullptr : SwIoSystem::GetFileFilter(sFileURL);
+ if( pFlt && dynamic_cast< const SwWebDocShell *>( rSh.GetView().GetDocShell() ) == nullptr )
+ {
+ // and then pull up the insert-region-dialog
+ SwSectionData aSect(
+ SectionType::FileLink,
+ rSh.GetDoc()->GetUniqueSectionName() );
+ aSect.SetLinkFileName( sFileURL );
+ aSect.SetProtectFlag( true );
+
+ rSh.StartInsertRegionDialog( aSect ); // starts dialog asynchronously
+ bRet = true;
+ }
+ else if (SwPasteSdr::Insert == nAction && rData.HasFormat(SotClipboardFormatId::SIMPLE_FILE))
+ {
+ // insert file as OLE
+ PasteOLE(rData, rSh, nFormat, nActionFlags, nullptr == pPt);
+ }
+ else if( SwPasteSdr::SetAttr == nAction ||
+ ( bIsURLFile && SwPasteSdr::Insert == nAction ))
+ {
+ //we can insert foreign files as links after all
+
+ // first, make the URL absolute
+ INetURLObject aURL;
+ aURL.SetSmartProtocol( INetProtocol::File );
+ aURL.SetSmartURL( sFile );
+ sFile = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+ switch( rSh.GetObjCntTypeOfSelection() )
+ {
+ case OBJCNT_FLY:
+ case OBJCNT_GRF:
+ case OBJCNT_OLE:
+ {
+ SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
+ rSh.GetFlyFrameAttr( aSet );
+ SwFormatURL aURL2( aSet.Get( RES_URL ) );
+ aURL2.SetURL( sFile, false );
+ if( aURL2.GetName().isEmpty() )
+ aURL2.SetName( sFile );
+ aSet.Put( aURL2 );
+ rSh.SetFlyFrameAttr( aSet );
+ }
+ break;
+
+ default:
+ {
+ rSh.InsertURL( SwFormatINetFormat( sFile, OUString() ),
+ sDesc.isEmpty() ? sFile : sDesc );
+ }
+ }
+ bRet = true;
+ }
+ }
+ }
+ }
+ return bRet;
+}
+
+bool SwTransferable::PasteDBData( const TransferableDataHelper& rData,
+ SwWrtShell& rSh, SotClipboardFormatId nFormat, bool bLink,
+ const Point* pDragPt, bool bMsg )
+{
+ bool bRet = false;
+ OUString sText;
+ if( rData.GetString( nFormat, sText ) && !sText.isEmpty() )
+ {
+ sal_uInt16 nWh = SotClipboardFormatId::SBA_CTRLDATAEXCHANGE == nFormat
+ ? 0
+ : SotClipboardFormatId::SBA_DATAEXCHANGE == nFormat
+ ? (bLink
+ ? FN_QRY_MERGE_FIELD
+ : FN_QRY_INSERT)
+ : (bLink
+ ? 0
+ : FN_QRY_INSERT_FIELD );
+ const DataFlavorExVector& rVector = rData.GetDataFlavorExVector();
+ bool bHaveColumnDescriptor = OColumnTransferable::canExtractColumnDescriptor(rVector, ColumnTransferFormatFlags::COLUMN_DESCRIPTOR | ColumnTransferFormatFlags::CONTROL_EXCHANGE);
+ if ( SotClipboardFormatId::XFORMS == nFormat )
+ {
+ rSh.MakeDrawView();
+ FmFormView* pFmView = dynamic_cast<FmFormView*>( rSh.GetDrawView() );
+ if (pFmView && pDragPt)
+ {
+ OXFormsDescriptor aDesc = OXFormsTransferable::extractDescriptor(rData);
+ rtl::Reference<SdrObject> pObj = pFmView->CreateXFormsControl(aDesc);
+ if(pObj)
+ {
+ rSh.SwFEShell::InsertDrawObj( *pObj, *pDragPt );
+ }
+ }
+ }
+ else if( nWh )
+ {
+ std::unique_ptr<SfxUnoAnyItem> pConnectionItem;
+ std::unique_ptr<SfxUnoAnyItem> pCursorItem;
+ std::unique_ptr<SfxUnoAnyItem> pColumnItem;
+ std::unique_ptr<SfxUnoAnyItem> pSourceItem;
+ std::unique_ptr<SfxUnoAnyItem> pCommandItem;
+ std::unique_ptr<SfxUnoAnyItem> pCommandTypeItem;
+ std::unique_ptr<SfxUnoAnyItem> pColumnNameItem;
+ std::unique_ptr<SfxUnoAnyItem> pSelectionItem;
+
+ bool bDataAvailable = true;
+ ODataAccessDescriptor aDesc;
+ if(bHaveColumnDescriptor)
+ aDesc = OColumnTransferable::extractColumnDescriptor(rData);
+ else if(ODataAccessObjectTransferable::canExtractObjectDescriptor(rVector) )
+ aDesc = ODataAccessObjectTransferable::extractObjectDescriptor(rData);
+ else
+ bDataAvailable = false;
+
+ if ( bDataAvailable )
+ {
+ pConnectionItem.reset(new SfxUnoAnyItem(FN_DB_CONNECTION_ANY, aDesc[DataAccessDescriptorProperty::Connection]));
+ pColumnItem.reset(new SfxUnoAnyItem(FN_DB_COLUMN_ANY, aDesc[DataAccessDescriptorProperty::ColumnObject]));
+ pSourceItem.reset(new SfxUnoAnyItem(FN_DB_DATA_SOURCE_ANY, Any(aDesc.getDataSource())));
+ pCommandItem.reset(new SfxUnoAnyItem(FN_DB_DATA_COMMAND_ANY, aDesc[DataAccessDescriptorProperty::Command]));
+ pCommandTypeItem.reset(new SfxUnoAnyItem(FN_DB_DATA_COMMAND_TYPE_ANY, aDesc[DataAccessDescriptorProperty::CommandType]));
+ pColumnNameItem.reset(new SfxUnoAnyItem(FN_DB_DATA_COLUMN_NAME_ANY, aDesc[DataAccessDescriptorProperty::ColumnName]));
+ pSelectionItem.reset(new SfxUnoAnyItem(FN_DB_DATA_SELECTION_ANY, aDesc[DataAccessDescriptorProperty::Selection]));
+ pCursorItem.reset(new SfxUnoAnyItem(FN_DB_DATA_CURSOR_ANY, aDesc[DataAccessDescriptorProperty::Cursor]));
+ }
+
+ SwView& rView = rSh.GetView();
+ //force ::SelectShell
+ rView.StopShellTimer();
+
+ SfxStringItem aDataDesc( nWh, sText );
+ rView.GetViewFrame().GetDispatcher()->ExecuteList(
+ nWh, SfxCallMode::ASYNCHRON,
+ { &aDataDesc, pConnectionItem.get(), pColumnItem.get(),
+ pSourceItem.get(), pCommandItem.get(), pCommandTypeItem.get(),
+ pColumnNameItem.get(), pSelectionItem.get(),
+ pCursorItem.get() });
+ }
+ else
+ {
+ rSh.MakeDrawView();
+ FmFormView* pFmView = dynamic_cast<FmFormView*>( rSh.GetDrawView() );
+ if (pFmView && bHaveColumnDescriptor && pDragPt)
+ {
+ rtl::Reference<SdrObject> pObj = pFmView->CreateFieldControl( OColumnTransferable::extractColumnDescriptor(rData) );
+ if (pObj)
+ rSh.SwFEShell::InsertDrawObj( *pObj, *pDragPt );
+ }
+ }
+ bRet = true;
+ }
+ else if( bMsg )
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
+ VclMessageType::Info, VclButtonsType::Ok,
+ SwResId(STR_CLPBRD_FORMAT_ERROR)));
+ xBox->run();
+ }
+ return bRet;
+}
+
+bool SwTransferable::PasteFileList( const TransferableDataHelper& rData,
+ SwWrtShell& rSh, bool bLink,
+ const Point* pPt, bool bMsg )
+{
+ bool bRet = false;
+ FileList aFileList;
+ if( rData.GetFileList( SotClipboardFormatId::FILE_LIST, aFileList ) &&
+ aFileList.Count() )
+ {
+ SwPasteSdr nAct = bLink ? SwPasteSdr::SetAttr : SwPasteSdr::Insert;
+ OUString sFlyNm;
+ // iterate over the filelist
+ for( sal_uLong n = 0, nEnd = aFileList.Count(); n < nEnd; ++n )
+ {
+ rtl::Reference<TransferDataContainer> pHlp = new TransferDataContainer;
+ pHlp->CopyString( SotClipboardFormatId::SIMPLE_FILE, aFileList.GetFile( n ));
+ TransferableDataHelper aData( pHlp );
+
+ if( SwTransferable::PasteFileName( aData, rSh, SotClipboardFormatId::SIMPLE_FILE, nAct,
+ pPt, SotExchangeActionFlags::NONE, nullptr ))
+ {
+ if( bLink )
+ {
+ sFlyNm = rSh.GetFlyName();
+ SwTransferable::SetSelInShell( rSh, false, pPt );
+ }
+ bRet = true;
+ }
+ }
+ if( !sFlyNm.isEmpty() )
+ rSh.GotoFly( sFlyNm );
+ }
+ else if( bMsg )
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
+ VclMessageType::Info, VclButtonsType::Ok,
+ SwResId(STR_CLPBRD_FORMAT_ERROR)));
+ xBox->run();
+ }
+ return bRet;
+}
+
+bool SwTransferable::CheckForURLOrLNKFile( const TransferableDataHelper& rData,
+ OUString& rFileName, OUString* pTitle )
+{
+ bool bIsURLFile = false;
+ INetBookmark aBkmk;
+ if( rData.GetINetBookmark( SotClipboardFormatId::SOLK, aBkmk ) )
+ {
+ rFileName = aBkmk.GetURL();
+ if( pTitle )
+ *pTitle = aBkmk.GetDescription();
+ bIsURLFile = true;
+ }
+ else
+ {
+ if( rFileName.getLength()>4 && rFileName.endsWithIgnoreAsciiCase(".url") )
+ {
+ OSL_ENSURE( false, "how do we read today .URL - Files?" );
+ }
+ }
+ return bIsURLFile;
+}
+
+bool SwTransferable::IsPasteSpecial( const SwWrtShell& rWrtShell,
+ const TransferableDataHelper& rData )
+{
+ // we can paste-special if there's an entry in the paste-special-format list
+ SvxClipboardFormatItem aClipboardFormatItem(TypedWhichId<SvxClipboardFormatItem>(0));
+ FillClipFormatItem( rWrtShell, rData, aClipboardFormatItem);
+ return aClipboardFormatItem.Count() > 0;
+}
+
+bool SwTransferable::IsPasteOwnFormat( const TransferableDataHelper& rData )
+{
+ return ( GetSwTransferable( rData ) != nullptr );
+}
+
+bool SwTransferable::PasteFormat( SwWrtShell& rSh,
+ TransferableDataHelper& rData,
+ SotClipboardFormatId nFormat )
+{
+ SwWait aWait( *rSh.GetView().GetDocShell(), false );
+ bool bRet = false;
+
+ SotClipboardFormatId nPrivateFormat = SotClipboardFormatId::PRIVATE;
+ SwTransferable *pClipboard = GetSwTransferable( rData );
+ if( pClipboard &&
+ ((TransferBufferType::Document|TransferBufferType::Graphic|TransferBufferType::Ole) & pClipboard->m_eBufferType ))
+ nPrivateFormat = SotClipboardFormatId::EMBED_SOURCE;
+
+ if( pClipboard && nPrivateFormat == nFormat )
+ bRet = pClipboard->PrivatePaste( rSh );
+ else if( rData.HasFormat( nFormat ) )
+ {
+ uno::Reference<XTransferable> xTransferable( rData.GetXTransferable() );
+ sal_uInt8 nEventAction;
+ SotExchangeDest nDestination = SwTransferable::GetSotDestination( rSh );
+ sal_uInt16 nSourceOptions =
+ (( SotExchangeDest::DOC_TEXTFRAME == nDestination ||
+ SotExchangeDest::SWDOC_FREE_AREA == nDestination ||
+ SotExchangeDest::DOC_TEXTFRAME_WEB == nDestination ||
+ SotExchangeDest::SWDOC_FREE_AREA_WEB == nDestination )
+ ? EXCHG_IN_ACTION_COPY
+ : EXCHG_IN_ACTION_MOVE);
+ SotExchangeActionFlags nActionFlags;
+ sal_uInt8 nAction = SotExchange::GetExchangeAction(
+ rData.GetDataFlavorExVector(),
+ nDestination,
+ nSourceOptions, /* ?? */
+ EXCHG_IN_ACTION_DEFAULT, /* ?? */
+ nFormat, nEventAction, nFormat,
+ lcl_getTransferPointer ( xTransferable ),
+ &nActionFlags );
+
+ if( EXCHG_INOUT_ACTION_NONE != nAction )
+ bRet = SwTransferable::PasteData( rData, rSh, nAction, nActionFlags, nFormat,
+ nDestination, true, false );
+ }
+ return bRet;
+}
+
+bool SwTransferable::TestAllowedFormat( const TransferableDataHelper& rData,
+ SotClipboardFormatId nFormat, SotExchangeDest nDestination )
+{
+ sal_uInt8 nAction = EXCHG_INOUT_ACTION_NONE;
+ if( rData.HasFormat( nFormat )) {
+ uno::Reference<XTransferable> xTransferable( rData.GetXTransferable() );
+ sal_uInt8 nEventAction;
+ nAction = SotExchange::GetExchangeAction(
+ rData.GetDataFlavorExVector(),
+ nDestination, EXCHG_IN_ACTION_COPY,
+ EXCHG_IN_ACTION_COPY, nFormat,
+ nEventAction, nFormat,
+ lcl_getTransferPointer ( xTransferable ) );
+ }
+ return EXCHG_INOUT_ACTION_NONE != nAction;
+}
+
+/**
+ * the list of formats which will be offered to the user in the 'Paste
+ * Special...' dialog and the paste button menu
+ */
+static SotClipboardFormatId aPasteSpecialIds[] =
+{
+ SotClipboardFormatId::HTML,
+ SotClipboardFormatId::HTML_SIMPLE,
+ SotClipboardFormatId::HTML_NO_COMMENT,
+ SotClipboardFormatId::RTF,
+ SotClipboardFormatId::RICHTEXT,
+ SotClipboardFormatId::STRING,
+ SotClipboardFormatId::SONLK,
+ SotClipboardFormatId::NETSCAPE_BOOKMARK,
+ SotClipboardFormatId::DRAWING,
+ SotClipboardFormatId::SVXB,
+ SotClipboardFormatId::GDIMETAFILE,
+ SotClipboardFormatId::BITMAP,
+ SotClipboardFormatId::SVIM,
+ SotClipboardFormatId::FILEGRPDESCRIPTOR,
+ SotClipboardFormatId::NONE
+};
+
+bool SwTransferable::PasteUnformatted( SwWrtShell& rSh, TransferableDataHelper& rData )
+{
+ // Plain text == unformatted
+ return SwTransferable::PasteFormat( rSh, rData, SotClipboardFormatId::STRING );
+}
+
+void SwTransferable::PrePasteSpecial( const SwWrtShell& rSh, TransferableDataHelper& rData, const VclPtr<SfxAbstractPasteDialog>& pDlg )
+{
+ DataFlavorExVector aFormats( rData.GetDataFlavorExVector() );
+ TransferableObjectDescriptor aDesc;
+
+ SotExchangeDest nDest = SwTransferable::GetSotDestination( rSh );
+
+ SwTransferable *pClipboard = GetSwTransferable( rData );
+ if( pClipboard )
+ {
+ aDesc = pClipboard->m_aObjDesc;
+ TranslateId pResId;
+ if( pClipboard->m_eBufferType & TransferBufferType::Document )
+ pResId = STR_PRIVATETEXT;
+ else if( pClipboard->m_eBufferType & TransferBufferType::Graphic )
+ pResId = STR_PRIVATEGRAPHIC;
+ else if( pClipboard->m_eBufferType == TransferBufferType::Ole )
+ pResId = STR_PRIVATEOLE;
+
+ if (pResId)
+ {
+ if (STR_PRIVATEOLE == pResId || STR_PRIVATEGRAPHIC == pResId)
+ {
+ // add SotClipboardFormatId::EMBED_SOURCE to the formats. This
+ // format display then the private format name.
+ DataFlavorEx aFlavorEx;
+ aFlavorEx.mnSotId = SotClipboardFormatId::EMBED_SOURCE;
+ aFormats.insert( aFormats.begin(), aFlavorEx );
+ }
+ pDlg->SetObjName( pClipboard->m_aObjDesc.maClassName,
+ SwResId(pResId) );
+ pDlg->Insert( SotClipboardFormatId::EMBED_SOURCE, OUString() );
+ }
+ }
+ else
+ {
+ if( rData.HasFormat( SotClipboardFormatId::OBJECTDESCRIPTOR ) )
+ {
+ (void)rData.GetTransferableObjectDescriptor(
+ SotClipboardFormatId::OBJECTDESCRIPTOR, aDesc );
+ }
+
+ if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::EMBED_SOURCE, nDest ))
+ pDlg->Insert( SotClipboardFormatId::EMBED_SOURCE, OUString() );
+ if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::LINK_SOURCE, nDest ))
+ pDlg->Insert( SotClipboardFormatId::LINK_SOURCE, OUString() );
+ }
+
+ if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::LINK, nDest ))
+ pDlg->Insert( SotClipboardFormatId::LINK, SwResId(STR_DDEFORMAT) );
+
+ for( SotClipboardFormatId* pIds = aPasteSpecialIds; *pIds != SotClipboardFormatId::NONE; ++pIds )
+ if( SwTransferable::TestAllowedFormat( rData, *pIds, nDest ))
+ pDlg->Insert( *pIds, OUString() );
+}
+
+void SwTransferable::FillClipFormatItem( const SwWrtShell& rSh,
+ const TransferableDataHelper& rData,
+ SvxClipboardFormatItem & rToFill )
+{
+ SotExchangeDest nDest = SwTransferable::GetSotDestination( rSh );
+
+ SwTransferable *pClipboard = GetSwTransferable( rData );
+ if( pClipboard )
+ {
+ TranslateId pResId;
+ if( pClipboard->m_eBufferType & TransferBufferType::Document )
+ pResId = STR_PRIVATETEXT;
+ else if( pClipboard->m_eBufferType & TransferBufferType::Graphic )
+ pResId = STR_PRIVATEGRAPHIC;
+ else if( pClipboard->m_eBufferType == TransferBufferType::Ole )
+ pResId = STR_PRIVATEOLE;
+
+ if (pResId)
+ rToFill.AddClipbrdFormat(SotClipboardFormatId::EMBED_SOURCE,
+ SwResId(pResId));
+ }
+ else
+ {
+ TransferableObjectDescriptor aDesc;
+ if (rData.HasFormat(SotClipboardFormatId::OBJECTDESCRIPTOR))
+ {
+ (void)rData.GetTransferableObjectDescriptor(
+ SotClipboardFormatId::OBJECTDESCRIPTOR, aDesc);
+ }
+
+ if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::EMBED_SOURCE, nDest ))
+ rToFill.AddClipbrdFormat( SotClipboardFormatId::EMBED_SOURCE,
+ aDesc.maTypeName );
+ if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::LINK_SOURCE, nDest ))
+ rToFill.AddClipbrdFormat( SotClipboardFormatId::LINK_SOURCE );
+
+ SotClipboardFormatId nFormat;
+ if ( rData.HasFormat(nFormat = SotClipboardFormatId::EMBED_SOURCE_OLE) || rData.HasFormat(nFormat = SotClipboardFormatId::EMBEDDED_OBJ_OLE) )
+ {
+ OUString sName,sSource;
+ if ( SvPasteObjectHelper::GetEmbeddedName(rData,sName,sSource,nFormat) )
+ rToFill.AddClipbrdFormat( nFormat, sName );
+ }
+ }
+
+ if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::LINK, nDest ))
+ rToFill.AddClipbrdFormat( SotClipboardFormatId::LINK, SwResId(STR_DDEFORMAT) );
+
+ for( SotClipboardFormatId* pIds = aPasteSpecialIds; *pIds != SotClipboardFormatId::NONE; ++pIds )
+ if( SwTransferable::TestAllowedFormat( rData, *pIds, nDest ))
+ rToFill.AddClipbrdFormat(*pIds, OUString());
+}
+
+void SwTransferable::SetDataForDragAndDrop( const Point& rSttPos )
+{
+ if(!m_pWrtShell)
+ return;
+ OUString sGrfNm;
+ const SelectionType nSelection = m_pWrtShell->GetSelectionType();
+ if( SelectionType::Graphic == nSelection)
+ {
+ AddFormat( SotClipboardFormatId::SVXB );
+ const Graphic* pGrf = m_pWrtShell->GetGraphic();
+ if ( pGrf && pGrf->IsSupportedGraphic() )
+ {
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ AddFormat( SotClipboardFormatId::PNG );
+ AddFormat( SotClipboardFormatId::BITMAP );
+ }
+ m_eBufferType = TransferBufferType::Graphic;
+ m_pWrtShell->GetGrfNms( &sGrfNm, nullptr );
+ }
+ else if( SelectionType::Ole == nSelection )
+ {
+ AddFormat( SotClipboardFormatId::EMBED_SOURCE );
+ PrepareOLE( m_aObjDesc );
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ m_eBufferType = TransferBufferType::Ole;
+ }
+ //Is there anything to provide anyway?
+ else if ( m_pWrtShell->IsSelection() || m_pWrtShell->IsFrameSelected() ||
+ m_pWrtShell->IsObjSelected() )
+ {
+ if( m_pWrtShell->IsObjSelected() )
+ m_eBufferType = TransferBufferType::Drawing;
+ else
+ {
+ m_eBufferType = TransferBufferType::Document;
+ if( SwWrtShell::NO_WORD !=
+ m_pWrtShell->IntelligentCut( nSelection, false ))
+ m_eBufferType = TransferBufferType::DocumentWord | m_eBufferType;
+ }
+
+ if( nSelection & SelectionType::TableCell )
+ m_eBufferType = TransferBufferType::Table | m_eBufferType;
+
+ AddFormat( SotClipboardFormatId::EMBED_SOURCE );
+
+ //put RTF ahead of the OLE's Metafile for less loss
+ if( !m_pWrtShell->IsObjSelected() )
+ {
+ AddFormat( SotClipboardFormatId::RTF );
+ AddFormat( SotClipboardFormatId::RICHTEXT );
+ AddFormat( SotClipboardFormatId::HTML );
+ }
+ if( m_pWrtShell->IsSelection() )
+ AddFormat( SotClipboardFormatId::STRING );
+
+ if( nSelection & ( SelectionType::DrawObject | SelectionType::DbForm ))
+ {
+ AddFormat( SotClipboardFormatId::DRAWING );
+ if ( nSelection & SelectionType::DrawObject )
+ {
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ AddFormat( SotClipboardFormatId::PNG );
+ AddFormat( SotClipboardFormatId::BITMAP );
+ }
+ m_eBufferType = TransferBufferType::Graphic | m_eBufferType;
+
+ // is it a URL-Button ?
+ OUString sURL;
+ OUString sDesc;
+ if( m_pWrtShell->GetURLFromButton( sURL, sDesc ) )
+ {
+ AddFormat( SotClipboardFormatId::STRING );
+ AddFormat( SotClipboardFormatId::SOLK );
+ AddFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK );
+ AddFormat( SotClipboardFormatId::FILECONTENT );
+ AddFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR );
+ m_eBufferType = TransferBufferType::InetField | m_eBufferType;
+ }
+ }
+
+ //ObjectDescriptor was already filled from the old DocShell.
+ //Now adjust it. Thus in GetData the first query can still
+ //be answered with delayed rendering.
+ m_aObjDesc.maDragStartPos = rSttPos;
+ m_aObjDesc.maSize = constOleSize100mm;
+
+ PrepareOLE( m_aObjDesc );
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+ }
+ else if( nSelection & SelectionType::Text && !m_pWrtShell->HasMark() )
+ {
+ // is only one field - selected?
+ SwContentAtPos aContentAtPos( IsAttrAtPos::InetAttr );
+ Point aPos( SwEditWin::GetDDStartPosX(), SwEditWin::GetDDStartPosY());
+
+ if( m_pWrtShell->GetContentAtPos( aPos, aContentAtPos ) )
+ {
+ AddFormat( SotClipboardFormatId::STRING );
+ AddFormat( SotClipboardFormatId::SOLK );
+ AddFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK );
+ AddFormat( SotClipboardFormatId::FILECONTENT );
+ AddFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR );
+ m_eBufferType = TransferBufferType::InetField;
+ }
+ }
+
+ if( !m_pWrtShell->IsFrameSelected() )
+ return;
+
+ SfxItemSetFixed<RES_URL, RES_URL> aSet( m_pWrtShell->GetAttrPool() );
+ m_pWrtShell->GetFlyFrameAttr( aSet );
+ const SwFormatURL& rURL = aSet.Get( RES_URL );
+ if( rURL.GetMap() )
+ {
+ m_pImageMap.reset( new ImageMap( *rURL.GetMap() ) );
+ AddFormat( SotClipboardFormatId::SVIM );
+ }
+ else if( !rURL.GetURL().isEmpty() )
+ {
+ m_pTargetURL.reset(new INetImage( sGrfNm, rURL.GetURL(),
+ rURL.GetTargetFrameName() ));
+ AddFormat( SotClipboardFormatId::INET_IMAGE );
+ }
+}
+
+void SwTransferable::StartDrag( vcl::Window* pWin, const Point& rPos )
+{
+ if(!m_pWrtShell)
+ return;
+ m_bOldIdle = m_pWrtShell->GetViewOptions()->IsIdle();
+ m_bCleanUp = true;
+
+ m_pWrtShell->GetViewOptions()->SetIdle( false );
+
+ if( m_pWrtShell->IsSelFrameMode() )
+ m_pWrtShell->ShowCursor();
+
+ SW_MOD()->m_pDragDrop = this;
+
+ SetDataForDragAndDrop( rPos );
+
+ sal_Int8 nDragOptions = DND_ACTION_COPYMOVE | DND_ACTION_LINK;
+ SwDocShell* pDShell = m_pWrtShell->GetView().GetDocShell();
+ if( ( pDShell && pDShell->IsReadOnly() ) || m_pWrtShell->HasReadonlySel() )
+ nDragOptions &= ~DND_ACTION_MOVE;
+
+ TransferableHelper::StartDrag( pWin, nDragOptions );
+}
+
+void SwTransferable::DragFinished( sal_Int8 nAction )
+{
+ //And the last finishing work so that all statuses are right
+ if( DND_ACTION_MOVE == nAction )
+ {
+ if( m_bCleanUp )
+ {
+ //It was dropped outside of Writer. We still have to
+ //delete.
+
+ m_pWrtShell->StartAllAction();
+ m_pWrtShell->StartUndo( SwUndoId::UI_DRAG_AND_MOVE );
+ if ( m_pWrtShell->IsTableMode() )
+ m_pWrtShell->DeleteTableSel();
+ else
+ {
+ if ( !(m_pWrtShell->IsSelFrameMode() || m_pWrtShell->IsObjSelected()) )
+ //SmartCut, take one of the blanks along
+ m_pWrtShell->IntelligentCut( m_pWrtShell->GetSelectionType() );
+ m_pWrtShell->DelRight();
+ }
+ m_pWrtShell->EndUndo( SwUndoId::UI_DRAG_AND_MOVE );
+ m_pWrtShell->EndAllAction();
+ }
+ else
+ {
+ const SelectionType nSelection = m_pWrtShell->GetSelectionType();
+ if( ( SelectionType::Frame | SelectionType::Graphic |
+ SelectionType::Ole | SelectionType::DrawObject ) & nSelection )
+ {
+ m_pWrtShell->EnterSelFrameMode();
+ }
+ }
+ }
+ m_pWrtShell->GetView().GetEditWin().DragFinished();
+
+ if( m_pWrtShell->IsSelFrameMode() )
+ m_pWrtShell->HideCursor();
+ else
+ m_pWrtShell->ShowCursor();
+
+ m_pWrtShell->GetViewOptions()->SetIdle( m_bOldIdle );
+}
+
+namespace
+{
+
+bool lcl_checkClassification(SwDoc* pSourceDoc, SwDoc* pDestinationDoc)
+{
+ if (!pSourceDoc || !pDestinationDoc)
+ return true;
+
+ SwDocShell* pSourceShell = pSourceDoc->GetDocShell();
+ SwDocShell* pDestinationShell = pDestinationDoc->GetDocShell();
+ if (!pSourceShell || !pDestinationShell)
+ return true;
+
+ SfxClassificationCheckPasteResult eResult = SfxClassificationHelper::CheckPaste(pSourceShell->getDocProperties(), pDestinationShell->getDocProperties());
+ return SfxClassificationHelper::ShowPasteInfo(eResult);
+}
+
+}
+
+bool SwTransferable::PrivatePaste(SwWrtShell& rShell, SwPasteContext* pContext, PasteTableType ePasteTable)
+{
+ // first, ask for the SelectionType, then action-bracketing !!!!
+ // (otherwise it's not pasted into a TableSelection!!!)
+ OSL_ENSURE( !rShell.ActionPend(), "Paste must never have an ActionPend" );
+ if ( !m_pClpDocFac )
+ return false; // the return value of the SwFEShell::Paste also is bool!
+
+ const SelectionType nSelection = rShell.GetSelectionType();
+
+ SwTrnsfrActionAndUndo aAction( &rShell );
+
+ bool bKillPaMs = false;
+
+ //Delete selected content, not at table-selection and table in Clipboard, and don't delete hovering graphics.
+ if( rShell.HasSelection() && !( nSelection & SelectionType::TableCell) && !( nSelection & SelectionType::DrawObject))
+ {
+ if (!(nSelection & SelectionType::NumberList))
+ {
+ bKillPaMs = true;
+ rShell.SetRetainSelection( true );
+ }
+ if (pContext)
+ pContext->forget();
+ rShell.DelRight();
+ if (pContext)
+ pContext->remember();
+ // when a Fly was selected, a valid cursor position has to be found now
+ // (parked Cursor!)
+ if( ( SelectionType::Frame | SelectionType::Graphic |
+ SelectionType::Ole | SelectionType::DrawObject |
+ SelectionType::DbForm ) & nSelection )
+ {
+ // position the cursor again
+ Point aPt( rShell.GetCharRect().Pos() );
+ rShell.SwCursorShell::SetCursor( aPt, true );
+ }
+ if (!(nSelection & SelectionType::NumberList))
+ {
+ rShell.SetRetainSelection( false );
+ }
+ }
+ if ( nSelection & SelectionType::DrawObject) //unselect hovering graphics
+ {
+ rShell.ResetSelect(nullptr,false);
+ }
+
+ bool bInWrd = false, bEndWrd = false, bSttWrd = false,
+ bSmart(TransferBufferType::DocumentWord & m_eBufferType);
+ if( bSmart )
+ {
+ // Why not for other Scripts? If TransferBufferType::DocumentWord is set, we have a word
+ // in the buffer, word in this context means 'something with spaces at beginning
+ // and end'. In this case we definitely want these spaces to be inserted here.
+ bInWrd = rShell.IsInWord();
+ bEndWrd = rShell.IsEndWrd();
+ bSmart = bInWrd || bEndWrd;
+ if( bSmart )
+ {
+ bSttWrd = rShell.IsStartWord();
+ if (!bSttWrd && (bInWrd || bEndWrd))
+ rShell.SwEditShell::Insert(' ');
+ }
+ }
+
+ 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(), ePasteTable == PasteTableType::PASTE_TABLE);
+
+ if( bKillPaMs )
+ rShell.KillPams();
+
+ // If Smart Paste then insert blank
+ if( bRet && bSmart && ((bInWrd && !bEndWrd )|| bSttWrd) )
+ rShell.SwEditShell::Insert(' ');
+
+ return bRet;
+}
+
+bool SwTransferable::PrivateDrop( SwWrtShell& rSh, const Point& rDragPt,
+ bool bMove, bool bIsXSelection )
+{
+ int cWord = 0;
+ bool bInWrd = false;
+ bool bEndWrd = false;
+ bool bSttWrd = false;
+ bool bSttPara = false;
+ bool bTableSel = false;
+ bool bTableMove = false;
+ bool bFrameSel = false;
+
+ SwWrtShell& rSrcSh = *GetShell();
+
+ rSh.UnSetVisibleCursor();
+
+ if( TransferBufferType::InetField == m_eBufferType )
+ {
+ if( rSh.GetFormatFromObj( rDragPt ) )
+ {
+ INetBookmark aTmp;
+ if( (TransferBufferType::InetField & m_eBufferType) && m_oBookmark )
+ aTmp = *m_oBookmark;
+
+ // select target graphic
+ if( rSh.SelectObj( rDragPt ) )
+ {
+ rSh.HideCursor();
+ rSh.EnterSelFrameMode( &rDragPt );
+ g_bFrameDrag = true;
+ }
+
+ const SelectionType nSelection = rSh.GetSelectionType();
+
+ // not yet consider Draw objects
+ if( SelectionType::Graphic & nSelection )
+ {
+ SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
+ rSh.GetFlyFrameAttr( aSet );
+ SwFormatURL aURL( aSet.Get( RES_URL ) );
+ aURL.SetURL( aTmp.GetURL(), false );
+ aSet.Put( aURL );
+ rSh.SetFlyFrameAttr( aSet );
+ return true;
+ }
+
+ if( SelectionType::DrawObject & nSelection )
+ {
+ rSh.LeaveSelFrameMode();
+ rSh.UnSelectFrame();
+ rSh.ShowCursor();
+ g_bFrameDrag = false;
+ }
+ }
+ }
+
+ if( &rSh != &rSrcSh && (SelectionType::Graphic & rSh.GetSelectionType()) &&
+ TransferBufferType::Graphic == m_eBufferType )
+ {
+ // ReRead the graphic
+ OUString sGrfNm;
+ OUString sFltNm;
+ rSrcSh.GetGrfNms( &sGrfNm, &sFltNm );
+ rSh.ReRead( sGrfNm, sFltNm, rSrcSh.GetGraphic() );
+ return true;
+ }
+
+ //not in selections or selected frames
+ if( rSh.TestCurrPam( rDragPt ) ||
+ ( rSh.IsSelFrameMode() && rSh.IsInsideSelectedObj( rDragPt )) )
+ return false;
+
+ if( rSrcSh.IsTableMode() )
+ {
+ bTableSel = true;
+ const SelectionType nSelection = rSrcSh.GetSelectionType();
+ // at enhanced table row/column selection or wholly selected tables,
+ // paste rows above or columns before, and in the case of moving, remove the selection
+ // (limit only to the single document case temporarily)
+ if( rSrcSh.GetDoc() == rSh.GetDoc() &&
+ ( (( SelectionType::TableRow | SelectionType::TableCol) & nSelection ) || rSrcSh.HasWholeTabSelection() ) )
+ {
+ bool bTableCol(SelectionType::TableCol & nSelection);
+
+ ::sw::mark::IMark* pMarkMoveFrom = bMove
+ ? rSh.SetBookmark(
+ vcl::KeyCode(),
+ OUString(),
+ IDocumentMarkAccess::MarkType::UNO_BOOKMARK )
+ : nullptr;
+
+ // row count and direction of the table selection:
+ // up to down, if the cursor is there in its last table row
+ const SwSelBoxes& rBoxes = rSrcSh.GetTableCursor()->GetSelectedBoxes();
+ const SwTableNode* pTableNd = rSh.IsCursorInTable();
+ if (!pTableNd)
+ {
+ SAL_WARN("sw", "presumably this case can't arise in practice");
+ return false;
+ }
+ const SwTableLines& rLines = pTableNd->GetTable().GetTabLines();
+ const SwStartNode& rDelPos = rBoxes.back()
+ ? *rBoxes.front()->GetSttNd()
+ : *pTableNd->GetStartNode();
+
+ // count selected rows or columns
+ sal_Int32 nSelRowOrCols = 0;
+ if ( rBoxes.back() )
+ {
+ if ( bTableCol )
+ {
+ // selected column count is the count of the cells
+ // in the first row of the selection
+ auto nLine = rLines.GetPos( rBoxes.front()->GetUpper() );
+ for (auto pBox : rBoxes)
+ {
+ // cell is in the next row
+ if ( nLine != rLines.GetPos( pBox->GetUpper() ) )
+ break;
+ ++nSelRowOrCols;
+ }
+ }
+ else
+ {
+ // selected row count is the difference of the row number of the
+ // first and the last cell of the selection
+ nSelRowOrCols = rLines.GetPos( rBoxes.back()->GetUpper() ) -
+ rLines.GetPos( rBoxes.front()->GetUpper() ) + 1;
+ }
+ }
+
+ bool bSelUpToDown = rBoxes.back() && rBoxes.back()->GetUpper() ==
+ rSh.GetCursor()->GetPointNode().GetTableBox()->GetUpper();
+
+ SwUndoId eUndoId = bMove ? SwUndoId::UI_DRAG_AND_MOVE : SwUndoId::UI_DRAG_AND_COPY;
+
+ SwRewriter aRewriter;
+
+ aRewriter.AddRule(UndoArg1, rSrcSh.GetSelDescr());
+
+ if(rSrcSh.GetDoc() != rSh.GetDoc())
+ rSrcSh.StartUndo( eUndoId, &aRewriter );
+ rSh.StartUndo( eUndoId, &aRewriter );
+
+ rSh.StartAction();
+ rSrcSh.StartAction();
+
+ SfxDispatcher* pDispatch = rSrcSh.GetView().GetViewFrame().GetDispatcher();
+ pDispatch->Execute(SID_COPY, SfxCallMode::SYNCHRON);
+
+ rSrcSh.Push(); // save selection for later restoration
+ rSh.EnterStdMode();
+ rSh.SwCursorShell::SetCursor(rDragPt, false);
+
+ bool bPasteIntoTable = rSh.GetCursor()->GetPointNode().GetTableBox() != nullptr;
+
+ // store cursor
+ ::sw::mark::IMark* pMark = rSh.SetBookmark(
+ vcl::KeyCode(),
+ OUString(),
+ IDocumentMarkAccess::MarkType::UNO_BOOKMARK );
+
+ // paste rows above/columns before
+ pDispatch->Execute(bTableCol ? FN_TABLE_PASTE_COL_BEFORE : FN_TABLE_PASTE_ROW_BEFORE, SfxCallMode::SYNCHRON);
+
+ // go to the previously inserted table rows and set them to tracked insertion, if needed
+ bool bNeedTrack = !bTableCol && rSh.getIDocumentRedlineAccess().IsRedlineOn();
+
+ // restore cursor position
+ if (bNeedTrack && pMark != nullptr)
+ rSh.GotoMark( pMark );
+
+ if ( !bNeedTrack && !bPasteIntoTable )
+ {
+ rSrcSh.Pop(SwCursorShell::PopMode::DeleteCurrent); // restore selection...
+
+ // delete source rows/columns
+ if (bMove)
+ pDispatch->Execute(bTableCol
+ ? FN_TABLE_DELETE_COL
+ : FN_TABLE_DELETE_ROW, SfxCallMode::SYNCHRON);
+ }
+ else
+ {
+ const SwTableBox* pBoxStt = rSh.GetCursor()->GetPointNode().GetTableBox();
+ SwTableLine* pLine = pBoxStt ? const_cast<SwTableLine*>( pBoxStt->GetUpper()): nullptr;
+
+ for (sal_Int32 nDeleted = 0; bNeedTrack && nDeleted < nSelRowOrCols;)
+ {
+ // move up text cursor (note: "true" is important for the layout level)
+ if ( !rSh.Up(false) )
+ break;
+
+ const SwTableBox* pBox = rSh.GetCursor()->GetPointNode().GetTableBox();
+
+ if ( !pBox )
+ break;
+
+ // Up() reaches a new row
+ if ( pBox->GetUpper() != pLine )
+ {
+ //rSh.SelTableRow();
+ SvxPrintItem aTracked(RES_PRINT, false);
+ rSh.GetDoc()->SetRowNotTracked( *rSh.GetCursor(), aTracked );
+ ++nDeleted;
+ pLine = const_cast<SwTableLine*>(pBox->GetUpper());
+ }
+ }
+
+ rSrcSh.Pop(SwCursorShell::PopMode::DeleteCurrent); // restore selection...
+
+ // delete source rows/columns
+ if (bMove)
+ {
+ // restore cursor position
+ if (pMarkMoveFrom != nullptr)
+ {
+ rSh.GotoMark( pMarkMoveFrom );
+ rSh.getIDocumentMarkAccess()->deleteMark( pMarkMoveFrom );
+ }
+
+ // tracked table row moving: set original rows as tracked deletion,
+ // otherwise delete original rows/columns (tracking column deletion
+ // and insertion is not supported yet)
+ if ( !bTableCol && bNeedTrack )
+ {
+ pLine = nullptr;
+
+ for (sal_Int32 nDeleted = 0; nDeleted < nSelRowOrCols;)
+ {
+ const SwTableBox* pBox = rSh.GetCursor()->GetPointNode().GetTableBox();
+
+ if ( !pBox )
+ break;
+
+ if ( pBox->GetUpper() != pLine )
+ {
+ pLine = const_cast<SwTableLine*>(pBox->GetUpper());
+ pDispatch->Execute(FN_TABLE_DELETE_ROW, SfxCallMode::SYNCHRON);
+ ++nDeleted;
+ }
+
+ bool bMoved = false;
+ if (bSelUpToDown)
+ bMoved = rSh.Up(false);
+ else
+ bMoved = rSh.Down(false);
+ if (!bMoved)
+ break;
+ }
+ }
+ else
+ {
+ // set cursor in the first cell of the original selection
+ rSh.GetCursor()->DeleteMark();
+ rSh.GetCursor()->GetPoint()->Assign( rDelPos.GetIndex() + 1);
+
+ for (sal_Int32 nDeleted = 0; nDeleted < nSelRowOrCols; ++nDeleted)
+ {
+ pDispatch->Execute(bTableCol
+ ? FN_TABLE_DELETE_COL
+ : FN_TABLE_DELETE_ROW, SfxCallMode::SYNCHRON);
+ }
+ }
+ }
+ }
+
+ // restore cursor position
+ if (pMark != nullptr)
+ {
+ rSh.GotoMark( pMark );
+ rSh.getIDocumentMarkAccess()->deleteMark( pMark );
+ }
+
+ rSh.DestroyCursor();
+ rSh.EndUndo();
+ rSh.EndAction();
+ rSh.EndAction();
+ return true;
+ }
+
+ if ( bMove && rSrcSh.HasWholeTabSelection() )
+ bTableMove = true;
+ }
+ else if( rSrcSh.IsSelFrameMode() || rSrcSh.IsObjSelected() )
+ {
+ // don't move position-protected objects!
+ if( bMove && rSrcSh.IsSelObjProtected( FlyProtectFlags::Pos ) != FlyProtectFlags::NONE )
+ return false;
+
+ bFrameSel = true;
+ }
+
+ const SelectionType nSel = rSrcSh.GetSelectionType();
+
+ SwUndoId eUndoId = bMove ? SwUndoId::UI_DRAG_AND_MOVE : SwUndoId::UI_DRAG_AND_COPY;
+
+ SwRewriter aRewriter;
+
+ aRewriter.AddRule(UndoArg1, rSrcSh.GetSelDescr());
+
+ if(rSrcSh.GetDoc() != rSh.GetDoc())
+ rSrcSh.StartUndo( eUndoId, &aRewriter );
+ rSh.StartUndo( eUndoId, &aRewriter );
+
+ rSh.StartAction();
+ rSrcSh.StartAction();
+
+ if( &rSrcSh != &rSh )
+ {
+ rSh.EnterStdMode();
+ rSh.SwCursorShell::SetCursor( rDragPt, true );
+ cWord = rSrcSh.IntelligentCut( nSel, false );
+ }
+ else if( !bTableSel && !bFrameSel )
+ {
+ if( !rSh.IsAddMode() )
+ {
+ // #i87233#
+ if ( rSh.IsBlockMode() )
+ {
+ // preserve order of cursors for block mode
+ rSh.GoPrevCursor();
+ }
+
+ rSh.SwCursorShell::CreateCursor();
+ }
+ rSh.SwCursorShell::SetCursor( rDragPt, true, false );
+ rSh.GoPrevCursor();
+ cWord = rSh.IntelligentCut( rSh.GetSelectionType(), false );
+ rSh.GoNextCursor();
+ }
+
+ bInWrd = rSh.IsInWord();
+ bEndWrd = rSh.IsEndWrd();
+ bSttWrd = !bEndWrd && rSh.IsStartWord();
+ bSttPara= rSh.IsSttPara();
+
+ Point aSttPt( SwEditWin::GetDDStartPosX(), SwEditWin::GetDDStartPosY() );
+
+ // at first, select InetFields!
+ if( TransferBufferType::InetField == m_eBufferType )
+ {
+ if( &rSrcSh == &rSh )
+ {
+ rSh.GoPrevCursor();
+ rSh.SwCursorShell::SetCursor( aSttPt, true );
+ rSh.SelectTextAttr( RES_TXTATR_INETFMT );
+ if( rSh.TestCurrPam( rDragPt ) )
+ {
+ // don't copy/move inside of yourself
+ rSh.DestroyCursor();
+ rSh.EndUndo();
+ rSh.EndAction();
+ rSh.EndAction();
+ return false;
+ }
+ rSh.GoNextCursor();
+ }
+ else
+ {
+ rSrcSh.SwCursorShell::SetCursor( aSttPt, true );
+ rSrcSh.SelectTextAttr( RES_TXTATR_INETFMT );
+ }
+
+ // is there a URL attribute at the insert point? Then replace that,
+ // so simply put up a selection?
+ rSh.DelINetAttrWithText();
+ g_bDDINetAttr = true;
+ }
+
+ if ( rSrcSh.IsSelFrameMode() )
+ {
+ //Hack: fool the special treatment
+ aSttPt = rSrcSh.GetObjRect().Pos();
+ }
+
+ bool bRet = rSrcSh.SwFEShell::Copy(rSh, aSttPt, rDragPt, bMove,
+ !bIsXSelection);
+
+ if( !bIsXSelection )
+ {
+ rSrcSh.Push();
+ if ( bRet && bMove && !bFrameSel )
+ {
+ if ( bTableSel )
+ {
+ /* delete table contents not cells */
+ rSrcSh.Delete(false);
+ }
+ else
+ {
+ //SmartCut, take one of the blanks along.
+ rSh.SwCursorShell::DestroyCursor();
+ if ( cWord == SwWrtShell::WORD_SPACE_BEFORE )
+ rSh.ExtendSelection( false );
+ else if ( cWord == SwWrtShell::WORD_SPACE_AFTER )
+ rSh.ExtendSelection();
+ rSrcSh.DelRight();
+ }
+ }
+ rSrcSh.KillPams();
+ rSrcSh.Pop(SwCursorShell::PopMode::DeleteCurrent);
+
+ /* after dragging a table selection inside one shell
+ set cursor to the drop position. */
+ if( &rSh == &rSrcSh && ( bTableSel || rSh.IsBlockMode() ) )
+ {
+ rSrcSh.CalcLayout();
+ rSrcSh.SwCursorShell::SetCursor(rDragPt);
+ rSrcSh.GetCursor()->SetMark();
+ }
+ }
+
+ if( bRet && !bTableSel && !bFrameSel )
+ {
+ if( (bInWrd || bEndWrd) &&
+ (cWord == SwWrtShell::WORD_SPACE_AFTER ||
+ cWord == SwWrtShell::WORD_SPACE_BEFORE) )
+ {
+ if ( bSttWrd || (bInWrd && !bEndWrd))
+ rSh.SwEditShell::Insert(' ', bIsXSelection);
+ if ( !bSttWrd || (bInWrd && !bSttPara) )
+ {
+ rSh.SwapPam();
+ if ( !bSttWrd )
+ rSh.SwEditShell::Insert(' ', bIsXSelection);
+ rSh.SwapPam();
+ }
+ }
+
+ if( bIsXSelection )
+ {
+ if( &rSrcSh == &rSh && !rSh.IsAddMode() )
+ {
+ rSh.SwCursorShell::DestroyCursor();
+ rSh.GoPrevCursor();
+ }
+ else
+ {
+ rSh.SwapPam();
+ rSh.SwCursorShell::ClearMark();
+ }
+ }
+ else
+ {
+ if( rSh.IsAddMode() )
+ rSh.SwCursorShell::CreateCursor();
+ else
+ {
+ // turn on selection mode
+ rSh.SttSelect();
+ rSh.EndSelect();
+ }
+ }
+ }
+ else if ( bRet && bTableMove )
+ {
+ SfxDispatcher* pDispatch = rSrcSh.GetView().GetViewFrame().GetDispatcher();
+ pDispatch->Execute(FN_TABLE_DELETE_TABLE, SfxCallMode::SYNCHRON);
+ }
+
+ if( bRet && bMove && bFrameSel )
+ rSrcSh.LeaveSelFrameMode();
+
+ if( rSrcSh.GetDoc() != rSh.GetDoc() )
+ rSrcSh.EndUndo();
+ rSh.EndUndo();
+
+ // put the shell in the right state
+ if( &rSrcSh != &rSh && ( rSh.IsFrameSelected() || rSh.IsObjSelected() ))
+ rSh.EnterSelFrameMode();
+
+ rSrcSh.EndAction();
+ rSh.EndAction();
+ return true;
+}
+
+// Interfaces for Selection
+void SwTransferable::CreateSelection( SwWrtShell& rSh,
+ const SwFrameShell * _pCreatorView )
+{
+ SwModule *pMod = SW_MOD();
+ rtl::Reference<SwTransferable> pNew = new SwTransferable( rSh );
+
+ pNew->m_pCreatorView = _pCreatorView;
+
+ pMod->m_pXSelection = pNew.get();
+ pNew->CopyToPrimarySelection();
+}
+
+void SwTransferable::ClearSelection( const SwWrtShell& rSh,
+ const SwFrameShell * _pCreatorView)
+{
+ SwModule *pMod = SW_MOD();
+ if( pMod->m_pXSelection &&
+ ((!pMod->m_pXSelection->m_pWrtShell) || (pMod->m_pXSelection->m_pWrtShell == &rSh)) &&
+ (!_pCreatorView || (pMod->m_pXSelection->m_pCreatorView == _pCreatorView)) )
+ {
+ TransferableHelper::ClearPrimarySelection();
+ }
+}
+
+SwTransferable* SwTransferable::GetSwTransferable( const TransferableDataHelper& rData )
+{
+ return dynamic_cast<SwTransferable*>(rData.GetTransferable().get());
+}
+
+SwTransferDdeLink::SwTransferDdeLink( SwTransferable& rTrans, SwWrtShell& rSh )
+ : m_rTransfer(rTrans)
+ , m_pDocShell(nullptr)
+ , m_nOldTimeOut(0)
+ , m_bDelBookmark(false)
+ , m_bInDisconnect(false)
+{
+ // we only end up here with table- or text selection
+ if( SelectionType::TableCell & rSh.GetSelectionType() )
+ {
+ SwFrameFormat* pFormat = rSh.GetTableFormat();
+ if( pFormat )
+ m_sName = pFormat->GetName();
+ }
+ else
+ {
+ // creating a temp. bookmark without undo
+ bool bUndo = rSh.DoesUndo();
+ rSh.DoUndo( false );
+ bool bIsModified = rSh.IsModified();
+
+ ::sw::mark::IMark* pMark = rSh.SetBookmark(
+ vcl::KeyCode(),
+ OUString(),
+ IDocumentMarkAccess::MarkType::DDE_BOOKMARK);
+ if(pMark)
+ {
+ m_sName = pMark->GetName();
+ m_bDelBookmark = true;
+ if( !bIsModified )
+ rSh.ResetModified();
+ }
+ else
+ m_sName.clear();
+ rSh.DoUndo( bUndo );
+ }
+
+ if( m_sName.isEmpty() ||
+ nullptr == ( m_pDocShell = rSh.GetDoc()->GetDocShell() ))
+ return;
+
+ // then we create our "server" and connect to it
+ m_xRefObj = m_pDocShell->DdeCreateLinkSource( m_sName );
+ if( m_xRefObj.is() )
+ {
+ m_xRefObj->AddConnectAdvise( this );
+ m_xRefObj->AddDataAdvise( this,
+ OUString(),
+ ADVISEMODE_NODATA | ADVISEMODE_ONLYONCE );
+ m_nOldTimeOut = m_xRefObj->GetUpdateTimeout();
+ m_xRefObj->SetUpdateTimeout( 0 );
+ }
+}
+
+SwTransferDdeLink::~SwTransferDdeLink()
+{
+ if( m_xRefObj.is() )
+ Disconnect( true );
+}
+
+::sfx2::SvBaseLink::UpdateResult SwTransferDdeLink::DataChanged( const OUString& ,
+ const uno::Any& )
+{
+ // well, that's it with the link
+ if( !m_bInDisconnect )
+ {
+ if( FindDocShell() && m_pDocShell->GetView() )
+ m_rTransfer.RemoveDDELinkFormat( m_pDocShell->GetView()->GetEditWin() );
+ Disconnect( false );
+ }
+ return SUCCESS;
+}
+
+bool SwTransferDdeLink::WriteData( SvStream& rStrm )
+{
+ if( !m_xRefObj.is() || !FindDocShell() )
+ return false;
+
+ rtl_TextEncoding eEncoding = osl_getThreadTextEncoding();
+ const OString aAppNm(OUStringToOString(
+ Application::GetAppName(), eEncoding));
+ const OString aTopic(OUStringToOString(
+ m_pDocShell->GetTitle(SFX_TITLE_FULLNAME), eEncoding));
+ const OString aName(OUStringToOString(m_sName, eEncoding));
+
+ std::unique_ptr<char[]> pMem(new char[ aAppNm.getLength() + aTopic.getLength() + aName.getLength() + 4 ]);
+
+ sal_Int32 nLen = aAppNm.getLength();
+ memcpy( pMem.get(), aAppNm.getStr(), nLen );
+ pMem[ nLen++ ] = 0;
+ memcpy( pMem.get() + nLen, aTopic.getStr(), aTopic.getLength() );
+ nLen = nLen + aTopic.getLength();
+ pMem[ nLen++ ] = 0;
+ memcpy( pMem.get() + nLen, aName.getStr(), aName.getLength() );
+ nLen = nLen + aName.getLength();
+ pMem[ nLen++ ] = 0;
+ pMem[ nLen++ ] = 0;
+
+ rStrm.WriteBytes( pMem.get(), nLen );
+ pMem.reset();
+
+ IDocumentMarkAccess* const pMarkAccess = m_pDocShell->GetDoc()->getIDocumentMarkAccess();
+ IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->findMark(m_sName);
+ if(ppMark != pMarkAccess->getAllMarksEnd()
+ && IDocumentMarkAccess::GetType(**ppMark) != IDocumentMarkAccess::MarkType::BOOKMARK)
+ {
+ // the mark is still a DdeBookmark
+ // we replace it with a Bookmark, so it will get saved etc.
+ ::sw::mark::IMark* const pMark = *ppMark;
+ ::sfx2::SvLinkSource* p = m_xRefObj.get();
+ SwServerObject& rServerObject = dynamic_cast<SwServerObject&>(*p);
+
+ // collecting state of old mark
+ SwPaM aPaM(pMark->GetMarkStart());
+ *aPaM.GetPoint() = pMark->GetMarkStart();
+ if(pMark->IsExpanded())
+ {
+ aPaM.SetMark();
+ *aPaM.GetMark() = pMark->GetMarkEnd();
+ }
+ OUString sMarkName = pMark->GetName();
+
+ // remove mark
+ rServerObject.SetNoServer(); // this removes the connection between SwServerObject and mark
+ // N.B. ppMark was not loaded from file and cannot have xml:id
+ pMarkAccess->deleteMark(ppMark, false);
+
+ // recreate as Bookmark
+ ::sw::mark::IMark* const pNewMark = pMarkAccess->makeMark(
+ aPaM,
+ sMarkName,
+ IDocumentMarkAccess::MarkType::BOOKMARK,
+ ::sw::mark::InsertMode::New);
+ rServerObject.SetDdeBookmark(*pNewMark);
+ }
+
+ m_bDelBookmark = false;
+ return true;
+}
+
+void SwTransferDdeLink::Disconnect( bool bRemoveDataAdvise )
+{
+ // don't accept DataChanged anymore, when already in Disconnect!
+ // (DTOR from Bookmark sends a DataChanged!)
+ bool bOldDisconnect = m_bInDisconnect;
+ m_bInDisconnect = true;
+
+ // destroy the unused bookmark again (without Undo!)?
+ if( m_bDelBookmark && m_xRefObj.is() && FindDocShell() )
+ {
+ SwDoc* pDoc = m_pDocShell->GetDoc();
+ ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
+
+ // #i58448#
+ Link<bool,void> aSavedOle2Link( pDoc->GetOle2Link() );
+ pDoc->SetOle2Link( Link<bool,void>() );
+
+ bool bIsModified = pDoc->getIDocumentState().IsModified();
+
+ IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
+ pMarkAccess->deleteMark(pMarkAccess->findMark(m_sName), false);
+
+ if( !bIsModified )
+ pDoc->getIDocumentState().ResetModified();
+ // #i58448#
+ pDoc->SetOle2Link( aSavedOle2Link );
+
+ m_bDelBookmark = false;
+ }
+
+ if( m_xRefObj.is() )
+ {
+ m_xRefObj->SetUpdateTimeout( m_nOldTimeOut );
+ m_xRefObj->RemoveConnectAdvise( this );
+ if( bRemoveDataAdvise )
+ // in a DataChanged the SelectionObject must NEVER be deleted
+ // is already handled by the base class
+ // (ADVISEMODE_ONLYONCE!!!!)
+ // but always in normal Disconnect!
+ m_xRefObj->RemoveAllDataAdvise( this );
+ m_xRefObj.clear();
+ }
+ m_bInDisconnect = bOldDisconnect;
+}
+
+bool SwTransferDdeLink::FindDocShell()
+{
+ SfxObjectShell* pTmpSh = SfxObjectShell::GetFirst( checkSfxObjectShell<SwDocShell> );
+ while( pTmpSh )
+ {
+ if( pTmpSh == m_pDocShell ) // that's what we want to have
+ {
+ if( m_pDocShell->GetDoc() )
+ return true;
+ break; // the Doc is not there anymore, so leave!
+ }
+ pTmpSh = SfxObjectShell::GetNext( *pTmpSh, checkSfxObjectShell<SwDocShell> );
+ }
+
+ m_pDocShell = nullptr;
+ return false;
+}
+
+void SwTransferDdeLink::Closed()
+{
+ if( !m_bInDisconnect && m_xRefObj.is() )
+ {
+ m_xRefObj->RemoveAllDataAdvise( this );
+ m_xRefObj->RemoveConnectAdvise( this );
+ m_xRefObj.clear();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */