Bug Summary

File:home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx
Warning:line 1437, column 5
Dereference of null pointer

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name impedit.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D EDITENG_DLLIMPLEMENTATION -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/editeng/inc -I /home/maarten/src/libreoffice/core/editeng/source/editeng -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/editeng/generated -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx
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 "impedit.hxx"
21#include <sal/log.hxx>
22#include <editeng/editeng.hxx>
23#include <editeng/editview.hxx>
24#include <editeng/outliner.hxx>
25#include <tools/poly.hxx>
26#include <editeng/unolingu.hxx>
27#include <com/sun/star/linguistic2/XDictionary.hpp>
28#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
29#include <com/sun/star/datatransfer/dnd/XDragGestureRecognizer.hpp>
30#include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>
31#include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp>
32#include <comphelper/lok.hxx>
33#include <editeng/flditem.hxx>
34#include <svl/intitem.hxx>
35#include <vcl/inputctx.hxx>
36#include <vcl/transfer.hxx>
37#include <vcl/svapp.hxx>
38#include <sot/exchange.hxx>
39#include <sot/formats.hxx>
40#include <LibreOfficeKit/LibreOfficeKitEnums.h>
41#include <comphelper/string.hxx>
42#include <sfx2/viewsh.hxx>
43#include <sfx2/lokhelper.hxx>
44#include <boost/property_tree/json_parser.hpp>
45
46using namespace ::com::sun::star;
47using namespace ::com::sun::star::uno;
48using namespace ::com::sun::star::linguistic2;
49
50#define SCRLRANGE20 20 // Scroll 1/20 of the width/height, when in QueryDrop
51
52static void lcl_AllignToPixel( Point& rPoint, OutputDevice const * pOutDev, short nDiffX, short nDiffY )
53{
54 rPoint = pOutDev->LogicToPixel( rPoint );
55
56 if ( nDiffX )
57 rPoint.AdjustX(nDiffX );
58 if ( nDiffY )
59 rPoint.AdjustY(nDiffY );
60
61 rPoint = pOutDev->PixelToLogic( rPoint );
62}
63
64LOKSpecialPositioning::LOKSpecialPositioning(const ImpEditView& rImpEditView, MapUnit eUnit,
65 const tools::Rectangle& rOutputArea,
66 const Point& rVisDocStartPos) :
67 mrImpEditView(rImpEditView),
68 maOutArea(rOutputArea),
69 maVisDocStartPos(rVisDocStartPos),
70 meUnit(eUnit)
71{
72}
73
74void LOKSpecialPositioning::ReInit(MapUnit eUnit, const tools::Rectangle& rOutputArea, const Point& rVisDocStartPos)
75{
76 meUnit = eUnit;
77 maOutArea = rOutputArea;
78 maVisDocStartPos = rVisDocStartPos;
79}
80
81void LOKSpecialPositioning::SetOutputArea(const tools::Rectangle& rOutputArea)
82{
83 maOutArea = rOutputArea;
84}
85
86const tools::Rectangle& LOKSpecialPositioning::GetOutputArea() const
87{
88 return maOutArea;
89}
90
91void LOKSpecialPositioning::SetVisDocStartPos(const Point& rVisDocStartPos)
92{
93 maVisDocStartPos = rVisDocStartPos;
94}
95
96tools::Rectangle LOKSpecialPositioning::GetVisDocArea() const
97{
98 return tools::Rectangle(GetVisDocLeft(), GetVisDocTop(), GetVisDocRight(), GetVisDocBottom());
99}
100
101bool LOKSpecialPositioning::IsVertical() const
102{
103 return mrImpEditView.IsVertical();
104}
105
106bool LOKSpecialPositioning::IsTopToBottom() const
107{
108 return mrImpEditView.IsTopToBottom();
109}
110
111Point LOKSpecialPositioning::GetWindowPos(const Point& rDocPos, MapUnit eDocPosUnit) const
112{
113 const Point aDocPos = convertUnit(rDocPos, eDocPosUnit);
114 Point aPoint;
115 if ( !IsVertical() )
116 {
117 aPoint.setX(aDocPos.X() + maOutArea.Left() - GetVisDocLeft());
118 aPoint.setY(aDocPos.Y() + maOutArea.Top() - GetVisDocTop());
119 }
120 else
121 {
122 if (IsTopToBottom())
123 {
124 aPoint.setX(maOutArea.Right() - aDocPos.Y() + GetVisDocTop());
125 aPoint.setY(aDocPos.X() + maOutArea.Top() - GetVisDocLeft());
126 }
127 else
128 {
129 aPoint.setX(maOutArea.Left() + aDocPos.Y() - GetVisDocTop());
130 aPoint.setY(maOutArea.Bottom() - aDocPos.X() + GetVisDocLeft());
131 }
132 }
133
134 return aPoint;
135}
136
137tools::Rectangle LOKSpecialPositioning::GetWindowPos(const tools::Rectangle& rDocRect, MapUnit eDocRectUnit) const
138{
139 const tools::Rectangle aDocRect = convertUnit(rDocRect, eDocRectUnit);
140 Point aPos(GetWindowPos(aDocRect.TopLeft(), meUnit));
141 Size aSz = aDocRect.GetSize();
142 tools::Rectangle aRect;
143 if (!IsVertical())
144 {
145 aRect = tools::Rectangle(aPos, aSz);
146 }
147 else
148 {
149 Point aNewPos(aPos.X() - aSz.Height(), aPos.Y());
150 // coverity[swapped_arguments : FALSE] - this is in the correct order
151 aRect = tools::Rectangle(aNewPos, Size(aSz.Height(), aSz.Width()));
152 }
153 return aRect;
154}
155
156Point LOKSpecialPositioning::convertUnit(const Point& rPos, MapUnit ePosUnit) const
157{
158 if (ePosUnit == meUnit)
159 return rPos;
160
161 return OutputDevice::LogicToLogic(rPos, MapMode(ePosUnit), MapMode(meUnit));
162}
163
164tools::Rectangle LOKSpecialPositioning::convertUnit(const tools::Rectangle& rRect, MapUnit eRectUnit) const
165{
166 if (eRectUnit == meUnit)
167 return rRect;
168
169 return OutputDevice::LogicToLogic(rRect, MapMode(eRectUnit), MapMode(meUnit));
170}
171
172Point LOKSpecialPositioning::GetRefPoint() const
173{
174 return maOutArea.TopLeft();
175}
176
177// class ImpEditView
178
179ImpEditView::ImpEditView( EditView* pView, EditEngine* pEng, vcl::Window* pWindow ) :
180 pEditView(pView),
181 mpViewShell(nullptr),
182 mpOtherShell(nullptr),
183 pEditEngine(pEng),
184 pOutWin(pWindow),
185 nInvMore(1),
186 nControl(EVControlBits::AUTOSCROLL | EVControlBits::ENABLEPASTE),
187 nTravelXPos(TRAVEL_X_DONTKNOW0xFFFFFFFF),
188 nExtraCursorFlags(GetCursorFlags::NONE),
189 nCursorBidiLevel(CURSOR_BIDILEVEL_DONTKNOW0xFFFF),
190 nScrollDiffX(0),
191 bReadOnly(false),
192 bClickedInSelection(false),
193 bActiveDragAndDropListener(false),
194 aOutArea( Point(), pEng->GetPaperSize() ),
195 eSelectionMode(EESelectionMode::Std),
196 eAnchorMode(EEAnchorMode::TopLeft),
197 mpEditViewCallbacks(nullptr),
198 mbBroadcastLOKViewCursor(comphelper::LibreOfficeKit::isActive()),
199 mbSuppressLOKMessages(false)
200{
201 aEditSelection.Min() = pEng->GetEditDoc().GetStartPaM();
202 aEditSelection.Max() = pEng->GetEditDoc().GetEndPaM();
203
204 SelectionChanged();
205}
206
207ImpEditView::~ImpEditView()
208{
209 RemoveDragAndDropListeners();
210
211 if ( pOutWin && ( pOutWin->GetCursor() == pCursor.get() ) )
212 pOutWin->SetCursor( nullptr );
213}
214
215void ImpEditView::SetBackgroundColor( const Color& rColor )
216{
217 pBackgroundColor.reset( new Color( rColor ) );
218}
219
220void ImpEditView::RegisterViewShell(OutlinerViewShell* pViewShell)
221{
222 mpViewShell = pViewShell;
223}
224
225void ImpEditView::RegisterOtherShell(OutlinerViewShell* pOtherShell)
226{
227 mpOtherShell = pOtherShell;
228}
229
230const OutlinerViewShell* ImpEditView::GetViewShell() const
231{
232 return mpViewShell;
233}
234
235void ImpEditView::SetEditSelection( const EditSelection& rEditSelection )
236{
237 // set state before notification
238 aEditSelection = rEditSelection;
239
240 SelectionChanged();
241
242 if (comphelper::LibreOfficeKit::isActive())
243 // Tiled rendering: selections are only painted when we are in selection mode.
244 pEditEngine->SetInSelectionMode(aEditSelection.HasRange());
245
246 if ( pEditEngine->pImpEditEngine->GetNotifyHdl().IsSet() )
247 {
248 const EditDoc& rDoc = pEditEngine->GetEditDoc();
249 const EditPaM pmEnd = rDoc.GetEndPaM();
250 EENotifyType eNotifyType;
251 if (rDoc.Count() > 1 &&
252 pmEnd == rEditSelection.Min() &&
253 pmEnd == rEditSelection.Max())//if move cursor to the last para.
254 {
255 eNotifyType = EE_NOTIFY_TEXTVIEWSELECTIONCHANGED_ENDD_PARA;
256 }
257 else
258 {
259 eNotifyType = EE_NOTIFY_TEXTVIEWSELECTIONCHANGED;
260 }
261 EENotify aNotify( eNotifyType );
262 pEditEngine->pImpEditEngine->GetNotifyHdl().Call( aNotify );
263 }
264 if(pEditEngine->pImpEditEngine->IsFormatted())
265 {
266 EENotify aNotify(EE_NOTIFY_PROCESSNOTIFICATIONS);
267 pEditEngine->pImpEditEngine->GetNotifyHdl().Call(aNotify);
268 }
269}
270
271/// Translate absolute <-> relative twips: LOK wants absolute coordinates as output and gives absolute coordinates as input.
272static void lcl_translateTwips(vcl::Window const & rParent, vcl::Window& rChild)
273{
274 // Don't translate if we already have a non-zero origin.
275 // This prevents multiple translate calls that negate
276 // one another.
277 const Point aOrigin = rChild.GetMapMode().GetOrigin();
278 if (aOrigin.getX() != 0 || aOrigin.getY() != 0)
279 return;
280
281 // Set map mode, so that callback payloads will contain absolute coordinates instead of relative ones.
282 Point aOffset(rChild.GetOutOffXPixel() - rParent.GetOutOffXPixel(), rChild.GetOutOffYPixel() - rParent.GetOutOffYPixel());
283 if (!rChild.IsMapModeEnabled())
284 {
285 MapMode aMapMode(rChild.GetMapMode());
286 aMapMode.SetMapUnit(MapUnit::MapTwip);
287 aMapMode.SetScaleX(rParent.GetMapMode().GetScaleX());
288 aMapMode.SetScaleY(rParent.GetMapMode().GetScaleY());
289 rChild.SetMapMode(aMapMode);
290 rChild.EnableMapMode();
291 }
292 aOffset = rChild.PixelToLogic(aOffset);
293 MapMode aMapMode(rChild.GetMapMode());
294 aMapMode.SetOrigin(aOffset);
295 aMapMode.SetMapUnit(rParent.GetMapMode().GetMapUnit());
296 rChild.SetMapMode(aMapMode);
297 rChild.EnableMapMode(false);
298}
299
300// EditView never had a central/secure place to react on SelectionChange since
301// Selection was changed in many places, often by not using SetEditSelection()
302// but (mis)using GetEditSelection() and manipulating this non-const return
303// value. Sorted this out now to have such a place, this is needed for safely
304// change/update the Selection visualization for enhanced mechanisms
305void ImpEditView::SelectionChanged()
306{
307 if (EditViewCallbacks* pCallbacks = getEditViewCallbacks())
308 {
309 // use callback to tell about change in selection visualisation
310 pCallbacks->EditViewSelectionChange();
311 }
312}
313
314// This function is also called when a text's font || size is changed. Because its highlight rectangle must be updated.
315void ImpEditView::lokSelectionCallback(const std::unique_ptr<tools::PolyPolygon> &pPolyPoly, bool bStartHandleVisible, bool bEndHandleVisible) {
316 VclPtr<vcl::Window> pParent = pOutWin->GetParentWithLOKNotifier();
317 vcl::Region aRegion( *pPolyPoly );
318
319 if (pParent && pParent->GetLOKWindowId() != 0)
320 {
321 const long nX = pOutWin->GetOutOffXPixel() - pParent->GetOutOffXPixel();
322 const long nY = pOutWin->GetOutOffYPixel() - pParent->GetOutOffYPixel();
323
324 std::vector<tools::Rectangle> aRectangles;
325 aRegion.GetRegionRectangles(aRectangles);
326
327 std::vector<OString> v;
328 for (tools::Rectangle & rRectangle : aRectangles)
329 {
330 rRectangle = pOutWin->LogicToPixel(rRectangle);
331 rRectangle.Move(nX, nY);
332 v.emplace_back(rRectangle.toString().getStr());
333 }
334 OString sRectangle = comphelper::string::join("; ", v);
335
336 const vcl::ILibreOfficeKitNotifier* pNotifier = pParent->GetLOKNotifier();
337 std::vector<vcl::LOKPayloadItem> aItems;
338 aItems.emplace_back("rectangles", sRectangle);
339 aItems.emplace_back("startHandleVisible", OString::boolean(bStartHandleVisible));
340 aItems.emplace_back("endHandleVisible", OString::boolean(bEndHandleVisible));
341 pNotifier->notifyWindow(pParent->GetLOKWindowId(), "text_selection", aItems);
342 }
343 else
344 {
345 pOutWin->Push(PushFlags::MAPMODE);
346 if (pOutWin->GetMapMode().GetMapUnit() == MapUnit::MapTwip)
347 {
348 // Find the parent that is not right
349 // on top of us to use its offset.
350 vcl::Window* parent = pOutWin->GetParent();
351 while (parent &&
352 parent->GetOutOffXPixel() == pOutWin->GetOutOffXPixel() &&
353 parent->GetOutOffYPixel() == pOutWin->GetOutOffYPixel())
354 {
355 parent = parent->GetParent();
356 }
357
358 if (parent)
359 {
360 lcl_translateTwips(*parent, *pOutWin);
361 }
362 }
363
364 bool bMm100ToTwip = !mpLOKSpecialPositioning &&
365 (pOutWin->GetMapMode().GetMapUnit() == MapUnit::Map100thMM);
366
367 Point aOrigin;
368 if (pOutWin->GetMapMode().GetMapUnit() == MapUnit::MapTwip)
369 // Writer comments: they use editeng, but are separate widgets.
370 aOrigin = pOutWin->GetMapMode().GetOrigin();
371
372 OString sRectangle;
373 OString sRefPoint;
374 if (mpLOKSpecialPositioning)
375 sRefPoint = mpLOKSpecialPositioning->GetRefPoint().toString();
376
377 std::vector<tools::Rectangle> aRectangles;
378 aRegion.GetRegionRectangles(aRectangles);
379
380 if (!aRectangles.empty())
381 {
382 if (pOutWin->IsChart())
383 {
384 const vcl::Window* pViewShellWindow = mpViewShell->GetEditWindowForActiveOLEObj();
385 if (pViewShellWindow && pViewShellWindow->IsAncestorOf(*pOutWin))
386 {
387 Point aOffsetPx = pOutWin->GetOffsetPixelFrom(*pViewShellWindow);
388 Point aLogicOffset = pOutWin->PixelToLogic(aOffsetPx);
389 for (tools::Rectangle& rRect : aRectangles)
390 rRect.Move(aLogicOffset.getX(), aLogicOffset.getY());
391 }
392 }
393
394 std::vector<OString> v;
395 for (tools::Rectangle & rRectangle : aRectangles)
396 {
397 if (bMm100ToTwip)
398 rRectangle = OutputDevice::LogicToLogic(rRectangle, MapMode(MapUnit::Map100thMM), MapMode(MapUnit::MapTwip));
399 rRectangle.Move(aOrigin.getX(), aOrigin.getY());
400 v.emplace_back(rRectangle.toString().getStr());
401 }
402 sRectangle = comphelper::string::join("; ", v);
403
404 if (mpLOKSpecialPositioning && !sRectangle.isEmpty())
405 sRectangle += ":: " + sRefPoint;
406
407 tools::Rectangle& rStart = aRectangles.front();
408 tools::Rectangle aStart(rStart.Left(), rStart.Top(), rStart.Left() + 1, rStart.Bottom());
409
410 OString aPayload = aStart.toString();
411 if (mpLOKSpecialPositioning)
412 aPayload += ":: " + sRefPoint;
413
414 mpViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION_START, aPayload.getStr());
415
416 tools::Rectangle& rEnd = aRectangles.back();
417 tools::Rectangle aEnd(rEnd.Right() - 1, rEnd.Top(), rEnd.Right(), rEnd.Bottom());
418
419 aPayload = aEnd.toString();
420 if (mpLOKSpecialPositioning)
421 aPayload += ":: " + sRefPoint;
422
423 mpViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION_END, aPayload.getStr());
424 }
425
426 if (mpOtherShell)
427 {
428 // Another shell wants to know about our existing selection.
429 if (mpViewShell != mpOtherShell)
430 mpViewShell->NotifyOtherView(mpOtherShell, LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", sRectangle);
431 }
432 else
433 {
434 mpViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, sRectangle.getStr());
435 mpViewShell->NotifyOtherViews(LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", sRectangle);
436 }
437
438 pOutWin->Pop();
439 }
440}
441
442// renamed from DrawSelection to DrawSelectionXOR to better reflect what this
443// method was used for: Paint Selection in XOR, change it and again paint it in XOR.
444// This can be safely assumed due to the EditView only being capable of painting the
445// selection in XOR until today.
446// This also means that all places calling DrawSelectionXOR are thoroughly weighted
447// and chosen to make this fragile XOR-paint water-proof and thus contain some
448// information in this sense.
449// Someone thankfully expanded it to collect the SelectionRectangles when called with
450// the Region*, see GetSelectionRectangles below.
451void ImpEditView::DrawSelectionXOR( EditSelection aTmpSel, vcl::Region* pRegion, OutputDevice* pTargetDevice )
452{
453 if (getEditViewCallbacks() && !pRegion && !comphelper::LibreOfficeKit::isActive())
454 {
455 // we are done, do *not* visualize self
456 // CAUTION: do not use when comphelper::LibreOfficeKit::isActive()
457 // due to event stuff triggered below. That *should* probably be moved
458 // to SelectionChanged() which exists now, but I do not know enough about
459 // that stuff to do it
460 return;
461 }
462
463 if ( eSelectionMode == EESelectionMode::Hidden )
464 return;
465
466 // It must be ensured before rendering the selection, that the contents of
467 // the window is completely valid! Must be here so that in any case if
468 // empty, then later on two-Paint Events! Must be done even before the
469 // query from bUpdate, if after Invalidate paints still in the queue,
470 // but someone switches the update mode!
471
472 // pRegion: When not NULL, then only calculate Region.
473
474 OutputDevice* pTarget;
475 if (pTargetDevice)
476 pTarget = pTargetDevice;
477 else
478 pTarget = getEditViewCallbacks() ? &getEditViewCallbacks()->EditViewOutputDevice() : pOutWin;
479 bool bClipRegion = pTarget->IsClipRegion();
480 vcl::Region aOldRegion = pTarget->GetClipRegion();
481
482 std::unique_ptr<tools::PolyPolygon> pPolyPoly;
483
484 if ( !pRegion && !comphelper::LibreOfficeKit::isActive())
485 {
486 if ( !pEditEngine->pImpEditEngine->GetUpdateMode() )
487 return;
488 if ( pEditEngine->pImpEditEngine->IsInUndo() )
489 return;
490
491 if ( !aTmpSel.HasRange() )
492 return;
493
494 // aTmpOutArea: if OutputArea > Paper width and
495 // Text > Paper width ( over large fields )
496 tools::Rectangle aTmpOutArea( aOutArea );
497 if ( aTmpOutArea.GetWidth() > pEditEngine->pImpEditEngine->GetPaperSize().Width() )
498 aTmpOutArea.SetRight( aTmpOutArea.Left() + pEditEngine->pImpEditEngine->GetPaperSize().Width() );
499 pTarget->IntersectClipRegion( aTmpOutArea );
500
501 if (pOutWin && pOutWin->GetCursor())
502 pOutWin->GetCursor()->Hide();
503 }
504
505 if (comphelper::LibreOfficeKit::isActive() || pRegion)
506 pPolyPoly.reset(new tools::PolyPolygon);
507
508 DBG_ASSERT( !pEditEngine->IsIdleFormatterActive(), "DrawSelectionXOR: Not formatted!" )do { if (true && (!(!pEditEngine->IsIdleFormatterActive
()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "508" ": "), "%s", "DrawSelectionXOR: Not formatted!"); }
} while (false)
;
509 aTmpSel.Adjust( pEditEngine->GetEditDoc() );
510
511 ContentNode* pStartNode = aTmpSel.Min().GetNode();
512 ContentNode* pEndNode = aTmpSel.Max().GetNode();
513 const sal_Int32 nStartPara = pEditEngine->GetEditDoc().GetPos(pStartNode);
514 const sal_Int32 nEndPara = pEditEngine->GetEditDoc().GetPos(pEndNode);
515 if (nStartPara == EE_PARA_NOT_FOUND((sal_Int32) 0x7FFFFFFF) || nEndPara == EE_PARA_NOT_FOUND((sal_Int32) 0x7FFFFFFF))
516 return;
517
518 bool bStartHandleVisible = false;
519 bool bEndHandleVisible = false;
520
521 for ( sal_Int32 nPara = nStartPara; nPara <= nEndPara; nPara++ )
522 {
523 ParaPortion* pTmpPortion = pEditEngine->GetParaPortions().SafeGetObject( nPara );
524 if (!pTmpPortion)
525 {
526 SAL_WARN( "editeng", "Portion in Selection not found!" )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "editeng")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "Portion in Selection not found!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "526" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Portion in Selection not found!"), 0)
; } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Portion in Selection not found!"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "526" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Portion in Selection not found!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "526" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Portion in Selection not found!"), 0)
; } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Portion in Selection not found!"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "526" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
527 continue;
528 }
529
530 DBG_ASSERT( !pTmpPortion->IsInvalid(), "Portion in Selection not formatted!" )do { if (true && (!(!pTmpPortion->IsInvalid()))) {
sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "530" ": "), "%s", "Portion in Selection not formatted!"
); } } while (false)
;
531
532 if ( !pTmpPortion->IsVisible() || pTmpPortion->IsInvalid() )
533 continue;
534
535 long nParaStart = pEditEngine->GetParaPortions().GetYOffset( pTmpPortion );
536 if ( ( nParaStart + pTmpPortion->GetHeight() ) < GetVisDocTop() )
537 continue;
538 if ( nParaStart > GetVisDocBottom() )
539 break;
540
541 sal_uInt16 nStartLine = 0;
542 sal_uInt16 nEndLine = pTmpPortion->GetLines().Count() -1;
543 if ( nPara == nStartPara )
544 nStartLine = pTmpPortion->GetLines().FindLine( aTmpSel.Min().GetIndex(), false );
545 if ( nPara == nEndPara )
546 nEndLine = pTmpPortion->GetLines().FindLine( aTmpSel.Max().GetIndex(), true );
547
548 for ( sal_uInt16 nLine = nStartLine; nLine <= nEndLine; nLine++ )
549 {
550 const EditLine& rLine = pTmpPortion->GetLines()[nLine];
551
552 bool bPartOfLine = false;
553 sal_Int32 nStartIndex = rLine.GetStart();
554 sal_Int32 nEndIndex = rLine.GetEnd();
555 if ( ( nPara == nStartPara ) && ( nLine == nStartLine ) && ( nStartIndex != aTmpSel.Min().GetIndex() ) )
556 {
557 nStartIndex = aTmpSel.Min().GetIndex();
558 bPartOfLine = true;
559 }
560 if ( ( nPara == nEndPara ) && ( nLine == nEndLine ) && ( nEndIndex != aTmpSel.Max().GetIndex() ) )
561 {
562 nEndIndex = aTmpSel.Max().GetIndex();
563 bPartOfLine = true;
564 }
565
566 // Can happen if at the beginning of a wrapped line.
567 if ( nEndIndex < nStartIndex )
568 nEndIndex = nStartIndex;
569
570 tools::Rectangle aTmpRect( pEditEngine->pImpEditEngine->GetEditCursor( pTmpPortion, nStartIndex ) );
571 Point aTopLeft( aTmpRect.TopLeft() );
572 Point aBottomRight( aTmpRect.BottomRight() );
573
574 aTopLeft.AdjustY(nParaStart );
575 aBottomRight.AdjustY(nParaStart );
576
577 // Only paint if in the visible range ...
578 if ( aTopLeft.Y() > GetVisDocBottom() )
579 break;
580
581 if ( aBottomRight.Y() < GetVisDocTop() )
582 continue;
583
584 if ( ( nPara == nStartPara ) && ( nLine == nStartLine ) )
585 bStartHandleVisible = true;
586 if ( ( nPara == nEndPara ) && ( nLine == nEndLine ) )
587 bEndHandleVisible = true;
588
589 // Now that we have Bidi, the first/last index doesn't have to be the 'most outside' position
590 if ( !bPartOfLine )
591 {
592 Range aLineXPosStartEnd = pEditEngine->GetLineXPosStartEnd(pTmpPortion, &rLine);
593 aTopLeft.setX( aLineXPosStartEnd.Min() );
594 aBottomRight.setX( aLineXPosStartEnd.Max() );
595 ImplDrawHighlightRect( pTarget, aTopLeft, aBottomRight, pPolyPoly.get() );
596 }
597 else
598 {
599 sal_Int32 nTmpStartIndex = nStartIndex;
600 sal_Int32 nWritingDirStart, nTmpEndIndex;
601
602 while ( nTmpStartIndex < nEndIndex )
603 {
604 pEditEngine->pImpEditEngine->GetRightToLeft( nPara, nTmpStartIndex+1, &nWritingDirStart, &nTmpEndIndex );
605 if ( nTmpEndIndex > nEndIndex )
606 nTmpEndIndex = nEndIndex;
607
608 DBG_ASSERT( nTmpEndIndex > nTmpStartIndex, "DrawSelectionXOR, Start >= End?" )do { if (true && (!(nTmpEndIndex > nTmpStartIndex)
)) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "608" ": "), "%s", "DrawSelectionXOR, Start >= End?")
; } } while (false)
;
609
610 long nX1 = pEditEngine->GetXPos(pTmpPortion, &rLine, nTmpStartIndex, true);
611 long nX2 = pEditEngine->GetXPos(pTmpPortion, &rLine, nTmpEndIndex);
612
613 Point aPt1( std::min( nX1, nX2 ), aTopLeft.Y() );
614 Point aPt2( std::max( nX1, nX2 ), aBottomRight.Y() );
615
616 ImplDrawHighlightRect( pTarget, aPt1, aPt2, pPolyPoly.get() );
617 nTmpStartIndex = nTmpEndIndex;
618 }
619 }
620 }
621 }
622
623 if (comphelper::LibreOfficeKit::isActive() && mpViewShell && pOutWin)
624 lokSelectionCallback(pPolyPoly, bStartHandleVisible, bEndHandleVisible);
625
626 if (pRegion || comphelper::LibreOfficeKit::isActive())
627 {
628 if (pRegion)
629 *pRegion = vcl::Region( *pPolyPoly );
630 pPolyPoly.reset();
631 }
632 else
633 {
634 if (pOutWin && pOutWin->GetCursor())
635 pOutWin->GetCursor()->Show();
636
637 if ( bClipRegion )
638 pTarget->SetClipRegion( aOldRegion );
639 else
640 pTarget->SetClipRegion();
641 }
642}
643
644void ImpEditView::GetSelectionRectangles(EditSelection aTmpSel, std::vector<tools::Rectangle>& rLogicRects)
645{
646 vcl::Region aRegion;
647 DrawSelectionXOR(aTmpSel, &aRegion);
648 aRegion.GetRegionRectangles(rLogicRects);
649}
650
651void ImpEditView::ImplDrawHighlightRect( OutputDevice* _pTarget, const Point& rDocPosTopLeft, const Point& rDocPosBottomRight, tools::PolyPolygon* pPolyPoly )
652{
653 if ( rDocPosTopLeft.X() == rDocPosBottomRight.X() )
654 return;
655
656 if (mpLOKSpecialPositioning && pPolyPoly)
657 {
658 MapUnit eDevUnit = _pTarget->GetMapMode().GetMapUnit();
659 tools::Rectangle aSelRect(rDocPosTopLeft, rDocPosBottomRight);
660 aSelRect = mpLOKSpecialPositioning->GetWindowPos(aSelRect, eDevUnit);
661 const Point aRefPoint = mpLOKSpecialPositioning->GetRefPoint();
662 aSelRect.Move(-aRefPoint.X(), -aRefPoint.Y());
663
664 tools::Polygon aTmpPoly(4);
665 aTmpPoly[0] = aSelRect.TopLeft();
666 aTmpPoly[1] = aSelRect.TopRight();
667 aTmpPoly[2] = aSelRect.BottomRight();
668 aTmpPoly[3] = aSelRect.BottomLeft();
669 pPolyPoly->Insert(aTmpPoly);
670 return;
671 }
672
673 bool bPixelMode = _pTarget->GetMapMode().GetMapUnit() == MapUnit::MapPixel;
674
675 Point aPnt1( GetWindowPos( rDocPosTopLeft ) );
676 Point aPnt2( GetWindowPos( rDocPosBottomRight ) );
677
678 if ( !IsVertical() )
679 {
680 lcl_AllignToPixel( aPnt1, _pTarget, +1, 0 );
681 lcl_AllignToPixel( aPnt2, _pTarget, 0, ( bPixelMode ? 0 : -1 ) );
682 }
683 else
684 {
685 lcl_AllignToPixel( aPnt1, _pTarget, 0, +1 );
686 lcl_AllignToPixel( aPnt2, _pTarget, ( bPixelMode ? 0 : +1 ), 0 );
687 }
688
689 tools::Rectangle aRect( aPnt1, aPnt2 );
690 if ( pPolyPoly )
691 {
692 tools::Polygon aTmpPoly( 4 );
693 aTmpPoly[0] = aRect.TopLeft();
694 aTmpPoly[1] = aRect.TopRight();
695 aTmpPoly[2] = aRect.BottomRight();
696 aTmpPoly[3] = aRect.BottomLeft();
697 pPolyPoly->Insert( aTmpPoly );
698 }
699 else
700 {
701 vcl::Window* pWindow = dynamic_cast< vcl::Window* >(_pTarget);
702
703 if(pWindow)
704 {
705 pWindow->Invert( aRect );
706 }
707 else
708 {
709 _pTarget->Push(PushFlags::LINECOLOR|PushFlags::FILLCOLOR|PushFlags::RASTEROP);
710 _pTarget->SetLineColor();
711 _pTarget->SetFillColor(COL_BLACK);
712 _pTarget->SetRasterOp(RasterOp::Invert);
713 _pTarget->DrawRect(aRect);
714 _pTarget->Pop();
715 }
716 }
717}
718
719
720bool ImpEditView::IsVertical() const
721{
722 return pEditEngine->pImpEditEngine->IsVertical();
723}
724
725bool ImpEditView::IsTopToBottom() const
726{
727 return pEditEngine->pImpEditEngine->IsTopToBottom();
728}
729
730tools::Rectangle ImpEditView::GetVisDocArea() const
731{
732 return tools::Rectangle( GetVisDocLeft(), GetVisDocTop(), GetVisDocRight(), GetVisDocBottom() );
733}
734
735Point ImpEditView::GetDocPos( const Point& rWindowPos ) const
736{
737 // Window Position => Position Document
738 Point aPoint;
739
740 if ( !pEditEngine->pImpEditEngine->IsVertical() )
741 {
742 aPoint.setX( rWindowPos.X() - aOutArea.Left() + GetVisDocLeft() );
743 aPoint.setY( rWindowPos.Y() - aOutArea.Top() + GetVisDocTop() );
744 }
745 else
746 {
747 if (pEditEngine->pImpEditEngine->IsTopToBottom())
748 {
749 aPoint.setX( rWindowPos.Y() - aOutArea.Top() + GetVisDocLeft() );
750 aPoint.setY( aOutArea.Right() - rWindowPos.X() + GetVisDocTop() );
751 }
752 else
753 {
754 aPoint.setX( aOutArea.Bottom() - rWindowPos.Y() + GetVisDocLeft() );
755 aPoint.setY( rWindowPos.X() - aOutArea.Left() + GetVisDocTop() );
756 }
757 }
758
759 return aPoint;
760}
761
762Point ImpEditView::GetWindowPos( const Point& rDocPos ) const
763{
764 // Document position => window position
765 Point aPoint;
766
767 if ( !pEditEngine->pImpEditEngine->IsVertical() )
768 {
769 aPoint.setX( rDocPos.X() + aOutArea.Left() - GetVisDocLeft() );
770 aPoint.setY( rDocPos.Y() + aOutArea.Top() - GetVisDocTop() );
771 }
772 else
773 {
774 if (pEditEngine->pImpEditEngine->IsTopToBottom())
775 {
776 aPoint.setX( aOutArea.Right() - rDocPos.Y() + GetVisDocTop() );
777 aPoint.setY( rDocPos.X() + aOutArea.Top() - GetVisDocLeft() );
778 }
779 else
780 {
781 aPoint.setX( aOutArea.Left() + rDocPos.Y() - GetVisDocTop() );
782 aPoint.setY( aOutArea.Bottom() - rDocPos.X() + GetVisDocLeft() );
783 }
784 }
785
786 return aPoint;
787}
788
789tools::Rectangle ImpEditView::GetWindowPos( const tools::Rectangle& rDocRect ) const
790{
791 // Document position => window position
792 Point aPos( GetWindowPos( rDocRect.TopLeft() ) );
793 Size aSz = rDocRect.GetSize();
794 tools::Rectangle aRect;
795 if ( !pEditEngine->pImpEditEngine->IsVertical() )
796 {
797 aRect = tools::Rectangle( aPos, aSz );
798 }
799 else
800 {
801 Point aNewPos( aPos.X()-aSz.Height(), aPos.Y() );
802 // coverity[swapped_arguments : FALSE] - this is in the correct order
803 aRect = tools::Rectangle( aNewPos, Size( aSz.Height(), aSz.Width() ) );
804 }
805 return aRect;
806}
807
808void ImpEditView::SetSelectionMode( EESelectionMode eNewMode )
809{
810 if ( eSelectionMode != eNewMode )
811 {
812 DrawSelectionXOR();
813 eSelectionMode = eNewMode;
814 DrawSelectionXOR(); // redraw
815 }
816}
817
818void ImpEditView::SetOutputArea( const tools::Rectangle& rRect )
819{
820 const OutputDevice& rOutDev = getEditViewCallbacks() ? getEditViewCallbacks()->EditViewOutputDevice() : *pOutWin;
821 // should be better be aligned on pixels!
822 tools::Rectangle aNewRect(rOutDev.LogicToPixel(rRect));
823 aNewRect = rOutDev.PixelToLogic(aNewRect);
824 aOutArea = aNewRect;
825 if ( !aOutArea.IsWidthEmpty() && aOutArea.Right() < aOutArea.Left() )
826 aOutArea.SetRight( aOutArea.Left() );
827 if ( !aOutArea.IsHeightEmpty() && aOutArea.Bottom() < aOutArea.Top() )
828 aOutArea.SetBottom( aOutArea.Top() );
829
830 SetScrollDiffX( static_cast<sal_uInt16>(aOutArea.GetWidth()) * 2 / 10 );
831}
832
833void ImpEditView::InvalidateAtWindow(const tools::Rectangle& rRect)
834{
835 if (EditViewCallbacks* pCallbacks = getEditViewCallbacks())
836 {
837 // do not invalidate and trigger a global repaint, but forward
838 // the need for change to the applied EditViewCallback, can e.g.
839 // be used to visualize the active edit text in an OverlayObject
840 pCallbacks->EditViewInvalidate(rRect);
841 }
842 else
843 {
844 // classic mode: invalidate and trigger full repaint
845 // of the changed area
846 GetWindow()->Invalidate(rRect);
847 }
848}
849
850void ImpEditView::ResetOutputArea( const tools::Rectangle& rRect )
851{
852 // remember old out area
853 const tools::Rectangle aOldArea(aOutArea);
854
855 // apply new one
856 SetOutputArea(rRect);
857
858 // invalidate surrounding areas if update is true
859 if(aOldArea.IsEmpty() || !pEditEngine->pImpEditEngine->GetUpdateMode())
860 return;
861
862 // #i119885# use grown area if needed; do when getting bigger OR smaller
863 const sal_Int32 nMore(DoInvalidateMore() ? GetWindow()->PixelToLogic(Size(nInvMore, 0)).Width() : 0);
864
865 if(aOldArea.Left() > aOutArea.Left())
866 {
867 const tools::Rectangle aRect(aOutArea.Left() - nMore, aOldArea.Top() - nMore, aOldArea.Left(), aOldArea.Bottom() + nMore);
868 InvalidateAtWindow(aRect);
869 }
870 else if(aOldArea.Left() < aOutArea.Left())
871 {
872 const tools::Rectangle aRect(aOldArea.Left() - nMore, aOldArea.Top() - nMore, aOutArea.Left(), aOldArea.Bottom() + nMore);
873 InvalidateAtWindow(aRect);
874 }
875
876 if(aOldArea.Right() > aOutArea.Right())
877 {
878 const tools::Rectangle aRect(aOutArea.Right(), aOldArea.Top() - nMore, aOldArea.Right() + nMore, aOldArea.Bottom() + nMore);
879 InvalidateAtWindow(aRect);
880 }
881 else if(aOldArea.Right() < aOutArea.Right())
882 {
883 const tools::Rectangle aRect(aOldArea.Right(), aOldArea.Top() - nMore, aOutArea.Right() + nMore, aOldArea.Bottom() + nMore);
884 InvalidateAtWindow(aRect);
885 }
886
887 if(aOldArea.Top() > aOutArea.Top())
888 {
889 const tools::Rectangle aRect(aOldArea.Left() - nMore, aOutArea.Top() - nMore, aOldArea.Right() + nMore, aOldArea.Top());
890 InvalidateAtWindow(aRect);
891 }
892 else if(aOldArea.Top() < aOutArea.Top())
893 {
894 const tools::Rectangle aRect(aOldArea.Left() - nMore, aOldArea.Top() - nMore, aOldArea.Right() + nMore, aOutArea.Top());
895 InvalidateAtWindow(aRect);
896 }
897
898 if(aOldArea.Bottom() > aOutArea.Bottom())
899 {
900 const tools::Rectangle aRect(aOldArea.Left() - nMore, aOutArea.Bottom(), aOldArea.Right() + nMore, aOldArea.Bottom() + nMore);
901 InvalidateAtWindow(aRect);
902 }
903 else if(aOldArea.Bottom() < aOutArea.Bottom())
904 {
905 const tools::Rectangle aRect(aOldArea.Left() - nMore, aOldArea.Bottom(), aOldArea.Right() + nMore, aOutArea.Bottom() + nMore);
906 InvalidateAtWindow(aRect);
907 }
908}
909
910void ImpEditView::RecalcOutputArea()
911{
912 Point aNewTopLeft( aOutArea.TopLeft() );
913 Size aNewSz( aOutArea.GetSize() );
914
915 // X:
916 if ( DoAutoWidth() )
917 {
918 if ( pEditEngine->pImpEditEngine->GetStatus().AutoPageWidth() )
919 aNewSz.setWidth( pEditEngine->pImpEditEngine->GetPaperSize().Width() );
920 switch ( eAnchorMode )
921 {
922 case EEAnchorMode::TopLeft:
923 case EEAnchorMode::VCenterLeft:
924 case EEAnchorMode::BottomLeft:
925 {
926 aNewTopLeft.setX( aAnchorPoint.X() );
927 }
928 break;
929 case EEAnchorMode::TopHCenter:
930 case EEAnchorMode::VCenterHCenter:
931 case EEAnchorMode::BottomHCenter:
932 {
933 aNewTopLeft.setX( aAnchorPoint.X() - aNewSz.Width() / 2 );
934 }
935 break;
936 case EEAnchorMode::TopRight:
937 case EEAnchorMode::VCenterRight:
938 case EEAnchorMode::BottomRight:
939 {
940 aNewTopLeft.setX( aAnchorPoint.X() - aNewSz.Width() - 1 );
941 }
942 break;
943 }
944 }
945
946 // Y:
947 if ( DoAutoHeight() )
948 {
949 if ( pEditEngine->pImpEditEngine->GetStatus().AutoPageHeight() )
950 aNewSz.setHeight( pEditEngine->pImpEditEngine->GetPaperSize().Height() );
951 switch ( eAnchorMode )
952 {
953 case EEAnchorMode::TopLeft:
954 case EEAnchorMode::TopHCenter:
955 case EEAnchorMode::TopRight:
956 {
957 aNewTopLeft.setY( aAnchorPoint.Y() );
958 }
959 break;
960 case EEAnchorMode::VCenterLeft:
961 case EEAnchorMode::VCenterHCenter:
962 case EEAnchorMode::VCenterRight:
963 {
964 aNewTopLeft.setY( aAnchorPoint.Y() - aNewSz.Height() / 2 );
965 }
966 break;
967 case EEAnchorMode::BottomLeft:
968 case EEAnchorMode::BottomHCenter:
969 case EEAnchorMode::BottomRight:
970 {
971 aNewTopLeft.setY( aAnchorPoint.Y() - aNewSz.Height() - 1 );
972 }
973 break;
974 }
975 }
976 ResetOutputArea( tools::Rectangle( aNewTopLeft, aNewSz ) );
977}
978
979void ImpEditView::SetAnchorMode( EEAnchorMode eMode )
980{
981 eAnchorMode = eMode;
982 CalcAnchorPoint();
983}
984
985void ImpEditView::CalcAnchorPoint()
986{
987 // GetHeight() and GetWidth() -1, because rectangle calculation not preferred.
988
989 // X:
990 switch ( eAnchorMode )
991 {
992 case EEAnchorMode::TopLeft:
993 case EEAnchorMode::VCenterLeft:
994 case EEAnchorMode::BottomLeft:
995 {
996 aAnchorPoint.setX( aOutArea.Left() );
997 }
998 break;
999 case EEAnchorMode::TopHCenter:
1000 case EEAnchorMode::VCenterHCenter:
1001 case EEAnchorMode::BottomHCenter:
1002 {
1003 aAnchorPoint.setX( aOutArea.Left() + (aOutArea.GetWidth()-1) / 2 );
1004 }
1005 break;
1006 case EEAnchorMode::TopRight:
1007 case EEAnchorMode::VCenterRight:
1008 case EEAnchorMode::BottomRight:
1009 {
1010 aAnchorPoint.setX( aOutArea.Right() );
1011 }
1012 break;
1013 }
1014
1015 // Y:
1016 switch ( eAnchorMode )
1017 {
1018 case EEAnchorMode::TopLeft:
1019 case EEAnchorMode::TopHCenter:
1020 case EEAnchorMode::TopRight:
1021 {
1022 aAnchorPoint.setY( aOutArea.Top() );
1023 }
1024 break;
1025 case EEAnchorMode::VCenterLeft:
1026 case EEAnchorMode::VCenterHCenter:
1027 case EEAnchorMode::VCenterRight:
1028 {
1029 aAnchorPoint.setY( aOutArea.Top() + (aOutArea.GetHeight()-1) / 2 );
1030 }
1031 break;
1032 case EEAnchorMode::BottomLeft:
1033 case EEAnchorMode::BottomHCenter:
1034 case EEAnchorMode::BottomRight:
1035 {
1036 aAnchorPoint.setY( aOutArea.Bottom() - 1 );
1037 }
1038 break;
1039 }
1040}
1041
1042namespace
1043{
1044
1045// For building JSON message to be sent to Online
1046boost::property_tree::ptree getHyperlinkPropTree(const OUString& sText, const OUString& sLink)
1047{
1048 boost::property_tree::ptree aTree;
1049 aTree.put("text", sText);
1050 aTree.put("link", sLink);
1051 return aTree;
1052}
1053
1054} // End of anon namespace
1055
1056tools::Rectangle ImpEditView::ImplGetEditCursor(EditPaM& aPaM, GetCursorFlags nShowCursorFlags, sal_Int32& nTextPortionStart,
1057 const ParaPortion* pParaPortion) const
1058{
1059 tools::Rectangle aEditCursor = pEditEngine->pImpEditEngine->PaMtoEditCursor( aPaM, nShowCursorFlags );
1060 if ( !IsInsertMode() && !aEditSelection.HasRange() )
1061 {
1062 if ( aPaM.GetNode()->Len() && ( aPaM.GetIndex() < aPaM.GetNode()->Len() ) )
1063 {
1064 // If we are behind a portion, and the next portion has other direction, we must change position...
1065 aEditCursor.SetLeft( pEditEngine->pImpEditEngine->PaMtoEditCursor( aPaM, GetCursorFlags::TextOnly|GetCursorFlags::PreferPortionStart ).Left() );
1066 aEditCursor.SetRight( aEditCursor.Left() );
1067
1068 sal_Int32 nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nTextPortionStart, true );
1069 const TextPortion& rTextPortion = pParaPortion->GetTextPortions()[nTextPortion];
1070 if ( rTextPortion.GetKind() == PortionKind::TAB )
1071 {
1072 aEditCursor.AdjustRight(rTextPortion.GetSize().Width() );
1073 }
1074 else
1075 {
1076 EditPaM aNext = pEditEngine->CursorRight( aPaM );
1077 tools::Rectangle aTmpRect = pEditEngine->pImpEditEngine->PaMtoEditCursor( aNext, GetCursorFlags::TextOnly );
1078 if ( aTmpRect.Top() != aEditCursor.Top() )
1079 aTmpRect = pEditEngine->pImpEditEngine->PaMtoEditCursor( aNext, GetCursorFlags::TextOnly|GetCursorFlags::EndOfLine );
1080 aEditCursor.SetRight( aTmpRect.Left() );
1081 }
1082 }
1083 }
1084
1085 long nMaxHeight = !IsVertical() ? aOutArea.GetHeight() : aOutArea.GetWidth();
1086 if ( aEditCursor.GetHeight() > nMaxHeight )
1087 {
1088 aEditCursor.SetBottom( aEditCursor.Top() + nMaxHeight - 1 );
1089 }
1090
1091 return aEditCursor;
1092}
1093
1094tools::Rectangle ImpEditView::GetEditCursor() const
1095{
1096 EditPaM aPaM( aEditSelection.Max() );
1097
1098 sal_Int32 nTextPortionStart = 0;
1099 sal_Int32 nPara = pEditEngine->GetEditDoc().GetPos( aPaM.GetNode() );
1100 if (nPara == EE_PARA_NOT_FOUND((sal_Int32) 0x7FFFFFFF)) // #i94322
1101 return tools::Rectangle();
1102
1103 const ParaPortion* pParaPortion = pEditEngine->GetParaPortions()[nPara];
1104
1105 GetCursorFlags nShowCursorFlags = nExtraCursorFlags | GetCursorFlags::TextOnly;
1106
1107 // Use CursorBidiLevel 0/1 in meaning of
1108 // 0: prefer portion end, normal mode
1109 // 1: prefer portion start
1110
1111 if ( ( GetCursorBidiLevel() != CURSOR_BIDILEVEL_DONTKNOW0xFFFF ) && GetCursorBidiLevel() )
1112 {
1113 nShowCursorFlags |= GetCursorFlags::PreferPortionStart;
1114 }
1115
1116 return ImplGetEditCursor(aPaM, nShowCursorFlags, nTextPortionStart, pParaPortion);
1117}
1118
1119void ImpEditView::ShowCursor( bool bGotoCursor, bool bForceVisCursor )
1120{
1121 // No ShowCursor in an empty View ...
1122 if (aOutArea.IsEmpty())
1
Taking false branch
1123 return;
1124 if ( ( aOutArea.Left() >= aOutArea.Right() ) && ( aOutArea.Top() >= aOutArea.Bottom() ) )
2
Assuming the condition is false
1125 return;
1126
1127 pEditEngine->CheckIdleFormatter();
1128 if (!pEditEngine->IsFormatted())
3
Assuming the condition is false
4
Taking false branch
1129 pEditEngine->pImpEditEngine->FormatDoc();
1130
1131 // For some reasons I end up here during the formatting, if the Outliner
1132 // is initialized in Paint, because no SetPool();
1133 if ( pEditEngine->pImpEditEngine->IsFormatting() )
5
Assuming the condition is false
6
Taking false branch
1134 return;
1135 if ( !pEditEngine->pImpEditEngine->GetUpdateMode() )
7
Assuming the condition is false
8
Taking false branch
1136 return;
1137 if ( pEditEngine->pImpEditEngine->IsInUndo() )
9
Assuming the condition is false
10
Taking false branch
1138 return;
1139
1140 if (pOutWin && pOutWin->GetCursor() != GetCursor())
1141 pOutWin->SetCursor(GetCursor());
1142
1143 EditPaM aPaM( aEditSelection.Max() );
1144
1145 sal_Int32 nTextPortionStart = 0;
1146 sal_Int32 nPara = pEditEngine->GetEditDoc().GetPos( aPaM.GetNode() );
1147 if (nPara == EE_PARA_NOT_FOUND((sal_Int32) 0x7FFFFFFF)) // #i94322
11
Assuming 'nPara' is not equal to EE_PARA_NOT_FOUND
12
Taking false branch
1148 return;
1149
1150 const ParaPortion* pParaPortion = pEditEngine->GetParaPortions()[nPara];
1151
1152 GetCursorFlags nShowCursorFlags = nExtraCursorFlags | GetCursorFlags::TextOnly;
1153
1154 // Use CursorBidiLevel 0/1 in meaning of
1155 // 0: prefer portion end, normal mode
1156 // 1: prefer portion start
1157
1158 if ( ( GetCursorBidiLevel() != CURSOR_BIDILEVEL_DONTKNOW0xFFFF ) && GetCursorBidiLevel() )
13
Assuming the condition is false
1159 {
1160 nShowCursorFlags |= GetCursorFlags::PreferPortionStart;
1161 }
1162
1163 tools::Rectangle aEditCursor = ImplGetEditCursor(aPaM, nShowCursorFlags, nTextPortionStart, pParaPortion);
1164
1165 if ( bGotoCursor ) // && (!pEditEngine->pImpEditEngine->GetStatus().AutoPageSize() ) )
14
Assuming 'bGotoCursor' is true
15
Taking true branch
1166 {
1167 // check if scrolling is necessary...
1168 // if scrolling, then update () and Scroll ()!
1169 long nDocDiffX = 0;
1170 long nDocDiffY = 0;
1171
1172 tools::Rectangle aTmpVisArea( GetVisDocArea() );
1173 // aTmpOutArea: if OutputArea > Paper width and
1174 // Text > Paper width ( over large fields )
1175 long nMaxTextWidth = !IsVertical() ? pEditEngine->pImpEditEngine->GetPaperSize().Width() : pEditEngine->pImpEditEngine->GetPaperSize().Height();
16
Assuming the condition is false
17
'?' condition is false
1176 if ( aTmpVisArea.GetWidth() > nMaxTextWidth )
18
Assuming the condition is false
19
Taking false branch
1177 aTmpVisArea.SetRight( aTmpVisArea.Left() + nMaxTextWidth );
1178
1179 if ( aEditCursor.Bottom() > aTmpVisArea.Bottom() )
20
Assuming the condition is false
21
Taking false branch
1180 { // Scroll up, here positive
1181 nDocDiffY = aEditCursor.Bottom() - aTmpVisArea.Bottom();
1182 }
1183 else if ( aEditCursor.Top() < aTmpVisArea.Top() )
22
Assuming the condition is false
23
Taking false branch
1184 { // Scroll down, here negative
1185 nDocDiffY = aEditCursor.Top() - aTmpVisArea.Top();
1186 }
1187
1188 if ( aEditCursor.Right() > aTmpVisArea.Right() )
24
Assuming the condition is false
25
Taking false branch
1189 {
1190 // Scroll left, positive
1191 nDocDiffX = aEditCursor.Right() - aTmpVisArea.Right();
1192 // Can it be a little more?
1193 if ( aEditCursor.Right() < ( nMaxTextWidth - GetScrollDiffX() ) )
1194 nDocDiffX += GetScrollDiffX();
1195 else
1196 {
1197 long n = nMaxTextWidth - aEditCursor.Right();
1198 // If MapMode != RefMapMode then the EditCursor can go beyond
1199 // the paper width!
1200 nDocDiffX += ( n > 0 ? n : -n );
1201 }
1202 }
1203 else if ( aEditCursor.Left() < aTmpVisArea.Left() )
26
Assuming the condition is false
27
Taking false branch
1204 {
1205 // Scroll right, negative:
1206 nDocDiffX = aEditCursor.Left() - aTmpVisArea.Left();
1207 // Can it be a little more?
1208 if ( aEditCursor.Left() > ( - static_cast<long>(GetScrollDiffX()) ) )
1209 nDocDiffX -= GetScrollDiffX();
1210 else
1211 nDocDiffX -= aEditCursor.Left();
1212 }
1213 if ( aPaM.GetIndex() == 0 ) // Olli needed for the Outliner
28
Assuming the condition is true
29
Taking true branch
1214 {
1215 // But make sure that the cursor is not leaving visible area
1216 // because of this!
1217 if ( aEditCursor.Left() < aTmpVisArea.GetWidth() )
30
Assuming the condition is true
31
Taking true branch
1218 {
1219 nDocDiffX = -aTmpVisArea.Left();
1220 }
1221 }
1222
1223 if ( nDocDiffX | nDocDiffY )
32
Assuming the condition is true
33
Taking true branch
1224 {
1225 long nDiffX = !IsVertical() ? nDocDiffX : (IsTopToBottom() ? -nDocDiffY : nDocDiffY);
34
Assuming the condition is true
35
'?' condition is true
1226 long nDiffY = !IsVertical() ? nDocDiffY : (IsTopToBottom() ? nDocDiffX : -nDocDiffX);
36
Assuming the condition is true
37
'?' condition is true
1227
1228 if ( nDiffX
37.1
'nDiffX' is not equal to 0
)
38
Taking true branch
1229 pEditEngine->GetInternalEditStatus().GetStatusWord() = pEditEngine->GetInternalEditStatus().GetStatusWord() | EditStatusFlags::HSCROLL;
1230 if ( nDiffY
38.1
'nDiffY' is 0
)
39
Taking false branch
1231 pEditEngine->GetInternalEditStatus().GetStatusWord() = pEditEngine->GetInternalEditStatus().GetStatusWord() | EditStatusFlags::VSCROLL;
1232 Scroll( -nDiffX, -nDiffY );
40
Calling 'ImpEditView::Scroll'
1233 pEditEngine->pImpEditEngine->DelayedCallStatusHdl();
1234 }
1235 }
1236
1237 // Cursor may trim a little ...
1238 if ( ( aEditCursor.Bottom() > GetVisDocTop() ) &&
1239 ( aEditCursor.Top() < GetVisDocBottom() ) )
1240 {
1241 if ( aEditCursor.Bottom() > GetVisDocBottom() )
1242 aEditCursor.SetBottom( GetVisDocBottom() );
1243 if ( aEditCursor.Top() < GetVisDocTop() )
1244 aEditCursor.SetTop( GetVisDocTop() );
1245 }
1246
1247 const OutputDevice& rOutDev = getEditViewCallbacks() ? getEditViewCallbacks()->EditViewOutputDevice() : *pOutWin;
1248
1249 long nOnePixel = rOutDev.PixelToLogic( Size( 1, 0 ) ).Width();
1250
1251 if ( ( aEditCursor.Top() + nOnePixel >= GetVisDocTop() ) &&
1252 ( aEditCursor.Bottom() - nOnePixel <= GetVisDocBottom() ) &&
1253 ( aEditCursor.Left() + nOnePixel >= GetVisDocLeft() ) &&
1254 ( aEditCursor.Right() - nOnePixel <= GetVisDocRight() ) )
1255 {
1256 tools::Rectangle aCursorRect = GetWindowPos( aEditCursor );
1257 GetCursor()->SetPos( aCursorRect.TopLeft() );
1258 Size aCursorSz( aCursorRect.GetSize() );
1259 // Rectangle is inclusive
1260 aCursorSz.AdjustWidth( -1 );
1261 aCursorSz.AdjustHeight( -1 );
1262 if ( !aCursorSz.Width() || !aCursorSz.Height() )
1263 {
1264 long nCursorSz = rOutDev.GetSettings().GetStyleSettings().GetCursorSize();
1265 nCursorSz = rOutDev.PixelToLogic( Size( nCursorSz, 0 ) ).Width();
1266 if ( !aCursorSz.Width() )
1267 aCursorSz.setWidth( nCursorSz );
1268 if ( !aCursorSz.Height() )
1269 aCursorSz.setHeight( nCursorSz );
1270 }
1271 // #111036# Let VCL do orientation for cursor, otherwise problem when cursor has direction flag
1272 if ( IsVertical() )
1273 {
1274 Size aOldSz( aCursorSz );
1275 aCursorSz.setWidth( aOldSz.Height() );
1276 aCursorSz.setHeight( aOldSz.Width() );
1277 GetCursor()->SetPos( aCursorRect.TopRight() );
1278 GetCursor()->SetOrientation( IsTopToBottom() ? 2700 : 900 );
1279 }
1280 else
1281 // #i32593# Reset correct orientation in horizontal layout
1282 GetCursor()->SetOrientation();
1283
1284 GetCursor()->SetSize( aCursorSz );
1285
1286 if (comphelper::LibreOfficeKit::isActive() && mpViewShell && !mbSuppressLOKMessages)
1287 {
1288 Point aPos = GetCursor()->GetPos();
1289 boost::property_tree::ptree aMessageParams;
1290 if (mpLOKSpecialPositioning)
1291 {
1292 // Sending the absolute (pure) logical coordinates of the cursor to the client is not
1293 // enough for it to accurately reconstruct the corresponding tile-twips coordinates of the cursor.
1294 // This is because the editeng(doc) positioning is not pixel aligned for each cell involved in the output-area
1295 // (it better not be!). A simple solution is to send the coordinates of a point ('refpoint') in the output-area
1296 // along with the relative position of the cursor w.r.t this chosen 'refpoint'.
1297
1298 MapUnit eDevUnit = rOutDev.GetMapMode().GetMapUnit();
1299 tools::Rectangle aCursorRectPureLogical(aEditCursor.TopLeft(), GetCursor()->GetSize());
1300 // Get rectangle in window-coordinates from editeng(doc) coordinates.
1301 aCursorRectPureLogical = mpLOKSpecialPositioning->GetWindowPos(aCursorRectPureLogical, eDevUnit);
1302 const Point aRefPoint = mpLOKSpecialPositioning->GetRefPoint();
1303 // Get the relative coordinates w.r.t rRefPoint.
1304 aCursorRectPureLogical.Move(-aRefPoint.X(), -aRefPoint.Y());
1305 aMessageParams.put("relrect", aCursorRectPureLogical.toString());
1306 aMessageParams.put("refpoint", aRefPoint.toString());
1307 }
1308
1309 if (pOutWin && pOutWin->IsChart())
1310 {
1311 const vcl::Window* pViewShellWindow = mpViewShell->GetEditWindowForActiveOLEObj();
1312 if (pViewShellWindow && pViewShellWindow->IsAncestorOf(*pOutWin))
1313 {
1314 Point aOffsetPx = pOutWin->GetOffsetPixelFrom(*pViewShellWindow);
1315 Point aLogicOffset = pOutWin->PixelToLogic(aOffsetPx);
1316 aPos.Move(aLogicOffset.getX(), aLogicOffset.getY());
1317 }
1318 }
1319
1320 tools::Rectangle aRect(aPos.getX(), aPos.getY(), aPos.getX() + GetCursor()->GetWidth(), aPos.getY() + GetCursor()->GetHeight());
1321
1322 // LOK output is always in twips, convert from mm100 if necessary.
1323 if (rOutDev.GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
1324 aRect = OutputDevice::LogicToLogic(aRect, MapMode(MapUnit::Map100thMM), MapMode(MapUnit::MapTwip));
1325 else if (rOutDev.GetMapMode().GetMapUnit() == MapUnit::MapTwip)
1326 {
1327 // Writer comments: they use editeng, but are separate widgets.
1328 Point aOrigin = rOutDev.GetMapMode().GetOrigin();
1329 // Move the rectangle, so that we output absolute twips.
1330 aRect.Move(aOrigin.getX(), aOrigin.getY());
1331 }
1332 // Let the LOK client decide the cursor width.
1333 aRect.setWidth(0);
1334
1335 OString sRect = aRect.toString();
1336 aMessageParams.put("rectangle", sRect);
1337
1338 SfxViewShell* pThisShell = dynamic_cast<SfxViewShell*>(mpViewShell);
1339 SfxViewShell* pOtherShell = dynamic_cast<SfxViewShell*>(mpOtherShell);
1340 assert(pThisShell)(static_cast <bool> (pThisShell) ? void (0) : __assert_fail
("pThisShell", "/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
, 1340, __extension__ __PRETTY_FUNCTION__))
;
1341
1342 if (pOtherShell && pThisShell != pOtherShell)
1343 {
1344 // Another shell wants to know about our existing cursor.
1345 SfxLokHelper::notifyOtherView(pThisShell, pOtherShell,
1346 LOK_CALLBACK_INVALIDATE_VIEW_CURSOR, aMessageParams);
1347 }
1348 else
1349 {
1350 // is cursor at a misspelled word ?
1351 Reference< linguistic2::XSpellChecker1 > xSpeller( pEditEngine->pImpEditEngine->GetSpeller() );
1352 bool bIsWrong = xSpeller.is() && IsWrongSpelledWord(aPaM, /*bMarkIfWrong*/ false);
1353
1354 boost::property_tree::ptree aHyperlinkTree;
1355 if (const SvxFieldItem* pFld = GetField(aPos, nullptr, nullptr))
1356 {
1357 if (auto pUrlField = dynamic_cast<const SvxURLField*>(pFld->GetField()))
1358 {
1359 aHyperlinkTree = getHyperlinkPropTree(pUrlField->GetRepresentation(), pUrlField->GetURL());
1360 }
1361 }
1362 else if (GetEditSelection().HasRange())
1363 {
1364 EditView* pActiveView = GetEditViewPtr();
1365
1366 if (pActiveView)
1367 {
1368 const SvxFieldItem* pFieldItem = pActiveView->GetFieldAtSelection();
1369 if (pFieldItem)
1370 {
1371 const SvxFieldData* pField = pFieldItem->GetField();
1372 if ( auto pUrlField = dynamic_cast<const SvxURLField*>( pField) )
1373 {
1374 aHyperlinkTree = getHyperlinkPropTree(pUrlField->GetRepresentation(), pUrlField->GetURL());
1375 }
1376 }
1377 }
1378 }
1379
1380 if (mbBroadcastLOKViewCursor)
1381 SfxLokHelper::notifyOtherViews(pThisShell,
1382 LOK_CALLBACK_INVALIDATE_VIEW_CURSOR, aMessageParams);
1383
1384 aMessageParams.put("mispelledWord", bIsWrong ? 1 : 0);
1385 aMessageParams.add_child("hyperlink", aHyperlinkTree);
1386
1387 if (comphelper::LibreOfficeKit::isViewIdForVisCursorInvalidation())
1388 SfxLokHelper::notifyOtherView(pThisShell, pThisShell,
1389 LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR, aMessageParams);
1390 else
1391 pThisShell->libreOfficeKitViewCallback(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR,
1392 aMessageParams.get<std::string>("rectangle").c_str());
1393 }
1394 }
1395
1396 CursorDirection nCursorDir = CursorDirection::NONE;
1397 if ( IsInsertMode() && !aEditSelection.HasRange() && ( pEditEngine->pImpEditEngine->HasDifferentRTLLevels( aPaM.GetNode() ) ) )
1398 {
1399 sal_uInt16 nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nTextPortionStart, bool(nShowCursorFlags & GetCursorFlags::PreferPortionStart) );
1400 const TextPortion& rTextPortion = pParaPortion->GetTextPortions()[nTextPortion];
1401 if (rTextPortion.IsRightToLeft())
1402 nCursorDir = CursorDirection::RTL;
1403 else
1404 nCursorDir = CursorDirection::LTR;
1405
1406 }
1407 GetCursor()->SetDirection( nCursorDir );
1408
1409 if ( bForceVisCursor )
1410 GetCursor()->Show();
1411 {
1412 SvxFont aFont;
1413 pEditEngine->SeekCursor( aPaM.GetNode(), aPaM.GetIndex()+1, aFont );
1414
1415 InputContext aInputContext(aFont, InputContextFlags::Text | InputContextFlags::ExtText);
1416 if (EditViewCallbacks* pCallbacks = getEditViewCallbacks())
1417 pCallbacks->EditViewInputContext(aInputContext);
1418 else if (auto xWindow = GetWindow())
1419 xWindow->SetInputContext(aInputContext);
1420 }
1421 }
1422 else
1423 {
1424 pEditEngine->pImpEditEngine->GetStatus().GetStatusWord() = pEditEngine->pImpEditEngine->GetStatus().GetStatusWord() | EditStatusFlags::CURSOROUT;
1425 GetCursor()->Hide();
1426 GetCursor()->SetPos( Point( -1, -1 ) );
1427 GetCursor()->SetSize( Size( 0, 0 ) );
1428 }
1429}
1430
1431Pair ImpEditView::Scroll( long ndX, long ndY, ScrollRangeCheck nRangeCheck )
1432{
1433 DBG_ASSERT( pEditEngine->pImpEditEngine->IsFormatted(), "Scroll: Not formatted!" )do { if (true && (!(pEditEngine->pImpEditEngine->
IsFormatted()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "1433" ": "), "%s", "Scroll: Not formatted!"); } } while
(false)
;
41
Assuming the condition is false
42
Taking false branch
43
Loop condition is false. Exiting loop
1434 if ( !ndX && !ndY )
44
Assuming 'ndX' is not equal to 0
1435 return Pair( 0, 0 );
1436
1437 const OutputDevice& rOutDev = getEditViewCallbacks() ? getEditViewCallbacks()->EditViewOutputDevice() : *GetWindow();
45
Assuming the condition is false
46
'?' condition is false
47
Dereference of null pointer
1438
1439#ifdef DBG_UTIL
1440 tools::Rectangle aR( aOutArea );
1441 aR = rOutDev.LogicToPixel( aR );
1442 aR = rOutDev.PixelToLogic( aR );
1443 SAL_WARN_IF( aR != aOutArea, "editeng", "OutArea before Scroll not aligned" )do { if (true && (aR != aOutArea)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "editeng")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "OutArea before Scroll not aligned"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "1443" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "OutArea before Scroll not aligned")
, 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "OutArea before Scroll not aligned"; ::sal::detail::
log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "1443" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "OutArea before Scroll not aligned") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "1443" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "OutArea before Scroll not aligned")
, 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "OutArea before Scroll not aligned"; ::sal::detail::
log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "1443" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1444#endif
1445
1446 tools::Rectangle aNewVisArea( GetVisDocArea() );
1447
1448 // Vertical:
1449 if ( !IsVertical() )
1450 {
1451 aNewVisArea.AdjustTop( -ndY );
1452 aNewVisArea.AdjustBottom( -ndY );
1453 }
1454 else
1455 {
1456 if( IsTopToBottom() )
1457 {
1458 aNewVisArea.AdjustTop(ndX );
1459 aNewVisArea.AdjustBottom(ndX );
1460 }
1461 else
1462 {
1463 aNewVisArea.AdjustTop( -ndX );
1464 aNewVisArea.AdjustBottom( -ndX );
1465 }
1466 }
1467 if ( ( nRangeCheck == ScrollRangeCheck::PaperWidthTextSize ) && ( aNewVisArea.Bottom() > static_cast<long>(pEditEngine->pImpEditEngine->GetTextHeight()) ) )
1468 {
1469 // GetTextHeight still optimizing!
1470 long nDiff = pEditEngine->pImpEditEngine->GetTextHeight() - aNewVisArea.Bottom(); // negative
1471 aNewVisArea.Move( 0, nDiff ); // could end up in the negative area...
1472 }
1473 if ( aNewVisArea.Top() < 0 )
1474 aNewVisArea.Move( 0, -aNewVisArea.Top() );
1475
1476 // Horizontal:
1477 if ( !IsVertical() )
1478 {
1479 aNewVisArea.AdjustLeft( -ndX );
1480 aNewVisArea.AdjustRight( -ndX );
1481 }
1482 else
1483 {
1484 if (IsTopToBottom())
1485 {
1486 aNewVisArea.AdjustLeft( -ndY );
1487 aNewVisArea.AdjustRight( -ndY );
1488 }
1489 else
1490 {
1491 aNewVisArea.AdjustLeft(ndY );
1492 aNewVisArea.AdjustRight(ndY );
1493 }
1494 }
1495 if ( ( nRangeCheck == ScrollRangeCheck::PaperWidthTextSize ) && ( aNewVisArea.Right() > static_cast<long>(pEditEngine->pImpEditEngine->CalcTextWidth( false )) ) )
1496 {
1497 long nDiff = pEditEngine->pImpEditEngine->CalcTextWidth( false ) - aNewVisArea.Right(); // negative
1498 aNewVisArea.Move( nDiff, 0 ); // could end up in the negative area...
1499 }
1500 if ( aNewVisArea.Left() < 0 )
1501 aNewVisArea.Move( -aNewVisArea.Left(), 0 );
1502
1503 // The difference must be alignt on pixel (due to scroll!)
1504 long nDiffX = !IsVertical() ? ( GetVisDocLeft() - aNewVisArea.Left() ) : (IsTopToBottom() ? -( GetVisDocTop() - aNewVisArea.Top() ) : (GetVisDocTop() - aNewVisArea.Top()));
1505 long nDiffY = !IsVertical() ? ( GetVisDocTop() - aNewVisArea.Top() ) : (IsTopToBottom() ? (GetVisDocLeft() - aNewVisArea.Left()) : -(GetVisDocTop() - aNewVisArea.Top()));
1506
1507 Size aDiffs( nDiffX, nDiffY );
1508 aDiffs = rOutDev.LogicToPixel( aDiffs );
1509 aDiffs = rOutDev.PixelToLogic( aDiffs );
1510
1511 long nRealDiffX = aDiffs.Width();
1512 long nRealDiffY = aDiffs.Height();
1513
1514
1515 if ( nRealDiffX || nRealDiffY )
1516 {
1517 vcl::Cursor* pCrsr = GetCursor();
1518 bool bVisCursor = pCrsr->IsVisible();
1519 pCrsr->Hide();
1520 if (pOutWin)
1521 pOutWin->PaintImmediately();
1522 if ( !IsVertical() )
1523 aVisDocStartPos.Move( -nRealDiffX, -nRealDiffY );
1524 else
1525 {
1526 if (IsTopToBottom())
1527 aVisDocStartPos.Move(-nRealDiffY, nRealDiffX);
1528 else
1529 aVisDocStartPos.Move(nRealDiffY, -nRealDiffX);
1530 }
1531 // Move by aligned value does not necessarily result in aligned
1532 // rectangle ...
1533 aVisDocStartPos = rOutDev.LogicToPixel( aVisDocStartPos );
1534 aVisDocStartPos = rOutDev.PixelToLogic( aVisDocStartPos );
1535 tools::Rectangle aRect( aOutArea );
1536
1537 if (pOutWin)
1538 {
1539 pOutWin->Scroll( nRealDiffX, nRealDiffY, aRect, ScrollFlags::Clip );
1540 }
1541
1542 if (comphelper::LibreOfficeKit::isActive() || getEditViewCallbacks())
1543 {
1544 // Need to invalidate the window, otherwise no tile will be re-painted.
1545 pEditView->Invalidate();
1546 }
1547
1548 if (pOutWin)
1549 pOutWin->PaintImmediately();
1550 pCrsr->SetPos( pCrsr->GetPos() + Point( nRealDiffX, nRealDiffY ) );
1551 if ( bVisCursor )
1552 {
1553 tools::Rectangle aCursorRect( pCrsr->GetPos(), pCrsr->GetSize() );
1554 if ( aOutArea.IsInside( aCursorRect ) )
1555 pCrsr->Show();
1556 }
1557
1558 if ( pEditEngine->pImpEditEngine->GetNotifyHdl().IsSet() )
1559 {
1560 EENotify aNotify( EE_NOTIFY_TEXTVIEWSCROLLED );
1561 pEditEngine->pImpEditEngine->GetNotifyHdl().Call( aNotify );
1562 }
1563
1564 if (comphelper::LibreOfficeKit::isActive())
1565 {
1566 DrawSelectionXOR();
1567 }
1568 }
1569
1570 return Pair( nRealDiffX, nRealDiffY );
1571}
1572
1573Reference<css::datatransfer::clipboard::XClipboard> ImpEditView::GetClipboard() const
1574{
1575 if (vcl::Window* pWindow = GetWindow())
1576 return pWindow->GetClipboard();
1577 return GetSystemClipboard();
1578}
1579
1580Reference<css::datatransfer::clipboard::XClipboard> ImpEditView::GetSelection() const
1581{
1582 if (vcl::Window* pWindow = GetWindow())
1583 return pWindow->GetPrimarySelection();
1584 return GetSystemPrimarySelection();
1585}
1586
1587bool ImpEditView::PostKeyEvent( const KeyEvent& rKeyEvent, vcl::Window const * pFrameWin )
1588{
1589 bool bDone = false;
1590
1591 KeyFuncType eFunc = rKeyEvent.GetKeyCode().GetFunction();
1592 if ( eFunc != KeyFuncType::DONTKNOW )
1593 {
1594 switch ( eFunc )
1595 {
1596 case KeyFuncType::CUT:
1597 {
1598 if ( !bReadOnly )
1599 {
1600 Reference<css::datatransfer::clipboard::XClipboard> aClipBoard(GetClipboard());
1601 CutCopy( aClipBoard, true );
1602 bDone = true;
1603 }
1604 }
1605 break;
1606 case KeyFuncType::COPY:
1607 {
1608 Reference<css::datatransfer::clipboard::XClipboard> aClipBoard(GetClipboard());
1609 CutCopy( aClipBoard, false );
1610 bDone = true;
1611 }
1612 break;
1613 case KeyFuncType::PASTE:
1614 {
1615 if ( !bReadOnly && IsPasteEnabled() )
1616 {
1617 pEditEngine->pImpEditEngine->UndoActionStart( EDITUNDO_PASTE110 );
1618 Reference<css::datatransfer::clipboard::XClipboard> aClipBoard(GetClipboard());
1619 Paste( aClipBoard, pEditEngine->pImpEditEngine->GetStatus().AllowPasteSpecial() );
1620 pEditEngine->pImpEditEngine->UndoActionEnd();
1621 bDone = true;
1622 }
1623 }
1624 break;
1625 default:
1626 break;
1627 }
1628 }
1629
1630 if( !bDone )
1631 bDone = pEditEngine->PostKeyEvent( rKeyEvent, GetEditViewPtr(), pFrameWin );
1632
1633 return bDone;
1634}
1635
1636bool ImpEditView::MouseButtonUp( const MouseEvent& rMouseEvent )
1637{
1638 nTravelXPos = TRAVEL_X_DONTKNOW0xFFFFFFFF;
1639 nCursorBidiLevel = CURSOR_BIDILEVEL_DONTKNOW0xFFFF;
1640 nExtraCursorFlags = GetCursorFlags::NONE;
1641 bClickedInSelection = false;
1642
1643 if (vcl::Window* pWindow = GetWindow())
1644 {
1645 if ( rMouseEvent.IsMiddle() && !bReadOnly &&
1646 ( pWindow->GetSettings().GetMouseSettings().GetMiddleButtonAction() == MouseMiddleButtonAction::PasteSelection ) )
1647 {
1648 Reference<css::datatransfer::clipboard::XClipboard> aClipBoard(GetSelection());
1649 Paste( aClipBoard );
1650 }
1651 else if ( rMouseEvent.IsLeft() && GetEditSelection().HasRange() )
1652 {
1653 Reference<css::datatransfer::clipboard::XClipboard> aClipBoard(GetSelection());
1654 CutCopy( aClipBoard, false );
1655 }
1656 }
1657
1658 return pEditEngine->pImpEditEngine->MouseButtonUp( rMouseEvent, GetEditViewPtr() );
1659}
1660
1661void ImpEditView::ReleaseMouse()
1662{
1663 pEditEngine->pImpEditEngine->ReleaseMouse();
1664}
1665
1666bool ImpEditView::MouseButtonDown( const MouseEvent& rMouseEvent )
1667{
1668 pEditEngine->CheckIdleFormatter(); // If fast typing and mouse button downs
1669 nTravelXPos = TRAVEL_X_DONTKNOW0xFFFFFFFF;
1670 nExtraCursorFlags = GetCursorFlags::NONE;
1671 nCursorBidiLevel = CURSOR_BIDILEVEL_DONTKNOW0xFFFF;
1672 bClickedInSelection = IsSelectionAtPoint( rMouseEvent.GetPosPixel() );
1673 return pEditEngine->pImpEditEngine->MouseButtonDown( rMouseEvent, GetEditViewPtr() );
1674}
1675
1676bool ImpEditView::MouseMove( const MouseEvent& rMouseEvent )
1677{
1678 return pEditEngine->pImpEditEngine->MouseMove( rMouseEvent, GetEditViewPtr() );
1679}
1680
1681void ImpEditView::Command( const CommandEvent& rCEvt )
1682{
1683 pEditEngine->CheckIdleFormatter(); // If fast typing and mouse button down
1684 pEditEngine->pImpEditEngine->Command( rCEvt, GetEditViewPtr() );
1685}
1686
1687
1688void ImpEditView::SetInsertMode( bool bInsert )
1689{
1690 if ( bInsert != IsInsertMode() )
1691 {
1692 SetFlags( nControl, EVControlBits::OVERWRITE, !bInsert );
1693 ShowCursor( DoAutoScroll(), false );
1694 }
1695}
1696
1697bool ImpEditView::IsWrongSpelledWord( const EditPaM& rPaM, bool bMarkIfWrong )
1698{
1699 bool bIsWrong = false;
1700 if ( rPaM.GetNode()->GetWrongList() )
1701 {
1702 EditSelection aSel = pEditEngine->SelectWord( rPaM, css::i18n::WordType::DICTIONARY_WORD );
1703 bIsWrong = rPaM.GetNode()->GetWrongList()->HasWrong( aSel.Min().GetIndex(), aSel.Max().GetIndex() );
1704 if ( bIsWrong && bMarkIfWrong )
1705 {
1706 DrawSelectionXOR();
1707 SetEditSelection( aSel );
1708 DrawSelectionXOR();
1709 }
1710 }
1711 return bIsWrong;
1712}
1713
1714OUString ImpEditView::SpellIgnoreWord()
1715{
1716 OUString aWord;
1717 if ( pEditEngine->pImpEditEngine->GetSpeller().is() )
1718 {
1719 EditPaM aPaM = GetEditSelection().Max();
1720 if ( !HasSelection() )
1721 {
1722 EditSelection aSel = pEditEngine->SelectWord(aPaM);
1723 aWord = pEditEngine->pImpEditEngine->GetSelected( aSel );
1724 }
1725 else
1726 {
1727 aWord = pEditEngine->pImpEditEngine->GetSelected( GetEditSelection() );
1728 // And deselect
1729 DrawSelectionXOR();
1730 SetEditSelection( EditSelection( aPaM, aPaM ) );
1731 DrawSelectionXOR();
1732 }
1733
1734 if ( !aWord.isEmpty() )
1735 {
1736 Reference< XDictionary > xDic = LinguMgr::GetIgnoreAllList();
1737 if (xDic.is())
1738 xDic->add( aWord, false, OUString() );
1739 EditDoc& rDoc = pEditEngine->GetEditDoc();
1740 sal_Int32 nNodes = rDoc.Count();
1741 for ( sal_Int32 n = 0; n < nNodes; n++ )
1742 {
1743 ContentNode* pNode = rDoc.GetObject( n );
1744 pNode->GetWrongList()->MarkWrongsInvalid();
1745 }
1746 pEditEngine->pImpEditEngine->DoOnlineSpelling( aPaM.GetNode() );
1747 pEditEngine->pImpEditEngine->StartOnlineSpellTimer();
1748 }
1749 }
1750 return aWord;
1751}
1752
1753void ImpEditView::DeleteSelected()
1754{
1755 DrawSelectionXOR();
1756
1757 pEditEngine->pImpEditEngine->UndoActionStart( EDITUNDO_DELETE108 );
1758
1759 EditPaM aPaM = pEditEngine->pImpEditEngine->DeleteSelected( GetEditSelection() );
1760
1761 pEditEngine->pImpEditEngine->UndoActionEnd();
1762
1763 SetEditSelection( EditSelection( aPaM, aPaM ) );
1764
1765 DrawSelectionXOR();
1766
1767 pEditEngine->pImpEditEngine->FormatAndUpdate( GetEditViewPtr() );
1768 ShowCursor( DoAutoScroll(), true );
1769}
1770
1771const SvxFieldItem* ImpEditView::GetField( const Point& rPos, sal_Int32* pPara, sal_Int32* pPos ) const
1772{
1773 if( !GetOutputArea().IsInside( rPos ) )
1774 return nullptr;
1775
1776 Point aDocPos( GetDocPos( rPos ) );
1777 EditPaM aPaM = pEditEngine->GetPaM(aDocPos, false);
1778
1779 if ( aPaM.GetIndex() == aPaM.GetNode()->Len() )
1780 {
1781 // Otherwise, whenever the Field at the very end and mouse under the text
1782 return nullptr;
1783 }
1784
1785 const CharAttribList::AttribsType& rAttrs = aPaM.GetNode()->GetCharAttribs().GetAttribs();
1786 const sal_Int32 nXPos = aPaM.GetIndex();
1787 for (size_t nAttr = rAttrs.size(); nAttr; )
1788 {
1789 const EditCharAttrib& rAttr = *rAttrs[--nAttr];
1790 if (rAttr.GetStart() == nXPos)
1791 {
1792 if (rAttr.Which() == EE_FEATURE_FIELD)
1793 {
1794 DBG_ASSERT(dynamic_cast<const SvxFieldItem*>(rAttr.GetItem()), "No FieldItem...")do { if (true && (!(dynamic_cast<const SvxFieldItem
*>(rAttr.GetItem())))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "1794" ": "), "%s", "No FieldItem..."); } } while (false
)
;
1795 if ( pPara )
1796 *pPara = pEditEngine->GetEditDoc().GetPos( aPaM.GetNode() );
1797 if ( pPos )
1798 *pPos = rAttr.GetStart();
1799 return static_cast<const SvxFieldItem*>(rAttr.GetItem());
1800 }
1801 }
1802 }
1803 return nullptr;
1804}
1805
1806bool ImpEditView::IsBulletArea( const Point& rPos, sal_Int32* pPara )
1807{
1808 if ( pPara )
1809 *pPara = EE_PARA_NOT_FOUND((sal_Int32) 0x7FFFFFFF);
1810
1811 if( !GetOutputArea().IsInside( rPos ) )
1812 return false;
1813
1814 Point aDocPos( GetDocPos( rPos ) );
1815 EditPaM aPaM = pEditEngine->GetPaM(aDocPos, false);
1816
1817 if ( aPaM.GetIndex() == 0 )
1818 {
1819 sal_Int32 nPara = pEditEngine->GetEditDoc().GetPos( aPaM.GetNode() );
1820 tools::Rectangle aBulletArea = pEditEngine->GetBulletArea( nPara );
1821 long nY = pEditEngine->GetDocPosTopLeft( nPara ).Y();
1822 const ParaPortion* pParaPortion = pEditEngine->GetParaPortions()[nPara];
1823 nY += pParaPortion->GetFirstLineOffset();
1824 if ( ( aDocPos.Y() > ( nY + aBulletArea.Top() ) ) &&
1825 ( aDocPos.Y() < ( nY + aBulletArea.Bottom() ) ) &&
1826 ( aDocPos.X() > ( aBulletArea.Left() ) ) &&
1827 ( aDocPos.X() < ( aBulletArea.Right() ) ) )
1828 {
1829 if ( pPara )
1830 *pPara = nPara;
1831 return true;
1832 }
1833 }
1834
1835 return false;
1836}
1837
1838void ImpEditView::CutCopy( css::uno::Reference< css::datatransfer::clipboard::XClipboard > const & rxClipboard, bool bCut )
1839{
1840 if ( !(rxClipboard.is() && HasSelection()) )
1841 return;
1842
1843 uno::Reference<datatransfer::XTransferable> xData = pEditEngine->CreateTransferable( GetEditSelection() );
1844
1845 {
1846 SolarMutexReleaser aReleaser;
1847
1848 try
1849 {
1850 rxClipboard->setContents( xData, nullptr );
1851
1852 // #87756# FlushClipboard, but it would be better to become a TerminateListener to the Desktop and flush on demand...
1853 uno::Reference< datatransfer::clipboard::XFlushableClipboard > xFlushableClipboard( rxClipboard, uno::UNO_QUERY );
1854 if( xFlushableClipboard.is() )
1855 xFlushableClipboard->flushClipboard();
1856 }
1857 catch( const css::uno::Exception& )
1858 {
1859 }
1860
1861 }
1862
1863 if (bCut)
1864 {
1865 pEditEngine->pImpEditEngine->UndoActionStart(EDITUNDO_CUT109);
1866 DeleteSelected();
1867 pEditEngine->pImpEditEngine->UndoActionEnd();
1868 }
1869}
1870
1871void ImpEditView::Paste( css::uno::Reference< css::datatransfer::clipboard::XClipboard > const & rxClipboard, bool bUseSpecial )
1872{
1873 if ( !rxClipboard.is() )
1874 return;
1875
1876 uno::Reference< datatransfer::XTransferable > xDataObj;
1877
1878 try
1879 {
1880 SolarMutexReleaser aReleaser;
1881 xDataObj = rxClipboard->getContents();
1882 }
1883 catch( const css::uno::Exception& )
1884 {
1885 }
1886
1887 if ( !xDataObj.is() || !EditEngine::HasValidData( xDataObj ) )
1888 return;
1889
1890 pEditEngine->pImpEditEngine->UndoActionStart( EDITUNDO_PASTE110 );
1891
1892 EditSelection aSel( GetEditSelection() );
1893 if ( aSel.HasRange() )
1894 {
1895 DrawSelectionXOR();
1896 aSel = pEditEngine->DeleteSelection(aSel);
1897 }
1898
1899 PasteOrDropInfos aPasteOrDropInfos;
1900 aPasteOrDropInfos.nStartPara = pEditEngine->GetEditDoc().GetPos( aSel.Min().GetNode() );
1901 pEditEngine->HandleBeginPasteOrDrop(aPasteOrDropInfos);
1902
1903 if ( DoSingleLinePaste() )
1904 {
1905 datatransfer::DataFlavor aFlavor;
1906 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING, aFlavor );
1907 if ( xDataObj->isDataFlavorSupported( aFlavor ) )
1908 {
1909 try
1910 {
1911 uno::Any aData = xDataObj->getTransferData( aFlavor );
1912 OUString aTmpText;
1913 aData >>= aTmpText;
1914 OUString aText(convertLineEnd(aTmpText, LINEEND_LF));
1915 aText = aText.replaceAll( OUStringChar(LINE_SEP'\x0A'), " " );
1916 aSel = pEditEngine->InsertText(aSel, aText);
1917 }
1918 catch( ... )
1919 {
1920 ; // #i9286# can happen, even if isDataFlavorSupported returns true...
1921 }
1922 }
1923 }
1924 else
1925 {
1926 // Prevent notifications of paragraph inserts et al that would trigger
1927 // a11y to format content in a half-ready state when obtaining
1928 // paragraphs. Collect and broadcast when done instead.
1929 aSel = pEditEngine->InsertText(
1930 xDataObj, OUString(), aSel.Min(),
1931 bUseSpecial && pEditEngine->GetInternalEditStatus().AllowPasteSpecial());
1932 }
1933
1934 aPasteOrDropInfos.nEndPara = pEditEngine->GetEditDoc().GetPos( aSel.Max().GetNode() );
1935 pEditEngine->HandleEndPasteOrDrop(aPasteOrDropInfos);
1936
1937 pEditEngine->pImpEditEngine->UndoActionEnd();
1938 SetEditSelection( aSel );
1939 pEditEngine->pImpEditEngine->UpdateSelections();
1940 pEditEngine->pImpEditEngine->FormatAndUpdate( GetEditViewPtr() );
1941 ShowCursor( DoAutoScroll(), true );
1942}
1943
1944
1945bool ImpEditView::IsInSelection( const EditPaM& rPaM )
1946{
1947 EditSelection aSel = GetEditSelection();
1948 if ( !aSel.HasRange() )
1949 return false;
1950
1951 aSel.Adjust( pEditEngine->GetEditDoc() );
1952
1953 sal_Int32 nStartNode = pEditEngine->GetEditDoc().GetPos( aSel.Min().GetNode() );
1954 sal_Int32 nEndNode = pEditEngine->GetEditDoc().GetPos( aSel.Max().GetNode() );
1955 sal_Int32 nCurNode = pEditEngine->GetEditDoc().GetPos( rPaM.GetNode() );
1956
1957 if ( ( nCurNode > nStartNode ) && ( nCurNode < nEndNode ) )
1958 return true;
1959
1960 if ( nStartNode == nEndNode )
1961 {
1962 if ( nCurNode == nStartNode )
1963 if ( ( rPaM.GetIndex() >= aSel.Min().GetIndex() ) && ( rPaM.GetIndex() < aSel.Max().GetIndex() ) )
1964 return true;
1965 }
1966 else if ( ( nCurNode == nStartNode ) && ( rPaM.GetIndex() >= aSel.Min().GetIndex() ) )
1967 return true;
1968 else if ( ( nCurNode == nEndNode ) && ( rPaM.GetIndex() < aSel.Max().GetIndex() ) )
1969 return true;
1970
1971 return false;
1972}
1973
1974void ImpEditView::CreateAnchor()
1975{
1976 pEditEngine->SetInSelectionMode(true);
1977 EditSelection aNewSelection(GetEditSelection());
1978 aNewSelection.Min() = aNewSelection.Max();
1979 SetEditSelection(aNewSelection);
1980 // const_cast<EditPaM&>(GetEditSelection().Min()) = GetEditSelection().Max();
1981}
1982
1983void ImpEditView::DeselectAll()
1984{
1985 pEditEngine->SetInSelectionMode(false);
1986 DrawSelectionXOR();
1987 EditSelection aNewSelection(GetEditSelection());
1988 aNewSelection.Min() = aNewSelection.Max();
1989 SetEditSelection(aNewSelection);
1990 // const_cast<EditPaM&>(GetEditSelection().Min()) = GetEditSelection().Max();
1991
1992 if (comphelper::LibreOfficeKit::isActive() && mpViewShell)
1993 {
1994 VclPtr<vcl::Window> pParent = pOutWin->GetParentWithLOKNotifier();
1995 if (pParent && pParent->GetLOKWindowId())
1996 {
1997 const vcl::ILibreOfficeKitNotifier* pNotifier = pParent->GetLOKNotifier();
1998 std::vector<vcl::LOKPayloadItem> aItems;
1999 aItems.emplace_back("rectangles", "");
2000 pNotifier->notifyWindow(pParent->GetLOKWindowId(), "text_selection", aItems);
2001 }
2002 }
2003}
2004
2005bool ImpEditView::IsSelectionAtPoint( const Point& rPosPixel )
2006{
2007 if ( pDragAndDropInfo && pDragAndDropInfo->pField )
2008 return true;
2009
2010 // Logical units ...
2011 const OutputDevice& rOutDev = getEditViewCallbacks() ? getEditViewCallbacks()->EditViewOutputDevice() : *GetWindow();
2012 Point aMousePos = rOutDev.PixelToLogic(rPosPixel);
2013
2014 if ( ( !GetOutputArea().IsInside( aMousePos ) ) && !pEditEngine->pImpEditEngine->IsInSelectionMode() )
2015 {
2016 return false;
2017 }
2018
2019 Point aDocPos( GetDocPos( aMousePos ) );
2020 EditPaM aPaM = pEditEngine->GetPaM(aDocPos, false);
2021 return IsInSelection( aPaM );
2022}
2023
2024bool ImpEditView::SetCursorAtPoint( const Point& rPointPixel )
2025{
2026 pEditEngine->CheckIdleFormatter();
2027
2028 Point aMousePos( rPointPixel );
2029
2030 // Logical units ...
2031 const OutputDevice& rOutDev = getEditViewCallbacks() ? getEditViewCallbacks()->EditViewOutputDevice() : *GetWindow();
2032 aMousePos = rOutDev.PixelToLogic( aMousePos );
2033
2034 if ( ( !GetOutputArea().IsInside( aMousePos ) ) && !pEditEngine->pImpEditEngine->IsInSelectionMode() )
2035 {
2036 return false;
2037 }
2038
2039 Point aDocPos( GetDocPos( aMousePos ) );
2040
2041 // Can be optimized: first go through the lines within a paragraph for PAM,
2042 // then again with the PaM for the Rect, even though the line is already
2043 // known... This must not be, though!
2044 EditPaM aPaM = pEditEngine->GetPaM(aDocPos);
2045 bool bGotoCursor = DoAutoScroll();
2046
2047 // aTmpNewSel: Diff between old and new, not the new selection, unless for tiled rendering
2048 EditSelection aTmpNewSel( comphelper::LibreOfficeKit::isActive() ? GetEditSelection().Min() : GetEditSelection().Max(), aPaM );
2049
2050 // #i27299#
2051 // work on copy of current selection and set new selection, if it has changed.
2052 EditSelection aNewEditSelection( GetEditSelection() );
2053
2054 aNewEditSelection.Max() = aPaM;
2055 if (!pEditEngine->GetSelectionEngine().HasAnchor())
2056 {
2057 if ( aNewEditSelection.Min() != aPaM )
2058 pEditEngine->CursorMoved(aNewEditSelection.Min().GetNode());
2059 aNewEditSelection.Min() = aPaM;
2060 }
2061 else
2062 {
2063 DrawSelectionXOR( aTmpNewSel );
2064 }
2065
2066 // set changed text selection
2067 if ( GetEditSelection() != aNewEditSelection )
2068 {
2069 SetEditSelection( aNewEditSelection );
2070 }
2071
2072 bool bForceCursor = pDragAndDropInfo == nullptr && !pEditEngine->pImpEditEngine->IsInSelectionMode();
2073 ShowCursor( bGotoCursor, bForceCursor );
2074 return true;
2075}
2076
2077void ImpEditView::HideDDCursor()
2078{
2079 if ( pDragAndDropInfo && pDragAndDropInfo->bVisCursor )
2080 {
2081 OutputDevice& rOutDev = getEditViewCallbacks() ? getEditViewCallbacks()->EditViewOutputDevice() : *GetWindow();
2082 rOutDev.DrawOutDev( pDragAndDropInfo->aCurSavedCursor.TopLeft(), pDragAndDropInfo->aCurSavedCursor.GetSize(),
2083 Point(0,0), pDragAndDropInfo->aCurSavedCursor.GetSize(),*pDragAndDropInfo->pBackground );
2084 pDragAndDropInfo->bVisCursor = false;
2085 }
2086}
2087
2088void ImpEditView::ShowDDCursor( const tools::Rectangle& rRect )
2089{
2090 if ( !pDragAndDropInfo || pDragAndDropInfo->bVisCursor )
2091 return;
2092
2093 if (pOutWin && pOutWin->GetCursor())
2094 pOutWin->GetCursor()->Hide();
2095
2096 OutputDevice& rOutDev = getEditViewCallbacks() ? getEditViewCallbacks()->EditViewOutputDevice() : *GetWindow();
2097 Color aOldFillColor = rOutDev.GetFillColor();
2098 rOutDev.SetFillColor( Color(4210752) ); // GRAY BRUSH_50, OLDSV, change to DDCursor!
2099
2100 // Save background ...
2101 tools::Rectangle aSaveRect( rOutDev.LogicToPixel( rRect ) );
2102 // prefer to save some more ...
2103 aSaveRect.AdjustRight(1 );
2104 aSaveRect.AdjustBottom(1 );
2105
2106#ifdef DBG_UTIL
2107 Size aNewSzPx( aSaveRect.GetSize() );
2108#endif
2109 if ( !pDragAndDropInfo->pBackground )
2110 {
2111 pDragAndDropInfo->pBackground = VclPtr<VirtualDevice>::Create(rOutDev);
2112 MapMode aMapMode( rOutDev.GetMapMode() );
2113 aMapMode.SetOrigin( Point( 0, 0 ) );
2114 pDragAndDropInfo->pBackground->SetMapMode( aMapMode );
2115
2116 }
2117
2118#ifdef DBG_UTIL
2119 Size aCurSzPx( pDragAndDropInfo->pBackground->GetOutputSizePixel() );
2120 if ( ( aCurSzPx.Width() < aNewSzPx.Width() ) ||( aCurSzPx.Height() < aNewSzPx.Height() ) )
2121 {
2122 bool bDone = pDragAndDropInfo->pBackground->SetOutputSizePixel( aNewSzPx );
2123 DBG_ASSERT( bDone, "Virtual Device broken?" )do { if (true && (!(bDone))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "2123" ": "), "%s", "Virtual Device broken?"); } } while
(false)
;
2124 }
2125#endif
2126
2127 aSaveRect = rOutDev.PixelToLogic( aSaveRect );
2128
2129 pDragAndDropInfo->pBackground->DrawOutDev( Point(0,0), aSaveRect.GetSize(),
2130 aSaveRect.TopLeft(), aSaveRect.GetSize(), rOutDev );
2131 pDragAndDropInfo->aCurSavedCursor = aSaveRect;
2132
2133 // Draw Cursor...
2134 rOutDev.DrawRect( rRect );
2135
2136 pDragAndDropInfo->bVisCursor = true;
2137 pDragAndDropInfo->aCurCursor = rRect;
2138
2139 rOutDev.SetFillColor( aOldFillColor );
2140}
2141
2142void ImpEditView::dragGestureRecognized(const css::datatransfer::dnd::DragGestureEvent& rDGE)
2143{
2144 DBG_ASSERT( !pDragAndDropInfo, "dragGestureRecognized - DragAndDropInfo exist!" )do { if (true && (!(!pDragAndDropInfo))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "2144" ": "), "%s", "dragGestureRecognized - DragAndDropInfo exist!"
); } } while (false)
;
2145
2146 SolarMutexGuard aVclGuard;
2147
2148 pDragAndDropInfo.reset();
2149
2150 Point aMousePosPixel( rDGE.DragOriginX, rDGE.DragOriginY );
2151
2152 EditSelection aCopySel( GetEditSelection() );
2153 aCopySel.Adjust( pEditEngine->GetEditDoc() );
2154
2155 if ( HasSelection() && bClickedInSelection )
2156 {
2157 pDragAndDropInfo.reset(new DragAndDropInfo());
2158 }
2159 else
2160 {
2161 // Field?!
2162 sal_Int32 nPara;
2163 sal_Int32 nPos;
2164 Point aMousePos = GetWindow()->PixelToLogic( aMousePosPixel );
2165 const SvxFieldItem* pField = GetField( aMousePos, &nPara, &nPos );
2166 if ( pField )
2167 {
2168 pDragAndDropInfo.reset(new DragAndDropInfo());
2169 pDragAndDropInfo->pField = pField;
2170 ContentNode* pNode = pEditEngine->GetEditDoc().GetObject( nPara );
2171 aCopySel = EditSelection( EditPaM( pNode, nPos ), EditPaM( pNode, nPos+1 ) );
2172 SetEditSelection(aCopySel);
2173 DrawSelectionXOR();
2174 bool bGotoCursor = DoAutoScroll();
2175 ShowCursor( bGotoCursor, /*bForceCursor=*/false );
2176 }
2177 else if ( IsBulletArea( aMousePos, &nPara ) )
2178 {
2179 pDragAndDropInfo.reset(new DragAndDropInfo());
2180 pDragAndDropInfo->bOutlinerMode = true;
2181 EditPaM aStartPaM( pEditEngine->GetEditDoc().GetObject( nPara ), 0 );
2182 EditPaM aEndPaM( aStartPaM );
2183 const SfxInt16Item& rLevel = pEditEngine->GetParaAttrib( nPara, EE_PARA_OUTLLEVEL );
2184 for ( sal_Int32 n = nPara +1; n < pEditEngine->GetEditDoc().Count(); n++ )
2185 {
2186 const SfxInt16Item& rL = pEditEngine->GetParaAttrib( n, EE_PARA_OUTLLEVEL );
2187 if ( rL.GetValue() > rLevel.GetValue() )
2188 {
2189 aEndPaM.SetNode( pEditEngine->GetEditDoc().GetObject( n ) );
2190 }
2191 else
2192 {
2193 break;
2194 }
2195 }
2196 aEndPaM.SetIndex( aEndPaM.GetNode()->Len() );
2197 SetEditSelection( EditSelection( aStartPaM, aEndPaM ) );
2198 }
2199 }
2200
2201 if ( !pDragAndDropInfo )
2202 return;
2203
2204
2205 pDragAndDropInfo->bStarterOfDD = true;
2206
2207 // Sensitive area to be scrolled.
2208 Size aSz( 5, 0 );
2209 aSz = GetWindow()->PixelToLogic( aSz );
2210 pDragAndDropInfo->nSensibleRange = static_cast<sal_uInt16>(aSz.Width());
2211 pDragAndDropInfo->nCursorWidth = static_cast<sal_uInt16>(aSz.Width()) / 2;
2212 pDragAndDropInfo->aBeginDragSel = pEditEngine->pImpEditEngine->CreateESel( aCopySel );
2213
2214 uno::Reference<datatransfer::XTransferable> xData = pEditEngine->CreateTransferable(aCopySel);
2215
2216 sal_Int8 nActions = bReadOnly ? datatransfer::dnd::DNDConstants::ACTION_COPY : datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE;
2217
2218 rDGE.DragSource->startDrag( rDGE, nActions, 0 /*cursor*/, 0 /*image*/, xData, mxDnDListener );
2219 // If Drag&Move in an Engine, then Copy&Del has to be optional!
2220 GetCursor()->Hide();
2221}
2222
2223void ImpEditView::dragDropEnd( const css::datatransfer::dnd::DragSourceDropEvent& rDSDE )
2224{
2225 SolarMutexGuard aVclGuard;
2226
2227 DBG_ASSERT( pDragAndDropInfo, "ImpEditView::dragDropEnd: pDragAndDropInfo is NULL!" )do { if (true && (!(pDragAndDropInfo))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "2227" ": "), "%s", "ImpEditView::dragDropEnd: pDragAndDropInfo is NULL!"
); } } while (false)
;
2228
2229 // #123688# Shouldn't happen, but seems to happen...
2230 if ( !pDragAndDropInfo )
2231 return;
2232
2233 if ( !bReadOnly && rDSDE.DropSuccess && !pDragAndDropInfo->bOutlinerMode && ( rDSDE.DropAction & datatransfer::dnd::DNDConstants::ACTION_MOVE ) )
2234 {
2235 if ( pDragAndDropInfo->bStarterOfDD && pDragAndDropInfo->bDroppedInMe )
2236 {
2237 // DropPos: Where was it dropped, irrespective of length.
2238 ESelection aDropPos( pDragAndDropInfo->aDropSel.nStartPara, pDragAndDropInfo->aDropSel.nStartPos, pDragAndDropInfo->aDropSel.nStartPara, pDragAndDropInfo->aDropSel.nStartPos );
2239 ESelection aToBeDelSel = pDragAndDropInfo->aBeginDragSel;
2240 ESelection aNewSel( pDragAndDropInfo->aDropSel.nEndPara, pDragAndDropInfo->aDropSel.nEndPos,
2241 pDragAndDropInfo->aDropSel.nEndPara, pDragAndDropInfo->aDropSel.nEndPos );
2242 bool bBeforeSelection = aDropPos < pDragAndDropInfo->aBeginDragSel;
2243 sal_Int32 nParaDiff = pDragAndDropInfo->aBeginDragSel.nEndPara - pDragAndDropInfo->aBeginDragSel.nStartPara;
2244 if ( bBeforeSelection )
2245 {
2246 // Adjust aToBeDelSel.
2247 DBG_ASSERT( pDragAndDropInfo->aBeginDragSel.nStartPara >= pDragAndDropInfo->aDropSel.nStartPara, "But not before? ")do { if (true && (!(pDragAndDropInfo->aBeginDragSel
.nStartPara >= pDragAndDropInfo->aDropSel.nStartPara)))
{ sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "2247" ": "), "%s", "But not before? "); } } while (false
)
;
2248 aToBeDelSel.nStartPara = aToBeDelSel.nStartPara + nParaDiff;
2249 aToBeDelSel.nEndPara = aToBeDelSel.nEndPara + nParaDiff;
2250 // To correct the character?
2251 if ( aToBeDelSel.nStartPara == pDragAndDropInfo->aDropSel.nEndPara )
2252 {
2253 sal_uInt16 nMoreChars;
2254 if ( pDragAndDropInfo->aDropSel.nStartPara == pDragAndDropInfo->aDropSel.nEndPara )
2255 nMoreChars = pDragAndDropInfo->aDropSel.nEndPos - pDragAndDropInfo->aDropSel.nStartPos;
2256 else
2257 nMoreChars = pDragAndDropInfo->aDropSel.nEndPos;
2258 aToBeDelSel.nStartPos =
2259 aToBeDelSel.nStartPos + nMoreChars;
2260 if ( aToBeDelSel.nStartPara == aToBeDelSel.nEndPara )
2261 aToBeDelSel.nEndPos =
2262 aToBeDelSel.nEndPos + nMoreChars;
2263 }
2264 }
2265 else
2266 {
2267 // aToBeDelSel is ok, but the selection of the View
2268 // has to be adapted, if it was deleted before!
2269 DBG_ASSERT( pDragAndDropInfo->aBeginDragSel.nStartPara <= pDragAndDropInfo->aDropSel.nStartPara, "But not before? ")do { if (true && (!(pDragAndDropInfo->aBeginDragSel
.nStartPara <= pDragAndDropInfo->aDropSel.nStartPara)))
{ sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "2269" ": "), "%s", "But not before? "); } } while (false
)
;
2270 aNewSel.nStartPara = aNewSel.nStartPara - nParaDiff;
2271 aNewSel.nEndPara = aNewSel.nEndPara - nParaDiff;
2272 // To correct the character?
2273 if ( pDragAndDropInfo->aBeginDragSel.nEndPara == pDragAndDropInfo->aDropSel.nStartPara )
2274 {
2275 sal_uInt16 nLessChars;
2276 if ( pDragAndDropInfo->aBeginDragSel.nStartPara == pDragAndDropInfo->aBeginDragSel.nEndPara )
2277 nLessChars = pDragAndDropInfo->aBeginDragSel.nEndPos - pDragAndDropInfo->aBeginDragSel.nStartPos;
2278 else
2279 nLessChars = pDragAndDropInfo->aBeginDragSel.nEndPos;
2280 aNewSel.nStartPos = aNewSel.nStartPos - nLessChars;
2281 if ( aNewSel.nStartPara == aNewSel.nEndPara )
2282 aNewSel.nEndPos = aNewSel.nEndPos - nLessChars;
2283 }
2284 }
2285
2286 DrawSelectionXOR();
2287 EditSelection aDelSel( pEditEngine->pImpEditEngine->CreateSel( aToBeDelSel ) );
2288 DBG_ASSERT( !aDelSel.DbgIsBuggy( pEditEngine->GetEditDoc() ), "ToBeDel is buggy!" )do { if (true && (!(!aDelSel.DbgIsBuggy( pEditEngine->
GetEditDoc() )))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "2288" ": "), "%s", "ToBeDel is buggy!"); } } while (false
)
;
2289 pEditEngine->DeleteSelection(aDelSel);
2290 if ( !bBeforeSelection )
2291 {
2292 DBG_ASSERT( !pEditEngine->pImpEditEngine->CreateSel( aNewSel ).DbgIsBuggy(pEditEngine->GetEditDoc()), "Bad" )do { if (true && (!(!pEditEngine->pImpEditEngine->
CreateSel( aNewSel ).DbgIsBuggy(pEditEngine->GetEditDoc())
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "2292" ": "), "%s", "Bad"); } } while (false)
;
2293 SetEditSelection( pEditEngine->pImpEditEngine->CreateSel( aNewSel ) );
2294 }
2295 pEditEngine->pImpEditEngine->FormatAndUpdate( pEditEngine->pImpEditEngine->GetActiveView() );
2296 DrawSelectionXOR();
2297 }
2298 else
2299 {
2300 // other EditEngine ...
2301 if (pEditEngine->HasText()) // #88630# SC is removing the content when switching the task
2302 DeleteSelected();
2303 }
2304 }
2305
2306 if ( pDragAndDropInfo->bUndoAction )
2307 pEditEngine->pImpEditEngine->UndoActionEnd();
2308
2309 HideDDCursor();
2310 ShowCursor( DoAutoScroll(), true );
2311 pDragAndDropInfo.reset();
2312 pEditEngine->GetEndDropHdl().Call(GetEditViewPtr());
2313}
2314
2315void ImpEditView::drop( const css::datatransfer::dnd::DropTargetDropEvent& rDTDE )
2316{
2317 SolarMutexGuard aVclGuard;
2318
2319 DBG_ASSERT( pDragAndDropInfo, "Drop - No Drag&Drop info?!" )do { if (true && (!(pDragAndDropInfo))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "2319" ": "), "%s", "Drop - No Drag&Drop info?!"); }
} while (false)
;
2320
2321 if ( !(pDragAndDropInfo && pDragAndDropInfo->bDragAccepted) )
2322 return;
2323
2324 pEditEngine->GetBeginDropHdl().Call(GetEditViewPtr());
2325 bool bChanges = false;
2326
2327 HideDDCursor();
2328
2329 if ( pDragAndDropInfo->bStarterOfDD )
2330 {
2331 pEditEngine->pImpEditEngine->UndoActionStart( EDITUNDO_DRAGANDDROP116 );
2332 pDragAndDropInfo->bUndoAction = true;
2333 }
2334
2335 if ( pDragAndDropInfo->bOutlinerMode )
2336 {
2337 bChanges = true;
2338 GetEditViewPtr()->MoveParagraphs( Range( pDragAndDropInfo->aBeginDragSel.nStartPara, pDragAndDropInfo->aBeginDragSel.nEndPara ), pDragAndDropInfo->nOutlinerDropDest );
2339 }
2340 else
2341 {
2342 uno::Reference< datatransfer::XTransferable > xDataObj = rDTDE.Transferable;
2343 if ( xDataObj.is() )
2344 {
2345 bChanges = true;
2346 // remove Selection ...
2347 DrawSelectionXOR();
2348 EditPaM aPaM( pDragAndDropInfo->aDropDest );
2349
2350 PasteOrDropInfos aPasteOrDropInfos;
2351 aPasteOrDropInfos.nStartPara = pEditEngine->GetEditDoc().GetPos( aPaM.GetNode() );
2352 pEditEngine->HandleBeginPasteOrDrop(aPasteOrDropInfos);
2353
2354 EditSelection aNewSel = pEditEngine->InsertText(
2355 xDataObj, OUString(), aPaM, pEditEngine->GetInternalEditStatus().AllowPasteSpecial());
2356
2357 aPasteOrDropInfos.nEndPara = pEditEngine->GetEditDoc().GetPos( aNewSel.Max().GetNode() );
2358 pEditEngine->HandleEndPasteOrDrop(aPasteOrDropInfos);
2359
2360 SetEditSelection( aNewSel );
2361 pEditEngine->pImpEditEngine->FormatAndUpdate( pEditEngine->pImpEditEngine->GetActiveView() );
2362 if ( pDragAndDropInfo->bStarterOfDD )
2363 {
2364 // Only set if the same engine!
2365 pDragAndDropInfo->aDropSel.nStartPara = pEditEngine->GetEditDoc().GetPos( aPaM.GetNode() );
2366 pDragAndDropInfo->aDropSel.nStartPos = aPaM.GetIndex();
2367 pDragAndDropInfo->aDropSel.nEndPara = pEditEngine->GetEditDoc().GetPos( aNewSel.Max().GetNode() );
2368 pDragAndDropInfo->aDropSel.nEndPos = aNewSel.Max().GetIndex();
2369 pDragAndDropInfo->bDroppedInMe = true;
2370 }
2371 }
2372 }
2373
2374 if ( bChanges )
2375 {
2376 rDTDE.Context->acceptDrop( rDTDE.DropAction );
2377 }
2378
2379 if ( !pDragAndDropInfo->bStarterOfDD )
2380 {
2381 pDragAndDropInfo.reset();
2382 }
2383
2384 rDTDE.Context->dropComplete( bChanges );
2385}
2386
2387void ImpEditView::dragEnter( const css::datatransfer::dnd::DropTargetDragEnterEvent& rDTDEE )
2388{
2389 SolarMutexGuard aVclGuard;
2390
2391 if ( !pDragAndDropInfo )
2392 pDragAndDropInfo.reset(new DragAndDropInfo());
2393
2394 pDragAndDropInfo->bHasValidData = false;
2395
2396 // Check for supported format...
2397 // Only check for text, will also be there if bin or rtf
2398 datatransfer::DataFlavor aTextFlavor;
2399 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING, aTextFlavor );
2400 const css::datatransfer::DataFlavor* pFlavors = rDTDEE.SupportedDataFlavors.getConstArray();
2401 int nFlavors = rDTDEE.SupportedDataFlavors.getLength();
2402 for ( int n = 0; n < nFlavors; n++ )
2403 {
2404 if( TransferableDataHelper::IsEqual( pFlavors[n], aTextFlavor ) )
2405 {
2406 pDragAndDropInfo->bHasValidData = true;
2407 break;
2408 }
2409 }
2410
2411 dragOver( rDTDEE );
2412}
2413
2414void ImpEditView::dragExit( const css::datatransfer::dnd::DropTargetEvent& )
2415{
2416 SolarMutexGuard aVclGuard;
2417
2418 HideDDCursor();
2419
2420 if ( pDragAndDropInfo && !pDragAndDropInfo->bStarterOfDD )
2421 {
2422 pDragAndDropInfo.reset();
2423 }
2424}
2425
2426void ImpEditView::dragOver(const css::datatransfer::dnd::DropTargetDragEvent& rDTDE)
2427{
2428 SolarMutexGuard aVclGuard;
2429
2430 const OutputDevice& rOutDev = getEditViewCallbacks() ? getEditViewCallbacks()->EditViewOutputDevice() : *GetWindow();
2431
2432 Point aMousePos( rDTDE.LocationX, rDTDE.LocationY );
2433 aMousePos = rOutDev.PixelToLogic( aMousePos );
2434
2435 bool bAccept = false;
2436
2437 if ( GetOutputArea().IsInside( aMousePos ) && !bReadOnly )
2438 {
2439 if ( pDragAndDropInfo && pDragAndDropInfo->bHasValidData )
2440 {
2441 bAccept = true;
2442
2443 bool bAllowScroll = DoAutoScroll();
2444 if ( bAllowScroll )
2445 {
2446 long nScrollX = 0;
2447 long nScrollY = 0;
2448 // Check if in the sensitive area
2449 if ( ( (aMousePos.X()-pDragAndDropInfo->nSensibleRange) < GetOutputArea().Left() ) && ( ( aMousePos.X() + pDragAndDropInfo->nSensibleRange ) > GetOutputArea().Left() ) )
2450 nScrollX = GetOutputArea().GetWidth() / SCRLRANGE20;
2451 else if ( ( (aMousePos.X()+pDragAndDropInfo->nSensibleRange) > GetOutputArea().Right() ) && ( ( aMousePos.X() - pDragAndDropInfo->nSensibleRange ) < GetOutputArea().Right() ) )
2452 nScrollX = -( GetOutputArea().GetWidth() / SCRLRANGE20 );
2453
2454 if ( ( (aMousePos.Y()-pDragAndDropInfo->nSensibleRange) < GetOutputArea().Top() ) && ( ( aMousePos.Y() + pDragAndDropInfo->nSensibleRange ) > GetOutputArea().Top() ) )
2455 nScrollY = GetOutputArea().GetHeight() / SCRLRANGE20;
2456 else if ( ( (aMousePos.Y()+pDragAndDropInfo->nSensibleRange) > GetOutputArea().Bottom() ) && ( ( aMousePos.Y() - pDragAndDropInfo->nSensibleRange ) < GetOutputArea().Bottom() ) )
2457 nScrollY = -( GetOutputArea().GetHeight() / SCRLRANGE20 );
2458
2459 if ( nScrollX || nScrollY )
2460 {
2461 HideDDCursor();
2462 Scroll( nScrollX, nScrollY, ScrollRangeCheck::PaperWidthTextSize );
2463 }
2464 }
2465
2466 Point aDocPos( GetDocPos( aMousePos ) );
2467 EditPaM aPaM = pEditEngine->GetPaM( aDocPos );
2468 pDragAndDropInfo->aDropDest = aPaM;
2469 if ( pDragAndDropInfo->bOutlinerMode )
2470 {
2471 sal_Int32 nPara = pEditEngine->GetEditDoc().GetPos( aPaM.GetNode() );
2472 ParaPortion* pPPortion = pEditEngine->GetParaPortions().SafeGetObject( nPara );
2473 if (pPPortion)
2474 {
2475 long nDestParaStartY = pEditEngine->GetParaPortions().GetYOffset( pPPortion );
2476 long nRel = aDocPos.Y() - nDestParaStartY;
2477 if ( nRel < ( pPPortion->GetHeight() / 2 ) )
2478 {
2479 pDragAndDropInfo->nOutlinerDropDest = nPara;
2480 }
2481 else
2482 {
2483 pDragAndDropInfo->nOutlinerDropDest = nPara+1;
2484 }
2485
2486 if( ( pDragAndDropInfo->nOutlinerDropDest >= pDragAndDropInfo->aBeginDragSel.nStartPara ) &&
2487 ( pDragAndDropInfo->nOutlinerDropDest <= (pDragAndDropInfo->aBeginDragSel.nEndPara+1) ) )
2488 {
2489 bAccept = false;
2490 }
2491 }
2492 }
2493 else if ( HasSelection() )
2494 {
2495 // it must not be dropped into a selection
2496 EPaM aP = pEditEngine->pImpEditEngine->CreateEPaM( aPaM );
2497 ESelection aDestSel( aP.nPara, aP.nIndex, aP.nPara, aP.nIndex);
2498 ESelection aCurSel = pEditEngine->pImpEditEngine->CreateESel( GetEditSelection() );
2499 aCurSel.Adjust();
2500 if ( !(aDestSel < aCurSel) && !(aDestSel > aCurSel) )
2501 {
2502 bAccept = false;
2503 }
2504 }
2505 if ( bAccept )
2506 {
2507 tools::Rectangle aEditCursor;
2508 if ( pDragAndDropInfo->bOutlinerMode )
2509 {
2510 long nDDYPos(0);
2511 if ( pDragAndDropInfo->nOutlinerDropDest < pEditEngine->GetEditDoc().Count() )
2512 {
2513 ParaPortion* pPPortion = pEditEngine->GetParaPortions().SafeGetObject( pDragAndDropInfo->nOutlinerDropDest );
2514 if (pPPortion)
2515 nDDYPos = pEditEngine->GetParaPortions().GetYOffset( pPPortion );
2516 }
2517 else
2518 {
2519 nDDYPos = pEditEngine->pImpEditEngine->GetTextHeight();
2520 }
2521 Point aStartPos( 0, nDDYPos );
2522 aStartPos = GetWindowPos( aStartPos );
2523 Point aEndPos( GetOutputArea().GetWidth(), nDDYPos );
2524 aEndPos = GetWindowPos( aEndPos );
2525 aEditCursor = rOutDev.LogicToPixel( tools::Rectangle( aStartPos, aEndPos ) );
2526 if ( !pEditEngine->IsVertical() )
2527 {
2528 aEditCursor.AdjustTop( -1 );
2529 aEditCursor.AdjustBottom( 1 );
2530 }
2531 else
2532 {
2533 if( IsTopToBottom() )
2534 {
2535 aEditCursor.AdjustLeft( -1 );
2536 aEditCursor.AdjustRight( 1 );
2537 }
2538 else
2539 {
2540 aEditCursor.AdjustLeft( 1 );
2541 aEditCursor.AdjustRight( -1 );
2542 }
2543 }
2544 aEditCursor = rOutDev.PixelToLogic( aEditCursor );
2545 }
2546 else
2547 {
2548 aEditCursor = pEditEngine->pImpEditEngine->PaMtoEditCursor( aPaM );
2549 Point aTopLeft( GetWindowPos( aEditCursor.TopLeft() ) );
2550 aEditCursor.SetPos( aTopLeft );
2551 aEditCursor.SetRight( aEditCursor.Left() + pDragAndDropInfo->nCursorWidth );
2552 aEditCursor = rOutDev.LogicToPixel( aEditCursor );
2553 aEditCursor = rOutDev.PixelToLogic( aEditCursor );
2554 }
2555
2556 bool bCursorChanged = !pDragAndDropInfo->bVisCursor || ( pDragAndDropInfo->aCurCursor != aEditCursor );
2557 if ( bCursorChanged )
2558 {
2559 HideDDCursor();
2560 ShowDDCursor(aEditCursor );
2561 }
2562 pDragAndDropInfo->bDragAccepted = true;
2563 rDTDE.Context->acceptDrag( rDTDE.DropAction );
2564 }
2565 }
2566 }
2567
2568 if ( !bAccept )
2569 {
2570 HideDDCursor();
2571 if (pDragAndDropInfo)
2572 pDragAndDropInfo->bDragAccepted = false;
2573 rDTDE.Context->rejectDrag();
2574 }
2575}
2576
2577void ImpEditView::AddDragAndDropListeners()
2578{
2579 if (bActiveDragAndDropListener)
2580 return;
2581
2582 css::uno::Reference<css::datatransfer::dnd::XDropTarget> xDropTarget;
2583 if (EditViewCallbacks* pCallbacks = getEditViewCallbacks())
2584 xDropTarget = pCallbacks->GetDropTarget();
2585 else if (GetWindow())
2586 xDropTarget = GetWindow()->GetDropTarget();
2587
2588 if (!xDropTarget.is())
2589 return;
2590
2591 vcl::unohelper::DragAndDropWrapper* pDnDWrapper = new vcl::unohelper::DragAndDropWrapper(this);
2592 mxDnDListener = pDnDWrapper;
2593
2594 css::uno::Reference<css::datatransfer::dnd::XDragGestureRecognizer> xDragGestureRecognizer(xDropTarget, uno::UNO_QUERY);
2595 if (xDragGestureRecognizer.is())
2596 {
2597 uno::Reference<datatransfer::dnd::XDragGestureListener> xDGL(mxDnDListener, uno::UNO_QUERY);
2598 xDragGestureRecognizer->addDragGestureListener(xDGL);
2599 }
2600
2601 uno::Reference<datatransfer::dnd::XDropTargetListener> xDTL(mxDnDListener, uno::UNO_QUERY);
2602 xDropTarget->addDropTargetListener(xDTL);
2603 xDropTarget->setActive(true);
2604 xDropTarget->setDefaultActions(datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE);
2605
2606 bActiveDragAndDropListener = true;
2607}
2608
2609void ImpEditView::RemoveDragAndDropListeners()
2610{
2611 if (!bActiveDragAndDropListener)
2612 return;
2613
2614 css::uno::Reference<css::datatransfer::dnd::XDropTarget> xDropTarget;
2615 if (EditViewCallbacks* pCallbacks = getEditViewCallbacks())
2616 xDropTarget = pCallbacks->GetDropTarget();
2617 else if (GetWindow())
2618 xDropTarget = GetWindow()->GetDropTarget();
2619
2620 if (!xDropTarget.is())
2621 return;
2622
2623 css::uno::Reference<css::datatransfer::dnd::XDragGestureRecognizer> xDragGestureRecognizer(xDropTarget, uno::UNO_QUERY);
2624 if (xDragGestureRecognizer.is())
2625 {
2626 uno::Reference<datatransfer::dnd::XDragGestureListener> xDGL(mxDnDListener, uno::UNO_QUERY);
2627 xDragGestureRecognizer->removeDragGestureListener(xDGL);
2628 }
2629
2630 uno::Reference<datatransfer::dnd::XDropTargetListener> xDTL(mxDnDListener, uno::UNO_QUERY);
2631 xDropTarget->removeDropTargetListener(xDTL);
2632
2633 if ( mxDnDListener.is() )
2634 {
2635 mxDnDListener->disposing( lang::EventObject() ); // #95154# Empty Source means it's the Client
2636 mxDnDListener.clear();
2637 }
2638
2639 bActiveDragAndDropListener = false;
2640}
2641
2642void ImpEditView::InitLOKSpecialPositioning(MapUnit eUnit,
2643 const tools::Rectangle& rOutputArea,
2644 const Point& rVisDocStartPos)
2645{
2646 if (!mpLOKSpecialPositioning)
2647 mpLOKSpecialPositioning.reset(new LOKSpecialPositioning(*this, eUnit, rOutputArea, rVisDocStartPos));
2648 else
2649 mpLOKSpecialPositioning->ReInit(eUnit, rOutputArea, rVisDocStartPos);
2650}
2651
2652void ImpEditView::SetLOKSpecialOutputArea(const tools::Rectangle& rOutputArea)
2653{
2654 assert(mpLOKSpecialPositioning)(static_cast <bool> (mpLOKSpecialPositioning) ? void (0
) : __assert_fail ("mpLOKSpecialPositioning", "/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
, 2654, __extension__ __PRETTY_FUNCTION__))
;
2655 mpLOKSpecialPositioning->SetOutputArea(rOutputArea);
2656}
2657
2658tools::Rectangle ImpEditView::GetLOKSpecialOutputArea() const
2659{
2660 assert(mpLOKSpecialPositioning)(static_cast <bool> (mpLOKSpecialPositioning) ? void (0
) : __assert_fail ("mpLOKSpecialPositioning", "/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
, 2660, __extension__ __PRETTY_FUNCTION__))
;
2661 return mpLOKSpecialPositioning->GetOutputArea();
2662}
2663
2664void ImpEditView::SetLOKSpecialVisArea(const tools::Rectangle& rVisArea)
2665{
2666 assert(mpLOKSpecialPositioning)(static_cast <bool> (mpLOKSpecialPositioning) ? void (0
) : __assert_fail ("mpLOKSpecialPositioning", "/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
, 2666, __extension__ __PRETTY_FUNCTION__))
;
2667 mpLOKSpecialPositioning->SetVisDocStartPos(rVisArea.TopLeft());
2668}
2669
2670tools::Rectangle ImpEditView::GetLOKSpecialVisArea() const
2671{
2672 assert(mpLOKSpecialPositioning)(static_cast <bool> (mpLOKSpecialPositioning) ? void (0
) : __assert_fail ("mpLOKSpecialPositioning", "/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
, 2672, __extension__ __PRETTY_FUNCTION__))
;
2673 return mpLOKSpecialPositioning->GetVisDocArea();
2674}
2675
2676bool ImpEditView::HasLOKSpecialPositioning() const
2677{
2678 return bool(mpLOKSpecialPositioning);
2679}
2680
2681/* vim:set shiftwidth=4 softtabstop=4 expandtab: */