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