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