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