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