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