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