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