1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_svtools.hxx" 30 #include <svtools/textview.hxx> 31 #include <svtools/texteng.hxx> 32 #include <textdoc.hxx> 33 #include <svtools/textdata.hxx> 34 #include <textdat2.hxx> 35 36 #include <svl/undo.hxx> 37 #include <vcl/cursor.hxx> 38 #include <vcl/window.hxx> 39 #include <vcl/svapp.hxx> 40 #include <vcl/sound.hxx> 41 #include <tools/stream.hxx> 42 43 #include <sot/formats.hxx> 44 #include <svl/urlbmk.hxx> 45 46 #ifndef _COM_SUN_STAR_TEXT_XBREAKITERATOR_HPP_ 47 #include <com/sun/star/i18n/XBreakIterator.hpp> 48 #endif 49 50 #ifndef _COM_SUN_STAR_TEXT_CHARACTERITERATORMODE_HPP_ 51 #include <com/sun/star/i18n/CharacterIteratorMode.hpp> 52 #endif 53 54 #ifndef _COM_SUN_STAR_TEXT_WORDTYPE_HPP_ 55 #include <com/sun/star/i18n/WordType.hpp> 56 #endif 57 #include <cppuhelper/weak.hxx> 58 #include <vcl/unohelp.hxx> 59 #include <com/sun/star/datatransfer/XTransferable.hpp> 60 #include <com/sun/star/datatransfer/clipboard/XClipboard.hpp> 61 #include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp> 62 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 63 64 #ifndef _COM_SUN_STAR_DATATRANSFER_DND_DNDCONSTANS_HPP_ 65 #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp> 66 #endif 67 #include <com/sun/star/datatransfer/dnd/XDragGestureRecognizer.hpp> 68 #include <com/sun/star/datatransfer/dnd/XDropTarget.hpp> 69 70 #include <vcl/edit.hxx> 71 72 73 #include <sot/exchange.hxx> 74 #include <sot/formats.hxx> 75 76 #include <vos/mutex.hxx> 77 78 79 using namespace ::com::sun::star; 80 81 class TETextDataObject : public ::com::sun::star::datatransfer::XTransferable, 82 public ::cppu::OWeakObject 83 84 { 85 private: 86 String maText; 87 SvMemoryStream maHTMLStream; 88 89 public: 90 TETextDataObject( const String& rText ); 91 ~TETextDataObject(); 92 93 String& GetText() { return maText; } 94 SvMemoryStream& GetHTMLStream() { return maHTMLStream; } 95 96 // ::com::sun::star::uno::XInterface 97 ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type & rType ) throw(::com::sun::star::uno::RuntimeException); 98 void SAL_CALL acquire() throw() { OWeakObject::acquire(); } 99 void SAL_CALL release() throw() { OWeakObject::release(); } 100 101 // ::com::sun::star::datatransfer::XTransferable 102 ::com::sun::star::uno::Any SAL_CALL getTransferData( const ::com::sun::star::datatransfer::DataFlavor& aFlavor ) throw(::com::sun::star::datatransfer::UnsupportedFlavorException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); 103 ::com::sun::star::uno::Sequence< ::com::sun::star::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors( ) throw(::com::sun::star::uno::RuntimeException); 104 sal_Bool SAL_CALL isDataFlavorSupported( const ::com::sun::star::datatransfer::DataFlavor& aFlavor ) throw(::com::sun::star::uno::RuntimeException); 105 }; 106 107 TETextDataObject::TETextDataObject( const String& rText ) : maText( rText ) 108 { 109 } 110 111 TETextDataObject::~TETextDataObject() 112 { 113 } 114 115 // uno::XInterface 116 uno::Any TETextDataObject::queryInterface( const uno::Type & rType ) throw(uno::RuntimeException) 117 { 118 uno::Any aRet = ::cppu::queryInterface( rType, SAL_STATIC_CAST( datatransfer::XTransferable*, this ) ); 119 return (aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType )); 120 } 121 122 // datatransfer::XTransferable 123 uno::Any TETextDataObject::getTransferData( const datatransfer::DataFlavor& rFlavor ) throw(datatransfer::UnsupportedFlavorException, io::IOException, uno::RuntimeException) 124 { 125 uno::Any aAny; 126 127 sal_uLong nT = SotExchange::GetFormat( rFlavor ); 128 if ( nT == SOT_FORMAT_STRING ) 129 { 130 aAny <<= (::rtl::OUString)GetText(); 131 } 132 else if ( nT == SOT_FORMATSTR_ID_HTML ) 133 { 134 GetHTMLStream().Seek( STREAM_SEEK_TO_END ); 135 sal_uLong nLen = GetHTMLStream().Tell(); 136 GetHTMLStream().Seek(0); 137 138 uno::Sequence< sal_Int8 > aSeq( nLen ); 139 memcpy( aSeq.getArray(), GetHTMLStream().GetData(), nLen ); 140 aAny <<= aSeq; 141 } 142 else 143 { 144 throw datatransfer::UnsupportedFlavorException(); 145 } 146 return aAny; 147 } 148 149 uno::Sequence< datatransfer::DataFlavor > TETextDataObject::getTransferDataFlavors( ) throw(uno::RuntimeException) 150 { 151 GetHTMLStream().Seek( STREAM_SEEK_TO_END ); 152 sal_Bool bHTML = GetHTMLStream().Tell() > 0; 153 uno::Sequence< datatransfer::DataFlavor > aDataFlavors( bHTML ? 2 : 1 ); 154 SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aDataFlavors.getArray()[0] ); 155 if ( bHTML ) 156 SotExchange::GetFormatDataFlavor( SOT_FORMATSTR_ID_HTML, aDataFlavors.getArray()[1] ); 157 return aDataFlavors; 158 } 159 160 sal_Bool TETextDataObject::isDataFlavorSupported( const datatransfer::DataFlavor& rFlavor ) throw(uno::RuntimeException) 161 { 162 sal_uLong nT = SotExchange::GetFormat( rFlavor ); 163 return ( nT == SOT_FORMAT_STRING ); 164 } 165 166 /*-- 24.06.2004 13:54:36--------------------------------------------------- 167 168 -----------------------------------------------------------------------*/ 169 struct ImpTextView 170 { 171 TextEngine* mpTextEngine; 172 173 Window* mpWindow; 174 TextSelection maSelection; 175 Point maStartDocPos; 176 // TextPaM maMBDownPaM; 177 178 Cursor* mpCursor; 179 180 TextDDInfo* mpDDInfo; 181 182 VirtualDevice* mpVirtDev; 183 184 SelectionEngine* mpSelEngine; 185 TextSelFunctionSet* mpSelFuncSet; 186 187 ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSourceListener > mxDnDListener; 188 189 sal_uInt16 mnTravelXPos; 190 191 sal_Bool mbAutoScroll : 1; 192 sal_Bool mbInsertMode : 1; 193 sal_Bool mbReadOnly : 1; 194 sal_Bool mbPaintSelection : 1; 195 sal_Bool mbAutoIndent : 1; 196 sal_Bool mbHighlightSelection : 1; 197 sal_Bool mbCursorEnabled : 1; 198 sal_Bool mbClickedInSelection : 1; 199 sal_Bool mbSupportProtectAttribute : 1; 200 bool mbCursorAtEndOfLine; 201 }; 202 203 // ------------------------------------------------------------------------- 204 // (+) class TextView 205 // ------------------------------------------------------------------------- 206 TextView::TextView( TextEngine* pEng, Window* pWindow ) : 207 mpImpl(new ImpTextView) 208 { 209 pWindow->EnableRTL( sal_False ); 210 211 mpImpl->mpWindow = pWindow; 212 mpImpl->mpTextEngine = pEng; 213 mpImpl->mpVirtDev = NULL; 214 215 mpImpl->mbPaintSelection = sal_True; 216 mpImpl->mbAutoScroll = sal_True; 217 mpImpl->mbInsertMode = sal_True; 218 mpImpl->mbReadOnly = sal_False; 219 mpImpl->mbHighlightSelection = sal_False; 220 mpImpl->mbAutoIndent = sal_False; 221 mpImpl->mbCursorEnabled = sal_True; 222 mpImpl->mbClickedInSelection = sal_False; 223 mpImpl->mbSupportProtectAttribute = sal_False; 224 mpImpl->mbCursorAtEndOfLine = false; 225 // mbInSelection = sal_False; 226 227 mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW; 228 229 mpImpl->mpSelFuncSet = new TextSelFunctionSet( this ); 230 mpImpl->mpSelEngine = new SelectionEngine( mpImpl->mpWindow, mpImpl->mpSelFuncSet ); 231 mpImpl->mpSelEngine->SetSelectionMode( RANGE_SELECTION ); 232 mpImpl->mpSelEngine->EnableDrag( sal_True ); 233 234 mpImpl->mpCursor = new Cursor; 235 mpImpl->mpCursor->Show(); 236 pWindow->SetCursor( mpImpl->mpCursor ); 237 pWindow->SetInputContext( InputContext( pEng->GetFont(), INPUTCONTEXT_TEXT|INPUTCONTEXT_EXTTEXTINPUT ) ); 238 239 if ( pWindow->GetSettings().GetStyleSettings().GetSelectionOptions() & SELECTION_OPTION_INVERT ) 240 mpImpl->mbHighlightSelection = sal_True; 241 242 pWindow->SetLineColor(); 243 244 mpImpl->mpDDInfo = NULL; 245 246 if ( pWindow->GetDragGestureRecognizer().is() ) 247 { 248 vcl::unohelper::DragAndDropWrapper* pDnDWrapper = new vcl::unohelper::DragAndDropWrapper( this ); 249 mpImpl->mxDnDListener = pDnDWrapper; 250 251 uno::Reference< datatransfer::dnd::XDragGestureListener> xDGL( mpImpl->mxDnDListener, uno::UNO_QUERY ); 252 pWindow->GetDragGestureRecognizer()->addDragGestureListener( xDGL ); 253 uno::Reference< datatransfer::dnd::XDropTargetListener> xDTL( xDGL, uno::UNO_QUERY ); 254 pWindow->GetDropTarget()->addDropTargetListener( xDTL ); 255 pWindow->GetDropTarget()->setActive( sal_True ); 256 pWindow->GetDropTarget()->setDefaultActions( datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE ); 257 } 258 } 259 260 TextView::~TextView() 261 { 262 delete mpImpl->mpSelEngine; 263 delete mpImpl->mpSelFuncSet; 264 delete mpImpl->mpVirtDev; 265 266 if ( mpImpl->mpWindow->GetCursor() == mpImpl->mpCursor ) 267 mpImpl->mpWindow->SetCursor( 0 ); 268 delete mpImpl->mpCursor; 269 delete mpImpl->mpDDInfo; 270 delete mpImpl; 271 } 272 273 void TextView::Invalidate() 274 { 275 mpImpl->mpWindow->Invalidate(); 276 } 277 278 void TextView::SetSelection( const TextSelection& rTextSel, sal_Bool bGotoCursor ) 279 { 280 // Falls jemand gerade ein leeres Attribut hinterlassen hat, 281 // und dann der Outliner die Selektion manipulitert: 282 if ( !mpImpl->maSelection.HasRange() ) 283 mpImpl->mpTextEngine->CursorMoved( mpImpl->maSelection.GetStart().GetPara() ); 284 285 // Wenn nach einem KeyInput die Selection manipuliert wird: 286 mpImpl->mpTextEngine->CheckIdleFormatter(); 287 288 HideSelection(); 289 TextSelection aNewSel( rTextSel ); 290 mpImpl->mpTextEngine->ValidateSelection( aNewSel ); 291 ImpSetSelection( aNewSel ); 292 ShowSelection(); 293 ShowCursor( bGotoCursor ); 294 } 295 296 void TextView::SetSelection( const TextSelection& rTextSel ) 297 { 298 SetSelection( rTextSel, mpImpl->mbAutoScroll ); 299 } 300 301 const TextSelection& TextView::GetSelection() const 302 { 303 return mpImpl->maSelection; 304 } 305 TextSelection& TextView::GetSelection() 306 { 307 return mpImpl->maSelection; 308 } 309 310 void TextView::DeleteSelected() 311 { 312 // HideSelection(); 313 314 mpImpl->mpTextEngine->UndoActionStart(); 315 TextPaM aPaM = mpImpl->mpTextEngine->ImpDeleteText( mpImpl->maSelection ); 316 mpImpl->mpTextEngine->UndoActionEnd(); 317 318 ImpSetSelection( aPaM ); 319 mpImpl->mpTextEngine->FormatAndUpdate( this ); 320 ShowCursor(); 321 } 322 323 void TextView::ImpPaint( OutputDevice* pOut, const Point& rStartPos, Rectangle const* pPaintArea, TextSelection const* pPaintRange, TextSelection const* pSelection ) 324 { 325 if ( !mpImpl->mbPaintSelection ) 326 pSelection = NULL; 327 else 328 { 329 // Richtige Hintergrundfarbe einstellen. 330 // Ich bekomme leider nicht mit, ob sich diese inzwischen geaendert hat. 331 Font aFont = mpImpl->mpTextEngine->GetFont(); 332 Color aColor = pOut->GetBackground().GetColor(); 333 aColor.SetTransparency( 0 ); 334 if ( aColor != aFont.GetFillColor() ) 335 { 336 if( aFont.IsTransparent() ) 337 aColor = Color( COL_TRANSPARENT ); 338 aFont.SetFillColor( aColor ); 339 mpImpl->mpTextEngine->maFont = aFont; 340 } 341 } 342 343 mpImpl->mpTextEngine->ImpPaint( pOut, rStartPos, pPaintArea, pPaintRange, pSelection ); 344 } 345 346 void TextView::Paint( const Rectangle& rRect ) 347 { 348 ImpPaint( rRect, sal_False ); 349 } 350 351 void TextView::ImpPaint( const Rectangle& rRect, sal_Bool bUseVirtDev ) 352 { 353 if ( !mpImpl->mpTextEngine->GetUpdateMode() || mpImpl->mpTextEngine->IsInUndo() ) 354 return; 355 356 TextSelection *pDrawSelection = NULL; 357 if ( !mpImpl->mbHighlightSelection && mpImpl->maSelection.HasRange() ) 358 pDrawSelection = &mpImpl->maSelection; 359 360 if ( bUseVirtDev ) 361 { 362 VirtualDevice* pVDev = GetVirtualDevice(); 363 364 const Color& rBackgroundColor = mpImpl->mpWindow->GetBackground().GetColor(); 365 if ( pVDev->GetFillColor() != rBackgroundColor ) 366 pVDev->SetFillColor( rBackgroundColor ); 367 if ( pVDev->GetBackground().GetColor() != rBackgroundColor ) 368 pVDev->SetBackground( rBackgroundColor ); 369 370 sal_Bool bVDevValid = sal_True; 371 Size aOutSz( pVDev->GetOutputSizePixel() ); 372 if ( ( aOutSz.Width() < rRect.GetWidth() ) || 373 ( aOutSz.Height() < rRect.GetHeight() ) ) 374 { 375 bVDevValid = pVDev->SetOutputSizePixel( rRect.GetSize() ); 376 } 377 else 378 { 379 // Das VirtDev kann bei einem Resize sehr gross werden => 380 // irgendwann mal kleiner machen! 381 if ( ( aOutSz.Height() > ( rRect.GetHeight() + 20 ) ) || 382 ( aOutSz.Width() > ( rRect.GetWidth() + 20 ) ) ) 383 { 384 bVDevValid = pVDev->SetOutputSizePixel( rRect.GetSize() ); 385 } 386 else 387 { 388 pVDev->Erase(); 389 } 390 } 391 if ( !bVDevValid ) 392 { 393 ImpPaint( rRect, sal_False /* ohne VDev */ ); 394 return; 395 } 396 397 Rectangle aTmpRec( Point( 0, 0 ), rRect.GetSize() ); 398 399 Point aDocPos( mpImpl->maStartDocPos.X(), mpImpl->maStartDocPos.Y() + rRect.Top() ); 400 Point aStartPos = ImpGetOutputStartPos( aDocPos ); 401 ImpPaint( pVDev, aStartPos, &aTmpRec, NULL, pDrawSelection ); 402 mpImpl->mpWindow->DrawOutDev( rRect.TopLeft(), rRect.GetSize(), 403 Point(0,0), rRect.GetSize(), *pVDev ); 404 // ShowSelection(); 405 if ( mpImpl->mbHighlightSelection ) 406 ImpHighlight( mpImpl->maSelection ); 407 } 408 else 409 { 410 Point aStartPos = ImpGetOutputStartPos( mpImpl->maStartDocPos ); 411 ImpPaint( mpImpl->mpWindow, aStartPos, &rRect, NULL, pDrawSelection ); 412 413 // ShowSelection(); 414 if ( mpImpl->mbHighlightSelection ) 415 ImpHighlight( mpImpl->maSelection ); 416 } 417 } 418 419 void TextView::ImpHighlight( const TextSelection& rSel ) 420 { 421 TextSelection aSel( rSel ); 422 aSel.Justify(); 423 if ( aSel.HasRange() && !mpImpl->mpTextEngine->IsInUndo() && mpImpl->mpTextEngine->GetUpdateMode() ) 424 { 425 mpImpl->mpCursor->Hide(); 426 427 DBG_ASSERT( !mpImpl->mpTextEngine->mpIdleFormatter->IsActive(), "ImpHighlight: Not formatted!" ); 428 429 Rectangle aVisArea( mpImpl->maStartDocPos, mpImpl->mpWindow->GetOutputSizePixel() ); 430 long nY = 0; 431 sal_uLong nStartPara = aSel.GetStart().GetPara(); 432 sal_uLong nEndPara = aSel.GetEnd().GetPara(); 433 for ( sal_uLong nPara = 0; nPara <= nEndPara; nPara++ ) 434 { 435 long nParaHeight = (long)mpImpl->mpTextEngine->CalcParaHeight( nPara ); 436 if ( ( nPara >= nStartPara ) && ( ( nY + nParaHeight ) > aVisArea.Top() ) ) 437 { 438 TEParaPortion* pTEParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( nPara ); 439 sal_uInt16 nStartLine = 0; 440 sal_uInt16 nEndLine = pTEParaPortion->GetLines().Count() -1; 441 if ( nPara == nStartPara ) 442 nStartLine = pTEParaPortion->GetLineNumber( aSel.GetStart().GetIndex(), sal_False ); 443 if ( nPara == nEndPara ) 444 nEndLine = pTEParaPortion->GetLineNumber( aSel.GetEnd().GetIndex(), sal_True ); 445 446 // ueber die Zeilen iterieren.... 447 for ( sal_uInt16 nLine = nStartLine; nLine <= nEndLine; nLine++ ) 448 { 449 TextLine* pLine = pTEParaPortion->GetLines().GetObject( nLine ); 450 sal_uInt16 nStartIndex = pLine->GetStart(); 451 sal_uInt16 nEndIndex = pLine->GetEnd(); 452 if ( ( nPara == nStartPara ) && ( nLine == nStartLine ) ) 453 nStartIndex = aSel.GetStart().GetIndex(); 454 if ( ( nPara == nEndPara ) && ( nLine == nEndLine ) ) 455 nEndIndex = aSel.GetEnd().GetIndex(); 456 457 // Kann passieren, wenn am Anfang einer umgebrochenen Zeile. 458 if ( nEndIndex < nStartIndex ) 459 nEndIndex = nStartIndex; 460 461 Rectangle aTmpRec( mpImpl->mpTextEngine->GetEditCursor( TextPaM( nPara, nStartIndex ), sal_False ) ); 462 aTmpRec.Top() += nY; 463 aTmpRec.Bottom() += nY; 464 Point aTopLeft( aTmpRec.TopLeft() ); 465 466 aTmpRec = mpImpl->mpTextEngine->GetEditCursor( TextPaM( nPara, nEndIndex ), sal_True ); 467 aTmpRec.Top() += nY; 468 aTmpRec.Bottom() += nY; 469 Point aBottomRight( aTmpRec.BottomRight() ); 470 aBottomRight.X()--; 471 472 // Nur Painten, wenn im sichtbaren Bereich... 473 if ( ( aTopLeft.X() < aBottomRight.X() ) && ( aBottomRight.Y() >= aVisArea.Top() ) ) 474 { 475 Point aPnt1( GetWindowPos( aTopLeft ) ); 476 Point aPnt2( GetWindowPos( aBottomRight ) ); 477 478 Rectangle aRect( aPnt1, aPnt2 ); 479 mpImpl->mpWindow->Invert( aRect ); 480 } 481 } 482 } 483 nY += nParaHeight; 484 485 if ( nY >= aVisArea.Bottom() ) 486 break; 487 } 488 } 489 } 490 491 void TextView::ImpSetSelection( const TextSelection& rSelection ) 492 { 493 if ( rSelection != mpImpl->maSelection ) 494 { 495 mpImpl->maSelection = rSelection; 496 mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_VIEWSELECTIONCHANGED ) ); 497 } 498 } 499 500 void TextView::ShowSelection() 501 { 502 ImpShowHideSelection( sal_True ); 503 } 504 505 void TextView::HideSelection() 506 { 507 ImpShowHideSelection( sal_False ); 508 } 509 510 void TextView::ShowSelection( const TextSelection& rRange ) 511 { 512 ImpShowHideSelection( sal_True, &rRange ); 513 } 514 515 void TextView::ImpShowHideSelection( sal_Bool bShow, const TextSelection* pRange ) 516 { 517 const TextSelection* pRangeOrSelection = pRange ? pRange : &mpImpl->maSelection; 518 519 if ( pRangeOrSelection->HasRange() ) 520 { 521 if ( mpImpl->mbHighlightSelection ) 522 { 523 ImpHighlight( *pRangeOrSelection ); 524 } 525 else 526 { 527 if( mpImpl->mpWindow->IsPaintTransparent() ) 528 mpImpl->mpWindow->Invalidate(); 529 else 530 { 531 Rectangle aOutArea( Point( 0, 0 ), mpImpl->mpWindow->GetOutputSizePixel() ); 532 Point aStartPos( ImpGetOutputStartPos( mpImpl->maStartDocPos ) ); 533 TextSelection aRange( *pRangeOrSelection ); 534 aRange.Justify(); 535 sal_Bool bVisCursor = mpImpl->mpCursor->IsVisible(); 536 mpImpl->mpCursor->Hide(); 537 ImpPaint( mpImpl->mpWindow, aStartPos, &aOutArea, &aRange, bShow ? &mpImpl->maSelection : NULL ); 538 if ( bVisCursor ) 539 mpImpl->mpCursor->Show(); 540 } 541 } 542 } 543 } 544 545 VirtualDevice* TextView::GetVirtualDevice() 546 { 547 if ( !mpImpl->mpVirtDev ) 548 { 549 mpImpl->mpVirtDev = new VirtualDevice; 550 mpImpl->mpVirtDev->SetLineColor(); 551 } 552 return mpImpl->mpVirtDev; 553 } 554 555 void TextView::EraseVirtualDevice() 556 { 557 delete mpImpl->mpVirtDev; 558 mpImpl->mpVirtDev = 0; 559 } 560 561 sal_Bool TextView::KeyInput( const KeyEvent& rKeyEvent ) 562 { 563 sal_Bool bDone = sal_True; 564 sal_Bool bModified = sal_False; 565 sal_Bool bMoved = sal_False; 566 sal_Bool bEndKey = sal_False; // spezielle CursorPosition 567 sal_Bool bAllowIdle = sal_True; 568 569 // Um zu pruefen ob durch irgendeine Aktion mModified, das lokale 570 // bModified wird z.B. bei Cut/Paste nicht gesetzt, weil dort an anderen 571 // Stellen das updaten erfolgt. 572 sal_Bool bWasModified = mpImpl->mpTextEngine->IsModified(); 573 mpImpl->mpTextEngine->SetModified( sal_False ); 574 575 TextSelection aCurSel( mpImpl->maSelection ); 576 TextSelection aOldSel( aCurSel ); 577 578 sal_uInt16 nCode = rKeyEvent.GetKeyCode().GetCode(); 579 KeyFuncType eFunc = rKeyEvent.GetKeyCode().GetFunction(); 580 if ( eFunc != KEYFUNC_DONTKNOW ) 581 { 582 switch ( eFunc ) 583 { 584 case KEYFUNC_CUT: 585 { 586 if ( !mpImpl->mbReadOnly ) 587 Cut(); 588 } 589 break; 590 case KEYFUNC_COPY: 591 { 592 Copy(); 593 } 594 break; 595 case KEYFUNC_PASTE: 596 { 597 if ( !mpImpl->mbReadOnly ) 598 Paste(); 599 } 600 break; 601 case KEYFUNC_UNDO: 602 { 603 if ( !mpImpl->mbReadOnly ) 604 Undo(); 605 } 606 break; 607 case KEYFUNC_REDO: 608 { 609 if ( !mpImpl->mbReadOnly ) 610 Redo(); 611 } 612 break; 613 614 default: // wird dann evtl. unten bearbeitet. 615 eFunc = KEYFUNC_DONTKNOW; 616 } 617 } 618 if ( eFunc == KEYFUNC_DONTKNOW ) 619 { 620 switch ( nCode ) 621 { 622 case KEY_UP: 623 case KEY_DOWN: 624 case KEY_LEFT: 625 case KEY_RIGHT: 626 case KEY_HOME: 627 case KEY_END: 628 case KEY_PAGEUP: 629 case KEY_PAGEDOWN: 630 case com::sun::star::awt::Key::MOVE_WORD_FORWARD: 631 case com::sun::star::awt::Key::SELECT_WORD_FORWARD: 632 case com::sun::star::awt::Key::MOVE_WORD_BACKWARD: 633 case com::sun::star::awt::Key::SELECT_WORD_BACKWARD: 634 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE: 635 case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE: 636 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE: 637 case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE: 638 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH: 639 case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH: 640 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH: 641 case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH: 642 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT: 643 case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT: 644 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT: 645 case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT: 646 { 647 if ( ( !rKeyEvent.GetKeyCode().IsMod2() || ( nCode == KEY_LEFT ) || ( nCode == KEY_RIGHT ) ) 648 && !( rKeyEvent.GetKeyCode().IsMod1() && ( nCode == KEY_PAGEUP || nCode == KEY_PAGEDOWN ) ) ) 649 { 650 aCurSel = ImpMoveCursor( rKeyEvent ); 651 if ( aCurSel.HasRange() ) { 652 uno::Reference<datatransfer::clipboard::XClipboard> aSelection(GetWindow()->GetPrimarySelection()); 653 Copy( aSelection ); 654 } 655 bMoved = sal_True; 656 if ( nCode == KEY_END ) 657 bEndKey = sal_True; 658 } 659 else 660 bDone = sal_False; 661 } 662 break; 663 case KEY_BACKSPACE: 664 case KEY_DELETE: 665 case com::sun::star::awt::Key::DELETE_WORD_BACKWARD: 666 case com::sun::star::awt::Key::DELETE_WORD_FORWARD: 667 case com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_LINE: 668 case com::sun::star::awt::Key::DELETE_TO_END_OF_LINE: 669 { 670 if ( !mpImpl->mbReadOnly && !rKeyEvent.GetKeyCode().IsMod2() ) 671 { 672 sal_uInt8 nDel = ( nCode == KEY_DELETE ) ? DEL_RIGHT : DEL_LEFT; 673 sal_uInt8 nMode = rKeyEvent.GetKeyCode().IsMod1() ? DELMODE_RESTOFWORD : DELMODE_SIMPLE; 674 if ( ( nMode == DELMODE_RESTOFWORD ) && rKeyEvent.GetKeyCode().IsShift() ) 675 nMode = DELMODE_RESTOFCONTENT; 676 677 switch( nCode ) 678 { 679 case com::sun::star::awt::Key::DELETE_WORD_BACKWARD: 680 nDel = DEL_LEFT; 681 nMode = DELMODE_RESTOFWORD; 682 break; 683 case com::sun::star::awt::Key::DELETE_WORD_FORWARD: 684 nDel = DEL_RIGHT; 685 nMode = DELMODE_RESTOFWORD; 686 break; 687 case com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_LINE: 688 nDel = DEL_LEFT; 689 nMode = DELMODE_RESTOFCONTENT; 690 break; 691 case com::sun::star::awt::Key::DELETE_TO_END_OF_LINE: 692 nDel = DEL_RIGHT; 693 nMode = DELMODE_RESTOFCONTENT; 694 break; 695 default: break; 696 } 697 698 mpImpl->mpTextEngine->UndoActionStart(); 699 if(mpImpl->mbSupportProtectAttribute) 700 { 701 //expand selection to include all protected content - if there is any 702 const TextCharAttrib* pStartAttr = mpImpl->mpTextEngine->FindCharAttrib( 703 TextPaM(mpImpl->maSelection.GetStart().GetPara(), 704 mpImpl->maSelection.GetStart().GetIndex()), 705 TEXTATTR_PROTECTED ); 706 const TextCharAttrib* pEndAttr = mpImpl->mpTextEngine->FindCharAttrib( 707 TextPaM(mpImpl->maSelection.GetEnd().GetPara(), 708 mpImpl->maSelection.GetEnd().GetIndex()), 709 TEXTATTR_PROTECTED ); 710 if(pStartAttr && pStartAttr->GetStart() < mpImpl->maSelection.GetStart().GetIndex()) 711 { 712 mpImpl->maSelection.GetStart().GetIndex() = pStartAttr->GetStart(); 713 } 714 if(pEndAttr && pEndAttr->GetEnd() > mpImpl->maSelection.GetEnd().GetIndex()) 715 { 716 mpImpl->maSelection.GetEnd().GetIndex() = pEndAttr->GetEnd(); 717 } 718 } 719 aCurSel = ImpDelete( nDel, nMode ); 720 mpImpl->mpTextEngine->UndoActionEnd(); 721 bModified = sal_True; 722 bAllowIdle = sal_False; 723 } 724 else 725 bDone = sal_False; 726 } 727 break; 728 case KEY_TAB: 729 { 730 if ( !mpImpl->mbReadOnly && !rKeyEvent.GetKeyCode().IsShift() && 731 !rKeyEvent.GetKeyCode().IsMod1() && !rKeyEvent.GetKeyCode().IsMod2() && 732 ImplCheckTextLen( 'x' ) ) 733 { 734 aCurSel = mpImpl->mpTextEngine->ImpInsertText( aCurSel, '\t', !IsInsertMode() ); 735 bModified = sal_True; 736 } 737 else 738 bDone = sal_False; 739 } 740 break; 741 case KEY_RETURN: 742 { 743 // Shift-RETURN darf nicht geschluckt werden, weil dann keine 744 // mehrzeilige Eingabe in Dialogen/Property-Editor moeglich. 745 if ( !mpImpl->mbReadOnly && !rKeyEvent.GetKeyCode().IsMod1() && 746 !rKeyEvent.GetKeyCode().IsMod2() && ImplCheckTextLen( 'x' ) ) 747 { 748 mpImpl->mpTextEngine->UndoActionStart(); 749 aCurSel = mpImpl->mpTextEngine->ImpInsertParaBreak( aCurSel ); 750 if ( mpImpl->mbAutoIndent ) 751 { 752 TextNode* pPrev = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aCurSel.GetEnd().GetPara() - 1 ); 753 sal_uInt16 n = 0; 754 while ( ( n < pPrev->GetText().Len() ) && ( 755 ( pPrev->GetText().GetChar( n ) == ' ' ) || 756 ( pPrev->GetText().GetChar( n ) == '\t' ) ) ) 757 { 758 n++; 759 } 760 if ( n ) 761 aCurSel = mpImpl->mpTextEngine->ImpInsertText( aCurSel, pPrev->GetText().Copy( 0, n ) ); 762 } 763 mpImpl->mpTextEngine->UndoActionEnd(); 764 bModified = sal_True; 765 } 766 else 767 bDone = sal_False; 768 } 769 break; 770 case KEY_INSERT: 771 { 772 if ( !mpImpl->mbReadOnly ) 773 SetInsertMode( !IsInsertMode() ); 774 } 775 break; 776 default: 777 { 778 if ( TextEngine::IsSimpleCharInput( rKeyEvent ) ) 779 { 780 xub_Unicode nCharCode = rKeyEvent.GetCharCode(); 781 if ( !mpImpl->mbReadOnly && ImplCheckTextLen( nCharCode ) ) // sonst trotzdem das Zeichen schlucken... 782 { 783 aCurSel = mpImpl->mpTextEngine->ImpInsertText( nCharCode, aCurSel, !IsInsertMode(), sal_True ); 784 bModified = sal_True; 785 } 786 } 787 else 788 bDone = sal_False; 789 } 790 } 791 } 792 793 if ( aCurSel != aOldSel ) // Check if changed, maybe other method already changed mpImpl->maSelection, don't overwrite that! 794 ImpSetSelection( aCurSel ); 795 796 mpImpl->mpTextEngine->UpdateSelections(); 797 798 if ( ( nCode != KEY_UP ) && ( nCode != KEY_DOWN ) ) 799 mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW; 800 801 if ( bModified ) 802 { 803 // Idle-Formatter nur, wenn AnyInput. 804 if ( bAllowIdle && Application::AnyInput( INPUT_KEYBOARD) ) 805 mpImpl->mpTextEngine->IdleFormatAndUpdate( this ); 806 else 807 mpImpl->mpTextEngine->FormatAndUpdate( this); 808 } 809 else if ( bMoved ) 810 { 811 // Selection wird jetzt gezielt in ImpMoveCursor gemalt. 812 ImpShowCursor( mpImpl->mbAutoScroll, sal_True, bEndKey ); 813 } 814 815 if ( mpImpl->mpTextEngine->IsModified() ) 816 mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) ); 817 else if ( bWasModified ) 818 mpImpl->mpTextEngine->SetModified( sal_True ); 819 820 return bDone; 821 } 822 823 void TextView::MouseButtonUp( const MouseEvent& rMouseEvent ) 824 { 825 mpImpl->mbClickedInSelection = sal_False; 826 mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW; 827 mpImpl->mpSelEngine->SelMouseButtonUp( rMouseEvent ); 828 if ( rMouseEvent.IsMiddle() && !IsReadOnly() && 829 ( GetWindow()->GetSettings().GetMouseSettings().GetMiddleButtonAction() == MOUSE_MIDDLE_PASTESELECTION ) ) 830 { 831 uno::Reference<datatransfer::clipboard::XClipboard> aSelection(GetWindow()->GetPrimarySelection()); 832 Paste( aSelection ); 833 if ( mpImpl->mpTextEngine->IsModified() ) 834 mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) ); 835 } 836 else if ( rMouseEvent.IsLeft() && GetSelection().HasRange() ) 837 { 838 uno::Reference<datatransfer::clipboard::XClipboard> aSelection(GetWindow()->GetPrimarySelection()); 839 Copy( aSelection ); 840 } 841 } 842 843 void TextView::MouseButtonDown( const MouseEvent& rMouseEvent ) 844 { 845 mpImpl->mpTextEngine->CheckIdleFormatter(); // Falls schnelles Tippen und MouseButtonDown 846 mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW; 847 mpImpl->mbClickedInSelection = IsSelectionAtPoint( rMouseEvent.GetPosPixel() ); 848 849 mpImpl->mpTextEngine->SetActiveView( this ); 850 851 mpImpl->mpSelEngine->SelMouseButtonDown( rMouseEvent ); 852 853 // mbu 20.01.2005 - SelMouseButtonDown() possibly triggers a 'selection changed' 854 // notification. The appropriate handler could change the current selection, 855 // which is the case in the MailMerge address block control. To enable select'n'drag 856 // we need to reevaluate the selection after the notification has been fired. 857 mpImpl->mbClickedInSelection = IsSelectionAtPoint( rMouseEvent.GetPosPixel() ); 858 859 // Sonderbehandlungen 860 if ( !rMouseEvent.IsShift() && ( rMouseEvent.GetClicks() >= 2 ) ) 861 { 862 if ( rMouseEvent.IsMod2() ) 863 { 864 HideSelection(); 865 ImpSetSelection( mpImpl->maSelection.GetEnd() ); 866 SetCursorAtPoint( rMouseEvent.GetPosPixel() ); // Wird von SelectionEngine bei MOD2 nicht gesetzt 867 } 868 869 if ( rMouseEvent.GetClicks() == 2 ) 870 { 871 // Wort selektieren 872 if ( mpImpl->maSelection.GetEnd().GetIndex() < mpImpl->mpTextEngine->GetTextLen( mpImpl->maSelection.GetEnd().GetPara() ) ) 873 { 874 HideSelection(); 875 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( mpImpl->maSelection.GetEnd().GetPara() ); 876 uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator(); 877 i18n::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), mpImpl->maSelection.GetEnd().GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True ); 878 TextSelection aNewSel( mpImpl->maSelection ); 879 aNewSel.GetStart().GetIndex() = (sal_uInt16)aBoundary.startPos; 880 aNewSel.GetEnd().GetIndex() = (sal_uInt16)aBoundary.endPos; 881 if(mpImpl->mbSupportProtectAttribute) 882 { 883 //expand selection to include all protected content - if there is any 884 const TextCharAttrib* pStartAttr = mpImpl->mpTextEngine->FindCharAttrib( 885 TextPaM(aNewSel.GetStart().GetPara(), 886 (sal_uInt16)aBoundary.startPos), 887 TEXTATTR_PROTECTED ); 888 const TextCharAttrib* pEndAttr = mpImpl->mpTextEngine->FindCharAttrib( 889 TextPaM(aNewSel.GetEnd().GetPara(), 890 (sal_uInt16)aBoundary.endPos), 891 TEXTATTR_PROTECTED ); 892 if(pStartAttr && pStartAttr->GetStart() < aNewSel.GetStart().GetIndex()) 893 { 894 aNewSel.GetStart().GetIndex() = pStartAttr->GetStart(); 895 } 896 if(pEndAttr && pEndAttr->GetEnd() > aNewSel.GetEnd().GetIndex()) 897 { 898 aNewSel.GetEnd().GetIndex() = pEndAttr->GetEnd(); 899 } 900 } 901 ImpSetSelection( aNewSel ); 902 ShowSelection(); 903 ShowCursor( sal_True, sal_True ); 904 } 905 } 906 else if ( rMouseEvent.GetClicks() == 3 ) 907 { 908 // Absatz selektieren 909 if ( mpImpl->maSelection.GetStart().GetIndex() || ( mpImpl->maSelection.GetEnd().GetIndex() < mpImpl->mpTextEngine->GetTextLen( mpImpl->maSelection.GetEnd().GetPara() ) ) ) 910 { 911 HideSelection(); 912 TextSelection aNewSel( mpImpl->maSelection ); 913 aNewSel.GetStart().GetIndex() = 0; 914 aNewSel.GetEnd().GetIndex() = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( mpImpl->maSelection.GetEnd().GetPara() )->GetText().Len(); 915 ImpSetSelection( aNewSel ); 916 ShowSelection(); 917 ShowCursor( sal_True, sal_True ); 918 } 919 } 920 } 921 } 922 923 924 void TextView::MouseMove( const MouseEvent& rMouseEvent ) 925 { 926 mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW; 927 mpImpl->mpSelEngine->SelMouseMove( rMouseEvent ); 928 } 929 930 void TextView::Command( const CommandEvent& rCEvt ) 931 { 932 mpImpl->mpTextEngine->CheckIdleFormatter(); // Falls schnelles Tippen und MouseButtonDown 933 mpImpl->mpTextEngine->SetActiveView( this ); 934 935 if ( rCEvt.GetCommand() == COMMAND_STARTEXTTEXTINPUT ) 936 { 937 DeleteSelected(); 938 delete mpImpl->mpTextEngine->mpIMEInfos; 939 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( GetSelection().GetEnd().GetPara() ); 940 mpImpl->mpTextEngine->mpIMEInfos = new TEIMEInfos( GetSelection().GetEnd(), pNode->GetText().Copy( GetSelection().GetEnd().GetIndex() ) ); 941 mpImpl->mpTextEngine->mpIMEInfos->bWasCursorOverwrite = !IsInsertMode(); 942 } 943 else if ( rCEvt.GetCommand() == COMMAND_ENDEXTTEXTINPUT ) 944 { 945 DBG_ASSERT( mpImpl->mpTextEngine->mpIMEInfos, "COMMAND_ENDEXTTEXTINPUT => Kein Start ?" ); 946 if( mpImpl->mpTextEngine->mpIMEInfos ) 947 { 948 TEParaPortion* pPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetPara() ); 949 pPortion->MarkSelectionInvalid( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetIndex(), 0 ); 950 951 sal_Bool bInsertMode = !mpImpl->mpTextEngine->mpIMEInfos->bWasCursorOverwrite; 952 953 delete mpImpl->mpTextEngine->mpIMEInfos; 954 mpImpl->mpTextEngine->mpIMEInfos = NULL; 955 956 mpImpl->mpTextEngine->FormatAndUpdate( this ); 957 958 SetInsertMode( bInsertMode ); 959 960 if ( mpImpl->mpTextEngine->IsModified() ) 961 mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) ); 962 } 963 } 964 else if ( rCEvt.GetCommand() == COMMAND_EXTTEXTINPUT ) 965 { 966 DBG_ASSERT( mpImpl->mpTextEngine->mpIMEInfos, "COMMAND_EXTTEXTINPUT => Kein Start ?" ); 967 if( mpImpl->mpTextEngine->mpIMEInfos ) 968 { 969 const CommandExtTextInputData* pData = rCEvt.GetExtTextInputData(); 970 971 if ( !pData->IsOnlyCursorChanged() ) 972 { 973 TextSelection aSelect( mpImpl->mpTextEngine->mpIMEInfos->aPos ); 974 aSelect.GetEnd().GetIndex() = aSelect.GetEnd().GetIndex() + mpImpl->mpTextEngine->mpIMEInfos->nLen; 975 aSelect = mpImpl->mpTextEngine->ImpDeleteText( aSelect ); 976 aSelect = mpImpl->mpTextEngine->ImpInsertText( aSelect, pData->GetText() ); 977 978 if ( mpImpl->mpTextEngine->mpIMEInfos->bWasCursorOverwrite ) 979 { 980 sal_uInt16 nOldIMETextLen = mpImpl->mpTextEngine->mpIMEInfos->nLen; 981 sal_uInt16 nNewIMETextLen = pData->GetText().Len(); 982 983 if ( ( nOldIMETextLen > nNewIMETextLen ) && 984 ( nNewIMETextLen < mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Len() ) ) 985 { 986 // restore old characters 987 sal_uInt16 nRestore = nOldIMETextLen - nNewIMETextLen; 988 TextPaM aPaM( mpImpl->mpTextEngine->mpIMEInfos->aPos ); 989 aPaM.GetIndex() = aPaM.GetIndex() + nNewIMETextLen; 990 mpImpl->mpTextEngine->ImpInsertText( aPaM, mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Copy( nNewIMETextLen, nRestore ) ); 991 } 992 else if ( ( nOldIMETextLen < nNewIMETextLen ) && 993 ( nOldIMETextLen < mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Len() ) ) 994 { 995 // overwrite 996 sal_uInt16 nOverwrite = nNewIMETextLen - nOldIMETextLen; 997 if ( ( nOldIMETextLen + nOverwrite ) > mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Len() ) 998 nOverwrite = mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Len() - nOldIMETextLen; 999 DBG_ASSERT( nOverwrite && (nOverwrite < 0xFF00), "IME Overwrite?!" ); 1000 TextPaM aPaM( mpImpl->mpTextEngine->mpIMEInfos->aPos ); 1001 aPaM.GetIndex() = aPaM.GetIndex() + nNewIMETextLen; 1002 TextSelection aSel( aPaM ); 1003 aSel.GetEnd().GetIndex() = 1004 aSel.GetEnd().GetIndex() + nOverwrite; 1005 mpImpl->mpTextEngine->ImpDeleteText( aSel ); 1006 } 1007 } 1008 1009 if ( pData->GetTextAttr() ) 1010 { 1011 mpImpl->mpTextEngine->mpIMEInfos->CopyAttribs( pData->GetTextAttr(), pData->GetText().Len() ); 1012 mpImpl->mpTextEngine->mpIMEInfos->bCursor = pData->IsCursorVisible(); 1013 } 1014 else 1015 { 1016 mpImpl->mpTextEngine->mpIMEInfos->DestroyAttribs(); 1017 } 1018 1019 TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetPara() ); 1020 pPPortion->MarkSelectionInvalid( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetIndex(), 0 ); 1021 mpImpl->mpTextEngine->FormatAndUpdate( this ); 1022 } 1023 1024 TextSelection aNewSel = TextPaM( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetPara(), mpImpl->mpTextEngine->mpIMEInfos->aPos.GetIndex()+pData->GetCursorPos() ); 1025 SetSelection( aNewSel ); 1026 SetInsertMode( !pData->IsCursorOverwrite() ); 1027 1028 if ( pData->IsCursorVisible() ) 1029 ShowCursor(); 1030 else 1031 HideCursor(); 1032 } 1033 } 1034 else if ( rCEvt.GetCommand() == COMMAND_CURSORPOS ) 1035 { 1036 if ( mpImpl->mpTextEngine->mpIMEInfos && mpImpl->mpTextEngine->mpIMEInfos->nLen ) 1037 { 1038 TextPaM aPaM( GetSelection().GetEnd() ); 1039 Rectangle aR1 = mpImpl->mpTextEngine->PaMtoEditCursor( aPaM ); 1040 1041 sal_uInt16 nInputEnd = mpImpl->mpTextEngine->mpIMEInfos->aPos.GetIndex() + mpImpl->mpTextEngine->mpIMEInfos->nLen; 1042 1043 if ( !mpImpl->mpTextEngine->IsFormatted() ) 1044 mpImpl->mpTextEngine->FormatDoc(); 1045 1046 TEParaPortion* pParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() ); 1047 sal_uInt16 nLine = pParaPortion->GetLineNumber( aPaM.GetIndex(), sal_True ); 1048 TextLine* pLine = pParaPortion->GetLines().GetObject( nLine ); 1049 if ( pLine && ( nInputEnd > pLine->GetEnd() ) ) 1050 nInputEnd = pLine->GetEnd(); 1051 Rectangle aR2 = mpImpl->mpTextEngine->PaMtoEditCursor( TextPaM( aPaM.GetPara(), nInputEnd ) ); 1052 1053 long nWidth = aR2.Left()-aR1.Right(); 1054 aR1.Move( -GetStartDocPos().X(), -GetStartDocPos().Y() ); 1055 GetWindow()->SetCursorRect( &aR1, nWidth ); 1056 } 1057 else 1058 { 1059 GetWindow()->SetCursorRect(); 1060 } 1061 } 1062 else 1063 { 1064 mpImpl->mpSelEngine->Command( rCEvt ); 1065 } 1066 } 1067 1068 void TextView::ShowCursor( sal_Bool bGotoCursor, sal_Bool bForceVisCursor ) 1069 { 1070 // Die Einstellung hat mehr Gewicht: 1071 if ( !mpImpl->mbAutoScroll ) 1072 bGotoCursor = sal_False; 1073 ImpShowCursor( bGotoCursor, bForceVisCursor, sal_False ); 1074 } 1075 1076 void TextView::HideCursor() 1077 { 1078 mpImpl->mpCursor->Hide(); 1079 } 1080 1081 void TextView::Scroll( long ndX, long ndY ) 1082 { 1083 DBG_ASSERT( mpImpl->mpTextEngine->IsFormatted(), "Scroll: Nicht formatiert!" ); 1084 1085 if ( !ndX && !ndY ) 1086 return; 1087 1088 Point aNewStartPos( mpImpl->maStartDocPos ); 1089 1090 // Vertical: 1091 aNewStartPos.Y() -= ndY; 1092 if ( aNewStartPos.Y() < 0 ) 1093 aNewStartPos.Y() = 0; 1094 1095 // Horizontal: 1096 aNewStartPos.X() -= ndX; 1097 if ( aNewStartPos.X() < 0 ) 1098 aNewStartPos.X() = 0; 1099 1100 long nDiffX = mpImpl->maStartDocPos.X() - aNewStartPos.X(); 1101 long nDiffY = mpImpl->maStartDocPos.Y() - aNewStartPos.Y(); 1102 1103 if ( nDiffX || nDiffY ) 1104 { 1105 sal_Bool bVisCursor = mpImpl->mpCursor->IsVisible(); 1106 mpImpl->mpCursor->Hide(); 1107 mpImpl->mpWindow->Update(); 1108 mpImpl->maStartDocPos = aNewStartPos; 1109 1110 if ( mpImpl->mpTextEngine->IsRightToLeft() ) 1111 nDiffX = -nDiffX; 1112 mpImpl->mpWindow->Scroll( nDiffX, nDiffY ); 1113 mpImpl->mpWindow->Update(); 1114 mpImpl->mpCursor->SetPos( mpImpl->mpCursor->GetPos() + Point( nDiffX, nDiffY ) ); 1115 if ( bVisCursor && !mpImpl->mbReadOnly ) 1116 mpImpl->mpCursor->Show(); 1117 } 1118 1119 mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_VIEWSCROLLED ) ); 1120 } 1121 1122 void TextView::Undo() 1123 { 1124 mpImpl->mpTextEngine->SetActiveView( this ); 1125 mpImpl->mpTextEngine->GetUndoManager().Undo(); 1126 } 1127 1128 void TextView::Redo() 1129 { 1130 mpImpl->mpTextEngine->SetActiveView( this ); 1131 mpImpl->mpTextEngine->GetUndoManager().Redo(); 1132 } 1133 1134 void TextView::Cut() 1135 { 1136 mpImpl->mpTextEngine->UndoActionStart(); 1137 Copy(); 1138 DeleteSelected(); 1139 mpImpl->mpTextEngine->UndoActionEnd(); 1140 } 1141 1142 void TextView::Copy( uno::Reference< datatransfer::clipboard::XClipboard >& rxClipboard ) 1143 { 1144 if ( rxClipboard.is() ) 1145 { 1146 TETextDataObject* pDataObj = new TETextDataObject( GetSelected() ); 1147 1148 if ( mpImpl->mpTextEngine->HasAttrib( TEXTATTR_HYPERLINK ) ) // Dann auch als HTML 1149 mpImpl->mpTextEngine->Write( pDataObj->GetHTMLStream(), &mpImpl->maSelection, sal_True ); 1150 1151 const sal_uInt32 nRef = Application::ReleaseSolarMutex(); 1152 1153 try 1154 { 1155 rxClipboard->setContents( pDataObj, NULL ); 1156 1157 uno::Reference< datatransfer::clipboard::XFlushableClipboard > xFlushableClipboard( rxClipboard, uno::UNO_QUERY ); 1158 if( xFlushableClipboard.is() ) 1159 xFlushableClipboard->flushClipboard(); 1160 } 1161 catch( const ::com::sun::star::uno::Exception& ) 1162 { 1163 } 1164 1165 Application::AcquireSolarMutex( nRef ); 1166 } 1167 } 1168 1169 void TextView::Copy() 1170 { 1171 uno::Reference<datatransfer::clipboard::XClipboard> aClipboard(GetWindow()->GetClipboard()); 1172 Copy( aClipboard ); 1173 } 1174 1175 void TextView::Paste( uno::Reference< datatransfer::clipboard::XClipboard >& rxClipboard ) 1176 { 1177 if ( rxClipboard.is() ) 1178 { 1179 uno::Reference< datatransfer::XTransferable > xDataObj; 1180 1181 const sal_uInt32 nRef = Application::ReleaseSolarMutex(); 1182 1183 try 1184 { 1185 xDataObj = rxClipboard->getContents(); 1186 } 1187 catch( const ::com::sun::star::uno::Exception& ) 1188 { 1189 } 1190 1191 Application::AcquireSolarMutex( nRef ); 1192 1193 if ( xDataObj.is() ) 1194 { 1195 datatransfer::DataFlavor aFlavor; 1196 SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor ); 1197 if ( xDataObj->isDataFlavorSupported( aFlavor ) ) 1198 { 1199 try 1200 { 1201 uno::Any aData = xDataObj->getTransferData( aFlavor ); 1202 ::rtl::OUString aText; 1203 aData >>= aText; 1204 bool bWasTruncated = false; 1205 if( mpImpl->mpTextEngine->GetMaxTextLen() != 0 ) 1206 bWasTruncated = ImplTruncateNewText( aText ); 1207 InsertNewText( aText, sal_False ); 1208 mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) ); 1209 1210 if( bWasTruncated ) 1211 Edit::ShowTruncationWarning( mpImpl->mpWindow ); 1212 } 1213 catch( const ::com::sun::star::datatransfer::UnsupportedFlavorException& ) 1214 { 1215 } 1216 } 1217 } 1218 } 1219 } 1220 1221 void TextView::Paste() 1222 { 1223 uno::Reference<datatransfer::clipboard::XClipboard> aClipboard(GetWindow()->GetClipboard()); 1224 Paste( aClipboard ); 1225 } 1226 1227 String TextView::GetSelected() 1228 { 1229 return GetSelected( GetSystemLineEnd() ); 1230 } 1231 1232 String TextView::GetSelected( LineEnd aSeparator ) 1233 { 1234 return mpImpl->mpTextEngine->GetText( mpImpl->maSelection, aSeparator ); 1235 } 1236 1237 void TextView::SetInsertMode( sal_Bool bInsert ) 1238 { 1239 if ( mpImpl->mbInsertMode != bInsert ) 1240 { 1241 mpImpl->mbInsertMode = bInsert; 1242 ShowCursor( mpImpl->mbAutoScroll, sal_False ); 1243 } 1244 } 1245 1246 void TextView::SetReadOnly( sal_Bool bReadOnly ) 1247 { 1248 if ( mpImpl->mbReadOnly != bReadOnly ) 1249 { 1250 mpImpl->mbReadOnly = bReadOnly; 1251 if ( !mpImpl->mbReadOnly ) 1252 ShowCursor( mpImpl->mbAutoScroll, sal_False ); 1253 else 1254 HideCursor(); 1255 1256 GetWindow()->SetInputContext( InputContext( mpImpl->mpTextEngine->GetFont(), bReadOnly ? INPUTCONTEXT_TEXT|INPUTCONTEXT_EXTTEXTINPUT : 0 ) ); 1257 } 1258 } 1259 1260 TextSelection TextView::ImpMoveCursor( const KeyEvent& rKeyEvent ) 1261 { 1262 // Eigentlich nur bei Up/Down noetig, aber was solls. 1263 mpImpl->mpTextEngine->CheckIdleFormatter(); 1264 1265 TextPaM aPaM( mpImpl->maSelection.GetEnd() ); 1266 TextPaM aOldEnd( aPaM ); 1267 1268 TextDirectionality eTextDirection = TextDirectionality_LeftToRight_TopToBottom; 1269 if ( mpImpl->mpTextEngine->IsRightToLeft() ) 1270 eTextDirection = TextDirectionality_RightToLeft_TopToBottom; 1271 1272 KeyEvent aTranslatedKeyEvent = rKeyEvent.LogicalTextDirectionality( eTextDirection ); 1273 1274 sal_Bool bCtrl = aTranslatedKeyEvent.GetKeyCode().IsMod1() ? sal_True : sal_False; 1275 sal_uInt16 nCode = aTranslatedKeyEvent.GetKeyCode().GetCode(); 1276 1277 bool bSelect = aTranslatedKeyEvent.GetKeyCode().IsShift(); 1278 switch ( nCode ) 1279 { 1280 case KEY_UP: aPaM = CursorUp( aPaM ); 1281 break; 1282 case KEY_DOWN: aPaM = CursorDown( aPaM ); 1283 break; 1284 case KEY_HOME: aPaM = bCtrl ? CursorStartOfDoc() : CursorStartOfLine( aPaM ); 1285 break; 1286 case KEY_END: aPaM = bCtrl ? CursorEndOfDoc() : CursorEndOfLine( aPaM ); 1287 break; 1288 case KEY_PAGEUP: aPaM = bCtrl ? CursorStartOfDoc() : PageUp( aPaM ); 1289 break; 1290 case KEY_PAGEDOWN: aPaM = bCtrl ? CursorEndOfDoc() : PageDown( aPaM ); 1291 break; 1292 case KEY_LEFT: aPaM = bCtrl ? CursorWordLeft( aPaM ) : CursorLeft( aPaM, aTranslatedKeyEvent.GetKeyCode().IsMod2() ? (sal_uInt16)i18n::CharacterIteratorMode::SKIPCHARACTER : (sal_uInt16)i18n::CharacterIteratorMode::SKIPCELL ); 1293 break; 1294 case KEY_RIGHT: aPaM = bCtrl ? CursorWordRight( aPaM ) : CursorRight( aPaM, aTranslatedKeyEvent.GetKeyCode().IsMod2() ? (sal_uInt16)i18n::CharacterIteratorMode::SKIPCHARACTER : (sal_uInt16)i18n::CharacterIteratorMode::SKIPCELL ); 1295 break; 1296 case com::sun::star::awt::Key::SELECT_WORD_FORWARD: 1297 bSelect = true; // fallthrough intentional 1298 case com::sun::star::awt::Key::MOVE_WORD_FORWARD: 1299 aPaM = CursorWordRight( aPaM ); 1300 break; 1301 case com::sun::star::awt::Key::SELECT_WORD_BACKWARD: 1302 bSelect = true; // fallthrough intentional 1303 case com::sun::star::awt::Key::MOVE_WORD_BACKWARD: 1304 aPaM = CursorWordLeft( aPaM ); 1305 break; 1306 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE: 1307 bSelect = true; // fallthrough intentional 1308 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE: 1309 aPaM = CursorStartOfLine( aPaM ); 1310 break; 1311 case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE: 1312 bSelect = true; // fallthrough intentional 1313 case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE: 1314 aPaM = CursorEndOfLine( aPaM ); 1315 break; 1316 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH: 1317 bSelect = true; // falltthrough intentional 1318 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH: 1319 aPaM = CursorStartOfParagraph( aPaM ); 1320 break; 1321 case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH: 1322 bSelect = true; // falltthrough intentional 1323 case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH: 1324 aPaM = CursorEndOfParagraph( aPaM ); 1325 break; 1326 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT: 1327 bSelect = true; // falltthrough intentional 1328 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT: 1329 aPaM = CursorStartOfDoc(); 1330 break; 1331 case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT: 1332 bSelect = true; // falltthrough intentional 1333 case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT: 1334 aPaM = CursorEndOfDoc(); 1335 break; 1336 } 1337 1338 // Bewirkt evtl. ein CreateAnchor oder Deselection all 1339 mpImpl->mpSelEngine->CursorPosChanging( bSelect, aTranslatedKeyEvent.GetKeyCode().IsMod1() ); 1340 1341 if ( aOldEnd != aPaM ) 1342 { 1343 mpImpl->mpTextEngine->CursorMoved( aOldEnd.GetPara() ); 1344 1345 1346 TextSelection aOldSelection( mpImpl->maSelection ); 1347 TextSelection aNewSelection( mpImpl->maSelection ); 1348 aNewSelection.GetEnd() = aPaM; 1349 if ( bSelect ) 1350 { 1351 // Dann wird die Selektion erweitert... 1352 ImpSetSelection( aNewSelection ); 1353 ShowSelection( TextSelection( aOldEnd, aPaM ) ); 1354 } 1355 else 1356 { 1357 aNewSelection.GetStart() = aPaM; 1358 ImpSetSelection( aNewSelection ); 1359 } 1360 } 1361 1362 return mpImpl->maSelection; 1363 } 1364 1365 void TextView::InsertText( const XubString& rStr, sal_Bool bSelect ) 1366 { 1367 InsertNewText( rStr, bSelect ); 1368 } 1369 1370 void TextView::InsertNewText( const rtl::OUString& rStr, sal_Bool bSelect ) 1371 { 1372 // HideSelection(); 1373 mpImpl->mpTextEngine->UndoActionStart(); 1374 1375 /* #i87633# 1376 break inserted text into chunks that fit into the underlying String 1377 based API (which has a maximum length of 65534 elements 1378 1379 note: this will of course still cause problems for lines longer than those 1380 65534 elements, but those cases will hopefully be few. 1381 In the long run someone should switch the TextEngine to OUString instead of String 1382 */ 1383 sal_Int32 nLen = rStr.getLength(); 1384 sal_Int32 nPos = 0; 1385 while( nLen ) 1386 { 1387 sal_Int32 nChunkLen = nLen > 65534 ? 65534 : nLen; 1388 String aChunk( rStr.copy( nPos, nChunkLen ) ); 1389 1390 TextSelection aNewSel( mpImpl->maSelection ); 1391 1392 TextPaM aPaM = mpImpl->mpTextEngine->ImpInsertText( mpImpl->maSelection, aChunk ); 1393 1394 if ( bSelect ) 1395 { 1396 aNewSel.Justify(); 1397 aNewSel.GetEnd() = aPaM; 1398 } 1399 else 1400 { 1401 aNewSel = aPaM; 1402 } 1403 1404 ImpSetSelection( aNewSel ); 1405 nLen -= nChunkLen; 1406 nPos += nChunkLen; 1407 } 1408 mpImpl->mpTextEngine->UndoActionEnd(); 1409 1410 mpImpl->mpTextEngine->FormatAndUpdate( this ); 1411 } 1412 1413 /* 1414 void TextView::InsertText( const XubString& rStr, sal_Bool bSelect ) 1415 { 1416 // HideSelection(); 1417 1418 TextSelection aNewSel( mpImpl->maSelection ); 1419 1420 mpImpl->mpTextEngine->UndoActionStart(); 1421 TextPaM aPaM = mpImpl->mpTextEngine->ImpInsertText( mpImpl->maSelection, rStr ); 1422 mpImpl->mpTextEngine->UndoActionEnd(); 1423 1424 if ( bSelect ) 1425 { 1426 aNewSel.Justify(); 1427 aNewSel.GetEnd() = aPaM; 1428 } 1429 else 1430 { 1431 aNewSel = aPaM; 1432 } 1433 1434 ImpSetSelection( aNewSel ); 1435 1436 mpImpl->mpTextEngine->FormatAndUpdate( this ); 1437 } 1438 */ 1439 1440 // OLD 1441 TextPaM TextView::CursorLeft( const TextPaM& rPaM, sal_Bool bWordMode ) 1442 { 1443 return bWordMode ? CursorWordLeft( rPaM ) : CursorLeft( rPaM, (sal_uInt16)i18n::CharacterIteratorMode::SKIPCELL ); 1444 1445 // Remove (sal_uInt16) typecasts in this file when removing this method! 1446 } 1447 1448 // OLD 1449 TextPaM TextView::CursorRight( const TextPaM& rPaM, sal_Bool bWordMode ) 1450 { 1451 return bWordMode ? CursorWordRight( rPaM ) : CursorRight( rPaM, (sal_uInt16)i18n::CharacterIteratorMode::SKIPCELL ); 1452 1453 // Remove (sal_uInt16) typecasts in this file when removing this method! 1454 } 1455 1456 TextPaM TextView::CursorLeft( const TextPaM& rPaM, sal_uInt16 nCharacterIteratorMode ) 1457 { 1458 TextPaM aPaM( rPaM ); 1459 1460 if ( aPaM.GetIndex() ) 1461 { 1462 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() ); 1463 uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator(); 1464 sal_Int32 nCount = 1; 1465 aPaM.GetIndex() = (sal_uInt16)xBI->previousCharacters( pNode->GetText(), aPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), nCharacterIteratorMode, nCount, nCount ); 1466 } 1467 else if ( aPaM.GetPara() ) 1468 { 1469 aPaM.GetPara()--; 1470 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() ); 1471 aPaM.GetIndex() = pNode->GetText().Len(); 1472 } 1473 return aPaM; 1474 } 1475 1476 TextPaM TextView::CursorRight( const TextPaM& rPaM, sal_uInt16 nCharacterIteratorMode ) 1477 { 1478 TextPaM aPaM( rPaM ); 1479 1480 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() ); 1481 if ( aPaM.GetIndex() < pNode->GetText().Len() ) 1482 { 1483 uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator(); 1484 sal_Int32 nCount = 1; 1485 aPaM.GetIndex() = (sal_uInt16)xBI->nextCharacters( pNode->GetText(), aPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), nCharacterIteratorMode, nCount, nCount ); 1486 } 1487 else if ( aPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().Count()-1) ) 1488 { 1489 aPaM.GetPara()++; 1490 aPaM.GetIndex() = 0; 1491 } 1492 1493 return aPaM; 1494 } 1495 1496 1497 TextPaM TextView::CursorWordLeft( const TextPaM& rPaM ) 1498 { 1499 TextPaM aPaM( rPaM ); 1500 1501 if ( aPaM.GetIndex() ) 1502 { 1503 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() ); 1504 uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator(); 1505 i18n::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), rPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True ); 1506 if ( aBoundary.startPos >= rPaM.GetIndex() ) 1507 aBoundary = xBI->previousWord( pNode->GetText(), rPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES ); 1508 aPaM.GetIndex() = ( aBoundary.startPos != -1 ) ? (sal_uInt16)aBoundary.startPos : 0; 1509 } 1510 else if ( aPaM.GetPara() ) 1511 { 1512 aPaM.GetPara()--; 1513 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() ); 1514 aPaM.GetIndex() = pNode->GetText().Len(); 1515 } 1516 return aPaM; 1517 } 1518 1519 1520 TextPaM TextView::CursorWordRight( const TextPaM& rPaM ) 1521 { 1522 TextPaM aPaM( rPaM ); 1523 1524 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() ); 1525 if ( aPaM.GetIndex() < pNode->GetText().Len() ) 1526 { 1527 uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator(); 1528 i18n::Boundary aBoundary = xBI->nextWord( pNode->GetText(), aPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES ); 1529 aPaM.GetIndex() = (sal_uInt16)aBoundary.startPos; 1530 } 1531 else if ( aPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().Count()-1) ) 1532 { 1533 aPaM.GetPara()++; 1534 aPaM.GetIndex() = 0; 1535 } 1536 1537 return aPaM; 1538 } 1539 1540 TextPaM TextView::ImpDelete( sal_uInt8 nMode, sal_uInt8 nDelMode ) 1541 { 1542 if ( mpImpl->maSelection.HasRange() ) // dann nur Sel. loeschen 1543 return mpImpl->mpTextEngine->ImpDeleteText( mpImpl->maSelection ); 1544 1545 TextPaM aStartPaM = mpImpl->maSelection.GetStart(); 1546 TextPaM aEndPaM = aStartPaM; 1547 if ( nMode == DEL_LEFT ) 1548 { 1549 if ( nDelMode == DELMODE_SIMPLE ) 1550 { 1551 aEndPaM = CursorLeft( aEndPaM, (sal_uInt16)i18n::CharacterIteratorMode::SKIPCHARACTER ); 1552 } 1553 else if ( nDelMode == DELMODE_RESTOFWORD ) 1554 { 1555 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aEndPaM.GetPara() ); 1556 uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator(); 1557 i18n::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), mpImpl->maSelection.GetEnd().GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True ); 1558 if ( aBoundary.startPos == mpImpl->maSelection.GetEnd().GetIndex() ) 1559 aBoundary = xBI->previousWord( pNode->GetText(), mpImpl->maSelection.GetEnd().GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES ); 1560 // #i63506# startPos is -1 when the paragraph starts with a tab 1561 aEndPaM.GetIndex() = (aBoundary.startPos >= 0) ? (sal_uInt16)aBoundary.startPos : 0; 1562 } 1563 else // DELMODE_RESTOFCONTENT 1564 { 1565 if ( aEndPaM.GetIndex() != 0 ) 1566 aEndPaM.GetIndex() = 0; 1567 else if ( aEndPaM.GetPara() ) 1568 { 1569 // Absatz davor 1570 aEndPaM.GetPara()--; 1571 aEndPaM.GetIndex() = 0; 1572 } 1573 } 1574 } 1575 else 1576 { 1577 if ( nDelMode == DELMODE_SIMPLE ) 1578 { 1579 aEndPaM = CursorRight( aEndPaM, (sal_uInt16)i18n::CharacterIteratorMode::SKIPCELL ); 1580 } 1581 else if ( nDelMode == DELMODE_RESTOFWORD ) 1582 { 1583 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aEndPaM.GetPara() ); 1584 uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator(); 1585 i18n::Boundary aBoundary = xBI->nextWord( pNode->GetText(), mpImpl->maSelection.GetEnd().GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES ); 1586 aEndPaM.GetIndex() = (sal_uInt16)aBoundary.startPos; 1587 } 1588 else // DELMODE_RESTOFCONTENT 1589 { 1590 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aEndPaM.GetPara() ); 1591 if ( aEndPaM.GetIndex() < pNode->GetText().Len() ) 1592 aEndPaM.GetIndex() = pNode->GetText().Len(); 1593 else if ( aEndPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().Count() - 1 ) ) 1594 { 1595 // Absatz danach 1596 aEndPaM.GetPara()++; 1597 TextNode* pNextNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aEndPaM.GetPara() ); 1598 aEndPaM.GetIndex() = pNextNode->GetText().Len(); 1599 } 1600 } 1601 } 1602 1603 return mpImpl->mpTextEngine->ImpDeleteText( TextSelection( aStartPaM, aEndPaM ) ); 1604 } 1605 1606 1607 1608 TextPaM TextView::CursorUp( const TextPaM& rPaM ) 1609 { 1610 TextPaM aPaM( rPaM ); 1611 1612 long nX; 1613 if ( mpImpl->mnTravelXPos == TRAVEL_X_DONTKNOW ) 1614 { 1615 nX = mpImpl->mpTextEngine->GetEditCursor( rPaM, sal_False ).Left(); 1616 mpImpl->mnTravelXPos = (sal_uInt16)nX+1; 1617 } 1618 else 1619 nX = mpImpl->mnTravelXPos; 1620 1621 TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() ); 1622 sal_uInt16 nLine = pPPortion->GetLineNumber( rPaM.GetIndex(), sal_False ); 1623 if ( nLine ) // gleicher Absatz 1624 { 1625 sal_uInt16 nCharPos = mpImpl->mpTextEngine->GetCharPos( rPaM.GetPara(), nLine-1, nX ); 1626 aPaM.GetIndex() = nCharPos; 1627 // Wenn davor eine autom.Umgebrochene Zeile, und ich muss genau an das 1628 // Ende dieser Zeile, landet der Cursor in der aktuellen Zeile am Anfang 1629 // Siehe Problem: Letztes Zeichen einer autom.umgebr. Zeile = Cursor 1630 TextLine* pLine = pPPortion->GetLines().GetObject( nLine - 1 ); 1631 if ( aPaM.GetIndex() && ( aPaM.GetIndex() == pLine->GetEnd() ) ) 1632 aPaM.GetIndex()--; 1633 } 1634 else if ( rPaM.GetPara() ) // vorheriger Absatz 1635 { 1636 aPaM.GetPara()--; 1637 pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() ); 1638 sal_uInt16 nL = pPPortion->GetLines().Count() - 1; 1639 sal_uInt16 nCharPos = mpImpl->mpTextEngine->GetCharPos( aPaM.GetPara(), nL, nX+1 ); 1640 aPaM.GetIndex() = nCharPos; 1641 } 1642 1643 return aPaM; 1644 } 1645 1646 TextPaM TextView::CursorDown( const TextPaM& rPaM ) 1647 { 1648 TextPaM aPaM( rPaM ); 1649 1650 long nX; 1651 if ( mpImpl->mnTravelXPos == TRAVEL_X_DONTKNOW ) 1652 { 1653 nX = mpImpl->mpTextEngine->GetEditCursor( rPaM, sal_False ).Left(); 1654 mpImpl->mnTravelXPos = (sal_uInt16)nX+1; 1655 } 1656 else 1657 nX = mpImpl->mnTravelXPos; 1658 1659 TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() ); 1660 sal_uInt16 nLine = pPPortion->GetLineNumber( rPaM.GetIndex(), sal_False ); 1661 if ( nLine < ( pPPortion->GetLines().Count() - 1 ) ) 1662 { 1663 sal_uInt16 nCharPos = mpImpl->mpTextEngine->GetCharPos( rPaM.GetPara(), nLine+1, nX ); 1664 aPaM.GetIndex() = nCharPos; 1665 1666 // Sonderbehandlung siehe CursorUp... 1667 TextLine* pLine = pPPortion->GetLines().GetObject( nLine + 1 ); 1668 if ( ( aPaM.GetIndex() == pLine->GetEnd() ) && ( aPaM.GetIndex() > pLine->GetStart() ) && aPaM.GetIndex() < pPPortion->GetNode()->GetText().Len() ) 1669 aPaM.GetIndex()--; 1670 } 1671 else if ( rPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().Count() - 1 ) ) // naechster Absatz 1672 { 1673 aPaM.GetPara()++; 1674 pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() ); 1675 sal_uInt16 nCharPos = mpImpl->mpTextEngine->GetCharPos( aPaM.GetPara(), 0, nX+1 ); 1676 aPaM.GetIndex() = nCharPos; 1677 TextLine* pLine = pPPortion->GetLines().GetObject( 0 ); 1678 if ( ( aPaM.GetIndex() == pLine->GetEnd() ) && ( aPaM.GetIndex() > pLine->GetStart() ) && ( pPPortion->GetLines().Count() > 1 ) ) 1679 aPaM.GetIndex()--; 1680 } 1681 1682 return aPaM; 1683 } 1684 1685 TextPaM TextView::CursorStartOfLine( const TextPaM& rPaM ) 1686 { 1687 TextPaM aPaM( rPaM ); 1688 1689 TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() ); 1690 sal_uInt16 nLine = pPPortion->GetLineNumber( aPaM.GetIndex(), sal_False ); 1691 TextLine* pLine = pPPortion->GetLines().GetObject( nLine ); 1692 aPaM.GetIndex() = pLine->GetStart(); 1693 1694 return aPaM; 1695 } 1696 1697 TextPaM TextView::CursorEndOfLine( const TextPaM& rPaM ) 1698 { 1699 TextPaM aPaM( rPaM ); 1700 1701 TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() ); 1702 sal_uInt16 nLine = pPPortion->GetLineNumber( aPaM.GetIndex(), sal_False ); 1703 TextLine* pLine = pPPortion->GetLines().GetObject( nLine ); 1704 aPaM.GetIndex() = pLine->GetEnd(); 1705 1706 if ( pLine->GetEnd() > pLine->GetStart() ) // Leerzeile 1707 { 1708 xub_Unicode cLastChar = pPPortion->GetNode()->GetText().GetChar((sal_uInt16)(aPaM.GetIndex()-1) ); 1709 if ( ( cLastChar == ' ' ) && ( aPaM.GetIndex() != pPPortion->GetNode()->GetText().Len() ) ) 1710 { 1711 // Bei einem Blank in einer autom. umgebrochenen Zeile macht es Sinn, 1712 // davor zu stehen, da der Anwender hinter das Wort will. 1713 // Wenn diese geaendert wird, Sonderbehandlung fuer Pos1 nach End! 1714 aPaM.GetIndex()--; 1715 } 1716 } 1717 return aPaM; 1718 } 1719 1720 TextPaM TextView::CursorStartOfParagraph( const TextPaM& rPaM ) 1721 { 1722 TextPaM aPaM( rPaM ); 1723 aPaM.GetIndex() = 0; 1724 return aPaM; 1725 } 1726 1727 TextPaM TextView::CursorEndOfParagraph( const TextPaM& rPaM ) 1728 { 1729 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( rPaM.GetPara() ); 1730 TextPaM aPaM( rPaM ); 1731 aPaM.GetIndex() = pNode->GetText().Len(); 1732 return aPaM; 1733 } 1734 1735 TextPaM TextView::CursorStartOfDoc() 1736 { 1737 TextPaM aPaM( 0, 0 ); 1738 return aPaM; 1739 } 1740 1741 TextPaM TextView::CursorEndOfDoc() 1742 { 1743 sal_uLong nNode = mpImpl->mpTextEngine->mpDoc->GetNodes().Count() - 1; 1744 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( nNode ); 1745 TextPaM aPaM( nNode, pNode->GetText().Len() ); 1746 return aPaM; 1747 } 1748 1749 TextPaM TextView::PageUp( const TextPaM& rPaM ) 1750 { 1751 Rectangle aRec = mpImpl->mpTextEngine->PaMtoEditCursor( rPaM ); 1752 Point aTopLeft = aRec.TopLeft(); 1753 aTopLeft.Y() -= mpImpl->mpWindow->GetOutputSizePixel().Height() * 9/10; 1754 aTopLeft.X() += 1; 1755 if ( aTopLeft.Y() < 0 ) 1756 aTopLeft.Y() = 0; 1757 1758 TextPaM aPaM = mpImpl->mpTextEngine->GetPaM( aTopLeft ); 1759 return aPaM; 1760 } 1761 1762 TextPaM TextView::PageDown( const TextPaM& rPaM ) 1763 { 1764 Rectangle aRec = mpImpl->mpTextEngine->PaMtoEditCursor( rPaM ); 1765 Point aBottomRight = aRec.BottomRight(); 1766 aBottomRight.Y() += mpImpl->mpWindow->GetOutputSizePixel().Height() * 9/10; 1767 aBottomRight.X() += 1; 1768 long nHeight = mpImpl->mpTextEngine->GetTextHeight(); 1769 if ( aBottomRight.Y() > nHeight ) 1770 aBottomRight.Y() = nHeight-1; 1771 1772 TextPaM aPaM = mpImpl->mpTextEngine->GetPaM( aBottomRight ); 1773 return aPaM; 1774 } 1775 1776 void TextView::ImpShowCursor( sal_Bool bGotoCursor, sal_Bool bForceVisCursor, sal_Bool bSpecial ) 1777 { 1778 if ( mpImpl->mpTextEngine->IsFormatting() ) 1779 return; 1780 if ( mpImpl->mpTextEngine->GetUpdateMode() == sal_False ) 1781 return; 1782 if ( mpImpl->mpTextEngine->IsInUndo() ) 1783 return; 1784 1785 mpImpl->mpTextEngine->CheckIdleFormatter(); 1786 if ( !mpImpl->mpTextEngine->IsFormatted() ) 1787 mpImpl->mpTextEngine->FormatAndUpdate( this ); 1788 1789 1790 TextPaM aPaM( mpImpl->maSelection.GetEnd() ); 1791 Rectangle aEditCursor = mpImpl->mpTextEngine->PaMtoEditCursor( aPaM, bSpecial ); 1792 1793 // Remember that we placed the cursor behind the last character of a line 1794 mpImpl->mbCursorAtEndOfLine = false; 1795 if( bSpecial ) 1796 { 1797 TEParaPortion* pParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() ); 1798 mpImpl->mbCursorAtEndOfLine = 1799 pParaPortion->GetLineNumber( aPaM.GetIndex(), sal_True ) != pParaPortion->GetLineNumber( aPaM.GetIndex(), sal_False ); 1800 } 1801 1802 if ( !IsInsertMode() && !mpImpl->maSelection.HasRange() ) 1803 { 1804 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() ); 1805 if ( pNode->GetText().Len() && ( aPaM.GetIndex() < pNode->GetText().Len() ) ) 1806 { 1807 // If we are behind a portion, and the next portion has other direction, we must change position... 1808 aEditCursor.Left() = aEditCursor.Right() = mpImpl->mpTextEngine->GetEditCursor( aPaM, sal_False, sal_True ).Left(); 1809 1810 TEParaPortion* pParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() ); 1811 1812 sal_uInt16 nTextPortionStart = 0; 1813 sal_uInt16 nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nTextPortionStart, sal_True ); 1814 TETextPortion* pTextPortion = pParaPortion->GetTextPortions().GetObject( nTextPortion ); 1815 if ( pTextPortion->GetKind() == PORTIONKIND_TAB ) 1816 { 1817 if ( mpImpl->mpTextEngine->IsRightToLeft() ) 1818 { 1819 1820 } 1821 aEditCursor.Right() += pTextPortion->GetWidth(); 1822 } 1823 else 1824 { 1825 TextPaM aNext = CursorRight( TextPaM( aPaM.GetPara(), aPaM.GetIndex() ), (sal_uInt16)i18n::CharacterIteratorMode::SKIPCELL ); 1826 aEditCursor.Right() = mpImpl->mpTextEngine->GetEditCursor( aNext, sal_True ).Left(); 1827 } 1828 } 1829 } 1830 1831 Size aOutSz = mpImpl->mpWindow->GetOutputSizePixel(); 1832 if ( aEditCursor.GetHeight() > aOutSz.Height() ) 1833 aEditCursor.Bottom() = aEditCursor.Top() + aOutSz.Height() - 1; 1834 1835 aEditCursor.Left() -= 1; 1836 1837 if ( bGotoCursor 1838 // #i81283# protext maStartDocPos against initialization problems 1839 && aOutSz.Width() && aOutSz.Height() 1840 ) 1841 { 1842 long nVisStartY = mpImpl->maStartDocPos.Y(); 1843 long nVisEndY = mpImpl->maStartDocPos.Y() + aOutSz.Height(); 1844 long nVisStartX = mpImpl->maStartDocPos.X(); 1845 long nVisEndX = mpImpl->maStartDocPos.X() + aOutSz.Width(); 1846 long nMoreX = aOutSz.Width() / 4; 1847 1848 Point aNewStartPos( mpImpl->maStartDocPos ); 1849 1850 if ( aEditCursor.Bottom() > nVisEndY ) 1851 { 1852 aNewStartPos.Y() += ( aEditCursor.Bottom() - nVisEndY ); 1853 } 1854 else if ( aEditCursor.Top() < nVisStartY ) 1855 { 1856 aNewStartPos.Y() -= ( nVisStartY - aEditCursor.Top() ); 1857 } 1858 1859 if ( aEditCursor.Right() >= nVisEndX ) 1860 { 1861 aNewStartPos.X() += ( aEditCursor.Right() - nVisEndX ); 1862 1863 // Darfs ein bischen mehr sein? 1864 aNewStartPos.X() += nMoreX; 1865 } 1866 else if ( aEditCursor.Left() <= nVisStartX ) 1867 { 1868 aNewStartPos.X() -= ( nVisStartX - aEditCursor.Left() ); 1869 1870 // Darfs ein bischen mehr sein? 1871 aNewStartPos.X() -= nMoreX; 1872 } 1873 1874 // X kann durch das 'bischen mehr' falsch sein: 1875 // sal_uLong nMaxTextWidth = mpImpl->mpTextEngine->GetMaxTextWidth(); 1876 // if ( !nMaxTextWidth || ( nMaxTextWidth > 0x7FFFFFFF ) ) 1877 // nMaxTextWidth = 0x7FFFFFFF; 1878 // long nMaxX = (long)nMaxTextWidth - aOutSz.Width(); 1879 long nMaxX = mpImpl->mpTextEngine->CalcTextWidth() - aOutSz.Width(); 1880 if ( nMaxX < 0 ) 1881 nMaxX = 0; 1882 1883 if ( aNewStartPos.X() < 0 ) 1884 aNewStartPos.X() = 0; 1885 else if ( aNewStartPos.X() > nMaxX ) 1886 aNewStartPos.X() = nMaxX; 1887 1888 // Y sollte nicht weiter unten als noetig liegen: 1889 long nYMax = mpImpl->mpTextEngine->GetTextHeight() - aOutSz.Height(); 1890 if ( nYMax < 0 ) 1891 nYMax = 0; 1892 if ( aNewStartPos.Y() > nYMax ) 1893 aNewStartPos.Y() = nYMax; 1894 1895 if ( aNewStartPos != mpImpl->maStartDocPos ) 1896 Scroll( -(aNewStartPos.X() - mpImpl->maStartDocPos.X()), -(aNewStartPos.Y() - mpImpl->maStartDocPos.Y()) ); 1897 } 1898 1899 if ( aEditCursor.Right() < aEditCursor.Left() ) 1900 { 1901 long n = aEditCursor.Left(); 1902 aEditCursor.Left() = aEditCursor.Right(); 1903 aEditCursor.Right() = n; 1904 } 1905 1906 Point aPoint( GetWindowPos( !mpImpl->mpTextEngine->IsRightToLeft() ? aEditCursor.TopLeft() : aEditCursor.TopRight() ) ); 1907 mpImpl->mpCursor->SetPos( aPoint ); 1908 mpImpl->mpCursor->SetSize( aEditCursor.GetSize() ); 1909 if ( bForceVisCursor && mpImpl->mbCursorEnabled ) 1910 mpImpl->mpCursor->Show(); 1911 } 1912 1913 sal_Bool TextView::SetCursorAtPoint( const Point& rPosPixel ) 1914 { 1915 mpImpl->mpTextEngine->CheckIdleFormatter(); 1916 1917 Point aDocPos = GetDocPos( rPosPixel ); 1918 1919 TextPaM aPaM = mpImpl->mpTextEngine->GetPaM( aDocPos ); 1920 1921 // aTmpNewSel: Diff zwischen alt und neu, nicht die neue Selektion 1922 TextSelection aTmpNewSel( mpImpl->maSelection.GetEnd(), aPaM ); 1923 TextSelection aNewSel( mpImpl->maSelection ); 1924 aNewSel.GetEnd() = aPaM; 1925 1926 if ( !mpImpl->mpSelEngine->HasAnchor() ) 1927 { 1928 if ( mpImpl->maSelection.GetStart() != aPaM ) 1929 mpImpl->mpTextEngine->CursorMoved( mpImpl->maSelection.GetStart().GetPara() ); 1930 aNewSel.GetStart() = aPaM; 1931 ImpSetSelection( aNewSel ); 1932 } 1933 else 1934 { 1935 ImpSetSelection( aNewSel ); 1936 ShowSelection( aTmpNewSel ); 1937 } 1938 1939 sal_Bool bForceCursor = mpImpl->mpDDInfo ? sal_False : sal_True; // && !mbInSelection 1940 ImpShowCursor( mpImpl->mbAutoScroll, bForceCursor, sal_False ); 1941 return sal_True; 1942 } 1943 1944 sal_Bool TextView::IsSelectionAtPoint( const Point& rPosPixel ) 1945 { 1946 // if ( !Rectangle( Point(), mpImpl->mpWindow->GetOutputSizePixel() ).IsInside( rPosPixel ) && !mbInSelection ) 1947 // return sal_False; 1948 1949 Point aDocPos = GetDocPos( rPosPixel ); 1950 TextPaM aPaM = mpImpl->mpTextEngine->GetPaM( aDocPos, sal_False ); 1951 // Bei Hyperlinks D&D auch ohne Selektion starten. 1952 // BeginDrag wird aber nur gerufen, wenn IsSelectionAtPoint() 1953 // Problem: IsSelectionAtPoint wird bei Command() nicht gerufen, 1954 // wenn vorher im MBDown schon sal_False returnt wurde. 1955 return ( IsInSelection( aPaM ) || 1956 ( /* mpImpl->mpSelEngine->IsInCommand() && */ mpImpl->mpTextEngine->FindAttrib( aPaM, TEXTATTR_HYPERLINK ) ) ); 1957 } 1958 1959 sal_Bool TextView::IsInSelection( const TextPaM& rPaM ) 1960 { 1961 TextSelection aSel = mpImpl->maSelection; 1962 aSel.Justify(); 1963 1964 sal_uLong nStartNode = aSel.GetStart().GetPara(); 1965 sal_uLong nEndNode = aSel.GetEnd().GetPara(); 1966 sal_uLong nCurNode = rPaM.GetPara(); 1967 1968 if ( ( nCurNode > nStartNode ) && ( nCurNode < nEndNode ) ) 1969 return sal_True; 1970 1971 if ( nStartNode == nEndNode ) 1972 { 1973 if ( nCurNode == nStartNode ) 1974 if ( ( rPaM.GetIndex() >= aSel.GetStart().GetIndex() ) && ( rPaM.GetIndex() < aSel.GetEnd().GetIndex() ) ) 1975 return sal_True; 1976 } 1977 else if ( ( nCurNode == nStartNode ) && ( rPaM.GetIndex() >= aSel.GetStart().GetIndex() ) ) 1978 return sal_True; 1979 else if ( ( nCurNode == nEndNode ) && ( rPaM.GetIndex() < aSel.GetEnd().GetIndex() ) ) 1980 return sal_True; 1981 1982 return sal_False; 1983 } 1984 1985 void TextView::ImpHideDDCursor() 1986 { 1987 if ( mpImpl->mpDDInfo && mpImpl->mpDDInfo->mbVisCursor ) 1988 { 1989 mpImpl->mpDDInfo->maCursor.Hide(); 1990 mpImpl->mpDDInfo->mbVisCursor = sal_False; 1991 } 1992 } 1993 1994 void TextView::ImpShowDDCursor() 1995 { 1996 if ( !mpImpl->mpDDInfo->mbVisCursor ) 1997 { 1998 Rectangle aCursor = mpImpl->mpTextEngine->PaMtoEditCursor( mpImpl->mpDDInfo->maDropPos, sal_True ); 1999 aCursor.Right()++; 2000 aCursor.SetPos( GetWindowPos( aCursor.TopLeft() ) ); 2001 2002 mpImpl->mpDDInfo->maCursor.SetWindow( mpImpl->mpWindow ); 2003 mpImpl->mpDDInfo->maCursor.SetPos( aCursor.TopLeft() ); 2004 mpImpl->mpDDInfo->maCursor.SetSize( aCursor.GetSize() ); 2005 mpImpl->mpDDInfo->maCursor.Show(); 2006 mpImpl->mpDDInfo->mbVisCursor = sal_True; 2007 } 2008 } 2009 2010 void TextView::SetPaintSelection( sal_Bool bPaint ) 2011 { 2012 if ( bPaint != mpImpl->mbPaintSelection ) 2013 { 2014 mpImpl->mbPaintSelection = bPaint; 2015 ShowSelection( mpImpl->maSelection ); 2016 } 2017 } 2018 2019 void TextView::SetHighlightSelection( sal_Bool bSelectByHighlight ) 2020 { 2021 if ( bSelectByHighlight != mpImpl->mbHighlightSelection ) 2022 { 2023 // Falls umschalten zwischendurch moeglich... 2024 mpImpl->mbHighlightSelection = bSelectByHighlight; 2025 } 2026 } 2027 2028 sal_Bool TextView::Read( SvStream& rInput ) 2029 { 2030 sal_Bool bDone = mpImpl->mpTextEngine->Read( rInput, &mpImpl->maSelection ); 2031 ShowCursor(); 2032 return bDone; 2033 } 2034 2035 sal_Bool TextView::Write( SvStream& rOutput ) 2036 { 2037 return mpImpl->mpTextEngine->Read( rOutput, &mpImpl->maSelection ); 2038 } 2039 2040 bool TextView::ImplTruncateNewText( rtl::OUString& rNewText ) const 2041 { 2042 bool bTruncated = false; 2043 2044 if( rNewText.getLength() > 65534 ) // limit to String API 2045 { 2046 rNewText = rNewText.copy( 0, 65534 ); 2047 bTruncated = true; 2048 } 2049 2050 sal_uLong nMaxLen = mpImpl->mpTextEngine->GetMaxTextLen(); 2051 // 0 means unlimited, there is just the String API limit handled above 2052 if( nMaxLen != 0 ) 2053 { 2054 sal_uLong nCurLen = mpImpl->mpTextEngine->GetTextLen(); 2055 2056 sal_uInt32 nNewLen = rNewText.getLength(); 2057 if ( nCurLen + nNewLen > nMaxLen ) 2058 { 2059 // see how much text will be replaced 2060 sal_uLong nSelLen = mpImpl->mpTextEngine->GetTextLen( mpImpl->maSelection ); 2061 if ( nCurLen + nNewLen - nSelLen > nMaxLen ) 2062 { 2063 sal_uInt32 nTruncatedLen = static_cast<sal_uInt32>(nMaxLen - (nCurLen - nSelLen)); 2064 rNewText = rNewText.copy( 0, nTruncatedLen ); 2065 bTruncated = true; 2066 } 2067 } 2068 } 2069 return bTruncated; 2070 } 2071 2072 sal_Bool TextView::ImplCheckTextLen( const String& rNewText ) 2073 { 2074 sal_Bool bOK = sal_True; 2075 if ( mpImpl->mpTextEngine->GetMaxTextLen() ) 2076 { 2077 sal_uLong n = mpImpl->mpTextEngine->GetTextLen(); 2078 n += rNewText.Len(); 2079 if ( n > mpImpl->mpTextEngine->GetMaxTextLen() ) 2080 { 2081 // nur dann noch ermitteln, wie viel Text geloescht wird 2082 n -= mpImpl->mpTextEngine->GetTextLen( mpImpl->maSelection ); 2083 if ( n > mpImpl->mpTextEngine->GetMaxTextLen() ) 2084 { 2085 // Beep hat hier eigentlich nichts verloren, sondern lieber ein Hdl, 2086 // aber so funktioniert es wenigstens in ME, BasicIDE, SourceView 2087 Sound::Beep(); 2088 bOK = sal_False; 2089 } 2090 } 2091 } 2092 return bOK; 2093 } 2094 2095 void TextView::dragGestureRecognized( const ::com::sun::star::datatransfer::dnd::DragGestureEvent& rDGE ) throw (::com::sun::star::uno::RuntimeException) 2096 { 2097 if ( mpImpl->mbClickedInSelection ) 2098 { 2099 vos::OGuard aVclGuard( Application::GetSolarMutex() ); 2100 2101 DBG_ASSERT( mpImpl->maSelection.HasRange(), "TextView::dragGestureRecognized: mpImpl->mbClickedInSelection, but no selection?" ); 2102 2103 delete mpImpl->mpDDInfo; 2104 mpImpl->mpDDInfo = new TextDDInfo; 2105 mpImpl->mpDDInfo->mbStarterOfDD = sal_True; 2106 2107 TETextDataObject* pDataObj = new TETextDataObject( GetSelected() ); 2108 2109 if ( mpImpl->mpTextEngine->HasAttrib( TEXTATTR_HYPERLINK ) ) // Dann auch als HTML 2110 mpImpl->mpTextEngine->Write( pDataObj->GetHTMLStream(), &mpImpl->maSelection, sal_True ); 2111 2112 2113 /* 2114 // D&D eines Hyperlinks. 2115 // Besser waere es im MBDown sich den MBDownPaM zu merken, 2116 // ist dann aber inkompatibel => spaeter mal umstellen. 2117 TextPaM aPaM( mpImpl->mpTextEngine->GetPaM( GetDocPos( GetWindow()->GetPointerPosPixel() ) ) ); 2118 const TextCharAttrib* pAttr = mpImpl->mpTextEngine->FindCharAttrib( aPaM, TEXTATTR_HYPERLINK ); 2119 if ( pAttr ) 2120 { 2121 aSel = aPaM; 2122 aSel.GetStart().GetIndex() = pAttr->GetStart(); 2123 aSel.GetEnd().GetIndex() = pAttr->GetEnd(); 2124 2125 const TextAttribHyperLink& rLink = (const TextAttribHyperLink&)pAttr->GetAttr(); 2126 String aText( rLink.GetDescription() ); 2127 if ( !aText.Len() ) 2128 aText = mpImpl->mpTextEngine->GetText( aSel ); 2129 INetBookmark aBookmark( rLink.GetURL(), aText ); 2130 aBookmark.CopyDragServer(); 2131 } 2132 */ 2133 2134 mpImpl->mpCursor->Hide(); 2135 2136 sal_Int8 nActions = datatransfer::dnd::DNDConstants::ACTION_COPY; 2137 if ( !IsReadOnly() ) 2138 nActions |= datatransfer::dnd::DNDConstants::ACTION_MOVE; 2139 rDGE.DragSource->startDrag( rDGE, nActions, 0 /*cursor*/, 0 /*image*/, pDataObj, mpImpl->mxDnDListener ); 2140 } 2141 } 2142 2143 void TextView::dragDropEnd( const ::com::sun::star::datatransfer::dnd::DragSourceDropEvent& ) throw (::com::sun::star::uno::RuntimeException) 2144 { 2145 ImpHideDDCursor(); 2146 delete mpImpl->mpDDInfo; 2147 mpImpl->mpDDInfo = NULL; 2148 } 2149 2150 void TextView::drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException) 2151 { 2152 vos::OGuard aVclGuard( Application::GetSolarMutex() ); 2153 2154 sal_Bool bChanges = sal_False; 2155 if ( !mpImpl->mbReadOnly && mpImpl->mpDDInfo ) 2156 { 2157 ImpHideDDCursor(); 2158 2159 // Daten fuer das loeschen nach einem DROP_MOVE: 2160 TextSelection aPrevSel( mpImpl->maSelection ); 2161 aPrevSel.Justify(); 2162 sal_uLong nPrevParaCount = mpImpl->mpTextEngine->GetParagraphCount(); 2163 sal_uInt16 nPrevStartParaLen = mpImpl->mpTextEngine->GetTextLen( aPrevSel.GetStart().GetPara() ); 2164 2165 sal_Bool bStarterOfDD = sal_False; 2166 for ( sal_uInt16 nView = mpImpl->mpTextEngine->GetViewCount(); nView && !bStarterOfDD; ) 2167 bStarterOfDD = mpImpl->mpTextEngine->GetView( --nView )->mpImpl->mpDDInfo ? mpImpl->mpTextEngine->GetView( nView )->mpImpl->mpDDInfo->mbStarterOfDD : sal_False; 2168 2169 HideSelection(); 2170 ImpSetSelection( mpImpl->mpDDInfo->maDropPos ); 2171 2172 mpImpl->mpTextEngine->UndoActionStart(); 2173 2174 String aText; 2175 uno::Reference< datatransfer::XTransferable > xDataObj = rDTDE.Transferable; 2176 if ( xDataObj.is() ) 2177 { 2178 datatransfer::DataFlavor aFlavor; 2179 SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor ); 2180 if ( xDataObj->isDataFlavorSupported( aFlavor ) ) 2181 { 2182 uno::Any aData = xDataObj->getTransferData( aFlavor ); 2183 ::rtl::OUString aOUString; 2184 aData >>= aOUString; 2185 aText = aOUString; 2186 aText.ConvertLineEnd( LINEEND_LF ); 2187 } 2188 } 2189 2190 if ( aText.Len() && ( aText.GetChar( aText.Len()-1 ) == LINE_SEP ) ) 2191 aText.Erase( aText.Len()-1 ); 2192 2193 TextPaM aTempStart = mpImpl->maSelection.GetStart(); 2194 if ( ImplCheckTextLen( aText ) ) 2195 ImpSetSelection( mpImpl->mpTextEngine->ImpInsertText( mpImpl->mpDDInfo->maDropPos, aText ) ); 2196 if(mpImpl->mbSupportProtectAttribute) 2197 { 2198 mpImpl->mpTextEngine->SetAttrib( TextAttribProtect(), 2199 aTempStart.GetPara(), 2200 aTempStart.GetIndex(), 2201 mpImpl->maSelection.GetEnd().GetIndex(), sal_False ); 2202 } 2203 2204 if ( aPrevSel.HasRange() && 2205 !mpImpl->mbSupportProtectAttribute && // don't remove currently selected element 2206 (( rDTDE.DropAction & datatransfer::dnd::DNDConstants::ACTION_MOVE ) || !bStarterOfDD) ) 2207 { 2208 // ggf. Selection anpasssen: 2209 if ( ( mpImpl->mpDDInfo->maDropPos.GetPara() < aPrevSel.GetStart().GetPara() ) || 2210 ( ( mpImpl->mpDDInfo->maDropPos.GetPara() == aPrevSel.GetStart().GetPara() ) 2211 && ( mpImpl->mpDDInfo->maDropPos.GetIndex() < aPrevSel.GetStart().GetIndex() ) ) ) 2212 { 2213 sal_uLong nNewParasBeforeSelection = 2214 mpImpl->mpTextEngine->GetParagraphCount() - nPrevParaCount; 2215 2216 aPrevSel.GetStart().GetPara() += nNewParasBeforeSelection; 2217 aPrevSel.GetEnd().GetPara() += nNewParasBeforeSelection; 2218 2219 if ( mpImpl->mpDDInfo->maDropPos.GetPara() == aPrevSel.GetStart().GetPara() ) 2220 { 2221 sal_uInt16 nNewChars = 2222 mpImpl->mpTextEngine->GetTextLen( aPrevSel.GetStart().GetPara() ) - nPrevStartParaLen; 2223 2224 aPrevSel.GetStart().GetIndex() = 2225 aPrevSel.GetStart().GetIndex() + nNewChars; 2226 if ( aPrevSel.GetStart().GetPara() == aPrevSel.GetEnd().GetPara() ) 2227 aPrevSel.GetEnd().GetIndex() = 2228 aPrevSel.GetEnd().GetIndex() + nNewChars; 2229 } 2230 } 2231 else 2232 { 2233 // aktuelle Selektion anpassen 2234 TextPaM aPaM = mpImpl->maSelection.GetStart(); 2235 aPaM.GetPara() -= ( aPrevSel.GetEnd().GetPara() - aPrevSel.GetStart().GetPara() ); 2236 if ( aPrevSel.GetEnd().GetPara() == mpImpl->mpDDInfo->maDropPos.GetPara() ) 2237 { 2238 aPaM.GetIndex() = 2239 aPaM.GetIndex() - aPrevSel.GetEnd().GetIndex(); 2240 if ( aPrevSel.GetStart().GetPara() == mpImpl->mpDDInfo->maDropPos.GetPara() ) 2241 aPaM.GetIndex() = 2242 aPaM.GetIndex() + aPrevSel.GetStart().GetIndex(); 2243 } 2244 ImpSetSelection( aPaM ); 2245 2246 } 2247 mpImpl->mpTextEngine->ImpDeleteText( aPrevSel ); 2248 } 2249 2250 mpImpl->mpTextEngine->UndoActionEnd(); 2251 2252 delete mpImpl->mpDDInfo; 2253 mpImpl->mpDDInfo = 0; 2254 2255 mpImpl->mpTextEngine->FormatAndUpdate( this ); 2256 2257 mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) ); 2258 } 2259 rDTDE.Context->dropComplete( bChanges ); 2260 } 2261 2262 void TextView::dragEnter( const ::com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& ) throw (::com::sun::star::uno::RuntimeException) 2263 { 2264 } 2265 2266 void TextView::dragExit( const ::com::sun::star::datatransfer::dnd::DropTargetEvent& ) throw (::com::sun::star::uno::RuntimeException) 2267 { 2268 vos::OGuard aVclGuard( Application::GetSolarMutex() ); 2269 ImpHideDDCursor(); 2270 } 2271 2272 void TextView::dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException) 2273 { 2274 vos::OGuard aVclGuard( Application::GetSolarMutex() ); 2275 2276 if ( !mpImpl->mpDDInfo ) 2277 mpImpl->mpDDInfo = new TextDDInfo; 2278 2279 TextPaM aPrevDropPos = mpImpl->mpDDInfo->maDropPos; 2280 Point aMousePos( rDTDE.LocationX, rDTDE.LocationY ); 2281 Point aDocPos = GetDocPos( aMousePos ); 2282 mpImpl->mpDDInfo->maDropPos = mpImpl->mpTextEngine->GetPaM( aDocPos ); 2283 2284 /* 2285 Size aOutSize = mpImpl->mpWindow->GetOutputSizePixel(); 2286 if ( ( aMousePos.X() < 0 ) || ( aMousePos.X() > aOutSize.Width() ) || 2287 ( aMousePos.Y() < 0 ) || ( aMousePos.Y() > aOutSize.Height() ) ) 2288 { 2289 // Scroll? 2290 // No, I will not receive events for this... 2291 } 2292 */ 2293 2294 sal_Bool bProtected = sal_False; 2295 if(mpImpl->mbSupportProtectAttribute) 2296 { 2297 const TextCharAttrib* pStartAttr = mpImpl->mpTextEngine->FindCharAttrib( 2298 mpImpl->mpDDInfo->maDropPos, 2299 TEXTATTR_PROTECTED ); 2300 bProtected = pStartAttr != 0 && 2301 pStartAttr->GetStart() != mpImpl->mpDDInfo->maDropPos.GetIndex() && 2302 pStartAttr->GetEnd() != mpImpl->mpDDInfo->maDropPos.GetIndex(); 2303 } 2304 // Don't drop in selection or in read only engine 2305 if ( IsReadOnly() || IsInSelection( mpImpl->mpDDInfo->maDropPos ) || bProtected) 2306 { 2307 ImpHideDDCursor(); 2308 rDTDE.Context->rejectDrag(); 2309 } 2310 else 2311 { 2312 // Alten Cursor wegzeichnen... 2313 if ( !mpImpl->mpDDInfo->mbVisCursor || ( aPrevDropPos != mpImpl->mpDDInfo->maDropPos ) ) 2314 { 2315 ImpHideDDCursor(); 2316 ImpShowDDCursor(); 2317 } 2318 rDTDE.Context->acceptDrag( rDTDE.DropAction ); 2319 } 2320 } 2321 2322 Point TextView::ImpGetOutputStartPos( const Point& rStartDocPos ) const 2323 { 2324 Point aStartPos( -rStartDocPos.X(), -rStartDocPos.Y() ); 2325 if ( mpImpl->mpTextEngine->IsRightToLeft() ) 2326 { 2327 Size aSz = mpImpl->mpWindow->GetOutputSizePixel(); 2328 aStartPos.X() = rStartDocPos.X() + aSz.Width() - 1; // -1: Start is 0 2329 } 2330 return aStartPos; 2331 } 2332 2333 Point TextView::GetDocPos( const Point& rWindowPos ) const 2334 { 2335 // Fensterposition => Dokumentposition 2336 2337 Point aPoint; 2338 2339 aPoint.Y() = rWindowPos.Y() + mpImpl->maStartDocPos.Y(); 2340 2341 if ( !mpImpl->mpTextEngine->IsRightToLeft() ) 2342 { 2343 aPoint.X() = rWindowPos.X() + mpImpl->maStartDocPos.X(); 2344 } 2345 else 2346 { 2347 Size aSz = mpImpl->mpWindow->GetOutputSizePixel(); 2348 aPoint.X() = ( aSz.Width() - 1 ) - rWindowPos.X() + mpImpl->maStartDocPos.X(); 2349 } 2350 2351 return aPoint; 2352 } 2353 2354 Point TextView::GetWindowPos( const Point& rDocPos ) const 2355 { 2356 // Dokumentposition => Fensterposition 2357 2358 Point aPoint; 2359 2360 aPoint.Y() = rDocPos.Y() - mpImpl->maStartDocPos.Y(); 2361 2362 if ( !mpImpl->mpTextEngine->IsRightToLeft() ) 2363 { 2364 aPoint.X() = rDocPos.X() - mpImpl->maStartDocPos.X(); 2365 } 2366 else 2367 { 2368 Size aSz = mpImpl->mpWindow->GetOutputSizePixel(); 2369 aPoint.X() = ( aSz.Width() - 1 ) - ( rDocPos.X() - mpImpl->maStartDocPos.X() ); 2370 } 2371 2372 return aPoint; 2373 } 2374 2375 sal_Int32 TextView::GetLineNumberOfCursorInSelection() const 2376 { 2377 // PROGRESS 2378 sal_Int32 nLineNo = -1; 2379 if( mpImpl->mbCursorEnabled ) 2380 { 2381 TextPaM aPaM = GetSelection().GetEnd(); 2382 TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() ); 2383 nLineNo = pPPortion->GetLineNumber( aPaM.GetIndex(), sal_False ); 2384 if( mpImpl->mbCursorAtEndOfLine ) 2385 --nLineNo; 2386 } 2387 return nLineNo; 2388 } 2389 2390 2391 // ------------------------------------------------------------------------- 2392 // (+) class TextSelFunctionSet 2393 // ------------------------------------------------------------------------- 2394 TextSelFunctionSet::TextSelFunctionSet( TextView* pView ) 2395 { 2396 mpView = pView; 2397 } 2398 2399 void __EXPORT TextSelFunctionSet::BeginDrag() 2400 { 2401 } 2402 2403 void __EXPORT TextSelFunctionSet::CreateAnchor() 2404 { 2405 // TextSelection aSel( mpView->GetSelection() ); 2406 // aSel.GetStart() = aSel.GetEnd(); 2407 // mpView->SetSelection( aSel ); 2408 2409 // Es darf kein ShowCursor folgen: 2410 mpView->HideSelection(); 2411 mpView->ImpSetSelection( mpView->mpImpl->maSelection.GetEnd() ); 2412 } 2413 2414 sal_Bool __EXPORT TextSelFunctionSet::SetCursorAtPoint( const Point& rPointPixel, sal_Bool ) 2415 { 2416 return mpView->SetCursorAtPoint( rPointPixel ); 2417 } 2418 2419 sal_Bool __EXPORT TextSelFunctionSet::IsSelectionAtPoint( const Point& rPointPixel ) 2420 { 2421 return mpView->IsSelectionAtPoint( rPointPixel ); 2422 } 2423 2424 void __EXPORT TextSelFunctionSet::DeselectAll() 2425 { 2426 CreateAnchor(); 2427 } 2428 2429 void __EXPORT TextSelFunctionSet::DeselectAtPoint( const Point& ) 2430 { 2431 // Nur bei Mehrfachselektion 2432 } 2433 2434 void __EXPORT TextSelFunctionSet::DestroyAnchor() 2435 { 2436 // Nur bei Mehrfachselektion 2437 } 2438 TextEngine* TextView::GetTextEngine() const 2439 { return mpImpl->mpTextEngine; } 2440 Window* TextView::GetWindow() const 2441 { return mpImpl->mpWindow; } 2442 void TextView::EnableCursor( sal_Bool bEnable ) 2443 { mpImpl->mbCursorEnabled = bEnable; } 2444 sal_Bool TextView::IsCursorEnabled() const 2445 { return mpImpl->mbCursorEnabled; } 2446 void TextView::SetStartDocPos( const Point& rPos ) 2447 { mpImpl->maStartDocPos = rPos; } 2448 const Point& TextView::GetStartDocPos() const 2449 { return mpImpl->maStartDocPos; } 2450 void TextView::SetAutoIndentMode( sal_Bool bAutoIndent ) 2451 { mpImpl->mbAutoIndent = bAutoIndent; } 2452 sal_Bool TextView::IsAutoIndentMode() const 2453 { return mpImpl->mbAutoIndent; } 2454 sal_Bool TextView::IsReadOnly() const 2455 { return mpImpl->mbReadOnly; } 2456 void TextView::SetAutoScroll( sal_Bool bAutoScroll ) 2457 { mpImpl->mbAutoScroll = bAutoScroll; } 2458 sal_Bool TextView::IsAutoScroll() const 2459 { return mpImpl->mbAutoScroll; } 2460 sal_Bool TextView::IsPaintSelection() const 2461 { return mpImpl->mbPaintSelection; } 2462 sal_Bool TextView::IsHighlightSelection() const 2463 { return mpImpl->mbHighlightSelection; } 2464 sal_Bool TextView::HasSelection() const 2465 { return mpImpl->maSelection.HasRange(); } 2466 sal_Bool TextView::IsInsertMode() const 2467 { return mpImpl->mbInsertMode; } 2468 void TextView::SupportProtectAttribute(sal_Bool bSupport) 2469 { mpImpl->mbSupportProtectAttribute = bSupport;} 2470 2471