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