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