Line data Source code
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 <hintids.hxx>
21 : #include <svl/macitem.hxx>
22 : #include <sfx2/frame.hxx>
23 : #include <vcl/msgbox.hxx>
24 : #include <svl/urihelper.hxx>
25 : #include <svl/eitem.hxx>
26 : #include <svl/stritem.hxx>
27 : #include <sfx2/docfile.hxx>
28 : #include <sfx2/fcontnr.hxx>
29 : #include <sfx2/dispatch.hxx>
30 : #include <sfx2/linkmgr.hxx>
31 : #include <fmtinfmt.hxx>
32 : #include <frmatr.hxx>
33 : #include <swtypes.hxx>
34 : #include <wrtsh.hxx>
35 : #include <docsh.hxx>
36 : #include <fldbas.hxx>
37 : #include <expfld.hxx>
38 : #include <ddefld.hxx>
39 : #include <docufld.hxx>
40 : #include <reffld.hxx>
41 : #include <swundo.hxx>
42 : #include <doc.hxx>
43 : #include <IDocumentUndoRedo.hxx>
44 : #include <viewopt.hxx>
45 : #include <frmfmt.hxx>
46 : #include <fmtfld.hxx>
47 : #include <swtable.hxx>
48 : #include <mdiexp.hxx>
49 : #include <view.hxx>
50 : #include <swevent.hxx>
51 : #include <poolfmt.hxx>
52 : #include <section.hxx>
53 : #include <navicont.hxx>
54 : #include <navipi.hxx>
55 : #include <crsskip.hxx>
56 : #include <txtinet.hxx>
57 : #include <cmdid.h>
58 : #include <wrtsh.hrc>
59 : #include "swabstdlg.hxx"
60 : #include "fldui.hrc"
61 : #include <SwRewriter.hxx>
62 :
63 : #include <com/sun/star/document/XDocumentProperties.hpp>
64 : #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
65 :
66 : #include <xmloff/odffields.hxx>
67 : #include <boost/scoped_ptr.hpp>
68 :
69 2 : void SwWrtShell::Insert(SwField &rFld)
70 : {
71 2 : ResetCursorStack();
72 2 : if(!CanInsert())
73 2 : return;
74 2 : StartAllAction();
75 :
76 2 : SwRewriter aRewriter;
77 2 : aRewriter.AddRule(UndoArg1, rFld.GetDescription());
78 :
79 2 : StartUndo(UNDO_INSERT, &aRewriter);
80 :
81 2 : bool bDeleted = false;
82 4 : boost::scoped_ptr<SwPaM> pAnnotationTextRange;
83 2 : if ( HasSelection() )
84 : {
85 0 : if ( rFld.GetTyp()->Which() == RES_POSTITFLD )
86 : {
87 : // for annotation fields:
88 : // - keep the current selection in order to create a corresponding annotation mark
89 : // - collapse cursor to its end
90 0 : if ( IsTableMode() )
91 : {
92 0 : GetTblCrs()->Normalize( false );
93 0 : const SwPosition rStartPos( *(GetTblCrs()->GetMark()->nNode.GetNode().GetCntntNode()), 0 );
94 0 : KillPams();
95 0 : if ( !IsEndOfPara() )
96 : {
97 0 : EndPara();
98 : }
99 0 : const SwPosition rEndPos( *GetCurrentShellCursor().GetPoint() );
100 0 : pAnnotationTextRange.reset(new SwPaM( rStartPos, rEndPos ));
101 : }
102 : else
103 : {
104 0 : NormalizePam( false );
105 0 : const SwPaM& rCurrPaM = GetCurrentShellCursor();
106 0 : pAnnotationTextRange.reset(new SwPaM( *rCurrPaM.GetPoint(), *rCurrPaM.GetMark() ));
107 0 : ClearMark();
108 : }
109 : }
110 : else
111 : {
112 0 : bDeleted = DelRight() != 0;
113 : }
114 : }
115 :
116 2 : SwEditShell::Insert2(rFld, bDeleted);
117 :
118 2 : if ( pAnnotationTextRange )
119 : {
120 0 : if ( GetDoc() != NULL )
121 : {
122 0 : IDocumentMarkAccess* pMarksAccess = GetDoc()->getIDocumentMarkAccess();
123 0 : pMarksAccess->makeAnnotationMark( *pAnnotationTextRange, ::rtl::OUString() );
124 : }
125 0 : pAnnotationTextRange.reset();
126 : }
127 :
128 2 : EndUndo();
129 4 : EndAllAction();
130 : }
131 :
132 : // Start the field update
133 :
134 0 : void SwWrtShell::UpdateInputFlds( SwInputFieldList* pLst )
135 : {
136 : // Go through the list of fields and updating
137 0 : SwInputFieldList* pTmp = pLst;
138 0 : if( !pTmp )
139 0 : pTmp = new SwInputFieldList( this );
140 :
141 0 : const size_t nCnt = pTmp->Count();
142 0 : if(nCnt)
143 : {
144 0 : pTmp->PushCrsr();
145 :
146 0 : bool bCancel = false;
147 0 : OString aDlgPos;
148 0 : for( size_t i = 0; i < nCnt && !bCancel; ++i )
149 : {
150 0 : pTmp->GotoFieldPos( i );
151 0 : SwField* pField = pTmp->GetField( i );
152 0 : if(pField->GetTyp()->Which() == RES_DROPDOWN)
153 0 : bCancel = StartDropDownFldDlg( pField, true, &aDlgPos );
154 : else
155 0 : bCancel = StartInputFldDlg( pField, true, 0, &aDlgPos);
156 :
157 0 : if (!bCancel)
158 : {
159 : // Otherwise update error at multi-selection:
160 0 : pTmp->GetField( i )->GetTyp()->UpdateFlds();
161 : }
162 : }
163 0 : pTmp->PopCrsr();
164 : }
165 :
166 0 : if( !pLst )
167 0 : delete pTmp;
168 0 : }
169 :
170 : // Listener class: will close InputField dialog if input field(s)
171 : // is(are) deleted (for instance, by an extension) after the dialog shows up.
172 : // Otherwise, the for loop in SwWrtShell::UpdateInputFlds will crash when doing:
173 : // 'pTmp->GetField( i )->GetTyp()->UpdateFlds();'
174 : // on a deleted field.
175 0 : class FieldDeletionModify : public SwModify
176 : {
177 : public:
178 0 : FieldDeletionModify(AbstractFldInputDlg* pInputFieldDlg) : mpInputFieldDlg(pInputFieldDlg) {}
179 :
180 0 : void Modify( const SfxPoolItem* pOld, const SfxPoolItem *) SAL_OVERRIDE
181 : {
182 : // Input field has been deleted: better to close the dialog
183 0 : if (pOld)
184 : {
185 0 : switch (pOld->Which())
186 : {
187 : case RES_REMOVE_UNO_OBJECT:
188 : case RES_OBJECTDYING:
189 0 : mpInputFieldDlg->EndDialog(RET_CANCEL);
190 0 : break;
191 : }
192 : }
193 0 : }
194 : private:
195 : AbstractFldInputDlg* mpInputFieldDlg;
196 : };
197 :
198 : // Start input dialog for a specific field
199 :
200 0 : bool SwWrtShell::StartInputFldDlg( SwField* pFld, bool bNextButton,
201 : vcl::Window* pParentWin, OString* pWindowState )
202 : {
203 :
204 0 : SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
205 : OSL_ENSURE(pFact, "Dialog creation failed!");
206 0 : boost::scoped_ptr<AbstractFldInputDlg> pDlg(pFact->CreateFldInputDlg(pParentWin, *this, pFld, bNextButton));
207 : OSL_ENSURE(pDlg, "Dialog creation failed!");
208 0 : if(pWindowState && !pWindowState->isEmpty())
209 0 : pDlg->SetWindowState(*pWindowState);
210 :
211 0 : FieldDeletionModify aModify(pDlg.get());
212 0 : SwInputField *const pInputField(dynamic_cast<SwInputField*>(pFld));
213 0 : SwSetExpField *const pSetExpFld(dynamic_cast<SwSetExpField*>(pFld));
214 0 : if (pInputField && pInputField->GetFmtFld())
215 : {
216 : // Register for possible input field deletion while dialog is open
217 0 : pInputField->GetFmtFld()->Add(&aModify);
218 : }
219 0 : else if (pSetExpFld && pSetExpFld->GetFmtFld())
220 : {
221 0 : pSetExpFld->GetFmtFld()->Add(&aModify);
222 : }
223 :
224 0 : bool bRet = RET_CANCEL == pDlg->Execute();
225 :
226 0 : if (pInputField && pInputField->GetFmtFld())
227 : {
228 : // Dialog closed, remove modification listener
229 0 : pInputField->GetFmtFld()->Remove(&aModify);
230 : }
231 0 : else if (pSetExpFld && pSetExpFld->GetFmtFld())
232 : {
233 0 : pSetExpFld->GetFmtFld()->Remove(&aModify);
234 : }
235 :
236 0 : if(pWindowState)
237 0 : *pWindowState = pDlg->GetWindowState();
238 :
239 0 : pDlg.reset();
240 0 : GetWin()->Update();
241 0 : return bRet;
242 : }
243 :
244 0 : bool SwWrtShell::StartDropDownFldDlg(SwField* pFld, bool bNextButton, OString* pWindowState)
245 : {
246 0 : SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
247 : OSL_ENSURE(pFact, "SwAbstractDialogFactory fail!");
248 :
249 0 : boost::scoped_ptr<AbstractDropDownFieldDialog> pDlg(pFact->CreateDropDownFieldDialog(NULL, *this, pFld, bNextButton));
250 : OSL_ENSURE(pDlg, "Dialog creation failed!");
251 0 : if(pWindowState && !pWindowState->isEmpty())
252 0 : pDlg->SetWindowState(*pWindowState);
253 0 : const short nRet = pDlg->Execute();
254 0 : if(pWindowState)
255 0 : *pWindowState = pDlg->GetWindowState();
256 0 : pDlg.reset();
257 0 : bool bRet = RET_CANCEL == nRet;
258 0 : GetWin()->Update();
259 0 : if(RET_YES == nRet)
260 : {
261 0 : GetView().GetViewFrame()->GetDispatcher()->Execute(FN_EDIT_FIELD, SfxCallMode::SYNCHRON);
262 : }
263 0 : return bRet;
264 : }
265 :
266 : // Insert directory - remove selection
267 :
268 0 : void SwWrtShell::InsertTableOf(const SwTOXBase& rTOX, const SfxItemSet* pSet)
269 : {
270 0 : if(!CanInsert())
271 0 : return;
272 :
273 0 : if(HasSelection())
274 0 : DelRight();
275 :
276 0 : SwEditShell::InsertTableOf(rTOX, pSet);
277 : }
278 :
279 : // Update directory - remove selection
280 :
281 0 : bool SwWrtShell::UpdateTableOf(const SwTOXBase& rTOX, const SfxItemSet* pSet)
282 : {
283 0 : bool bResult = false;
284 :
285 0 : if(CanInsert())
286 : {
287 0 : bResult = SwEditShell::UpdateTableOf(rTOX, pSet);
288 :
289 0 : if (pSet == NULL)
290 : {
291 0 : SwDoc *const pDoc_ = GetDoc();
292 0 : if (pDoc_)
293 : {
294 0 : pDoc_->GetIDocumentUndoRedo().DelAllUndoObj();
295 : }
296 : }
297 : }
298 :
299 0 : return bResult;
300 : }
301 :
302 : // handler for click on the field given as parameter.
303 : // the cursor is positioned on the field.
304 :
305 0 : void SwWrtShell::ClickToField( const SwField& rFld )
306 : {
307 : // cross reference field must not be selected because it moves the cursor
308 0 : if (RES_GETREFFLD != rFld.GetTyp()->Which())
309 : {
310 0 : StartAllAction();
311 0 : Right( CRSR_SKIP_CHARS, true, 1, false ); // Select the field.
312 0 : NormalizePam();
313 0 : EndAllAction();
314 : }
315 :
316 0 : bIsInClickToEdit = true;
317 0 : switch( rFld.GetTyp()->Which() )
318 : {
319 : case RES_JUMPEDITFLD:
320 : {
321 0 : sal_uInt16 nSlotId = 0;
322 0 : switch( rFld.GetFormat() )
323 : {
324 : case JE_FMT_TABLE:
325 0 : nSlotId = FN_INSERT_TABLE;
326 0 : break;
327 :
328 : case JE_FMT_FRAME:
329 0 : nSlotId = FN_INSERT_FRAME;
330 0 : break;
331 :
332 0 : case JE_FMT_GRAPHIC: nSlotId = SID_INSERT_GRAPHIC; break;
333 0 : case JE_FMT_OLE: nSlotId = SID_INSERT_OBJECT; break;
334 :
335 : }
336 :
337 0 : if( nSlotId )
338 : {
339 0 : StartUndo( UNDO_START );
340 : //#97295# immediately select the right shell
341 0 : GetView().StopShellTimer();
342 0 : GetView().GetViewFrame()->GetDispatcher()->Execute( nSlotId,
343 0 : SfxCallMode::SYNCHRON|SfxCallMode::RECORD );
344 0 : EndUndo( UNDO_END );
345 : }
346 : }
347 0 : break;
348 :
349 : case RES_MACROFLD:
350 : {
351 0 : const SwMacroField *pFld = (const SwMacroField*)&rFld;
352 0 : const OUString sText( rFld.GetPar2() );
353 0 : OUString sRet( sText );
354 0 : ExecMacro( pFld->GetSvxMacro(), &sRet );
355 :
356 : // return value changed?
357 0 : if( sRet != sText )
358 : {
359 0 : StartAllAction();
360 0 : ((SwField&)rFld).SetPar2( sRet );
361 0 : ((SwField&)rFld).GetTyp()->UpdateFlds();
362 0 : EndAllAction();
363 0 : }
364 : }
365 0 : break;
366 :
367 : case RES_GETREFFLD:
368 0 : StartAllAction();
369 : SwCrsrShell::GotoRefMark( ((SwGetRefField&)rFld).GetSetRefName(),
370 0 : ((SwGetRefField&)rFld).GetSubType(),
371 0 : ((SwGetRefField&)rFld).GetSeqNo() );
372 0 : EndAllAction();
373 0 : break;
374 :
375 : case RES_INPUTFLD:
376 : {
377 0 : const SwInputField* pInputField = dynamic_cast<const SwInputField*>(&rFld);
378 0 : if ( pInputField == NULL )
379 : {
380 0 : StartInputFldDlg( (SwField*)&rFld, false );
381 : }
382 : }
383 0 : break;
384 :
385 : case RES_SETEXPFLD:
386 0 : if( ((SwSetExpField&)rFld).GetInputFlag() )
387 0 : StartInputFldDlg( (SwField*)&rFld, false );
388 0 : break;
389 : case RES_DROPDOWN :
390 0 : StartDropDownFldDlg( (SwField*)&rFld, false );
391 0 : break;
392 : default:
393 : SAL_WARN_IF(rFld.IsClickable(), "sw", "unhandled clickable field!");
394 : }
395 :
396 0 : bIsInClickToEdit = false;
397 0 : }
398 :
399 0 : void SwWrtShell::ClickToINetAttr( const SwFmtINetFmt& rItem, sal_uInt16 nFilter )
400 : {
401 0 : if( rItem.GetValue().isEmpty() )
402 0 : return ;
403 :
404 0 : bIsInClickToEdit = true;
405 :
406 : // At first run the possibly set ObjectSelect Macro
407 0 : const SvxMacro* pMac = rItem.GetMacro( SFX_EVENT_MOUSECLICK_OBJECT );
408 0 : if( pMac )
409 : {
410 0 : SwCallMouseEvent aCallEvent;
411 0 : aCallEvent.Set( &rItem );
412 0 : GetDoc()->CallEvent( SFX_EVENT_MOUSECLICK_OBJECT, aCallEvent, false );
413 : }
414 :
415 : // So that the implementation of templates is displayed immediately
416 0 : ::LoadURL( *this, rItem.GetValue(), nFilter, rItem.GetTargetFrame() );
417 0 : const SwTxtINetFmt* pTxtAttr = rItem.GetTxtINetFmt();
418 0 : if( pTxtAttr )
419 : {
420 0 : const_cast<SwTxtINetFmt*>(pTxtAttr)->SetVisited( true );
421 0 : const_cast<SwTxtINetFmt*>(pTxtAttr)->SetVisitedValid( true );
422 : }
423 :
424 0 : bIsInClickToEdit = false;
425 : }
426 :
427 0 : bool SwWrtShell::ClickToINetGrf( const Point& rDocPt, sal_uInt16 nFilter )
428 : {
429 0 : bool bRet = false;
430 0 : OUString sURL;
431 0 : OUString sTargetFrameName;
432 0 : const SwFrmFmt* pFnd = IsURLGrfAtPos( rDocPt, &sURL, &sTargetFrameName );
433 0 : if( pFnd && !sURL.isEmpty() )
434 : {
435 0 : bRet = true;
436 : // At first run the possibly set ObjectSelect Macro
437 0 : const SvxMacro* pMac = &pFnd->GetMacro().GetMacro( SFX_EVENT_MOUSECLICK_OBJECT );
438 0 : if( pMac )
439 : {
440 0 : SwCallMouseEvent aCallEvent;
441 0 : aCallEvent.Set( EVENT_OBJECT_URLITEM, pFnd );
442 0 : GetDoc()->CallEvent( SFX_EVENT_MOUSECLICK_OBJECT, aCallEvent, false );
443 : }
444 :
445 0 : ::LoadURL(*this, sURL, nFilter, sTargetFrameName);
446 : }
447 0 : return bRet;
448 : }
449 :
450 0 : void LoadURL( SwViewShell& rVSh, const OUString& rURL, sal_uInt16 nFilter,
451 : const OUString& rTargetFrameName )
452 : {
453 : OSL_ENSURE( !rURL.isEmpty(), "what should be loaded here?" );
454 0 : if( rURL.isEmpty() )
455 0 : return ;
456 :
457 : // The shell could be 0 also!!!!!
458 0 : if ( !rVSh.ISA(SwCrsrShell) )
459 0 : return;
460 :
461 : //A CrsrShell is always a WrtShell
462 0 : SwWrtShell &rSh = (SwWrtShell&)rVSh;
463 :
464 0 : SwDocShell* pDShell = rSh.GetView().GetDocShell();
465 : OSL_ENSURE( pDShell, "No DocShell?!");
466 0 : OUString sTargetFrame(rTargetFrameName);
467 0 : if (sTargetFrame.isEmpty() && pDShell)
468 : {
469 : using namespace ::com::sun::star;
470 : uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
471 0 : pDShell->GetModel(), uno::UNO_QUERY_THROW);
472 : uno::Reference<document::XDocumentProperties> xDocProps
473 0 : = xDPS->getDocumentProperties();
474 0 : sTargetFrame = xDocProps->getDefaultTarget();
475 : }
476 :
477 0 : OUString sReferer;
478 0 : if( pDShell && pDShell->GetMedium() )
479 0 : sReferer = pDShell->GetMedium()->GetName();
480 0 : SfxViewFrame* pViewFrm = rSh.GetView().GetViewFrame();
481 0 : SfxFrameItem aView( SID_DOCFRAME, pViewFrm );
482 0 : SfxStringItem aName( SID_FILE_NAME, rURL );
483 0 : SfxStringItem aTargetFrameName( SID_TARGETNAME, sTargetFrame );
484 0 : SfxStringItem aReferer( SID_REFERER, sReferer );
485 :
486 0 : SfxBoolItem aNewView( SID_OPEN_NEW_VIEW, false );
487 : //#39076# Silent can be removed accordingly to SFX.
488 0 : SfxBoolItem aBrowse( SID_BROWSE, true );
489 :
490 0 : if( nFilter & URLLOAD_NEWVIEW )
491 0 : aTargetFrameName.SetValue( OUString("_blank") );
492 :
493 : const SfxPoolItem* aArr[] = {
494 : &aName,
495 : &aNewView, /*&aSilent,*/
496 : &aReferer,
497 : &aView, &aTargetFrameName,
498 : &aBrowse,
499 : 0L
500 0 : };
501 :
502 : pViewFrm->GetDispatcher()->GetBindings()->Execute( SID_OPENDOC, aArr, 0,
503 0 : SfxCallMode::ASYNCHRON|SfxCallMode::RECORD );
504 : }
505 :
506 0 : void SwWrtShell::NavigatorPaste( const NaviContentBookmark& rBkmk,
507 : const sal_uInt16 nAction )
508 : {
509 0 : if( EXCHG_IN_ACTION_COPY == nAction )
510 : {
511 : // Insert
512 0 : OUString sURL = rBkmk.GetURL();
513 : // Is this is a jump within the current Doc?
514 0 : const SwDocShell* pDocShell = GetView().GetDocShell();
515 0 : if(pDocShell->HasName())
516 : {
517 0 : const OUString rName = pDocShell->GetMedium()->GetURLObject().GetURLNoMark();
518 :
519 0 : if (sURL.startsWith(rName))
520 : {
521 0 : if (sURL.getLength()>rName.getLength())
522 : {
523 0 : sURL = sURL.copy(rName.getLength());
524 : }
525 : else
526 : {
527 0 : sURL = OUString();
528 : }
529 0 : }
530 : }
531 0 : SwFmtINetFmt aFmt( sURL, OUString() );
532 0 : InsertURL( aFmt, rBkmk.GetDescription() );
533 : }
534 : else
535 : {
536 0 : SwSectionData aSection( FILE_LINK_SECTION, GetUniqueSectionName() );
537 0 : OUString aLinkFile( rBkmk.GetURL().getToken(0, '#') );
538 0 : aLinkFile += OUString(sfx2::cTokenSeparator);
539 0 : aLinkFile += OUString(sfx2::cTokenSeparator);
540 0 : aLinkFile += rBkmk.GetURL().getToken(1, '#');
541 0 : aSection.SetLinkFileName( aLinkFile );
542 0 : aSection.SetProtectFlag( true );
543 0 : const SwSection* pIns = InsertSection( aSection );
544 0 : if( EXCHG_IN_ACTION_MOVE == nAction && pIns )
545 : {
546 0 : aSection = SwSectionData(*pIns);
547 0 : aSection.SetLinkFileName( OUString() );
548 0 : aSection.SetType( CONTENT_SECTION );
549 0 : aSection.SetProtectFlag( false );
550 :
551 : // the update of content from linked section at time delete
552 : // the undostack. Then the change of the section dont create
553 : // any undoobject. - BUG 69145
554 0 : bool bDoesUndo = DoesUndo();
555 0 : SwUndoId nLastUndoId(UNDO_EMPTY);
556 0 : if (GetLastUndoInfo(0, & nLastUndoId))
557 : {
558 0 : if (UNDO_INSSECTION != nLastUndoId)
559 : {
560 0 : DoUndo(false);
561 : }
562 : }
563 0 : UpdateSection( GetSectionFmtPos( *pIns->GetFmt() ), aSection );
564 0 : DoUndo( bDoesUndo );
565 0 : }
566 : }
567 270 : }
568 :
569 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|