File: | home/maarten/src/libreoffice/core/include/svx/svdedtv.hxx |
Warning: | line 180, column 114 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 <com/sun/star/i18n/WordType.hpp> | |||
21 | #include <editeng/editdata.hxx> | |||
22 | #include <editeng/editeng.hxx> | |||
23 | #include <editeng/editobj.hxx> | |||
24 | #include <editeng/editstat.hxx> | |||
25 | #include <editeng/outlobj.hxx> | |||
26 | #include <editeng/unotext.hxx> | |||
27 | #include <svl/itemiter.hxx> | |||
28 | #include <svl/style.hxx> | |||
29 | #include <svl/whiter.hxx> | |||
30 | #include <svtools/accessibilityoptions.hxx> | |||
31 | #include <svx/sdtfchim.hxx> | |||
32 | #include <svx/selectioncontroller.hxx> | |||
33 | #include <svx/svdedxv.hxx> | |||
34 | #include <svx/svdetc.hxx> | |||
35 | #include <svx/svdotable.hxx> | |||
36 | #include <svx/svdotext.hxx> | |||
37 | #include <svx/svdoutl.hxx> | |||
38 | #include <svx/svdpage.hxx> | |||
39 | #include <svx/svdpagv.hxx> | |||
40 | #include <svx/svdundo.hxx> | |||
41 | #include <vcl/canvastools.hxx> | |||
42 | #include <vcl/commandevent.hxx> | |||
43 | #include <vcl/cursor.hxx> | |||
44 | #include <vcl/weld.hxx> | |||
45 | #include <comphelper/lok.hxx> | |||
46 | #include <drawinglayer/processor2d/baseprocessor2d.hxx> | |||
47 | #include <drawinglayer/processor2d/processor2dtools.hxx> | |||
48 | #include <editeng/outliner.hxx> | |||
49 | #include <sal/log.hxx> | |||
50 | #include <sdr/overlay/overlaytools.hxx> | |||
51 | #include <sfx2/viewsh.hxx> | |||
52 | #include <svx/dialmgr.hxx> | |||
53 | #include <svx/sdr/overlay/overlaymanager.hxx> | |||
54 | #include <svx/sdr/overlay/overlayselection.hxx> | |||
55 | #include <svx/sdr/table/tablecontroller.hxx> | |||
56 | #include <svx/sdrpagewindow.hxx> | |||
57 | #include <svx/sdrpaintwindow.hxx> | |||
58 | #include <svx/sdrundomanager.hxx> | |||
59 | #include <svx/strings.hrc> | |||
60 | #include <svx/svdviter.hxx> | |||
61 | #include <textchain.hxx> | |||
62 | #include <textchaincursor.hxx> | |||
63 | #include <tools/debug.hxx> | |||
64 | #include <vcl/svapp.hxx> | |||
65 | ||||
66 | #include <memory> | |||
67 | ||||
68 | SdrObjEditView::SdrObjEditView(SdrModel& rSdrModel, OutputDevice* pOut) | |||
69 | : SdrGlueEditView(rSdrModel, pOut) | |||
70 | , pTextEditPV(nullptr) | |||
71 | , pTextEditOutlinerView(nullptr) | |||
72 | , pTextEditWin(nullptr) | |||
73 | , pTextEditCursorBuffer(nullptr) | |||
74 | , pMacroObj(nullptr) | |||
75 | , pMacroPV(nullptr) | |||
76 | , pMacroWin(nullptr) | |||
77 | , nMacroTol(0) | |||
78 | , bTextEditDontDelete(false) | |||
79 | , bTextEditOnlyOneView(false) | |||
80 | , bTextEditNewObj(false) | |||
81 | , bQuickTextEditMode(true) | |||
82 | , bMacroDown(false) | |||
83 | , mpOldTextEditUndoManager(nullptr) | |||
84 | { | |||
85 | } | |||
86 | ||||
87 | SdrObjEditView::~SdrObjEditView() | |||
88 | { | |||
89 | pTextEditWin = nullptr; // so there's no ShowCursor in SdrEndTextEdit | |||
90 | assert(!IsTextEdit())(static_cast <bool> (!IsTextEdit()) ? void (0) : __assert_fail ("!IsTextEdit()", "/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" , 90, __extension__ __PRETTY_FUNCTION__)); | |||
91 | if (IsTextEdit()) | |||
92 | SdrEndTextEdit(); | |||
93 | pTextEditOutliner.reset(); | |||
94 | assert(nullptr == mpOldTextEditUndoManager)(static_cast <bool> (nullptr == mpOldTextEditUndoManager ) ? void (0) : __assert_fail ("nullptr == mpOldTextEditUndoManager" , "/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" , 94, __extension__ __PRETTY_FUNCTION__)); // should have been reset | |||
95 | } | |||
96 | ||||
97 | bool SdrObjEditView::IsAction() const { return IsMacroObj() || SdrGlueEditView::IsAction(); } | |||
98 | ||||
99 | void SdrObjEditView::MovAction(const Point& rPnt) | |||
100 | { | |||
101 | if (IsMacroObj()) | |||
102 | MovMacroObj(rPnt); | |||
103 | SdrGlueEditView::MovAction(rPnt); | |||
104 | } | |||
105 | ||||
106 | void SdrObjEditView::EndAction() | |||
107 | { | |||
108 | if (IsMacroObj()) | |||
109 | EndMacroObj(); | |||
110 | SdrGlueEditView::EndAction(); | |||
111 | } | |||
112 | ||||
113 | void SdrObjEditView::BckAction() | |||
114 | { | |||
115 | BrkMacroObj(); | |||
116 | SdrGlueEditView::BckAction(); | |||
117 | } | |||
118 | ||||
119 | void SdrObjEditView::BrkAction() | |||
120 | { | |||
121 | BrkMacroObj(); | |||
122 | SdrGlueEditView::BrkAction(); | |||
123 | } | |||
124 | ||||
125 | SdrPageView* SdrObjEditView::ShowSdrPage(SdrPage* pPage) | |||
126 | { | |||
127 | SdrPageView* pPageView = SdrGlueEditView::ShowSdrPage(pPage); | |||
128 | ||||
129 | if (comphelper::LibreOfficeKit::isActive() && pPageView) | |||
130 | { | |||
131 | // Check if other views have an active text edit on the same page as | |||
132 | // this one. | |||
133 | SdrViewIter aIter(pPageView->GetPage()); | |||
134 | for (SdrView* pView = aIter.FirstView(); pView; pView = aIter.NextView()) | |||
135 | { | |||
136 | if (pView == this || !pView->IsTextEdit()) | |||
137 | continue; | |||
138 | ||||
139 | OutputDevice* pOutDev = GetFirstOutputDevice(); | |||
140 | if (!pOutDev || pOutDev->GetOutDevType() != OUTDEV_WINDOW) | |||
141 | continue; | |||
142 | ||||
143 | // Found one, so create an outliner view, to get invalidations when | |||
144 | // the text edit changes. | |||
145 | // Call GetSfxViewShell() to make sure ImpMakeOutlinerView() | |||
146 | // registers the view shell of this draw view, and not the view | |||
147 | // shell of pView. | |||
148 | OutlinerView* pOutlinerView = pView->ImpMakeOutlinerView( | |||
149 | static_cast<vcl::Window*>(pOutDev), nullptr, GetSfxViewShell()); | |||
150 | pOutlinerView->HideCursor(); | |||
151 | pView->GetTextEditOutliner()->InsertView(pOutlinerView); | |||
152 | } | |||
153 | } | |||
154 | ||||
155 | return pPageView; | |||
156 | } | |||
157 | ||||
158 | namespace | |||
159 | { | |||
160 | /// Removes outliner views registered in other draw views that use pOutputDevice. | |||
161 | void lcl_RemoveTextEditOutlinerViews(SdrObjEditView const* pThis, SdrPageView const* pPageView, | |||
162 | OutputDevice const* pOutputDevice) | |||
163 | { | |||
164 | if (!comphelper::LibreOfficeKit::isActive()) | |||
165 | return; | |||
166 | ||||
167 | if (!pPageView) | |||
168 | return; | |||
169 | ||||
170 | if (!pOutputDevice || pOutputDevice->GetOutDevType() != OUTDEV_WINDOW) | |||
171 | return; | |||
172 | ||||
173 | SdrViewIter aIter(pPageView->GetPage()); | |||
174 | for (SdrView* pView = aIter.FirstView(); pView; pView = aIter.NextView()) | |||
175 | { | |||
176 | if (pView == pThis || !pView->IsTextEdit()) | |||
177 | continue; | |||
178 | ||||
179 | SdrOutliner* pOutliner = pView->GetTextEditOutliner(); | |||
180 | for (size_t nView = 0; nView < pOutliner->GetViewCount(); ++nView) | |||
181 | { | |||
182 | OutlinerView* pOutlinerView = pOutliner->GetView(nView); | |||
183 | if (pOutlinerView->GetWindow() != pOutputDevice) | |||
184 | continue; | |||
185 | ||||
186 | pOutliner->RemoveView(pOutlinerView); | |||
187 | delete pOutlinerView; | |||
188 | } | |||
189 | } | |||
190 | } | |||
191 | } | |||
192 | ||||
193 | void SdrObjEditView::HideSdrPage() | |||
194 | { | |||
195 | lcl_RemoveTextEditOutlinerViews(this, GetSdrPageView(), GetFirstOutputDevice()); | |||
196 | ||||
197 | SdrGlueEditView::HideSdrPage(); | |||
198 | } | |||
199 | ||||
200 | void SdrObjEditView::TakeActionRect(tools::Rectangle& rRect) const | |||
201 | { | |||
202 | if (IsMacroObj()) | |||
203 | { | |||
204 | rRect = pMacroObj->GetCurrentBoundRect(); | |||
205 | } | |||
206 | else | |||
207 | { | |||
208 | SdrGlueEditView::TakeActionRect(rRect); | |||
209 | } | |||
210 | } | |||
211 | ||||
212 | void SdrObjEditView::Notify(SfxBroadcaster& rBC, const SfxHint& rHint) | |||
213 | { | |||
214 | SdrGlueEditView::Notify(rBC, rHint); | |||
215 | if (pTextEditOutliner == nullptr) | |||
216 | return; | |||
217 | ||||
218 | // change of printer while editing | |||
219 | if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint) | |||
220 | return; | |||
221 | ||||
222 | const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint); | |||
223 | SdrHintKind eKind = pSdrHint->GetKind(); | |||
224 | if (eKind == SdrHintKind::RefDeviceChange) | |||
225 | { | |||
226 | pTextEditOutliner->SetRefDevice(mpModel->GetRefDevice()); | |||
227 | } | |||
228 | if (eKind == SdrHintKind::DefaultTabChange) | |||
229 | { | |||
230 | pTextEditOutliner->SetDefTab(mpModel->GetDefaultTabulator()); | |||
231 | } | |||
232 | } | |||
233 | ||||
234 | void SdrObjEditView::ModelHasChanged() | |||
235 | { | |||
236 | SdrGlueEditView::ModelHasChanged(); | |||
237 | if (mxTextEditObj.is() && !mxTextEditObj->IsInserted()) | |||
238 | SdrEndTextEdit(); // object deleted | |||
239 | // TextEditObj changed? | |||
240 | if (!IsTextEdit()) | |||
241 | return; | |||
242 | ||||
243 | SdrTextObj* pTextObj = mxTextEditObj.get(); | |||
244 | if (pTextObj != nullptr) | |||
245 | { | |||
246 | size_t nOutlViewCnt = pTextEditOutliner->GetViewCount(); | |||
247 | bool bAreaChg = false; | |||
248 | bool bAnchorChg = false; | |||
249 | bool bColorChg = false; | |||
250 | bool bContourFrame = pTextObj->IsContourTextFrame(); | |||
251 | EEAnchorMode eNewAnchor(EEAnchorMode::VCenterHCenter); | |||
252 | tools::Rectangle aOldArea(aMinTextEditArea); | |||
253 | aOldArea.Union(aTextEditArea); | |||
254 | Color aNewColor; | |||
255 | { // check area | |||
256 | Size aPaperMin1; | |||
257 | Size aPaperMax1; | |||
258 | tools::Rectangle aEditArea1; | |||
259 | tools::Rectangle aMinArea1; | |||
260 | pTextObj->TakeTextEditArea(&aPaperMin1, &aPaperMax1, &aEditArea1, &aMinArea1); | |||
261 | Point aPvOfs(pTextObj->GetTextEditOffset()); | |||
262 | ||||
263 | // add possible GridOffset to up-to-now view-independent EditAreas | |||
264 | basegfx::B2DVector aGridOffset(0.0, 0.0); | |||
265 | if (getPossibleGridOffsetForSdrObject(aGridOffset, pTextObj, GetSdrPageView())) | |||
266 | { | |||
267 | const Point aOffset(basegfx::fround(aGridOffset.getX()), | |||
268 | basegfx::fround(aGridOffset.getY())); | |||
269 | ||||
270 | aEditArea1 += aOffset; | |||
271 | aMinArea1 += aOffset; | |||
272 | } | |||
273 | ||||
274 | aEditArea1.Move(aPvOfs.X(), aPvOfs.Y()); | |||
275 | aMinArea1.Move(aPvOfs.X(), aPvOfs.Y()); | |||
276 | tools::Rectangle aNewArea(aMinArea1); | |||
277 | aNewArea.Union(aEditArea1); | |||
278 | ||||
279 | if (aNewArea != aOldArea || aEditArea1 != aTextEditArea || aMinArea1 != aMinTextEditArea | |||
280 | || pTextEditOutliner->GetMinAutoPaperSize() != aPaperMin1 | |||
281 | || pTextEditOutliner->GetMaxAutoPaperSize() != aPaperMax1) | |||
282 | { | |||
283 | aTextEditArea = aEditArea1; | |||
284 | aMinTextEditArea = aMinArea1; | |||
285 | pTextEditOutliner->SetUpdateMode(false); | |||
286 | pTextEditOutliner->SetMinAutoPaperSize(aPaperMin1); | |||
287 | pTextEditOutliner->SetMaxAutoPaperSize(aPaperMax1); | |||
288 | pTextEditOutliner->SetPaperSize(Size(0, 0)); // re-format Outliner | |||
289 | if (!bContourFrame) | |||
290 | { | |||
291 | pTextEditOutliner->ClearPolygon(); | |||
292 | EEControlBits nStat = pTextEditOutliner->GetControlWord(); | |||
293 | nStat |= EEControlBits::AUTOPAGESIZE; | |||
294 | pTextEditOutliner->SetControlWord(nStat); | |||
295 | } | |||
296 | else | |||
297 | { | |||
298 | EEControlBits nStat = pTextEditOutliner->GetControlWord(); | |||
299 | nStat &= ~EEControlBits::AUTOPAGESIZE; | |||
300 | pTextEditOutliner->SetControlWord(nStat); | |||
301 | tools::Rectangle aAnchorRect; | |||
302 | pTextObj->TakeTextAnchorRect(aAnchorRect); | |||
303 | pTextObj->ImpSetContourPolygon(*pTextEditOutliner, aAnchorRect, true); | |||
304 | } | |||
305 | for (size_t nOV = 0; nOV < nOutlViewCnt; nOV++) | |||
306 | { | |||
307 | OutlinerView* pOLV = pTextEditOutliner->GetView(nOV); | |||
308 | EVControlBits nStat0 = pOLV->GetControlWord(); | |||
309 | EVControlBits nStat = nStat0; | |||
310 | // AutoViewSize only if not ContourFrame. | |||
311 | if (!bContourFrame) | |||
312 | nStat |= EVControlBits::AUTOSIZE; | |||
313 | else | |||
314 | nStat &= ~EVControlBits::AUTOSIZE; | |||
315 | if (nStat != nStat0) | |||
316 | pOLV->SetControlWord(nStat); | |||
317 | } | |||
318 | pTextEditOutliner->SetUpdateMode(true); | |||
319 | bAreaChg = true; | |||
320 | } | |||
321 | } | |||
322 | if (pTextEditOutlinerView != nullptr) | |||
323 | { // check fill and anchor | |||
324 | EEAnchorMode eOldAnchor = pTextEditOutlinerView->GetAnchorMode(); | |||
325 | eNewAnchor = pTextObj->GetOutlinerViewAnchorMode(); | |||
326 | bAnchorChg = eOldAnchor != eNewAnchor; | |||
327 | Color aOldColor(pTextEditOutlinerView->GetBackgroundColor()); | |||
328 | aNewColor = GetTextEditBackgroundColor(*this); | |||
329 | bColorChg = aOldColor != aNewColor; | |||
330 | } | |||
331 | // refresh always when it's a contour frame. That | |||
332 | // refresh is necessary since it triggers the repaint | |||
333 | // which makes the Handles visible. Changes at TakeTextRect() | |||
334 | // seem to have resulted in a case where no refresh is executed. | |||
335 | // Before that, a refresh must have been always executed | |||
336 | // (else this error would have happened earlier), thus I | |||
337 | // even think here a refresh should be done always. | |||
338 | // Since follow-up problems cannot even be guessed I only | |||
339 | // add this one more case to the if below. | |||
340 | // BTW: It's VERY bad style that here, inside ModelHasChanged() | |||
341 | // the outliner is again massively changed for the text object | |||
342 | // in text edit mode. Normally, all necessary data should be | |||
343 | // set at SdrBeginTextEdit(). Some changes and value assigns in | |||
344 | // SdrBeginTextEdit() are completely useless since they are set here | |||
345 | // again on ModelHasChanged(). | |||
346 | if (bContourFrame || bAreaChg || bAnchorChg || bColorChg) | |||
347 | { | |||
348 | for (size_t nOV = 0; nOV < nOutlViewCnt; nOV++) | |||
349 | { | |||
350 | OutlinerView* pOLV = pTextEditOutliner->GetView(nOV); | |||
351 | { // invalidate old OutlinerView area | |||
352 | vcl::Window* pWin = pOLV->GetWindow(); | |||
353 | tools::Rectangle aTmpRect(aOldArea); | |||
354 | sal_uInt16 nPixSiz = pOLV->GetInvalidateMore() + 1; | |||
355 | Size aMore(pWin->PixelToLogic(Size(nPixSiz, nPixSiz))); | |||
356 | aTmpRect.AdjustLeft(-(aMore.Width())); | |||
357 | aTmpRect.AdjustRight(aMore.Width()); | |||
358 | aTmpRect.AdjustTop(-(aMore.Height())); | |||
359 | aTmpRect.AdjustBottom(aMore.Height()); | |||
360 | InvalidateOneWin(*pWin, aTmpRect); | |||
361 | } | |||
362 | if (bAnchorChg) | |||
363 | pOLV->SetAnchorMode(eNewAnchor); | |||
364 | if (bColorChg) | |||
365 | pOLV->SetBackgroundColor(aNewColor); | |||
366 | ||||
367 | pOLV->SetOutputArea( | |||
368 | aTextEditArea); // because otherwise, we're not re-anchoring correctly | |||
369 | ImpInvalidateOutlinerView(*pOLV); | |||
370 | } | |||
371 | pTextEditOutlinerView->ShowCursor(); | |||
372 | } | |||
373 | } | |||
374 | ImpMakeTextCursorAreaVisible(); | |||
375 | } | |||
376 | ||||
377 | namespace | |||
378 | { | |||
379 | /** | |||
380 | Helper class to visualize the content of an active EditView as an | |||
381 | OverlayObject. These objects work with Primitives and are handled | |||
382 | from the OverlayManager(s) in place as needed. | |||
383 | ||||
384 | It allows complete visualization of the content of the active | |||
385 | EditView without the need of Invalidates triggered by the EditView | |||
386 | and thus avoiding potentially expensive repaints by using the | |||
387 | automatically buffered Overlay mechanism. | |||
388 | ||||
389 | It buffers as much as possible locally and *only* triggers a real | |||
390 | change (see call to objectChange()) when really needed. | |||
391 | */ | |||
392 | class TextEditOverlayObject : public sdr::overlay::OverlayObject | |||
393 | { | |||
394 | protected: | |||
395 | /// local access to associated sdr::overlay::OverlaySelection | |||
396 | sdr::overlay::OverlaySelection* mpOverlaySelection; | |||
397 | ||||
398 | /// local definition depends on active OutlinerView | |||
399 | OutlinerView& mrOutlinerView; | |||
400 | ||||
401 | /// geometry definitions with buffering | |||
402 | basegfx::B2DRange maLastRange; | |||
403 | basegfx::B2DRange maRange; | |||
404 | ||||
405 | /// text content definitions with buffering | |||
406 | drawinglayer::primitive2d::Primitive2DContainer maTextPrimitives; | |||
407 | drawinglayer::primitive2d::Primitive2DContainer maLastTextPrimitives; | |||
408 | ||||
409 | /// bitfield | |||
410 | bool mbVisualizeSurroundingFrame : 1; | |||
411 | ||||
412 | // geometry creation for OverlayObject, can use local *Last* values | |||
413 | virtual drawinglayer::primitive2d::Primitive2DContainer | |||
414 | createOverlayObjectPrimitive2DSequence() override; | |||
415 | ||||
416 | public: | |||
417 | TextEditOverlayObject(const Color& rColor, OutlinerView& rOutlinerView, | |||
418 | bool bVisualizeSurroundingFrame); | |||
419 | virtual ~TextEditOverlayObject() override; | |||
420 | ||||
421 | // data read access | |||
422 | const sdr::overlay::OverlaySelection* getOverlaySelection() const { return mpOverlaySelection; } | |||
423 | const OutlinerView& getOutlinerView() const { return mrOutlinerView; } | |||
424 | ||||
425 | /// override to check conditions for last createOverlayObjectPrimitive2DSequence | |||
426 | virtual drawinglayer::primitive2d::Primitive2DContainer | |||
427 | getOverlayObjectPrimitive2DSequence() const override; | |||
428 | ||||
429 | // data write access. In this OverlayObject we only have the | |||
430 | // callback that triggers detecting if something *has* changed | |||
431 | void checkDataChange(const basegfx::B2DRange& rMinTextEditArea); | |||
432 | void checkSelectionChange(); | |||
433 | }; | |||
434 | ||||
435 | drawinglayer::primitive2d::Primitive2DContainer | |||
436 | TextEditOverlayObject::createOverlayObjectPrimitive2DSequence() | |||
437 | { | |||
438 | drawinglayer::primitive2d::Primitive2DContainer aRetval; | |||
439 | ||||
440 | /// outer frame visualization | |||
441 | if (mbVisualizeSurroundingFrame) | |||
442 | { | |||
443 | const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer; | |||
444 | const double fTransparence(aSvtOptionsDrawinglayer.GetTransparentSelectionPercent() * 0.01); | |||
445 | const sal_uInt16 nPixSiz(getOutlinerView().GetInvalidateMore() - 1); | |||
446 | ||||
447 | aRetval.push_back(new drawinglayer::primitive2d::OverlayRectanglePrimitive( | |||
448 | maRange, getBaseColor().getBColor(), fTransparence, std::max(6, nPixSiz - 2), // grow | |||
449 | 0.0, // shrink | |||
450 | 0.0)); | |||
451 | } | |||
452 | ||||
453 | // add buffered TextPrimitives | |||
454 | aRetval.append(maTextPrimitives); | |||
455 | ||||
456 | return aRetval; | |||
457 | } | |||
458 | ||||
459 | TextEditOverlayObject::TextEditOverlayObject(const Color& rColor, OutlinerView& rOutlinerView, | |||
460 | bool bVisualizeSurroundingFrame) | |||
461 | : OverlayObject(rColor) | |||
462 | , mpOverlaySelection(nullptr) | |||
463 | , mrOutlinerView(rOutlinerView) | |||
464 | , maLastRange() | |||
465 | , maRange() | |||
466 | , maTextPrimitives() | |||
467 | , maLastTextPrimitives() | |||
468 | , mbVisualizeSurroundingFrame(bVisualizeSurroundingFrame) | |||
469 | { | |||
470 | // no AA for TextEdit overlay | |||
471 | allowAntiAliase(false); | |||
472 | ||||
473 | // create local OverlaySelection - this is an integral part of EditText | |||
474 | // visualization | |||
475 | const std::vector<basegfx::B2DRange> aEmptySelection{}; | |||
476 | mpOverlaySelection = new sdr::overlay::OverlaySelection(sdr::overlay::OverlayType::Transparent, | |||
477 | rColor, aEmptySelection, true); | |||
478 | } | |||
479 | ||||
480 | TextEditOverlayObject::~TextEditOverlayObject() | |||
481 | { | |||
482 | if (getOverlaySelection()) | |||
483 | { | |||
484 | delete mpOverlaySelection; | |||
485 | mpOverlaySelection = nullptr; | |||
486 | } | |||
487 | ||||
488 | if (getOverlayManager()) | |||
489 | { | |||
490 | getOverlayManager()->remove(*this); | |||
491 | } | |||
492 | } | |||
493 | ||||
494 | drawinglayer::primitive2d::Primitive2DContainer | |||
495 | TextEditOverlayObject::getOverlayObjectPrimitive2DSequence() const | |||
496 | { | |||
497 | if (!getPrimitive2DSequence().empty()) | |||
498 | { | |||
499 | if (!maRange.equal(maLastRange) || maLastTextPrimitives != maTextPrimitives) | |||
500 | { | |||
501 | // conditions of last local decomposition have changed, delete to force new evaluation | |||
502 | const_cast<TextEditOverlayObject*>(this)->resetPrimitive2DSequence(); | |||
503 | } | |||
504 | } | |||
505 | ||||
506 | if (getPrimitive2DSequence().empty()) | |||
507 | { | |||
508 | // remember new buffered values | |||
509 | const_cast<TextEditOverlayObject*>(this)->maLastRange = maRange; | |||
510 | const_cast<TextEditOverlayObject*>(this)->maLastTextPrimitives = maTextPrimitives; | |||
511 | } | |||
512 | ||||
513 | // call base implementation | |||
514 | return OverlayObject::getOverlayObjectPrimitive2DSequence(); | |||
515 | } | |||
516 | ||||
517 | void TextEditOverlayObject::checkDataChange(const basegfx::B2DRange& rMinTextEditArea) | |||
518 | { | |||
519 | bool bObjectChange(false); | |||
520 | ||||
521 | // check current range | |||
522 | const tools::Rectangle aOutArea(mrOutlinerView.GetOutputArea()); | |||
523 | basegfx::B2DRange aNewRange = vcl::unotools::b2DRectangleFromRectangle(aOutArea); | |||
524 | aNewRange.expand(rMinTextEditArea); | |||
525 | ||||
526 | if (aNewRange != maRange) | |||
527 | { | |||
528 | maRange = aNewRange; | |||
529 | bObjectChange = true; | |||
530 | } | |||
531 | ||||
532 | // check if text primitives did change | |||
533 | SdrOutliner* pSdrOutliner = dynamic_cast<SdrOutliner*>(getOutlinerView().GetOutliner()); | |||
534 | ||||
535 | if (pSdrOutliner) | |||
536 | { | |||
537 | // get TextPrimitives directly from active Outliner | |||
538 | basegfx::B2DHomMatrix aNewTransformA; | |||
539 | basegfx::B2DHomMatrix aNewTransformB; | |||
540 | basegfx::B2DRange aClipRange; | |||
541 | drawinglayer::primitive2d::Primitive2DContainer aNewTextPrimitives; | |||
542 | ||||
543 | // active Outliner is always in unified oriented coordinate system (currently) | |||
544 | // so just translate to TopLeft of visible Range. Keep in mind that top-left | |||
545 | // depends on vertical text and top-to-bottom text attributes | |||
546 | const tools::Rectangle aVisArea(mrOutlinerView.GetVisArea()); | |||
547 | const bool bVerticalWriting(pSdrOutliner->IsVertical()); | |||
548 | const bool bTopToBottom(pSdrOutliner->IsTopToBottom()); | |||
549 | const double fStartInX(bVerticalWriting && bTopToBottom | |||
550 | ? aOutArea.Right() - aVisArea.Left() | |||
551 | : aOutArea.Left() - aVisArea.Left()); | |||
552 | const double fStartInY(bVerticalWriting && !bTopToBottom | |||
553 | ? aOutArea.Bottom() - aVisArea.Top() | |||
554 | : aOutArea.Top() - aVisArea.Top()); | |||
555 | ||||
556 | aNewTransformB.translate(fStartInX, fStartInY); | |||
557 | ||||
558 | // get the current TextPrimitives. This is the most expensive part | |||
559 | // of this mechanism, it *may* be possible to buffer layouted | |||
560 | // primitives per ParaPortion with/in/dependent on the EditEngine | |||
561 | // content if needed. For now, get and compare | |||
562 | SdrTextObj::impDecomposeBlockTextPrimitiveDirect( | |||
563 | aNewTextPrimitives, *pSdrOutliner, aNewTransformA, aNewTransformB, aClipRange); | |||
564 | ||||
565 | if (aNewTextPrimitives != maTextPrimitives) | |||
566 | { | |||
567 | maTextPrimitives = aNewTextPrimitives; | |||
568 | bObjectChange = true; | |||
569 | } | |||
570 | } | |||
571 | ||||
572 | if (bObjectChange) | |||
573 | { | |||
574 | // if there really *was* a change signal the OverlayManager to | |||
575 | // refresh this object's visualization | |||
576 | objectChange(); | |||
577 | ||||
578 | // on data change, always do a SelectionChange, too | |||
579 | // since the selection is an integral part of text visualization | |||
580 | checkSelectionChange(); | |||
581 | } | |||
582 | } | |||
583 | ||||
584 | void TextEditOverlayObject::checkSelectionChange() | |||
585 | { | |||
586 | if (!(getOverlaySelection() && getOverlayManager())) | |||
587 | return; | |||
588 | ||||
589 | std::vector<tools::Rectangle> aLogicRects; | |||
590 | std::vector<basegfx::B2DRange> aLogicRanges; | |||
591 | const Size aLogicPixel(getOverlayManager()->getOutputDevice().PixelToLogic(Size(1, 1))); | |||
592 | ||||
593 | // get logic selection | |||
594 | getOutlinerView().GetSelectionRectangles(aLogicRects); | |||
595 | ||||
596 | aLogicRanges.reserve(aLogicRects.size()); | |||
597 | for (const auto& aRect : aLogicRects) | |||
598 | { | |||
599 | // convert from logic Rectangles to logic Ranges, do not forget to add | |||
600 | // one Unit (in this case logical units for one pixel, pre-calculated) | |||
601 | aLogicRanges.emplace_back( | |||
602 | aRect.Left() - aLogicPixel.Width(), aRect.Top() - aLogicPixel.Height(), | |||
603 | aRect.Right() + aLogicPixel.Width(), aRect.Bottom() + aLogicPixel.Height()); | |||
604 | } | |||
605 | ||||
606 | mpOverlaySelection->setRanges(aLogicRanges); | |||
607 | } | |||
608 | } // end of anonymous namespace | |||
609 | ||||
610 | // TextEdit | |||
611 | ||||
612 | // callback from the active EditView, forward to evtl. existing instances of the | |||
613 | // TextEditOverlayObject(s). This will additionally update the selection which | |||
614 | // is an integral part of the text visualization | |||
615 | void SdrObjEditView::EditViewInvalidate(const tools::Rectangle&) | |||
616 | { | |||
617 | if (!IsTextEdit()) | |||
618 | return; | |||
619 | ||||
620 | // MinTextRange may have changed. Forward it, too | |||
621 | const basegfx::B2DRange aMinTextRange | |||
622 | = vcl::unotools::b2DRectangleFromRectangle(aMinTextEditArea); | |||
623 | ||||
624 | for (sal_uInt32 a(0); a < maTEOverlayGroup.count(); a++) | |||
625 | { | |||
626 | TextEditOverlayObject* pCandidate | |||
627 | = dynamic_cast<TextEditOverlayObject*>(&maTEOverlayGroup.getOverlayObject(a)); | |||
628 | ||||
629 | if (pCandidate) | |||
630 | { | |||
631 | pCandidate->checkDataChange(aMinTextRange); | |||
632 | } | |||
633 | } | |||
634 | } | |||
635 | ||||
636 | // callback from the active EditView, forward to evtl. existing instances of the | |||
637 | // TextEditOverlayObject(s). This cvall *only* updates the selection visualization | |||
638 | // which is e.g. used when only the selection is changed, but not the text | |||
639 | void SdrObjEditView::EditViewSelectionChange() | |||
640 | { | |||
641 | if (!IsTextEdit()) | |||
642 | return; | |||
643 | ||||
644 | for (sal_uInt32 a(0); a < maTEOverlayGroup.count(); a++) | |||
645 | { | |||
646 | TextEditOverlayObject* pCandidate | |||
647 | = dynamic_cast<TextEditOverlayObject*>(&maTEOverlayGroup.getOverlayObject(a)); | |||
648 | ||||
649 | if (pCandidate) | |||
650 | { | |||
651 | pCandidate->checkSelectionChange(); | |||
652 | } | |||
653 | } | |||
654 | } | |||
655 | ||||
656 | OutputDevice& SdrObjEditView::EditViewOutputDevice() const { return *pTextEditWin; } | |||
657 | ||||
658 | void SdrObjEditView::EditViewInputContext(const InputContext& rInputContext) | |||
659 | { | |||
660 | if (!pTextEditWin) | |||
661 | return; | |||
662 | pTextEditWin->SetInputContext(rInputContext); | |||
663 | } | |||
664 | ||||
665 | void SdrObjEditView::EditViewCursorRect(const tools::Rectangle& rRect, int nExtTextInputWidth) | |||
666 | { | |||
667 | if (!pTextEditWin) | |||
668 | return; | |||
669 | pTextEditWin->SetCursorRect(&rRect, nExtTextInputWidth); | |||
670 | } | |||
671 | ||||
672 | void SdrObjEditView::TextEditDrawing(SdrPaintWindow& rPaintWindow) | |||
673 | { | |||
674 | if (!comphelper::LibreOfficeKit::isActive()) | |||
675 | { | |||
676 | // adapt all TextEditOverlayObject(s), so call EditViewInvalidate() | |||
677 | // to update accordingly (will update selection, too). Suppress new | |||
678 | // stuff when LibreOfficeKit is active | |||
679 | EditViewInvalidate(tools::Rectangle()); | |||
680 | } | |||
681 | else | |||
682 | { | |||
683 | // draw old text edit stuff | |||
684 | if (IsTextEdit()) | |||
685 | { | |||
686 | const SdrOutliner* pActiveOutliner = GetTextEditOutliner(); | |||
687 | ||||
688 | if (pActiveOutliner) | |||
689 | { | |||
690 | const sal_uInt32 nViewCount(pActiveOutliner->GetViewCount()); | |||
691 | ||||
692 | if (nViewCount) | |||
693 | { | |||
694 | const vcl::Region& rRedrawRegion = rPaintWindow.GetRedrawRegion(); | |||
695 | const tools::Rectangle aCheckRect(rRedrawRegion.GetBoundRect()); | |||
696 | ||||
697 | for (sal_uInt32 i(0); i < nViewCount; i++) | |||
698 | { | |||
699 | OutlinerView* pOLV = pActiveOutliner->GetView(i); | |||
700 | ||||
701 | // If rPaintWindow knows that the output device is a render | |||
702 | // context and is aware of the underlying vcl::Window, | |||
703 | // compare against that; that's how double-buffering can | |||
704 | // still find the matching OutlinerView. | |||
705 | OutputDevice* pOutputDevice = rPaintWindow.GetWindow() | |||
706 | ? rPaintWindow.GetWindow() | |||
707 | : &rPaintWindow.GetOutputDevice(); | |||
708 | if (pOLV->GetWindow() == pOutputDevice | |||
709 | || comphelper::LibreOfficeKit::isActive()) | |||
710 | { | |||
711 | ImpPaintOutlinerView(*pOLV, aCheckRect, | |||
712 | rPaintWindow.GetTargetOutputDevice()); | |||
713 | return; | |||
714 | } | |||
715 | } | |||
716 | } | |||
717 | } | |||
718 | } | |||
719 | } | |||
720 | } | |||
721 | ||||
722 | void SdrObjEditView::ImpPaintOutlinerView(OutlinerView& rOutlView, const tools::Rectangle& rRect, | |||
723 | OutputDevice& rTargetDevice) const | |||
724 | { | |||
725 | const SdrTextObj* pText = GetTextEditObject(); | |||
726 | bool bTextFrame(pText && pText->IsTextFrame()); | |||
727 | bool bFitToSize(pTextEditOutliner->GetControlWord() & EEControlBits::STRETCHING); | |||
728 | bool bModified(pTextEditOutliner->IsModified()); | |||
729 | tools::Rectangle aBlankRect(rOutlView.GetOutputArea()); | |||
730 | aBlankRect.Union(aMinTextEditArea); | |||
731 | tools::Rectangle aPixRect(rTargetDevice.LogicToPixel(aBlankRect)); | |||
732 | ||||
733 | // in the tiled rendering case, the setup is incomplete, and we very | |||
734 | // easily get an empty rRect on input - that will cause that everything is | |||
735 | // clipped; happens in case of editing text inside a shape in Calc. | |||
736 | // FIXME would be better to complete the setup so that we don't get an | |||
737 | // empty rRect here | |||
738 | if (!comphelper::LibreOfficeKit::isActive() || !rRect.IsEmpty()) | |||
739 | aBlankRect.Intersection(rRect); | |||
740 | ||||
741 | rOutlView.GetOutliner()->SetUpdateMode(true); // Bugfix #22596# | |||
742 | rOutlView.Paint(aBlankRect, &rTargetDevice); | |||
743 | ||||
744 | if (!bModified) | |||
745 | { | |||
746 | pTextEditOutliner->ClearModifyFlag(); | |||
747 | } | |||
748 | ||||
749 | if (bTextFrame && !bFitToSize) | |||
750 | { | |||
751 | // completely reworked to use primitives; this ensures same look and functionality | |||
752 | const drawinglayer::geometry::ViewInformation2D aViewInformation2D; | |||
753 | std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> xProcessor( | |||
754 | drawinglayer::processor2d::createProcessor2DFromOutputDevice(rTargetDevice, | |||
755 | aViewInformation2D)); | |||
756 | ||||
757 | if (xProcessor) | |||
758 | { | |||
759 | const bool bMapModeEnabled(rTargetDevice.IsMapModeEnabled()); | |||
760 | const basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(aPixRect); | |||
761 | const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer; | |||
762 | const Color aHilightColor(aSvtOptionsDrawinglayer.getHilightColor()); | |||
763 | const double fTransparence(aSvtOptionsDrawinglayer.GetTransparentSelectionPercent() | |||
764 | * 0.01); | |||
765 | const sal_uInt16 nPixSiz(rOutlView.GetInvalidateMore() - 1); | |||
766 | const drawinglayer::primitive2d::Primitive2DReference xReference( | |||
767 | new drawinglayer::primitive2d::OverlayRectanglePrimitive( | |||
768 | aRange, aHilightColor.getBColor(), fTransparence, | |||
769 | std::max(6, nPixSiz - 2), // grow | |||
770 | 0.0, // shrink | |||
771 | 0.0)); | |||
772 | const drawinglayer::primitive2d::Primitive2DContainer aSequence{ xReference }; | |||
773 | ||||
774 | rTargetDevice.EnableMapMode(false); | |||
775 | xProcessor->process(aSequence); | |||
776 | rTargetDevice.EnableMapMode(bMapModeEnabled); | |||
777 | } | |||
778 | } | |||
779 | ||||
780 | rOutlView.ShowCursor(/*bGotoCursor=*/true, /*bActivate=*/true); | |||
781 | } | |||
782 | ||||
783 | void SdrObjEditView::ImpInvalidateOutlinerView(OutlinerView const& rOutlView) const | |||
784 | { | |||
785 | vcl::Window* pWin = rOutlView.GetWindow(); | |||
786 | ||||
787 | if (!pWin) | |||
788 | return; | |||
789 | ||||
790 | const SdrTextObj* pText = GetTextEditObject(); | |||
791 | bool bTextFrame(pText && pText->IsTextFrame()); | |||
792 | bool bFitToSize(pText && pText->IsFitToSize()); | |||
793 | ||||
794 | if (!bTextFrame || bFitToSize) | |||
795 | return; | |||
796 | ||||
797 | tools::Rectangle aBlankRect(rOutlView.GetOutputArea()); | |||
798 | aBlankRect.Union(aMinTextEditArea); | |||
799 | tools::Rectangle aPixRect(pWin->LogicToPixel(aBlankRect)); | |||
800 | sal_uInt16 nPixSiz(rOutlView.GetInvalidateMore() - 1); | |||
801 | ||||
802 | aPixRect.AdjustLeft(-1); | |||
803 | aPixRect.AdjustTop(-1); | |||
804 | aPixRect.AdjustRight(1); | |||
805 | aPixRect.AdjustBottom(1); | |||
806 | ||||
807 | { | |||
808 | // limit xPixRect because of driver problems when pixel coordinates are too far out | |||
809 | Size aMaxXY(pWin->GetOutputSizePixel()); | |||
810 | long a(2 * nPixSiz); | |||
811 | long nMaxX(aMaxXY.Width() + a); | |||
812 | long nMaxY(aMaxXY.Height() + a); | |||
813 | ||||
814 | if (aPixRect.Left() < -a) | |||
815 | aPixRect.SetLeft(-a); | |||
816 | if (aPixRect.Top() < -a) | |||
817 | aPixRect.SetTop(-a); | |||
818 | if (aPixRect.Right() > nMaxX) | |||
819 | aPixRect.SetRight(nMaxX); | |||
820 | if (aPixRect.Bottom() > nMaxY) | |||
821 | aPixRect.SetBottom(nMaxY); | |||
822 | } | |||
823 | ||||
824 | tools::Rectangle aOuterPix(aPixRect); | |||
825 | aOuterPix.AdjustLeft(-nPixSiz); | |||
826 | aOuterPix.AdjustTop(-nPixSiz); | |||
827 | aOuterPix.AdjustRight(nPixSiz); | |||
828 | aOuterPix.AdjustBottom(nPixSiz); | |||
829 | ||||
830 | bool bMapModeEnabled(pWin->IsMapModeEnabled()); | |||
831 | pWin->EnableMapMode(false); | |||
832 | pWin->Invalidate(aOuterPix); | |||
833 | pWin->EnableMapMode(bMapModeEnabled); | |||
834 | } | |||
835 | ||||
836 | OutlinerView* SdrObjEditView::ImpMakeOutlinerView(vcl::Window* pWin, OutlinerView* pGivenView, | |||
837 | SfxViewShell* pViewShell) const | |||
838 | { | |||
839 | // background | |||
840 | Color aBackground(GetTextEditBackgroundColor(*this)); | |||
841 | SdrTextObj* pText = mxTextEditObj.get(); | |||
842 | bool bTextFrame = pText != nullptr && pText->IsTextFrame(); | |||
843 | bool bContourFrame = pText != nullptr && pText->IsContourTextFrame(); | |||
844 | // create OutlinerView | |||
845 | OutlinerView* pOutlView = pGivenView; | |||
846 | pTextEditOutliner->SetUpdateMode(false); | |||
847 | ||||
848 | if (pOutlView == nullptr) | |||
849 | { | |||
850 | pOutlView = new OutlinerView(pTextEditOutliner.get(), pWin); | |||
851 | } | |||
852 | else | |||
853 | { | |||
854 | pOutlView->SetWindow(pWin); | |||
855 | } | |||
856 | ||||
857 | // disallow scrolling | |||
858 | EVControlBits nStat = pOutlView->GetControlWord(); | |||
859 | nStat &= ~EVControlBits::AUTOSCROLL; | |||
860 | // AutoViewSize only if not ContourFrame. | |||
861 | if (!bContourFrame) | |||
862 | nStat |= EVControlBits::AUTOSIZE; | |||
863 | if (bTextFrame) | |||
864 | { | |||
865 | sal_uInt16 nPixSiz = maHdlList.GetHdlSize() * 2 + 1; | |||
866 | nStat |= EVControlBits::INVONEMORE; | |||
867 | pOutlView->SetInvalidateMore(nPixSiz); | |||
868 | } | |||
869 | pOutlView->SetControlWord(nStat); | |||
870 | pOutlView->SetBackgroundColor(aBackground); | |||
871 | ||||
872 | // In case we're in the process of constructing a new view shell, | |||
873 | // SfxViewShell::Current() may still point to the old one. So if possible, | |||
874 | // depend on the application owning this draw view to provide the view | |||
875 | // shell. | |||
876 | SfxViewShell* pSfxViewShell = pViewShell ? pViewShell : GetSfxViewShell(); | |||
877 | pOutlView->RegisterViewShell(pSfxViewShell ? pSfxViewShell : SfxViewShell::Current()); | |||
878 | ||||
879 | if (pText != nullptr) | |||
880 | { | |||
881 | pOutlView->SetAnchorMode(pText->GetOutlinerViewAnchorMode()); | |||
882 | pTextEditOutliner->SetFixedCellHeight( | |||
883 | pText->GetMergedItem(SDRATTR_TEXT_USEFIXEDCELLHEIGHT).GetValue()); | |||
884 | } | |||
885 | // do update before setting output area so that aTextEditArea can be recalculated | |||
886 | pTextEditOutliner->SetUpdateMode(true); | |||
887 | pOutlView->SetOutputArea(aTextEditArea); | |||
888 | ImpInvalidateOutlinerView(*pOutlView); | |||
889 | return pOutlView; | |||
890 | } | |||
891 | ||||
892 | IMPL_LINK(SdrObjEditView, ImpOutlinerStatusEventHdl, EditStatus&, rEditStat, void)void SdrObjEditView::LinkStubImpOutlinerStatusEventHdl(void * instance, EditStatus& data) { return static_cast<SdrObjEditView *>(instance)->ImpOutlinerStatusEventHdl(data); } void SdrObjEditView ::ImpOutlinerStatusEventHdl(EditStatus& rEditStat) | |||
893 | { | |||
894 | if (pTextEditOutliner) | |||
895 | { | |||
896 | SdrTextObj* pTextObj = mxTextEditObj.get(); | |||
897 | if (pTextObj) | |||
898 | { | |||
899 | pTextObj->onEditOutlinerStatusEvent(&rEditStat); | |||
900 | } | |||
901 | } | |||
902 | } | |||
903 | ||||
904 | void SdrObjEditView::ImpChainingEventHdl() | |||
905 | { | |||
906 | if (!pTextEditOutliner) | |||
907 | return; | |||
908 | ||||
909 | SdrTextObj* pTextObj = mxTextEditObj.get(); | |||
910 | OutlinerView* pOLV = GetTextEditOutlinerView(); | |||
911 | if (pTextObj && pOLV) | |||
912 | { | |||
913 | TextChain* pTextChain = pTextObj->GetTextChain(); | |||
914 | ||||
915 | // XXX: IsChainable and GetNilChainingEvent are a bit mixed up atm | |||
916 | if (!pTextObj->IsChainable()) | |||
917 | { | |||
918 | return; | |||
919 | } | |||
920 | // This is true during an underflow-caused overflow (with pEdtOutl->SetText()) | |||
921 | if (pTextChain->GetNilChainingEvent(pTextObj)) | |||
922 | { | |||
923 | return; | |||
924 | } | |||
925 | ||||
926 | // We prevent to trigger further handling of overflow/underflow for pTextObj | |||
927 | pTextChain->SetNilChainingEvent(pTextObj, true); // XXX | |||
928 | ||||
929 | // Save previous selection pos // NOTE: It must be done to have the right CursorEvent in KeyInput | |||
930 | pTextChain->SetPreChainingSel(pTextObj, pOLV->GetSelection()); | |||
931 | //maPreChainingSel = new ESelection(pOLV->GetSelection()); | |||
932 | ||||
933 | // Handling Undo | |||
934 | const int nText = 0; // XXX: hardcoded index (SdrTextObj::getText handles only 0) | |||
935 | ||||
936 | const bool bUndoEnabled = GetModel() && IsUndoEnabled(); | |||
937 | std::unique_ptr<SdrUndoObjSetText> pTxtUndo; | |||
938 | if (bUndoEnabled) | |||
939 | pTxtUndo.reset( | |||
940 | dynamic_cast<SdrUndoObjSetText*>(GetModel() | |||
941 | ->GetSdrUndoFactory() | |||
942 | .CreateUndoObjectSetText(*pTextObj, nText) | |||
943 | .release())); | |||
944 | ||||
945 | // trigger actual chaining | |||
946 | pTextObj->onChainingEvent(); | |||
947 | ||||
948 | if (pTxtUndo) | |||
949 | { | |||
950 | pTxtUndo->AfterSetText(); | |||
951 | if (!pTxtUndo->IsDifferent()) | |||
952 | { | |||
953 | pTxtUndo.reset(); | |||
954 | } | |||
955 | } | |||
956 | ||||
957 | if (pTxtUndo) | |||
958 | AddUndo(std::move(pTxtUndo)); | |||
959 | ||||
960 | //maCursorEvent = new CursorChainingEvent(pTextChain->GetCursorEvent(pTextObj)); | |||
961 | //SdrTextObj *pNextLink = pTextObj->GetNextLinkInChain(); | |||
962 | ||||
963 | // NOTE: Must be called. Don't let the function return if you set it to true and not reset it | |||
964 | pTextChain->SetNilChainingEvent(pTextObj, false); | |||
965 | } | |||
966 | else | |||
967 | { | |||
968 | // XXX | |||
969 | SAL_INFO("svx.chaining", "[OnChaining] No Edit Outliner View")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "svx.chaining")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "[OnChaining] No Edit Outliner View" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx.chaining" ), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" ":" "969" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "[OnChaining] No Edit Outliner View"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "[OnChaining] No Edit Outliner View"; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx.chaining"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" ":" "969" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "[OnChaining] No Edit Outliner View") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx.chaining"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" ":" "969" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "[OnChaining] No Edit Outliner View"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "[OnChaining] No Edit Outliner View"; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx.chaining"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" ":" "969" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
970 | } | |||
971 | } | |||
972 | ||||
973 | IMPL_LINK_NOARG(SdrObjEditView, ImpAfterCutOrPasteChainingEventHdl, LinkParamNone*, void)void SdrObjEditView::LinkStubImpAfterCutOrPasteChainingEventHdl (void * instance, LinkParamNone* data) { return static_cast< SdrObjEditView *>(instance)->ImpAfterCutOrPasteChainingEventHdl (data); } void SdrObjEditView::ImpAfterCutOrPasteChainingEventHdl (__attribute__ ((unused)) LinkParamNone*) | |||
974 | { | |||
975 | SdrTextObj* pTextObj = GetTextEditObject(); | |||
976 | if (!pTextObj) | |||
977 | return; | |||
978 | ImpChainingEventHdl(); | |||
979 | TextChainCursorManager aCursorManager(this, pTextObj); | |||
980 | ImpMoveCursorAfterChainingEvent(&aCursorManager); | |||
981 | } | |||
982 | ||||
983 | void SdrObjEditView::ImpMoveCursorAfterChainingEvent(TextChainCursorManager* pCursorManager) | |||
984 | { | |||
985 | if (!mxTextEditObj.is() || !pCursorManager) | |||
986 | return; | |||
987 | ||||
988 | SdrTextObj* pTextObj = mxTextEditObj.get(); | |||
989 | ||||
990 | // Check if it has links to move it to | |||
991 | if (!pTextObj || !pTextObj->IsChainable()) | |||
992 | return; | |||
993 | ||||
994 | TextChain* pTextChain = pTextObj->GetTextChain(); | |||
995 | ESelection aNewSel = pTextChain->GetPostChainingSel(pTextObj); | |||
996 | ||||
997 | pCursorManager->HandleCursorEventAfterChaining(pTextChain->GetCursorEvent(pTextObj), aNewSel); | |||
998 | ||||
999 | // Reset event | |||
1000 | pTextChain->SetCursorEvent(pTextObj, CursorChainingEvent::NULL_EVENT); | |||
1001 | } | |||
1002 | ||||
1003 | IMPL_LINK(SdrObjEditView, ImpOutlinerCalcFieldValueHdl, EditFieldInfo*, pFI, void)void SdrObjEditView::LinkStubImpOutlinerCalcFieldValueHdl(void * instance, EditFieldInfo* data) { return static_cast<SdrObjEditView *>(instance)->ImpOutlinerCalcFieldValueHdl(data); } void SdrObjEditView::ImpOutlinerCalcFieldValueHdl(EditFieldInfo* pFI ) | |||
1004 | { | |||
1005 | bool bOk = false; | |||
1006 | OUString& rStr = pFI->GetRepresentation(); | |||
1007 | rStr.clear(); | |||
1008 | SdrTextObj* pTextObj = mxTextEditObj.get(); | |||
1009 | if (pTextObj != nullptr) | |||
1010 | { | |||
1011 | std::optional<Color> pTxtCol; | |||
1012 | std::optional<Color> pFldCol; | |||
1013 | bOk = pTextObj->CalcFieldValue(pFI->GetField(), pFI->GetPara(), pFI->GetPos(), true, | |||
1014 | pTxtCol, pFldCol, rStr); | |||
1015 | if (bOk) | |||
1016 | { | |||
1017 | if (pTxtCol) | |||
1018 | { | |||
1019 | pFI->SetTextColor(*pTxtCol); | |||
1020 | } | |||
1021 | if (pFldCol) | |||
1022 | { | |||
1023 | pFI->SetFieldColor(*pFldCol); | |||
1024 | } | |||
1025 | else | |||
1026 | { | |||
1027 | pFI->SetFieldColor(COL_LIGHTGRAY); // TODO: remove this later on (357) | |||
1028 | } | |||
1029 | } | |||
1030 | } | |||
1031 | Outliner& rDrawOutl = mpModel->GetDrawOutliner(pTextObj); | |||
1032 | Link<EditFieldInfo*, void> aDrawOutlLink = rDrawOutl.GetCalcFieldValueHdl(); | |||
1033 | if (!bOk && aDrawOutlLink.IsSet()) | |||
1034 | { | |||
1035 | aDrawOutlLink.Call(pFI); | |||
1036 | bOk = !rStr.isEmpty(); | |||
1037 | } | |||
1038 | if (!bOk) | |||
1039 | { | |||
1040 | aOldCalcFieldValueLink.Call(pFI); | |||
1041 | } | |||
1042 | } | |||
1043 | ||||
1044 | IMPL_LINK_NOARG(SdrObjEditView, EndTextEditHdl, SdrUndoManager*, void)void SdrObjEditView::LinkStubEndTextEditHdl(void * instance, SdrUndoManager * data) { return static_cast<SdrObjEditView *>(instance )->EndTextEditHdl(data); } void SdrObjEditView::EndTextEditHdl (__attribute__ ((unused)) SdrUndoManager*) { SdrEndTextEdit(); } | |||
1045 | ||||
1046 | SdrUndoManager* SdrObjEditView::getSdrUndoManagerForEnhancedTextEdit() const | |||
1047 | { | |||
1048 | // default returns registered UndoManager | |||
1049 | return GetModel() ? dynamic_cast<SdrUndoManager*>(GetModel()->GetSdrUndoManager()) : nullptr; | |||
1050 | } | |||
1051 | ||||
1052 | bool SdrObjEditView::SdrBeginTextEdit(SdrObject* pObj_, SdrPageView* pPV, vcl::Window* pWin, | |||
1053 | bool bIsNewObj, SdrOutliner* pGivenOutliner, | |||
1054 | OutlinerView* pGivenOutlinerView, bool bDontDeleteOutliner, | |||
1055 | bool bOnlyOneView, bool bGrabFocus) | |||
1056 | { | |||
1057 | // FIXME cannot be an assert() yet, the code is not ready for that; | |||
1058 | // eg. press F7 in Impress when you are inside a text object with spelling | |||
1059 | // mistakes => boom; and it is unclear how to avoid that | |||
1060 | SAL_WARN_IF(IsTextEdit(), "svx", "SdrBeginTextEdit called when IsTextEdit() is already true.")do { if (true && (IsTextEdit())) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "svx")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "SdrBeginTextEdit called when IsTextEdit() is already true." ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svx" ), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" ":" "1060" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "SdrBeginTextEdit called when IsTextEdit() is already true." ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "SdrBeginTextEdit called when IsTextEdit() is already true." ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svx"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" ":" "1060" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "SdrBeginTextEdit called when IsTextEdit() is already true." ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svx" ), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" ":" "1060" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "SdrBeginTextEdit called when IsTextEdit() is already true." ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "SdrBeginTextEdit called when IsTextEdit() is already true." ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svx"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" ":" "1060" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1061 | // FIXME this encourages all sorts of bad habits and should be removed | |||
1062 | SdrEndTextEdit(); | |||
1063 | ||||
1064 | SdrTextObj* pObj = dynamic_cast<SdrTextObj*>(pObj_); | |||
1065 | if (!pObj) | |||
1066 | return false; // currently only possible with text objects | |||
1067 | ||||
1068 | if (bGrabFocus && pWin) | |||
1069 | { | |||
1070 | // attention, this call may cause an EndTextEdit() call to this view | |||
1071 | pWin->GrabFocus(); // to force the cursor into the edit view | |||
1072 | } | |||
1073 | ||||
1074 | bTextEditDontDelete = bDontDeleteOutliner && pGivenOutliner != nullptr; | |||
1075 | bTextEditOnlyOneView = bOnlyOneView; | |||
1076 | bTextEditNewObj = bIsNewObj; | |||
1077 | const sal_uInt32 nWinCount(PaintWindowCount()); | |||
1078 | sal_uInt32 i; | |||
1079 | bool bBrk(false); | |||
1080 | ||||
1081 | if (!pWin) | |||
1082 | { | |||
1083 | for (i = 0; i < nWinCount && !pWin; i++) | |||
1084 | { | |||
1085 | SdrPaintWindow* pPaintWindow = GetPaintWindow(i); | |||
1086 | ||||
1087 | if (OUTDEV_WINDOW == pPaintWindow->GetOutputDevice().GetOutDevType()) | |||
1088 | { | |||
1089 | pWin = static_cast<vcl::Window*>(&pPaintWindow->GetOutputDevice()); | |||
1090 | } | |||
1091 | } | |||
1092 | ||||
1093 | // break, when no window exists | |||
1094 | if (!pWin) | |||
1095 | { | |||
1096 | bBrk = true; | |||
1097 | } | |||
1098 | } | |||
1099 | ||||
1100 | if (!bBrk && !pPV) | |||
1101 | { | |||
1102 | pPV = GetSdrPageView(); | |||
1103 | ||||
1104 | // break, when no PageView for the object exists | |||
1105 | if (!pPV) | |||
1106 | { | |||
1107 | bBrk = true; | |||
1108 | } | |||
1109 | } | |||
1110 | ||||
1111 | // no TextEdit on objects in locked Layer | |||
1112 | if (pPV && pPV->GetLockedLayers().IsSet(pObj->GetLayer())) | |||
1113 | { | |||
1114 | bBrk = true; | |||
1115 | } | |||
1116 | ||||
1117 | if (pTextEditOutliner) | |||
1118 | { | |||
1119 | OSL_FAIL("SdrObjEditView::SdrBeginTextEdit(): Old Outliner still exists.")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" ":" "1119" ": "), "%s", "SdrObjEditView::SdrBeginTextEdit(): Old Outliner still exists." ); } } while (false); | |||
1120 | pTextEditOutliner.reset(); | |||
1121 | } | |||
1122 | ||||
1123 | if (!bBrk) | |||
1124 | { | |||
1125 | pTextEditWin = pWin; | |||
1126 | pTextEditPV = pPV; | |||
1127 | mxTextEditObj.reset(pObj); | |||
1128 | if (pGivenOutliner) | |||
1129 | { | |||
1130 | pTextEditOutliner.reset(pGivenOutliner); | |||
1131 | pGivenOutliner = nullptr; // so we don't delete it on the error path | |||
1132 | } | |||
1133 | else | |||
1134 | pTextEditOutliner = SdrMakeOutliner(OutlinerMode::TextObject, | |||
1135 | mxTextEditObj->getSdrModelFromSdrObject()); | |||
1136 | ||||
1137 | { | |||
1138 | SvtAccessibilityOptions aOptions; | |||
1139 | pTextEditOutliner->ForceAutoColor(aOptions.GetIsAutomaticFontColor()); | |||
1140 | } | |||
1141 | ||||
1142 | aOldCalcFieldValueLink = pTextEditOutliner->GetCalcFieldValueHdl(); | |||
1143 | // FieldHdl has to be set by SdrBeginTextEdit, because this call an UpdateFields | |||
1144 | pTextEditOutliner->SetCalcFieldValueHdl( | |||
1145 | LINK(this, SdrObjEditView, ImpOutlinerCalcFieldValueHdl)::tools::detail::makeLink( ::tools::detail::castTo<SdrObjEditView *>(this), &SdrObjEditView::LinkStubImpOutlinerCalcFieldValueHdl )); | |||
1146 | pTextEditOutliner->SetBeginPasteOrDropHdl(LINK(this, SdrObjEditView, BeginPasteOrDropHdl)::tools::detail::makeLink( ::tools::detail::castTo<SdrObjEditView *>(this), &SdrObjEditView::LinkStubBeginPasteOrDropHdl )); | |||
1147 | pTextEditOutliner->SetEndPasteOrDropHdl(LINK(this, SdrObjEditView, EndPasteOrDropHdl)::tools::detail::makeLink( ::tools::detail::castTo<SdrObjEditView *>(this), &SdrObjEditView::LinkStubEndPasteOrDropHdl)); | |||
1148 | ||||
1149 | // It is just necessary to make the visualized page known. Set it. | |||
1150 | pTextEditOutliner->setVisualizedPage(pPV->GetPage()); | |||
1151 | ||||
1152 | pTextEditOutliner->SetTextObjNoInit(mxTextEditObj.get()); | |||
1153 | ||||
1154 | if (mxTextEditObj->BegTextEdit(*pTextEditOutliner)) | |||
1155 | { | |||
1156 | SdrTextObj* pTextObj = mxTextEditObj.get(); | |||
1157 | DBG_ASSERT(pTextObj, "svx::SdrObjEditView::BegTextEdit(), no text object?")do { if (true && (!(pTextObj))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" ":" "1157" ": "), "%s", "svx::SdrObjEditView::BegTextEdit(), no text object?" ); } } while (false); | |||
1158 | if (!pTextObj) | |||
1159 | return false; | |||
1160 | ||||
1161 | // switch off any running TextAnimations | |||
1162 | pTextObj->SetTextAnimationAllowed(false); | |||
1163 | ||||
1164 | // remember old cursor | |||
1165 | if (pTextEditOutliner->GetViewCount() != 0) | |||
1166 | { | |||
1167 | pTextEditOutliner->RemoveView(static_cast<size_t>(0)); | |||
1168 | } | |||
1169 | ||||
1170 | // Determine EditArea via TakeTextEditArea. | |||
1171 | // TODO: This could theoretically be left out, because TakeTextRect() calculates the aTextEditArea, | |||
1172 | // but aMinTextEditArea has to happen, too (therefore leaving this in right now) | |||
1173 | pTextObj->TakeTextEditArea(nullptr, nullptr, &aTextEditArea, &aMinTextEditArea); | |||
1174 | ||||
1175 | tools::Rectangle aTextRect; | |||
1176 | tools::Rectangle aAnchorRect; | |||
1177 | pTextObj->TakeTextRect(*pTextEditOutliner, aTextRect, true, | |||
1178 | &aAnchorRect /* Give true here, not false */); | |||
1179 | ||||
1180 | if (!pTextObj->IsContourTextFrame()) | |||
1181 | { | |||
1182 | // FitToSize not together with ContourFrame, for now | |||
1183 | if (pTextObj->IsFitToSize()) | |||
1184 | aTextRect = aAnchorRect; | |||
1185 | } | |||
1186 | ||||
1187 | aTextEditArea = aTextRect; | |||
1188 | ||||
1189 | // add possible GridOffset to up-to-now view-independent EditAreas | |||
1190 | basegfx::B2DVector aGridOffset(0.0, 0.0); | |||
1191 | if (getPossibleGridOffsetForSdrObject(aGridOffset, pTextObj, pPV)) | |||
1192 | { | |||
1193 | const Point aOffset(basegfx::fround(aGridOffset.getX()), | |||
1194 | basegfx::fround(aGridOffset.getY())); | |||
1195 | ||||
1196 | aTextEditArea += aOffset; | |||
1197 | aMinTextEditArea += aOffset; | |||
1198 | } | |||
1199 | ||||
1200 | Point aPvOfs(pTextObj->GetTextEditOffset()); | |||
1201 | aTextEditArea.Move(aPvOfs.X(), aPvOfs.Y()); | |||
1202 | aMinTextEditArea.Move(aPvOfs.X(), aPvOfs.Y()); | |||
1203 | pTextEditCursorBuffer = pWin->GetCursor(); | |||
1204 | ||||
1205 | maHdlList.SetMoveOutside(true); | |||
1206 | ||||
1207 | // Since IsMarkHdlWhenTextEdit() is ignored, it is necessary | |||
1208 | // to call AdjustMarkHdl() always. | |||
1209 | AdjustMarkHdl(); | |||
1210 | ||||
1211 | pTextEditOutlinerView = ImpMakeOutlinerView(pWin, pGivenOutlinerView); | |||
1212 | ||||
1213 | if (!comphelper::LibreOfficeKit::isActive() && pTextEditOutlinerView) | |||
1214 | { | |||
1215 | // activate visualization of EditView on Overlay, suppress when | |||
1216 | // LibreOfficeKit is active | |||
1217 | pTextEditOutlinerView->GetEditView().setEditViewCallbacks(this); | |||
1218 | ||||
1219 | const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer; | |||
1220 | const Color aHilightColor(aSvtOptionsDrawinglayer.getHilightColor()); | |||
1221 | const SdrTextObj* pText = GetTextEditObject(); | |||
1222 | const bool bTextFrame(pText && pText->IsTextFrame()); | |||
1223 | const bool bFitToSize(pTextEditOutliner->GetControlWord() | |||
1224 | & EEControlBits::STRETCHING); | |||
1225 | const bool bVisualizeSurroundingFrame(bTextFrame && !bFitToSize); | |||
1226 | SdrPageView* pPageView = GetSdrPageView(); | |||
1227 | ||||
1228 | if (pPageView) | |||
1229 | { | |||
1230 | for (sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++) | |||
1231 | { | |||
1232 | const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b); | |||
1233 | ||||
1234 | if (rPageWindow.GetPaintWindow().OutputToWindow()) | |||
1235 | { | |||
1236 | const rtl::Reference<sdr::overlay::OverlayManager>& xManager | |||
1237 | = rPageWindow.GetOverlayManager(); | |||
1238 | if (xManager.is()) | |||
1239 | { | |||
1240 | std::unique_ptr<TextEditOverlayObject> pNewTextEditOverlayObject( | |||
1241 | new TextEditOverlayObject(aHilightColor, *pTextEditOutlinerView, | |||
1242 | bVisualizeSurroundingFrame)); | |||
1243 | ||||
1244 | xManager->add(*pNewTextEditOverlayObject); | |||
1245 | xManager->add(const_cast<sdr::overlay::OverlaySelection&>( | |||
1246 | *pNewTextEditOverlayObject->getOverlaySelection())); | |||
1247 | ||||
1248 | maTEOverlayGroup.append(std::move(pNewTextEditOverlayObject)); | |||
1249 | } | |||
1250 | } | |||
1251 | } | |||
1252 | } | |||
1253 | } | |||
1254 | ||||
1255 | // check if this view is already inserted | |||
1256 | size_t i2, nCount = pTextEditOutliner->GetViewCount(); | |||
1257 | for (i2 = 0; i2 < nCount; i2++) | |||
1258 | { | |||
1259 | if (pTextEditOutliner->GetView(i2) == pTextEditOutlinerView) | |||
1260 | break; | |||
1261 | } | |||
1262 | ||||
1263 | if (i2 == nCount) | |||
1264 | pTextEditOutliner->InsertView(pTextEditOutlinerView, 0); | |||
1265 | ||||
1266 | maHdlList.SetMoveOutside(false); | |||
1267 | maHdlList.SetMoveOutside(true); | |||
1268 | ||||
1269 | // register all windows as OutlinerViews with the Outliner | |||
1270 | if (!bOnlyOneView) | |||
1271 | { | |||
1272 | for (i = 0; i < nWinCount; i++) | |||
1273 | { | |||
1274 | SdrPaintWindow* pPaintWindow = GetPaintWindow(i); | |||
1275 | OutputDevice& rOutDev = pPaintWindow->GetOutputDevice(); | |||
1276 | ||||
1277 | if (&rOutDev != pWin && OUTDEV_WINDOW == rOutDev.GetOutDevType()) | |||
1278 | { | |||
1279 | OutlinerView* pOutlView | |||
1280 | = ImpMakeOutlinerView(static_cast<vcl::Window*>(&rOutDev), nullptr); | |||
1281 | pTextEditOutliner->InsertView(pOutlView, static_cast<sal_uInt16>(i)); | |||
1282 | } | |||
1283 | } | |||
1284 | ||||
1285 | if (comphelper::LibreOfficeKit::isActive()) | |||
1286 | { | |||
1287 | // Register an outliner view for all other sdr views that | |||
1288 | // show the same page, so that when the text edit changes, | |||
1289 | // all interested windows get an invalidation. | |||
1290 | SdrViewIter aIter(pObj->getSdrPageFromSdrObject()); | |||
1291 | for (SdrView* pView = aIter.FirstView(); pView; pView = aIter.NextView()) | |||
1292 | { | |||
1293 | if (pView == this) | |||
1294 | continue; | |||
1295 | ||||
1296 | for (sal_uInt32 nViewPaintWindow = 0; | |||
1297 | nViewPaintWindow < pView->PaintWindowCount(); ++nViewPaintWindow) | |||
1298 | { | |||
1299 | SdrPaintWindow* pPaintWindow = pView->GetPaintWindow(nViewPaintWindow); | |||
1300 | OutputDevice& rOutDev = pPaintWindow->GetOutputDevice(); | |||
1301 | ||||
1302 | if (&rOutDev != pWin && OUTDEV_WINDOW == rOutDev.GetOutDevType()) | |||
1303 | { | |||
1304 | OutlinerView* pOutlView = ImpMakeOutlinerView( | |||
1305 | static_cast<vcl::Window*>(&rOutDev), nullptr); | |||
1306 | pOutlView->HideCursor(); | |||
1307 | static_cast<vcl::Window*>(&rOutDev)->SetCursor(nullptr); | |||
1308 | pTextEditOutliner->InsertView(pOutlView); | |||
1309 | } | |||
1310 | } | |||
1311 | } | |||
1312 | } | |||
1313 | } | |||
1314 | ||||
1315 | pTextEditOutlinerView->ShowCursor(); | |||
1316 | pTextEditOutliner->SetStatusEventHdl( | |||
1317 | LINK(this, SdrObjEditView, ImpOutlinerStatusEventHdl)::tools::detail::makeLink( ::tools::detail::castTo<SdrObjEditView *>(this), &SdrObjEditView::LinkStubImpOutlinerStatusEventHdl )); | |||
1318 | if (pTextObj->IsChainable()) | |||
1319 | { | |||
1320 | pTextEditOutlinerView->SetEndCutPasteLinkHdl( | |||
1321 | LINK(this, SdrObjEditView, ImpAfterCutOrPasteChainingEventHdl)::tools::detail::makeLink( ::tools::detail::castTo<SdrObjEditView *>(this), &SdrObjEditView::LinkStubImpAfterCutOrPasteChainingEventHdl )); | |||
1322 | } | |||
1323 | ||||
1324 | pTextEditOutliner->ClearModifyFlag(); | |||
1325 | ||||
1326 | if (pTextObj->IsFitToSize()) | |||
1327 | { | |||
1328 | pWin->Invalidate(aTextEditArea); | |||
1329 | } | |||
1330 | ||||
1331 | if (GetModel()) | |||
1332 | { | |||
1333 | SdrHint aHint(SdrHintKind::BeginEdit, *pTextObj); | |||
1334 | GetModel()->Broadcast(aHint); | |||
1335 | } | |||
1336 | ||||
1337 | pTextEditOutliner->setVisualizedPage(nullptr); | |||
1338 | ||||
1339 | if (mxSelectionController.is()) | |||
1340 | mxSelectionController->onSelectionHasChanged(); | |||
1341 | ||||
1342 | if (GetModel() && IsUndoEnabled() | |||
1343 | && !GetModel()->GetDisableTextEditUsesCommonUndoManager()) | |||
1344 | { | |||
1345 | SdrUndoManager* pSdrUndoManager = getSdrUndoManagerForEnhancedTextEdit(); | |||
1346 | ||||
1347 | if (pSdrUndoManager) | |||
1348 | { | |||
1349 | // we have an outliner, undo manager and it's an EditUndoManager, exchange | |||
1350 | // the document undo manager and the default one from the outliner and tell | |||
1351 | // it that text edit starts by setting a callback if it needs to end text edit mode. | |||
1352 | assert(nullptr == mpOldTextEditUndoManager)(static_cast <bool> (nullptr == mpOldTextEditUndoManager ) ? void (0) : __assert_fail ("nullptr == mpOldTextEditUndoManager" , "/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" , 1352, __extension__ __PRETTY_FUNCTION__)); | |||
1353 | ||||
1354 | mpOldTextEditUndoManager = pTextEditOutliner->SetUndoManager(pSdrUndoManager); | |||
1355 | pSdrUndoManager->SetEndTextEditHdl(LINK(this, SdrObjEditView, EndTextEditHdl)::tools::detail::makeLink( ::tools::detail::castTo<SdrObjEditView *>(this), &SdrObjEditView::LinkStubEndTextEditHdl)); | |||
1356 | } | |||
1357 | else | |||
1358 | { | |||
1359 | OSL_ENSURE(false,do { if (true && (!(false))) { sal_detail_logFormat(( SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" ":" "1360" ": "), "%s", "The document undo manager is not derived from SdrUndoManager (!)" ); } } while (false) | |||
1360 | "The document undo manager is not derived from SdrUndoManager (!)")do { if (true && (!(false))) { sal_detail_logFormat(( SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" ":" "1360" ": "), "%s", "The document undo manager is not derived from SdrUndoManager (!)" ); } } while (false); | |||
1361 | } | |||
1362 | } | |||
1363 | ||||
1364 | return true; // ran fine, let TextEdit run now | |||
1365 | } | |||
1366 | else | |||
1367 | { | |||
1368 | pTextEditOutliner->SetCalcFieldValueHdl(aOldCalcFieldValueLink); | |||
1369 | pTextEditOutliner->SetBeginPasteOrDropHdl(Link<PasteOrDropInfos*, void>()); | |||
1370 | pTextEditOutliner->SetEndPasteOrDropHdl(Link<PasteOrDropInfos*, void>()); | |||
1371 | } | |||
1372 | } | |||
1373 | if (pTextEditOutliner != nullptr) | |||
1374 | { | |||
1375 | pTextEditOutliner->setVisualizedPage(nullptr); | |||
1376 | } | |||
1377 | ||||
1378 | // something went wrong... | |||
1379 | if (!bDontDeleteOutliner) | |||
1380 | { | |||
1381 | delete pGivenOutliner; | |||
1382 | if (pGivenOutlinerView != nullptr) | |||
1383 | { | |||
1384 | delete pGivenOutlinerView; | |||
1385 | pGivenOutlinerView = nullptr; | |||
1386 | } | |||
1387 | } | |||
1388 | pTextEditOutliner.reset(); | |||
1389 | ||||
1390 | pTextEditOutlinerView = nullptr; | |||
1391 | mxTextEditObj.reset(nullptr); | |||
1392 | pTextEditPV = nullptr; | |||
1393 | pTextEditWin = nullptr; | |||
1394 | maHdlList.SetMoveOutside(false); | |||
1395 | ||||
1396 | return false; | |||
1397 | } | |||
1398 | ||||
1399 | SdrEndTextEditKind SdrObjEditView::SdrEndTextEdit(bool bDontDeleteReally) | |||
1400 | { | |||
1401 | SdrEndTextEditKind eRet = SdrEndTextEditKind::Unchanged; | |||
1402 | SdrTextObj* pTEObj = mxTextEditObj.get(); | |||
1403 | vcl::Window* pTEWin = pTextEditWin; | |||
1404 | OutlinerView* pTEOutlinerView = pTextEditOutlinerView; | |||
1405 | vcl::Cursor* pTECursorBuffer = pTextEditCursorBuffer; | |||
1406 | SdrUndoManager* pUndoEditUndoManager = nullptr; | |||
1407 | bool bNeedToUndoSavedRedoTextEdit(false); | |||
1408 | ||||
1409 | if (GetModel() && IsUndoEnabled() && pTEObj && pTextEditOutliner | |||
| ||||
1410 | && !GetModel()->GetDisableTextEditUsesCommonUndoManager()) | |||
1411 | { | |||
1412 | // change back the UndoManager to the remembered original one | |||
1413 | SfxUndoManager* pOriginal = pTextEditOutliner->SetUndoManager(mpOldTextEditUndoManager); | |||
1414 | mpOldTextEditUndoManager = nullptr; | |||
1415 | ||||
1416 | if (pOriginal) | |||
1417 | { | |||
1418 | // check if we got back our document undo manager | |||
1419 | SdrUndoManager* pSdrUndoManager = getSdrUndoManagerForEnhancedTextEdit(); | |||
1420 | ||||
1421 | if (pSdrUndoManager && dynamic_cast<SdrUndoManager*>(pOriginal) == pSdrUndoManager) | |||
1422 | { | |||
1423 | if (pSdrUndoManager->isEndTextEditTriggeredFromUndo()) | |||
1424 | { | |||
1425 | // remember the UndoManager where missing Undos have to be triggered after end | |||
1426 | // text edit. When the undo had triggered the end text edit, the original action | |||
1427 | // which had to be undone originally is not yet undone. | |||
1428 | pUndoEditUndoManager = pSdrUndoManager; | |||
1429 | ||||
1430 | // We are ending text edit; if text edit was triggered from undo, execute all redos | |||
1431 | // to create a complete text change undo action for the redo buffer. Also mark this | |||
1432 | // state when at least one redo was executed; the created extra TextChange needs to | |||
1433 | // be undone in addition to the first real undo outside the text edit changes | |||
1434 | while (pSdrUndoManager->GetRedoActionCount()) | |||
1435 | { | |||
1436 | bNeedToUndoSavedRedoTextEdit = true; | |||
1437 | pSdrUndoManager->Redo(); | |||
1438 | } | |||
1439 | } | |||
1440 | ||||
1441 | // reset the callback link and let the undo manager cleanup all text edit | |||
1442 | // undo actions to get the stack back to the form before the text edit | |||
1443 | pSdrUndoManager->SetEndTextEditHdl(Link<SdrUndoManager*, void>()); | |||
1444 | } | |||
1445 | else | |||
1446 | { | |||
1447 | OSL_ENSURE(false, "Got UndoManager back in SdrEndTextEdit which is NOT the "do { if (true && (!(false))) { sal_detail_logFormat(( SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" ":" "1448" ": "), "%s", "Got UndoManager back in SdrEndTextEdit which is NOT the " "expected document UndoManager (!)"); } } while (false) | |||
1448 | "expected document UndoManager (!)")do { if (true && (!(false))) { sal_detail_logFormat(( SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" ":" "1448" ": "), "%s", "Got UndoManager back in SdrEndTextEdit which is NOT the " "expected document UndoManager (!)"); } } while (false); | |||
1449 | delete pOriginal; | |||
1450 | } | |||
1451 | } | |||
1452 | } | |||
1453 | else | |||
1454 | { | |||
1455 | assert(nullptr == mpOldTextEditUndoManager)(static_cast <bool> (nullptr == mpOldTextEditUndoManager ) ? void (0) : __assert_fail ("nullptr == mpOldTextEditUndoManager" , "/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" , 1455, __extension__ __PRETTY_FUNCTION__)); // cannot be restored! | |||
1456 | } | |||
1457 | ||||
1458 | if (GetModel() && mxTextEditObj.is()) | |||
1459 | { | |||
1460 | SdrHint aHint(SdrHintKind::EndEdit, *mxTextEditObj); | |||
1461 | GetModel()->Broadcast(aHint); | |||
1462 | } | |||
1463 | ||||
1464 | // if new mechanism was used, clean it up. At cleanup no need to check | |||
1465 | // for LibreOfficeKit | |||
1466 | if (pTextEditOutlinerView) | |||
1467 | { | |||
1468 | pTextEditOutlinerView->GetEditView().setEditViewCallbacks(nullptr); | |||
1469 | maTEOverlayGroup.clear(); | |||
1470 | } | |||
1471 | ||||
1472 | mxTextEditObj.reset(nullptr); | |||
1473 | pTextEditPV = nullptr; | |||
1474 | pTextEditWin = nullptr; | |||
1475 | SdrOutliner* pTEOutliner = pTextEditOutliner.release(); | |||
1476 | pTextEditOutlinerView = nullptr; | |||
1477 | pTextEditCursorBuffer = nullptr; | |||
1478 | aTextEditArea = tools::Rectangle(); | |||
1479 | ||||
1480 | if (pTEOutliner != nullptr) | |||
1481 | { | |||
1482 | bool bModified = pTEOutliner->IsModified(); | |||
1483 | if (pTEOutlinerView != nullptr) | |||
1484 | { | |||
1485 | pTEOutlinerView->HideCursor(); | |||
1486 | } | |||
1487 | if (pTEObj != nullptr) | |||
1488 | { | |||
1489 | pTEOutliner->CompleteOnlineSpelling(); | |||
1490 | ||||
1491 | std::unique_ptr<SdrUndoObjSetText> pTxtUndo; | |||
1492 | ||||
1493 | if (bModified) | |||
1494 | { | |||
1495 | sal_Int32 nText; | |||
1496 | for (nText = 0; nText < pTEObj->getTextCount(); ++nText) | |||
1497 | if (pTEObj->getText(nText) == pTEObj->getActiveText()) | |||
1498 | break; | |||
1499 | ||||
1500 | pTxtUndo.reset( | |||
1501 | dynamic_cast<SdrUndoObjSetText*>(GetModel() | |||
1502 | ->GetSdrUndoFactory() | |||
1503 | .CreateUndoObjectSetText(*pTEObj, nText) | |||
1504 | .release())); | |||
1505 | } | |||
1506 | DBG_ASSERT(!bModified || pTxtUndo,do { if (true && (!(!bModified || pTxtUndo))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" ":" "1507" ": "), "%s", "svx::SdrObjEditView::EndTextEdit(), could not create undo action!" ); } } while (false) | |||
1507 | "svx::SdrObjEditView::EndTextEdit(), could not create undo action!")do { if (true && (!(!bModified || pTxtUndo))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" ":" "1507" ": "), "%s", "svx::SdrObjEditView::EndTextEdit(), could not create undo action!" ); } } while (false); | |||
1508 | // Set old CalcFieldValue-Handler again, this | |||
1509 | // has to happen before Obj::EndTextEdit(), as this does UpdateFields(). | |||
1510 | pTEOutliner->SetCalcFieldValueHdl(aOldCalcFieldValueLink); | |||
1511 | pTEOutliner->SetBeginPasteOrDropHdl(Link<PasteOrDropInfos*, void>()); | |||
1512 | pTEOutliner->SetEndPasteOrDropHdl(Link<PasteOrDropInfos*, void>()); | |||
1513 | ||||
1514 | const bool bUndo = IsUndoEnabled(); | |||
1515 | if (bUndo) | |||
1516 | { | |||
1517 | EndTextEditAllViews(); | |||
1518 | OUString aObjName(pTEObj->TakeObjNameSingul()); | |||
1519 | BegUndo(SvxResId(STR_UndoObjSetTextreinterpret_cast<char const *>("STR_UndoObjSetText" "\004" u8"Edit text of %1")), aObjName); | |||
1520 | } | |||
1521 | ||||
1522 | pTEObj->EndTextEdit(*pTEOutliner); | |||
1523 | ||||
1524 | if ((pTEObj->GetRotateAngle() != 0) | |||
1525 | || (dynamic_cast<const SdrTextObj*>(pTEObj) != nullptr && pTEObj->IsFontwork())) | |||
1526 | { | |||
1527 | pTEObj->ActionChanged(); | |||
1528 | } | |||
1529 | ||||
1530 | if (pTxtUndo != nullptr) | |||
1531 | { | |||
1532 | pTxtUndo->AfterSetText(); | |||
1533 | if (!pTxtUndo->IsDifferent()) | |||
1534 | { | |||
1535 | pTxtUndo.reset(); | |||
1536 | } | |||
1537 | } | |||
1538 | // check deletion of entire TextObj | |||
1539 | std::unique_ptr<SdrUndoAction> pDelUndo; | |||
1540 | bool bDelObj = false; | |||
1541 | if (bTextEditNewObj) | |||
1542 | { | |||
1543 | bDelObj = pTEObj->IsTextFrame() && !pTEObj->HasText() && !pTEObj->IsEmptyPresObj() | |||
1544 | && !pTEObj->HasFill() && !pTEObj->HasLine(); | |||
1545 | ||||
1546 | if (pTEObj->IsInserted() && bDelObj | |||
1547 | && pTEObj->GetObjInventor() == SdrInventor::Default && !bDontDeleteReally) | |||
1548 | { | |||
1549 | SdrObjKind eIdent = static_cast<SdrObjKind>(pTEObj->GetObjIdentifier()); | |||
1550 | if (eIdent == OBJ_TEXT) | |||
1551 | { | |||
1552 | pDelUndo = GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pTEObj); | |||
1553 | } | |||
1554 | } | |||
1555 | } | |||
1556 | if (pTxtUndo) | |||
1557 | { | |||
1558 | if (bUndo) | |||
1559 | AddUndo(std::move(pTxtUndo)); | |||
1560 | eRet = SdrEndTextEditKind::Changed; | |||
1561 | } | |||
1562 | if (pDelUndo != nullptr) | |||
1563 | { | |||
1564 | if (bUndo) | |||
1565 | { | |||
1566 | AddUndo(std::move(pDelUndo)); | |||
1567 | } | |||
1568 | eRet = SdrEndTextEditKind::Deleted; | |||
1569 | DBG_ASSERT(pTEObj->getParentSdrObjListFromSdrObject() != nullptr,do { if (true && (!(pTEObj->getParentSdrObjListFromSdrObject () != nullptr))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" ":" "1571" ": "), "%s", "SdrObjEditView::SdrEndTextEdit(): Fatal: Object edited doesn't have an " "ObjList!"); } } while (false) | |||
1570 | "SdrObjEditView::SdrEndTextEdit(): Fatal: Object edited doesn't have an "do { if (true && (!(pTEObj->getParentSdrObjListFromSdrObject () != nullptr))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" ":" "1571" ": "), "%s", "SdrObjEditView::SdrEndTextEdit(): Fatal: Object edited doesn't have an " "ObjList!"); } } while (false) | |||
1571 | "ObjList!")do { if (true && (!(pTEObj->getParentSdrObjListFromSdrObject () != nullptr))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" ":" "1571" ": "), "%s", "SdrObjEditView::SdrEndTextEdit(): Fatal: Object edited doesn't have an " "ObjList!"); } } while (false); | |||
1572 | if (pTEObj->getParentSdrObjListFromSdrObject() != nullptr) | |||
1573 | { | |||
1574 | pTEObj->getParentSdrObjListFromSdrObject()->RemoveObject(pTEObj->GetOrdNum()); | |||
1575 | CheckMarked(); // remove selection immediately... | |||
1576 | } | |||
1577 | } | |||
1578 | else if (bDelObj) | |||
1579 | { // for Writer: the app has to do the deletion itself. | |||
1580 | eRet = SdrEndTextEditKind::ShouldBeDeleted; | |||
1581 | } | |||
1582 | ||||
1583 | if (bUndo) | |||
1584 | EndUndo(); // EndUndo after Remove, in case UndoStack is deleted immediately | |||
1585 | ||||
1586 | // Switch on any TextAnimation again after TextEdit | |||
1587 | if (dynamic_cast<const SdrTextObj*>(pTEObj) != nullptr) | |||
1588 | { | |||
1589 | pTEObj->SetTextAnimationAllowed(true); | |||
1590 | } | |||
1591 | ||||
1592 | // Since IsMarkHdlWhenTextEdit() is ignored, it is necessary | |||
1593 | // to call AdjustMarkHdl() always. | |||
1594 | AdjustMarkHdl(); | |||
1595 | } | |||
1596 | // delete all OutlinerViews | |||
1597 | for (size_t i = pTEOutliner->GetViewCount(); i > 0;) | |||
1598 | { | |||
1599 | i--; | |||
1600 | OutlinerView* pOLV = pTEOutliner->GetView(i); | |||
1601 | sal_uInt16 nMorePix = pOLV->GetInvalidateMore() + 10; | |||
1602 | vcl::Window* pWin = pOLV->GetWindow(); | |||
1603 | tools::Rectangle aRect(pOLV->GetOutputArea()); | |||
1604 | pTEOutliner->RemoveView(i); | |||
1605 | if (!bTextEditDontDelete || i != 0) | |||
1606 | { | |||
1607 | // may not own the zeroth one | |||
1608 | delete pOLV; | |||
1609 | } | |||
1610 | aRect.Union(aTextEditArea); | |||
1611 | aRect.Union(aMinTextEditArea); | |||
1612 | aRect = pWin->LogicToPixel(aRect); | |||
1613 | aRect.AdjustLeft(-nMorePix); | |||
1614 | aRect.AdjustTop(-nMorePix); | |||
1615 | aRect.AdjustRight(nMorePix); | |||
1616 | aRect.AdjustBottom(nMorePix); | |||
1617 | aRect = pWin->PixelToLogic(aRect); | |||
1618 | InvalidateOneWin(*pWin, aRect); | |||
1619 | pWin->SetFillColor(); | |||
1620 | pWin->SetLineColor(COL_BLACK); | |||
1621 | } | |||
1622 | // and now the Outliner itself | |||
1623 | if (!bTextEditDontDelete) | |||
1624 | delete pTEOutliner; | |||
1625 | else | |||
1626 | pTEOutliner->Clear(); | |||
1627 | if (pTEWin != nullptr) | |||
1628 | { | |||
1629 | pTEWin->SetCursor(pTECursorBuffer); | |||
1630 | } | |||
1631 | maHdlList.SetMoveOutside(false); | |||
1632 | if (eRet != SdrEndTextEditKind::Unchanged) | |||
1633 | { | |||
1634 | GetMarkedObjectListWriteAccess().SetNameDirty(); | |||
1635 | } | |||
1636 | } | |||
1637 | ||||
1638 | if (pTEObj && !pTEObj->getSdrModelFromSdrObject().isLocked() && pTEObj->GetBroadcaster()) | |||
1639 | { | |||
1640 | SdrHint aHint(SdrHintKind::EndEdit, *pTEObj); | |||
1641 | const_cast<SfxBroadcaster*>(pTEObj->GetBroadcaster())->Broadcast(aHint); | |||
1642 | } | |||
1643 | ||||
1644 | if (pUndoEditUndoManager) | |||
1645 | { | |||
1646 | if (bNeedToUndoSavedRedoTextEdit) | |||
1647 | { | |||
1648 | // undo the text edit action since it was created as part of an EndTextEdit | |||
1649 | // callback from undo itself. This needs to be done after the call to | |||
1650 | // FmFormView::SdrEndTextEdit since it gets created there | |||
1651 | pUndoEditUndoManager->Undo(); | |||
1652 | } | |||
1653 | ||||
1654 | // trigger the Undo which was not executed, but lead to this | |||
1655 | // end text edit | |||
1656 | pUndoEditUndoManager->Undo(); | |||
1657 | } | |||
1658 | ||||
1659 | return eRet; | |||
1660 | } | |||
1661 | ||||
1662 | // info about TextEdit. Default is false. | |||
1663 | bool SdrObjEditView::IsTextEdit() const { return mxTextEditObj.is(); } | |||
1664 | ||||
1665 | // info about TextEditPageView. Default is 0L. | |||
1666 | SdrPageView* SdrObjEditView::GetTextEditPageView() const { return pTextEditPV; } | |||
1667 | ||||
1668 | OutlinerView* SdrObjEditView::ImpFindOutlinerView(vcl::Window const* pWin) const | |||
1669 | { | |||
1670 | if (pWin == nullptr) | |||
1671 | return nullptr; | |||
1672 | if (pTextEditOutliner == nullptr) | |||
1673 | return nullptr; | |||
1674 | OutlinerView* pNewView = nullptr; | |||
1675 | size_t nWinCount = pTextEditOutliner->GetViewCount(); | |||
1676 | for (size_t i = 0; i < nWinCount && pNewView == nullptr; i++) | |||
1677 | { | |||
1678 | OutlinerView* pView = pTextEditOutliner->GetView(i); | |||
1679 | if (pView->GetWindow() == pWin) | |||
1680 | pNewView = pView; | |||
1681 | } | |||
1682 | return pNewView; | |||
1683 | } | |||
1684 | ||||
1685 | void SdrObjEditView::SetTextEditWin(vcl::Window* pWin) | |||
1686 | { | |||
1687 | if (!(mxTextEditObj.is() && pWin != nullptr && pWin != pTextEditWin)) | |||
1688 | return; | |||
1689 | ||||
1690 | OutlinerView* pNewView = ImpFindOutlinerView(pWin); | |||
1691 | if (pNewView != nullptr && pNewView != pTextEditOutlinerView) | |||
1692 | { | |||
1693 | if (pTextEditOutlinerView != nullptr) | |||
1694 | { | |||
1695 | pTextEditOutlinerView->HideCursor(); | |||
1696 | } | |||
1697 | pTextEditOutlinerView = pNewView; | |||
1698 | pTextEditWin = pWin; | |||
1699 | pWin->GrabFocus(); // Make the cursor blink here as well | |||
1700 | pNewView->ShowCursor(); | |||
1701 | ImpMakeTextCursorAreaVisible(); | |||
1702 | } | |||
1703 | } | |||
1704 | ||||
1705 | bool SdrObjEditView::IsTextEditHit(const Point& rHit) const | |||
1706 | { | |||
1707 | bool bOk = false; | |||
1708 | if (mxTextEditObj.is()) | |||
1709 | { | |||
1710 | tools::Rectangle aEditArea; | |||
1711 | OutlinerView* pOLV = pTextEditOutliner->GetView(0); | |||
1712 | if (pOLV != nullptr) | |||
1713 | { | |||
1714 | aEditArea.Union(pOLV->GetOutputArea()); | |||
1715 | } | |||
1716 | bOk = aEditArea.IsInside(rHit); | |||
1717 | if (bOk) | |||
1718 | { // check if any characters were actually hit | |||
1719 | Point aPnt(rHit); | |||
1720 | aPnt -= aEditArea.TopLeft(); | |||
1721 | long nHitTol = 2000; | |||
1722 | OutputDevice* pRef = pTextEditOutliner->GetRefDevice(); | |||
1723 | if (pRef) | |||
1724 | nHitTol = OutputDevice::LogicToLogic(nHitTol, MapUnit::Map100thMM, | |||
1725 | pRef->GetMapMode().GetMapUnit()); | |||
1726 | ||||
1727 | bOk = pTextEditOutliner->IsTextPos(aPnt, static_cast<sal_uInt16>(nHitTol)); | |||
1728 | } | |||
1729 | } | |||
1730 | return bOk; | |||
1731 | } | |||
1732 | ||||
1733 | bool SdrObjEditView::IsTextEditFrameHit(const Point& rHit) const | |||
1734 | { | |||
1735 | bool bOk = false; | |||
1736 | if (mxTextEditObj.is()) | |||
1737 | { | |||
1738 | SdrTextObj* pText = mxTextEditObj.get(); | |||
1739 | OutlinerView* pOLV = pTextEditOutliner->GetView(0); | |||
1740 | if (pOLV) | |||
1741 | { | |||
1742 | vcl::Window* pWin = pOLV->GetWindow(); | |||
1743 | if (pText != nullptr && pText->IsTextFrame() && pWin != nullptr) | |||
1744 | { | |||
1745 | sal_uInt16 nPixSiz = pOLV->GetInvalidateMore(); | |||
1746 | tools::Rectangle aEditArea(aMinTextEditArea); | |||
1747 | aEditArea.Union(pOLV->GetOutputArea()); | |||
1748 | if (!aEditArea.IsInside(rHit)) | |||
1749 | { | |||
1750 | Size aSiz(pWin->PixelToLogic(Size(nPixSiz, nPixSiz))); | |||
1751 | aEditArea.AdjustLeft(-(aSiz.Width())); | |||
1752 | aEditArea.AdjustTop(-(aSiz.Height())); | |||
1753 | aEditArea.AdjustRight(aSiz.Width()); | |||
1754 | aEditArea.AdjustBottom(aSiz.Height()); | |||
1755 | bOk = aEditArea.IsInside(rHit); | |||
1756 | } | |||
1757 | } | |||
1758 | } | |||
1759 | } | |||
1760 | return bOk; | |||
1761 | } | |||
1762 | ||||
1763 | TextChainCursorManager* SdrObjEditView::ImpHandleMotionThroughBoxesKeyInput(const KeyEvent& rKEvt, | |||
1764 | bool* bOutHandled) | |||
1765 | { | |||
1766 | *bOutHandled = false; | |||
1767 | ||||
1768 | SdrTextObj* pTextObj = mxTextEditObj.get(); | |||
1769 | if (!pTextObj) | |||
1770 | return nullptr; | |||
1771 | ||||
1772 | if (!pTextObj->GetNextLinkInChain() && !pTextObj->GetPrevLinkInChain()) | |||
1773 | return nullptr; | |||
1774 | ||||
1775 | TextChainCursorManager* pCursorManager = new TextChainCursorManager(this, pTextObj); | |||
1776 | if (pCursorManager->HandleKeyEvent(rKEvt)) | |||
1777 | { | |||
1778 | // Possibly do other stuff here if necessary... | |||
1779 | // XXX: Careful with the checks below (in KeyInput) for pWin and co. You should do them here I guess. | |||
1780 | *bOutHandled = true; | |||
1781 | } | |||
1782 | ||||
1783 | return pCursorManager; | |||
1784 | } | |||
1785 | ||||
1786 | bool SdrObjEditView::KeyInput(const KeyEvent& rKEvt, vcl::Window* pWin) | |||
1787 | { | |||
1788 | if (pTextEditOutlinerView) | |||
1789 | { | |||
1790 | /* Start special handling of keys within a chain */ | |||
1791 | // We possibly move to another box before any handling | |||
1792 | bool bHandled = false; | |||
1793 | std::unique_ptr<TextChainCursorManager> xCursorManager( | |||
1794 | ImpHandleMotionThroughBoxesKeyInput(rKEvt, &bHandled)); | |||
1795 | if (bHandled) | |||
1796 | return true; | |||
1797 | /* End special handling of keys within a chain */ | |||
1798 | ||||
1799 | if (pTextEditOutlinerView->PostKeyEvent(rKEvt, pWin)) | |||
1800 | { | |||
1801 | if (mpModel) | |||
1802 | { | |||
1803 | if (pTextEditOutliner && pTextEditOutliner->IsModified()) | |||
1804 | mpModel->SetChanged(); | |||
1805 | } | |||
1806 | ||||
1807 | /* Start chaining processing */ | |||
1808 | ImpChainingEventHdl(); | |||
1809 | ImpMoveCursorAfterChainingEvent(xCursorManager.get()); | |||
1810 | /* End chaining processing */ | |||
1811 | ||||
1812 | if (pWin != nullptr && pWin != pTextEditWin) | |||
1813 | SetTextEditWin(pWin); | |||
1814 | ImpMakeTextCursorAreaVisible(); | |||
1815 | return true; | |||
1816 | } | |||
1817 | } | |||
1818 | return SdrGlueEditView::KeyInput(rKEvt, pWin); | |||
1819 | } | |||
1820 | ||||
1821 | bool SdrObjEditView::MouseButtonDown(const MouseEvent& rMEvt, OutputDevice* pWin) | |||
1822 | { | |||
1823 | if (pTextEditOutlinerView != nullptr) | |||
1824 | { | |||
1825 | bool bPostIt = pTextEditOutliner->IsInSelectionMode(); | |||
1826 | if (!bPostIt) | |||
1827 | { | |||
1828 | Point aPt(rMEvt.GetPosPixel()); | |||
1829 | if (pWin != nullptr) | |||
1830 | aPt = pWin->PixelToLogic(aPt); | |||
1831 | else if (pTextEditWin != nullptr) | |||
1832 | aPt = pTextEditWin->PixelToLogic(aPt); | |||
1833 | bPostIt = IsTextEditHit(aPt); | |||
1834 | } | |||
1835 | if (bPostIt) | |||
1836 | { | |||
1837 | Point aPixPos(rMEvt.GetPosPixel()); | |||
1838 | if (pWin) | |||
1839 | { | |||
1840 | tools::Rectangle aR(pWin->LogicToPixel(pTextEditOutlinerView->GetOutputArea())); | |||
1841 | if (aPixPos.X() < aR.Left()) | |||
1842 | aPixPos.setX(aR.Left()); | |||
1843 | if (aPixPos.X() > aR.Right()) | |||
1844 | aPixPos.setX(aR.Right()); | |||
1845 | if (aPixPos.Y() < aR.Top()) | |||
1846 | aPixPos.setY(aR.Top()); | |||
1847 | if (aPixPos.Y() > aR.Bottom()) | |||
1848 | aPixPos.setY(aR.Bottom()); | |||
1849 | } | |||
1850 | MouseEvent aMEvt(aPixPos, rMEvt.GetClicks(), rMEvt.GetMode(), rMEvt.GetButtons(), | |||
1851 | rMEvt.GetModifier()); | |||
1852 | if (pTextEditOutlinerView->MouseButtonDown(aMEvt)) | |||
1853 | { | |||
1854 | if (pWin != nullptr && pWin != pTextEditWin | |||
1855 | && pWin->GetOutDevType() == OUTDEV_WINDOW) | |||
1856 | SetTextEditWin(static_cast<vcl::Window*>(pWin)); | |||
1857 | ImpMakeTextCursorAreaVisible(); | |||
1858 | return true; | |||
1859 | } | |||
1860 | } | |||
1861 | } | |||
1862 | return SdrGlueEditView::MouseButtonDown(rMEvt, pWin); | |||
1863 | } | |||
1864 | ||||
1865 | bool SdrObjEditView::MouseButtonUp(const MouseEvent& rMEvt, OutputDevice* pWin) | |||
1866 | { | |||
1867 | if (pTextEditOutlinerView != nullptr) | |||
1868 | { | |||
1869 | bool bPostIt = pTextEditOutliner->IsInSelectionMode(); | |||
1870 | if (!bPostIt) | |||
1871 | { | |||
1872 | Point aPt(rMEvt.GetPosPixel()); | |||
1873 | if (pWin != nullptr) | |||
1874 | aPt = pWin->PixelToLogic(aPt); | |||
1875 | else if (pTextEditWin != nullptr) | |||
1876 | aPt = pTextEditWin->PixelToLogic(aPt); | |||
1877 | bPostIt = IsTextEditHit(aPt); | |||
1878 | } | |||
1879 | if (bPostIt && pWin) | |||
1880 | { | |||
1881 | Point aPixPos(rMEvt.GetPosPixel()); | |||
1882 | tools::Rectangle aR(pWin->LogicToPixel(pTextEditOutlinerView->GetOutputArea())); | |||
1883 | if (aPixPos.X() < aR.Left()) | |||
1884 | aPixPos.setX(aR.Left()); | |||
1885 | if (aPixPos.X() > aR.Right()) | |||
1886 | aPixPos.setX(aR.Right()); | |||
1887 | if (aPixPos.Y() < aR.Top()) | |||
1888 | aPixPos.setY(aR.Top()); | |||
1889 | if (aPixPos.Y() > aR.Bottom()) | |||
1890 | aPixPos.setY(aR.Bottom()); | |||
1891 | MouseEvent aMEvt(aPixPos, rMEvt.GetClicks(), rMEvt.GetMode(), rMEvt.GetButtons(), | |||
1892 | rMEvt.GetModifier()); | |||
1893 | if (pTextEditOutlinerView->MouseButtonUp(aMEvt)) | |||
1894 | { | |||
1895 | ImpMakeTextCursorAreaVisible(); | |||
1896 | return true; | |||
1897 | } | |||
1898 | } | |||
1899 | } | |||
1900 | return SdrGlueEditView::MouseButtonUp(rMEvt, pWin); | |||
1901 | } | |||
1902 | ||||
1903 | bool SdrObjEditView::MouseMove(const MouseEvent& rMEvt, OutputDevice* pWin) | |||
1904 | { | |||
1905 | if (pTextEditOutlinerView != nullptr) | |||
1906 | { | |||
1907 | bool bSelMode = pTextEditOutliner->IsInSelectionMode(); | |||
1908 | bool bPostIt = bSelMode; | |||
1909 | if (!bPostIt) | |||
1910 | { | |||
1911 | Point aPt(rMEvt.GetPosPixel()); | |||
1912 | if (pWin) | |||
1913 | aPt = pWin->PixelToLogic(aPt); | |||
1914 | else if (pTextEditWin) | |||
1915 | aPt = pTextEditWin->PixelToLogic(aPt); | |||
1916 | bPostIt = IsTextEditHit(aPt); | |||
1917 | } | |||
1918 | if (bPostIt) | |||
1919 | { | |||
1920 | Point aPixPos(rMEvt.GetPosPixel()); | |||
1921 | tools::Rectangle aR(pTextEditOutlinerView->GetOutputArea()); | |||
1922 | if (pWin) | |||
1923 | aR = pWin->LogicToPixel(aR); | |||
1924 | else if (pTextEditWin) | |||
1925 | aR = pTextEditWin->LogicToPixel(aR); | |||
1926 | if (aPixPos.X() < aR.Left()) | |||
1927 | aPixPos.setX(aR.Left()); | |||
1928 | if (aPixPos.X() > aR.Right()) | |||
1929 | aPixPos.setX(aR.Right()); | |||
1930 | if (aPixPos.Y() < aR.Top()) | |||
1931 | aPixPos.setY(aR.Top()); | |||
1932 | if (aPixPos.Y() > aR.Bottom()) | |||
1933 | aPixPos.setY(aR.Bottom()); | |||
1934 | MouseEvent aMEvt(aPixPos, rMEvt.GetClicks(), rMEvt.GetMode(), rMEvt.GetButtons(), | |||
1935 | rMEvt.GetModifier()); | |||
1936 | if (pTextEditOutlinerView->MouseMove(aMEvt) && bSelMode) | |||
1937 | { | |||
1938 | ImpMakeTextCursorAreaVisible(); | |||
1939 | return true; | |||
1940 | } | |||
1941 | } | |||
1942 | } | |||
1943 | return SdrGlueEditView::MouseMove(rMEvt, pWin); | |||
1944 | } | |||
1945 | ||||
1946 | bool SdrObjEditView::Command(const CommandEvent& rCEvt, vcl::Window* pWin) | |||
1947 | { | |||
1948 | // as long as OutlinerView returns a sal_Bool, it only gets CommandEventId::StartDrag | |||
1949 | if (pTextEditOutlinerView != nullptr) | |||
1950 | { | |||
1951 | if (rCEvt.GetCommand() == CommandEventId::StartDrag) | |||
1952 | { | |||
1953 | bool bPostIt = pTextEditOutliner->IsInSelectionMode() || !rCEvt.IsMouseEvent(); | |||
1954 | if (!bPostIt && rCEvt.IsMouseEvent()) | |||
1955 | { | |||
1956 | Point aPt(rCEvt.GetMousePosPixel()); | |||
1957 | if (pWin != nullptr) | |||
1958 | aPt = pWin->PixelToLogic(aPt); | |||
1959 | else if (pTextEditWin != nullptr) | |||
1960 | aPt = pTextEditWin->PixelToLogic(aPt); | |||
1961 | bPostIt = IsTextEditHit(aPt); | |||
1962 | } | |||
1963 | if (bPostIt) | |||
1964 | { | |||
1965 | Point aPixPos(rCEvt.GetMousePosPixel()); | |||
1966 | if (rCEvt.IsMouseEvent() && pWin) | |||
1967 | { | |||
1968 | tools::Rectangle aR(pWin->LogicToPixel(pTextEditOutlinerView->GetOutputArea())); | |||
1969 | if (aPixPos.X() < aR.Left()) | |||
1970 | aPixPos.setX(aR.Left()); | |||
1971 | if (aPixPos.X() > aR.Right()) | |||
1972 | aPixPos.setX(aR.Right()); | |||
1973 | if (aPixPos.Y() < aR.Top()) | |||
1974 | aPixPos.setY(aR.Top()); | |||
1975 | if (aPixPos.Y() > aR.Bottom()) | |||
1976 | aPixPos.setY(aR.Bottom()); | |||
1977 | } | |||
1978 | CommandEvent aCEvt(aPixPos, rCEvt.GetCommand(), rCEvt.IsMouseEvent()); | |||
1979 | // Command is void at the OutlinerView, sadly | |||
1980 | pTextEditOutlinerView->Command(aCEvt); | |||
1981 | if (pWin != nullptr && pWin != pTextEditWin) | |||
1982 | SetTextEditWin(pWin); | |||
1983 | ImpMakeTextCursorAreaVisible(); | |||
1984 | return true; | |||
1985 | } | |||
1986 | } | |||
1987 | else | |||
1988 | { | |||
1989 | pTextEditOutlinerView->Command(rCEvt); | |||
1990 | if (mpModel && comphelper::LibreOfficeKit::isActive()) | |||
1991 | { | |||
1992 | // It could execute CommandEventId::ExtTextInput, while SdrObjEditView::KeyInput | |||
1993 | // isn't called | |||
1994 | if (pTextEditOutliner && pTextEditOutliner->IsModified()) | |||
1995 | mpModel->SetChanged(); | |||
1996 | } | |||
1997 | return true; | |||
1998 | } | |||
1999 | } | |||
2000 | return SdrGlueEditView::Command(rCEvt, pWin); | |||
2001 | } | |||
2002 | ||||
2003 | bool SdrObjEditView::ImpIsTextEditAllSelected() const | |||
2004 | { | |||
2005 | bool bRet = false; | |||
2006 | if (pTextEditOutliner != nullptr && pTextEditOutlinerView != nullptr) | |||
2007 | { | |||
2008 | if (SdrTextObj::HasTextImpl(pTextEditOutliner.get())) | |||
2009 | { | |||
2010 | const sal_Int32 nParaCnt = pTextEditOutliner->GetParagraphCount(); | |||
2011 | Paragraph* pLastPara = pTextEditOutliner->GetParagraph(nParaCnt > 1 ? nParaCnt - 1 : 0); | |||
2012 | ||||
2013 | ESelection aESel(pTextEditOutlinerView->GetSelection()); | |||
2014 | if (aESel.nStartPara == 0 && aESel.nStartPos == 0 && aESel.nEndPara == (nParaCnt - 1)) | |||
2015 | { | |||
2016 | if (pTextEditOutliner->GetText(pLastPara).getLength() == aESel.nEndPos) | |||
2017 | bRet = true; | |||
2018 | } | |||
2019 | // in case the selection was done backwards | |||
2020 | if (!bRet && aESel.nEndPara == 0 && aESel.nEndPos == 0 | |||
2021 | && aESel.nStartPara == (nParaCnt - 1)) | |||
2022 | { | |||
2023 | if (pTextEditOutliner->GetText(pLastPara).getLength() == aESel.nStartPos) | |||
2024 | bRet = true; | |||
2025 | } | |||
2026 | } | |||
2027 | else | |||
2028 | { | |||
2029 | bRet = true; | |||
2030 | } | |||
2031 | } | |||
2032 | return bRet; | |||
2033 | } | |||
2034 | ||||
2035 | void SdrObjEditView::ImpMakeTextCursorAreaVisible() | |||
2036 | { | |||
2037 | if (pTextEditOutlinerView != nullptr && pTextEditWin != nullptr) | |||
2038 | { | |||
2039 | vcl::Cursor* pCsr = pTextEditWin->GetCursor(); | |||
2040 | if (pCsr != nullptr) | |||
2041 | { | |||
2042 | Size aSiz(pCsr->GetSize()); | |||
2043 | if (!aSiz.IsEmpty()) | |||
2044 | { | |||
2045 | MakeVisible(tools::Rectangle(pCsr->GetPos(), aSiz), *pTextEditWin); | |||
2046 | } | |||
2047 | } | |||
2048 | } | |||
2049 | } | |||
2050 | ||||
2051 | SvtScriptType SdrObjEditView::GetScriptType() const | |||
2052 | { | |||
2053 | SvtScriptType nScriptType = SvtScriptType::NONE; | |||
2054 | ||||
2055 | if (IsTextEdit()) | |||
2056 | { | |||
2057 | if (mxTextEditObj->GetOutlinerParaObject()) | |||
2058 | nScriptType = mxTextEditObj->GetOutlinerParaObject()->GetTextObject().GetScriptType(); | |||
2059 | ||||
2060 | if (pTextEditOutlinerView) | |||
2061 | nScriptType = pTextEditOutlinerView->GetSelectedScriptType(); | |||
2062 | } | |||
2063 | else | |||
2064 | { | |||
2065 | const size_t nMarkCount(GetMarkedObjectCount()); | |||
2066 | ||||
2067 | for (size_t i = 0; i < nMarkCount; ++i) | |||
2068 | { | |||
2069 | OutlinerParaObject* pParaObj = GetMarkedObjectByIndex(i)->GetOutlinerParaObject(); | |||
2070 | ||||
2071 | if (pParaObj) | |||
2072 | { | |||
2073 | nScriptType |= pParaObj->GetTextObject().GetScriptType(); | |||
2074 | } | |||
2075 | } | |||
2076 | } | |||
2077 | ||||
2078 | if (nScriptType == SvtScriptType::NONE) | |||
2079 | nScriptType = SvtScriptType::LATIN; | |||
2080 | ||||
2081 | return nScriptType; | |||
2082 | } | |||
2083 | ||||
2084 | void SdrObjEditView::GetAttributes(SfxItemSet& rTargetSet, bool bOnlyHardAttr) const | |||
2085 | { | |||
2086 | if (mxSelectionController.is()) | |||
2087 | if (mxSelectionController->GetAttributes(rTargetSet, bOnlyHardAttr)) | |||
2088 | return; | |||
2089 | ||||
2090 | if (IsTextEdit()) | |||
2091 | { | |||
2092 | DBG_ASSERT(pTextEditOutlinerView != nullptr,do { if (true && (!(pTextEditOutlinerView != nullptr) )) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools" ), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" ":" "2093" ": "), "%s", "SdrObjEditView::GetAttributes(): pTextEditOutlinerView=NULL" ); } } while (false) | |||
2093 | "SdrObjEditView::GetAttributes(): pTextEditOutlinerView=NULL")do { if (true && (!(pTextEditOutlinerView != nullptr) )) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools" ), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" ":" "2093" ": "), "%s", "SdrObjEditView::GetAttributes(): pTextEditOutlinerView=NULL" ); } } while (false); | |||
2094 | DBG_ASSERT(pTextEditOutliner != nullptr,do { if (true && (!(pTextEditOutliner != nullptr))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools" ), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" ":" "2095" ": "), "%s", "SdrObjEditView::GetAttributes(): pTextEditOutliner=NULL" ); } } while (false) | |||
2095 | "SdrObjEditView::GetAttributes(): pTextEditOutliner=NULL")do { if (true && (!(pTextEditOutliner != nullptr))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools" ), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" ":" "2095" ": "), "%s", "SdrObjEditView::GetAttributes(): pTextEditOutliner=NULL" ); } } while (false); | |||
2096 | ||||
2097 | // take care of bOnlyHardAttr(!) | |||
2098 | if (!bOnlyHardAttr && mxTextEditObj->GetStyleSheet()) | |||
2099 | rTargetSet.Put(mxTextEditObj->GetStyleSheet()->GetItemSet()); | |||
2100 | ||||
2101 | // add object attributes | |||
2102 | rTargetSet.Put(mxTextEditObj->GetMergedItemSet()); | |||
2103 | ||||
2104 | if (pTextEditOutlinerView) | |||
2105 | { | |||
2106 | // FALSE= regard InvalidItems as "holes," not as Default | |||
2107 | rTargetSet.Put(pTextEditOutlinerView->GetAttribs(), false); | |||
2108 | } | |||
2109 | ||||
2110 | if (GetMarkedObjectCount() == 1 && GetMarkedObjectByIndex(0) == mxTextEditObj.get()) | |||
2111 | { | |||
2112 | MergeNotPersistAttrFromMarked(rTargetSet); | |||
2113 | } | |||
2114 | } | |||
2115 | else | |||
2116 | { | |||
2117 | SdrGlueEditView::GetAttributes(rTargetSet, bOnlyHardAttr); | |||
2118 | } | |||
2119 | } | |||
2120 | ||||
2121 | bool SdrObjEditView::SetAttributes(const SfxItemSet& rSet, bool bReplaceAll) | |||
2122 | { | |||
2123 | bool bRet = false; | |||
2124 | bool bTextEdit = pTextEditOutlinerView != nullptr && mxTextEditObj.is(); | |||
2125 | bool bAllTextSelected = ImpIsTextEditAllSelected(); | |||
2126 | const SfxItemSet* pSet = &rSet; | |||
2127 | ||||
2128 | if (!bTextEdit) | |||
2129 | { | |||
2130 | // no TextEdit active -> all Items to drawing object | |||
2131 | if (mxSelectionController.is()) | |||
2132 | bRet = mxSelectionController->SetAttributes(*pSet, bReplaceAll); | |||
2133 | ||||
2134 | if (!bRet) | |||
2135 | { | |||
2136 | SdrGlueEditView::SetAttributes(*pSet, bReplaceAll); | |||
2137 | bRet = true; | |||
2138 | } | |||
2139 | } | |||
2140 | else | |||
2141 | { | |||
2142 | #ifdef DBG_UTIL | |||
2143 | { | |||
2144 | bool bHasEEFeatureItems = false; | |||
2145 | SfxItemIter aIter(rSet); | |||
2146 | for (const SfxPoolItem* pItem = aIter.GetCurItem(); !bHasEEFeatureItems && pItem; | |||
2147 | pItem = aIter.NextItem()) | |||
2148 | { | |||
2149 | if (!IsInvalidItem(pItem)) | |||
2150 | { | |||
2151 | sal_uInt16 nW = pItem->Which(); | |||
2152 | if (nW >= EE_FEATURE_START && nW <= EE_FEATURE_END) | |||
2153 | bHasEEFeatureItems = true; | |||
2154 | } | |||
2155 | } | |||
2156 | ||||
2157 | if (bHasEEFeatureItems) | |||
2158 | { | |||
2159 | std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog( | |||
2160 | nullptr, VclMessageType::Info, VclButtonsType::Ok, | |||
2161 | "SdrObjEditView::SetAttributes(): Setting EE_FEATURE items " | |||
2162 | "at the SdrView does not make sense! It only leads to " | |||
2163 | "overhead and unreadable documents.")); | |||
2164 | xInfoBox->run(); | |||
2165 | } | |||
2166 | } | |||
2167 | #endif | |||
2168 | ||||
2169 | bool bOnlyEEItems; | |||
2170 | bool bNoEEItems = !SearchOutlinerItems(*pSet, bReplaceAll, &bOnlyEEItems); | |||
2171 | // everything selected? -> attributes to the border, too | |||
2172 | // if no EEItems, attributes to the border only | |||
2173 | if (bAllTextSelected || bNoEEItems) | |||
2174 | { | |||
2175 | if (mxSelectionController.is()) | |||
2176 | bRet = mxSelectionController->SetAttributes(*pSet, bReplaceAll); | |||
2177 | ||||
2178 | if (!bRet) | |||
2179 | { | |||
2180 | const bool bUndo = IsUndoEnabled(); | |||
2181 | ||||
2182 | if (bUndo) | |||
2183 | { | |||
2184 | BegUndo(ImpGetDescriptionString(STR_EditSetAttributesreinterpret_cast<char const *>("STR_EditSetAttributes" "\004" u8"Apply attributes to %1"))); | |||
2185 | AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*mxTextEditObj)); | |||
2186 | ||||
2187 | // If this is a text object also rescue the OutlinerParaObject since | |||
2188 | // applying attributes to the object may change text layout when | |||
2189 | // multiple portions exist with multiple formats. If an OutlinerParaObject | |||
2190 | // really exists and needs to be rescued is evaluated in the undo | |||
2191 | // implementation itself. | |||
2192 | bool bRescueText = mxTextEditObj; | |||
2193 | ||||
2194 | AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoAttrObject( | |||
2195 | *mxTextEditObj, false, !bNoEEItems || bRescueText)); | |||
2196 | EndUndo(); | |||
2197 | } | |||
2198 | ||||
2199 | mxTextEditObj->SetMergedItemSetAndBroadcast(*pSet, bReplaceAll); | |||
2200 | ||||
2201 | FlushComeBackTimer(); // to set ModeHasChanged immediately | |||
2202 | } | |||
2203 | } | |||
2204 | else if (!bOnlyEEItems) | |||
2205 | { | |||
2206 | // Otherwise split Set, if necessary. | |||
2207 | // Now we build an ItemSet aSet that doesn't contain EE_Items from | |||
2208 | // *pSet (otherwise it would be a copy). | |||
2209 | std::unique_ptr<sal_uInt16[]> pNewWhichTable | |||
2210 | = RemoveWhichRange(pSet->GetRanges(), EE_ITEMS_START, EE_ITEMS_END); | |||
2211 | SfxItemSet aSet(mpModel->GetItemPool(), pNewWhichTable.get()); | |||
2212 | pNewWhichTable.reset(); | |||
2213 | SfxWhichIter aIter(aSet); | |||
2214 | sal_uInt16 nWhich = aIter.FirstWhich(); | |||
2215 | while (nWhich != 0) | |||
2216 | { | |||
2217 | const SfxPoolItem* pItem; | |||
2218 | SfxItemState eState = pSet->GetItemState(nWhich, false, &pItem); | |||
2219 | if (eState == SfxItemState::SET) | |||
2220 | aSet.Put(*pItem); | |||
2221 | nWhich = aIter.NextWhich(); | |||
2222 | } | |||
2223 | ||||
2224 | if (mxSelectionController.is()) | |||
2225 | bRet = mxSelectionController->SetAttributes(aSet, bReplaceAll); | |||
2226 | ||||
2227 | if (!bRet) | |||
2228 | { | |||
2229 | if (IsUndoEnabled()) | |||
2230 | { | |||
2231 | BegUndo(ImpGetDescriptionString(STR_EditSetAttributesreinterpret_cast<char const *>("STR_EditSetAttributes" "\004" u8"Apply attributes to %1"))); | |||
2232 | AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*mxTextEditObj)); | |||
2233 | AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*mxTextEditObj)); | |||
2234 | EndUndo(); | |||
2235 | } | |||
2236 | ||||
2237 | mxTextEditObj->SetMergedItemSetAndBroadcast(aSet, bReplaceAll); | |||
2238 | ||||
2239 | if (GetMarkedObjectCount() == 1 && GetMarkedObjectByIndex(0) == mxTextEditObj.get()) | |||
2240 | { | |||
2241 | SetNotPersistAttrToMarked(aSet); | |||
2242 | } | |||
2243 | } | |||
2244 | FlushComeBackTimer(); | |||
2245 | } | |||
2246 | if (!bNoEEItems) | |||
2247 | { | |||
2248 | // and now the attributes to the EditEngine | |||
2249 | if (bReplaceAll) | |||
2250 | { | |||
2251 | pTextEditOutlinerView->RemoveAttribs(true); | |||
2252 | } | |||
2253 | pTextEditOutlinerView->SetAttribs(rSet); | |||
2254 | ||||
2255 | Outliner* pTEOutliner = pTextEditOutlinerView->GetOutliner(); | |||
2256 | if (mpModel && pTEOutliner && pTEOutliner->IsModified()) | |||
2257 | mpModel->SetChanged(); | |||
2258 | ||||
2259 | ImpMakeTextCursorAreaVisible(); | |||
2260 | } | |||
2261 | bRet = true; | |||
2262 | } | |||
2263 | return bRet; | |||
2264 | } | |||
2265 | ||||
2266 | SfxStyleSheet* SdrObjEditView::GetStyleSheet() const | |||
2267 | { | |||
2268 | SfxStyleSheet* pSheet = nullptr; | |||
2269 | ||||
2270 | if (mxSelectionController.is()) | |||
2271 | { | |||
2272 | if (mxSelectionController->GetStyleSheet(pSheet)) | |||
2273 | return pSheet; | |||
2274 | } | |||
2275 | ||||
2276 | if (pTextEditOutlinerView) | |||
2277 | { | |||
2278 | pSheet = pTextEditOutlinerView->GetStyleSheet(); | |||
2279 | } | |||
2280 | else | |||
2281 | { | |||
2282 | pSheet = SdrGlueEditView::GetStyleSheet(); | |||
2283 | } | |||
2284 | return pSheet; | |||
2285 | } | |||
2286 | ||||
2287 | void SdrObjEditView::SetStyleSheet(SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr) | |||
2288 | { | |||
2289 | if (mxSelectionController.is()) | |||
2290 | { | |||
2291 | if (mxSelectionController->SetStyleSheet(pStyleSheet, bDontRemoveHardAttr)) | |||
2292 | return; | |||
2293 | } | |||
2294 | ||||
2295 | // if we are currently in edit mode we must also set the stylesheet | |||
2296 | // on all paragraphs in the Outliner for the edit view | |||
2297 | if (nullptr != pTextEditOutlinerView) | |||
2298 | { | |||
2299 | Outliner* pOutliner = pTextEditOutlinerView->GetOutliner(); | |||
2300 | ||||
2301 | const sal_Int32 nParaCount = pOutliner->GetParagraphCount(); | |||
2302 | for (sal_Int32 nPara = 0; nPara < nParaCount; nPara++) | |||
2303 | { | |||
2304 | pOutliner->SetStyleSheet(nPara, pStyleSheet); | |||
2305 | } | |||
2306 | } | |||
2307 | ||||
2308 | SdrGlueEditView::SetStyleSheet(pStyleSheet, bDontRemoveHardAttr); | |||
2309 | } | |||
2310 | ||||
2311 | void SdrObjEditView::AddWindowToPaintView(OutputDevice* pNewWin, vcl::Window* pWindow) | |||
2312 | { | |||
2313 | SdrGlueEditView::AddWindowToPaintView(pNewWin, pWindow); | |||
2314 | ||||
2315 | if (mxTextEditObj.is() && !bTextEditOnlyOneView && pNewWin->GetOutDevType() == OUTDEV_WINDOW) | |||
2316 | { | |||
2317 | OutlinerView* pOutlView = ImpMakeOutlinerView(static_cast<vcl::Window*>(pNewWin), nullptr); | |||
2318 | pTextEditOutliner->InsertView(pOutlView); | |||
2319 | } | |||
2320 | } | |||
2321 | ||||
2322 | void SdrObjEditView::DeleteWindowFromPaintView(OutputDevice* pOldWin) | |||
2323 | { | |||
2324 | SdrGlueEditView::DeleteWindowFromPaintView(pOldWin); | |||
2325 | ||||
2326 | if (mxTextEditObj.is() && !bTextEditOnlyOneView && pOldWin->GetOutDevType() == OUTDEV_WINDOW) | |||
2327 | { | |||
2328 | for (size_t i = pTextEditOutliner->GetViewCount(); i > 0;) | |||
2329 | { | |||
2330 | i--; | |||
2331 | OutlinerView* pOLV = pTextEditOutliner->GetView(i); | |||
2332 | if (pOLV && pOLV->GetWindow() == static_cast<vcl::Window*>(pOldWin)) | |||
2333 | { | |||
2334 | pTextEditOutliner->RemoveView(i); | |||
2335 | } | |||
2336 | } | |||
2337 | } | |||
2338 | ||||
2339 | lcl_RemoveTextEditOutlinerViews(this, GetSdrPageView(), pOldWin); | |||
2340 | } | |||
2341 | ||||
2342 | bool SdrObjEditView::IsTextEditInSelectionMode() const | |||
2343 | { | |||
2344 | return pTextEditOutliner != nullptr && pTextEditOutliner->IsInSelectionMode(); | |||
2345 | } | |||
2346 | ||||
2347 | // MacroMode | |||
2348 | ||||
2349 | void SdrObjEditView::BegMacroObj(const Point& rPnt, short nTol, SdrObject* pObj, SdrPageView* pPV, | |||
2350 | vcl::Window* pWin) | |||
2351 | { | |||
2352 | BrkMacroObj(); | |||
2353 | if (pObj != nullptr && pPV != nullptr && pWin != nullptr && pObj->HasMacro()) | |||
2354 | { | |||
2355 | nTol = ImpGetHitTolLogic(nTol, nullptr); | |||
2356 | pMacroObj = pObj; | |||
2357 | pMacroPV = pPV; | |||
2358 | pMacroWin = pWin; | |||
2359 | bMacroDown = false; | |||
2360 | nMacroTol = sal_uInt16(nTol); | |||
2361 | aMacroDownPos = rPnt; | |||
2362 | MovMacroObj(rPnt); | |||
2363 | } | |||
2364 | } | |||
2365 | ||||
2366 | void SdrObjEditView::ImpMacroUp(const Point& rUpPos) | |||
2367 | { | |||
2368 | if (pMacroObj != nullptr && bMacroDown) | |||
2369 | { | |||
2370 | SdrObjMacroHitRec aHitRec; | |||
2371 | aHitRec.aPos = rUpPos; | |||
2372 | aHitRec.nTol = nMacroTol; | |||
2373 | aHitRec.pVisiLayer = &pMacroPV->GetVisibleLayers(); | |||
2374 | aHitRec.pPageView = pMacroPV; | |||
2375 | pMacroObj->PaintMacro(*pMacroWin, tools::Rectangle(), aHitRec); | |||
2376 | bMacroDown = false; | |||
2377 | } | |||
2378 | } | |||
2379 | ||||
2380 | void SdrObjEditView::ImpMacroDown(const Point& rDownPos) | |||
2381 | { | |||
2382 | if (pMacroObj != nullptr && !bMacroDown) | |||
2383 | { | |||
2384 | SdrObjMacroHitRec aHitRec; | |||
2385 | aHitRec.aPos = rDownPos; | |||
2386 | aHitRec.nTol = nMacroTol; | |||
2387 | aHitRec.pVisiLayer = &pMacroPV->GetVisibleLayers(); | |||
2388 | aHitRec.pPageView = pMacroPV; | |||
2389 | pMacroObj->PaintMacro(*pMacroWin, tools::Rectangle(), aHitRec); | |||
2390 | bMacroDown = true; | |||
2391 | } | |||
2392 | } | |||
2393 | ||||
2394 | void SdrObjEditView::MovMacroObj(const Point& rPnt) | |||
2395 | { | |||
2396 | if (pMacroObj == nullptr) | |||
2397 | return; | |||
2398 | ||||
2399 | SdrObjMacroHitRec aHitRec; | |||
2400 | aHitRec.aPos = rPnt; | |||
2401 | aHitRec.nTol = nMacroTol; | |||
2402 | aHitRec.pVisiLayer = &pMacroPV->GetVisibleLayers(); | |||
2403 | aHitRec.pPageView = pMacroPV; | |||
2404 | bool bDown = pMacroObj->IsMacroHit(aHitRec); | |||
2405 | if (bDown) | |||
2406 | ImpMacroDown(rPnt); | |||
2407 | else | |||
2408 | ImpMacroUp(rPnt); | |||
2409 | } | |||
2410 | ||||
2411 | void SdrObjEditView::BrkMacroObj() | |||
2412 | { | |||
2413 | if (pMacroObj != nullptr) | |||
2414 | { | |||
2415 | ImpMacroUp(aMacroDownPos); | |||
2416 | pMacroObj = nullptr; | |||
2417 | pMacroPV = nullptr; | |||
2418 | pMacroWin = nullptr; | |||
2419 | } | |||
2420 | } | |||
2421 | ||||
2422 | bool SdrObjEditView::EndMacroObj() | |||
2423 | { | |||
2424 | if (pMacroObj != nullptr && bMacroDown) | |||
2425 | { | |||
2426 | ImpMacroUp(aMacroDownPos); | |||
2427 | SdrObjMacroHitRec aHitRec; | |||
2428 | aHitRec.aPos = aMacroDownPos; | |||
2429 | aHitRec.nTol = nMacroTol; | |||
2430 | aHitRec.pVisiLayer = &pMacroPV->GetVisibleLayers(); | |||
2431 | aHitRec.pPageView = pMacroPV; | |||
2432 | bool bRet = pMacroObj->DoMacro(aHitRec); | |||
2433 | pMacroObj = nullptr; | |||
2434 | pMacroPV = nullptr; | |||
2435 | pMacroWin = nullptr; | |||
2436 | return bRet; | |||
2437 | } | |||
2438 | else | |||
2439 | { | |||
2440 | BrkMacroObj(); | |||
2441 | return false; | |||
2442 | } | |||
2443 | } | |||
2444 | ||||
2445 | /** fills the given any with a XTextCursor for the current text selection. | |||
2446 | Leaves the any untouched if there currently is no text selected */ | |||
2447 | void SdrObjEditView::getTextSelection(css::uno::Any& rSelection) | |||
2448 | { | |||
2449 | if (!IsTextEdit()) | |||
2450 | return; | |||
2451 | ||||
2452 | OutlinerView* pOutlinerView = GetTextEditOutlinerView(); | |||
2453 | if (!(pOutlinerView && pOutlinerView->HasSelection())) | |||
2454 | return; | |||
2455 | ||||
2456 | SdrObject* pObj = GetTextEditObject(); | |||
2457 | ||||
2458 | if (!pObj) | |||
2459 | return; | |||
2460 | ||||
2461 | css::uno::Reference<css::text::XText> xText(pObj->getUnoShape(), css::uno::UNO_QUERY); | |||
2462 | if (xText.is()) | |||
2463 | { | |||
2464 | SvxUnoTextBase* pRange = comphelper::getUnoTunnelImplementation<SvxUnoTextBase>(xText); | |||
2465 | if (pRange) | |||
2466 | { | |||
2467 | rSelection <<= pRange->createTextCursorBySelection(pOutlinerView->GetSelection()); | |||
2468 | } | |||
2469 | } | |||
2470 | } | |||
2471 | ||||
2472 | /* check if we have a single selection and that single object likes | |||
2473 | to handle the mouse and keyboard events itself | |||
2474 | ||||
2475 | TODO: the selection controller should be queried from the | |||
2476 | object specific view contact. Currently this method only | |||
2477 | works for tables. | |||
2478 | */ | |||
2479 | void SdrObjEditView::MarkListHasChanged() | |||
2480 | { | |||
2481 | SdrGlueEditView::MarkListHasChanged(); | |||
2482 | ||||
2483 | if (mxSelectionController.is()) | |||
2484 | { | |||
2485 | mxLastSelectionController = mxSelectionController; | |||
2486 | mxSelectionController->onSelectionHasChanged(); | |||
2487 | } | |||
2488 | ||||
2489 | mxSelectionController.clear(); | |||
2490 | ||||
2491 | const SdrMarkList& rMarkList = GetMarkedObjectList(); | |||
2492 | if (rMarkList.GetMarkCount() != 1) | |||
2493 | return; | |||
2494 | ||||
2495 | const SdrObject* pObj(rMarkList.GetMark(0)->GetMarkedSdrObj()); | |||
2496 | SdrView* pView(dynamic_cast<SdrView*>(this)); | |||
2497 | ||||
2498 | // check for table | |||
2499 | if (pObj && pView && (pObj->GetObjInventor() == SdrInventor::Default) | |||
2500 | && (pObj->GetObjIdentifier() == OBJ_TABLE)) | |||
2501 | { | |||
2502 | mxSelectionController = sdr::table::CreateTableController( | |||
2503 | *pView, static_cast<const sdr::table::SdrTableObj&>(*pObj), mxLastSelectionController); | |||
2504 | ||||
2505 | if (mxSelectionController.is()) | |||
2506 | { | |||
2507 | mxLastSelectionController.clear(); | |||
2508 | mxSelectionController->onSelectionHasChanged(); | |||
2509 | } | |||
2510 | } | |||
2511 | } | |||
2512 | ||||
2513 | IMPL_LINK(SdrObjEditView, EndPasteOrDropHdl, PasteOrDropInfos*, pInfo, void)void SdrObjEditView::LinkStubEndPasteOrDropHdl(void * instance , PasteOrDropInfos* data) { return static_cast<SdrObjEditView *>(instance)->EndPasteOrDropHdl(data); } void SdrObjEditView ::EndPasteOrDropHdl(PasteOrDropInfos* pInfo) | |||
2514 | { | |||
2515 | OnEndPasteOrDrop(pInfo); | |||
2516 | } | |||
2517 | ||||
2518 | IMPL_LINK(SdrObjEditView, BeginPasteOrDropHdl, PasteOrDropInfos*, pInfo, void)void SdrObjEditView::LinkStubBeginPasteOrDropHdl(void * instance , PasteOrDropInfos* data) { return static_cast<SdrObjEditView *>(instance)->BeginPasteOrDropHdl(data); } void SdrObjEditView ::BeginPasteOrDropHdl(PasteOrDropInfos* pInfo) | |||
2519 | { | |||
2520 | OnBeginPasteOrDrop(pInfo); | |||
2521 | } | |||
2522 | ||||
2523 | void SdrObjEditView::OnBeginPasteOrDrop(PasteOrDropInfos*) | |||
2524 | { | |||
2525 | // applications can derive from these virtual methods to do something before a drop or paste operation | |||
2526 | } | |||
2527 | ||||
2528 | void SdrObjEditView::OnEndPasteOrDrop(PasteOrDropInfos*) | |||
2529 | { | |||
2530 | // applications can derive from these virtual methods to do something before a drop or paste operation | |||
2531 | } | |||
2532 | ||||
2533 | sal_uInt16 SdrObjEditView::GetSelectionLevel() const | |||
2534 | { | |||
2535 | sal_uInt16 nLevel = 0xFFFF; | |||
2536 | if (IsTextEdit()) | |||
2537 | { | |||
2538 | DBG_ASSERT(pTextEditOutlinerView != nullptr,do { if (true && (!(pTextEditOutlinerView != nullptr) )) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools" ), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" ":" "2539" ": "), "%s", "SdrObjEditView::GetAttributes(): pTextEditOutlinerView=NULL" ); } } while (false) | |||
2539 | "SdrObjEditView::GetAttributes(): pTextEditOutlinerView=NULL")do { if (true && (!(pTextEditOutlinerView != nullptr) )) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools" ), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" ":" "2539" ": "), "%s", "SdrObjEditView::GetAttributes(): pTextEditOutlinerView=NULL" ); } } while (false); | |||
2540 | DBG_ASSERT(pTextEditOutliner != nullptr,do { if (true && (!(pTextEditOutliner != nullptr))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools" ), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" ":" "2541" ": "), "%s", "SdrObjEditView::GetAttributes(): pTextEditOutliner=NULL" ); } } while (false) | |||
2541 | "SdrObjEditView::GetAttributes(): pTextEditOutliner=NULL")do { if (true && (!(pTextEditOutliner != nullptr))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools" ), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx" ":" "2541" ": "), "%s", "SdrObjEditView::GetAttributes(): pTextEditOutliner=NULL" ); } } while (false); | |||
2542 | if (pTextEditOutlinerView) | |||
2543 | { | |||
2544 | //start and end position | |||
2545 | ESelection aSelect = pTextEditOutlinerView->GetSelection(); | |||
2546 | sal_uInt16 nStartPara = ::std::min(aSelect.nStartPara, aSelect.nEndPara); | |||
2547 | sal_uInt16 nEndPara = ::std::max(aSelect.nStartPara, aSelect.nEndPara); | |||
2548 | //get level from each paragraph | |||
2549 | nLevel = 0; | |||
2550 | for (sal_uInt16 nPara = nStartPara; nPara <= nEndPara; nPara++) | |||
2551 | { | |||
2552 | sal_uInt16 nParaDepth | |||
2553 | = 1 << static_cast<sal_uInt16>(pTextEditOutliner->GetDepth(nPara)); | |||
2554 | if (!(nLevel & nParaDepth)) | |||
2555 | nLevel += nParaDepth; | |||
2556 | } | |||
2557 | //reduce one level for Outliner Object | |||
2558 | //if( nLevel > 0 && GetTextEditObject()->GetObjIdentifier() == OBJ_OUTLINETEXT ) | |||
2559 | // nLevel = nLevel >> 1; | |||
2560 | //no bullet paragraph selected | |||
2561 | if (nLevel == 0) | |||
2562 | nLevel = 0xFFFF; | |||
2563 | } | |||
2564 | } | |||
2565 | return nLevel; | |||
2566 | } | |||
2567 | ||||
2568 | bool SdrObjEditView::SupportsFormatPaintbrush(SdrInventor nObjectInventor, | |||
2569 | sal_uInt16 nObjectIdentifier) | |||
2570 | { | |||
2571 | if (nObjectInventor != SdrInventor::Default && nObjectInventor != SdrInventor::E3d) | |||
2572 | return false; | |||
2573 | switch (nObjectIdentifier) | |||
2574 | { | |||
2575 | case OBJ_NONE: | |||
2576 | case OBJ_GRUP: | |||
2577 | return false; | |||
2578 | case OBJ_LINE: | |||
2579 | case OBJ_RECT: | |||
2580 | case OBJ_CIRC: | |||
2581 | case OBJ_SECT: | |||
2582 | case OBJ_CARC: | |||
2583 | case OBJ_CCUT: | |||
2584 | case OBJ_POLY: | |||
2585 | case OBJ_PLIN: | |||
2586 | case OBJ_PATHLINE: | |||
2587 | case OBJ_PATHFILL: | |||
2588 | case OBJ_FREELINE: | |||
2589 | case OBJ_FREEFILL: | |||
2590 | case OBJ_SPLNLINE: | |||
2591 | case OBJ_SPLNFILL: | |||
2592 | case OBJ_TEXT: | |||
2593 | case OBJ_TITLETEXT: | |||
2594 | case OBJ_OUTLINETEXT: | |||
2595 | case OBJ_GRAF: | |||
2596 | case OBJ_OLE2: | |||
2597 | case OBJ_TABLE: | |||
2598 | return true; | |||
2599 | case OBJ_EDGE: | |||
2600 | case OBJ_CAPTION: | |||
2601 | return false; | |||
2602 | case OBJ_PATHPOLY: | |||
2603 | case OBJ_PATHPLIN: | |||
2604 | return true; | |||
2605 | case OBJ_PAGE: | |||
2606 | case OBJ_MEASURE: | |||
2607 | case OBJ_FRAME: | |||
2608 | case OBJ_UNO: | |||
2609 | return false; | |||
2610 | case OBJ_CUSTOMSHAPE: | |||
2611 | return true; | |||
2612 | default: | |||
2613 | return false; | |||
2614 | } | |||
2615 | } | |||
2616 | ||||
2617 | static const sal_uInt16* GetFormatRangeImpl(bool bTextOnly) | |||
2618 | { | |||
2619 | static const sal_uInt16 gRanges[] = { SDRATTR_SHADOW_FIRST, | |||
2620 | SDRATTR_SHADOW_LAST, | |||
2621 | SDRATTR_GRAF_FIRST, | |||
2622 | SDRATTR_GRAF_LAST, | |||
2623 | SDRATTR_TABLE_FIRST, | |||
2624 | SDRATTR_TABLE_LAST, | |||
2625 | XATTR_LINE_FIRST, | |||
2626 | XATTR_LINE_LAST, | |||
2627 | XATTR_FILL_FIRST, | |||
2628 | XATTRSET_FILL, | |||
2629 | EE_PARA_START, | |||
2630 | EE_PARA_END, // text-only from here on | |||
2631 | EE_CHAR_START, | |||
2632 | EE_CHAR_END, | |||
2633 | SDRATTR_MISC_FIRST, | |||
2634 | SDRATTR_MISC_LAST, // table cell formats | |||
2635 | 0, | |||
2636 | 0 }; | |||
2637 | return &gRanges[bTextOnly ? 10 : 0]; | |||
2638 | } | |||
2639 | ||||
2640 | void SdrObjEditView::TakeFormatPaintBrush(std::shared_ptr<SfxItemSet>& rFormatSet) | |||
2641 | { | |||
2642 | const SdrMarkList& rMarkList = GetMarkedObjectList(); | |||
2643 | if (rMarkList.GetMarkCount() <= 0) | |||
2644 | return; | |||
2645 | ||||
2646 | OutlinerView* pOLV = GetTextEditOutlinerView(); | |||
2647 | ||||
2648 | rFormatSet = std::make_shared<SfxItemSet>(GetModel()->GetItemPool(), | |||
2649 | GetFormatRangeImpl(pOLV != nullptr)); | |||
2650 | if (pOLV) | |||
2651 | { | |||
2652 | rFormatSet->Put(pOLV->GetAttribs()); | |||
2653 | } | |||
2654 | else | |||
2655 | { | |||
2656 | const bool bOnlyHardAttr = false; | |||
2657 | rFormatSet->Put(GetAttrFromMarked(bOnlyHardAttr)); | |||
2658 | } | |||
2659 | ||||
2660 | // check for cloning from table cell, in which case we need to copy cell-specific formatting attributes | |||
2661 | const SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj(); | |||
2662 | if (pObj && (pObj->GetObjInventor() == SdrInventor::Default) | |||
2663 | && (pObj->GetObjIdentifier() == OBJ_TABLE)) | |||
2664 | { | |||
2665 | auto pTable = static_cast<const sdr::table::SdrTableObj*>(pObj); | |||
2666 | if (mxSelectionController.is() && pTable->getActiveCell().is()) | |||
2667 | { | |||
2668 | mxSelectionController->GetAttributes(*rFormatSet, false); | |||
2669 | } | |||
2670 | } | |||
2671 | } | |||
2672 | ||||
2673 | static SfxItemSet CreatePaintSet(const sal_uInt16* pRanges, SfxItemPool& rPool, | |||
2674 | const SfxItemSet& rSourceSet, const SfxItemSet& rTargetSet, | |||
2675 | bool bNoCharacterFormats, bool bNoParagraphFormats) | |||
2676 | { | |||
2677 | SfxItemSet aPaintSet(rPool, pRanges); | |||
2678 | ||||
2679 | while (*pRanges) | |||
2680 | { | |||
2681 | sal_uInt16 nWhich = *pRanges++; | |||
2682 | const sal_uInt16 nLastWhich = *pRanges++; | |||
2683 | ||||
2684 | if (bNoCharacterFormats && (nWhich == EE_CHAR_START)) | |||
2685 | continue; | |||
2686 | ||||
2687 | if (bNoParagraphFormats && (nWhich == EE_PARA_START)) | |||
2688 | continue; | |||
2689 | ||||
2690 | for (; nWhich < nLastWhich; nWhich++) | |||
2691 | { | |||
2692 | const SfxPoolItem* pSourceItem = rSourceSet.GetItem(nWhich); | |||
2693 | const SfxPoolItem* pTargetItem = rTargetSet.GetItem(nWhich); | |||
2694 | ||||
2695 | if ((pSourceItem && !pTargetItem) | |||
2696 | || (pSourceItem && pTargetItem && *pSourceItem != *pTargetItem)) | |||
2697 | { | |||
2698 | aPaintSet.Put(*pSourceItem); | |||
2699 | } | |||
2700 | } | |||
2701 | } | |||
2702 | return aPaintSet; | |||
2703 | } | |||
2704 | ||||
2705 | void SdrObjEditView::ApplyFormatPaintBrushToText(SfxItemSet const& rFormatSet, SdrTextObj& rTextObj, | |||
2706 | SdrText* pText, bool bNoCharacterFormats, | |||
2707 | bool bNoParagraphFormats) | |||
2708 | { | |||
2709 | OutlinerParaObject* pParaObj = pText ? pText->GetOutlinerParaObject() : nullptr; | |||
2710 | if (!pParaObj) | |||
2711 | return; | |||
2712 | ||||
2713 | SdrOutliner& rOutliner = rTextObj.ImpGetDrawOutliner(); | |||
2714 | rOutliner.SetText(*pParaObj); | |||
2715 | ||||
2716 | sal_Int32 nParaCount(rOutliner.GetParagraphCount()); | |||
2717 | ||||
2718 | if (!nParaCount) | |||
2719 | return; | |||
2720 | ||||
2721 | for (sal_Int32 nPara = 0; nPara < nParaCount; nPara++) | |||
2722 | { | |||
2723 | if (!bNoCharacterFormats) | |||
2724 | rOutliner.RemoveCharAttribs(nPara); | |||
2725 | ||||
2726 | SfxItemSet aSet(rOutliner.GetParaAttribs(nPara)); | |||
2727 | aSet.Put(CreatePaintSet(GetFormatRangeImpl(true), *aSet.GetPool(), rFormatSet, aSet, | |||
2728 | bNoCharacterFormats, bNoParagraphFormats)); | |||
2729 | rOutliner.SetParaAttribs(nPara, aSet); | |||
2730 | } | |||
2731 | ||||
2732 | std::unique_ptr<OutlinerParaObject> pTemp = rOutliner.CreateParaObject(0, nParaCount); | |||
2733 | rOutliner.Clear(); | |||
2734 | ||||
2735 | rTextObj.NbcSetOutlinerParaObjectForText(std::move(pTemp), pText); | |||
2736 | } | |||
2737 | ||||
2738 | void SdrObjEditView::ApplyFormatPaintBrush(SfxItemSet& rFormatSet, bool bNoCharacterFormats, | |||
2739 | bool bNoParagraphFormats) | |||
2740 | { | |||
2741 | if (mxSelectionController.is() | |||
2742 | && mxSelectionController->ApplyFormatPaintBrush(rFormatSet, bNoCharacterFormats, | |||
2743 | bNoParagraphFormats)) | |||
2744 | { | |||
2745 | return; | |||
2746 | } | |||
2747 | ||||
2748 | OutlinerView* pOLV = GetTextEditOutlinerView(); | |||
2749 | const SdrMarkList& rMarkList = GetMarkedObjectList(); | |||
2750 | if (!pOLV) | |||
2751 | { | |||
2752 | SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj(); | |||
2753 | const SfxItemSet& rShapeSet = pObj->GetMergedItemSet(); | |||
2754 | ||||
2755 | // if not in text edit mode (aka the user selected text or clicked on a word) | |||
2756 | // apply formatting attributes to selected shape | |||
2757 | // All formatting items (see ranges above) that are unequal in selected shape and | |||
2758 | // the format paintbrush are hard set on the selected shape. | |||
2759 | ||||
2760 | const sal_uInt16* pRanges = rFormatSet.GetRanges(); | |||
2761 | bool bTextOnly = true; | |||
2762 | ||||
2763 | while (*pRanges) | |||
2764 | { | |||
2765 | if ((*pRanges != EE_PARA_START) && (*pRanges != EE_CHAR_START)) | |||
2766 | { | |||
2767 | bTextOnly = false; | |||
2768 | break; | |||
2769 | } | |||
2770 | pRanges += 2; | |||
2771 | } | |||
2772 | ||||
2773 | if (!bTextOnly) | |||
2774 | { | |||
2775 | SfxItemSet aPaintSet(CreatePaintSet(GetFormatRangeImpl(false), *rShapeSet.GetPool(), | |||
2776 | rFormatSet, rShapeSet, bNoCharacterFormats, | |||
2777 | bNoParagraphFormats)); | |||
2778 | SetAttrToMarked(aPaintSet, false /*bReplaceAll*/); | |||
2779 | } | |||
2780 | ||||
2781 | // now apply character and paragraph formatting to text, if the shape has any | |||
2782 | SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>(pObj); | |||
2783 | if (pTextObj) | |||
2784 | { | |||
2785 | sal_Int32 nText = pTextObj->getTextCount(); | |||
2786 | ||||
2787 | while (--nText >= 0) | |||
2788 | { | |||
2789 | SdrText* pText = pTextObj->getText(nText); | |||
2790 | ApplyFormatPaintBrushToText(rFormatSet, *pTextObj, pText, bNoCharacterFormats, | |||
2791 | bNoParagraphFormats); | |||
2792 | } | |||
2793 | } | |||
2794 | } | |||
2795 | else | |||
2796 | { | |||
2797 | ::Outliner* pOutliner = pOLV->GetOutliner(); | |||
2798 | if (pOutliner) | |||
2799 | { | |||
2800 | const EditEngine& rEditEngine = pOutliner->GetEditEngine(); | |||
2801 | ||||
2802 | ESelection aSel(pOLV->GetSelection()); | |||
2803 | if (!aSel.HasRange()) | |||
2804 | pOLV->SetSelection(rEditEngine.GetWord(aSel, css::i18n::WordType::DICTIONARY_WORD)); | |||
2805 | ||||
2806 | const bool bRemoveParaAttribs = !bNoParagraphFormats; | |||
2807 | pOLV->RemoveAttribsKeepLanguages(bRemoveParaAttribs); | |||
2808 | SfxItemSet aSet(pOLV->GetAttribs()); | |||
2809 | SfxItemSet aPaintSet(CreatePaintSet(GetFormatRangeImpl(true), *aSet.GetPool(), | |||
2810 | rFormatSet, aSet, bNoCharacterFormats, | |||
2811 | bNoParagraphFormats)); | |||
2812 | pOLV->SetAttribs(aPaintSet); | |||
2813 | } | |||
2814 | } | |||
2815 | ||||
2816 | // check for cloning to table cell, in which case we need to copy cell-specific formatting attributes | |||
2817 | SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj(); | |||
2818 | if (pObj && (pObj->GetObjInventor() == SdrInventor::Default) | |||
2819 | && (pObj->GetObjIdentifier() == OBJ_TABLE)) | |||
2820 | { | |||
2821 | auto pTable = static_cast<sdr::table::SdrTableObj*>(pObj); | |||
2822 | if (pTable->getActiveCell().is() && mxSelectionController.is()) | |||
2823 | { | |||
2824 | mxSelectionController->SetAttributes(rFormatSet, false); | |||
2825 | } | |||
2826 | } | |||
2827 | } | |||
2828 | ||||
2829 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
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 | #ifndef INCLUDED_SVX_SVDEDTV_HXX | |||
21 | #define INCLUDED_SVX_SVDEDTV_HXX | |||
22 | ||||
23 | #include <svx/svdmrkv.hxx> | |||
24 | #include <svx/xpoly.hxx> | |||
25 | #include <svx/svdmodel.hxx> | |||
26 | #include <svx/svxdllapi.h> | |||
27 | #include <svx/svdundo.hxx> | |||
28 | #include <o3tl/typed_flags_set.hxx> | |||
29 | ||||
30 | class SfxUndoAction; | |||
31 | class SdrUndoAction; | |||
32 | class SdrUndoGroup; | |||
33 | class SfxStyleSheet; | |||
34 | class SdrLayer; | |||
35 | class SvdProgressInfo; | |||
36 | ||||
37 | enum class SdrHorAlign { | |||
38 | NONE, | |||
39 | Left, | |||
40 | Right, | |||
41 | Center | |||
42 | }; | |||
43 | ||||
44 | enum class SdrVertAlign { | |||
45 | NONE, | |||
46 | Top, | |||
47 | Bottom, | |||
48 | Center | |||
49 | }; | |||
50 | ||||
51 | enum class SdrMergeMode { | |||
52 | Merge, | |||
53 | Subtract, | |||
54 | Intersect | |||
55 | }; | |||
56 | ||||
57 | // Options for InsertObject() | |||
58 | enum class SdrInsertFlags | |||
59 | { | |||
60 | NONE = 0x0000, | |||
61 | DONTMARK = 0x0001, /* object will not be marked (the actual marking remains) */ | |||
62 | ADDMARK = 0x0002, /* object will be added an existing selection */ | |||
63 | SETDEFATTR = 0x0004, /* actual attributes (+StyleSheet) are assigned to the object */ | |||
64 | SETDEFLAYER = 0x0008, /* actual layer is assigned to the object */ | |||
65 | }; | |||
66 | namespace o3tl | |||
67 | { | |||
68 | template<> struct typed_flags<SdrInsertFlags> : is_typed_flags<SdrInsertFlags, 0x0f> {}; | |||
69 | } | |||
70 | ||||
71 | class SVXCORE_DLLPUBLIC__attribute__ ((visibility("default"))) SdrEditView : public SdrMarkView | |||
72 | { | |||
73 | friend class SdrPageView; | |||
74 | friend class SdrDragDistort; | |||
75 | friend class SdrDragCrook; | |||
76 | ||||
77 | protected: | |||
78 | ||||
79 | // cache the transformation queries, etc. a little | |||
80 | bool m_bPossibilitiesDirty : 1; | |||
81 | bool m_bReadOnly : 1; | |||
82 | bool m_bGroupPossible : 1; | |||
83 | bool m_bUnGroupPossible : 1; | |||
84 | bool m_bGrpEnterPossible : 1; | |||
85 | bool m_bToTopPossible : 1; | |||
86 | bool m_bToBtmPossible : 1; | |||
87 | bool m_bReverseOrderPossible : 1; | |||
88 | bool m_bImportMtfPossible : 1; | |||
89 | bool m_bCombinePossible : 1; | |||
90 | bool m_bDismantlePossible : 1; | |||
91 | bool m_bCombineNoPolyPolyPossible : 1; | |||
92 | bool m_bDismantleMakeLinesPossible : 1; | |||
93 | bool m_bOrthoDesiredOnMarked : 1; | |||
94 | bool m_bOneOrMoreMovable : 1; // at least one object is moveable | |||
95 | bool m_bMoreThanOneNoMovRot : 1; // more than one object is not movable nor turnable (Crook) | |||
96 | bool m_bContortionPossible : 1; // all polygones (grouped if necessary) | |||
97 | bool m_bMoveAllowed : 1; | |||
98 | bool m_bResizeFreeAllowed : 1; | |||
99 | bool m_bResizePropAllowed : 1; | |||
100 | bool m_bRotateFreeAllowed : 1; | |||
101 | bool m_bRotate90Allowed : 1; | |||
102 | bool m_bMirrorFreeAllowed : 1; | |||
103 | bool m_bMirror45Allowed : 1; | |||
104 | bool m_bMirror90Allowed : 1; | |||
105 | bool m_bShearAllowed : 1; | |||
106 | bool m_bEdgeRadiusAllowed : 1; | |||
107 | bool m_bTransparenceAllowed : 1; | |||
108 | bool m_bCropAllowed : 1; | |||
109 | bool m_bGradientAllowed : 1; | |||
110 | bool m_bCanConvToPath : 1; | |||
111 | bool m_bCanConvToPoly : 1; | |||
112 | bool m_bCanConvToContour : 1; | |||
113 | bool m_bMoveProtect : 1; | |||
114 | bool m_bResizeProtect : 1; | |||
115 | ||||
116 | private: | |||
117 | SVX_DLLPRIVATE__attribute__ ((visibility("hidden"))) void ImpResetPossibilityFlags(); | |||
118 | ||||
119 | protected: | |||
120 | void ImpBroadcastEdgesOfMarkedNodes(); | |||
121 | ||||
122 | // convert the objects marked in poly resp. bezier | |||
123 | void ImpConvertTo(bool bPath, bool bLineToArea); | |||
124 | ||||
125 | // converts an object, when positive it removes the old one from its List | |||
126 | // and inserts the new one instead. including Undo. | |||
127 | // Nor MarkEntry nor ModelChgBroadcast is created. | |||
128 | SdrObject* ImpConvertOneObj(SdrObject* pObj, bool bPath, bool bLineToArea); | |||
129 | ||||
130 | // set both flags: bToTopPossible and bToBtmPossible. | |||
131 | // bToTopPossibleDirty and bToBtmPossibleDirty are reset at the same time | |||
132 | void ImpCheckToTopBtmPossible(); | |||
133 | ||||
134 | // for CombineMarkedObjects and DismantleMarkedObjects | |||
135 | void ImpCopyAttributes(const SdrObject* pSource, SdrObject* pDest) const; | |||
136 | ||||
137 | // for CombineMarkedObjects | |||
138 | static bool ImpCanConvertForCombine1(const SdrObject* pObj); | |||
139 | static bool ImpCanConvertForCombine(const SdrObject* pObj); | |||
140 | static basegfx::B2DPolyPolygon ImpGetPolyPolygon1(const SdrObject* pObj); | |||
141 | static basegfx::B2DPolyPolygon ImpGetPolyPolygon(const SdrObject* pObj); | |||
142 | static basegfx::B2DPolygon ImpCombineToSinglePolygon(const basegfx::B2DPolyPolygon& rPolyPolygon); | |||
143 | ||||
144 | // for DismantleMarkedObjects | |||
145 | static bool ImpCanDismantle(const basegfx::B2DPolyPolygon& rPpolyPpolygon, bool bMakeLines); | |||
146 | static bool ImpCanDismantle(const SdrObject* pObj, bool bMakeLines); | |||
147 | void ImpDismantleOneObject(const SdrObject* pObj, SdrObjList& rOL, size_t& rPos, SdrPageView* pPV, bool bMakeLines); | |||
148 | static void ImpCrookObj(SdrObject* pO, const Point& rRef, const Point& rRad, SdrCrookMode eMode, | |||
149 | bool bVertical, bool bNoContortion, bool bRotate, const tools::Rectangle& rMarkRect); | |||
150 | static void ImpDistortObj(SdrObject* pO, const tools::Rectangle& rRef, const XPolygon& rDistortedRect, bool bNoContortion); | |||
151 | bool ImpDelLayerCheck(SdrObjList const * pOL, SdrLayerID nDelID) const; | |||
152 | void ImpDelLayerDelObjs(SdrObjList* pOL, SdrLayerID nDelID); | |||
153 | ||||
154 | // Removes all objects of the MarkList from their ObjLists including Undo. | |||
155 | // The entries in rMark remain. | |||
156 | // @return a list of objects that must be deleted after the outermost EndUndo | |||
157 | std::vector<SdrObject *> DeleteMarkedList(SdrMarkList const& rMark); // DeleteMarked -> DeleteMarkedList | |||
158 | ||||
159 | // Check possibilities of all marked objects | |||
160 | virtual void CheckPossibilities(); | |||
161 | void ForcePossibilities() const { if (m_bPossibilitiesDirty || mbSomeObjChgdFlag) const_cast<SdrEditView*>(this)->CheckPossibilities(); } | |||
162 | ||||
163 | protected: | |||
164 | // #i71538# make constructors of SdrView sub-components protected to avoid incomplete incarnations which may get casted to SdrView | |||
165 | SdrEditView( | |||
166 | SdrModel& rSdrModel, | |||
167 | OutputDevice* pOut); | |||
168 | ||||
169 | virtual ~SdrEditView() override; | |||
170 | ||||
171 | public: | |||
172 | // each call of an undo-capable method from its view, generates an undo action. | |||
173 | // If one wishes to group method calls into one, these calls should be put | |||
174 | // between BegUndo() and EndUndo() calls (unlimited). | |||
175 | // The comment used for the UndoAction is the first BegUndo(String). | |||
176 | // In this case NotifyNewUndoAction is called at the last EndUndo(). | |||
177 | // NotifyNewUndoAction() is not called for an empty group. | |||
178 | void BegUndo() { mpModel->BegUndo(); } // open undo-grouping | |||
179 | void BegUndo(const OUString& rComment) { mpModel->BegUndo(rComment); } // open undo-grouping | |||
180 | void BegUndo(const OUString& rComment, const OUString& rObjDescr, SdrRepeatFunc eFunc=SdrRepeatFunc::NONE) { mpModel->BegUndo(rComment,rObjDescr,eFunc); } // open undo-grouping | |||
| ||||
181 | void EndUndo(); // close undo-grouping (incl. BroadcastEdges) | |||
182 | void AddUndo(std::unique_ptr<SdrUndoAction> pUndo) { mpModel->AddUndo(std::move(pUndo)); } // add action | |||
183 | // only after first BegUndo or before last EndUndo: | |||
184 | void SetUndoComment(const OUString& rComment, const OUString& rObjDescr) { mpModel->SetUndoComment(rComment,rObjDescr); } | |||
185 | bool IsUndoEnabled() const; | |||
186 | ||||
187 | /** | |||
188 | * Checks if this or other views have an active text edit, if true, end them. | |||
189 | */ | |||
190 | void EndTextEditAllViews() const; | |||
191 | ||||
192 | std::vector< std::unique_ptr<SdrUndoAction> > CreateConnectorUndo( SdrObject& rO ); | |||
193 | void AddUndoActions( std::vector< std::unique_ptr<SdrUndoAction> > ); | |||
194 | ||||
195 | // Layermanagement with Undo. | |||
196 | void InsertNewLayer(const OUString& rName, sal_uInt16 nPos); | |||
197 | // Delete a layer including all objects contained | |||
198 | void DeleteLayer(const OUString& rName); | |||
199 | ||||
200 | // Marked objects which are outside a page | |||
201 | // are assigned to another page; at the moment without undo!!! | |||
202 | void ForceMarkedObjToAnotherPage(); | |||
203 | void ForceMarkedToAnotherPage() { ForceMarkedObjToAnotherPage(); } | |||
204 | ||||
205 | // delete all marked objects | |||
206 | void DeleteMarkedObj(); | |||
207 | ||||
208 | // Set a logical enclosing rectangle for all marked objects. | |||
209 | // It is not guaranteed if this succeeds, as a horizontal | |||
210 | // line has always a height of 0 | |||
211 | void SetMarkedObjRect(const tools::Rectangle& rRect); | |||
212 | void MoveMarkedObj(const Size& rSiz, bool bCopy=false); | |||
213 | void ResizeMarkedObj(const Point& rRef, const Fraction& xFact, const Fraction& yFact, bool bCopy=false); | |||
214 | void ResizeMultMarkedObj(const Point& rRef, const Fraction& xFact, const Fraction& yFact, const bool bWdh, const bool bHgt); | |||
215 | long GetMarkedObjRotate() const; | |||
216 | void RotateMarkedObj(const Point& rRef, long nAngle, bool bCopy=false); | |||
217 | void MirrorMarkedObj(const Point& rRef1, const Point& rRef2, bool bCopy=false); | |||
218 | void MirrorMarkedObjHorizontal(); | |||
219 | void MirrorMarkedObjVertical(); | |||
220 | long GetMarkedObjShear() const; | |||
221 | void ShearMarkedObj(const Point& rRef, long nAngle, bool bVShear=false, bool bCopy=false); | |||
222 | void CrookMarkedObj(const Point& rRef, const Point& rRad, SdrCrookMode eMode, bool bVertical, bool bNoContortion, bool bCopy=false); | |||
223 | void DistortMarkedObj(const tools::Rectangle& rRef, const XPolygon& rDistortedRect, bool bNoContortion, bool bCopy=false); | |||
224 | ||||
225 | // copy marked objects and mark them instead of the old ones | |||
226 | void CopyMarkedObj(); | |||
227 | void SetAllMarkedRect(const tools::Rectangle& rRect) { SetMarkedObjRect(rRect); } | |||
228 | void MoveAllMarked(const Size& rSiz, bool bCopy=false) { MoveMarkedObj(rSiz,bCopy); } | |||
229 | void ResizeAllMarked(const Point& rRef, const Fraction& xFact, const Fraction& yFact) { ResizeMarkedObj(rRef,xFact,yFact); } | |||
230 | void RotateAllMarked(const Point& rRef, long nAngle) { RotateMarkedObj(rRef,nAngle); } | |||
231 | void MirrorAllMarkedHorizontal() { MirrorMarkedObjHorizontal(); } | |||
232 | void MirrorAllMarkedVertical() { MirrorMarkedObjVertical(); } | |||
233 | void CopyMarked() { CopyMarkedObj(); } | |||
234 | bool IsMoveAllowed() const { ForcePossibilities(); return m_bMoveAllowed && !m_bMoveProtect; } | |||
235 | bool IsResizeAllowed(bool bProp=false) const; | |||
236 | bool IsRotateAllowed(bool b90Deg=false) const; | |||
237 | bool IsMirrorAllowed(bool b45Deg=false, bool b90Deg=false) const; | |||
238 | bool IsTransparenceAllowed() const; | |||
239 | bool IsGradientAllowed() const; | |||
240 | bool IsShearAllowed() const; | |||
241 | bool IsEdgeRadiusAllowed() const; | |||
242 | bool IsCrookAllowed(bool bNoContortion=false) const; | |||
243 | bool IsCropAllowed() const; | |||
244 | bool IsDistortAllowed(bool bNoContortion=false) const; | |||
245 | ||||
246 | // Consolidate the text from multiple, selected TextObjects, | |||
247 | // attempting to identify paragraph fragments and join them together | |||
248 | void CombineMarkedTextObjects(); | |||
249 | ||||
250 | // Unite several objects to a polygon: | |||
251 | // - rectangles/circles/text... are implicitly converted. | |||
252 | // - polygones are closed automatically | |||
253 | // - attributes and layer are taken from the first object marked | |||
254 | // (thus from lowest Z-order). | |||
255 | // - group objects are included when all (!) member objects of | |||
256 | // the group can be changed. If a group includes for example | |||
257 | // a bitmap or an OLE-object, the complete group is not considered. | |||
258 | // bNoPolyPoly=TRUE: all is grouped to one single polygon | |||
259 | void CombineMarkedObjects(bool bNoPolyPoly = true); | |||
260 | ||||
261 | // for combining multiple polygons, with direct support of the modes | |||
262 | // SID_POLY_MERGE, SID_POLY_SUBSTRACT, SID_POLY_INTERSECT | |||
263 | void MergeMarkedObjects(SdrMergeMode eMode); | |||
264 | ||||
265 | // for distribution dialog function | |||
266 | void DistributeMarkedObjects(sal_uInt16 SlotID); | |||
267 | ||||
268 | // for setting either the width or height of all selected | |||
269 | // objects to the width/height of the last selected object | |||
270 | // of the selection | |||
271 | void EqualizeMarkedObjects(bool bWidth); | |||
272 | ||||
273 | // Decompose marked polypolygon objects into polygons. | |||
274 | // Grouped objects are searched and decomposed, if all member objects are PathObjs. | |||
275 | // bMakeLines=TRUE: all polygones are decomposed into single lines resp. bezier segments | |||
276 | void DismantleMarkedObjects(bool bMakeLines=false); | |||
277 | bool IsCombinePossible(bool bNoPolyPoly=false) const; | |||
278 | bool IsDismantlePossible(bool bMakeLines=false) const; | |||
279 | ||||
280 | // Inserts a new, completely constructed object. Subsequently the object belongs to | |||
281 | // the model. After insertion the object is marked (if not prevented by nOptions). | |||
282 | // Sometimes the object is not inserted, but deleted, this is the case when | |||
283 | // the target layer is locked or not visible. In this case | |||
284 | // the method returns FALSE. | |||
285 | // Amongst others the method does not create an undo-action. | |||
286 | bool InsertObjectAtView(SdrObject* pObj, SdrPageView& rPV, SdrInsertFlags nOptions=SdrInsertFlags::NONE); | |||
287 | ||||
288 | // Replace one drawing object by another. | |||
289 | // *pNewObj belongs to me, *pOldObj is changed into Undo. | |||
290 | // In any case an undo grouping is required and should be applied, e.g.: | |||
291 | // aStr+=" replace"; | |||
292 | // BegUndo(aStr); | |||
293 | // ReplaceObject(...); | |||
294 | ||||
295 | // EndUndo(); | |||
296 | void ReplaceObjectAtView(SdrObject* pOldObj, SdrPageView& rPV, SdrObject* pNewObj, bool bMark=true); | |||
297 | ||||
298 | void SetNotPersistAttrToMarked(const SfxItemSet& rAttr); | |||
299 | void MergeNotPersistAttrFromMarked(SfxItemSet& rAttr) const; | |||
300 | void MergeAttrFromMarked(SfxItemSet& rAttr, bool bOnlyHardAttr) const; | |||
301 | SfxItemSet GetAttrFromMarked(bool bOnlyHardAttr) const; | |||
302 | void SetAttrToMarked(const SfxItemSet& rAttr, bool bReplaceAll); | |||
303 | ||||
304 | // geometrical attribute (position, size, rotation angle) | |||
305 | // A PageOrigin set at a position is taken into account. | |||
306 | SfxItemSet GetGeoAttrFromMarked() const; | |||
307 | void SetGeoAttrToMarked(const SfxItemSet& rAttr); | |||
308 | ||||
309 | // Returns NULL if: | |||
310 | // - nothing is marked, | |||
311 | // - no stylesheet is set at the marked object | |||
312 | // - point the marked objects to different StyleSheets for multiple selections | |||
313 | SfxStyleSheet* GetStyleSheetFromMarked() const; | |||
314 | ||||
315 | // at the moment without undo :( | |||
316 | void SetStyleSheetToMarked(SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr); | |||
317 | ||||
318 | /* new interface src537 */ | |||
319 | void GetAttributes(SfxItemSet& rTargetSet, bool bOnlyHardAttr) const; | |||
320 | ||||
321 | void SetAttributes(const SfxItemSet& rSet, bool bReplaceAll); | |||
322 | SfxStyleSheet* GetStyleSheet() const; // SfxStyleSheet* GetStyleSheet(bool& rOk) const; | |||
323 | void SetStyleSheet(SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr); | |||
324 | ||||
325 | // Group all marked objects to a single group. | |||
326 | // Subsequently mark the new group . If the group spawns multiple | |||
327 | // pages a group is created per page. | |||
328 | // All groups created are subsequently marked. | |||
329 | // The method creates SdrObjGroup-instances. | |||
330 | void GroupMarked(); | |||
331 | ||||
332 | // All marked object groups are dissolved (1 level). | |||
333 | // Now all previously marked member objects are marked. | |||
334 | // Previously marked objects, which are not group objects, remain marked. | |||
335 | void UnGroupMarked(); | |||
336 | ||||
337 | bool IsGroupPossible() const { ForcePossibilities(); return m_bGroupPossible; } | |||
338 | bool IsUnGroupPossible() const { ForcePossibilities(); return m_bUnGroupPossible; } | |||
339 | bool IsGroupEnterPossible() const { ForcePossibilities(); return m_bGrpEnterPossible; } | |||
340 | ||||
341 | // Convert marked objects to polygones/Beziercurves. The bool-functions | |||
342 | // return sal_True, if at least one marked object could be converted. | |||
343 | // Also member objects of group objects are converted. | |||
344 | // For a better description see: SdrObj.HXX | |||
345 | bool IsConvertToPathObjPossible() const { ForcePossibilities(); return m_bCanConvToPath; } | |||
346 | bool IsConvertToPolyObjPossible() const { ForcePossibilities(); return m_bCanConvToPoly; } | |||
347 | bool IsConvertToContourPossible() const { ForcePossibilities(); return m_bCanConvToContour; } | |||
348 | void ConvertMarkedToPathObj(bool bLineToArea); | |||
349 | void ConvertMarkedToPolyObj(); | |||
350 | ||||
351 | // Align all marked objects vertically. Normally the SnapRect of an object is used. | |||
352 | void AlignMarkedObjects(SdrHorAlign eHor, SdrVertAlign eVert); | |||
353 | bool IsAlignPossible() const; | |||
354 | ||||
355 | // move marked objects "up" | |||
356 | void MovMarkedToTop(); | |||
357 | ||||
358 | // move marked objects "down" | |||
359 | void MovMarkedToBtm(); | |||
360 | ||||
361 | // move marked objects "at top" | |||
362 | void PutMarkedToTop(); | |||
363 | ||||
364 | // move marked objects "at bottom" | |||
365 | void PutMarkedToBtm(); | |||
366 | ||||
367 | // move marked immediately before the object passed | |||
368 | // NULL -> as PutMarkedToTop(); | |||
369 | void PutMarkedInFrontOfObj(const SdrObject* pRefObj); | |||
370 | ||||
371 | // move marked immediately after object passed | |||
372 | // NULL -> as PutMarkedToBtm(); | |||
373 | void PutMarkedBehindObj(const SdrObject* pRefObj); | |||
374 | ||||
375 | // swap Z-Order of marked objects | |||
376 | void ReverseOrderOfMarked(); | |||
377 | ||||
378 | // Check if forward, backward is possible. | |||
379 | // GetMaxToBtmObj() is only partly taken into account by these methods. | |||
380 | // Which means it can happen that IsToTopPossible() returns sal_True, | |||
381 | // but MovMarkedToTop() changes nothing (e.g. for multiple selections), | |||
382 | // as restriction derived via a view by GetMaxToTopObj() prevents this. | |||
383 | bool IsToTopPossible() const { ForcePossibilities(); return m_bToTopPossible; } | |||
384 | bool IsToBtmPossible() const { ForcePossibilities(); return m_bToBtmPossible; } | |||
385 | bool IsReverseOrderPossible() const { ForcePossibilities(); return m_bReverseOrderPossible; } | |||
386 | ||||
387 | // Using this method the view determines how far an object | |||
388 | // can be moved forward or backward (Z-order). | |||
389 | // The object returned is not "obsolete". When NULL is | |||
390 | // returned there is not such a restriction. | |||
391 | virtual SdrObject* GetMaxToTopObj(SdrObject* pObj) const; | |||
392 | virtual SdrObject* GetMaxToBtmObj(SdrObject* pObj) const; | |||
393 | ||||
394 | // Next method is called, if via ToTop, ToBtm, ... the | |||
395 | // sequence of object has been changed. It is called after | |||
396 | // each SdrObjList::SetObjectOrdNum(nOldPos,nNewPos); | |||
397 | virtual void ObjOrderChanged(SdrObject* pObj, size_t nOldPos, size_t nNewPos); | |||
398 | ||||
399 | // If one or more objects of the type SdrGrafObj or SdrOle2Obj | |||
400 | // are marked and these are capable to deliver a StarView-metafile, | |||
401 | // this methods converts the metafile to a drawing object. | |||
402 | // The SdrGrafObjs/SdrOle2Objs are replaced by the new objects. | |||
403 | void DoImportMarkedMtf(SvdProgressInfo *pProgrInfo=nullptr); | |||
404 | bool IsImportMtfPossible() const { ForcePossibilities(); return m_bImportMtfPossible; } | |||
405 | ||||
406 | // override SdrMarkView, for internal use | |||
407 | virtual void MarkListHasChanged() override; | |||
408 | virtual void ModelHasChanged() override; | |||
409 | }; | |||
410 | ||||
411 | #endif // INCLUDED_SVX_SVDEDTV_HXX | |||
412 | ||||
413 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |