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