1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include <memory> 21 #include <i18nutil/searchopt.hxx> 22 #include <o3tl/deleter.hxx> 23 #include <vcl/textview.hxx> 24 #include <vcl/texteng.hxx> 25 #include <vcl/settings.hxx> 26 #include "textdoc.hxx" 27 #include <vcl/textdata.hxx> 28 #include <vcl/xtextedt.hxx> 29 #include "textdat2.hxx" 30 #include <vcl/commandevent.hxx> 31 #include <vcl/inputctx.hxx> 32 33 #include <svl/undo.hxx> 34 #include <vcl/cursor.hxx> 35 #include <vcl/weld.hxx> 36 #include <vcl/window.hxx> 37 #include <vcl/svapp.hxx> 38 #include <tools/stream.hxx> 39 40 #include <sal/log.hxx> 41 #include <sot/formats.hxx> 42 43 #include <cppuhelper/weak.hxx> 44 #include <cppuhelper/queryinterface.hxx> 45 #include <com/sun/star/i18n/XBreakIterator.hpp> 46 #include <com/sun/star/i18n/CharacterIteratorMode.hpp> 47 #include <com/sun/star/i18n/WordType.hpp> 48 #include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp> 49 #include <com/sun/star/datatransfer/XTransferable.hpp> 50 #include <com/sun/star/datatransfer/clipboard/XClipboard.hpp> 51 #include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp> 52 #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp> 53 #include <com/sun/star/datatransfer/dnd/XDragGestureRecognizer.hpp> 54 #include <com/sun/star/datatransfer/dnd/XDropTarget.hpp> 55 #include <com/sun/star/util/SearchFlags.hpp> 56 57 #include <vcl/edit.hxx> 58 59 #include <sot/exchange.hxx> 60 61 #include <algorithm> 62 #include <cstddef> 63 64 TETextDataObject::TETextDataObject( const OUString& rText ) : maText( rText ) 65 { 66 } 67 68 // css::uno::XInterface 69 css::uno::Any TETextDataObject::queryInterface( const css::uno::Type & rType ) 70 { 71 css::uno::Any aRet = ::cppu::queryInterface( rType, static_cast< css::datatransfer::XTransferable* >(this) ); 72 return (aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType )); 73 } 74 75 // css::datatransfer::XTransferable 76 css::uno::Any TETextDataObject::getTransferData( const css::datatransfer::DataFlavor& rFlavor ) 77 { 78 css::uno::Any aAny; 79 80 SotClipboardFormatId nT = SotExchange::GetFormat( rFlavor ); 81 if ( nT == SotClipboardFormatId::STRING ) 82 { 83 aAny <<= GetText(); 84 } 85 else if ( nT == SotClipboardFormatId::HTML ) 86 { 87 sal_uLong nLen = GetHTMLStream().TellEnd(); 88 GetHTMLStream().Seek(0); 89 90 css::uno::Sequence< sal_Int8 > aSeq( nLen ); 91 memcpy( aSeq.getArray(), GetHTMLStream().GetData(), nLen ); 92 aAny <<= aSeq; 93 } 94 else 95 { 96 throw css::datatransfer::UnsupportedFlavorException(); 97 } 98 return aAny; 99 } 100 101 css::uno::Sequence< css::datatransfer::DataFlavor > TETextDataObject::getTransferDataFlavors( ) 102 { 103 GetHTMLStream().Seek( STREAM_SEEK_TO_END ); 104 bool bHTML = GetHTMLStream().Tell() > 0; 105 css::uno::Sequence< css::datatransfer::DataFlavor > aDataFlavors( bHTML ? 2 : 1 ); 106 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING, aDataFlavors.getArray()[0] ); 107 if ( bHTML ) 108 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::HTML, aDataFlavors.getArray()[1] ); 109 return aDataFlavors; 110 } 111 112 sal_Bool TETextDataObject::isDataFlavorSupported( const css::datatransfer::DataFlavor& rFlavor ) 113 { 114 SotClipboardFormatId nT = SotExchange::GetFormat( rFlavor ); 115 return ( nT == SotClipboardFormatId::STRING ); 116 } 117 118 struct ImpTextView 119 { 120 ExtTextEngine* mpTextEngine; 121 122 VclPtr<vcl::Window> mpWindow; 123 TextSelection maSelection; 124 Point maStartDocPos; 125 126 std::unique_ptr<vcl::Cursor, o3tl::default_delete<vcl::Cursor>> mpCursor; 127 128 std::unique_ptr<TextDDInfo, o3tl::default_delete<TextDDInfo>> mpDDInfo; 129 130 std::unique_ptr<SelectionEngine> mpSelEngine; 131 std::unique_ptr<TextSelFunctionSet> mpSelFuncSet; 132 133 css::uno::Reference< css::datatransfer::dnd::XDragSourceListener > mxDnDListener; 134 135 sal_uInt16 mnTravelXPos; 136 137 bool mbAutoScroll : 1; 138 bool mbInsertMode : 1; 139 bool mbReadOnly : 1; 140 bool mbPaintSelection : 1; 141 bool mbAutoIndent : 1; 142 bool mbHighlightSelection : 1; 143 bool mbCursorEnabled : 1; 144 bool mbClickedInSelection : 1; 145 bool mbSupportProtectAttribute : 1; 146 bool mbCursorAtEndOfLine; 147 }; 148 149 TextView::TextView( ExtTextEngine* pEng, vcl::Window* pWindow ) : 150 mpImpl(new ImpTextView) 151 { 152 pWindow->EnableRTL( false ); 153 154 mpImpl->mpWindow = pWindow; 155 mpImpl->mpTextEngine = pEng; 156 157 mpImpl->mbPaintSelection = true; 158 mpImpl->mbAutoScroll = true; 159 mpImpl->mbInsertMode = true; 160 mpImpl->mbReadOnly = false; 161 mpImpl->mbHighlightSelection = false; 162 mpImpl->mbAutoIndent = false; 163 mpImpl->mbCursorEnabled = true; 164 mpImpl->mbClickedInSelection = false; 165 mpImpl->mbSupportProtectAttribute = false; 166 mpImpl->mbCursorAtEndOfLine = false; 167 // mbInSelection = false; 168 169 mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW; 170 171 mpImpl->mpSelFuncSet = std::make_unique<TextSelFunctionSet>( this ); 172 mpImpl->mpSelEngine = std::make_unique<SelectionEngine>( mpImpl->mpWindow, mpImpl->mpSelFuncSet.get() ); 173 mpImpl->mpSelEngine->SetSelectionMode( SelectionMode::Range ); 174 mpImpl->mpSelEngine->EnableDrag( true ); 175 176 mpImpl->mpCursor.reset(new vcl::Cursor); 177 mpImpl->mpCursor->Show(); 178 pWindow->SetCursor( mpImpl->mpCursor.get() ); 179 pWindow->SetInputContext( InputContext( pEng->GetFont(), InputContextFlags::Text|InputContextFlags::ExtText ) ); 180 181 if ( pWindow->GetSettings().GetStyleSettings().GetSelectionOptions() & SelectionOptions::Invert ) 182 mpImpl->mbHighlightSelection = true; 183 184 pWindow->SetLineColor(); 185 186 if ( pWindow->GetDragGestureRecognizer().is() ) 187 { 188 vcl::unohelper::DragAndDropWrapper* pDnDWrapper = new vcl::unohelper::DragAndDropWrapper( this ); 189 mpImpl->mxDnDListener = pDnDWrapper; 190 191 css::uno::Reference< css::datatransfer::dnd::XDragGestureListener> xDGL( mpImpl->mxDnDListener, css::uno::UNO_QUERY ); 192 pWindow->GetDragGestureRecognizer()->addDragGestureListener( xDGL ); 193 css::uno::Reference< css::datatransfer::dnd::XDropTargetListener> xDTL( xDGL, css::uno::UNO_QUERY ); 194 pWindow->GetDropTarget()->addDropTargetListener( xDTL ); 195 pWindow->GetDropTarget()->setActive( true ); 196 pWindow->GetDropTarget()->setDefaultActions( css::datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE ); 197 } 198 } 199 200 TextView::~TextView() 201 { 202 mpImpl->mpSelEngine.reset(); 203 mpImpl->mpSelFuncSet.reset(); 204 205 if ( mpImpl->mpWindow->GetCursor() == mpImpl->mpCursor.get() ) 206 mpImpl->mpWindow->SetCursor( nullptr ); 207 208 mpImpl->mpCursor.reset(); 209 mpImpl->mpDDInfo.reset(); 210 } 211 212 void TextView::Invalidate() 213 { 214 mpImpl->mpWindow->Invalidate(); 215 } 216 217 void TextView::SetSelection( const TextSelection& rTextSel, bool bGotoCursor ) 218 { 219 // if someone left an empty attribute and then the Outliner manipulated the selection 220 if ( !mpImpl->maSelection.HasRange() ) 221 mpImpl->mpTextEngine->CursorMoved( mpImpl->maSelection.GetStart().GetPara() ); 222 223 // if the selection is manipulated after a KeyInput 224 mpImpl->mpTextEngine->CheckIdleFormatter(); 225 226 HideSelection(); 227 TextSelection aNewSel( rTextSel ); 228 mpImpl->mpTextEngine->ValidateSelection( aNewSel ); 229 ImpSetSelection( aNewSel ); 230 ShowSelection(); 231 ShowCursor( bGotoCursor ); 232 } 233 234 void TextView::SetSelection( const TextSelection& rTextSel ) 235 { 236 SetSelection( rTextSel, mpImpl->mbAutoScroll ); 237 } 238 239 const TextSelection& TextView::GetSelection() const 240 { 241 return mpImpl->maSelection; 242 } 243 TextSelection& TextView::GetSelection() 244 { 245 return mpImpl->maSelection; 246 } 247 248 void TextView::DeleteSelected() 249 { 250 // HideSelection(); 251 252 mpImpl->mpTextEngine->UndoActionStart(); 253 TextPaM aPaM = mpImpl->mpTextEngine->ImpDeleteText( mpImpl->maSelection ); 254 mpImpl->mpTextEngine->UndoActionEnd(); 255 256 ImpSetSelection( aPaM ); 257 mpImpl->mpTextEngine->FormatAndUpdate( this ); 258 ShowCursor(); 259 } 260 261 void TextView::ImpPaint(vcl::RenderContext& rRenderContext, const Point& rStartPos, tools::Rectangle const* pPaintArea, TextSelection const* pSelection) 262 { 263 if (!mpImpl->mbPaintSelection) 264 { 265 pSelection = nullptr; 266 } 267 else 268 { 269 // set correct background color; 270 // unfortunately we cannot detect if it has changed 271 vcl::Font aFont = mpImpl->mpTextEngine->GetFont(); 272 Color aColor = rRenderContext.GetBackground().GetColor(); 273 aColor.SetTransparency(0); 274 if (aColor != aFont.GetFillColor()) 275 { 276 if (aFont.IsTransparent()) 277 aColor = COL_TRANSPARENT; 278 aFont.SetFillColor(aColor); 279 mpImpl->mpTextEngine->maFont = aFont; 280 } 281 } 282 283 mpImpl->mpTextEngine->ImpPaint(&rRenderContext, rStartPos, pPaintArea, pSelection); 284 } 285 286 void TextView::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) 287 { 288 ImpPaint(rRenderContext, rRect); 289 } 290 291 void TextView::ImpPaint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) 292 { 293 if ( !mpImpl->mpTextEngine->GetUpdateMode() || mpImpl->mpTextEngine->IsInUndo() ) 294 return; 295 296 TextSelection *pDrawSelection = nullptr; 297 if (!mpImpl->mbHighlightSelection && mpImpl->maSelection.HasRange()) 298 pDrawSelection = &mpImpl->maSelection; 299 300 Point aStartPos = ImpGetOutputStartPos(mpImpl->maStartDocPos); 301 ImpPaint(rRenderContext, aStartPos, &rRect, pDrawSelection); 302 if (mpImpl->mbHighlightSelection) 303 ImpHighlight(mpImpl->maSelection); 304 } 305 306 void TextView::ImpHighlight( const TextSelection& rSel ) 307 { 308 TextSelection aSel( rSel ); 309 aSel.Justify(); 310 if ( aSel.HasRange() && !mpImpl->mpTextEngine->IsInUndo() && mpImpl->mpTextEngine->GetUpdateMode() ) 311 { 312 mpImpl->mpCursor->Hide(); 313 314 SAL_WARN_IF( mpImpl->mpTextEngine->mpIdleFormatter->IsActive(), "vcl", "ImpHighlight: Not formatted!" ); 315 316 tools::Rectangle aVisArea( mpImpl->maStartDocPos, mpImpl->mpWindow->GetOutputSizePixel() ); 317 long nY = 0; 318 const sal_uInt32 nStartPara = aSel.GetStart().GetPara(); 319 const sal_uInt32 nEndPara = aSel.GetEnd().GetPara(); 320 for ( sal_uInt32 nPara = 0; nPara <= nEndPara; ++nPara ) 321 { 322 const long nParaHeight = mpImpl->mpTextEngine->CalcParaHeight( nPara ); 323 if ( ( nPara >= nStartPara ) && ( ( nY + nParaHeight ) > aVisArea.Top() ) ) 324 { 325 TEParaPortion* pTEParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( nPara ); 326 std::vector<TextLine>::size_type nStartLine = 0; 327 std::vector<TextLine>::size_type nEndLine = pTEParaPortion->GetLines().size() -1; 328 if ( nPara == nStartPara ) 329 nStartLine = pTEParaPortion->GetLineNumber( aSel.GetStart().GetIndex(), false ); 330 if ( nPara == nEndPara ) 331 nEndLine = pTEParaPortion->GetLineNumber( aSel.GetEnd().GetIndex(), true ); 332 333 // iterate over all lines 334 for ( std::vector<TextLine>::size_type nLine = nStartLine; nLine <= nEndLine; nLine++ ) 335 { 336 TextLine& rLine = pTEParaPortion->GetLines()[ nLine ]; 337 sal_Int32 nStartIndex = rLine.GetStart(); 338 sal_Int32 nEndIndex = rLine.GetEnd(); 339 if ( ( nPara == nStartPara ) && ( nLine == nStartLine ) ) 340 nStartIndex = aSel.GetStart().GetIndex(); 341 if ( ( nPara == nEndPara ) && ( nLine == nEndLine ) ) 342 nEndIndex = aSel.GetEnd().GetIndex(); 343 344 // possible if at the beginning of a wrapped line 345 if ( nEndIndex < nStartIndex ) 346 nEndIndex = nStartIndex; 347 348 tools::Rectangle aTmpRect( mpImpl->mpTextEngine->GetEditCursor( TextPaM( nPara, nStartIndex ), false ) ); 349 aTmpRect.AdjustTop(nY ); 350 aTmpRect.AdjustBottom(nY ); 351 Point aTopLeft( aTmpRect.TopLeft() ); 352 353 aTmpRect = mpImpl->mpTextEngine->GetEditCursor( TextPaM( nPara, nEndIndex ), true ); 354 aTmpRect.AdjustTop(nY ); 355 aTmpRect.AdjustBottom(nY ); 356 Point aBottomRight( aTmpRect.BottomRight() ); 357 aBottomRight.AdjustX( -1 ); 358 359 // only paint if in the visible region 360 if ( ( aTopLeft.X() < aBottomRight.X() ) && ( aBottomRight.Y() >= aVisArea.Top() ) ) 361 { 362 Point aPnt1( GetWindowPos( aTopLeft ) ); 363 Point aPnt2( GetWindowPos( aBottomRight ) ); 364 365 tools::Rectangle aRect( aPnt1, aPnt2 ); 366 mpImpl->mpWindow->Invert( aRect ); 367 } 368 } 369 } 370 nY += nParaHeight; 371 372 if ( nY >= aVisArea.Bottom() ) 373 break; 374 } 375 } 376 } 377 378 void TextView::ImpSetSelection( const TextSelection& rSelection ) 379 { 380 if (rSelection != mpImpl->maSelection) 381 { 382 bool bCaret = false, bSelection = false; 383 const TextPaM &rEnd = rSelection.GetEnd(); 384 const TextPaM &rOldEnd = mpImpl->maSelection.GetEnd(); 385 bool bGap = rSelection.HasRange(), bOldGap = mpImpl->maSelection.HasRange(); 386 if (rEnd != rOldEnd) 387 bCaret = true; 388 if (bGap || bOldGap) 389 bSelection = true; 390 391 mpImpl->maSelection = rSelection; 392 393 if (bSelection) 394 mpImpl->mpTextEngine->Broadcast(TextHint(SfxHintId::TextViewSelectionChanged)); 395 396 if (bCaret) 397 mpImpl->mpTextEngine->Broadcast(TextHint(SfxHintId::TextViewCaretChanged)); 398 } 399 } 400 401 void TextView::ShowSelection() 402 { 403 ImpShowHideSelection(); 404 } 405 406 void TextView::HideSelection() 407 { 408 ImpShowHideSelection(); 409 } 410 411 void TextView::ShowSelection( const TextSelection& rRange ) 412 { 413 ImpShowHideSelection( &rRange ); 414 } 415 416 void TextView::ImpShowHideSelection(const TextSelection* pRange) 417 { 418 const TextSelection* pRangeOrSelection = pRange ? pRange : &mpImpl->maSelection; 419 420 if ( pRangeOrSelection->HasRange() ) 421 { 422 if ( mpImpl->mbHighlightSelection ) 423 { 424 ImpHighlight( *pRangeOrSelection ); 425 } 426 else 427 { 428 if( mpImpl->mpWindow->IsPaintTransparent() ) 429 mpImpl->mpWindow->Invalidate(); 430 else 431 { 432 TextSelection aRange( *pRangeOrSelection ); 433 aRange.Justify(); 434 bool bVisCursor = mpImpl->mpCursor->IsVisible(); 435 mpImpl->mpCursor->Hide(); 436 Invalidate(); 437 if (bVisCursor) 438 mpImpl->mpCursor->Show(); 439 } 440 } 441 } 442 } 443 444 bool TextView::KeyInput( const KeyEvent& rKeyEvent ) 445 { 446 bool bDone = true; 447 bool bModified = false; 448 bool bMoved = false; 449 bool bEndKey = false; // special CursorPosition 450 bool bAllowIdle = true; 451 452 // check mModified; 453 // the local bModified is not set e.g. by Cut/Paste, as here 454 // the update happens somewhere else 455 bool bWasModified = mpImpl->mpTextEngine->IsModified(); 456 mpImpl->mpTextEngine->SetModified( false ); 457 458 TextSelection aCurSel( mpImpl->maSelection ); 459 TextSelection aOldSel( aCurSel ); 460 461 sal_uInt16 nCode = rKeyEvent.GetKeyCode().GetCode(); 462 KeyFuncType eFunc = rKeyEvent.GetKeyCode().GetFunction(); 463 if ( eFunc != KeyFuncType::DONTKNOW ) 464 { 465 switch ( eFunc ) 466 { 467 case KeyFuncType::CUT: 468 { 469 if ( !mpImpl->mbReadOnly ) 470 Cut(); 471 } 472 break; 473 case KeyFuncType::COPY: 474 { 475 Copy(); 476 } 477 break; 478 case KeyFuncType::PASTE: 479 { 480 if ( !mpImpl->mbReadOnly ) 481 Paste(); 482 } 483 break; 484 case KeyFuncType::UNDO: 485 { 486 if ( !mpImpl->mbReadOnly ) 487 Undo(); 488 } 489 break; 490 case KeyFuncType::REDO: 491 { 492 if ( !mpImpl->mbReadOnly ) 493 Redo(); 494 } 495 break; 496 497 default: // might get processed below 498 eFunc = KeyFuncType::DONTKNOW; 499 } 500 } 501 if ( eFunc == KeyFuncType::DONTKNOW ) 502 { 503 switch ( nCode ) 504 { 505 case KEY_UP: 506 case KEY_DOWN: 507 case KEY_LEFT: 508 case KEY_RIGHT: 509 case KEY_HOME: 510 case KEY_END: 511 case KEY_PAGEUP: 512 case KEY_PAGEDOWN: 513 case css::awt::Key::MOVE_WORD_FORWARD: 514 case css::awt::Key::SELECT_WORD_FORWARD: 515 case css::awt::Key::MOVE_WORD_BACKWARD: 516 case css::awt::Key::SELECT_WORD_BACKWARD: 517 case css::awt::Key::MOVE_TO_BEGIN_OF_LINE: 518 case css::awt::Key::MOVE_TO_END_OF_LINE: 519 case css::awt::Key::SELECT_TO_BEGIN_OF_LINE: 520 case css::awt::Key::SELECT_TO_END_OF_LINE: 521 case css::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH: 522 case css::awt::Key::MOVE_TO_END_OF_PARAGRAPH: 523 case css::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH: 524 case css::awt::Key::SELECT_TO_END_OF_PARAGRAPH: 525 case css::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT: 526 case css::awt::Key::MOVE_TO_END_OF_DOCUMENT: 527 case css::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT: 528 case css::awt::Key::SELECT_TO_END_OF_DOCUMENT: 529 { 530 if ( ( !rKeyEvent.GetKeyCode().IsMod2() || ( nCode == KEY_LEFT ) || ( nCode == KEY_RIGHT ) ) 531 && !( rKeyEvent.GetKeyCode().IsMod1() && ( nCode == KEY_PAGEUP || nCode == KEY_PAGEDOWN ) ) ) 532 { 533 aCurSel = ImpMoveCursor( rKeyEvent ); 534 if ( aCurSel.HasRange() ) { 535 css::uno::Reference<css::datatransfer::clipboard::XClipboard> aSelection(GetWindow()->GetPrimarySelection()); 536 Copy( aSelection ); 537 } 538 bMoved = true; 539 if ( nCode == KEY_END ) 540 bEndKey = true; 541 } 542 else 543 bDone = false; 544 } 545 break; 546 case KEY_BACKSPACE: 547 case KEY_DELETE: 548 case css::awt::Key::DELETE_WORD_BACKWARD: 549 case css::awt::Key::DELETE_WORD_FORWARD: 550 case css::awt::Key::DELETE_TO_BEGIN_OF_LINE: 551 case css::awt::Key::DELETE_TO_END_OF_LINE: 552 { 553 if ( !mpImpl->mbReadOnly && !rKeyEvent.GetKeyCode().IsMod2() ) 554 { 555 sal_uInt8 nDel = ( nCode == KEY_DELETE ) ? DEL_RIGHT : DEL_LEFT; 556 sal_uInt8 nMode = rKeyEvent.GetKeyCode().IsMod1() ? DELMODE_RESTOFWORD : DELMODE_SIMPLE; 557 if ( ( nMode == DELMODE_RESTOFWORD ) && rKeyEvent.GetKeyCode().IsShift() ) 558 nMode = DELMODE_RESTOFCONTENT; 559 560 switch( nCode ) 561 { 562 case css::awt::Key::DELETE_WORD_BACKWARD: 563 nDel = DEL_LEFT; 564 nMode = DELMODE_RESTOFWORD; 565 break; 566 case css::awt::Key::DELETE_WORD_FORWARD: 567 nDel = DEL_RIGHT; 568 nMode = DELMODE_RESTOFWORD; 569 break; 570 case css::awt::Key::DELETE_TO_BEGIN_OF_LINE: 571 nDel = DEL_LEFT; 572 nMode = DELMODE_RESTOFCONTENT; 573 break; 574 case css::awt::Key::DELETE_TO_END_OF_LINE: 575 nDel = DEL_RIGHT; 576 nMode = DELMODE_RESTOFCONTENT; 577 break; 578 default: break; 579 } 580 581 mpImpl->mpTextEngine->UndoActionStart(); 582 if(mpImpl->mbSupportProtectAttribute) 583 { 584 //expand selection to include all protected content - if there is any 585 const TextCharAttrib* pStartAttr = mpImpl->mpTextEngine->FindCharAttrib( 586 TextPaM(mpImpl->maSelection.GetStart().GetPara(), 587 mpImpl->maSelection.GetStart().GetIndex()), 588 TEXTATTR_PROTECTED ); 589 const TextCharAttrib* pEndAttr = mpImpl->mpTextEngine->FindCharAttrib( 590 TextPaM(mpImpl->maSelection.GetEnd().GetPara(), 591 mpImpl->maSelection.GetEnd().GetIndex()), 592 TEXTATTR_PROTECTED ); 593 if(pStartAttr && pStartAttr->GetStart() < mpImpl->maSelection.GetStart().GetIndex()) 594 { 595 mpImpl->maSelection.GetStart().GetIndex() = pStartAttr->GetStart(); 596 aOldSel = mpImpl->maSelection; // update to deleted! 597 } 598 if(pEndAttr && pEndAttr->GetEnd() > mpImpl->maSelection.GetEnd().GetIndex()) 599 { 600 mpImpl->maSelection.GetEnd().GetIndex() = pEndAttr->GetEnd(); 601 aOldSel = mpImpl->maSelection; // update to deleted! 602 } 603 } 604 aCurSel = ImpDelete( nDel, nMode ); 605 mpImpl->mpTextEngine->UndoActionEnd(); 606 bModified = true; 607 bAllowIdle = false; 608 } 609 else 610 bDone = false; 611 } 612 break; 613 case KEY_TAB: 614 { 615 if ( !mpImpl->mbReadOnly && !rKeyEvent.GetKeyCode().IsShift() && 616 !rKeyEvent.GetKeyCode().IsMod1() && !rKeyEvent.GetKeyCode().IsMod2() && 617 ImplCheckTextLen( OUString('x') ) ) 618 { 619 aCurSel = mpImpl->mpTextEngine->ImpInsertText( aCurSel, '\t', !IsInsertMode() ); 620 bModified = true; 621 } 622 else 623 bDone = false; 624 } 625 break; 626 case KEY_RETURN: 627 { 628 // do not swallow Shift-RETURN, as this would disable multi-line entries 629 // in dialogs & property editors 630 if ( !mpImpl->mbReadOnly && !rKeyEvent.GetKeyCode().IsMod1() && 631 !rKeyEvent.GetKeyCode().IsMod2() && ImplCheckTextLen( OUString('x') ) ) 632 { 633 mpImpl->mpTextEngine->UndoActionStart(); 634 aCurSel = mpImpl->mpTextEngine->ImpInsertParaBreak( aCurSel ); 635 if ( mpImpl->mbAutoIndent ) 636 { 637 TextNode* pPrev = mpImpl->mpTextEngine->mpDoc->GetNodes()[ aCurSel.GetEnd().GetPara() - 1 ].get(); 638 sal_Int32 n = 0; 639 while ( ( n < pPrev->GetText().getLength() ) && ( 640 ( pPrev->GetText()[ n ] == ' ' ) || 641 ( pPrev->GetText()[ n ] == '\t' ) ) ) 642 { 643 n++; 644 } 645 if ( n ) 646 aCurSel = mpImpl->mpTextEngine->ImpInsertText( aCurSel, pPrev->GetText().copy( 0, n ) ); 647 } 648 mpImpl->mpTextEngine->UndoActionEnd(); 649 bModified = true; 650 } 651 else 652 bDone = false; 653 } 654 break; 655 case KEY_INSERT: 656 { 657 if ( !mpImpl->mbReadOnly ) 658 SetInsertMode( !IsInsertMode() ); 659 } 660 break; 661 default: 662 { 663 if ( TextEngine::IsSimpleCharInput( rKeyEvent ) ) 664 { 665 sal_Unicode nCharCode = rKeyEvent.GetCharCode(); 666 if ( !mpImpl->mbReadOnly && ImplCheckTextLen( OUString(nCharCode) ) ) // otherwise swallow the character anyway 667 { 668 aCurSel = mpImpl->mpTextEngine->ImpInsertText( nCharCode, aCurSel, !IsInsertMode(), true ); 669 bModified = true; 670 } 671 } 672 else 673 bDone = false; 674 } 675 } 676 } 677 678 if ( aCurSel != aOldSel ) // Check if changed, maybe other method already changed mpImpl->maSelection, don't overwrite that! 679 ImpSetSelection( aCurSel ); 680 681 if ( ( nCode != KEY_UP ) && ( nCode != KEY_DOWN ) ) 682 mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW; 683 684 if ( bModified ) 685 { 686 // Idle-Formatter only if AnyInput 687 if ( bAllowIdle && Application::AnyInput( VclInputFlags::KEYBOARD) ) 688 mpImpl->mpTextEngine->IdleFormatAndUpdate( this ); 689 else 690 mpImpl->mpTextEngine->FormatAndUpdate( this); 691 } 692 else if ( bMoved ) 693 { 694 // selection is painted now in ImpMoveCursor 695 ImpShowCursor( mpImpl->mbAutoScroll, true, bEndKey ); 696 } 697 698 if ( mpImpl->mpTextEngine->IsModified() ) 699 mpImpl->mpTextEngine->Broadcast( TextHint( SfxHintId::TextModified ) ); 700 else if ( bWasModified ) 701 mpImpl->mpTextEngine->SetModified( true ); 702 703 return bDone; 704 } 705 706 void TextView::MouseButtonUp( const MouseEvent& rMouseEvent ) 707 { 708 mpImpl->mbClickedInSelection = false; 709 mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW; 710 mpImpl->mpSelEngine->SelMouseButtonUp( rMouseEvent ); 711 if ( rMouseEvent.IsMiddle() && !IsReadOnly() && 712 ( GetWindow()->GetSettings().GetMouseSettings().GetMiddleButtonAction() == MouseMiddleButtonAction::PasteSelection ) ) 713 { 714 css::uno::Reference<css::datatransfer::clipboard::XClipboard> aSelection(GetWindow()->GetPrimarySelection()); 715 Paste( aSelection ); 716 if ( mpImpl->mpTextEngine->IsModified() ) 717 mpImpl->mpTextEngine->Broadcast( TextHint( SfxHintId::TextModified ) ); 718 } 719 else if ( rMouseEvent.IsLeft() && GetSelection().HasRange() ) 720 { 721 css::uno::Reference<css::datatransfer::clipboard::XClipboard> aSelection(GetWindow()->GetPrimarySelection()); 722 Copy( aSelection ); 723 } 724 } 725 726 void TextView::MouseButtonDown( const MouseEvent& rMouseEvent ) 727 { 728 mpImpl->mpTextEngine->CheckIdleFormatter(); // for fast typing and MouseButtonDown 729 mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW; 730 mpImpl->mbClickedInSelection = IsSelectionAtPoint( rMouseEvent.GetPosPixel() ); 731 732 mpImpl->mpTextEngine->SetActiveView( this ); 733 734 mpImpl->mpSelEngine->SelMouseButtonDown( rMouseEvent ); 735 736 // mbu 20.01.2005 - SelMouseButtonDown() possibly triggers a 'selection changed' 737 // notification. The appropriate handler could change the current selection, 738 // which is the case in the MailMerge address block control. To enable select'n'drag 739 // we need to reevaluate the selection after the notification has been fired. 740 mpImpl->mbClickedInSelection = IsSelectionAtPoint( rMouseEvent.GetPosPixel() ); 741 742 // special cases 743 if ( !rMouseEvent.IsShift() && ( rMouseEvent.GetClicks() >= 2 ) ) 744 { 745 if ( rMouseEvent.IsMod2() ) 746 { 747 HideSelection(); 748 ImpSetSelection( mpImpl->maSelection.GetEnd() ); 749 SetCursorAtPoint( rMouseEvent.GetPosPixel() ); // not set by SelectionEngine for MOD2 750 } 751 752 if ( rMouseEvent.GetClicks() == 2 ) 753 { 754 // select word 755 if ( mpImpl->maSelection.GetEnd().GetIndex() < mpImpl->mpTextEngine->GetTextLen( mpImpl->maSelection.GetEnd().GetPara() ) ) 756 { 757 HideSelection(); 758 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes()[ mpImpl->maSelection.GetEnd().GetPara() ].get(); 759 css::uno::Reference < css::i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator(); 760 css::i18n::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), mpImpl->maSelection.GetEnd().GetIndex(), mpImpl->mpTextEngine->GetLocale(), css::i18n::WordType::ANYWORD_IGNOREWHITESPACES, true ); 761 TextSelection aNewSel( mpImpl->maSelection ); 762 aNewSel.GetStart().GetIndex() = aBoundary.startPos; 763 aNewSel.GetEnd().GetIndex() = aBoundary.endPos; 764 if(mpImpl->mbSupportProtectAttribute) 765 { 766 //expand selection to include all protected content - if there is any 767 const TextCharAttrib* pStartAttr = mpImpl->mpTextEngine->FindCharAttrib( 768 TextPaM(aNewSel.GetStart().GetPara(), aBoundary.startPos), 769 TEXTATTR_PROTECTED ); 770 const TextCharAttrib* pEndAttr = mpImpl->mpTextEngine->FindCharAttrib( 771 TextPaM(aNewSel.GetEnd().GetPara(), aBoundary.endPos), 772 TEXTATTR_PROTECTED ); 773 if(pStartAttr && pStartAttr->GetStart() < aNewSel.GetStart().GetIndex()) 774 { 775 aNewSel.GetStart().GetIndex() = pStartAttr->GetStart(); 776 } 777 if(pEndAttr && pEndAttr->GetEnd() > aNewSel.GetEnd().GetIndex()) 778 { 779 aNewSel.GetEnd().GetIndex() = pEndAttr->GetEnd(); 780 } 781 } 782 ImpSetSelection( aNewSel ); 783 ShowSelection(); 784 ShowCursor(); 785 } 786 } 787 else if ( rMouseEvent.GetClicks() == 3 ) 788 { 789 // select paragraph 790 if ( mpImpl->maSelection.GetStart().GetIndex() || ( mpImpl->maSelection.GetEnd().GetIndex() < mpImpl->mpTextEngine->GetTextLen( mpImpl->maSelection.GetEnd().GetPara() ) ) ) 791 { 792 HideSelection(); 793 TextSelection aNewSel( mpImpl->maSelection ); 794 aNewSel.GetStart().GetIndex() = 0; 795 aNewSel.GetEnd().GetIndex() = mpImpl->mpTextEngine->mpDoc->GetNodes()[ mpImpl->maSelection.GetEnd().GetPara() ]->GetText().getLength(); 796 ImpSetSelection( aNewSel ); 797 ShowSelection(); 798 ShowCursor(); 799 } 800 } 801 } 802 } 803 804 void TextView::MouseMove( const MouseEvent& rMouseEvent ) 805 { 806 mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW; 807 mpImpl->mpSelEngine->SelMouseMove( rMouseEvent ); 808 } 809 810 void TextView::Command( const CommandEvent& rCEvt ) 811 { 812 mpImpl->mpTextEngine->CheckIdleFormatter(); // for fast typing and MouseButtonDown 813 mpImpl->mpTextEngine->SetActiveView( this ); 814 815 if ( rCEvt.GetCommand() == CommandEventId::StartExtTextInput ) 816 { 817 DeleteSelected(); 818 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes()[ GetSelection().GetEnd().GetPara() ].get(); 819 mpImpl->mpTextEngine->mpIMEInfos = std::make_unique<TEIMEInfos>( GetSelection().GetEnd(), pNode->GetText().copy( GetSelection().GetEnd().GetIndex() ) ); 820 mpImpl->mpTextEngine->mpIMEInfos->bWasCursorOverwrite = !IsInsertMode(); 821 } 822 else if ( rCEvt.GetCommand() == CommandEventId::EndExtTextInput ) 823 { 824 SAL_WARN_IF( !mpImpl->mpTextEngine->mpIMEInfos, "vcl", "CommandEventId::EndExtTextInput => No Start ?" ); 825 if( mpImpl->mpTextEngine->mpIMEInfos ) 826 { 827 TEParaPortion* pPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetPara() ); 828 pPortion->MarkSelectionInvalid( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetIndex() ); 829 830 bool bInsertMode = !mpImpl->mpTextEngine->mpIMEInfos->bWasCursorOverwrite; 831 832 mpImpl->mpTextEngine->mpIMEInfos.reset(); 833 834 mpImpl->mpTextEngine->TextModified(); 835 mpImpl->mpTextEngine->FormatAndUpdate( this ); 836 837 SetInsertMode( bInsertMode ); 838 839 if ( mpImpl->mpTextEngine->IsModified() ) 840 mpImpl->mpTextEngine->Broadcast( TextHint( SfxHintId::TextModified ) ); 841 } 842 } 843 else if ( rCEvt.GetCommand() == CommandEventId::ExtTextInput ) 844 { 845 SAL_WARN_IF( !mpImpl->mpTextEngine->mpIMEInfos, "vcl", "CommandEventId::ExtTextInput => No Start ?" ); 846 if( mpImpl->mpTextEngine->mpIMEInfos ) 847 { 848 const CommandExtTextInputData* pData = rCEvt.GetExtTextInputData(); 849 850 if ( !pData->IsOnlyCursorChanged() ) 851 { 852 TextSelection aSelect( mpImpl->mpTextEngine->mpIMEInfos->aPos ); 853 aSelect.GetEnd().GetIndex() += mpImpl->mpTextEngine->mpIMEInfos->nLen; 854 aSelect = mpImpl->mpTextEngine->ImpDeleteText( aSelect ); 855 aSelect = mpImpl->mpTextEngine->ImpInsertText( aSelect, pData->GetText() ); 856 857 if ( mpImpl->mpTextEngine->mpIMEInfos->bWasCursorOverwrite ) 858 { 859 const sal_Int32 nOldIMETextLen = mpImpl->mpTextEngine->mpIMEInfos->nLen; 860 const sal_Int32 nNewIMETextLen = pData->GetText().getLength(); 861 862 if ( ( nOldIMETextLen > nNewIMETextLen ) && 863 ( nNewIMETextLen < mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.getLength() ) ) 864 { 865 // restore old characters 866 sal_Int32 nRestore = nOldIMETextLen - nNewIMETextLen; 867 TextPaM aPaM( mpImpl->mpTextEngine->mpIMEInfos->aPos ); 868 aPaM.GetIndex() += nNewIMETextLen; 869 mpImpl->mpTextEngine->ImpInsertText( aPaM, mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.copy( nNewIMETextLen, nRestore ) ); 870 } 871 else if ( ( nOldIMETextLen < nNewIMETextLen ) && 872 ( nOldIMETextLen < mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.getLength() ) ) 873 { 874 // overwrite 875 const sal_Int32 nOverwrite = std::min( nNewIMETextLen, mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.getLength() ) - nOldIMETextLen; 876 SAL_WARN_IF( !nOverwrite || (nOverwrite >= 0xFF00), "vcl", "IME Overwrite?!" ); 877 TextPaM aPaM( mpImpl->mpTextEngine->mpIMEInfos->aPos ); 878 aPaM.GetIndex() += nNewIMETextLen; 879 TextSelection aSel( aPaM ); 880 aSel.GetEnd().GetIndex() += nOverwrite; 881 mpImpl->mpTextEngine->ImpDeleteText( aSel ); 882 } 883 } 884 885 if ( pData->GetTextAttr() ) 886 { 887 mpImpl->mpTextEngine->mpIMEInfos->CopyAttribs( pData->GetTextAttr(), pData->GetText().getLength() ); 888 } 889 else 890 { 891 mpImpl->mpTextEngine->mpIMEInfos->DestroyAttribs(); 892 } 893 894 TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetPara() ); 895 pPPortion->MarkSelectionInvalid( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetIndex() ); 896 mpImpl->mpTextEngine->FormatAndUpdate( this ); 897 } 898 899 TextSelection aNewSel = TextPaM( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetPara(), mpImpl->mpTextEngine->mpIMEInfos->aPos.GetIndex()+pData->GetCursorPos() ); 900 SetSelection( aNewSel ); 901 SetInsertMode( !pData->IsCursorOverwrite() ); 902 903 if ( pData->IsCursorVisible() ) 904 ShowCursor(); 905 else 906 HideCursor(); 907 } 908 } 909 else if ( rCEvt.GetCommand() == CommandEventId::CursorPos ) 910 { 911 if ( mpImpl->mpTextEngine->mpIMEInfos && mpImpl->mpTextEngine->mpIMEInfos->nLen ) 912 { 913 TextPaM aPaM( GetSelection().GetEnd() ); 914 tools::Rectangle aR1 = mpImpl->mpTextEngine->PaMtoEditCursor( aPaM ); 915 916 sal_Int32 nInputEnd = mpImpl->mpTextEngine->mpIMEInfos->aPos.GetIndex() + mpImpl->mpTextEngine->mpIMEInfos->nLen; 917 918 if ( !mpImpl->mpTextEngine->IsFormatted() ) 919 mpImpl->mpTextEngine->FormatDoc(); 920 921 TEParaPortion* pParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() ); 922 std::vector<TextLine>::size_type nLine = pParaPortion->GetLineNumber( aPaM.GetIndex(), true ); 923 TextLine& rLine = pParaPortion->GetLines()[ nLine ]; 924 if ( nInputEnd > rLine.GetEnd() ) 925 nInputEnd = rLine.GetEnd(); 926 tools::Rectangle aR2 = mpImpl->mpTextEngine->PaMtoEditCursor( TextPaM( aPaM.GetPara(), nInputEnd ) ); 927 928 long nWidth = aR2.Left()-aR1.Right(); 929 aR1.Move( -GetStartDocPos().X(), -GetStartDocPos().Y() ); 930 GetWindow()->SetCursorRect( &aR1, nWidth ); 931 } 932 else 933 { 934 GetWindow()->SetCursorRect(); 935 } 936 } 937 else 938 { 939 mpImpl->mpSelEngine->Command( rCEvt ); 940 } 941 } 942 943 void TextView::ShowCursor( bool bGotoCursor, bool bForceVisCursor ) 944 { 945 // this setting has more weight 946 if ( !mpImpl->mbAutoScroll ) 947 bGotoCursor = false; 948 ImpShowCursor( bGotoCursor, bForceVisCursor, false ); 949 } 950 951 void TextView::HideCursor() 952 { 953 mpImpl->mpCursor->Hide(); 954 } 955 956 void TextView::Scroll( long ndX, long ndY ) 957 { 958 SAL_WARN_IF( !mpImpl->mpTextEngine->IsFormatted(), "vcl", "Scroll: Not formatted!" ); 959 960 if ( !ndX && !ndY ) 961 return; 962 963 Point aNewStartPos( mpImpl->maStartDocPos ); 964 965 // Vertical: 966 aNewStartPos.AdjustY( -ndY ); 967 if ( aNewStartPos.Y() < 0 ) 968 aNewStartPos.setY( 0 ); 969 970 // Horizontal: 971 aNewStartPos.AdjustX( -ndX ); 972 if ( aNewStartPos.X() < 0 ) 973 aNewStartPos.setX( 0 ); 974 975 long nDiffX = mpImpl->maStartDocPos.X() - aNewStartPos.X(); 976 long nDiffY = mpImpl->maStartDocPos.Y() - aNewStartPos.Y(); 977 978 if ( nDiffX || nDiffY ) 979 { 980 bool bVisCursor = mpImpl->mpCursor->IsVisible(); 981 mpImpl->mpCursor->Hide(); 982 mpImpl->mpWindow->Update(); 983 mpImpl->maStartDocPos = aNewStartPos; 984 985 if ( mpImpl->mpTextEngine->IsRightToLeft() ) 986 nDiffX = -nDiffX; 987 mpImpl->mpWindow->Scroll( nDiffX, nDiffY ); 988 mpImpl->mpWindow->Update(); 989 mpImpl->mpCursor->SetPos( mpImpl->mpCursor->GetPos() + Point( nDiffX, nDiffY ) ); 990 if ( bVisCursor && !mpImpl->mbReadOnly ) 991 mpImpl->mpCursor->Show(); 992 } 993 994 mpImpl->mpTextEngine->Broadcast( TextHint( SfxHintId::TextViewScrolled ) ); 995 } 996 997 void TextView::Undo() 998 { 999 mpImpl->mpTextEngine->SetActiveView( this ); 1000 mpImpl->mpTextEngine->GetUndoManager().Undo(); 1001 } 1002 1003 void TextView::Redo() 1004 { 1005 mpImpl->mpTextEngine->SetActiveView( this ); 1006 mpImpl->mpTextEngine->GetUndoManager().Redo(); 1007 } 1008 1009 void TextView::Cut() 1010 { 1011 mpImpl->mpTextEngine->UndoActionStart(); 1012 Copy(); 1013 DeleteSelected(); 1014 mpImpl->mpTextEngine->UndoActionEnd(); 1015 } 1016 1017 void TextView::Copy( css::uno::Reference< css::datatransfer::clipboard::XClipboard > const & rxClipboard ) 1018 { 1019 if ( rxClipboard.is() ) 1020 { 1021 TETextDataObject* pDataObj = new TETextDataObject( GetSelected() ); 1022 1023 SolarMutexReleaser aReleaser; 1024 1025 try 1026 { 1027 rxClipboard->setContents( pDataObj, nullptr ); 1028 1029 css::uno::Reference< css::datatransfer::clipboard::XFlushableClipboard > xFlushableClipboard( rxClipboard, css::uno::UNO_QUERY ); 1030 if( xFlushableClipboard.is() ) 1031 xFlushableClipboard->flushClipboard(); 1032 } 1033 catch( const css::uno::Exception& ) 1034 { 1035 } 1036 } 1037 } 1038 1039 void TextView::Copy() 1040 { 1041 css::uno::Reference<css::datatransfer::clipboard::XClipboard> aClipboard(GetWindow()->GetClipboard()); 1042 Copy( aClipboard ); 1043 } 1044 1045 void TextView::Paste( css::uno::Reference< css::datatransfer::clipboard::XClipboard > const & rxClipboard ) 1046 { 1047 if ( rxClipboard.is() ) 1048 { 1049 css::uno::Reference< css::datatransfer::XTransferable > xDataObj; 1050 1051 try 1052 { 1053 SolarMutexReleaser aReleaser; 1054 xDataObj = rxClipboard->getContents(); 1055 } 1056 catch( const css::uno::Exception& ) 1057 { 1058 } 1059 1060 if ( xDataObj.is() ) 1061 { 1062 css::datatransfer::DataFlavor aFlavor; 1063 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING, aFlavor ); 1064 if ( xDataObj->isDataFlavorSupported( aFlavor ) ) 1065 { 1066 try 1067 { 1068 css::uno::Any aData = xDataObj->getTransferData( aFlavor ); 1069 OUString aText; 1070 aData >>= aText; 1071 bool bWasTruncated = false; 1072 if( mpImpl->mpTextEngine->GetMaxTextLen() != 0 ) 1073 bWasTruncated = ImplTruncateNewText( aText ); 1074 InsertText( aText ); 1075 mpImpl->mpTextEngine->Broadcast( TextHint( SfxHintId::TextModified ) ); 1076 1077 if( bWasTruncated ) 1078 Edit::ShowTruncationWarning(mpImpl->mpWindow->GetFrameWeld()); 1079 } 1080 catch( const css::datatransfer::UnsupportedFlavorException& ) 1081 { 1082 } 1083 } 1084 } 1085 } 1086 } 1087 1088 void TextView::Paste() 1089 { 1090 css::uno::Reference<css::datatransfer::clipboard::XClipboard> aClipboard(GetWindow()->GetClipboard()); 1091 Paste( aClipboard ); 1092 } 1093 1094 OUString TextView::GetSelected() 1095 { 1096 return GetSelected( GetSystemLineEnd() ); 1097 } 1098 1099 OUString TextView::GetSelected( LineEnd aSeparator ) 1100 { 1101 return mpImpl->mpTextEngine->GetText( mpImpl->maSelection, aSeparator ); 1102 } 1103 1104 void TextView::SetInsertMode( bool bInsert ) 1105 { 1106 if ( mpImpl->mbInsertMode != bInsert ) 1107 { 1108 mpImpl->mbInsertMode = bInsert; 1109 ShowCursor( mpImpl->mbAutoScroll, false ); 1110 } 1111 } 1112 1113 void TextView::SetReadOnly( bool bReadOnly ) 1114 { 1115 if ( mpImpl->mbReadOnly != bReadOnly ) 1116 { 1117 mpImpl->mbReadOnly = bReadOnly; 1118 if ( !mpImpl->mbReadOnly ) 1119 ShowCursor( mpImpl->mbAutoScroll, false ); 1120 else 1121 HideCursor(); 1122 1123 GetWindow()->SetInputContext( InputContext( mpImpl->mpTextEngine->GetFont(), bReadOnly ? InputContextFlags::Text|InputContextFlags::ExtText : InputContextFlags::NONE ) ); 1124 } 1125 } 1126 1127 TextSelection const & TextView::ImpMoveCursor( const KeyEvent& rKeyEvent ) 1128 { 1129 // normally only needed for Up/Down; but who cares 1130 mpImpl->mpTextEngine->CheckIdleFormatter(); 1131 1132 TextPaM aPaM( mpImpl->maSelection.GetEnd() ); 1133 TextPaM aOldEnd( aPaM ); 1134 1135 TextDirectionality eTextDirection = TextDirectionality::LeftToRight_TopToBottom; 1136 if ( mpImpl->mpTextEngine->IsRightToLeft() ) 1137 eTextDirection = TextDirectionality::RightToLeft_TopToBottom; 1138 1139 KeyEvent aTranslatedKeyEvent = rKeyEvent.LogicalTextDirectionality( eTextDirection ); 1140 1141 bool bCtrl = aTranslatedKeyEvent.GetKeyCode().IsMod1(); 1142 sal_uInt16 nCode = aTranslatedKeyEvent.GetKeyCode().GetCode(); 1143 1144 bool bSelect = aTranslatedKeyEvent.GetKeyCode().IsShift(); 1145 switch ( nCode ) 1146 { 1147 case KEY_UP: aPaM = CursorUp( aPaM ); 1148 break; 1149 case KEY_DOWN: aPaM = CursorDown( aPaM ); 1150 break; 1151 case KEY_HOME: aPaM = bCtrl ? CursorStartOfDoc() : CursorStartOfLine( aPaM ); 1152 break; 1153 case KEY_END: aPaM = bCtrl ? CursorEndOfDoc() : CursorEndOfLine( aPaM ); 1154 break; 1155 case KEY_PAGEUP: aPaM = bCtrl ? CursorStartOfDoc() : PageUp( aPaM ); 1156 break; 1157 case KEY_PAGEDOWN: aPaM = bCtrl ? CursorEndOfDoc() : PageDown( aPaM ); 1158 break; 1159 case KEY_LEFT: aPaM = bCtrl ? CursorWordLeft( aPaM ) : CursorLeft( aPaM, aTranslatedKeyEvent.GetKeyCode().IsMod2() ? sal_uInt16(css::i18n::CharacterIteratorMode::SKIPCHARACTER) : sal_uInt16(css::i18n::CharacterIteratorMode::SKIPCELL) ); 1160 break; 1161 case KEY_RIGHT: aPaM = bCtrl ? CursorWordRight( aPaM ) : CursorRight( aPaM, aTranslatedKeyEvent.GetKeyCode().IsMod2() ? sal_uInt16(css::i18n::CharacterIteratorMode::SKIPCHARACTER) : sal_uInt16(css::i18n::CharacterIteratorMode::SKIPCELL) ); 1162 break; 1163 case css::awt::Key::SELECT_WORD_FORWARD: 1164 bSelect = true; 1165 [[fallthrough]]; 1166 case css::awt::Key::MOVE_WORD_FORWARD: 1167 aPaM = CursorWordRight( aPaM ); 1168 break; 1169 case css::awt::Key::SELECT_WORD_BACKWARD: 1170 bSelect = true; 1171 [[fallthrough]]; 1172 case css::awt::Key::MOVE_WORD_BACKWARD: 1173 aPaM = CursorWordLeft( aPaM ); 1174 break; 1175 case css::awt::Key::SELECT_TO_BEGIN_OF_LINE: 1176 bSelect = true; 1177 [[fallthrough]]; 1178 case css::awt::Key::MOVE_TO_BEGIN_OF_LINE: 1179 aPaM = CursorStartOfLine( aPaM ); 1180 break; 1181 case css::awt::Key::SELECT_TO_END_OF_LINE: 1182 bSelect = true; 1183 [[fallthrough]]; 1184 case css::awt::Key::MOVE_TO_END_OF_LINE: 1185 aPaM = CursorEndOfLine( aPaM ); 1186 break; 1187 case css::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH: 1188 bSelect = true; 1189 [[fallthrough]]; 1190 case css::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH: 1191 aPaM = CursorStartOfParagraph( aPaM ); 1192 break; 1193 case css::awt::Key::SELECT_TO_END_OF_PARAGRAPH: 1194 bSelect = true; 1195 [[fallthrough]]; 1196 case css::awt::Key::MOVE_TO_END_OF_PARAGRAPH: 1197 aPaM = CursorEndOfParagraph( aPaM ); 1198 break; 1199 case css::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT: 1200 bSelect = true; 1201 [[fallthrough]]; 1202 case css::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT: 1203 aPaM = CursorStartOfDoc(); 1204 break; 1205 case css::awt::Key::SELECT_TO_END_OF_DOCUMENT: 1206 bSelect = true; 1207 [[fallthrough]]; 1208 case css::awt::Key::MOVE_TO_END_OF_DOCUMENT: 1209 aPaM = CursorEndOfDoc(); 1210 break; 1211 } 1212 1213 // might cause a CreateAnchor or Deselection all 1214 mpImpl->mpSelEngine->CursorPosChanging( bSelect, aTranslatedKeyEvent.GetKeyCode().IsMod1() ); 1215 1216 if ( aOldEnd != aPaM ) 1217 { 1218 mpImpl->mpTextEngine->CursorMoved( aOldEnd.GetPara() ); 1219 1220 TextSelection aNewSelection( mpImpl->maSelection ); 1221 aNewSelection.GetEnd() = aPaM; 1222 if ( bSelect ) 1223 { 1224 // extend the selection 1225 ImpSetSelection( aNewSelection ); 1226 ShowSelection( TextSelection( aOldEnd, aPaM ) ); 1227 } 1228 else 1229 { 1230 aNewSelection.GetStart() = aPaM; 1231 ImpSetSelection( aNewSelection ); 1232 } 1233 } 1234 1235 return mpImpl->maSelection; 1236 } 1237 1238 void TextView::InsertText( const OUString& rStr ) 1239 { 1240 mpImpl->mpTextEngine->UndoActionStart(); 1241 1242 TextSelection aNewSel = mpImpl->mpTextEngine->ImpInsertText( mpImpl->maSelection, rStr ); 1243 1244 ImpSetSelection( aNewSel ); 1245 1246 mpImpl->mpTextEngine->UndoActionEnd(); 1247 1248 mpImpl->mpTextEngine->FormatAndUpdate( this ); 1249 } 1250 1251 TextPaM TextView::CursorLeft( const TextPaM& rPaM, sal_uInt16 nCharacterIteratorMode ) 1252 { 1253 TextPaM aPaM( rPaM ); 1254 1255 if ( aPaM.GetIndex() ) 1256 { 1257 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes()[ aPaM.GetPara() ].get(); 1258 css::uno::Reference < css::i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator(); 1259 sal_Int32 nCount = 1; 1260 aPaM.GetIndex() = xBI->previousCharacters( pNode->GetText(), aPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), nCharacterIteratorMode, nCount, nCount ); 1261 } 1262 else if ( aPaM.GetPara() ) 1263 { 1264 aPaM.GetPara()--; 1265 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes()[ aPaM.GetPara() ].get(); 1266 aPaM.GetIndex() = pNode->GetText().getLength(); 1267 } 1268 return aPaM; 1269 } 1270 1271 TextPaM TextView::CursorRight( const TextPaM& rPaM, sal_uInt16 nCharacterIteratorMode ) 1272 { 1273 TextPaM aPaM( rPaM ); 1274 1275 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes()[ aPaM.GetPara() ].get(); 1276 if ( aPaM.GetIndex() < pNode->GetText().getLength() ) 1277 { 1278 css::uno::Reference < css::i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator(); 1279 sal_Int32 nCount = 1; 1280 aPaM.GetIndex() = xBI->nextCharacters( pNode->GetText(), aPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), nCharacterIteratorMode, nCount, nCount ); 1281 } 1282 else if ( aPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().size()-1) ) 1283 { 1284 aPaM.GetPara()++; 1285 aPaM.GetIndex() = 0; 1286 } 1287 1288 return aPaM; 1289 } 1290 1291 TextPaM TextView::CursorWordLeft( const TextPaM& rPaM ) 1292 { 1293 TextPaM aPaM( rPaM ); 1294 1295 if ( aPaM.GetIndex() ) 1296 { 1297 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes()[ aPaM.GetPara() ].get(); 1298 css::uno::Reference < css::i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator(); 1299 css::i18n::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), rPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), css::i18n::WordType::ANYWORD_IGNOREWHITESPACES, true ); 1300 if ( aBoundary.startPos >= rPaM.GetIndex() ) 1301 aBoundary = xBI->previousWord( pNode->GetText(), rPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), css::i18n::WordType::ANYWORD_IGNOREWHITESPACES ); 1302 aPaM.GetIndex() = ( aBoundary.startPos != -1 ) ? aBoundary.startPos : 0; 1303 } 1304 else if ( aPaM.GetPara() ) 1305 { 1306 aPaM.GetPara()--; 1307 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes()[ aPaM.GetPara() ].get(); 1308 aPaM.GetIndex() = pNode->GetText().getLength(); 1309 } 1310 return aPaM; 1311 } 1312 1313 TextPaM TextView::CursorWordRight( const TextPaM& rPaM ) 1314 { 1315 TextPaM aPaM( rPaM ); 1316 1317 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes()[ aPaM.GetPara() ].get(); 1318 if ( aPaM.GetIndex() < pNode->GetText().getLength() ) 1319 { 1320 css::uno::Reference < css::i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator(); 1321 css::i18n::Boundary aBoundary = xBI->nextWord( pNode->GetText(), aPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), css::i18n::WordType::ANYWORD_IGNOREWHITESPACES ); 1322 aPaM.GetIndex() = aBoundary.startPos; 1323 } 1324 else if ( aPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().size()-1) ) 1325 { 1326 aPaM.GetPara()++; 1327 aPaM.GetIndex() = 0; 1328 } 1329 1330 return aPaM; 1331 } 1332 1333 TextPaM TextView::ImpDelete( sal_uInt8 nMode, sal_uInt8 nDelMode ) 1334 { 1335 if ( mpImpl->maSelection.HasRange() ) // only delete selection 1336 return mpImpl->mpTextEngine->ImpDeleteText( mpImpl->maSelection ); 1337 1338 TextPaM aStartPaM = mpImpl->maSelection.GetStart(); 1339 TextPaM aEndPaM = aStartPaM; 1340 if ( nMode == DEL_LEFT ) 1341 { 1342 if ( nDelMode == DELMODE_SIMPLE ) 1343 { 1344 aEndPaM = CursorLeft( aEndPaM, sal_uInt16(css::i18n::CharacterIteratorMode::SKIPCHARACTER) ); 1345 } 1346 else if ( nDelMode == DELMODE_RESTOFWORD ) 1347 { 1348 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes()[ aEndPaM.GetPara() ].get(); 1349 css::uno::Reference < css::i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator(); 1350 css::i18n::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), mpImpl->maSelection.GetEnd().GetIndex(), mpImpl->mpTextEngine->GetLocale(), css::i18n::WordType::ANYWORD_IGNOREWHITESPACES, true ); 1351 if ( aBoundary.startPos == mpImpl->maSelection.GetEnd().GetIndex() ) 1352 aBoundary = xBI->previousWord( pNode->GetText(), mpImpl->maSelection.GetEnd().GetIndex(), mpImpl->mpTextEngine->GetLocale(), css::i18n::WordType::ANYWORD_IGNOREWHITESPACES ); 1353 // #i63506# startPos is -1 when the paragraph starts with a tab 1354 aEndPaM.GetIndex() = std::max<sal_Int32>(aBoundary.startPos, 0); 1355 } 1356 else // DELMODE_RESTOFCONTENT 1357 { 1358 if ( aEndPaM.GetIndex() != 0 ) 1359 aEndPaM.GetIndex() = 0; 1360 else if ( aEndPaM.GetPara() ) 1361 { 1362 // previous paragraph 1363 aEndPaM.GetPara()--; 1364 aEndPaM.GetIndex() = 0; 1365 } 1366 } 1367 } 1368 else 1369 { 1370 if ( nDelMode == DELMODE_SIMPLE ) 1371 { 1372 aEndPaM = CursorRight( aEndPaM, sal_uInt16(css::i18n::CharacterIteratorMode::SKIPCELL) ); 1373 } 1374 else if ( nDelMode == DELMODE_RESTOFWORD ) 1375 { 1376 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes()[ aEndPaM.GetPara() ].get(); 1377 css::uno::Reference < css::i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator(); 1378 css::i18n::Boundary aBoundary = xBI->nextWord( pNode->GetText(), mpImpl->maSelection.GetEnd().GetIndex(), mpImpl->mpTextEngine->GetLocale(), css::i18n::WordType::ANYWORD_IGNOREWHITESPACES ); 1379 aEndPaM.GetIndex() = aBoundary.startPos; 1380 } 1381 else // DELMODE_RESTOFCONTENT 1382 { 1383 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes()[ aEndPaM.GetPara() ].get(); 1384 if ( aEndPaM.GetIndex() < pNode->GetText().getLength() ) 1385 aEndPaM.GetIndex() = pNode->GetText().getLength(); 1386 else if ( aEndPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().size() - 1 ) ) 1387 { 1388 // next paragraph 1389 aEndPaM.GetPara()++; 1390 TextNode* pNextNode = mpImpl->mpTextEngine->mpDoc->GetNodes()[ aEndPaM.GetPara() ].get(); 1391 aEndPaM.GetIndex() = pNextNode->GetText().getLength(); 1392 } 1393 } 1394 } 1395 1396 return mpImpl->mpTextEngine->ImpDeleteText( TextSelection( aStartPaM, aEndPaM ) ); 1397 } 1398 1399 TextPaM TextView::CursorUp( const TextPaM& rPaM ) 1400 { 1401 TextPaM aPaM( rPaM ); 1402 1403 long nX; 1404 if ( mpImpl->mnTravelXPos == TRAVEL_X_DONTKNOW ) 1405 { 1406 nX = mpImpl->mpTextEngine->GetEditCursor( rPaM, false ).Left(); 1407 mpImpl->mnTravelXPos = static_cast<sal_uInt16>(nX)+1; 1408 } 1409 else 1410 nX = mpImpl->mnTravelXPos; 1411 1412 TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() ); 1413 std::vector<TextLine>::size_type nLine = pPPortion->GetLineNumber( rPaM.GetIndex(), false ); 1414 if ( nLine ) // same paragraph 1415 { 1416 aPaM.GetIndex() = mpImpl->mpTextEngine->GetCharPos( rPaM.GetPara(), nLine-1, nX ); 1417 // If we need to go to the end of a line that was wrapped automatically, 1418 // the cursor ends up at the beginning of the 2nd line 1419 // Problem: Last character of an automatically wrapped line = Cursor 1420 TextLine& rLine = pPPortion->GetLines()[ nLine - 1 ]; 1421 if ( aPaM.GetIndex() && ( aPaM.GetIndex() == rLine.GetEnd() ) ) 1422 --aPaM.GetIndex(); 1423 } 1424 else if ( rPaM.GetPara() ) // previous paragraph 1425 { 1426 aPaM.GetPara()--; 1427 pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() ); 1428 std::vector<TextLine>::size_type nL = pPPortion->GetLines().size() - 1; 1429 aPaM.GetIndex() = mpImpl->mpTextEngine->GetCharPos( aPaM.GetPara(), nL, nX+1 ); 1430 } 1431 1432 return aPaM; 1433 } 1434 1435 TextPaM TextView::CursorDown( const TextPaM& rPaM ) 1436 { 1437 TextPaM aPaM( rPaM ); 1438 1439 long nX; 1440 if ( mpImpl->mnTravelXPos == TRAVEL_X_DONTKNOW ) 1441 { 1442 nX = mpImpl->mpTextEngine->GetEditCursor( rPaM, false ).Left(); 1443 mpImpl->mnTravelXPos = static_cast<sal_uInt16>(nX)+1; 1444 } 1445 else 1446 nX = mpImpl->mnTravelXPos; 1447 1448 TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() ); 1449 std::vector<TextLine>::size_type nLine = pPPortion->GetLineNumber( rPaM.GetIndex(), false ); 1450 if ( nLine < ( pPPortion->GetLines().size() - 1 ) ) 1451 { 1452 aPaM.GetIndex() = mpImpl->mpTextEngine->GetCharPos( rPaM.GetPara(), nLine+1, nX ); 1453 1454 // special case CursorUp 1455 TextLine& rLine = pPPortion->GetLines()[ nLine + 1 ]; 1456 if ( ( aPaM.GetIndex() == rLine.GetEnd() ) && ( aPaM.GetIndex() > rLine.GetStart() ) && aPaM.GetIndex() < pPPortion->GetNode()->GetText().getLength() ) 1457 --aPaM.GetIndex(); 1458 } 1459 else if ( rPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().size() - 1 ) ) // next paragraph 1460 { 1461 aPaM.GetPara()++; 1462 pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() ); 1463 aPaM.GetIndex() = mpImpl->mpTextEngine->GetCharPos( aPaM.GetPara(), 0, nX+1 ); 1464 TextLine& rLine = pPPortion->GetLines().front(); 1465 if ( ( aPaM.GetIndex() == rLine.GetEnd() ) && ( aPaM.GetIndex() > rLine.GetStart() ) && ( pPPortion->GetLines().size() > 1 ) ) 1466 --aPaM.GetIndex(); 1467 } 1468 1469 return aPaM; 1470 } 1471 1472 TextPaM TextView::CursorStartOfLine( const TextPaM& rPaM ) 1473 { 1474 TextPaM aPaM( rPaM ); 1475 1476 TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() ); 1477 std::vector<TextLine>::size_type nLine = pPPortion->GetLineNumber( aPaM.GetIndex(), false ); 1478 TextLine& rLine = pPPortion->GetLines()[ nLine ]; 1479 aPaM.GetIndex() = rLine.GetStart(); 1480 1481 return aPaM; 1482 } 1483 1484 TextPaM TextView::CursorEndOfLine( const TextPaM& rPaM ) 1485 { 1486 TextPaM aPaM( rPaM ); 1487 1488 TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() ); 1489 std::vector<TextLine>::size_type nLine = pPPortion->GetLineNumber( aPaM.GetIndex(), false ); 1490 TextLine& rLine = pPPortion->GetLines()[ nLine ]; 1491 aPaM.GetIndex() = rLine.GetEnd(); 1492 1493 if ( rLine.GetEnd() > rLine.GetStart() ) // empty line 1494 { 1495 sal_Unicode cLastChar = pPPortion->GetNode()->GetText()[ aPaM.GetIndex()-1 ]; 1496 if ( ( cLastChar == ' ' ) && ( aPaM.GetIndex() != pPPortion->GetNode()->GetText().getLength() ) ) 1497 { 1498 // for a blank in an automatically-wrapped line it is better to stand before it, 1499 // as the user will intend to stand behind the prior word. 1500 // If there is a change, special case for Pos1 after End! 1501 --aPaM.GetIndex(); 1502 } 1503 } 1504 return aPaM; 1505 } 1506 1507 TextPaM TextView::CursorStartOfParagraph( const TextPaM& rPaM ) 1508 { 1509 TextPaM aPaM( rPaM ); 1510 aPaM.GetIndex() = 0; 1511 return aPaM; 1512 } 1513 1514 TextPaM TextView::CursorEndOfParagraph( const TextPaM& rPaM ) 1515 { 1516 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes()[ rPaM.GetPara() ].get(); 1517 TextPaM aPaM( rPaM ); 1518 aPaM.GetIndex() = pNode->GetText().getLength(); 1519 return aPaM; 1520 } 1521 1522 TextPaM TextView::CursorStartOfDoc() 1523 { 1524 TextPaM aPaM( 0, 0 ); 1525 return aPaM; 1526 } 1527 1528 TextPaM TextView::CursorEndOfDoc() 1529 { 1530 const sal_uInt32 nNode = static_cast<sal_uInt32>(mpImpl->mpTextEngine->mpDoc->GetNodes().size() - 1); 1531 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes()[ nNode ].get(); 1532 TextPaM aPaM( nNode, pNode->GetText().getLength() ); 1533 return aPaM; 1534 } 1535 1536 TextPaM TextView::PageUp( const TextPaM& rPaM ) 1537 { 1538 tools::Rectangle aRect = mpImpl->mpTextEngine->PaMtoEditCursor( rPaM ); 1539 Point aTopLeft = aRect.TopLeft(); 1540 aTopLeft.AdjustY( -(mpImpl->mpWindow->GetOutputSizePixel().Height() * 9/10) ); 1541 aTopLeft.AdjustX(1 ); 1542 if ( aTopLeft.Y() < 0 ) 1543 aTopLeft.setY( 0 ); 1544 1545 TextPaM aPaM = mpImpl->mpTextEngine->GetPaM( aTopLeft ); 1546 return aPaM; 1547 } 1548 1549 TextPaM TextView::PageDown( const TextPaM& rPaM ) 1550 { 1551 tools::Rectangle aRect = mpImpl->mpTextEngine->PaMtoEditCursor( rPaM ); 1552 Point aBottomRight = aRect.BottomRight(); 1553 aBottomRight.AdjustY(mpImpl->mpWindow->GetOutputSizePixel().Height() * 9/10 ); 1554 aBottomRight.AdjustX(1 ); 1555 long nHeight = mpImpl->mpTextEngine->GetTextHeight(); 1556 if ( aBottomRight.Y() > nHeight ) 1557 aBottomRight.setY( nHeight-1 ); 1558 1559 TextPaM aPaM = mpImpl->mpTextEngine->GetPaM( aBottomRight ); 1560 return aPaM; 1561 } 1562 1563 void TextView::ImpShowCursor( bool bGotoCursor, bool bForceVisCursor, bool bSpecial ) 1564 { 1565 if ( mpImpl->mpTextEngine->IsFormatting() ) 1566 return; 1567 if ( !mpImpl->mpTextEngine->GetUpdateMode() ) 1568 return; 1569 if ( mpImpl->mpTextEngine->IsInUndo() ) 1570 return; 1571 1572 mpImpl->mpTextEngine->CheckIdleFormatter(); 1573 if ( !mpImpl->mpTextEngine->IsFormatted() ) 1574 mpImpl->mpTextEngine->FormatAndUpdate( this ); 1575 1576 TextPaM aPaM( mpImpl->maSelection.GetEnd() ); 1577 tools::Rectangle aEditCursor = mpImpl->mpTextEngine->PaMtoEditCursor( aPaM, bSpecial ); 1578 1579 // Remember that we placed the cursor behind the last character of a line 1580 mpImpl->mbCursorAtEndOfLine = false; 1581 if( bSpecial ) 1582 { 1583 TEParaPortion* pParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() ); 1584 mpImpl->mbCursorAtEndOfLine = 1585 pParaPortion->GetLineNumber( aPaM.GetIndex(), true ) != pParaPortion->GetLineNumber( aPaM.GetIndex(), false ); 1586 } 1587 1588 if ( !IsInsertMode() && !mpImpl->maSelection.HasRange() ) 1589 { 1590 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes()[ aPaM.GetPara() ].get(); 1591 if ( !pNode->GetText().isEmpty() && ( aPaM.GetIndex() < pNode->GetText().getLength() ) ) 1592 { 1593 // If we are behind a portion, and the next portion has other direction, we must change position... 1594 aEditCursor.SetLeft( mpImpl->mpTextEngine->GetEditCursor( aPaM, false, true ).Left() ); 1595 aEditCursor.SetRight( aEditCursor.Left() ); 1596 1597 TEParaPortion* pParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() ); 1598 1599 sal_Int32 nTextPortionStart = 0; 1600 std::size_t nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nTextPortionStart, true ); 1601 TETextPortion* pTextPortion = pParaPortion->GetTextPortions()[ nTextPortion ]; 1602 if ( pTextPortion->GetKind() == PORTIONKIND_TAB ) 1603 { 1604 aEditCursor.AdjustRight(pTextPortion->GetWidth() ); 1605 } 1606 else 1607 { 1608 TextPaM aNext = CursorRight( TextPaM( aPaM.GetPara(), aPaM.GetIndex() ), sal_uInt16(css::i18n::CharacterIteratorMode::SKIPCELL) ); 1609 aEditCursor.SetRight( mpImpl->mpTextEngine->GetEditCursor( aNext, true ).Left() ); 1610 } 1611 } 1612 } 1613 1614 Size aOutSz = mpImpl->mpWindow->GetOutputSizePixel(); 1615 if ( aEditCursor.GetHeight() > aOutSz.Height() ) 1616 aEditCursor.SetBottom( aEditCursor.Top() + aOutSz.Height() - 1 ); 1617 1618 aEditCursor.AdjustLeft( -1 ); 1619 1620 if ( bGotoCursor 1621 // #i81283# protect maStartDocPos against initialization problems 1622 && aOutSz.Width() && aOutSz.Height() 1623 ) 1624 { 1625 long nVisStartY = mpImpl->maStartDocPos.Y(); 1626 long nVisEndY = mpImpl->maStartDocPos.Y() + aOutSz.Height(); 1627 long nVisStartX = mpImpl->maStartDocPos.X(); 1628 long nVisEndX = mpImpl->maStartDocPos.X() + aOutSz.Width(); 1629 long nMoreX = aOutSz.Width() / 4; 1630 1631 Point aNewStartPos( mpImpl->maStartDocPos ); 1632 1633 if ( aEditCursor.Bottom() > nVisEndY ) 1634 { 1635 aNewStartPos.AdjustY( aEditCursor.Bottom() - nVisEndY); 1636 } 1637 else if ( aEditCursor.Top() < nVisStartY ) 1638 { 1639 aNewStartPos.AdjustY( -( nVisStartY - aEditCursor.Top() ) ); 1640 } 1641 1642 if ( aEditCursor.Right() >= nVisEndX ) 1643 { 1644 aNewStartPos.AdjustX( aEditCursor.Right() - nVisEndX ); 1645 1646 // do you want some more? 1647 aNewStartPos.AdjustX(nMoreX ); 1648 } 1649 else if ( aEditCursor.Left() <= nVisStartX ) 1650 { 1651 aNewStartPos.AdjustX( -( nVisStartX - aEditCursor.Left() ) ); 1652 1653 // do you want some more? 1654 aNewStartPos.AdjustX( -nMoreX ); 1655 } 1656 1657 // X can be wrong for the 'some more' above: 1658 // sal_uLong nMaxTextWidth = mpImpl->mpTextEngine->GetMaxTextWidth(); 1659 // if ( !nMaxTextWidth || ( nMaxTextWidth > 0x7FFFFFFF ) ) 1660 // nMaxTextWidth = 0x7FFFFFFF; 1661 // long nMaxX = (long)nMaxTextWidth - aOutSz.Width(); 1662 long nMaxX = mpImpl->mpTextEngine->CalcTextWidth() - aOutSz.Width(); 1663 if ( nMaxX < 0 ) 1664 nMaxX = 0; 1665 1666 if ( aNewStartPos.X() < 0 ) 1667 aNewStartPos.setX( 0 ); 1668 else if ( aNewStartPos.X() > nMaxX ) 1669 aNewStartPos.setX( nMaxX ); 1670 1671 // Y should not be further down than needed 1672 long nYMax = mpImpl->mpTextEngine->GetTextHeight() - aOutSz.Height(); 1673 if ( nYMax < 0 ) 1674 nYMax = 0; 1675 if ( aNewStartPos.Y() > nYMax ) 1676 aNewStartPos.setY( nYMax ); 1677 1678 if ( aNewStartPos != mpImpl->maStartDocPos ) 1679 Scroll( -(aNewStartPos.X() - mpImpl->maStartDocPos.X()), -(aNewStartPos.Y() - mpImpl->maStartDocPos.Y()) ); 1680 } 1681 1682 if ( aEditCursor.Right() < aEditCursor.Left() ) 1683 { 1684 long n = aEditCursor.Left(); 1685 aEditCursor.SetLeft( aEditCursor.Right() ); 1686 aEditCursor.SetRight( n ); 1687 } 1688 1689 Point aPoint( GetWindowPos( !mpImpl->mpTextEngine->IsRightToLeft() ? aEditCursor.TopLeft() : aEditCursor.TopRight() ) ); 1690 mpImpl->mpCursor->SetPos( aPoint ); 1691 mpImpl->mpCursor->SetSize( aEditCursor.GetSize() ); 1692 if ( bForceVisCursor && mpImpl->mbCursorEnabled ) 1693 mpImpl->mpCursor->Show(); 1694 } 1695 1696 void TextView::SetCursorAtPoint( const Point& rPosPixel ) 1697 { 1698 mpImpl->mpTextEngine->CheckIdleFormatter(); 1699 1700 Point aDocPos = GetDocPos( rPosPixel ); 1701 1702 TextPaM aPaM = mpImpl->mpTextEngine->GetPaM( aDocPos ); 1703 1704 // aTmpNewSel: Diff between old and new; not the new selection 1705 TextSelection aTmpNewSel( mpImpl->maSelection.GetEnd(), aPaM ); 1706 TextSelection aNewSel( mpImpl->maSelection ); 1707 aNewSel.GetEnd() = aPaM; 1708 1709 if ( !mpImpl->mpSelEngine->HasAnchor() ) 1710 { 1711 if ( mpImpl->maSelection.GetStart() != aPaM ) 1712 mpImpl->mpTextEngine->CursorMoved( mpImpl->maSelection.GetStart().GetPara() ); 1713 aNewSel.GetStart() = aPaM; 1714 ImpSetSelection( aNewSel ); 1715 } 1716 else 1717 { 1718 ImpSetSelection( aNewSel ); 1719 ShowSelection( aTmpNewSel ); 1720 } 1721 1722 bool bForceCursor = !mpImpl->mpDDInfo; // && !mbInSelection 1723 ImpShowCursor( mpImpl->mbAutoScroll, bForceCursor, false ); 1724 } 1725 1726 bool TextView::IsSelectionAtPoint( const Point& rPosPixel ) 1727 { 1728 Point aDocPos = GetDocPos( rPosPixel ); 1729 TextPaM aPaM = mpImpl->mpTextEngine->GetPaM( aDocPos ); 1730 // BeginDrag is only called, however, if IsSelectionAtPoint() 1731 // Problem: IsSelectionAtPoint is not called by Command() 1732 // if before MBDown returned false. 1733 return IsInSelection( aPaM ); 1734 } 1735 1736 bool TextView::IsInSelection( const TextPaM& rPaM ) 1737 { 1738 TextSelection aSel = mpImpl->maSelection; 1739 aSel.Justify(); 1740 1741 const sal_uInt32 nStartNode = aSel.GetStart().GetPara(); 1742 const sal_uInt32 nEndNode = aSel.GetEnd().GetPara(); 1743 const sal_uInt32 nCurNode = rPaM.GetPara(); 1744 1745 if ( ( nCurNode > nStartNode ) && ( nCurNode < nEndNode ) ) 1746 return true; 1747 1748 if ( nStartNode == nEndNode ) 1749 { 1750 if ( nCurNode == nStartNode ) 1751 if ( ( rPaM.GetIndex() >= aSel.GetStart().GetIndex() ) && ( rPaM.GetIndex() < aSel.GetEnd().GetIndex() ) ) 1752 return true; 1753 } 1754 else if ( ( nCurNode == nStartNode ) && ( rPaM.GetIndex() >= aSel.GetStart().GetIndex() ) ) 1755 return true; 1756 else if ( ( nCurNode == nEndNode ) && ( rPaM.GetIndex() < aSel.GetEnd().GetIndex() ) ) 1757 return true; 1758 1759 return false; 1760 } 1761 1762 void TextView::ImpHideDDCursor() 1763 { 1764 if ( mpImpl->mpDDInfo && mpImpl->mpDDInfo->mbVisCursor ) 1765 { 1766 mpImpl->mpDDInfo->maCursor.Hide(); 1767 mpImpl->mpDDInfo->mbVisCursor = false; 1768 } 1769 } 1770 1771 void TextView::ImpShowDDCursor() 1772 { 1773 if ( !mpImpl->mpDDInfo->mbVisCursor ) 1774 { 1775 tools::Rectangle aCursor = mpImpl->mpTextEngine->PaMtoEditCursor( mpImpl->mpDDInfo->maDropPos, true ); 1776 aCursor.AdjustRight( 1 ); 1777 aCursor.SetPos( GetWindowPos( aCursor.TopLeft() ) ); 1778 1779 mpImpl->mpDDInfo->maCursor.SetWindow( mpImpl->mpWindow ); 1780 mpImpl->mpDDInfo->maCursor.SetPos( aCursor.TopLeft() ); 1781 mpImpl->mpDDInfo->maCursor.SetSize( aCursor.GetSize() ); 1782 mpImpl->mpDDInfo->maCursor.Show(); 1783 mpImpl->mpDDInfo->mbVisCursor = true; 1784 } 1785 } 1786 1787 void TextView::SetPaintSelection( bool bPaint ) 1788 { 1789 if ( bPaint != mpImpl->mbPaintSelection ) 1790 { 1791 mpImpl->mbPaintSelection = bPaint; 1792 ShowSelection( mpImpl->maSelection ); 1793 } 1794 } 1795 1796 void TextView::Read( SvStream& rInput ) 1797 { 1798 mpImpl->mpTextEngine->Read( rInput, &mpImpl->maSelection ); 1799 ShowCursor(); 1800 } 1801 1802 bool TextView::ImplTruncateNewText( OUString& rNewText ) const 1803 { 1804 bool bTruncated = false; 1805 1806 const sal_Int32 nMaxLen = mpImpl->mpTextEngine->GetMaxTextLen(); 1807 // 0 means unlimited 1808 if( nMaxLen != 0 ) 1809 { 1810 const sal_Int32 nCurLen = mpImpl->mpTextEngine->GetTextLen(); 1811 1812 const sal_Int32 nNewLen = rNewText.getLength(); 1813 if ( nCurLen + nNewLen > nMaxLen ) 1814 { 1815 // see how much text will be replaced 1816 const sal_Int32 nSelLen = mpImpl->mpTextEngine->GetTextLen( mpImpl->maSelection ); 1817 if ( nCurLen + nNewLen - nSelLen > nMaxLen ) 1818 { 1819 const sal_Int32 nTruncatedLen = nMaxLen - (nCurLen - nSelLen); 1820 rNewText = rNewText.copy( 0, nTruncatedLen ); 1821 bTruncated = true; 1822 } 1823 } 1824 } 1825 return bTruncated; 1826 } 1827 1828 bool TextView::ImplCheckTextLen( const OUString& rNewText ) 1829 { 1830 bool bOK = true; 1831 if ( mpImpl->mpTextEngine->GetMaxTextLen() ) 1832 { 1833 sal_Int32 n = mpImpl->mpTextEngine->GetTextLen() + rNewText.getLength(); 1834 if ( n > mpImpl->mpTextEngine->GetMaxTextLen() ) 1835 { 1836 // calculate how much text is being deleted 1837 n -= mpImpl->mpTextEngine->GetTextLen( mpImpl->maSelection ); 1838 if ( n > mpImpl->mpTextEngine->GetMaxTextLen() ) 1839 bOK = false; 1840 } 1841 } 1842 return bOK; 1843 } 1844 1845 void TextView::dragGestureRecognized( const css::datatransfer::dnd::DragGestureEvent& rDGE ) 1846 { 1847 if ( mpImpl->mbClickedInSelection ) 1848 { 1849 SolarMutexGuard aVclGuard; 1850 1851 SAL_WARN_IF( !mpImpl->maSelection.HasRange(), "vcl", "TextView::dragGestureRecognized: mpImpl->mbClickedInSelection, but no selection?" ); 1852 1853 mpImpl->mpDDInfo.reset(new TextDDInfo); 1854 mpImpl->mpDDInfo->mbStarterOfDD = true; 1855 1856 TETextDataObject* pDataObj = new TETextDataObject( GetSelected() ); 1857 1858 mpImpl->mpCursor->Hide(); 1859 1860 sal_Int8 nActions = css::datatransfer::dnd::DNDConstants::ACTION_COPY; 1861 if ( !IsReadOnly() ) 1862 nActions |= css::datatransfer::dnd::DNDConstants::ACTION_MOVE; 1863 rDGE.DragSource->startDrag( rDGE, nActions, 0 /*cursor*/, 0 /*image*/, pDataObj, mpImpl->mxDnDListener ); 1864 } 1865 } 1866 1867 void TextView::dragDropEnd( const css::datatransfer::dnd::DragSourceDropEvent& ) 1868 { 1869 ImpHideDDCursor(); 1870 mpImpl->mpDDInfo.reset(); 1871 } 1872 1873 void TextView::drop( const css::datatransfer::dnd::DropTargetDropEvent& rDTDE ) 1874 { 1875 SolarMutexGuard aVclGuard; 1876 1877 if ( !mpImpl->mbReadOnly && mpImpl->mpDDInfo ) 1878 { 1879 ImpHideDDCursor(); 1880 1881 // Data for deleting after DROP_MOVE: 1882 TextSelection aPrevSel( mpImpl->maSelection ); 1883 aPrevSel.Justify(); 1884 const sal_uInt32 nPrevParaCount = mpImpl->mpTextEngine->GetParagraphCount(); 1885 const sal_Int32 nPrevStartParaLen = mpImpl->mpTextEngine->GetTextLen( aPrevSel.GetStart().GetPara() ); 1886 1887 bool bStarterOfDD = false; 1888 for ( sal_uInt16 nView = mpImpl->mpTextEngine->GetViewCount(); nView && !bStarterOfDD; ) 1889 bStarterOfDD = mpImpl->mpTextEngine->GetView( --nView )->mpImpl->mpDDInfo && mpImpl->mpTextEngine->GetView( nView )->mpImpl->mpDDInfo->mbStarterOfDD; 1890 1891 HideSelection(); 1892 ImpSetSelection( mpImpl->mpDDInfo->maDropPos ); 1893 1894 mpImpl->mpTextEngine->UndoActionStart(); 1895 1896 OUString aText; 1897 css::uno::Reference< css::datatransfer::XTransferable > xDataObj = rDTDE.Transferable; 1898 if ( xDataObj.is() ) 1899 { 1900 css::datatransfer::DataFlavor aFlavor; 1901 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING, aFlavor ); 1902 if ( xDataObj->isDataFlavorSupported( aFlavor ) ) 1903 { 1904 css::uno::Any aData = xDataObj->getTransferData( aFlavor ); 1905 OUString aOUString; 1906 aData >>= aOUString; 1907 aText = convertLineEnd(aOUString, LINEEND_LF); 1908 } 1909 } 1910 1911 if ( !aText.isEmpty() && ( aText[ aText.getLength()-1 ] == LINE_SEP ) ) 1912 aText = aText.copy(0, aText.getLength()-1); 1913 1914 TextPaM aTempStart = mpImpl->maSelection.GetStart(); 1915 if ( ImplCheckTextLen( aText ) ) 1916 ImpSetSelection( mpImpl->mpTextEngine->ImpInsertText( mpImpl->mpDDInfo->maDropPos, aText ) ); 1917 if(mpImpl->mbSupportProtectAttribute) 1918 { 1919 mpImpl->mpTextEngine->SetAttrib( TextAttribProtect(), 1920 aTempStart.GetPara(), 1921 aTempStart.GetIndex(), 1922 mpImpl->maSelection.GetEnd().GetIndex(), false ); 1923 } 1924 1925 if ( aPrevSel.HasRange() && 1926 !mpImpl->mbSupportProtectAttribute && // don't remove currently selected element 1927 (( rDTDE.DropAction & css::datatransfer::dnd::DNDConstants::ACTION_MOVE ) || !bStarterOfDD) ) 1928 { 1929 // adjust selection if necessary 1930 if ( ( mpImpl->mpDDInfo->maDropPos.GetPara() < aPrevSel.GetStart().GetPara() ) || 1931 ( ( mpImpl->mpDDInfo->maDropPos.GetPara() == aPrevSel.GetStart().GetPara() ) 1932 && ( mpImpl->mpDDInfo->maDropPos.GetIndex() < aPrevSel.GetStart().GetIndex() ) ) ) 1933 { 1934 const sal_uInt32 nNewParasBeforeSelection = 1935 mpImpl->mpTextEngine->GetParagraphCount() - nPrevParaCount; 1936 1937 aPrevSel.GetStart().GetPara() += nNewParasBeforeSelection; 1938 aPrevSel.GetEnd().GetPara() += nNewParasBeforeSelection; 1939 1940 if ( mpImpl->mpDDInfo->maDropPos.GetPara() == aPrevSel.GetStart().GetPara() ) 1941 { 1942 const sal_Int32 nNewChars = 1943 mpImpl->mpTextEngine->GetTextLen( aPrevSel.GetStart().GetPara() ) - nPrevStartParaLen; 1944 1945 aPrevSel.GetStart().GetIndex() += nNewChars; 1946 if ( aPrevSel.GetStart().GetPara() == aPrevSel.GetEnd().GetPara() ) 1947 aPrevSel.GetEnd().GetIndex() += nNewChars; 1948 } 1949 } 1950 else 1951 { 1952 // adjust current selection 1953 TextPaM aPaM = mpImpl->maSelection.GetStart(); 1954 aPaM.GetPara() -= ( aPrevSel.GetEnd().GetPara() - aPrevSel.GetStart().GetPara() ); 1955 if ( aPrevSel.GetEnd().GetPara() == mpImpl->mpDDInfo->maDropPos.GetPara() ) 1956 { 1957 aPaM.GetIndex() -= aPrevSel.GetEnd().GetIndex(); 1958 if ( aPrevSel.GetStart().GetPara() == mpImpl->mpDDInfo->maDropPos.GetPara() ) 1959 aPaM.GetIndex() += aPrevSel.GetStart().GetIndex(); 1960 } 1961 ImpSetSelection( aPaM ); 1962 1963 } 1964 mpImpl->mpTextEngine->ImpDeleteText( aPrevSel ); 1965 } 1966 1967 mpImpl->mpTextEngine->UndoActionEnd(); 1968 1969 mpImpl->mpDDInfo.reset(); 1970 1971 mpImpl->mpTextEngine->FormatAndUpdate( this ); 1972 1973 mpImpl->mpTextEngine->Broadcast( TextHint( SfxHintId::TextModified ) ); 1974 } 1975 rDTDE.Context->dropComplete( false/*bChanges*/ ); 1976 } 1977 1978 void TextView::dragEnter( const css::datatransfer::dnd::DropTargetDragEnterEvent& ) 1979 { 1980 } 1981 1982 void TextView::dragExit( const css::datatransfer::dnd::DropTargetEvent& ) 1983 { 1984 SolarMutexGuard aVclGuard; 1985 ImpHideDDCursor(); 1986 } 1987 1988 void TextView::dragOver( const css::datatransfer::dnd::DropTargetDragEvent& rDTDE ) 1989 { 1990 SolarMutexGuard aVclGuard; 1991 1992 if (!mpImpl->mpDDInfo) 1993 mpImpl->mpDDInfo.reset(new TextDDInfo); 1994 1995 TextPaM aPrevDropPos = mpImpl->mpDDInfo->maDropPos; 1996 Point aMousePos( rDTDE.LocationX, rDTDE.LocationY ); 1997 Point aDocPos = GetDocPos( aMousePos ); 1998 mpImpl->mpDDInfo->maDropPos = mpImpl->mpTextEngine->GetPaM( aDocPos ); 1999 2000 bool bProtected = false; 2001 if(mpImpl->mbSupportProtectAttribute) 2002 { 2003 const TextCharAttrib* pStartAttr = mpImpl->mpTextEngine->FindCharAttrib( 2004 mpImpl->mpDDInfo->maDropPos, 2005 TEXTATTR_PROTECTED ); 2006 bProtected = pStartAttr != nullptr && 2007 pStartAttr->GetStart() != mpImpl->mpDDInfo->maDropPos.GetIndex() && 2008 pStartAttr->GetEnd() != mpImpl->mpDDInfo->maDropPos.GetIndex(); 2009 } 2010 // Don't drop in selection or in read only engine 2011 if ( IsReadOnly() || IsInSelection( mpImpl->mpDDInfo->maDropPos ) || bProtected) 2012 { 2013 ImpHideDDCursor(); 2014 rDTDE.Context->rejectDrag(); 2015 } 2016 else 2017 { 2018 // delete old Cursor 2019 if ( !mpImpl->mpDDInfo->mbVisCursor || ( aPrevDropPos != mpImpl->mpDDInfo->maDropPos ) ) 2020 { 2021 ImpHideDDCursor(); 2022 ImpShowDDCursor(); 2023 } 2024 rDTDE.Context->acceptDrag( rDTDE.DropAction ); 2025 } 2026 } 2027 2028 Point TextView::ImpGetOutputStartPos( const Point& rStartDocPos ) const 2029 { 2030 Point aStartPos( -rStartDocPos.X(), -rStartDocPos.Y() ); 2031 if ( mpImpl->mpTextEngine->IsRightToLeft() ) 2032 { 2033 Size aSz = mpImpl->mpWindow->GetOutputSizePixel(); 2034 aStartPos.setX( rStartDocPos.X() + aSz.Width() - 1 ); // -1: Start is 0 2035 } 2036 return aStartPos; 2037 } 2038 2039 Point TextView::GetDocPos( const Point& rWindowPos ) const 2040 { 2041 // Window Position => Document Position 2042 2043 Point aPoint; 2044 2045 aPoint.setY( rWindowPos.Y() + mpImpl->maStartDocPos.Y() ); 2046 2047 if ( !mpImpl->mpTextEngine->IsRightToLeft() ) 2048 { 2049 aPoint.setX( rWindowPos.X() + mpImpl->maStartDocPos.X() ); 2050 } 2051 else 2052 { 2053 Size aSz = mpImpl->mpWindow->GetOutputSizePixel(); 2054 aPoint.setX( ( aSz.Width() - 1 ) - rWindowPos.X() + mpImpl->maStartDocPos.X() ); 2055 } 2056 2057 return aPoint; 2058 } 2059 2060 Point TextView::GetWindowPos( const Point& rDocPos ) const 2061 { 2062 // Document Position => Window Position 2063 2064 Point aPoint; 2065 2066 aPoint.setY( rDocPos.Y() - mpImpl->maStartDocPos.Y() ); 2067 2068 if ( !mpImpl->mpTextEngine->IsRightToLeft() ) 2069 { 2070 aPoint.setX( rDocPos.X() - mpImpl->maStartDocPos.X() ); 2071 } 2072 else 2073 { 2074 Size aSz = mpImpl->mpWindow->GetOutputSizePixel(); 2075 aPoint.setX( ( aSz.Width() - 1 ) - ( rDocPos.X() - mpImpl->maStartDocPos.X() ) ); 2076 } 2077 2078 return aPoint; 2079 } 2080 2081 sal_Int32 TextView::GetLineNumberOfCursorInSelection() const 2082 { 2083 // PROGRESS 2084 sal_Int32 nLineNo = -1; 2085 if( mpImpl->mbCursorEnabled ) 2086 { 2087 TextPaM aPaM = GetSelection().GetEnd(); 2088 TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() ); 2089 nLineNo = pPPortion->GetLineNumber( aPaM.GetIndex(), false ); 2090 //TODO: std::vector<TextLine>::size_type -> sal_Int32! 2091 if( mpImpl->mbCursorAtEndOfLine ) 2092 --nLineNo; 2093 } 2094 return nLineNo; 2095 } 2096 2097 // (+) class TextSelFunctionSet 2098 2099 TextSelFunctionSet::TextSelFunctionSet( TextView* pView ) 2100 { 2101 mpView = pView; 2102 } 2103 2104 void TextSelFunctionSet::BeginDrag() 2105 { 2106 } 2107 2108 void TextSelFunctionSet::CreateAnchor() 2109 { 2110 // TextSelection aSel( mpView->GetSelection() ); 2111 // aSel.GetStart() = aSel.GetEnd(); 2112 // mpView->SetSelection( aSel ); 2113 2114 // may not be followed by ShowCursor 2115 mpView->HideSelection(); 2116 mpView->ImpSetSelection( mpView->mpImpl->maSelection.GetEnd() ); 2117 } 2118 2119 void TextSelFunctionSet::SetCursorAtPoint( const Point& rPointPixel, bool ) 2120 { 2121 mpView->SetCursorAtPoint( rPointPixel ); 2122 } 2123 2124 bool TextSelFunctionSet::IsSelectionAtPoint( const Point& rPointPixel ) 2125 { 2126 return mpView->IsSelectionAtPoint( rPointPixel ); 2127 } 2128 2129 void TextSelFunctionSet::DeselectAll() 2130 { 2131 CreateAnchor(); 2132 } 2133 2134 void TextSelFunctionSet::DeselectAtPoint( const Point& ) 2135 { 2136 // only for multiple selection 2137 } 2138 2139 void TextSelFunctionSet::DestroyAnchor() 2140 { 2141 // only for multiple selection 2142 } 2143 TextEngine* TextView::GetTextEngine() const 2144 { return mpImpl->mpTextEngine; } 2145 vcl::Window* TextView::GetWindow() const 2146 { return mpImpl->mpWindow; } 2147 void TextView::EnableCursor( bool bEnable ) 2148 { mpImpl->mbCursorEnabled = bEnable; } 2149 bool TextView::IsCursorEnabled() const 2150 { return mpImpl->mbCursorEnabled; } 2151 void TextView::SetStartDocPos( const Point& rPos ) 2152 { mpImpl->maStartDocPos = rPos; } 2153 const Point& TextView::GetStartDocPos() const 2154 { return mpImpl->maStartDocPos; } 2155 void TextView::SetAutoIndentMode( bool bAutoIndent ) 2156 { mpImpl->mbAutoIndent = bAutoIndent; } 2157 bool TextView::IsReadOnly() const 2158 { return mpImpl->mbReadOnly; } 2159 void TextView::SetAutoScroll( bool bAutoScroll ) 2160 { mpImpl->mbAutoScroll = bAutoScroll; } 2161 bool TextView::IsAutoScroll() const 2162 { return mpImpl->mbAutoScroll; } 2163 bool TextView::HasSelection() const 2164 { return mpImpl->maSelection.HasRange(); } 2165 bool TextView::IsInsertMode() const 2166 { return mpImpl->mbInsertMode; } 2167 2168 void TextView::MatchGroup() 2169 { 2170 TextSelection aTmpSel( GetSelection() ); 2171 aTmpSel.Justify(); 2172 if ( ( aTmpSel.GetStart().GetPara() != aTmpSel.GetEnd().GetPara() ) || 2173 ( ( aTmpSel.GetEnd().GetIndex() - aTmpSel.GetStart().GetIndex() ) > 1 ) ) 2174 { 2175 return; 2176 } 2177 2178 TextSelection aMatchSel = static_cast<ExtTextEngine*>(GetTextEngine())->MatchGroup( aTmpSel.GetStart() ); 2179 if ( aMatchSel.HasRange() ) 2180 SetSelection( aMatchSel ); 2181 } 2182 2183 void TextView::CenterPaM( const TextPaM& rPaM ) 2184 { 2185 // Get textview size and the corresponding y-coordinates 2186 Size aOutSz = mpImpl->mpWindow->GetOutputSizePixel(); 2187 long nVisStartY = mpImpl->maStartDocPos.Y(); 2188 long nVisEndY = mpImpl->maStartDocPos.Y() + aOutSz.Height(); 2189 2190 // Retrieve the coordinates of the PaM 2191 tools::Rectangle aRect = mpImpl->mpTextEngine->PaMtoEditCursor(rPaM); 2192 2193 // Recalculate the offset of the center y-coordinates and scroll 2194 Scroll(0, (nVisStartY + nVisEndY) / 2 - aRect.TopLeft().getY()); 2195 } 2196 2197 bool TextView::Search( const i18nutil::SearchOptions& rSearchOptions, bool bForward ) 2198 { 2199 bool bFound = false; 2200 TextSelection aSel( GetSelection() ); 2201 if ( static_cast<ExtTextEngine*>(GetTextEngine())->Search( aSel, rSearchOptions, bForward ) ) 2202 { 2203 bFound = true; 2204 // First add the beginning of the word to the selection, 2205 // so that the whole word is in the visible region. 2206 SetSelection( aSel.GetStart() ); 2207 ShowCursor( true, false ); 2208 } 2209 else 2210 { 2211 aSel = GetSelection().GetEnd(); 2212 } 2213 2214 SetSelection( aSel ); 2215 // tdf#49482: Move the start of the selection to the center of the textview 2216 if (bFound) 2217 { 2218 CenterPaM( aSel.GetStart() ); 2219 } 2220 ShowCursor(); 2221 2222 return bFound; 2223 } 2224 2225 sal_uInt16 TextView::Replace( const i18nutil::SearchOptions& rSearchOptions, bool bAll, bool bForward ) 2226 { 2227 sal_uInt16 nFound = 0; 2228 2229 if ( !bAll ) 2230 { 2231 if ( GetSelection().HasRange() ) 2232 { 2233 InsertText( rSearchOptions.replaceString ); 2234 nFound = 1; 2235 Search( rSearchOptions, bForward ); // right away to the next 2236 } 2237 else 2238 { 2239 if( Search( rSearchOptions, bForward ) ) 2240 nFound = 1; 2241 } 2242 } 2243 else 2244 { 2245 // the writer replaces all, from beginning to end 2246 2247 ExtTextEngine* pTextEngine = static_cast<ExtTextEngine*>(GetTextEngine()); 2248 2249 // HideSelection(); 2250 TextSelection aSel; 2251 2252 bool bSearchInSelection = (0 != (rSearchOptions.searchFlag & css::util::SearchFlags::REG_NOT_BEGINOFLINE) ); 2253 if ( bSearchInSelection ) 2254 { 2255 aSel = GetSelection(); 2256 aSel.Justify(); 2257 } 2258 2259 TextSelection aSearchSel( aSel ); 2260 2261 bool bFound = pTextEngine->Search( aSel, rSearchOptions ); 2262 if ( bFound ) 2263 pTextEngine->UndoActionStart(); 2264 while ( bFound ) 2265 { 2266 nFound++; 2267 2268 TextPaM aNewStart = pTextEngine->ImpInsertText( aSel, rSearchOptions.replaceString ); 2269 aSel = aSearchSel; 2270 aSel.GetStart() = aNewStart; 2271 bFound = pTextEngine->Search( aSel, rSearchOptions ); 2272 } 2273 if ( nFound ) 2274 { 2275 SetSelection( aSel.GetStart() ); 2276 pTextEngine->FormatAndUpdate( this ); 2277 pTextEngine->UndoActionEnd(); 2278 } 2279 } 2280 return nFound; 2281 } 2282 2283 bool TextView::ImpIndentBlock( bool bRight ) 2284 { 2285 bool bDone = false; 2286 2287 TextSelection aSel = GetSelection(); 2288 aSel.Justify(); 2289 2290 HideSelection(); 2291 GetTextEngine()->UndoActionStart(); 2292 2293 const sal_uInt32 nStartPara = aSel.GetStart().GetPara(); 2294 sal_uInt32 nEndPara = aSel.GetEnd().GetPara(); 2295 if ( aSel.HasRange() && !aSel.GetEnd().GetIndex() ) 2296 { 2297 nEndPara--; // do not indent 2298 } 2299 2300 for ( sal_uInt32 nPara = nStartPara; nPara <= nEndPara; ++nPara ) 2301 { 2302 if ( bRight ) 2303 { 2304 // add tabs 2305 GetTextEngine()->ImpInsertText( TextPaM( nPara, 0 ), '\t' ); 2306 bDone = true; 2307 } 2308 else 2309 { 2310 // remove Tabs/Blanks 2311 OUString aText = GetTextEngine()->GetText( nPara ); 2312 if ( !aText.isEmpty() && ( 2313 ( aText[ 0 ] == '\t' ) || 2314 ( aText[ 0 ] == ' ' ) ) ) 2315 { 2316 GetTextEngine()->ImpDeleteText( TextSelection( TextPaM( nPara, 0 ), TextPaM( nPara, 1 ) ) ); 2317 bDone = true; 2318 } 2319 } 2320 } 2321 2322 GetTextEngine()->UndoActionEnd(); 2323 2324 bool bRange = aSel.HasRange(); 2325 if ( bRight ) 2326 { 2327 ++aSel.GetStart().GetIndex(); 2328 if ( bRange && ( aSel.GetEnd().GetPara() == nEndPara ) ) 2329 ++aSel.GetEnd().GetIndex(); 2330 } 2331 else 2332 { 2333 if ( aSel.GetStart().GetIndex() ) 2334 --aSel.GetStart().GetIndex(); 2335 if ( bRange && aSel.GetEnd().GetIndex() ) 2336 --aSel.GetEnd().GetIndex(); 2337 } 2338 2339 ImpSetSelection( aSel ); 2340 GetTextEngine()->FormatAndUpdate( this ); 2341 2342 return bDone; 2343 } 2344 2345 bool TextView::IndentBlock() 2346 { 2347 return ImpIndentBlock( true ); 2348 } 2349 2350 bool TextView::UnindentBlock() 2351 { 2352 return ImpIndentBlock( false ); 2353 } 2354 2355 2356 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 2357
