nss: upgrade to release 3.73
[LibreOffice.git] / sw / source / uibase / wrtsh / wrtsh2.cxx
blob93cd532781ff4073f8977b9ced1b4f995638fa4a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <hintids.hxx>
21 #include <svl/macitem.hxx>
22 #include <sfx2/frame.hxx>
23 #include <svl/eitem.hxx>
24 #include <svl/listener.hxx>
25 #include <svl/stritem.hxx>
26 #include <sfx2/docfile.hxx>
27 #include <sfx2/dispatch.hxx>
28 #include <sfx2/linkmgr.hxx>
29 #include <sfx2/viewfrm.hxx>
30 #include <sot/exchange.hxx>
31 #include <fmtinfmt.hxx>
32 #include <wrtsh.hxx>
33 #include <docsh.hxx>
34 #include <fldbas.hxx>
35 #include <expfld.hxx>
36 #include <docufld.hxx>
37 #include <reffld.hxx>
38 #include <swundo.hxx>
39 #include <doc.hxx>
40 #include <frmfmt.hxx>
41 #include <fmtfld.hxx>
42 #include <view.hxx>
43 #include <swevent.hxx>
44 #include <section.hxx>
45 #include <navicont.hxx>
46 #include <txtinet.hxx>
47 #include <cmdid.h>
48 #include <swabstdlg.hxx>
49 #include <SwRewriter.hxx>
51 #include <com/sun/star/document/XDocumentProperties.hpp>
52 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
54 #include <memory>
56 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
57 #include <comphelper/lok.hxx>
58 #include <sfx2/event.hxx>
59 #include <sal/log.hxx>
61 void SwWrtShell::Insert(SwField const& rField, SwPaM* pAnnotationRange)
63 ResetCursorStack();
64 if(!CanInsert())
65 return;
66 StartAllAction();
68 SwRewriter aRewriter;
69 aRewriter.AddRule(UndoArg1, rField.GetDescription());
71 StartUndo(SwUndoId::INSERT, &aRewriter);
73 bool bDeleted = false;
74 std::unique_ptr<SwPaM> pAnnotationTextRange;
75 if (pAnnotationRange)
77 pAnnotationTextRange.reset(new SwPaM(*pAnnotationRange->Start(), *pAnnotationRange->End()));
80 if ( HasSelection() )
82 if ( rField.GetTyp()->Which() == SwFieldIds::Postit )
84 // for annotation fields:
85 // - keep the current selection in order to create a corresponding annotation mark
86 // - collapse cursor to its end
87 if ( IsTableMode() )
89 GetTableCrs()->Normalize( false );
90 const SwPosition rStartPos( *(GetTableCrs()->GetMark()->nNode.GetNode().GetContentNode()), 0 );
91 KillPams();
92 if ( !IsEndOfPara() )
94 EndPara();
96 const SwPosition rEndPos( *GetCurrentShellCursor().GetPoint() );
97 pAnnotationTextRange.reset(new SwPaM( rStartPos, rEndPos ));
99 else
101 NormalizePam( false );
102 const SwPaM& rCurrPaM = GetCurrentShellCursor();
103 pAnnotationTextRange.reset(new SwPaM( *rCurrPaM.GetPoint(), *rCurrPaM.GetMark() ));
104 ClearMark();
107 else
109 bDeleted = DelRight();
113 SwEditShell::Insert2(rField, bDeleted);
115 if ( pAnnotationTextRange )
117 if ( GetDoc() != nullptr )
119 const SwPaM& rCurrPaM = GetCurrentShellCursor();
120 if (*rCurrPaM.Start() == *pAnnotationTextRange->Start()
121 && *rCurrPaM.End() == *pAnnotationTextRange->End())
123 // Annotation range was passed in externally, and inserting the postit field shifted
124 // its start/end positions right by one. Restore the original position for the range
125 // start. This allows commenting on the placeholder character of the field.
126 SwIndex& rRangeStart = pAnnotationTextRange->Start()->nContent;
127 if (rRangeStart.GetIndex() > 0)
128 --rRangeStart;
130 IDocumentMarkAccess* pMarksAccess = GetDoc()->getIDocumentMarkAccess();
131 pMarksAccess->makeAnnotationMark( *pAnnotationTextRange, OUString() );
133 pAnnotationTextRange.reset();
136 EndUndo();
137 EndAllAction();
140 // Start the field update
142 void SwWrtShell::UpdateInputFields( SwInputFieldList* pLst )
144 // Go through the list of fields and updating
145 std::unique_ptr<SwInputFieldList> pTmp;
146 if (!pLst)
148 pTmp.reset(new SwInputFieldList( this ));
149 pLst = pTmp.get();
152 const size_t nCnt = pLst->Count();
153 if(!nCnt)
154 return;
156 pLst->PushCursor();
158 bool bCancel = false;
160 size_t nIndex = 0;
161 FieldDialogPressedButton ePressedButton = FieldDialogPressedButton::NONE;
163 SwField* pField = GetCurField();
164 if (pField)
166 for (size_t i = 0; i < nCnt; i++)
168 if (pField == pLst->GetField(i))
170 nIndex = i;
171 break;
176 while (!bCancel)
178 bool bPrev = nIndex > 0;
179 bool bNext = nIndex < nCnt - 1;
180 pLst->GotoFieldPos(nIndex);
181 pField = pLst->GetField(nIndex);
182 if (pField->GetTyp()->Which() == SwFieldIds::Dropdown)
184 bCancel = StartDropDownFieldDlg(pField, bPrev, bNext, GetView().GetFrameWeld(), &ePressedButton);
186 else
187 bCancel = StartInputFieldDlg(pField, bPrev, bNext, GetView().GetFrameWeld(), &ePressedButton);
189 if (!bCancel)
191 // Otherwise update error at multi-selection:
192 pLst->GetField(nIndex)->GetTyp()->UpdateFields();
194 if (ePressedButton == FieldDialogPressedButton::Previous && nIndex > 0)
195 nIndex--;
196 else if (ePressedButton == FieldDialogPressedButton::Next && nIndex < nCnt - 1)
197 nIndex++;
198 else
199 bCancel = true;
203 pLst->PopCursor();
206 namespace {
208 // Listener class: will close InputField dialog if input field(s)
209 // is(are) deleted (for instance, by an extension) after the dialog shows up.
210 // Otherwise, the for loop in SwWrtShell::UpdateInputFields will crash when doing:
211 // 'pTmp->GetField( i )->GetTyp()->UpdateFields();'
212 // on a deleted field.
213 class FieldDeletionListener : public SvtListener
215 public:
216 FieldDeletionListener(AbstractFieldInputDlg* pInputFieldDlg, SwField* pField)
217 : mpInputFieldDlg(pInputFieldDlg)
218 , mpFormatField(nullptr)
220 SwInputField *const pInputField(dynamic_cast<SwInputField*>(pField));
221 SwSetExpField *const pSetExpField(dynamic_cast<SwSetExpField*>(pField));
223 if (pInputField && pInputField->GetFormatField())
225 mpFormatField = pInputField->GetFormatField();
227 else if (pSetExpField && pSetExpField->GetFormatField())
229 mpFormatField = pSetExpField->GetFormatField();
232 // Register for possible field deletion while dialog is open
233 if (mpFormatField)
234 StartListening(mpFormatField->GetNotifier());
237 virtual ~FieldDeletionListener() override
239 // Dialog closed, remove modification listener
240 EndListeningAll();
243 virtual void Notify(const SfxHint& rHint) override
245 // Input field has been deleted: better to close the dialog
246 if(rHint.GetId() == SfxHintId::Dying)
248 mpFormatField = nullptr;
249 mpInputFieldDlg->EndDialog(RET_CANCEL);
252 private:
253 VclPtr<AbstractFieldInputDlg> mpInputFieldDlg;
254 SwFormatField* mpFormatField;
259 // Start input dialog for a specific field
260 bool SwWrtShell::StartInputFieldDlg(SwField* pField, bool bPrevButton, bool bNextButton,
261 weld::Widget* pParentWin, SwWrtShell::FieldDialogPressedButton* pPressedButton)
264 SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
265 ScopedVclPtr<AbstractFieldInputDlg> pDlg(pFact->CreateFieldInputDlg(pParentWin, *this, pField, bPrevButton, bNextButton));
267 bool bRet;
270 FieldDeletionListener aModify(pDlg.get(), pField);
271 bRet = RET_CANCEL == pDlg->Execute();
274 if (pPressedButton)
276 if (pDlg->PrevButtonPressed())
277 *pPressedButton = FieldDialogPressedButton::Previous;
278 else if (pDlg->NextButtonPressed())
279 *pPressedButton = FieldDialogPressedButton::Next;
282 pDlg.disposeAndClear();
283 GetWin()->PaintImmediately();
284 return bRet;
287 bool SwWrtShell::StartDropDownFieldDlg(SwField* pField, bool bPrevButton, bool bNextButton,
288 weld::Widget* pParentWin, SwWrtShell::FieldDialogPressedButton* pPressedButton)
290 SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
291 ScopedVclPtr<AbstractDropDownFieldDialog> pDlg(pFact->CreateDropDownFieldDialog(pParentWin, *this, pField, bPrevButton, bNextButton));
292 const short nRet = pDlg->Execute();
294 if (pPressedButton)
296 if (pDlg->PrevButtonPressed())
297 *pPressedButton = FieldDialogPressedButton::Previous;
298 else if (pDlg->NextButtonPressed())
299 *pPressedButton = FieldDialogPressedButton::Next;
302 pDlg.disposeAndClear();
303 bool bRet = RET_CANCEL == nRet;
304 GetWin()->PaintImmediately();
305 if(RET_YES == nRet)
307 GetView().GetViewFrame()->GetDispatcher()->Execute(FN_EDIT_FIELD, SfxCallMode::SYNCHRON);
309 return bRet;
312 // Insert directory - remove selection
314 void SwWrtShell::InsertTableOf(const SwTOXBase& rTOX, const SfxItemSet* pSet)
316 if(!CanInsert())
317 return;
319 if(HasSelection())
320 DelRight();
322 SwEditShell::InsertTableOf(rTOX, pSet);
325 // Update directory - remove selection
327 void SwWrtShell::UpdateTableOf(const SwTOXBase& rTOX, const SfxItemSet* pSet)
329 if(CanInsert())
331 SwEditShell::UpdateTableOf(rTOX, pSet);
335 // handler for click on the field given as parameter.
336 // the cursor is positioned on the field.
338 void SwWrtShell::ClickToField( const SwField& rField )
340 // cross reference field must not be selected because it moves the cursor
341 if (SwFieldIds::GetRef != rField.GetTyp()->Which())
343 StartAllAction();
344 Right( CRSR_SKIP_CHARS, true, 1, false ); // Select the field.
345 NormalizePam();
346 EndAllAction();
349 m_bIsInClickToEdit = true;
350 switch( rField.GetTyp()->Which() )
352 case SwFieldIds::JumpEdit:
354 sal_uInt16 nSlotId = 0;
355 switch( rField.GetFormat() )
357 case JE_FMT_TABLE:
358 nSlotId = FN_INSERT_TABLE;
359 break;
361 case JE_FMT_FRAME:
362 nSlotId = FN_INSERT_FRAME;
363 break;
365 case JE_FMT_GRAPHIC: nSlotId = SID_INSERT_GRAPHIC; break;
366 case JE_FMT_OLE: nSlotId = SID_INSERT_OBJECT; break;
370 if( nSlotId )
372 StartUndo( SwUndoId::START );
373 //#97295# immediately select the right shell
374 GetView().StopShellTimer();
375 GetView().GetViewFrame()->GetDispatcher()->Execute( nSlotId,
376 SfxCallMode::SYNCHRON|SfxCallMode::RECORD );
377 EndUndo( SwUndoId::END );
380 break;
382 case SwFieldIds::Macro:
384 const SwMacroField *pField = static_cast<const SwMacroField*>(&rField);
385 const OUString sText( rField.GetPar2() );
386 OUString sRet( sText );
387 ExecMacro( pField->GetSvxMacro(), &sRet );
389 // return value changed?
390 if( sRet != sText )
392 StartAllAction();
393 const_cast<SwField&>(rField).SetPar2( sRet );
394 rField.GetTyp()->UpdateFields();
395 EndAllAction();
398 break;
400 case SwFieldIds::GetRef:
401 StartAllAction();
402 SwCursorShell::GotoRefMark( static_cast<const SwGetRefField&>(rField).GetSetRefName(),
403 static_cast<const SwGetRefField&>(rField).GetSubType(),
404 static_cast<const SwGetRefField&>(rField).GetSeqNo() );
405 EndAllAction();
406 break;
408 case SwFieldIds::Input:
410 const SwInputField* pInputField = dynamic_cast<const SwInputField*>(&rField);
411 if ( pInputField == nullptr )
413 StartInputFieldDlg(const_cast<SwField*>(&rField), false, false, GetView().GetFrameWeld());
416 break;
418 case SwFieldIds::SetExp:
419 if( static_cast<const SwSetExpField&>(rField).GetInputFlag() )
420 StartInputFieldDlg(const_cast<SwField*>(&rField), false, false, GetView().GetFrameWeld());
421 break;
422 case SwFieldIds::Dropdown :
423 StartDropDownFieldDlg(const_cast<SwField*>(&rField), false, false, GetView().GetFrameWeld());
424 break;
425 default:
426 SAL_WARN_IF(rField.IsClickable(), "sw", "unhandled clickable field!");
429 m_bIsInClickToEdit = false;
432 void SwWrtShell::ClickToINetAttr( const SwFormatINetFormat& rItem, LoadUrlFlags nFilter )
434 if( rItem.GetValue().isEmpty() )
435 return ;
437 m_bIsInClickToEdit = true;
439 // At first run the possibly set ObjectSelect Macro
440 const SvxMacro* pMac = rItem.GetMacro( SvMacroItemId::OnClick );
441 if( pMac )
443 SwCallMouseEvent aCallEvent;
444 aCallEvent.Set( &rItem );
445 GetDoc()->CallEvent( SvMacroItemId::OnClick, aCallEvent );
448 // So that the implementation of templates is displayed immediately
449 ::LoadURL( *this, rItem.GetValue(), nFilter, rItem.GetTargetFrame() );
450 const SwTextINetFormat* pTextAttr = rItem.GetTextINetFormat();
451 if( pTextAttr )
453 const_cast<SwTextINetFormat*>(pTextAttr)->SetVisited( true );
454 const_cast<SwTextINetFormat*>(pTextAttr)->SetVisitedValid( true );
457 m_bIsInClickToEdit = false;
460 bool SwWrtShell::ClickToINetGrf( const Point& rDocPt, LoadUrlFlags nFilter )
462 bool bRet = false;
463 OUString sURL;
464 OUString sTargetFrameName;
465 const SwFrameFormat* pFnd = IsURLGrfAtPos( rDocPt, &sURL, &sTargetFrameName );
466 if( pFnd && !sURL.isEmpty() )
468 bRet = true;
469 // At first run the possibly set ObjectSelect Macro
470 SwCallMouseEvent aCallEvent;
471 aCallEvent.Set(EVENT_OBJECT_URLITEM, pFnd);
472 GetDoc()->CallEvent(SvMacroItemId::OnClick, aCallEvent);
474 ::LoadURL(*this, sURL, nFilter, sTargetFrameName);
476 return bRet;
479 void LoadURL( SwViewShell& rVSh, const OUString& rURL, LoadUrlFlags nFilter,
480 const OUString& rTargetFrameName )
482 OSL_ENSURE( !rURL.isEmpty(), "what should be loaded here?" );
483 if( rURL.isEmpty() )
484 return ;
486 // The shell could be 0 also!!!!!
487 if ( dynamic_cast<const SwCursorShell*>( &rVSh) == nullptr )
488 return;
490 // We are doing tiledRendering, let the client handles the URL loading,
491 // unless we are jumping to a TOC mark.
492 if (comphelper::LibreOfficeKit::isActive() && !rURL.startsWith("#"))
494 rVSh.GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_HYPERLINK_CLICKED, rURL.toUtf8().getStr());
495 return;
498 //A CursorShell is always a WrtShell
499 SwWrtShell &rSh = static_cast<SwWrtShell&>(rVSh);
501 SwDocShell* pDShell = rSh.GetView().GetDocShell();
502 OSL_ENSURE( pDShell, "No DocShell?!");
503 OUString sTargetFrame(rTargetFrameName);
504 if (sTargetFrame.isEmpty() && pDShell)
506 using namespace ::com::sun::star;
507 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
508 pDShell->GetModel(), uno::UNO_QUERY_THROW);
509 uno::Reference<document::XDocumentProperties> xDocProps
510 = xDPS->getDocumentProperties();
511 sTargetFrame = xDocProps->getDefaultTarget();
514 OUString sReferer;
515 if( pDShell && pDShell->GetMedium() )
516 sReferer = pDShell->GetMedium()->GetName();
517 SfxViewFrame* pViewFrame = rSh.GetView().GetViewFrame();
518 SfxFrameItem aView( SID_DOCFRAME, pViewFrame );
519 SfxStringItem aName( SID_FILE_NAME, rURL );
520 SfxStringItem aTargetFrameName( SID_TARGETNAME, sTargetFrame );
521 SfxStringItem aReferer( SID_REFERER, sReferer );
523 SfxBoolItem aNewView( SID_OPEN_NEW_VIEW, false );
524 //#39076# Silent can be removed accordingly to SFX.
525 SfxBoolItem aBrowse( SID_BROWSE, true );
527 if ((nFilter & LoadUrlFlags::NewView) && !comphelper::LibreOfficeKit::isActive())
528 aTargetFrameName.SetValue( "_blank" );
530 const SfxPoolItem* aArr[] = {
531 &aName,
532 &aNewView, /*&aSilent,*/
533 &aReferer,
534 &aView, &aTargetFrameName,
535 &aBrowse,
536 nullptr
539 pViewFrame->GetDispatcher()->GetBindings()->Execute( SID_OPENDOC, aArr,
540 SfxCallMode::ASYNCHRON|SfxCallMode::RECORD );
543 void SwWrtShell::NavigatorPaste( const NaviContentBookmark& rBkmk,
544 const sal_uInt16 nAction )
546 if( EXCHG_IN_ACTION_COPY == nAction )
548 // Insert
549 OUString sURL = rBkmk.GetURL();
550 // Is this is a jump within the current Doc?
551 const SwDocShell* pDocShell = GetView().GetDocShell();
552 if(pDocShell->HasName())
554 const OUString rName = pDocShell->GetMedium()->GetURLObject().GetURLNoMark();
556 if (sURL.startsWith(rName))
558 if (sURL.getLength()>rName.getLength())
560 sURL = sURL.copy(rName.getLength());
562 else
564 sURL.clear();
568 SwFormatINetFormat aFormat( sURL, OUString() );
569 InsertURL( aFormat, rBkmk.GetDescription() );
571 else
573 SwSectionData aSection( SectionType::FileLink, GetUniqueSectionName() );
574 OUString aLinkFile = rBkmk.GetURL().getToken(0, '#')
575 + OUStringChar(sfx2::cTokenSeparator)
576 + OUStringChar(sfx2::cTokenSeparator)
577 + rBkmk.GetURL().getToken(1, '#');
578 aSection.SetLinkFileName( aLinkFile );
579 aSection.SetProtectFlag( true );
580 const SwSection* pIns = InsertSection( aSection );
581 if( EXCHG_IN_ACTION_MOVE == nAction && pIns )
583 aSection = SwSectionData(*pIns);
584 aSection.SetLinkFileName( OUString() );
585 aSection.SetType( SectionType::Content );
586 aSection.SetProtectFlag( false );
588 // the update of content from linked section at time delete
589 // the undostack. Then the change of the section don't create
590 // any undoobject. - BUG 69145
591 bool bDoesUndo = DoesUndo();
592 SwUndoId nLastUndoId(SwUndoId::EMPTY);
593 if (GetLastUndoInfo(nullptr, & nLastUndoId))
595 if (SwUndoId::INSSECTION != nLastUndoId)
597 DoUndo(false);
600 UpdateSection( GetSectionFormatPos( *pIns->GetFormat() ), aSection );
601 DoUndo( bDoesUndo );
606 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */