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