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 if ( Application::IsAccessibilityEnabled() ) 539 { 540 SvxSearchDialog* pSearchDlg = 541 ((SvxSearchDialog*)(SfxViewFrame::Current()->GetChildWindow( 542 SvxSearchDialogWrapper::GetChildWindowId())->GetWindow())); 543 pSearchDlg->SetDocWin( pViewShell->GetActiveWindow() ); 544 pSearchDlg->SetSrchFlag(); 545 } 546 } 547 else 548 mpDrawDocument->GetDocSh()->SetWaitCursor( sal_False ); 549 550 return bEndOfSearch; 551 } 552 553 554 555 556 void Outliner::Initialize (bool bDirectionIsForward) 557 { 558 const bool bIsAtEnd (maObjectIterator == ::sd::outliner::OutlinerContainer(this).end()); 559 const bool bOldDirectionIsForward = mbDirectionIsForward; 560 mbDirectionIsForward = bDirectionIsForward; 561 562 if (maObjectIterator == ::sd::outliner::Iterator()) 563 { 564 // Initialize a new search. 565 maObjectIterator = ::sd::outliner::OutlinerContainer(this).current(); 566 maCurrentPosition = *maObjectIterator; 567 568 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock()); 569 if ( ! pViewShell) 570 { 571 OSL_ASSERT(pViewShell); 572 return; 573 } 574 575 // In case we are searching in an outline view then first remove the 576 // current selection and place cursor at its start or end. 577 if (pViewShell->ISA(OutlineViewShell)) 578 { 579 ESelection aSelection = mpImpl->GetOutlinerView()->GetSelection (); 580 if (mbDirectionIsForward) 581 { 582 aSelection.nEndPara = aSelection.nStartPara; 583 aSelection.nEndPos = aSelection.nStartPos; 584 } 585 else 586 { 587 aSelection.nStartPara = aSelection.nEndPara; 588 aSelection.nStartPos = aSelection.nEndPos; 589 } 590 mpImpl->GetOutlinerView()->SetSelection (aSelection); 591 } 592 593 // When not beginning the search at the beginning of the search area 594 // then there may be matches before the current position. 595 mbMatchMayExist = (maObjectIterator!=::sd::outliner::OutlinerContainer(this).begin()); 596 } 597 else if (bOldDirectionIsForward != mbDirectionIsForward) 598 { 599 // Requested iteration direction has changed. Turn arround the iterator. 600 maObjectIterator.Reverse(); 601 if (bIsAtEnd) 602 { 603 // The iterator has pointed to end(), which after the search 604 // direction is reversed, becomes begin(). 605 maObjectIterator = ::sd::outliner::OutlinerContainer(this).begin(); 606 } 607 else 608 { 609 // The iterator has pointed to the object one ahead/before the current 610 // one. Now move it to the one before/ahead the current one. 611 ++maObjectIterator; 612 ++maObjectIterator; 613 } 614 615 mbMatchMayExist = true; 616 } 617 618 // Initialize the last valid position with where the search starts so 619 // that it always points to a valid position. 620 maLastValidPosition = *::sd::outliner::OutlinerContainer(this).current(); 621 } 622 623 624 625 626 bool Outliner::SearchAndReplaceAll (void) 627 { 628 // Save the current position to be restored after having replaced all 629 // matches. 630 RememberStartPosition (); 631 632 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock()); 633 if ( ! pViewShell) 634 { 635 OSL_ASSERT(pViewShell); 636 return true; 637 } 638 639 if (pViewShell->ISA(OutlineViewShell)) 640 { 641 // Put the cursor to the beginning/end of the outliner. 642 mpImpl->GetOutlinerView()->SetSelection (GetSearchStartPosition ()); 643 644 // The outliner does all the work for us when we are in this mode. 645 SearchAndReplaceOnce(); 646 } 647 else if (pViewShell->ISA(DrawViewShell)) 648 { 649 // Go to beginning/end of document. 650 maObjectIterator = ::sd::outliner::OutlinerContainer(this).begin(); 651 // Switch to the current object only if it is a valid text object. 652 ::sd::outliner::IteratorPosition aNewPosition (*maObjectIterator); 653 if (IsValidTextObject (aNewPosition)) 654 { 655 maCurrentPosition = aNewPosition; 656 SetObject (maCurrentPosition); 657 } 658 659 // Search/replace until the end of the document is reached. 660 bool bFoundMatch; 661 do 662 { 663 bFoundMatch = ! SearchAndReplaceOnce(); 664 } 665 while (bFoundMatch); 666 } 667 668 RestoreStartPosition (); 669 670 return true; 671 } 672 673 674 675 676 bool Outliner::SearchAndReplaceOnce (void) 677 { 678 DetectChange (); 679 680 OutlinerView* pOutlinerView = mpImpl->GetOutlinerView(); 681 DBG_ASSERT(pOutlinerView!=NULL && GetEditEngine().HasView( &pOutlinerView->GetEditView() ), 682 "SearchAndReplace without valid view!" ); 683 684 if( NULL == pOutlinerView || !GetEditEngine().HasView( &pOutlinerView->GetEditView() ) ) 685 return true; 686 687 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock()); 688 if (pViewShell != NULL) 689 { 690 mpView = pViewShell->GetView(); 691 mpWindow = pViewShell->GetActiveWindow(); 692 pOutlinerView->SetWindow(mpWindow); 693 694 if (pViewShell->ISA(DrawViewShell) ) 695 { 696 // When replacing we first check if there is a selection 697 // indicating a match. If there is then replace it. The 698 // following call to StartSearchAndReplace will then search for 699 // the next match. 700 if (meMode == SEARCH 701 && mpSearchItem->GetCommand() == SVX_SEARCHCMD_REPLACE) 702 if (pOutlinerView->GetSelection().HasRange()) 703 pOutlinerView->StartSearchAndReplace(*mpSearchItem); 704 705 // Search for the next match. 706 sal_uLong nMatchCount = 0; 707 if (mpSearchItem->GetCommand() != SVX_SEARCHCMD_REPLACE_ALL) 708 nMatchCount = pOutlinerView->StartSearchAndReplace(*mpSearchItem); 709 710 // Go to the next text object when there have been no matches in 711 // the current object or the whole object has already been 712 // processed. 713 if (nMatchCount==0 || mpSearchItem->GetCommand()==SVX_SEARCHCMD_REPLACE_ALL) 714 { 715 ProvideNextTextObject (); 716 717 if ( ! mbEndOfSearch) 718 { 719 // Remember the current position as the last one with a 720 // text object. 721 maLastValidPosition = maCurrentPosition; 722 723 // Now that the mbEndOfSearch flag guards this block the 724 // following assertion and return should not be 725 // necessary anymore. 726 DBG_ASSERT(GetEditEngine().HasView(&pOutlinerView->GetEditView() ), 727 "SearchAndReplace without valid view!" ); 728 if ( ! GetEditEngine().HasView( &pOutlinerView->GetEditView() ) ) 729 { 730 mpDrawDocument->GetDocSh()->SetWaitCursor( sal_False ); 731 return true; 732 } 733 734 if (meMode == SEARCH) 735 nMatchCount = pOutlinerView->StartSearchAndReplace(*mpSearchItem); 736 } 737 } 738 } 739 else if (pViewShell->ISA(OutlineViewShell)) 740 { 741 mpDrawDocument->GetDocSh()->SetWaitCursor (sal_False); 742 // The following loop is executed more then once only when a 743 // wrap arround search is done. 744 while (true) 745 { 746 int nResult = pOutlinerView->StartSearchAndReplace(*mpSearchItem); 747 if (nResult == 0) 748 { 749 if (HandleFailedSearch ()) 750 { 751 pOutlinerView->SetSelection (GetSearchStartPosition ()); 752 continue; 753 } 754 } 755 else 756 mbStringFound = true; 757 break; 758 } 759 } 760 } 761 762 mpDrawDocument->GetDocSh()->SetWaitCursor( sal_False ); 763 764 return mbEndOfSearch; 765 } 766 767 768 769 770 /** Try to detect whether the document or the view (shell) has changed since 771 the last time <member>StartSearchAndReplace()</member> has been called. 772 */ 773 void Outliner::DetectChange (void) 774 { 775 ::sd::outliner::IteratorPosition aPosition (maCurrentPosition); 776 777 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock()); 778 ::boost::shared_ptr<DrawViewShell> pDrawViewShell ( 779 ::boost::dynamic_pointer_cast<DrawViewShell>(pViewShell)); 780 781 // Detect whether the view has been switched from the outside. 782 if (pDrawViewShell.get() != NULL 783 && (aPosition.meEditMode != pDrawViewShell->GetEditMode() 784 || aPosition.mePageKind != pDrawViewShell->GetPageKind())) 785 { 786 // Either the edit mode or the page kind has changed. 787 SetStatusEventHdl(Link()); 788 789 SdrPageView* pPageView = mpView->GetSdrPageView(); 790 if (pPageView != NULL) 791 mpView->UnmarkAllObj (pPageView); 792 mpView->SdrEndTextEdit(); 793 SetUpdateMode(sal_False); 794 OutlinerView* pOutlinerView = mpImpl->GetOutlinerView(); 795 if (pOutlinerView != NULL) 796 pOutlinerView->SetOutputArea( Rectangle( Point(), Size(1, 1) ) ); 797 if (meMode == SPELL) 798 SetPaperSize( Size(1, 1) ); 799 SetText( String(), GetParagraph( 0 ) ); 800 801 RememberStartPosition (); 802 803 mnPageCount = mpDrawDocument->GetSdPageCount(pDrawViewShell->GetPageKind()); 804 maObjectIterator = ::sd::outliner::OutlinerContainer(this).current(); 805 } 806 807 // Detect change of the set of selected objects. If their number has 808 // changed start again with the first selected object. 809 else if (DetectSelectionChange()) 810 { 811 HandleChangedSelection (); 812 maObjectIterator = ::sd::outliner::OutlinerContainer(this).current(); 813 } 814 815 // Detect change of page count. Restart search at first/last page in 816 // that case. 817 else if (aPosition.meEditMode == EM_PAGE 818 && mpDrawDocument->GetSdPageCount(aPosition.mePageKind) != mnPageCount) 819 { 820 // The number of pages has changed. 821 mnPageCount = mpDrawDocument->GetSdPageCount(aPosition.mePageKind); 822 maObjectIterator = ::sd::outliner::OutlinerContainer(this).current(); 823 } 824 else if (aPosition.meEditMode == EM_MASTERPAGE 825 && mpDrawDocument->GetSdPageCount(aPosition.mePageKind) != mnPageCount) 826 { 827 // The number of master pages has changed. 828 mnPageCount = mpDrawDocument->GetSdPageCount(aPosition.mePageKind); 829 maObjectIterator = ::sd::outliner::OutlinerContainer(this).current(); 830 } 831 } 832 833 834 835 836 bool Outliner::DetectSelectionChange (void) 837 { 838 bool bSelectionHasChanged = false; 839 sal_uLong nMarkCount = mpView->GetMarkedObjectList().GetMarkCount(); 840 841 // If mpObj is NULL then we have not yet found our first match. 842 // Detecting a change makes no sense. 843 if (mpObj != NULL) 844 switch (nMarkCount) 845 { 846 case 0: 847 // The selection has changed when previously there have been 848 // selected objects. 849 bSelectionHasChanged = mbRestrictSearchToSelection; 850 break; 851 case 1: 852 // Check if the only selected object is not the one that we 853 // had selected. 854 if (mpView != NULL) 855 { 856 SdrMark* pMark = mpView->GetMarkedObjectList().GetMark(0); 857 if (pMark != NULL) 858 bSelectionHasChanged = (mpObj != pMark->GetMarkedSdrObj ()); 859 } 860 break; 861 default: 862 // We had selected exactly one object. 863 bSelectionHasChanged = true; 864 break; 865 } 866 867 return bSelectionHasChanged; 868 } 869 870 871 872 873 void Outliner::RememberStartPosition (void) 874 { 875 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock()); 876 if ( ! pViewShell) 877 { 878 OSL_ASSERT(pViewShell); 879 return; 880 } 881 882 if (pViewShell->ISA(DrawViewShell)) 883 { 884 ::boost::shared_ptr<DrawViewShell> pDrawViewShell ( 885 ::boost::dynamic_pointer_cast<DrawViewShell>(pViewShell)); 886 if (pDrawViewShell.get() != NULL) 887 { 888 meStartViewMode = pDrawViewShell->GetPageKind(); 889 meStartEditMode = pDrawViewShell->GetEditMode(); 890 mnStartPageIndex = pDrawViewShell->GetCurPageId() - 1; 891 } 892 893 if (mpView != NULL) 894 { 895 mpStartEditedObject = mpView->GetTextEditObject(); 896 if (mpStartEditedObject != NULL) 897 { 898 // Try to retrieve current caret position only when there is an 899 // edited object. 900 ::Outliner* pOutliner = 901 static_cast<DrawView*>(mpView)->GetTextEditOutliner(); 902 if (pOutliner!=NULL && pOutliner->GetViewCount()>0) 903 { 904 OutlinerView* pOutlinerView = pOutliner->GetView(0); 905 maStartSelection = pOutlinerView->GetSelection(); 906 } 907 } 908 } 909 } 910 else if (pViewShell->ISA(OutlineViewShell)) 911 { 912 // Remember the current cursor position. 913 OutlinerView* pView = GetView(0); 914 if (pView != NULL) 915 pView->GetSelection(); 916 } 917 else 918 { 919 mnStartPageIndex = (sal_uInt16)-1; 920 } 921 } 922 923 924 925 926 void Outliner::RestoreStartPosition (void) 927 { 928 bool bRestore = true; 929 // Take a negative start page index as inidicator that restoring the 930 // start position is not requested. 931 if (mnStartPageIndex == (sal_uInt16)-1 ) 932 bRestore = false; 933 // Dont't restore when the view shell is not valid. 934 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock()); 935 if (pViewShell == NULL) 936 bRestore = false; 937 938 if (bRestore) 939 { 940 if (pViewShell->ISA(DrawViewShell)) 941 { 942 ::boost::shared_ptr<DrawViewShell> pDrawViewShell ( 943 ::boost::dynamic_pointer_cast<DrawViewShell>(pViewShell)); 944 SetViewMode (meStartViewMode); 945 if (pDrawViewShell.get() != NULL) 946 SetPage (meStartEditMode, mnStartPageIndex); 947 948 949 if (mpStartEditedObject != NULL) 950 { 951 // Turn on the text toolbar as it is done in FuText so that 952 // undo manager setting/restoring in 953 // sd::View::{Beg,End}TextEdit() works on the same view shell. 954 pViewShell->GetViewShellBase().GetToolBarManager()->SetToolBarShell( 955 ToolBarManager::TBG_FUNCTION, 956 RID_DRAW_TEXT_TOOLBOX); 957 958 mpView->SdrBeginTextEdit(mpStartEditedObject); 959 ::Outliner* pOutliner = 960 static_cast<DrawView*>(mpView)->GetTextEditOutliner(); 961 if (pOutliner!=NULL && pOutliner->GetViewCount()>0) 962 { 963 OutlinerView* pOutlinerView = pOutliner->GetView(0); 964 pOutlinerView->SetSelection(maStartSelection); 965 } 966 } 967 } 968 else if (pViewShell->ISA(OutlineViewShell)) 969 { 970 // Set cursor to its old position. 971 OutlinerView* pView = GetView(0); 972 if (pView != NULL) 973 pView->SetSelection (maStartSelection); 974 } 975 } 976 } 977 978 979 980 981 /** The main purpose of this method is to iterate over all shape objects of 982 the search area (current selection, current view, or whole document) 983 until a text object has been found that contains at least one match or 984 until no such object can be found anymore. These two conditions are 985 expressed by setting one of the flags <member>mbFoundObject</member> or 986 <member>mbEndOfSearch</member> to <TRUE/>. 987 */ 988 void Outliner::ProvideNextTextObject (void) 989 { 990 mbEndOfSearch = false; 991 mbFoundObject = false; 992 993 mpView->UnmarkAllObj (mpView->GetSdrPageView()); 994 try 995 { 996 mpView->SdrEndTextEdit(); 997 } 998 catch (::com::sun::star::uno::Exception e) 999 { 1000 DBG_UNHANDLED_EXCEPTION(); 1001 } 1002 SetUpdateMode(sal_False); 1003 OutlinerView* pOutlinerView = mpImpl->GetOutlinerView(); 1004 if (pOutlinerView != NULL) 1005 pOutlinerView->SetOutputArea( Rectangle( Point(), Size(1, 1) ) ); 1006 if (meMode == SPELL) 1007 SetPaperSize( Size(1, 1) ); 1008 SetText( String(), GetParagraph( 0 ) ); 1009 1010 mpTextObj = NULL; 1011 1012 // Iterate until a valid text object has been found or the search ends. 1013 do 1014 { 1015 mpObj = NULL; 1016 mpParaObj = NULL; 1017 1018 if (maObjectIterator != ::sd::outliner::OutlinerContainer(this).end()) 1019 { 1020 maCurrentPosition = *maObjectIterator; 1021 // Switch to the current object only if it is a valid text object. 1022 if (IsValidTextObject (maCurrentPosition)) 1023 { 1024 mpObj = SetObject (maCurrentPosition); 1025 } 1026 ++maObjectIterator; 1027 1028 if (mpObj != NULL) 1029 { 1030 PutTextIntoOutliner (); 1031 1032 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock()); 1033 if (pViewShell != NULL) 1034 switch (meMode) 1035 { 1036 case SEARCH: 1037 PrepareSearchAndReplace (); 1038 break; 1039 case SPELL: 1040 PrepareSpellCheck (); 1041 break; 1042 case TEXT_CONVERSION: 1043 PrepareConversion(); 1044 break; 1045 } 1046 } 1047 } 1048 else 1049 { 1050 mbEndOfSearch = true; 1051 EndOfSearch (); 1052 } 1053 } 1054 while ( ! (mbFoundObject || mbEndOfSearch)); 1055 } 1056 1057 1058 1059 1060 void Outliner::EndOfSearch (void) 1061 { 1062 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock()); 1063 if ( ! pViewShell) 1064 { 1065 OSL_ASSERT(pViewShell); 1066 return; 1067 } 1068 1069 // Before we display a dialog we first jump to where the last valid text 1070 // object was found. All page and view mode switching since then was 1071 // temporary and should not be visible to the user. 1072 if ( ! pViewShell->ISA(OutlineViewShell)) 1073 SetObject (maLastValidPosition); 1074 1075 if (mbRestrictSearchToSelection) 1076 ShowEndOfSearchDialog (); 1077 else 1078 { 1079 // When no match has been found so far then terminate the search. 1080 if ( ! mbMatchMayExist) 1081 { 1082 ShowEndOfSearchDialog (); 1083 mbEndOfSearch = sal_True; 1084 } 1085 // Ask the user whether to wrap arround and continue the search or 1086 // to terminate. 1087 else if (meMode==TEXT_CONVERSION || ShowWrapArroundDialog ()) 1088 { 1089 mbMatchMayExist = false; 1090 // Everything back to beginning (or end?) of the document. 1091 maObjectIterator = ::sd::outliner::OutlinerContainer(this).begin(); 1092 if (pViewShell->ISA(OutlineViewShell)) 1093 { 1094 // Set cursor to first character of the document. 1095 OutlinerView* pOutlinerView = mpImpl->GetOutlinerView(); 1096 if (pOutlinerView != NULL) 1097 pOutlinerView->SetSelection (GetSearchStartPosition ()); 1098 } 1099 1100 mbEndOfSearch = false; 1101 } 1102 else 1103 { 1104 // No wrap arround. 1105 mbEndOfSearch = true; 1106 } 1107 } 1108 } 1109 1110 void Outliner::ShowEndOfSearchDialog (void) 1111 { 1112 String aString; 1113 if (meMode == SEARCH) 1114 { 1115 if (mbStringFound) 1116 aString = String( SdResId(STR_END_SEARCHING) ); 1117 else 1118 aString = String( SdResId(STR_STRING_NOTFOUND) ); 1119 } 1120 else 1121 { 1122 if (mpView->AreObjectsMarked()) 1123 aString = String(SdResId(STR_END_SPELLING_OBJ)); 1124 else 1125 aString = String(SdResId(STR_END_SPELLING)); 1126 } 1127 1128 // Show the message in an info box that is modal with respect to the 1129 // whole application. 1130 InfoBox aInfoBox (NULL, aString); 1131 ShowModalMessageBox (aInfoBox); 1132 1133 mbWholeDocumentProcessed = true; 1134 } 1135 1136 1137 1138 1139 bool Outliner::ShowWrapArroundDialog (void) 1140 { 1141 bool bDoWrapArround = false; 1142 1143 // Determine whether to show the dialog. 1144 bool bShowDialog = false; 1145 if (mpSearchItem != NULL) 1146 { 1147 // When searching display the dialog only for single find&replace. 1148 sal_uInt16 nCommand = mpSearchItem->GetCommand(); 1149 bShowDialog = (nCommand==SVX_SEARCHCMD_REPLACE) 1150 || (nCommand==SVX_SEARCHCMD_FIND); 1151 } 1152 else 1153 // Spell checking needs the dialog, too. 1154 bShowDialog = (meMode == SPELL); 1155 1156 if (bShowDialog) 1157 { 1158 // The question text depends on the search direction. 1159 sal_Bool bImpress = mpDrawDocument!=NULL 1160 && mpDrawDocument->GetDocumentType() == DOCUMENT_TYPE_IMPRESS; 1161 sal_uInt16 nStringId; 1162 if (mbDirectionIsForward) 1163 nStringId = bImpress 1164 ? STR_SAR_WRAP_FORWARD 1165 : STR_SAR_WRAP_FORWARD_DRAW; 1166 else 1167 nStringId = bImpress 1168 ? STR_SAR_WRAP_BACKWARD 1169 : STR_SAR_WRAP_BACKWARD_DRAW; 1170 1171 // Pop up question box that asks the user whether to wrap arround. 1172 // The dialog is made modal with respect to the whole application. 1173 QueryBox aQuestionBox ( 1174 NULL, 1175 WB_YES_NO | WB_DEF_YES, 1176 String(SdResId(nStringId))); 1177 aQuestionBox.SetImage (QueryBox::GetStandardImage()); 1178 sal_uInt16 nBoxResult = ShowModalMessageBox(aQuestionBox); 1179 bDoWrapArround = (nBoxResult == BUTTONID_YES); 1180 } 1181 1182 return bDoWrapArround; 1183 } 1184 1185 1186 1187 1188 bool Outliner::IsValidTextObject (const ::sd::outliner::IteratorPosition& rPosition) 1189 { 1190 SdrTextObj* pObject = dynamic_cast< SdrTextObj* >( rPosition.mxObject.get() ); 1191 return (pObject != NULL) && pObject->HasText() && ! pObject->IsEmptyPresObj(); 1192 } 1193 1194 1195 1196 1197 void Outliner::PutTextIntoOutliner() 1198 { 1199 mpTextObj = dynamic_cast<SdrTextObj*>( mpObj ); 1200 if ( mpTextObj && mpTextObj->HasText() && !mpTextObj->IsEmptyPresObj() ) 1201 { 1202 SdrText* pText = mpTextObj->getText( mnText ); 1203 mpParaObj = pText ? pText->GetOutlinerParaObject() : NULL; 1204 1205 if (mpParaObj != NULL) 1206 { 1207 SetText(*mpParaObj); 1208 1209 ClearModifyFlag(); 1210 } 1211 } 1212 else 1213 { 1214 mpTextObj = NULL; 1215 } 1216 } 1217 1218 1219 1220 1221 void Outliner::PrepareSpellCheck (void) 1222 { 1223 EESpellState eState = HasSpellErrors(); 1224 DBG_ASSERT(eState != EE_SPELL_NOSPELLER, "No SpellChecker"); 1225 1226 if (eState == EE_SPELL_NOLANGUAGE) 1227 { 1228 mbError = sal_True; 1229 mbEndOfSearch = sal_True; 1230 ErrorBox aErrorBox (NULL, 1231 WB_OK, 1232 String(SdResId(STR_NOLANGUAGE))); 1233 ShowModalMessageBox (aErrorBox); 1234 } 1235 else if (eState != EE_SPELL_OK) 1236 { 1237 // When spell checking we have to test whether we have processed the 1238 // whole document and have reached the start page again. 1239 if (meMode == SPELL) 1240 { 1241 if (maSearchStartPosition == ::sd::outliner::Iterator()) 1242 // Remember the position of the first text object so that we 1243 // know when we have processed the whole document. 1244 maSearchStartPosition = maObjectIterator; 1245 else if (maSearchStartPosition == maObjectIterator) 1246 { 1247 mbEndOfSearch = true; 1248 } 1249 } 1250 1251 EnterEditMode( sal_False ); 1252 } 1253 } 1254 1255 1256 1257 1258 void Outliner::PrepareSearchAndReplace (void) 1259 { 1260 if (HasText( *mpSearchItem )) 1261 { 1262 mbStringFound = true; 1263 mbMatchMayExist = true; 1264 1265 EnterEditMode (); 1266 1267 mpDrawDocument->GetDocSh()->SetWaitCursor( sal_False ); 1268 // Start seach at the right end of the current object's text 1269 // depending on the search direction. 1270 OutlinerView* pOutlinerView = mpImpl->GetOutlinerView(); 1271 if (pOutlinerView != NULL) 1272 pOutlinerView->SetSelection (GetSearchStartPosition ()); 1273 } 1274 } 1275 1276 1277 1278 1279 void Outliner::SetViewMode (PageKind ePageKind) 1280 { 1281 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock()); 1282 ::boost::shared_ptr<DrawViewShell> pDrawViewShell( 1283 ::boost::dynamic_pointer_cast<DrawViewShell>(pViewShell)); 1284 if (pDrawViewShell.get()!=NULL && ePageKind != pDrawViewShell->GetPageKind()) 1285 { 1286 // Restore old edit mode. 1287 pDrawViewShell->ChangeEditMode(mpImpl->meOriginalEditMode, sal_False); 1288 1289 SetStatusEventHdl(Link()); 1290 ::rtl::OUString sViewURL; 1291 switch (ePageKind) 1292 { 1293 case PK_STANDARD: 1294 default: 1295 sViewURL = framework::FrameworkHelper::msImpressViewURL; 1296 break; 1297 case PK_NOTES: 1298 sViewURL = framework::FrameworkHelper::msNotesViewURL; 1299 break; 1300 case PK_HANDOUT: 1301 sViewURL = framework::FrameworkHelper::msHandoutViewURL; 1302 break; 1303 } 1304 // The text object iterator is destroyed when the shells are 1305 // switched but we need it so save it and restore it afterwards. 1306 ::sd::outliner::Iterator aIterator (maObjectIterator); 1307 bool bMatchMayExist = mbMatchMayExist; 1308 1309 ViewShellBase& rBase = pViewShell->GetViewShellBase(); 1310 SetViewShell(::boost::shared_ptr<ViewShell>()); 1311 framework::FrameworkHelper::Instance(rBase)->RequestView( 1312 sViewURL, 1313 framework::FrameworkHelper::msCenterPaneURL); 1314 1315 // Force (well, request) a synchronous update of the configuration. 1316 // In a better world we would handle the asynchronous view update 1317 // instead. But that would involve major restucturing of the 1318 // Outliner code. 1319 framework::FrameworkHelper::Instance(rBase)->RequestSynchronousUpdate(); 1320 SetViewShell(rBase.GetMainViewShell()); 1321 1322 // Switching to another view shell has intermediatly called 1323 // EndSpelling(). A PrepareSpelling() is pending, so call that now. 1324 PrepareSpelling(); 1325 1326 // Update the number of pages so that 1327 // <member>DetectChange()</member> has the correct value to compare 1328 // to. 1329 mnPageCount = mpDrawDocument->GetSdPageCount(ePageKind); 1330 1331 maObjectIterator = aIterator; 1332 mbMatchMayExist = bMatchMayExist; 1333 1334 // Save edit mode so that it can be restored when switching the view 1335 // shell again. 1336 pDrawViewShell = ::boost::dynamic_pointer_cast<DrawViewShell>(pViewShell); 1337 OSL_ASSERT(pDrawViewShell.get()!=NULL); 1338 if (pDrawViewShell.get() != NULL) 1339 mpImpl->meOriginalEditMode = pDrawViewShell->GetEditMode(); 1340 } 1341 } 1342 1343 1344 1345 1346 void Outliner::SetPage (EditMode eEditMode, sal_uInt16 nPageIndex) 1347 { 1348 if ( ! mbRestrictSearchToSelection) 1349 { 1350 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock()); 1351 ::boost::shared_ptr<DrawViewShell> pDrawViewShell( 1352 ::boost::dynamic_pointer_cast<DrawViewShell>(pViewShell)); 1353 OSL_ASSERT(pDrawViewShell.get()!=NULL); 1354 if (pDrawViewShell.get() != NULL) 1355 { 1356 pDrawViewShell->ChangeEditMode(eEditMode, sal_False); 1357 pDrawViewShell->SwitchPage(nPageIndex); 1358 } 1359 } 1360 } 1361 1362 1363 1364 1365 void Outliner::EnterEditMode (sal_Bool bGrabFocus) 1366 { 1367 OutlinerView* pOutlinerView = mpImpl->GetOutlinerView(); 1368 if (pOutlinerView != NULL) 1369 { 1370 pOutlinerView->SetOutputArea( Rectangle( Point(), Size(1, 1))); 1371 SetPaperSize( mpTextObj->GetLogicRect().GetSize() ); 1372 SdrPageView* pPV = mpView->GetSdrPageView(); 1373 1374 // Make FuText the current function. 1375 SfxUInt16Item aItem (SID_TEXTEDIT, 1); 1376 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock()); 1377 pViewShell->GetDispatcher()-> 1378 Execute(SID_TEXTEDIT, SFX_CALLMODE_SYNCHRON | 1379 SFX_CALLMODE_RECORD, &aItem, 0L); 1380 1381 // To be consistent with the usual behaviour in the Office the text 1382 // object that is put into edit mode would have also to be selected. 1383 // Starting the text edit mode is not enough so we do it here by 1384 // hand. 1385 mbExpectingSelectionChangeEvent = true; 1386 mpView->UnmarkAllObj (pPV); 1387 mpView->MarkObj (mpTextObj, pPV); 1388 1389 if( mpTextObj ) 1390 mpTextObj->setActiveText( mnText ); 1391 1392 // Turn on the edit mode for the text object. 1393 mpView->SdrBeginTextEdit(mpTextObj, pPV, mpWindow, sal_True, this, pOutlinerView, sal_True, sal_True, bGrabFocus); 1394 1395 SetUpdateMode(sal_True); 1396 mbFoundObject = sal_True; 1397 } 1398 } 1399 1400 1401 1402 1403 /************************************************************************* 1404 |* 1405 |* SpellChecker: Error-LinkHdl 1406 |* 1407 \************************************************************************/ 1408 1409 IMPL_LINK_INLINE_START( Outliner, SpellError, void *, nLang ) 1410 { 1411 mbError = true; 1412 String aError( SvtLanguageTable::GetLanguageString( (LanguageType)(sal_uLong)nLang ) ); 1413 ErrorHandler::HandleError(* new StringErrorInfo( 1414 ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS, aError) ); 1415 return 0; 1416 } 1417 IMPL_LINK_INLINE_END( Outliner, SpellError, void *, nLang ) 1418 1419 1420 1421 1422 ESelection Outliner::GetSearchStartPosition (void) 1423 { 1424 ESelection aPosition; 1425 if (mbDirectionIsForward) 1426 { 1427 // The default constructor uses the beginning of the text as default. 1428 aPosition = ESelection (); 1429 } 1430 else 1431 { 1432 // Retrieve the position after the last character in the last 1433 // paragraph. 1434 sal_uInt16 nParagraphCount = static_cast<sal_uInt16>(GetParagraphCount()); 1435 if (nParagraphCount == 0) 1436 aPosition = ESelection(); 1437 else 1438 { 1439 xub_StrLen nLastParagraphLength = GetEditEngine().GetTextLen ( 1440 nParagraphCount-1); 1441 aPosition = ESelection (nParagraphCount-1, nLastParagraphLength); 1442 } 1443 } 1444 1445 return aPosition; 1446 } 1447 1448 1449 1450 1451 bool Outliner::HasNoPreviousMatch (void) 1452 { 1453 OutlinerView* pOutlinerView = mpImpl->GetOutlinerView(); 1454 1455 DBG_ASSERT (pOutlinerView!=NULL, "outline view in Outliner::HasNoPreviousMatch is NULL"); 1456 1457 // Detect whether the cursor stands at the beginning 1458 // resp. at the end of the text. 1459 return pOutlinerView->GetSelection().IsEqual(GetSearchStartPosition ()) == sal_True; 1460 } 1461 1462 1463 1464 1465 bool Outliner::HandleFailedSearch (void) 1466 { 1467 bool bContinueSearch = false; 1468 1469 OutlinerView* pOutlinerView = mpImpl->GetOutlinerView(); 1470 if (pOutlinerView != NULL && mpSearchItem != NULL) 1471 { 1472 // Detect whether there is/may be a prior match. If there is then 1473 // ask the user whether to wrap arround. Otherwise tell the user 1474 // that there is no match. 1475 if (HasNoPreviousMatch ()) 1476 { 1477 // No match found in the whole presentation. Tell the user. 1478 InfoBox aInfoBox (NULL, 1479 String(SdResId(STR_SAR_NOT_FOUND))); 1480 ShowModalMessageBox (aInfoBox); 1481 } 1482 1483 else 1484 { 1485 // No further matches found. Ask the user whether to wrap 1486 // arround and start again. 1487 bContinueSearch = ShowWrapArroundDialog (); 1488 } 1489 } 1490 1491 return bContinueSearch; 1492 } 1493 1494 1495 SdrObject* Outliner::SetObject ( 1496 const ::sd::outliner::IteratorPosition& rPosition) 1497 { 1498 SetViewMode (rPosition.mePageKind); 1499 SetPage (rPosition.meEditMode, (sal_uInt16)rPosition.mnPageIndex); 1500 mnText = rPosition.mnText; 1501 return rPosition.mxObject.get(); 1502 } 1503 1504 1505 1506 1507 void Outliner::SetViewShell (const ::boost::shared_ptr<ViewShell>& rpViewShell) 1508 { 1509 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock()); 1510 if (pViewShell != rpViewShell) 1511 { 1512 // Set the new view shell. 1513 mpWeakViewShell = rpViewShell; 1514 // When the outline view is not owned by us then we have to clear 1515 // that pointer so that the current one for the new view shell will 1516 // be used (in ProvideOutlinerView). 1517 // if ( ! mbOwnOutlineView) 1518 // mpOutlineView = NULL; 1519 if (rpViewShell) 1520 { 1521 mpView = rpViewShell->GetView(); 1522 1523 mpWindow = rpViewShell->GetActiveWindow(); 1524 1525 mpImpl->ProvideOutlinerView(*this, rpViewShell, mpWindow); 1526 OutlinerView* pOutlinerView = mpImpl->GetOutlinerView(); 1527 if (pOutlinerView != NULL) 1528 pOutlinerView->SetWindow(mpWindow); 1529 } 1530 else 1531 { 1532 mpView = NULL; 1533 mpWindow = NULL; 1534 } 1535 } 1536 } 1537 1538 1539 1540 1541 void Outliner::HandleChangedSelection (void) 1542 { 1543 maMarkListCopy.clear(); 1544 mbRestrictSearchToSelection = (mpView->AreObjectsMarked()==sal_True); 1545 if (mbRestrictSearchToSelection) 1546 { 1547 // Make a copy of the current mark list. 1548 const SdrMarkList& rMarkList = mpView->GetMarkedObjectList(); 1549 sal_uLong nCount = rMarkList.GetMarkCount(); 1550 if (nCount > 0) 1551 { 1552 maMarkListCopy.clear(); 1553 maMarkListCopy.reserve (nCount); 1554 for (sal_uLong i=0; i<nCount; i++) 1555 maMarkListCopy.push_back (rMarkList.GetMark(i)->GetMarkedSdrObj ()); 1556 } 1557 else 1558 // No marked object. Is this case possible? 1559 mbRestrictSearchToSelection = false; 1560 } 1561 } 1562 1563 1564 1565 1566 1567 void Outliner::StartConversion( sal_Int16 nSourceLanguage, sal_Int16 nTargetLanguage, 1568 const Font *pTargetFont, sal_Int32 nOptions, sal_Bool bIsInteractive ) 1569 { 1570 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock()); 1571 sal_Bool bMultiDoc = pViewShell->ISA(DrawViewShell); 1572 1573 meMode = TEXT_CONVERSION; 1574 mbDirectionIsForward = true; 1575 mpSearchItem = NULL; 1576 mnConversionLanguage = nSourceLanguage; 1577 1578 BeginConversion(); 1579 1580 OutlinerView* pOutlinerView = mpImpl->GetOutlinerView(); 1581 if (pOutlinerView != NULL) 1582 { 1583 pOutlinerView->StartTextConversion( 1584 nSourceLanguage, 1585 nTargetLanguage, 1586 pTargetFont, 1587 nOptions, 1588 bIsInteractive, 1589 bMultiDoc); 1590 } 1591 1592 EndConversion(); 1593 } 1594 1595 1596 1597 1598 /** Prepare to do a text conversion on the current text object. This 1599 includes putting it into edit mode. 1600 */ 1601 void Outliner::PrepareConversion (void) 1602 { 1603 SetUpdateMode(sal_True); 1604 if( HasConvertibleTextPortion( mnConversionLanguage ) ) 1605 { 1606 SetUpdateMode(sal_False); 1607 mbStringFound = sal_True; 1608 mbMatchMayExist = sal_True; 1609 1610 EnterEditMode (); 1611 1612 mpDrawDocument->GetDocSh()->SetWaitCursor( sal_False ); 1613 // Start seach at the right end of the current object's text 1614 // depending on the search direction. 1615 // mpOutlineView->SetSelection (GetSearchStartPosition ()); 1616 } 1617 else 1618 { 1619 SetUpdateMode(sal_False); 1620 } 1621 } 1622 1623 1624 1625 1626 void Outliner::BeginConversion (void) 1627 { 1628 SetRefDevice( SD_MOD()->GetRefDevice( *mpDrawDocument->GetDocSh() ) ); 1629 1630 ViewShellBase* pBase = PTR_CAST(ViewShellBase, SfxViewShell::Current()); 1631 if (pBase != NULL) 1632 SetViewShell (pBase->GetMainViewShell()); 1633 1634 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock()); 1635 if (pViewShell) 1636 { 1637 mbStringFound = sal_False; 1638 1639 // Supposed that we are not located at the very beginning/end of the 1640 // document then there may be a match in the document prior/after 1641 // the current position. 1642 mbMatchMayExist = sal_True; 1643 1644 maObjectIterator = ::sd::outliner::Iterator(); 1645 maSearchStartPosition = ::sd::outliner::Iterator(); 1646 RememberStartPosition(); 1647 1648 mpImpl->ProvideOutlinerView(*this, pViewShell, mpWindow); 1649 1650 HandleChangedSelection (); 1651 } 1652 ClearModifyFlag(); 1653 } 1654 1655 1656 1657 1658 void Outliner::EndConversion() 1659 { 1660 EndSpelling(); 1661 } 1662 1663 1664 1665 1666 sal_Bool Outliner::ConvertNextDocument() 1667 { 1668 ::boost::shared_ptr<ViewShell> pViewShell (mpWeakViewShell.lock()); 1669 if (pViewShell && pViewShell->ISA(OutlineViewShell) ) 1670 return false; 1671 1672 mpDrawDocument->GetDocSh()->SetWaitCursor( sal_True ); 1673 1674 Initialize ( true ); 1675 1676 OutlinerView* pOutlinerView = mpImpl->GetOutlinerView(); 1677 if (pOutlinerView != NULL) 1678 { 1679 mpWindow = pViewShell->GetActiveWindow(); 1680 pOutlinerView->SetWindow(mpWindow); 1681 } 1682 ProvideNextTextObject (); 1683 1684 mpDrawDocument->GetDocSh()->SetWaitCursor( sal_False ); 1685 ClearModifyFlag(); 1686 1687 // for text conversion we automaticly wrap around one 1688 // time and stop at the start shape 1689 if( mpFirstObj ) 1690 { 1691 if( (mnText == 0) && (mpFirstObj == mpObj) ) 1692 return false; 1693 } 1694 else 1695 { 1696 mpFirstObj = mpObj; 1697 } 1698 1699 return !mbEndOfSearch; 1700 } 1701 1702 1703 1704 1705 sal_uInt16 Outliner::ShowModalMessageBox (Dialog& rMessageBox) 1706 { 1707 // We assume that the parent of the given messge box is NULL, i.e. it is 1708 // modal with respect to the top application window. However, this 1709 // does not affect the search dialog. Therefore we have to lock it here 1710 // while the message box is being shown. We also have to take into 1711 // account that we are called during a spell check and the search dialog 1712 // is not available. 1713 ::Window* pSearchDialog = NULL; 1714 SfxChildWindow* pChildWindow = NULL; 1715 switch (meMode) 1716 { 1717 case SEARCH: 1718 pChildWindow = SfxViewFrame::Current()->GetChildWindow( 1719 SvxSearchDialogWrapper::GetChildWindowId()); 1720 break; 1721 1722 case SPELL: 1723 pChildWindow = SfxViewFrame::Current()->GetChildWindow( 1724 SpellDialogChildWindow::GetChildWindowId()); 1725 break; 1726 1727 case TEXT_CONVERSION: 1728 // There should no messages boxes be displayed while doing the 1729 // hangul hanja conversion. 1730 break; 1731 } 1732 1733 if (pChildWindow != NULL) 1734 pSearchDialog = pChildWindow->GetWindow(); 1735 if (pSearchDialog != NULL) 1736 pSearchDialog->EnableInput(sal_False,sal_True); 1737 1738 sal_uInt16 nResult = rMessageBox.Execute(); 1739 1740 // Unlock the search dialog. 1741 if (pSearchDialog != NULL) 1742 pSearchDialog->EnableInput(sal_True,sal_True); 1743 1744 return nResult; 1745 } 1746 1747 1748 1749 1750 //===== Outliner::Implementation ============================================== 1751 1752 Outliner::Implementation::Implementation (void) 1753 : meOriginalEditMode(EM_PAGE), 1754 mbOwnOutlineView(false), 1755 mpOutlineView(NULL) 1756 { 1757 } 1758 1759 1760 1761 1762 Outliner::Implementation::~Implementation (void) 1763 { 1764 if (mbOwnOutlineView && mpOutlineView!=NULL) 1765 { 1766 mpOutlineView->SetWindow(NULL); 1767 delete mpOutlineView; 1768 mpOutlineView = NULL; 1769 } 1770 } 1771 1772 1773 1774 1775 OutlinerView* Outliner::Implementation::GetOutlinerView () 1776 { 1777 return mpOutlineView; 1778 } 1779 1780 1781 1782 1783 /** We try to create a new OutlinerView only when there is none available, 1784 either from an OutlinerViewShell or a previous call to 1785 ProvideOutlinerView(). This is necessary to support the spell checker 1786 which can not cope with exchanging the OutlinerView. 1787 */ 1788 void Outliner::Implementation::ProvideOutlinerView ( 1789 Outliner& rOutliner, 1790 const ::boost::shared_ptr<ViewShell>& rpViewShell, 1791 ::Window* pWindow) 1792 { 1793 if (rpViewShell.get() != NULL) 1794 { 1795 switch (rpViewShell->GetShellType()) 1796 { 1797 case ViewShell::ST_DRAW: 1798 case ViewShell::ST_IMPRESS: 1799 case ViewShell::ST_NOTES: 1800 case ViewShell::ST_HANDOUT: 1801 { 1802 // Create a new outline view to do the search on. 1803 bool bInsert = false; 1804 if (mpOutlineView!=NULL && !mbOwnOutlineView) 1805 mpOutlineView = NULL; 1806 if (mpOutlineView == NULL) 1807 { 1808 mpOutlineView = new OutlinerView(&rOutliner, pWindow); 1809 mbOwnOutlineView = true; 1810 bInsert = true; 1811 } 1812 else 1813 mpOutlineView->SetWindow(pWindow); 1814 sal_uLong nStat = mpOutlineView->GetControlWord(); 1815 nStat &= ~EV_CNTRL_AUTOSCROLL; 1816 mpOutlineView->SetControlWord(nStat); 1817 if (bInsert) 1818 rOutliner.InsertView( mpOutlineView ); 1819 rOutliner.SetUpdateMode(sal_False); 1820 mpOutlineView->SetOutputArea (Rectangle (Point(), Size(1, 1))); 1821 rOutliner.SetPaperSize( Size(1, 1) ); 1822 rOutliner.SetText( String(), rOutliner.GetParagraph( 0 ) ); 1823 1824 meOriginalEditMode = 1825 ::boost::static_pointer_cast<DrawViewShell>(rpViewShell)->GetEditMode(); 1826 } 1827 break; 1828 1829 case ViewShell::ST_OUTLINE: 1830 { 1831 if (mpOutlineView!=NULL && mbOwnOutlineView) 1832 delete mpOutlineView; 1833 mpOutlineView = rOutliner.GetView(0); 1834 mbOwnOutlineView = false; 1835 } 1836 break; 1837 1838 default: 1839 case ViewShell::ST_NONE: 1840 case ViewShell::ST_PRESENTATION: 1841 // Ignored 1842 break; 1843 } 1844 } 1845 } 1846 1847 1848 1849 1850 void Outliner::Implementation::ReleaseOutlinerView (void) 1851 { 1852 if (mbOwnOutlineView) 1853 { 1854 OutlinerView* pView = mpOutlineView; 1855 mpOutlineView = NULL; 1856 mbOwnOutlineView = false; 1857 if (pView != NULL) 1858 { 1859 pView->SetWindow(NULL); 1860 delete pView; 1861 } 1862 } 1863 else 1864 { 1865 mpOutlineView = NULL; 1866 } 1867 } 1868 1869 } // end of namespace sd 1870