1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <config_features.h>
21 
22 #include <memory>
23 #include <editeng/eeitem.hxx>
24 
25 #include <editeng/editobj.hxx>
26 #include <editeng/editstat.hxx>
27 #include <editeng/editview.hxx>
28 #include <editeng/flditem.hxx>
29 #include <sot/storage.hxx>
30 #include <svx/hlnkitem.hxx>
31 #include <editeng/unolingu.hxx>
32 
33 #include <sfx2/bindings.hxx>
34 #include <sfx2/dispatch.hxx>
35 #include <sfx2/docfile.hxx>
36 #include <sfx2/docfilt.hxx>
37 #include <sfx2/fcontnr.hxx>
38 #include <svtools/langtab.hxx>
39 #include <vcl/graphicfilter.hxx>
40 #include <svl/stritem.hxx>
41 #include <vcl/transfer.hxx>
42 #include <svl/urlbmk.hxx>
43 #include <svl/sharedstringpool.hxx>
44 #include <vcl/svapp.hxx>
45 #include <vcl/weld.hxx>
46 #include <avmedia/mediawindow.hxx>
47 
48 #include <comphelper/storagehelper.hxx>
49 
50 #include <viewfunc.hxx>
51 #include <docsh.hxx>
52 #include <document.hxx>
53 #include <globstr.hrc>
54 #include <global.hxx>
55 #include <scresid.hxx>
56 #include <undoblk.hxx>
57 #include <undocell.hxx>
58 #include <formulacell.hxx>
59 #include <scmod.hxx>
60 #include <spelleng.hxx>
61 #include <patattr.hxx>
62 #include <sc.hrc>
63 #include <tabvwsh.hxx>
64 #include <impex.hxx>
65 #include <editutil.hxx>
66 #include <editable.hxx>
67 #include <dociter.hxx>
68 #include <reffind.hxx>
69 #include <compiler.hxx>
70 #include <tokenarray.hxx>
71 #include <refupdatecontext.hxx>
72 #include <gridwin.hxx>
73 #include <refundo.hxx>
74 
75 using namespace com::sun::star;
76 
77 bool bPasteIsDrop = false;
78 
PasteRTF(SCCOL nStartCol,SCROW nStartRow,const css::uno::Reference<css::datatransfer::XTransferable> & rxTransferable)79 void ScViewFunc::PasteRTF( SCCOL nStartCol, SCROW nStartRow,
80                                 const css::uno::Reference< css::datatransfer::XTransferable >& rxTransferable )
81 {
82     TransferableDataHelper aDataHelper( rxTransferable );
83     if ( aDataHelper.HasFormat( SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT ) )
84     {
85         HideAllCursors();
86 
87         ScDocShell* pDocSh = GetViewData().GetDocShell();
88         ScDocument& rDoc = pDocSh->GetDocument();
89         SCTAB nTab = GetViewData().GetTabNo();
90         const bool bRecord (rDoc.IsUndoEnabled());
91 
92         const ScPatternAttr* pPattern = rDoc.GetPattern( nStartCol, nStartRow, nTab );
93         std::unique_ptr<ScTabEditEngine> pEngine(new ScTabEditEngine( *pPattern, rDoc.GetEnginePool(), &rDoc ));
94         pEngine->EnableUndo( false );
95 
96         vcl::Window* pActWin = GetActiveWin();
97         if (pActWin)
98         {
99             pEngine->SetPaperSize(Size(100000,100000));
100             ScopedVclPtrInstance< vcl::Window > aWin( pActWin );
101             EditView aEditView( pEngine.get(), aWin.get() );
102             aEditView.SetOutputArea(tools::Rectangle(0,0,100000,100000));
103 
104             // same method now for clipboard or drag&drop
105             // mba: clipboard always must contain absolute URLs (could be from alien source)
106             aEditView.InsertText( rxTransferable, OUString(), true );
107         }
108 
109         sal_Int32 nParCnt = pEngine->GetParagraphCount();
110         if (nParCnt)
111         {
112             SCROW nEndRow = nStartRow + static_cast<SCROW>(nParCnt) - 1;
113             if (nEndRow > rDoc.MaxRow())
114                 nEndRow = rDoc.MaxRow();
115 
116             ScDocumentUniquePtr pUndoDoc;
117             if (bRecord)
118             {
119                 pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
120                 pUndoDoc->InitUndo( &rDoc, nTab, nTab );
121                 rDoc.CopyToDocument( nStartCol,nStartRow,nTab, nStartCol,nEndRow,nTab, InsertDeleteFlags::ALL, false, *pUndoDoc );
122             }
123 
124             SCROW nRow = nStartRow;
125 
126             // Temporarily turn off undo generation for this lot
127             bool bUndoEnabled = rDoc.IsUndoEnabled();
128             rDoc.EnableUndo( false );
129             for( sal_Int32 n = 0; n < nParCnt; n++ )
130             {
131                 std::unique_ptr<EditTextObject> pObject(pEngine->CreateTextObject(n));
132                 EnterData(nStartCol, nRow, nTab, *pObject, true);
133                 if( ++nRow > rDoc.MaxRow() )
134                     break;
135             }
136             rDoc.EnableUndo(bUndoEnabled);
137 
138             if (bRecord)
139             {
140                 ScDocumentUniquePtr pRedoDoc(new ScDocument( SCDOCMODE_UNDO ));
141                 pRedoDoc->InitUndo( &rDoc, nTab, nTab );
142                 rDoc.CopyToDocument( nStartCol,nStartRow,nTab, nStartCol,nEndRow,nTab, InsertDeleteFlags::ALL|InsertDeleteFlags::NOCAPTIONS, false, *pRedoDoc );
143 
144                 ScRange aMarkRange(nStartCol, nStartRow, nTab, nStartCol, nEndRow, nTab);
145                 ScMarkData aDestMark(rDoc.MaxRow(), rDoc.MaxCol());
146                 aDestMark.SetMarkArea( aMarkRange );
147                 pDocSh->GetUndoManager()->AddUndoAction(
148                     std::make_unique<ScUndoPaste>( pDocSh, aMarkRange, aDestMark,
149                                      std::move(pUndoDoc), std::move(pRedoDoc), InsertDeleteFlags::ALL, nullptr));
150             }
151         }
152 
153         pEngine.reset();
154 
155         ShowAllCursors();
156     }
157     else
158     {
159         HideAllCursors();
160         ScDocShell* pDocSh = GetViewData().GetDocShell();
161         ScImportExport aImpEx( &pDocSh->GetDocument(),
162             ScAddress( nStartCol, nStartRow, GetViewData().GetTabNo() ) );
163 
164         OUString aStr;
165         tools::SvRef<SotStorageStream> xStream;
166         if ( aDataHelper.GetSotStorageStream( SotClipboardFormatId::RTF, xStream ) && xStream.is() )
167             // mba: clipboard always must contain absolute URLs (could be from alien source)
168             aImpEx.ImportStream( *xStream, OUString(), SotClipboardFormatId::RTF );
169         else if ( aDataHelper.GetString( SotClipboardFormatId::RTF, aStr ) )
170             aImpEx.ImportString( aStr, SotClipboardFormatId::RTF );
171         else if ( aDataHelper.GetSotStorageStream( SotClipboardFormatId::RICHTEXT, xStream ) && xStream.is() )
172             aImpEx.ImportStream( *xStream, OUString(), SotClipboardFormatId::RICHTEXT );
173         else if ( aDataHelper.GetString( SotClipboardFormatId::RICHTEXT, aStr ) )
174             aImpEx.ImportString( aStr, SotClipboardFormatId::RICHTEXT );
175 
176         AdjustRowHeight( nStartRow, aImpEx.GetRange().aEnd.Row() );
177         pDocSh->UpdateOle(&GetViewData());
178         ShowAllCursors();
179     }
180 }
DoRefConversion()181 void ScViewFunc::DoRefConversion()
182 {
183     ScDocument* pDoc = GetViewData().GetDocument();
184     ScMarkData& rMark = GetViewData().GetMarkData();
185     SCTAB nTabCount = pDoc->GetTableCount();
186     bool bRecord = true;
187     if (!pDoc->IsUndoEnabled())
188         bRecord = false;
189 
190     ScRange aMarkRange;
191     rMark.MarkToSimple();
192     bool bMulti = rMark.IsMultiMarked();
193     if (bMulti)
194         rMark.GetMultiMarkArea( aMarkRange );
195     else if (rMark.IsMarked())
196         rMark.GetMarkArea( aMarkRange );
197     else
198     {
199         aMarkRange = ScRange( GetViewData().GetCurX(),
200             GetViewData().GetCurY(), GetViewData().GetTabNo() );
201     }
202     ScEditableTester aTester( pDoc, aMarkRange.aStart.Col(), aMarkRange.aStart.Row(),
203                             aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(),rMark );
204     if (!aTester.IsEditable())
205     {
206         ErrorMessage(aTester.GetMessageId());
207         return;
208     }
209 
210     ScDocShell* pDocSh = GetViewData().GetDocShell();
211     bool bOk = false;
212 
213     ScDocumentUniquePtr pUndoDoc;
214     if (bRecord)
215     {
216         pUndoDoc.reset( new ScDocument( SCDOCMODE_UNDO ) );
217         SCTAB nTab = aMarkRange.aStart.Tab();
218         pUndoDoc->InitUndo( pDoc, nTab, nTab );
219 
220         if ( rMark.GetSelectCount() > 1 )
221         {
222             for (const auto& rTab : rMark)
223                 if ( rTab != nTab )
224                     pUndoDoc->AddUndoTab( rTab, rTab );
225         }
226         ScRange aCopyRange = aMarkRange;
227         aCopyRange.aStart.SetTab(0);
228         aCopyRange.aEnd.SetTab(nTabCount-1);
229         pDoc->CopyToDocument( aCopyRange, InsertDeleteFlags::ALL, bMulti, *pUndoDoc, &rMark );
230     }
231 
232     ScRangeListRef xRanges;
233     GetViewData().GetMultiArea( xRanges );
234     size_t nCount = xRanges->size();
235 
236     for (const SCTAB& i : rMark)
237     {
238         for (size_t j = 0; j < nCount; ++j)
239         {
240             ScRange aRange = (*xRanges)[j];
241             aRange.aStart.SetTab(i);
242             aRange.aEnd.SetTab(i);
243             ScCellIterator aIter( pDoc, aRange );
244             for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
245             {
246                 if (aIter.getType() != CELLTYPE_FORMULA)
247                     continue;
248 
249                 ScFormulaCell* pCell = aIter.getFormulaCell();
250                 ScMatrixMode eMatrixMode = pCell->GetMatrixFlag();
251                 if (eMatrixMode == ScMatrixMode::Reference)
252                     continue;
253 
254                 OUString aOld;
255                 pCell->GetFormula(aOld);
256                 sal_Int32 nLen = aOld.getLength();
257                 if (eMatrixMode == ScMatrixMode::Formula)
258                 {
259                     assert(nLen >= 2 && aOld[0] == '{' && aOld[nLen-1] == '}');
260                     nLen -= 2;
261                     aOld = aOld.copy( 1, nLen);
262                 }
263                 ScRefFinder aFinder( aOld, aIter.GetPos(), pDoc, pDoc->GetAddressConvention() );
264                 aFinder.ToggleRel( 0, nLen );
265                 if (aFinder.GetFound())
266                 {
267                     ScAddress aPos = pCell->aPos;
268                     const OUString& aNew = aFinder.GetText();
269                     ScCompiler aComp( pDoc, aPos, pDoc->GetGrammar());
270                     std::unique_ptr<ScTokenArray> pArr(aComp.CompileString(aNew));
271                     ScFormulaCell* pNewCell =
272                         new ScFormulaCell(
273                             pDoc, aPos, *pArr, formula::FormulaGrammar::GRAM_DEFAULT, eMatrixMode);
274 
275                     pDoc->SetFormulaCell(aPos, pNewCell);
276                     bOk = true;
277                 }
278             }
279         }
280     }
281     if (bRecord)
282     {
283         ScDocumentUniquePtr pRedoDoc(new ScDocument( SCDOCMODE_UNDO ));
284         SCTAB nTab = aMarkRange.aStart.Tab();
285         pRedoDoc->InitUndo( pDoc, nTab, nTab );
286 
287         if ( rMark.GetSelectCount() > 1 )
288         {
289             for (const auto& rTab : rMark)
290                 if ( rTab != nTab )
291                     pRedoDoc->AddUndoTab( rTab, rTab );
292         }
293         ScRange aCopyRange = aMarkRange;
294         aCopyRange.aStart.SetTab(0);
295         aCopyRange.aEnd.SetTab(nTabCount-1);
296         pDoc->CopyToDocument( aCopyRange, InsertDeleteFlags::ALL, bMulti, *pRedoDoc, &rMark );
297 
298         pDocSh->GetUndoManager()->AddUndoAction(
299             std::make_unique<ScUndoRefConversion>( pDocSh,
300                                     aMarkRange, rMark, std::move(pUndoDoc), std::move(pRedoDoc), bMulti) );
301     }
302 
303     pDocSh->PostPaint( aMarkRange, PaintPartFlags::Grid );
304     pDocSh->UpdateOle(&GetViewData());
305     pDocSh->SetDocumentModified();
306     CellContentChanged();
307 
308     if (!bOk)
309         ErrorMessage(STR_ERR_NOREF);
310 }
311 //  Thesaurus - Undo ok
DoThesaurus()312 void ScViewFunc::DoThesaurus()
313 {
314     SCCOL nCol;
315     SCROW nRow;
316     SCTAB nTab;
317     ScDocShell* pDocSh = GetViewData().GetDocShell();
318     ScDocument& rDoc = pDocSh->GetDocument();
319     ScMarkData& rMark = GetViewData().GetMarkData();
320     ScSplitPos eWhich = GetViewData().GetActivePart();
321     EESpellState eState;
322     EditView* pEditView = nullptr;
323     std::unique_ptr<ESelection> pEditSel;
324     std::unique_ptr<ScEditEngineDefaulter> pThesaurusEngine;
325     bool bIsEditMode = GetViewData().HasEditView(eWhich);
326     bool bRecord = true;
327     if (!rDoc.IsUndoEnabled())
328         bRecord = false;
329     if (bIsEditMode)                                            // edit mode active
330     {
331         GetViewData().GetEditView(eWhich, pEditView, nCol, nRow);
332         pEditSel.reset(new ESelection(pEditView->GetSelection()));
333         SC_MOD()->InputEnterHandler();
334         GetViewData().GetBindings().Update();          // otherwise the Sfx becomes mixed-up...
335     }
336     else
337     {
338         nCol = GetViewData().GetCurX();
339         nRow = GetViewData().GetCurY();
340     }
341     nTab = GetViewData().GetTabNo();
342 
343     ScAddress aPos(nCol, nRow, nTab);
344     ScEditableTester aTester( &rDoc, nCol, nRow, nCol, nRow, rMark );
345     if (!aTester.IsEditable())
346     {
347         ErrorMessage(aTester.GetMessageId());
348         return;
349     }
350 
351     ScCellValue aOldText;
352     aOldText.assign(rDoc, aPos);
353     if (aOldText.meType != CELLTYPE_STRING && aOldText.meType != CELLTYPE_EDIT)
354     {
355         ErrorMessage(STR_THESAURUS_NO_STRING);
356         return;
357     }
358 
359     uno::Reference<linguistic2::XSpellChecker1> xSpeller = LinguMgr::GetSpellChecker();
360 
361     pThesaurusEngine.reset(new ScEditEngineDefaulter(rDoc.GetEnginePool()));
362     pThesaurusEngine->SetEditTextObjectPool( rDoc.GetEditPool() );
363     pThesaurusEngine->SetRefDevice(GetViewData().GetActiveWin());
364     pThesaurusEngine->SetSpeller(xSpeller);
365     MakeEditView(pThesaurusEngine.get(), nCol, nRow );
366     std::unique_ptr<SfxItemSet> pEditDefaults(
367         new SfxItemSet(pThesaurusEngine->GetEmptyItemSet()));
368     const ScPatternAttr* pPattern = rDoc.GetPattern(nCol, nRow, nTab);
369     if (pPattern)
370     {
371         pPattern->FillEditItemSet( pEditDefaults.get() );
372         pThesaurusEngine->SetDefaults( *pEditDefaults );
373     }
374 
375     if (aOldText.meType == CELLTYPE_EDIT)
376         pThesaurusEngine->SetText(*aOldText.mpEditText);
377     else
378         pThesaurusEngine->SetText(aOldText.getString(&rDoc));
379 
380     pEditView = GetViewData().GetEditView(GetViewData().GetActivePart());
381     if (pEditSel)
382         pEditView->SetSelection(*pEditSel);
383     else
384         pEditView->SetSelection(ESelection(0,0,0,0));
385 
386     pThesaurusEngine->ClearModifyFlag();
387 
388     //  language is now in EditEngine attributes -> no longer passed to StartThesaurus
389 
390     eState = pEditView->StartThesaurus();
391     OSL_ENSURE(eState != EESpellState::NoSpeller, "No SpellChecker");
392 
393     if (eState == EESpellState::ErrorFound)              // should happen later through Wrapper!
394     {
395         LanguageType eLnge = ScViewUtil::GetEffLanguage( &rDoc, ScAddress( nCol, nRow, nTab ) );
396         OUString aErr = SvtLanguageTable::GetLanguageString(eLnge) + ScResId( STR_SPELLING_NO_LANG );
397 
398         std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetViewData().GetDialogParent(),
399                                                       VclMessageType::Info, VclButtonsType::Ok,
400                                                       aErr));
401         xInfoBox->run();
402     }
403     if (pThesaurusEngine->IsModified())
404     {
405         ScCellValue aNewText;
406 
407         if (aOldText.meType == CELLTYPE_EDIT)
408         {
409             // The cell will own the text object instance.
410             std::unique_ptr<EditTextObject> pText = pThesaurusEngine->CreateTextObject();
411             auto tmp = pText.get();
412             if (rDoc.SetEditText(ScAddress(nCol,nRow,nTab), std::move(pText)))
413                 aNewText.set(*tmp);
414         }
415         else
416         {
417             OUString aStr = pThesaurusEngine->GetText();
418             aNewText.set(rDoc.GetSharedStringPool().intern(aStr));
419             rDoc.SetString(nCol, nRow, nTab, aStr);
420         }
421 
422         pDocSh->SetDocumentModified();
423         if (bRecord)
424         {
425             GetViewData().GetDocShell()->GetUndoManager()->AddUndoAction(
426                 std::make_unique<ScUndoThesaurus>(
427                     GetViewData().GetDocShell(), nCol, nRow, nTab, aOldText, aNewText));
428         }
429     }
430 
431     KillEditView(true);
432     pDocSh->PostPaintGridAll();
433 }
434 
DoHangulHanjaConversion()435 void ScViewFunc::DoHangulHanjaConversion()
436 {
437     ScConversionParam aConvParam( SC_CONVERSION_HANGULHANJA, LANGUAGE_KOREAN, 0, true );
438     DoSheetConversion( aConvParam );
439 }
440 
DoSheetConversion(const ScConversionParam & rConvParam)441 void ScViewFunc::DoSheetConversion( const ScConversionParam& rConvParam )
442 {
443     SCCOL nCol;
444     SCROW nRow;
445     SCTAB nTab;
446     ScViewData& rViewData = GetViewData();
447     ScDocShell* pDocSh = rViewData.GetDocShell();
448     ScDocument& rDoc = pDocSh->GetDocument();
449     ScMarkData& rMark = rViewData.GetMarkData();
450     ScSplitPos eWhich = rViewData.GetActivePart();
451     EditView* pEditView = nullptr;
452     bool bIsEditMode = rViewData.HasEditView(eWhich);
453     bool bRecord = true;
454     if (!rDoc.IsUndoEnabled())
455         bRecord = false;
456     if (bIsEditMode)                                            // edit mode active
457     {
458         rViewData.GetEditView(eWhich, pEditView, nCol, nRow);
459         SC_MOD()->InputEnterHandler();
460     }
461     else
462     {
463         nCol = rViewData.GetCurX();
464         nRow = rViewData.GetCurY();
465 
466         AlignToCursor( nCol, nRow, SC_FOLLOW_JUMP);
467     }
468     nTab = rViewData.GetTabNo();
469 
470     rMark.MarkToMulti();
471     bool bMarked = rMark.IsMultiMarked();
472     if (bMarked)
473     {
474         ScEditableTester aTester( &rDoc, rMark );
475         if (!aTester.IsEditable())
476         {
477             ErrorMessage(aTester.GetMessageId());
478             return;
479         }
480     }
481 
482     ScDocumentUniquePtr pUndoDoc;
483     ScDocumentUniquePtr pRedoDoc;
484     if (bRecord)
485     {
486         pUndoDoc.reset( new ScDocument( SCDOCMODE_UNDO ) );
487         pUndoDoc->InitUndo( &rDoc, nTab, nTab );
488         pRedoDoc.reset( new ScDocument( SCDOCMODE_UNDO ) );
489         pRedoDoc->InitUndo( &rDoc, nTab, nTab );
490 
491         if ( rMark.GetSelectCount() > 1 )
492         {
493             for (const auto& rTab : rMark)
494                 if ( rTab != nTab )
495                 {
496                     pUndoDoc->AddUndoTab( rTab, rTab );
497                     pRedoDoc->AddUndoTab( rTab, rTab );
498                 }
499         }
500     }
501 
502     // from here no return
503 
504     bool bOldEnabled = rDoc.IsIdleEnabled();
505     rDoc.EnableIdle(false);   // stop online spelling
506 
507     // *** create and init the edit engine *** --------------------------------
508 
509     std::unique_ptr<ScConversionEngineBase> pEngine;
510     switch( rConvParam.GetType() )
511     {
512         case SC_CONVERSION_SPELLCHECK:
513             pEngine.reset(new ScSpellingEngine(
514                 rDoc.GetEnginePool(), rViewData, pUndoDoc.get(), pRedoDoc.get(), LinguMgr::GetSpellChecker() ));
515         break;
516         case SC_CONVERSION_HANGULHANJA:
517         case SC_CONVERSION_CHINESE_TRANSL:
518             pEngine.reset(new ScTextConversionEngine(
519                 rDoc.GetEnginePool(), rViewData, rConvParam, pUndoDoc.get(), pRedoDoc.get() ));
520         break;
521         default:
522             OSL_FAIL( "ScViewFunc::DoSheetConversion - unknown conversion type" );
523     }
524 
525     MakeEditView( pEngine.get(), nCol, nRow );
526     pEngine->SetRefDevice( rViewData.GetActiveWin() );
527                                         // simulate dummy cell:
528     pEditView = rViewData.GetEditView( rViewData.GetActivePart() );
529     rViewData.SetSpellingView( pEditView );
530     tools::Rectangle aRect( Point( 0, 0 ), Point( 0, 0 ) );
531     pEditView->SetOutputArea( aRect );
532     pEngine->SetControlWord( EEControlBits::USECHARATTRIBS );
533     pEngine->EnableUndo( false );
534     pEngine->SetPaperSize( aRect.GetSize() );
535     pEngine->SetText( EMPTY_OUSTRING );
536 
537     // *** do the conversion *** ----------------------------------------------
538 
539     pEngine->ClearModifyFlag();
540     pEngine->ConvertAll( *pEditView );
541 
542     // *** undo/redo *** ------------------------------------------------------
543 
544     if( pEngine->IsAnyModified() )
545     {
546         if (bRecord)
547         {
548             SCCOL nNewCol = rViewData.GetCurX();
549             SCROW nNewRow = rViewData.GetCurY();
550             rViewData.GetDocShell()->GetUndoManager()->AddUndoAction(
551                 std::make_unique<ScUndoConversion>(
552                         pDocSh, rMark,
553                         nCol, nRow, nTab, std::move(pUndoDoc),
554                         nNewCol, nNewRow, nTab, std::move(pRedoDoc), rConvParam ) );
555         }
556 
557         sc::SetFormulaDirtyContext aCxt;
558         rDoc.SetAllFormulasDirty(aCxt);
559 
560         pDocSh->SetDocumentModified();
561     }
562     else
563     {
564         pUndoDoc.reset();
565         pRedoDoc.reset();
566     }
567 
568     // *** final cleanup *** --------------------------------------------------
569 
570     rViewData.SetSpellingView( nullptr );
571     KillEditView(true);
572     pEngine.reset();
573     pDocSh->PostPaintGridAll();
574     rViewData.GetViewShell()->UpdateInputHandler();
575     rDoc.EnableIdle(bOldEnabled);
576 }
577 
578 // past from SotClipboardFormatId::FILE items
579 // is not called directly from Drop, but asynchronously -> dialogs are allowed
580 
PasteFile(const Point & rPos,const OUString & rFile,bool bLink)581 bool ScViewFunc::PasteFile( const Point& rPos, const OUString& rFile, bool bLink )
582 {
583     INetURLObject aURL;
584     aURL.SetSmartURL( rFile );
585     OUString aStrURL = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
586 
587     // is it a media URL?
588 #if HAVE_FEATURE_AVMEDIA
589     if( ::avmedia::MediaWindow::isMediaURL( aStrURL, ""/*TODO?*/ ) )
590     {
591         const SfxStringItem aMediaURLItem( SID_INSERT_AVMEDIA, aStrURL );
592         return ( nullptr != GetViewData().GetDispatcher().ExecuteList(
593                                 SID_INSERT_AVMEDIA, SfxCallMode::SYNCHRON,
594                                 { &aMediaURLItem }) );
595     }
596 #endif
597 
598     if (!bLink)     // for bLink only graphics or URL
599     {
600         // 1. can I open the file?
601         std::shared_ptr<const SfxFilter> pFlt;
602 
603         // search only for its own filters, without selection box (as in ScDocumentLoader)
604         SfxFilterMatcher aMatcher( ScDocShell::Factory().GetFilterContainer()->GetName() );
605         SfxMedium aSfxMedium( aStrURL, (StreamMode::READ | StreamMode::SHARE_DENYNONE) );
606         // #i73992# GuessFilter no longer calls UseInteractionHandler.
607         // This is UI, so it can be called here.
608         aSfxMedium.UseInteractionHandler(true);
609         ErrCode nErr = aMatcher.GuessFilter( aSfxMedium, pFlt );
610 
611         if ( pFlt && !nErr )
612         {
613             // code stolen from the SFX!
614             SfxDispatcher &rDispatcher = GetViewData().GetDispatcher();
615             SfxStringItem aFileNameItem( SID_FILE_NAME, aStrURL );
616             SfxStringItem aFilterItem( SID_FILTER_NAME, pFlt->GetName() );
617             // #i69524# add target, as in SfxApplication when the Open dialog is used
618             SfxStringItem aTargetItem( SID_TARGETNAME, "_default" );
619 
620             // Open Asynchronously, because it can also happen from D&D
621             // and that is not so good for the MAC...
622             return (nullptr != rDispatcher.ExecuteList(SID_OPENDOC,
623                                 SfxCallMode::ASYNCHRON,
624                                 { &aFileNameItem, &aFilterItem, &aTargetItem}));
625         }
626     }
627 
628     // 2. can the file be inserted using the graphics filter?
629     // (as a link, since the Gallery provides it in this way)
630 
631     sal_uInt16 nFilterFormat;
632     Graphic aGraphic;
633     GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
634 
635     if (!rGraphicFilter.ImportGraphic(aGraphic, aURL,
636             GRFILTER_FORMAT_DONTKNOW, &nFilterFormat ))
637     {
638         if ( bLink )
639         {
640             OUString aFltName = rGraphicFilter.GetImportFormatName(nFilterFormat);
641             return PasteGraphic( rPos, aGraphic, aStrURL, aFltName );
642         }
643         else
644         {
645             // #i76709# if bLink isn't set, pass empty URL/filter, so a non-linked image is inserted
646             return PasteGraphic( rPos, aGraphic, EMPTY_OUSTRING, EMPTY_OUSTRING );
647         }
648     }
649 
650     if (bLink)                      // for bLink everything, which is not graphics, as URL
651     {
652         tools::Rectangle aRect( rPos, Size(0,0) );
653         ScRange aRange = GetViewData().GetDocument()->
654                             GetRange( GetViewData().GetTabNo(), aRect );
655         SCCOL nPosX = aRange.aStart.Col();
656         SCROW nPosY = aRange.aStart.Row();
657 
658         InsertBookmark( aStrURL, aStrURL, nPosX, nPosY );
659         return true;
660     }
661     else
662     {
663         // 3. can the file be inserted as OLE?
664         // also non-storages, for instance sounds (#38282#)
665         uno::Reference < embed::XStorage > xStorage = comphelper::OStorageHelper::GetTemporaryStorage();
666 
667         //TODO/LATER: what about "bLink"?
668 
669         uno::Sequence < beans::PropertyValue > aMedium(1);
670         aMedium[0].Name = "URL";
671         aMedium[0].Value <<= aStrURL;
672 
673         comphelper::EmbeddedObjectContainer aCnt( xStorage );
674         OUString aName;
675         uno::Reference < embed::XEmbeddedObject > xObj = aCnt.InsertEmbeddedObject( aMedium, aName );
676         if( xObj.is() )
677             return PasteObject( rPos, xObj, nullptr );
678 
679         // If an OLE object can't be created, insert a URL button
680 
681         GetViewData().GetViewShell()->InsertURLButton( aStrURL, aStrURL, EMPTY_OUSTRING, &rPos );
682         return true;
683     }
684 }
685 
PasteBookmark(SotClipboardFormatId nFormatId,const css::uno::Reference<css::datatransfer::XTransferable> & rxTransferable,SCCOL nPosX,SCROW nPosY)686 bool ScViewFunc::PasteBookmark( SotClipboardFormatId nFormatId,
687                                 const css::uno::Reference< css::datatransfer::XTransferable >& rxTransferable,
688                                 SCCOL nPosX, SCROW nPosY )
689 {
690     INetBookmark aBookmark;
691     TransferableDataHelper aDataHelper( rxTransferable );
692     if ( !aDataHelper.GetINetBookmark( nFormatId, aBookmark ) )
693         return false;
694 
695     InsertBookmark( aBookmark.GetDescription(), aBookmark.GetURL(), nPosX, nPosY );
696     return true;
697 }
698 
InsertBookmark(const OUString & rDescription,const OUString & rURL,SCCOL nPosX,SCROW nPosY,const OUString * pTarget,bool bTryReplace)699 void ScViewFunc::InsertBookmark( const OUString& rDescription, const OUString& rURL,
700                                     SCCOL nPosX, SCROW nPosY, const OUString* pTarget,
701                                     bool bTryReplace )
702 {
703     ScViewData& rViewData = GetViewData();
704     if ( rViewData.HasEditView( rViewData.GetActivePart() ) &&
705             nPosX >= rViewData.GetEditStartCol() && nPosX <= rViewData.GetEditEndCol() &&
706             nPosY >= rViewData.GetEditStartRow() && nPosY <= rViewData.GetEditEndRow() )
707     {
708         // insert into the cell which just got edited
709 
710         OUString aTargetFrame;
711         if (pTarget)
712             aTargetFrame = *pTarget;
713         rViewData.GetViewShell()->InsertURLField( rDescription, rURL, aTargetFrame );
714         return;
715     }
716 
717     // insert into not edited cell
718 
719     ScDocument* pDoc = GetViewData().GetDocument();
720     SCTAB nTab = GetViewData().GetTabNo();
721     ScAddress aCellPos( nPosX, nPosY, nTab );
722     EditEngine aEngine( pDoc->GetEnginePool() );
723 
724     const EditTextObject* pOld = pDoc->GetEditText(aCellPos);
725     if (pOld)
726         aEngine.SetText(*pOld);
727     else
728     {
729         OUString aOld;
730         pDoc->GetInputString(nPosX, nPosY, nTab, aOld);
731         if (!aOld.isEmpty())
732             aEngine.SetText(aOld);
733     }
734 
735     sal_Int32 nPara = aEngine.GetParagraphCount();
736     if (nPara)
737         --nPara;
738     sal_Int32 nTxtLen = aEngine.GetTextLen(nPara);
739     ESelection aInsSel( nPara, nTxtLen, nPara, nTxtLen );
740 
741     if ( bTryReplace && HasBookmarkAtCursor( nullptr ) )
742     {
743         //  if called from hyperlink slot and cell contains only a URL,
744         //  replace old URL with new one
745 
746         aInsSel = ESelection( 0, 0, 0, 1 );     // replace first character (field)
747     }
748 
749     SvxURLField aField( rURL, rDescription, SvxURLFormat::AppDefault );
750     if (pTarget)
751         aField.SetTargetFrame(*pTarget);
752     aEngine.QuickInsertField( SvxFieldItem( aField, EE_FEATURE_FIELD ), aInsSel );
753 
754     std::unique_ptr<EditTextObject> pData(aEngine.CreateTextObject());
755     EnterData(nPosX, nPosY, nTab, *pData);
756 }
757 
HasBookmarkAtCursor(SvxHyperlinkItem * pContent)758 bool ScViewFunc::HasBookmarkAtCursor( SvxHyperlinkItem* pContent )
759 {
760     ScAddress aPos( GetViewData().GetCurX(), GetViewData().GetCurY(), GetViewData().GetTabNo() );
761     ScDocument& rDoc = GetViewData().GetDocShell()->GetDocument();
762 
763     const EditTextObject* pData = rDoc.GetEditText(aPos);
764     if (!pData)
765         return false;
766 
767     if (!pData->IsFieldObject())
768         // not a field object.
769         return false;
770 
771     const SvxFieldItem* pFieldItem = pData->GetField();
772     if (!pFieldItem)
773         // doesn't have a field item.
774         return false;
775 
776     const SvxFieldData* pField = pFieldItem->GetField();
777     if (!pField)
778         // doesn't have a field item data.
779         return false;
780 
781     if (pField->GetClassId() != css::text::textfield::Type::URL)
782         // not a URL field.
783         return false;
784 
785     if (pContent)
786     {
787         const SvxURLField* pURLField = static_cast<const SvxURLField*>(pField);
788         pContent->SetName( pURLField->GetRepresentation() );
789         pContent->SetURL( pURLField->GetURL() );
790         pContent->SetTargetFrame( pURLField->GetTargetFrame() );
791     }
792     return true;
793 }
794 
795 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
796