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