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