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