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