1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sd.hxx"
26
27 #include "Outliner.hxx"
28 #include <vcl/wrkwin.hxx>
29 #include <svl/srchitem.hxx>
30 #include <editeng/colritem.hxx>
31 #include <editeng/eeitem.hxx>
32 #include <editeng/editstat.hxx>
33 #include <vcl/outdev.hxx>
34 #include <svx/dlgutil.hxx>
35 #include <svx/xtable.hxx>
36 #include <vcl/msgbox.hxx>
37 #include <sfx2/dispatch.hxx>
38 #include <sfx2/printer.hxx>
39 #include <svx/svxerr.hxx>
40 #include <svx/svdotext.hxx>
41 #include <editeng/unolingu.hxx>
42 #include <svx/svditer.hxx>
43 #include <comphelper/extract.hxx>
44 #include <com/sun/star/linguistic2/XSpellChecker1.hpp>
45 #include <com/sun/star/beans/XPropertySet.hpp>
46 #include <comphelper/processfactory.hxx>
47 #include <editeng/eeitem.hxx>
48 #include <editeng/forbiddencharacterstable.hxx>
49 #include <svx/srchdlg.hxx>
50 #include <unotools/linguprops.hxx>
51 #include <unotools/lingucfg.hxx>
52 #include <editeng/editeng.hxx>
53 #include <vcl/metric.hxx>
54 #include <sfx2/viewfrm.hxx>
55 #include <svtools/langtab.hxx>
56 #include <tools/diagnose_ex.h>
57
58 #include "strings.hrc"
59 #include "sdstring.hrc"
60 #include "eetext.hxx"
61 #include "sdpage.hxx"
62 #include "app.hxx"
63 #include "Window.hxx"
64 #include "sdresid.hxx"
65 #include "DrawViewShell.hxx"
66 #include "OutlineViewShell.hxx"
67 #include "drawdoc.hxx"
68 #include "DrawDocShell.hxx"
69 #include "FrameView.hxx"
70 #include "optsitem.hxx"
71 #include "drawview.hxx"
72 #include "ViewShellBase.hxx"
73 #include "SpellDialogChildWindow.hxx"
74 #include "ToolBarManager.hxx"
75 #include "framework/FrameworkHelper.hxx"
76 #include <svx/svxids.hrc>
77 #include <editeng/editerr.hxx>
78
79 using ::rtl::OUString;
80 using namespace ::com::sun::star;
81 using namespace ::com::sun::star::uno;
82 using namespace ::com::sun::star::lang;
83 using namespace ::com::sun::star::linguistic2;
84
85 class SfxStyleSheetPool;
86
87 namespace sd {
88
89 class Outliner::Implementation
90 {
91 public:
92 /** The original edit mode directly after switching to a different view
93 mode. Used for restoring the edit mode when leaving that view mode
94 again.
95 */
96 EditMode meOriginalEditMode;
97
98 Implementation (void);
99 ~Implementation (void);
100
101 /** Return the OutlinerView that was provided by the last call to
102 ProvideOutlinerView() (or NULL when there was no such call.)
103 */
104 OutlinerView* GetOutlinerView (void);
105
106 /** Provide in the member mpOutlineView an instance of OutlinerView that
107 is either taken from the ViewShell, when it is an OutlineViewShell,
108 or is created. When an OutlinerView already exists it is initialied.
109 */
110 void ProvideOutlinerView (
111 Outliner& rOutliner,
112 const ::boost::shared_ptr<ViewShell>& rpViewShell,
113 ::Window* pWindow);
114
115 /** This method is called when the OutlinerView is no longer used.
116 */
117 void ReleaseOutlinerView (void);
118
119 private:
120 /** Flag that specifies whether we own the outline view pointed to by
121 <member>mpOutlineView</member> and thus have to
122 delete it in <member>EndSpelling()</member>.
123 */
124 bool mbOwnOutlineView;
125
126 /** The outline view used for searching and spelling. If searching or
127 spell checking an outline view this data member points to that view.
128 For all other views an instance is created. The
129 <member>mbOwnOutlineView</member> distinguishes between both cases.
130 */
131 OutlinerView* mpOutlineView;
132 };
133
134
135
136
137 /*************************************************************************
138 |*
139 |* Ctor
140 |*
141 \************************************************************************/
142
Outliner(SdDrawDocument * pDoc,sal_uInt16 nMode)143 Outliner::Outliner( SdDrawDocument* pDoc, sal_uInt16 nMode )
144 : SdrOutliner( &pDoc->GetItemPool(), nMode ),
145 mpImpl(new Implementation()),
146 meMode(SEARCH),
147 mpView(NULL),
148 mpWeakViewShell(),
149 mpWindow(NULL),
150 mpDrawDocument(pDoc),
151 mnConversionLanguage(LANGUAGE_NONE),
152 mnIgnoreCurrentPageChangesLevel(0),
153 mbStringFound(sal_False),
154 mbMatchMayExist(false),
155 mnPageCount(0),
156 mnObjectCount(0),
157 mbEndOfSearch(sal_False),
158 mbFoundObject(sal_False),
159 mbError(sal_False),
160 mbDirectionIsForward(true),
161 mbRestrictSearchToSelection(false),
162 maMarkListCopy(),
163 mbProcessCurrentViewOnly(false),
164 mpObj(NULL),
165 mpFirstObj(NULL),
166 mpTextObj(NULL),
167 mnText(0),
168 mpParaObj(NULL),
169 meStartViewMode(PK_STANDARD),
170 meStartEditMode(EM_PAGE),
171 mnStartPageIndex((sal_uInt16)-1),
172 mpStartEditedObject(NULL),
173 maStartSelection(),
174 mpSearchItem(NULL),
175 maObjectIterator(),
176 maCurrentPosition(),
177 maSearchStartPosition(),
178 maLastValidPosition(),
179 mbSelectionHasChanged(false),
180 mbExpectingSelectionChangeEvent(false),
181 mbWholeDocumentProcessed(false),
182 mbPrepareSpellingPending(true)
183 {
184 SetStyleSheetPool((SfxStyleSheetPool*) mpDrawDocument->GetStyleSheetPool());
185 SetEditTextObjectPool( &pDoc->GetItemPool() );
186 SetCalcFieldValueHdl(LINK(SD_MOD(), SdModule, CalcFieldValueHdl));
187 SetForbiddenCharsTable( pDoc->GetForbiddenCharsTable() );
188
189 sal_uLong nCntrl = GetControlWord();
190 nCntrl |= EE_CNTRL_ALLOWBIGOBJS;
191 nCntrl |= EE_CNTRL_URLSFXEXECUTE;
192 nCntrl |= EE_CNTRL_MARKFIELDS;
193 nCntrl |= EE_CNTRL_AUTOCORRECT;
194
195 sal_Bool bOnlineSpell = false;
196
197 DrawDocShell* pDocSh = mpDrawDocument->GetDocSh();
198
199 if (pDocSh)
200 {
201 bOnlineSpell = mpDrawDocument->GetOnlineSpell();
202 }
203 else
204 {
205 bOnlineSpell = false;
206
207 try
208 {
209 const SvtLinguConfig aLinguConfig;
210 Any aAny;
211
212 aAny = aLinguConfig.GetProperty(
213 rtl::OUString::createFromAscii( UPN_IS_SPELL_AUTO ) );
214 aAny >>= bOnlineSpell;
215 }
216 catch( ... )
217 {
218 DBG_ERROR( "Ill. type in linguistic property" );
219 }
220 }
221
222 if (bOnlineSpell)
223 nCntrl |= EE_CNTRL_ONLINESPELLING;
224 else
225 nCntrl &= ~EE_CNTRL_ONLINESPELLING;
226
227 SetControlWord(nCntrl);
228
229 Reference< XSpellChecker1 > xSpellChecker( LinguMgr::GetSpellChecker() );
230 if ( xSpellChecker.is() )
231 SetSpeller( xSpellChecker );
232
233 Reference< XHyphenator > xHyphenator( LinguMgr::GetHyphenator() );
234 if( xHyphenator.is() )
235 SetHyphenator( xHyphenator );
236
237 SetDefaultLanguage( Application::GetSettings().GetLanguage() );
238 }
239
240
241
242
243 /// Nothing spectecular in the destructor.
~Outliner(void)244 Outliner::~Outliner (void)
245 {
246 mpImpl.reset();
247 }
248
249
250
251
252 /** Prepare find&replace or spellchecking. This distinguishes between three
253 cases:
254 <ol>
255 <li>The current shell is a <type>DrawViewShell</type>: Create a
256 <type>OutlinerView</type> object and search all objects of (i) the
257 current mark list, (ii) of the current view, or (iii) of all the view
258 combinations:
259 <ol>
260 <li>Draw view, slide view</li>
261 <li>Draw view, background view</li>
262 <li>Notes view, slide view</li>
263 <li>Notes view, background view</li>
264 <li>Handout view, slide view</li>
265 <li>Handout view, background view</li>
266 </ol>
267
268 <li>When the current shell is a <type>SdOutlineViewShell</type> then
269 directly operate on it. No switching into other views takes place.</li>
270
271 <li>For a <type>SlideViewShell</type> no action is performed.</li>
272 </ol>
273 */
PrepareSpelling(void)274 void Outliner::PrepareSpelling (void)
275 {
276 mbPrepareSpellingPending = false;
277
278 ViewShellBase* pBase = PTR_CAST(ViewShellBase,SfxViewShell::Current());
279 if (pBase != NULL)
280 SetViewShell (pBase->GetMainViewShell());
281 SetRefDevice( SD_MOD()->GetRefDevice( *mpDrawDocument->GetDocSh() ) );
282
283 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock());
284 if (pViewShell)
285 {
286 mbStringFound = sal_False;
287
288 mbWholeDocumentProcessed = false;
289 // Supposed that we are not located at the very beginning/end of
290 // the document then there may be a match in the document
291 // prior/after the current position.
292 mbMatchMayExist = sal_True;
293
294 maObjectIterator = ::sd::outliner::Iterator();
295 maSearchStartPosition = ::sd::outliner::Iterator();
296 RememberStartPosition();
297
298 mpImpl->ProvideOutlinerView(*this, pViewShell, mpWindow);
299
300 HandleChangedSelection ();
301 }
302 ClearModifyFlag();
303 }
304
305
306
307
308
StartSpelling(void)309 void Outliner::StartSpelling (void)
310 {
311 meMode = SPELL;
312 mbDirectionIsForward = true;
313 mpSearchItem = NULL;
314 }
315
316 /** Proxy for method from base class to avoid compiler warning */
StartSpelling(EditView & rView,unsigned char c)317 void Outliner::StartSpelling(EditView& rView, unsigned char c)
318 {
319 SdrOutliner::StartSpelling( rView, c );
320 }
321
322 /** Free all resources acquired during the search/spell check. After a
323 spell check the start position is restored here.
324 */
EndSpelling(void)325 void Outliner::EndSpelling (void)
326 {
327 // Keep old view shell alive until we release the outliner view.
328 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock());
329 ::boost::shared_ptr<ViewShell> pOldViewShell (pViewShell);
330
331 ViewShellBase* pBase = PTR_CAST(ViewShellBase,SfxViewShell::Current());
332 if (pBase != NULL)
333 pViewShell = pBase->GetMainViewShell();
334 else
335 pViewShell.reset();
336 mpWeakViewShell = pViewShell;
337
338 // When in <member>PrepareSpelling()</member> a new outline view has
339 // been created then delete it here.
340 sal_Bool bViewIsDrawViewShell(pViewShell && pViewShell->ISA(DrawViewShell));
341 if (bViewIsDrawViewShell)
342 {
343 SetStatusEventHdl(Link());
344 mpView = pViewShell->GetView();
345 mpView->UnmarkAllObj (mpView->GetSdrPageView());
346 mpView->SdrEndTextEdit();
347 // Make FuSelection the current function.
348 pViewShell->GetDispatcher()->Execute(
349 SID_OBJECT_SELECT,
350 SFX_CALLMODE_SYNCHRON | SFX_CALLMODE_RECORD);
351
352 // Remove and, if previously created by us, delete the outline
353 // view.
354 OutlinerView* pOutlinerView = mpImpl->GetOutlinerView();
355 if (pOutlinerView != NULL)
356 {
357 RemoveView(pOutlinerView);
358 mpImpl->ReleaseOutlinerView();
359 }
360
361 SetUpdateMode(sal_True);
362 }
363
364 // #95811# Before clearing the modify flag use it as a hint that
365 // changes were done at SpellCheck
366 if(IsModified())
367 {
368 if(mpView && mpView->ISA(OutlineView))
369 static_cast<OutlineView*>(mpView)->PrepareClose(sal_False);
370 if(mpDrawDocument && !mpDrawDocument->IsChanged())
371 mpDrawDocument->SetChanged(sal_True);
372 }
373
374 // #95811# now clear the modify flag to have a specified state of
375 // Outliner
376 ClearModifyFlag();
377
378 // When spell checking then restore the start position.
379 if (meMode==SPELL || meMode==TEXT_CONVERSION)
380 RestoreStartPosition ();
381
382 mpWeakViewShell.reset();
383 mpView = NULL;
384 mpWindow = NULL;
385 }
386
387
388
389
SpellNextDocument(void)390 sal_Bool Outliner::SpellNextDocument (void)
391 {
392 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock());
393 if (pViewShell->ISA(OutlineViewShell))
394 {
395 // When doing a spell check in the outline view then there is
396 // only one document.
397 mbEndOfSearch = true;
398 EndOfSearch ();
399 }
400 else
401 {
402 if (mpView->ISA(OutlineView))
403 ((OutlineView*)mpView)->PrepareClose(sal_False);
404 mpDrawDocument->GetDocSh()->SetWaitCursor( sal_True );
405
406 Initialize (true);
407
408 mpWindow = pViewShell->GetActiveWindow();
409 OutlinerView* pOutlinerView = mpImpl->GetOutlinerView();
410 if (pOutlinerView != NULL)
411 pOutlinerView->SetWindow(mpWindow);
412 ProvideNextTextObject ();
413
414 mpDrawDocument->GetDocSh()->SetWaitCursor( sal_False );
415 ClearModifyFlag();
416 }
417
418 return mbEndOfSearch ? sal_False : sal_True;
419
420 }
421
422
423 /*************************************************************************
424 |*
425 |* Spelling: naechstes TextObjekt pruefen
426 |*
427 \************************************************************************/
428
GetNextSpellSentence(void)429 ::svx::SpellPortions Outliner::GetNextSpellSentence (void)
430 {
431 ::svx::SpellPortions aResult;
432
433 DetectChange();
434 // Iterate over sentences and text shapes until a sentence with a
435 // spelling error has been found. If no such sentence can be
436 // found the loop is left through a break.
437 // It is the responsibility of the sd outliner object to correctly
438 // iterate over all text shapes, i.e. switch between views, wrap
439 // around at the end of the document, stop when all text shapes
440 // have been examined exactly once.
441 bool bFoundNextSentence = false;
442 while ( ! bFoundNextSentence)
443 {
444 OutlinerView* pOutlinerView = GetView(0);
445 if (pOutlinerView != NULL)
446 {
447 ESelection aCurrentSelection (pOutlinerView->GetSelection());
448 if ( ! mbMatchMayExist
449 && maStartSelection.IsLess(aCurrentSelection))
450 EndOfSearch();
451
452 // Advance to the next sentence.
453 bFoundNextSentence = SpellSentence (
454 pOutlinerView->GetEditView(),
455 aResult, false);
456 }
457
458 // When no sentence with spelling errors has been found in the
459 // currently selected text shape or there is no selected text
460 // shape then advance to the next text shape.
461 if ( ! bFoundNextSentence)
462 if ( ! SpellNextDocument())
463 // All text objects have been processed so exit the
464 // loop and return an empty portions list.
465 break;
466 }
467
468 return aResult;
469 }
470
471
472
473
474 /** Go to next match.
475 */
StartSearchAndReplace(const SvxSearchItem * pSearchItem)476 bool Outliner::StartSearchAndReplace (const SvxSearchItem* pSearchItem)
477 {
478 sal_Bool bEndOfSearch = sal_True;
479
480 mpDrawDocument->GetDocSh()->SetWaitCursor( sal_True );
481 if (mbPrepareSpellingPending)
482 PrepareSpelling();
483 ViewShellBase* pBase = PTR_CAST(ViewShellBase,SfxViewShell::Current());
484 // Determine whether we have to abort the search. This is necessary
485 // when the main view shell does not support searching.
486 bool bAbort = false;
487 if (pBase != NULL)
488 {
489 ::boost::shared_ptr<ViewShell> pShell (pBase->GetMainViewShell());
490 SetViewShell(pShell);
491 if (pShell.get() == NULL)
492 bAbort = true;
493 else
494 switch (pShell->GetShellType())
495 {
496 case ViewShell::ST_DRAW:
497 case ViewShell::ST_IMPRESS:
498 case ViewShell::ST_NOTES:
499 case ViewShell::ST_HANDOUT:
500 case ViewShell::ST_OUTLINE:
501 bAbort = false;
502 break;
503 default:
504 bAbort = true;
505 break;
506 }
507 }
508
509 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock());
510 if ( ! pViewShell)
511 {
512 OSL_ASSERT(pViewShell);
513 return true;
514 }
515
516 if ( ! bAbort)
517 {
518 meMode = SEARCH;
519 mpSearchItem = pSearchItem;
520
521 mbFoundObject = sal_False;
522
523 Initialize ( ! mpSearchItem->GetBackward());
524
525 const sal_uInt16 nCommand (mpSearchItem->GetCommand());
526 if (nCommand == SVX_SEARCHCMD_REPLACE_ALL)
527 bEndOfSearch = SearchAndReplaceAll ();
528 else
529 {
530 RememberStartPosition ();
531 bEndOfSearch = SearchAndReplaceOnce ();
532 //#107233# restore start position if nothing was found
533 if(!mbStringFound)
534 RestoreStartPosition ();
535 else
536 mnStartPageIndex = (sal_uInt16)-1;
537 }
538 if ( Application::IsAccessibilityEnabled() )
539 {
540 SvxSearchDialog* pSearchDlg =
541 ((SvxSearchDialog*)(SfxViewFrame::Current()->GetChildWindow(
542 SvxSearchDialogWrapper::GetChildWindowId())->GetWindow()));
543 pSearchDlg->SetDocWin( pViewShell->GetActiveWindow() );
544 pSearchDlg->SetSrchFlag();
545 }
546 }
547 else
548 mpDrawDocument->GetDocSh()->SetWaitCursor( sal_False );
549
550 return bEndOfSearch;
551 }
552
553
554
555
Initialize(bool bDirectionIsForward)556 void Outliner::Initialize (bool bDirectionIsForward)
557 {
558 const bool bIsAtEnd (maObjectIterator == ::sd::outliner::OutlinerContainer(this).end());
559 const bool bOldDirectionIsForward = mbDirectionIsForward;
560 mbDirectionIsForward = bDirectionIsForward;
561
562 if (maObjectIterator == ::sd::outliner::Iterator())
563 {
564 // Initialize a new search.
565 maObjectIterator = ::sd::outliner::OutlinerContainer(this).current();
566 maCurrentPosition = *maObjectIterator;
567
568 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock());
569 if ( ! pViewShell)
570 {
571 OSL_ASSERT(pViewShell);
572 return;
573 }
574
575 // In case we are searching in an outline view then first remove the
576 // current selection and place cursor at its start or end.
577 if (pViewShell->ISA(OutlineViewShell))
578 {
579 ESelection aSelection = mpImpl->GetOutlinerView()->GetSelection ();
580 if (mbDirectionIsForward)
581 {
582 aSelection.nEndPara = aSelection.nStartPara;
583 aSelection.nEndPos = aSelection.nStartPos;
584 }
585 else
586 {
587 aSelection.nStartPara = aSelection.nEndPara;
588 aSelection.nStartPos = aSelection.nEndPos;
589 }
590 mpImpl->GetOutlinerView()->SetSelection (aSelection);
591 }
592
593 // When not beginning the search at the beginning of the search area
594 // then there may be matches before the current position.
595 mbMatchMayExist = (maObjectIterator!=::sd::outliner::OutlinerContainer(this).begin());
596 }
597 else if (bOldDirectionIsForward != mbDirectionIsForward)
598 {
599 // Requested iteration direction has changed. Turn around the iterator.
600 maObjectIterator.Reverse();
601 if (bIsAtEnd)
602 {
603 // The iterator has pointed to end(), which after the search
604 // direction is reversed, becomes begin().
605 maObjectIterator = ::sd::outliner::OutlinerContainer(this).begin();
606 }
607 else
608 {
609 // The iterator has pointed to the object one ahead/before the current
610 // one. Now move it to the one before/ahead the current one.
611 ++maObjectIterator;
612 ++maObjectIterator;
613 }
614
615 mbMatchMayExist = true;
616 }
617
618 // Initialize the last valid position with where the search starts so
619 // that it always points to a valid position.
620 maLastValidPosition = *::sd::outliner::OutlinerContainer(this).current();
621 }
622
623
624
625
SearchAndReplaceAll(void)626 bool Outliner::SearchAndReplaceAll (void)
627 {
628 // Save the current position to be restored after having replaced all
629 // matches.
630 RememberStartPosition ();
631
632 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock());
633 if ( ! pViewShell)
634 {
635 OSL_ASSERT(pViewShell);
636 return true;
637 }
638
639 if (pViewShell->ISA(OutlineViewShell))
640 {
641 // Put the cursor to the beginning/end of the outliner.
642 mpImpl->GetOutlinerView()->SetSelection (GetSearchStartPosition ());
643
644 // The outliner does all the work for us when we are in this mode.
645 SearchAndReplaceOnce();
646 }
647 else if (pViewShell->ISA(DrawViewShell))
648 {
649 // Go to beginning/end of document.
650 maObjectIterator = ::sd::outliner::OutlinerContainer(this).begin();
651 // Switch to the current object only if it is a valid text object.
652 ::sd::outliner::IteratorPosition aNewPosition (*maObjectIterator);
653 if (IsValidTextObject (aNewPosition))
654 {
655 maCurrentPosition = aNewPosition;
656 SetObject (maCurrentPosition);
657 }
658
659 // Search/replace until the end of the document is reached.
660 bool bFoundMatch;
661 do
662 {
663 bFoundMatch = ! SearchAndReplaceOnce();
664 }
665 while (bFoundMatch);
666 }
667
668 RestoreStartPosition ();
669
670 return true;
671 }
672
673
674
675
SearchAndReplaceOnce(void)676 bool Outliner::SearchAndReplaceOnce (void)
677 {
678 DetectChange ();
679
680 OutlinerView* pOutlinerView = mpImpl->GetOutlinerView();
681 DBG_ASSERT(pOutlinerView!=NULL && GetEditEngine().HasView( &pOutlinerView->GetEditView() ),
682 "SearchAndReplace without valid view!" );
683
684 if( NULL == pOutlinerView || !GetEditEngine().HasView( &pOutlinerView->GetEditView() ) )
685 return true;
686
687 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock());
688 if( bool(pViewShell))
689 {
690 mpView = pViewShell->GetView();
691 mpWindow = pViewShell->GetActiveWindow();
692 pOutlinerView->SetWindow(mpWindow);
693
694 if (pViewShell->ISA(DrawViewShell) )
695 {
696 // When replacing we first check if there is a selection
697 // indicating a match. If there is then replace it. The
698 // following call to StartSearchAndReplace will then search for
699 // the next match.
700 if (meMode == SEARCH
701 && mpSearchItem->GetCommand() == SVX_SEARCHCMD_REPLACE)
702 if (pOutlinerView->GetSelection().HasRange())
703 pOutlinerView->StartSearchAndReplace(*mpSearchItem);
704
705 // Search for the next match.
706 sal_uLong nMatchCount = 0;
707 if (mpSearchItem->GetCommand() != SVX_SEARCHCMD_REPLACE_ALL)
708 nMatchCount = pOutlinerView->StartSearchAndReplace(*mpSearchItem);
709
710 // Go to the next text object when there have been no matches in
711 // the current object or the whole object has already been
712 // processed.
713 if (nMatchCount==0 || mpSearchItem->GetCommand()==SVX_SEARCHCMD_REPLACE_ALL)
714 {
715 ProvideNextTextObject ();
716
717 if ( ! mbEndOfSearch)
718 {
719 // Remember the current position as the last one with a
720 // text object.
721 maLastValidPosition = maCurrentPosition;
722
723 // Now that the mbEndOfSearch flag guards this block the
724 // following assertion and return should not be
725 // necessary anymore.
726 DBG_ASSERT(GetEditEngine().HasView(&pOutlinerView->GetEditView() ),
727 "SearchAndReplace without valid view!" );
728 if ( ! GetEditEngine().HasView( &pOutlinerView->GetEditView() ) )
729 {
730 mpDrawDocument->GetDocSh()->SetWaitCursor( sal_False );
731 return true;
732 }
733
734 if (meMode == SEARCH)
735 nMatchCount = pOutlinerView->StartSearchAndReplace(*mpSearchItem);
736 }
737 }
738 }
739 else if (pViewShell->ISA(OutlineViewShell))
740 {
741 mpDrawDocument->GetDocSh()->SetWaitCursor (sal_False);
742 // The following loop is executed more then once only when a
743 // wrap around search is done.
744 while (true)
745 {
746 int nResult = pOutlinerView->StartSearchAndReplace(*mpSearchItem);
747 if (nResult == 0)
748 {
749 if (HandleFailedSearch ())
750 {
751 pOutlinerView->SetSelection (GetSearchStartPosition ());
752 continue;
753 }
754 }
755 else
756 mbStringFound = true;
757 break;
758 }
759 }
760 }
761
762 mpDrawDocument->GetDocSh()->SetWaitCursor( sal_False );
763
764 return mbEndOfSearch;
765 }
766
767
768
769
770 /** Try to detect whether the document or the view (shell) has changed since
771 the last time <member>StartSearchAndReplace()</member> has been called.
772 */
DetectChange(void)773 void Outliner::DetectChange (void)
774 {
775 ::sd::outliner::IteratorPosition aPosition (maCurrentPosition);
776
777 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock());
778 ::boost::shared_ptr<DrawViewShell> pDrawViewShell (
779 ::boost::dynamic_pointer_cast<DrawViewShell>(pViewShell));
780
781 // Detect whether the view has been switched from the outside.
782 if (pDrawViewShell.get() != NULL
783 && (aPosition.meEditMode != pDrawViewShell->GetEditMode()
784 || aPosition.mePageKind != pDrawViewShell->GetPageKind()))
785 {
786 // Either the edit mode or the page kind has changed.
787 SetStatusEventHdl(Link());
788
789 SdrPageView* pPageView = mpView->GetSdrPageView();
790 if (pPageView != NULL)
791 mpView->UnmarkAllObj (pPageView);
792 mpView->SdrEndTextEdit();
793 SetUpdateMode(sal_False);
794 OutlinerView* pOutlinerView = mpImpl->GetOutlinerView();
795 if (pOutlinerView != NULL)
796 pOutlinerView->SetOutputArea( Rectangle( Point(), Size(1, 1) ) );
797 if (meMode == SPELL)
798 SetPaperSize( Size(1, 1) );
799 SetText( String(), GetParagraph( 0 ) );
800
801 RememberStartPosition ();
802
803 mnPageCount = mpDrawDocument->GetSdPageCount(pDrawViewShell->GetPageKind());
804 maObjectIterator = ::sd::outliner::OutlinerContainer(this).current();
805 }
806
807 // Detect change of the set of selected objects. If their number has
808 // changed start again with the first selected object.
809 else if (DetectSelectionChange())
810 {
811 HandleChangedSelection ();
812 maObjectIterator = ::sd::outliner::OutlinerContainer(this).current();
813 }
814
815 // Detect change of page count. Restart search at first/last page in
816 // that case.
817 else if (aPosition.meEditMode == EM_PAGE
818 && mpDrawDocument->GetSdPageCount(aPosition.mePageKind) != mnPageCount)
819 {
820 // The number of pages has changed.
821 mnPageCount = mpDrawDocument->GetSdPageCount(aPosition.mePageKind);
822 maObjectIterator = ::sd::outliner::OutlinerContainer(this).current();
823 }
824 else if (aPosition.meEditMode == EM_MASTERPAGE
825 && mpDrawDocument->GetSdPageCount(aPosition.mePageKind) != mnPageCount)
826 {
827 // The number of master pages has changed.
828 mnPageCount = mpDrawDocument->GetSdPageCount(aPosition.mePageKind);
829 maObjectIterator = ::sd::outliner::OutlinerContainer(this).current();
830 }
831 }
832
833
834
835
DetectSelectionChange(void)836 bool Outliner::DetectSelectionChange (void)
837 {
838 bool bSelectionHasChanged = false;
839 sal_uLong nMarkCount = mpView->GetMarkedObjectList().GetMarkCount();
840
841 // If mpObj is NULL then we have not yet found our first match.
842 // Detecting a change makes no sense.
843 if (mpObj != NULL)
844 switch (nMarkCount)
845 {
846 case 0:
847 // The selection has changed when previously there have been
848 // selected objects.
849 bSelectionHasChanged = mbRestrictSearchToSelection;
850 break;
851 case 1:
852 // Check if the only selected object is not the one that we
853 // had selected.
854 if (mpView != NULL)
855 {
856 SdrMark* pMark = mpView->GetMarkedObjectList().GetMark(0);
857 if (pMark != NULL)
858 bSelectionHasChanged = (mpObj != pMark->GetMarkedSdrObj ());
859 }
860 break;
861 default:
862 // We had selected exactly one object.
863 bSelectionHasChanged = true;
864 break;
865 }
866
867 return bSelectionHasChanged;
868 }
869
870
871
872
RememberStartPosition(void)873 void Outliner::RememberStartPosition (void)
874 {
875 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock());
876 if ( ! pViewShell)
877 {
878 OSL_ASSERT(pViewShell);
879 return;
880 }
881
882 if (pViewShell->ISA(DrawViewShell))
883 {
884 ::boost::shared_ptr<DrawViewShell> pDrawViewShell (
885 ::boost::dynamic_pointer_cast<DrawViewShell>(pViewShell));
886 if (pDrawViewShell.get() != NULL)
887 {
888 meStartViewMode = pDrawViewShell->GetPageKind();
889 meStartEditMode = pDrawViewShell->GetEditMode();
890 mnStartPageIndex = pDrawViewShell->GetCurPageId() - 1;
891 }
892
893 if (mpView != NULL)
894 {
895 mpStartEditedObject = mpView->GetTextEditObject();
896 if (mpStartEditedObject != NULL)
897 {
898 // Try to retrieve current caret position only when there is an
899 // edited object.
900 ::Outliner* pOutliner =
901 static_cast<DrawView*>(mpView)->GetTextEditOutliner();
902 if (pOutliner!=NULL && pOutliner->GetViewCount()>0)
903 {
904 OutlinerView* pOutlinerView = pOutliner->GetView(0);
905 maStartSelection = pOutlinerView->GetSelection();
906 }
907 }
908 }
909 }
910 else if (pViewShell->ISA(OutlineViewShell))
911 {
912 // Remember the current cursor position.
913 OutlinerView* pView = GetView(0);
914 if (pView != NULL)
915 pView->GetSelection();
916 }
917 else
918 {
919 mnStartPageIndex = (sal_uInt16)-1;
920 }
921 }
922
923
924
925
RestoreStartPosition(void)926 void Outliner::RestoreStartPosition (void)
927 {
928 bool bRestore = true;
929 // Take a negative start page index as inidicator that restoring the
930 // start position is not requested.
931 if (mnStartPageIndex == (sal_uInt16)-1 )
932 bRestore = false;
933 // Dont't restore when the view shell is not valid.
934 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock());
935 if( !bool(pViewShell))
936 bRestore = false;
937
938 if (bRestore)
939 {
940 if (pViewShell->ISA(DrawViewShell))
941 {
942 ::boost::shared_ptr<DrawViewShell> pDrawViewShell (
943 ::boost::dynamic_pointer_cast<DrawViewShell>(pViewShell));
944 SetViewMode (meStartViewMode);
945 if (pDrawViewShell.get() != NULL)
946 SetPage (meStartEditMode, mnStartPageIndex);
947
948
949 if (mpStartEditedObject != NULL)
950 {
951 // Turn on the text toolbar as it is done in FuText so that
952 // undo manager setting/restoring in
953 // sd::View::{Beg,End}TextEdit() works on the same view shell.
954 pViewShell->GetViewShellBase().GetToolBarManager()->SetToolBarShell(
955 ToolBarManager::TBG_FUNCTION,
956 RID_DRAW_TEXT_TOOLBOX);
957
958 mpView->SdrBeginTextEdit(mpStartEditedObject);
959 ::Outliner* pOutliner =
960 static_cast<DrawView*>(mpView)->GetTextEditOutliner();
961 if (pOutliner!=NULL && pOutliner->GetViewCount()>0)
962 {
963 OutlinerView* pOutlinerView = pOutliner->GetView(0);
964 pOutlinerView->SetSelection(maStartSelection);
965 }
966 }
967 }
968 else if (pViewShell->ISA(OutlineViewShell))
969 {
970 // Set cursor to its old position.
971 OutlinerView* pView = GetView(0);
972 if (pView != NULL)
973 pView->SetSelection (maStartSelection);
974 }
975 }
976 }
977
978
979
980
981 /** The main purpose of this method is to iterate over all shape objects of
982 the search area (current selection, current view, or whole document)
983 until a text object has been found that contains at least one match or
984 until no such object can be found anymore. These two conditions are
985 expressed by setting one of the flags <member>mbFoundObject</member> or
986 <member>mbEndOfSearch</member> to <TRUE/>.
987 */
ProvideNextTextObject(void)988 void Outliner::ProvideNextTextObject (void)
989 {
990 mbEndOfSearch = false;
991 mbFoundObject = false;
992
993 mpView->UnmarkAllObj (mpView->GetSdrPageView());
994 try
995 {
996 mpView->SdrEndTextEdit();
997 }
998 catch (::com::sun::star::uno::Exception e)
999 {
1000 DBG_UNHANDLED_EXCEPTION();
1001 }
1002 SetUpdateMode(sal_False);
1003 OutlinerView* pOutlinerView = mpImpl->GetOutlinerView();
1004 if (pOutlinerView != NULL)
1005 pOutlinerView->SetOutputArea( Rectangle( Point(), Size(1, 1) ) );
1006 if (meMode == SPELL)
1007 SetPaperSize( Size(1, 1) );
1008 SetText( String(), GetParagraph( 0 ) );
1009
1010 mpTextObj = NULL;
1011
1012 // Iterate until a valid text object has been found or the search ends.
1013 do
1014 {
1015 mpObj = NULL;
1016 mpParaObj = NULL;
1017
1018 if (maObjectIterator != ::sd::outliner::OutlinerContainer(this).end())
1019 {
1020 maCurrentPosition = *maObjectIterator;
1021 // Switch to the current object only if it is a valid text object.
1022 if (IsValidTextObject (maCurrentPosition))
1023 {
1024 mpObj = SetObject (maCurrentPosition);
1025 }
1026 ++maObjectIterator;
1027
1028 if (mpObj != NULL)
1029 {
1030 PutTextIntoOutliner ();
1031
1032 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock());
1033 if( bool(pViewShell))
1034 switch (meMode)
1035 {
1036 case SEARCH:
1037 PrepareSearchAndReplace ();
1038 break;
1039 case SPELL:
1040 PrepareSpellCheck ();
1041 break;
1042 case TEXT_CONVERSION:
1043 PrepareConversion();
1044 break;
1045 }
1046 }
1047 }
1048 else
1049 {
1050 mbEndOfSearch = true;
1051 EndOfSearch ();
1052 }
1053 }
1054 while ( ! (mbFoundObject || mbEndOfSearch));
1055 }
1056
1057
1058
1059
EndOfSearch(void)1060 void Outliner::EndOfSearch (void)
1061 {
1062 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock());
1063 if ( ! pViewShell)
1064 {
1065 OSL_ASSERT(pViewShell);
1066 return;
1067 }
1068
1069 // Before we display a dialog we first jump to where the last valid text
1070 // object was found. All page and view mode switching since then was
1071 // temporary and should not be visible to the user.
1072 if ( ! pViewShell->ISA(OutlineViewShell))
1073 SetObject (maLastValidPosition);
1074
1075 if (mbRestrictSearchToSelection)
1076 ShowEndOfSearchDialog ();
1077 else
1078 {
1079 // When no match has been found so far then terminate the search.
1080 if ( ! mbMatchMayExist)
1081 {
1082 ShowEndOfSearchDialog ();
1083 mbEndOfSearch = sal_True;
1084 }
1085 // Ask the user whether to wrap around and continue the search or
1086 // to terminate.
1087 else if (meMode==TEXT_CONVERSION || ShowWrapArroundDialog ())
1088 {
1089 mbMatchMayExist = false;
1090 // Everything back to beginning (or end?) of the document.
1091 maObjectIterator = ::sd::outliner::OutlinerContainer(this).begin();
1092 if (pViewShell->ISA(OutlineViewShell))
1093 {
1094 // Set cursor to first character of the document.
1095 OutlinerView* pOutlinerView = mpImpl->GetOutlinerView();
1096 if (pOutlinerView != NULL)
1097 pOutlinerView->SetSelection (GetSearchStartPosition ());
1098 }
1099
1100 mbEndOfSearch = false;
1101 }
1102 else
1103 {
1104 // No wrap around.
1105 mbEndOfSearch = true;
1106 }
1107 }
1108 }
1109
ShowEndOfSearchDialog(void)1110 void Outliner::ShowEndOfSearchDialog (void)
1111 {
1112 String aString;
1113 if (meMode == SEARCH)
1114 {
1115 if (mbStringFound)
1116 aString = String( SdResId(STR_END_SEARCHING) );
1117 else
1118 aString = String( SdResId(STR_STRING_NOTFOUND) );
1119 }
1120 else
1121 {
1122 if (mpView->AreObjectsMarked())
1123 aString = String(SdResId(STR_END_SPELLING_OBJ));
1124 else
1125 aString = String(SdResId(STR_END_SPELLING));
1126 }
1127
1128 // Show the message in an info box that is modal with respect to the
1129 // whole application.
1130 InfoBox aInfoBox (NULL, aString);
1131 ShowModalMessageBox (aInfoBox);
1132
1133 mbWholeDocumentProcessed = true;
1134 }
1135
1136
1137
1138
ShowWrapArroundDialog(void)1139 bool Outliner::ShowWrapArroundDialog (void)
1140 {
1141 bool bDoWrapArround = false;
1142
1143 // Determine whether to show the dialog.
1144 bool bShowDialog = false;
1145 if (mpSearchItem != NULL)
1146 {
1147 // When searching display the dialog only for single find&replace.
1148 sal_uInt16 nCommand = mpSearchItem->GetCommand();
1149 bShowDialog = (nCommand==SVX_SEARCHCMD_REPLACE)
1150 || (nCommand==SVX_SEARCHCMD_FIND);
1151 }
1152 else
1153 // Spell checking needs the dialog, too.
1154 bShowDialog = (meMode == SPELL);
1155
1156 if (bShowDialog)
1157 {
1158 // The question text depends on the search direction.
1159 sal_Bool bImpress = mpDrawDocument!=NULL
1160 && mpDrawDocument->GetDocumentType() == DOCUMENT_TYPE_IMPRESS;
1161 sal_uInt16 nStringId;
1162 if (mbDirectionIsForward)
1163 nStringId = bImpress
1164 ? STR_SAR_WRAP_FORWARD
1165 : STR_SAR_WRAP_FORWARD_DRAW;
1166 else
1167 nStringId = bImpress
1168 ? STR_SAR_WRAP_BACKWARD
1169 : STR_SAR_WRAP_BACKWARD_DRAW;
1170
1171 // Pop up question box that asks the user whether to wrap around.
1172 // The dialog is made modal with respect to the whole application.
1173 QueryBox aQuestionBox (
1174 NULL,
1175 WB_YES_NO | WB_DEF_YES,
1176 String(SdResId(nStringId)));
1177 aQuestionBox.SetImage (QueryBox::GetStandardImage());
1178 sal_uInt16 nBoxResult = ShowModalMessageBox(aQuestionBox);
1179 bDoWrapArround = (nBoxResult == BUTTONID_YES);
1180 }
1181
1182 return bDoWrapArround;
1183 }
1184
1185
1186
1187
IsValidTextObject(const::sd::outliner::IteratorPosition & rPosition)1188 bool Outliner::IsValidTextObject (const ::sd::outliner::IteratorPosition& rPosition)
1189 {
1190 SdrTextObj* pObject = dynamic_cast< SdrTextObj* >( rPosition.mxObject.get() );
1191 return (pObject != NULL) && pObject->HasText() && ! pObject->IsEmptyPresObj();
1192 }
1193
1194
1195
1196
PutTextIntoOutliner()1197 void Outliner::PutTextIntoOutliner()
1198 {
1199 mpTextObj = dynamic_cast<SdrTextObj*>( mpObj );
1200 if ( mpTextObj && mpTextObj->HasText() && !mpTextObj->IsEmptyPresObj() )
1201 {
1202 SdrText* pText = mpTextObj->getText( mnText );
1203 mpParaObj = pText ? pText->GetOutlinerParaObject() : NULL;
1204
1205 if (mpParaObj != NULL)
1206 {
1207 SetText(*mpParaObj);
1208
1209 ClearModifyFlag();
1210 }
1211 }
1212 else
1213 {
1214 mpTextObj = NULL;
1215 }
1216 }
1217
1218
1219
1220
PrepareSpellCheck(void)1221 void Outliner::PrepareSpellCheck (void)
1222 {
1223 EESpellState eState = HasSpellErrors();
1224 DBG_ASSERT(eState != EE_SPELL_NOSPELLER, "No SpellChecker");
1225
1226 if (eState == EE_SPELL_NOLANGUAGE)
1227 {
1228 mbError = sal_True;
1229 mbEndOfSearch = sal_True;
1230 ErrorBox aErrorBox (NULL,
1231 WB_OK,
1232 String(SdResId(STR_NOLANGUAGE)));
1233 ShowModalMessageBox (aErrorBox);
1234 }
1235 else if (eState != EE_SPELL_OK)
1236 {
1237 // When spell checking we have to test whether we have processed the
1238 // whole document and have reached the start page again.
1239 if (meMode == SPELL)
1240 {
1241 if (maSearchStartPosition == ::sd::outliner::Iterator())
1242 // Remember the position of the first text object so that we
1243 // know when we have processed the whole document.
1244 maSearchStartPosition = maObjectIterator;
1245 else if (maSearchStartPosition == maObjectIterator)
1246 {
1247 mbEndOfSearch = true;
1248 }
1249 }
1250
1251 EnterEditMode( sal_False );
1252 }
1253 }
1254
1255
1256
1257
PrepareSearchAndReplace(void)1258 void Outliner::PrepareSearchAndReplace (void)
1259 {
1260 if (HasText( *mpSearchItem ))
1261 {
1262 mbStringFound = true;
1263 mbMatchMayExist = true;
1264
1265 EnterEditMode ();
1266
1267 mpDrawDocument->GetDocSh()->SetWaitCursor( sal_False );
1268 // Start search at the right end of the current object's text
1269 // depending on the search direction.
1270 OutlinerView* pOutlinerView = mpImpl->GetOutlinerView();
1271 if (pOutlinerView != NULL)
1272 pOutlinerView->SetSelection (GetSearchStartPosition ());
1273 }
1274 }
1275
1276
1277
1278
SetViewMode(PageKind ePageKind)1279 void Outliner::SetViewMode (PageKind ePageKind)
1280 {
1281 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock());
1282 ::boost::shared_ptr<DrawViewShell> pDrawViewShell(
1283 ::boost::dynamic_pointer_cast<DrawViewShell>(pViewShell));
1284 if (pDrawViewShell.get()!=NULL && ePageKind != pDrawViewShell->GetPageKind())
1285 {
1286 // Restore old edit mode.
1287 pDrawViewShell->ChangeEditMode(mpImpl->meOriginalEditMode, sal_False);
1288
1289 SetStatusEventHdl(Link());
1290 ::rtl::OUString sViewURL;
1291 switch (ePageKind)
1292 {
1293 case PK_STANDARD:
1294 default:
1295 sViewURL = framework::FrameworkHelper::msImpressViewURL;
1296 break;
1297 case PK_NOTES:
1298 sViewURL = framework::FrameworkHelper::msNotesViewURL;
1299 break;
1300 case PK_HANDOUT:
1301 sViewURL = framework::FrameworkHelper::msHandoutViewURL;
1302 break;
1303 }
1304 // The text object iterator is destroyed when the shells are
1305 // switched but we need it so save it and restore it afterwards.
1306 ::sd::outliner::Iterator aIterator (maObjectIterator);
1307 bool bMatchMayExist = mbMatchMayExist;
1308
1309 ViewShellBase& rBase = pViewShell->GetViewShellBase();
1310 SetViewShell(::boost::shared_ptr<ViewShell>());
1311 framework::FrameworkHelper::Instance(rBase)->RequestView(
1312 sViewURL,
1313 framework::FrameworkHelper::msCenterPaneURL);
1314
1315 // Force (well, request) a synchronous update of the configuration.
1316 // In a better world we would handle the asynchronous view update
1317 // instead. But that would involve major restucturing of the
1318 // Outliner code.
1319 framework::FrameworkHelper::Instance(rBase)->RequestSynchronousUpdate();
1320 SetViewShell(rBase.GetMainViewShell());
1321
1322 // Switching to another view shell has intermediatly called
1323 // EndSpelling(). A PrepareSpelling() is pending, so call that now.
1324 PrepareSpelling();
1325
1326 // Update the number of pages so that
1327 // <member>DetectChange()</member> has the correct value to compare
1328 // to.
1329 mnPageCount = mpDrawDocument->GetSdPageCount(ePageKind);
1330
1331 maObjectIterator = aIterator;
1332 mbMatchMayExist = bMatchMayExist;
1333
1334 // Save edit mode so that it can be restored when switching the view
1335 // shell again.
1336 pDrawViewShell = ::boost::dynamic_pointer_cast<DrawViewShell>(pViewShell);
1337 OSL_ASSERT(pDrawViewShell.get()!=NULL);
1338 if (pDrawViewShell.get() != NULL)
1339 mpImpl->meOriginalEditMode = pDrawViewShell->GetEditMode();
1340 }
1341 }
1342
1343
1344
1345
SetPage(EditMode eEditMode,sal_uInt16 nPageIndex)1346 void Outliner::SetPage (EditMode eEditMode, sal_uInt16 nPageIndex)
1347 {
1348 if ( ! mbRestrictSearchToSelection)
1349 {
1350 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock());
1351 ::boost::shared_ptr<DrawViewShell> pDrawViewShell(
1352 ::boost::dynamic_pointer_cast<DrawViewShell>(pViewShell));
1353 OSL_ASSERT(pDrawViewShell.get()!=NULL);
1354 if (pDrawViewShell.get() != NULL)
1355 {
1356 pDrawViewShell->ChangeEditMode(eEditMode, sal_False);
1357 pDrawViewShell->SwitchPage(nPageIndex);
1358 }
1359 }
1360 }
1361
1362
1363
1364
EnterEditMode(sal_Bool bGrabFocus)1365 void Outliner::EnterEditMode (sal_Bool bGrabFocus)
1366 {
1367 OutlinerView* pOutlinerView = mpImpl->GetOutlinerView();
1368 if (pOutlinerView != NULL)
1369 {
1370 pOutlinerView->SetOutputArea( Rectangle( Point(), Size(1, 1)));
1371 SetPaperSize( mpTextObj->GetLogicRect().GetSize() );
1372 SdrPageView* pPV = mpView->GetSdrPageView();
1373
1374 // Make FuText the current function.
1375 SfxUInt16Item aItem (SID_TEXTEDIT, 1);
1376 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock());
1377 pViewShell->GetDispatcher()->
1378 Execute(SID_TEXTEDIT, SFX_CALLMODE_SYNCHRON |
1379 SFX_CALLMODE_RECORD, &aItem, 0L);
1380
1381 // To be consistent with the usual behaviour in the Office the text
1382 // object that is put into edit mode would have also to be selected.
1383 // Starting the text edit mode is not enough so we do it here by
1384 // hand.
1385 mbExpectingSelectionChangeEvent = true;
1386 mpView->UnmarkAllObj (pPV);
1387 mpView->MarkObj (mpTextObj, pPV);
1388
1389 if( mpTextObj )
1390 mpTextObj->setActiveText( mnText );
1391
1392 // Turn on the edit mode for the text object.
1393 mpView->SdrBeginTextEdit(mpTextObj, pPV, mpWindow, sal_True, this, pOutlinerView, sal_True, sal_True, bGrabFocus);
1394
1395 SetUpdateMode(sal_True);
1396 mbFoundObject = sal_True;
1397 }
1398 }
1399
1400
1401
1402
1403 /*************************************************************************
1404 |*
1405 |* SpellChecker: Error-LinkHdl
1406 |*
1407 \************************************************************************/
1408
IMPL_LINK_INLINE_START(Outliner,SpellError,void *,nLang)1409 IMPL_LINK_INLINE_START( Outliner, SpellError, void *, nLang )
1410 {
1411 mbError = true;
1412 String aError( SvtLanguageTable::GetLanguageString( (LanguageType)(sal_uLong)nLang ) );
1413 ErrorHandler::HandleError(* new StringErrorInfo(
1414 ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS, aError) );
1415 return 0;
1416 }
IMPL_LINK_INLINE_END(Outliner,SpellError,void *,nLang)1417 IMPL_LINK_INLINE_END( Outliner, SpellError, void *, nLang )
1418
1419
1420
1421
1422 ESelection Outliner::GetSearchStartPosition (void)
1423 {
1424 ESelection aPosition;
1425 if (mbDirectionIsForward)
1426 {
1427 // The default constructor uses the beginning of the text as default.
1428 aPosition = ESelection ();
1429 }
1430 else
1431 {
1432 // Retrieve the position after the last character in the last
1433 // paragraph.
1434 sal_uInt32 nParagraphCount = GetParagraphCount();
1435 if (nParagraphCount == 0)
1436 aPosition = ESelection();
1437 else
1438 {
1439 xub_StrLen nLastParagraphLength = GetEditEngine().GetTextLen (
1440 nParagraphCount-1);
1441 aPosition = ESelection (nParagraphCount-1, nLastParagraphLength);
1442 }
1443 }
1444
1445 return aPosition;
1446 }
1447
1448
1449
1450
HasNoPreviousMatch(void)1451 bool Outliner::HasNoPreviousMatch (void)
1452 {
1453 OutlinerView* pOutlinerView = mpImpl->GetOutlinerView();
1454
1455 DBG_ASSERT (pOutlinerView!=NULL, "outline view in Outliner::HasNoPreviousMatch is NULL");
1456
1457 // Detect whether the cursor stands at the beginning
1458 // resp. at the end of the text.
1459 return pOutlinerView->GetSelection().IsEqual(GetSearchStartPosition ()) == sal_True;
1460 }
1461
1462
1463
1464
HandleFailedSearch(void)1465 bool Outliner::HandleFailedSearch (void)
1466 {
1467 bool bContinueSearch = false;
1468
1469 OutlinerView* pOutlinerView = mpImpl->GetOutlinerView();
1470 if (pOutlinerView != NULL && mpSearchItem != NULL)
1471 {
1472 // Detect whether there is/may be a prior match. If there is then
1473 // ask the user whether to wrap around. Otherwise tell the user
1474 // that there is no match.
1475 if (HasNoPreviousMatch ())
1476 {
1477 // No match found in the whole presentation. Tell the user.
1478 InfoBox aInfoBox (NULL,
1479 String(SdResId(STR_SAR_NOT_FOUND)));
1480 ShowModalMessageBox (aInfoBox);
1481 }
1482
1483 else
1484 {
1485 // No further matches found. Ask the user whether to wrap
1486 // around and start again.
1487 bContinueSearch = ShowWrapArroundDialog ();
1488 }
1489 }
1490
1491 return bContinueSearch;
1492 }
1493
1494
SetObject(const::sd::outliner::IteratorPosition & rPosition)1495 SdrObject* Outliner::SetObject (
1496 const ::sd::outliner::IteratorPosition& rPosition)
1497 {
1498 SetViewMode (rPosition.mePageKind);
1499 SetPage (rPosition.meEditMode, (sal_uInt16)rPosition.mnPageIndex);
1500 mnText = rPosition.mnText;
1501 return rPosition.mxObject.get();
1502 }
1503
1504
1505
1506
SetViewShell(const::boost::shared_ptr<ViewShell> & rpViewShell)1507 void Outliner::SetViewShell (const ::boost::shared_ptr<ViewShell>& rpViewShell)
1508 {
1509 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock());
1510 if (pViewShell != rpViewShell)
1511 {
1512 // Set the new view shell.
1513 mpWeakViewShell = rpViewShell;
1514 // When the outline view is not owned by us then we have to clear
1515 // that pointer so that the current one for the new view shell will
1516 // be used (in ProvideOutlinerView).
1517 // if ( ! mbOwnOutlineView)
1518 // mpOutlineView = NULL;
1519 if (rpViewShell)
1520 {
1521 mpView = rpViewShell->GetView();
1522
1523 mpWindow = rpViewShell->GetActiveWindow();
1524
1525 mpImpl->ProvideOutlinerView(*this, rpViewShell, mpWindow);
1526 OutlinerView* pOutlinerView = mpImpl->GetOutlinerView();
1527 if (pOutlinerView != NULL)
1528 pOutlinerView->SetWindow(mpWindow);
1529 }
1530 else
1531 {
1532 mpView = NULL;
1533 mpWindow = NULL;
1534 }
1535 }
1536 }
1537
1538
1539
1540
HandleChangedSelection(void)1541 void Outliner::HandleChangedSelection (void)
1542 {
1543 maMarkListCopy.clear();
1544 mbRestrictSearchToSelection = (mpView->AreObjectsMarked()==sal_True);
1545 if (mbRestrictSearchToSelection)
1546 {
1547 // Make a copy of the current mark list.
1548 const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
1549 sal_uLong nCount = rMarkList.GetMarkCount();
1550 if (nCount > 0)
1551 {
1552 maMarkListCopy.clear();
1553 maMarkListCopy.reserve (nCount);
1554 for (sal_uLong i=0; i<nCount; i++)
1555 maMarkListCopy.push_back (rMarkList.GetMark(i)->GetMarkedSdrObj ());
1556 }
1557 else
1558 // No marked object. Is this case possible?
1559 mbRestrictSearchToSelection = false;
1560 }
1561 }
1562
1563
1564
1565
1566
StartConversion(sal_Int16 nSourceLanguage,sal_Int16 nTargetLanguage,const Font * pTargetFont,sal_Int32 nOptions,sal_Bool bIsInteractive)1567 void Outliner::StartConversion( sal_Int16 nSourceLanguage, sal_Int16 nTargetLanguage,
1568 const Font *pTargetFont, sal_Int32 nOptions, sal_Bool bIsInteractive )
1569 {
1570 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock());
1571 sal_Bool bMultiDoc = pViewShell->ISA(DrawViewShell);
1572
1573 meMode = TEXT_CONVERSION;
1574 mbDirectionIsForward = true;
1575 mpSearchItem = NULL;
1576 mnConversionLanguage = nSourceLanguage;
1577
1578 BeginConversion();
1579
1580 OutlinerView* pOutlinerView = mpImpl->GetOutlinerView();
1581 if (pOutlinerView != NULL)
1582 {
1583 pOutlinerView->StartTextConversion(
1584 nSourceLanguage,
1585 nTargetLanguage,
1586 pTargetFont,
1587 nOptions,
1588 bIsInteractive,
1589 bMultiDoc);
1590 }
1591
1592 EndConversion();
1593 }
1594
1595
1596
1597
1598 /** Prepare to do a text conversion on the current text object. This
1599 includes putting it into edit mode.
1600 */
PrepareConversion(void)1601 void Outliner::PrepareConversion (void)
1602 {
1603 SetUpdateMode(sal_True);
1604 if( HasConvertibleTextPortion( mnConversionLanguage ) )
1605 {
1606 SetUpdateMode(sal_False);
1607 mbStringFound = sal_True;
1608 mbMatchMayExist = sal_True;
1609
1610 EnterEditMode ();
1611
1612 mpDrawDocument->GetDocSh()->SetWaitCursor( sal_False );
1613 // Start search at the right end of the current object's text
1614 // depending on the search direction.
1615 // mpOutlineView->SetSelection (GetSearchStartPosition ());
1616 }
1617 else
1618 {
1619 SetUpdateMode(sal_False);
1620 }
1621 }
1622
1623
1624
1625
BeginConversion(void)1626 void Outliner::BeginConversion (void)
1627 {
1628 SetRefDevice( SD_MOD()->GetRefDevice( *mpDrawDocument->GetDocSh() ) );
1629
1630 ViewShellBase* pBase = PTR_CAST(ViewShellBase, SfxViewShell::Current());
1631 if (pBase != NULL)
1632 SetViewShell (pBase->GetMainViewShell());
1633
1634 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock());
1635 if (pViewShell)
1636 {
1637 mbStringFound = sal_False;
1638
1639 // Supposed that we are not located at the very beginning/end of the
1640 // document then there may be a match in the document prior/after
1641 // the current position.
1642 mbMatchMayExist = sal_True;
1643
1644 maObjectIterator = ::sd::outliner::Iterator();
1645 maSearchStartPosition = ::sd::outliner::Iterator();
1646 RememberStartPosition();
1647
1648 mpImpl->ProvideOutlinerView(*this, pViewShell, mpWindow);
1649
1650 HandleChangedSelection ();
1651 }
1652 ClearModifyFlag();
1653 }
1654
1655
1656
1657
EndConversion()1658 void Outliner::EndConversion()
1659 {
1660 EndSpelling();
1661 }
1662
1663
1664
1665
ConvertNextDocument()1666 sal_Bool Outliner::ConvertNextDocument()
1667 {
1668 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock());
1669 if (pViewShell && pViewShell->ISA(OutlineViewShell) )
1670 return false;
1671
1672 mpDrawDocument->GetDocSh()->SetWaitCursor( sal_True );
1673
1674 Initialize ( true );
1675
1676 OutlinerView* pOutlinerView = mpImpl->GetOutlinerView();
1677 if (pOutlinerView != NULL)
1678 {
1679 mpWindow = pViewShell->GetActiveWindow();
1680 pOutlinerView->SetWindow(mpWindow);
1681 }
1682 ProvideNextTextObject ();
1683
1684 mpDrawDocument->GetDocSh()->SetWaitCursor( sal_False );
1685 ClearModifyFlag();
1686
1687 // for text conversion we automatically wrap around one
1688 // time and stop at the start shape
1689 if( mpFirstObj )
1690 {
1691 if( (mnText == 0) && (mpFirstObj == mpObj) )
1692 return false;
1693 }
1694 else
1695 {
1696 mpFirstObj = mpObj;
1697 }
1698
1699 return !mbEndOfSearch;
1700 }
1701
1702
1703
1704
ShowModalMessageBox(Dialog & rMessageBox)1705 sal_uInt16 Outliner::ShowModalMessageBox (Dialog& rMessageBox)
1706 {
1707 // We assume that the parent of the given messge box is NULL, i.e. it is
1708 // modal with respect to the top application window. However, this
1709 // does not affect the search dialog. Therefore we have to lock it here
1710 // while the message box is being shown. We also have to take into
1711 // account that we are called during a spell check and the search dialog
1712 // is not available.
1713 ::Window* pSearchDialog = NULL;
1714 SfxChildWindow* pChildWindow = NULL;
1715 switch (meMode)
1716 {
1717 case SEARCH:
1718 pChildWindow = SfxViewFrame::Current()->GetChildWindow(
1719 SvxSearchDialogWrapper::GetChildWindowId());
1720 break;
1721
1722 case SPELL:
1723 pChildWindow = SfxViewFrame::Current()->GetChildWindow(
1724 SpellDialogChildWindow::GetChildWindowId());
1725 break;
1726
1727 case TEXT_CONVERSION:
1728 // There should no messages boxes be displayed while doing the
1729 // hangul hanja conversion.
1730 break;
1731 }
1732
1733 if (pChildWindow != NULL)
1734 pSearchDialog = pChildWindow->GetWindow();
1735 if (pSearchDialog != NULL)
1736 pSearchDialog->EnableInput(sal_False,sal_True);
1737
1738 sal_uInt16 nResult = rMessageBox.Execute();
1739
1740 // Unlock the search dialog.
1741 if (pSearchDialog != NULL)
1742 pSearchDialog->EnableInput(sal_True,sal_True);
1743
1744 return nResult;
1745 }
1746
1747
1748
1749
1750 //===== Outliner::Implementation ==============================================
1751
Implementation(void)1752 Outliner::Implementation::Implementation (void)
1753 : meOriginalEditMode(EM_PAGE),
1754 mbOwnOutlineView(false),
1755 mpOutlineView(NULL)
1756 {
1757 }
1758
1759
1760
1761
~Implementation(void)1762 Outliner::Implementation::~Implementation (void)
1763 {
1764 if (mbOwnOutlineView && mpOutlineView!=NULL)
1765 {
1766 mpOutlineView->SetWindow(NULL);
1767 delete mpOutlineView;
1768 mpOutlineView = NULL;
1769 }
1770 }
1771
1772
1773
1774
GetOutlinerView()1775 OutlinerView* Outliner::Implementation::GetOutlinerView ()
1776 {
1777 return mpOutlineView;
1778 }
1779
1780
1781
1782
1783 /** We try to create a new OutlinerView only when there is none available,
1784 either from an OutlinerViewShell or a previous call to
1785 ProvideOutlinerView(). This is necessary to support the spell checker
1786 which can not cope with exchanging the OutlinerView.
1787 */
ProvideOutlinerView(Outliner & rOutliner,const::boost::shared_ptr<ViewShell> & rpViewShell,::Window * pWindow)1788 void Outliner::Implementation::ProvideOutlinerView (
1789 Outliner& rOutliner,
1790 const ::boost::shared_ptr<ViewShell>& rpViewShell,
1791 ::Window* pWindow)
1792 {
1793 if (rpViewShell.get() != NULL)
1794 {
1795 switch (rpViewShell->GetShellType())
1796 {
1797 case ViewShell::ST_DRAW:
1798 case ViewShell::ST_IMPRESS:
1799 case ViewShell::ST_NOTES:
1800 case ViewShell::ST_HANDOUT:
1801 {
1802 // Create a new outline view to do the search on.
1803 bool bInsert = false;
1804 if (mpOutlineView!=NULL && !mbOwnOutlineView)
1805 mpOutlineView = NULL;
1806 if (mpOutlineView == NULL)
1807 {
1808 mpOutlineView = new OutlinerView(&rOutliner, pWindow);
1809 mbOwnOutlineView = true;
1810 bInsert = true;
1811 }
1812 else
1813 mpOutlineView->SetWindow(pWindow);
1814 sal_uLong nStat = mpOutlineView->GetControlWord();
1815 nStat &= ~EV_CNTRL_AUTOSCROLL;
1816 mpOutlineView->SetControlWord(nStat);
1817 if (bInsert)
1818 rOutliner.InsertView( mpOutlineView );
1819 rOutliner.SetUpdateMode(sal_False);
1820 mpOutlineView->SetOutputArea (Rectangle (Point(), Size(1, 1)));
1821 rOutliner.SetPaperSize( Size(1, 1) );
1822 rOutliner.SetText( String(), rOutliner.GetParagraph( 0 ) );
1823
1824 meOriginalEditMode =
1825 ::boost::static_pointer_cast<DrawViewShell>(rpViewShell)->GetEditMode();
1826 }
1827 break;
1828
1829 case ViewShell::ST_OUTLINE:
1830 {
1831 if (mpOutlineView!=NULL && mbOwnOutlineView)
1832 delete mpOutlineView;
1833 mpOutlineView = rOutliner.GetView(0);
1834 mbOwnOutlineView = false;
1835 }
1836 break;
1837
1838 default:
1839 case ViewShell::ST_NONE:
1840 case ViewShell::ST_PRESENTATION:
1841 // Ignored
1842 break;
1843 }
1844 }
1845 }
1846
1847
1848
1849
ReleaseOutlinerView(void)1850 void Outliner::Implementation::ReleaseOutlinerView (void)
1851 {
1852 if (mbOwnOutlineView)
1853 {
1854 OutlinerView* pView = mpOutlineView;
1855 mpOutlineView = NULL;
1856 mbOwnOutlineView = false;
1857 if (pView != NULL)
1858 {
1859 pView->SetWindow(NULL);
1860 delete pView;
1861 }
1862 }
1863 else
1864 {
1865 mpOutlineView = NULL;
1866 }
1867 }
1868
1869 } // end of namespace sd
1870