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