Bug Summary

File:home/maarten/src/libreoffice/core/include/rtl/ref.hxx
Warning:line 192, column 9
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name gridwin.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SC_DLLIMPLEMENTATION -D SC_INFO_OSVERSION="LINUX" -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/liborcus/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/mdds/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/clew/source/include -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/sc/source/core/inc -I /home/maarten/src/libreoffice/core/sc/source/filter/inc -I /home/maarten/src/libreoffice/core/sc/source/ui/inc -I /home/maarten/src/libreoffice/core/sc/inc -I /home/maarten/src/libreoffice/core/workdir/SdiTarget/sc/sdi -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sc/source/ui/view/gridwin.cxx

/home/maarten/src/libreoffice/core/sc/source/ui/view/gridwin.cxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <scitems.hxx>
21
22#include <memory>
23#include <editeng/adjustitem.hxx>
24#include <sot/storage.hxx>
25#include <editeng/eeitem.hxx>
26#include <editeng/editview.hxx>
27#include <editeng/editstat.hxx>
28#include <editeng/flditem.hxx>
29#include <editeng/justifyitem.hxx>
30#include <editeng/unolingu.hxx>
31#include <editeng/langitem.hxx>
32#include <editeng/misspellrange.hxx>
33#include <editeng/editobj.hxx>
34#include <sfx2/dispatch.hxx>
35#include <sfx2/viewfrm.hxx>
36#include <sfx2/docfile.hxx>
37#include <sfx2/ipclient.hxx>
38#include <svl/stritem.hxx>
39#include <svl/sharedstringpool.hxx>
40#include <vcl/canvastools.hxx>
41#include <vcl/commandevent.hxx>
42#include <vcl/cursor.hxx>
43#include <vcl/inputctx.hxx>
44#include <vcl/settings.hxx>
45#include <sot/formats.hxx>
46#include <comphelper/classids.hxx>
47
48#include <svx/svdview.hxx>
49#include <editeng/outliner.hxx>
50#include <svx/svdocapt.hxx>
51#include <svx/svdpagv.hxx>
52
53#include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
54#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
55#include <com/sun/star/sheet/DataPilotTableHeaderData.hpp>
56#include <com/sun/star/sheet/MemberResultFlags.hpp>
57#include <com/sun/star/sheet/TableValidationVisibility.hpp>
58#include <com/sun/star/awt/KeyModifier.hpp>
59#include <com/sun/star/awt/MouseButton.hpp>
60#include <com/sun/star/script/vba/VBAEventId.hpp>
61#include <com/sun/star/script/vba/XVBAEventProcessor.hpp>
62#include <com/sun/star/text/textfield/Type.hpp>
63
64#include <gridwin.hxx>
65#include <tabvwsh.hxx>
66#include <docsh.hxx>
67#include <viewdata.hxx>
68#include <tabview.hxx>
69#include <select.hxx>
70#include <scmod.hxx>
71#include <document.hxx>
72#include <attrib.hxx>
73#include <dbdata.hxx>
74#include <stlpool.hxx>
75#include <printfun.hxx>
76#include <cbutton.hxx>
77#include <sc.hrc>
78#include <helpids.h>
79#include <globstr.hrc>
80#include <strings.hrc>
81#include <editutil.hxx>
82#include <scresid.hxx>
83#include <inputhdl.hxx>
84#include <uiitems.hxx>
85#include <formulacell.hxx>
86#include <patattr.hxx>
87#include <notemark.hxx>
88#include <rfindlst.hxx>
89#include <output.hxx>
90#include <docfunc.hxx>
91#include <dbdocfun.hxx>
92#include <dpobject.hxx>
93#include <transobj.hxx>
94#include <drwtrans.hxx>
95#include <seltrans.hxx>
96#include <sizedev.hxx>
97#include <AccessibilityHints.hxx>
98#include <dpsave.hxx>
99#include <viewuno.hxx>
100#include <compiler.hxx>
101#include <editable.hxx>
102#include <fillinfo.hxx>
103#include <filterentries.hxx>
104#include <drwlayer.hxx>
105#include <validat.hxx>
106#include <tabprotection.hxx>
107#include <postit.hxx>
108#include <dpcontrol.hxx>
109#include <checklistmenu.hxx>
110#include <clipparam.hxx>
111#include <overlayobject.hxx>
112#include <cellsuno.hxx>
113#include <drawview.hxx>
114#include <dragdata.hxx>
115#include <cliputil.hxx>
116#include <queryentry.hxx>
117#include <markdata.hxx>
118#include <externalrefmgr.hxx>
119#include <dociter.hxx>
120#include <hints.hxx>
121#include <spellcheckcontext.hxx>
122#include <uiobject.hxx>
123#include <undoblk.hxx>
124#include <datamapper.hxx>
125
126#include <svx/sdrpagewindow.hxx>
127#include <svx/sdr/overlay/overlaymanager.hxx>
128#include <vcl/svapp.hxx>
129#include <vcl/uitest/logger.hxx>
130#include <vcl/uitest/eventdescription.hxx>
131#include <svx/sdr/overlay/overlayselection.hxx>
132#include <comphelper/string.hxx>
133#include <comphelper/lok.hxx>
134#include <sfx2/lokhelper.hxx>
135
136#include <LibreOfficeKit/LibreOfficeKitEnums.h>
137
138#include <vector>
139#include <boost/property_tree/json_parser.hpp>
140
141#include <FilterListBox.hxx>
142#include <FilterFloatingWindow.hxx>
143
144using namespace css;
145using namespace css::uno;
146
147struct ScGridWindow::MouseEventState
148{
149 bool mbActivatePart;
150
151 MouseEventState() :
152 mbActivatePart(false)
153 {}
154};
155
156#define SC_FILTERLISTBOX_LINES12 12
157
158ScGridWindow::VisibleRange::VisibleRange(const ScDocument& rDoc)
159 : mnCol1(0)
160 , mnCol2(rDoc.MaxCol())
161 , mnRow1(0)
162 , mnRow2(rDoc.MaxRow())
163{
164}
165
166bool ScGridWindow::VisibleRange::isInside(SCCOL nCol, SCROW nRow) const
167{
168 return mnCol1 <= nCol && nCol <= mnCol2 && mnRow1 <= nRow && nRow <= mnRow2;
169}
170
171bool ScGridWindow::VisibleRange::set(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
172{
173 bool bChanged = mnCol1 != nCol1 || mnRow1 != nRow1 || mnCol2 != nCol2 || mnRow2 != nRow2;
174
175 mnCol1 = nCol1;
176 mnRow1 = nRow1;
177 mnCol2 = nCol2;
178 mnRow2 = nRow2;
179
180 return bChanged;
181}
182
183// ListBox in a FloatingWindow (pParent)
184ScFilterListBox::ScFilterListBox( vcl::Window* pParent, ScGridWindow* pGrid,
185 SCCOL nNewCol, SCROW nNewRow, ScFilterBoxMode eNewMode ) :
186 InterimItemWindow(pParent, "modules/scalc/ui/filterlist.ui", "FilterList"),
187 xTreeView(m_xBuilder->weld_tree_view("list")),
188 pGridWin( pGrid ),
189 nCol( nNewCol ),
190 nRow( nNewRow ),
191 bInit( true ),
192 bCancelled( false ),
193 nSel( 0 ),
194 eMode( eNewMode ),
195 nAsyncSelectHdl(nullptr)
196{
197 xTreeView->connect_row_activated(LINK(this, ScFilterListBox, SelectHdl)::tools::detail::makeLink( ::tools::detail::castTo<ScFilterListBox
*>(this), &ScFilterListBox::LinkStubSelectHdl)
);
198 xTreeView->connect_key_press(LINK(this, ScFilterListBox, KeyInputHdl)::tools::detail::makeLink( ::tools::detail::castTo<ScFilterListBox
*>(this), &ScFilterListBox::LinkStubKeyInputHdl)
);
199}
200
201ScFilterListBox::~ScFilterListBox()
202{
203 disposeOnce();
204}
205
206void ScFilterListBox::dispose()
207{
208 if (nAsyncSelectHdl)
209 {
210 Application::RemoveUserEvent(nAsyncSelectHdl);
211 nAsyncSelectHdl = nullptr;
212 }
213 pGridWin.clear();
214 xTreeView.reset();
215 InterimItemWindow::dispose();
216}
217
218void ScFilterListBox::EndInit()
219{
220 sal_Int32 nPos = xTreeView->get_selected_index();
221 if (nPos == -1)
222 nSel = 0;
223 else
224 nSel = nPos;
225
226 bInit = false;
227}
228
229IMPL_LINK(ScFilterListBox, KeyInputHdl, const KeyEvent&, rKeyEvent, bool)bool ScFilterListBox::LinkStubKeyInputHdl(void * instance, const
KeyEvent& data) { return static_cast<ScFilterListBox *
>(instance)->KeyInputHdl(data); } bool ScFilterListBox::
KeyInputHdl(const KeyEvent& rKeyEvent)
230{
231 bool bDone = false;
232
233 vcl::KeyCode aCode = rKeyEvent.GetKeyCode();
234 // esc with no modifiers
235 if (!aCode.GetModifier() && aCode.GetCode() == KEY_ESCAPE)
236 {
237 pGridWin->ClickExtern(); // clears the listbox
238 bDone = true;
239 }
240
241 // nowhere to tab to
242 if (aCode.GetCode() == KEY_TAB)
243 bDone = true;
244
245 return bDone;
246}
247
248IMPL_LINK_NOARG(ScFilterListBox, SelectHdl, weld::TreeView&, bool)bool ScFilterListBox::LinkStubSelectHdl(void * instance, weld
::TreeView& data) { return static_cast<ScFilterListBox
*>(instance)->SelectHdl(data); } bool ScFilterListBox::
SelectHdl(__attribute__ ((unused)) weld::TreeView&)
249{
250 if (!bInit && !bCancelled && !nAsyncSelectHdl)
251 {
252 int nPos = xTreeView->get_selected_index();
253 if (nPos != -1)
254 {
255 nSel = nPos;
256 // #i81298# launch async so the box isn't deleted from modifications within FilterSelect
257 nAsyncSelectHdl = Application::PostUserEvent(LINK(this, ScFilterListBox, AsyncSelectHdl)::tools::detail::makeLink( ::tools::detail::castTo<ScFilterListBox
*>(this), &ScFilterListBox::LinkStubAsyncSelectHdl)
);
258 }
259 }
260 return true;
261}
262
263IMPL_LINK_NOARG(ScFilterListBox, AsyncSelectHdl, void*, void)void ScFilterListBox::LinkStubAsyncSelectHdl(void * instance,
void* data) { return static_cast<ScFilterListBox *>(instance
)->AsyncSelectHdl(data); } void ScFilterListBox::AsyncSelectHdl
(__attribute__ ((unused)) void*)
264{
265 nAsyncSelectHdl = nullptr;
266
267 //tdf#133971 hold self-ref until we return
268 VclPtr<ScFilterListBox> xThis(this);
269 pGridWin->FilterSelect(nSel);
270 if (!pGridWin)
271 {
272 // tdf#133855 we got disposed by FilterSelect
273 return;
274 }
275 pGridWin->ClickExtern();
276}
277
278ScFilterFloatingWindow::ScFilterFloatingWindow(vcl::Window* pParent)
279 : FloatingWindow( pParent, WB_BORDER | WB_SYSTEMWINDOW ) // make it a system floater
280 , m_bGridHadMouseCaptured(pParent->IsMouseCaptured())
281{
282}
283
284ScFilterFloatingWindow::~ScFilterFloatingWindow()
285{
286 disposeOnce();
287}
288
289void ScFilterFloatingWindow::dispose()
290{
291 EndPopupMode();
292 FloatingWindow::dispose();
293}
294
295static bool lcl_IsEditableMatrix( ScDocument& rDoc, const ScRange& rRange )
296{
297 // If it is an editable range and if there is a Matrix cell at the bottom right with an
298 // origin top left then the range will be set to contain the exact matrix.
299 //! Extract the MatrixEdges functions directly from the column ???
300 if ( !rDoc.IsBlockEditable( rRange.aStart.Tab(), rRange.aStart.Col(),rRange.aStart.Row(),
301 rRange.aEnd.Col(),rRange.aEnd.Row() ) )
302 return false;
303
304 ScRefCellValue aCell(rDoc, rRange.aEnd);
305 ScAddress aPos;
306 return (aCell.meType == CELLTYPE_FORMULA && aCell.mpFormula->GetMatrixOrigin(rDoc, aPos) && aPos == rRange.aStart);
307}
308
309static void lcl_UnLockComment( ScDrawView* pView, const Point& rPos, const ScViewData& rViewData )
310{
311 if (!pView)
312 return;
313
314 ScDocument& rDoc = rViewData.GetDocument();
315 ScAddress aCellPos( rViewData.GetCurX(), rViewData.GetCurY(), rViewData.GetTabNo() );
316 ScPostIt* pNote = rDoc.GetNote( aCellPos );
317 SdrObject* pObj = pNote ? pNote->GetCaption() : nullptr;
318 if( pObj && pObj->GetLogicRect().IsInside( rPos ) && ScDrawLayer::IsNoteCaption( pObj ) )
319 {
320 const ScProtectionAttr* pProtAttr = rDoc.GetAttr( aCellPos, ATTR_PROTECTION );
321 bool bProtectAttr = pProtAttr->GetProtection() || pProtAttr->GetHideCell() ;
322 bool bProtectDoc = rDoc.IsTabProtected( aCellPos.Tab() ) || rViewData.GetSfxDocShell()->IsReadOnly() ;
323 // unlock internal layer (if not protected), will be relocked in ScDrawView::MarkListHasChanged()
324 pView->LockInternalLayer( bProtectDoc && bProtectAttr );
325 }
326}
327
328static bool lcl_GetHyperlinkCell(
329 ScDocument& rDoc, SCCOL& rPosX, SCROW nPosY, SCTAB nTab, ScRefCellValue& rCell, OUString& rURL )
330{
331 bool bFound = false;
332 do
333 {
334 ScAddress aPos(rPosX, nPosY, nTab);
335 rCell.assign(rDoc, aPos);
336 if (rCell.isEmpty())
337 {
338 if ( rPosX <= 0 )
339 return false; // everything empty to the links
340 else
341 --rPosX; // continue search
342 }
343 else
344 {
345 const ScPatternAttr* pPattern = rDoc.GetPattern(aPos);
346 if ( !pPattern->GetItem(ATTR_HYPERLINK).GetValue().isEmpty() )
347 {
348 rURL = pPattern->GetItem(ATTR_HYPERLINK).GetValue();
349 bFound = true;
350 }
351 else if (rCell.meType == CELLTYPE_EDIT)
352 bFound = true;
353 else if (rCell.meType == CELLTYPE_FORMULA && rCell.mpFormula->IsHyperLinkCell())
354 bFound = true;
355 else
356 return false; // other cell
357 }
358 }
359 while ( !bFound );
360
361 return bFound;
362}
363
364// WB_DIALOGCONTROL needed for UNO-Controls
365ScGridWindow::ScGridWindow( vcl::Window* pParent, ScViewData& rData, ScSplitPos eWhichPos )
366: Window( pParent, WB_CLIPCHILDREN | WB_DIALOGCONTROL ),
367 DropTargetHelper( this ),
368 DragSourceHelper( this ),
369 mpOOCursors(),
370 mpOOSelection(),
371 mpOOSelectionBorder(),
372 mpOOAutoFill(),
373 mpOODragRect(),
374 mpOOHeader(),
375 mpOOShrink(),
376 maVisibleRange(rData.GetDocument()),
377 mrViewData( rData ),
378 eWhich( eWhichPos ),
379 mpNoteMarker(),
380 mpFilterBox(),
381 mpFilterFloat(),
382 mpAutoFilterPopup(),
383 mpDPFieldPopup(),
384 mpFilterButton(),
385 nCursorHideCount( 0 ),
386 nButtonDown( 0 ),
387 nMouseStatus( SC_GM_NONE0 ),
388 nNestedButtonState( ScNestedButtonState::NONE ),
389 nDPField( 0 ),
390 pDragDPObj( nullptr ),
391 nRFIndex( 0 ),
392 nRFAddX( 0 ),
393 nRFAddY( 0 ),
394 nPagebreakMouse( SC_PD_NONE0 ),
395 nPagebreakBreak( 0 ),
396 nPagebreakPrev( 0 ),
397 nPageScript( SvtScriptType::NONE ),
398 nDragStartX( -1 ),
399 nDragStartY( -1 ),
400 nDragEndX( -1 ),
401 nDragEndY( -1 ),
402 meDragInsertMode( INS_NONE ),
403 aComboButton( this ),
404 aCurMousePos( 0,0 ),
405 nPaintCount( 0 ),
406 aRFSelectedCorned( NONE ),
407 bEEMouse( false ),
408 bDPMouse( false ),
409 bRFMouse( false ),
410 bRFSize( false ),
411 bPagebreakDrawn( false ),
412 bDragRect( false ),
413 bIsInPaint( false ),
414 bNeedsRepaint( false ),
415 bAutoMarkVisible( false ),
416 bListValButton( false )
417{
418 set_id("grid_window");
419 switch(eWhich)
420 {
421 case SC_SPLIT_TOPLEFT:
422 eHWhich = SC_SPLIT_LEFT;
423 eVWhich = SC_SPLIT_TOP;
424 break;
425 case SC_SPLIT_TOPRIGHT:
426 eHWhich = SC_SPLIT_RIGHT;
427 eVWhich = SC_SPLIT_TOP;
428 break;
429 case SC_SPLIT_BOTTOMLEFT:
430 eHWhich = SC_SPLIT_LEFT;
431 eVWhich = SC_SPLIT_BOTTOM;
432 break;
433 case SC_SPLIT_BOTTOMRIGHT:
434 eHWhich = SC_SPLIT_RIGHT;
435 eVWhich = SC_SPLIT_BOTTOM;
436 break;
437 default:
438 OSL_FAIL("GridWindow: wrong position")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/ui/view/gridwin.cxx"
":" "438" ": "), "%s", "GridWindow: wrong position"); } } while
(false)
;
439 }
440
441 SetBackground();
442
443 SetMapMode(mrViewData.GetLogicMode(eWhich));
444 EnableChildTransparentMode();
445 SetDialogControlFlags( DialogControlFlags::Return | DialogControlFlags::WantFocus );
446
447 SetHelpId( HID_SC_WIN_GRIDWIN"SC_HID_SC_WIN_GRIDWIN" );
448
449 SetDigitLanguage( SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->GetOptDigitLanguage() );
450 EnableRTL( false );
451}
452
453ScGridWindow::~ScGridWindow()
454{
455 disposeOnce();
456}
457
458void ScGridWindow::dispose()
459{
460 ImpDestroyOverlayObjects();
461
462 mpFilterBox.disposeAndClear();
463 mpFilterFloat.disposeAndClear();
464 mpNoteMarker.reset();
465 mpAutoFilterPopup.disposeAndClear();
466 mpDPFieldPopup.disposeAndClear();
467 aComboButton.SetOutputDevice(nullptr);
468
469 vcl::Window::dispose();
470}
471
472void ScGridWindow::ClickExtern()
473{
474 do
475 {
476 // #i84277# when initializing the filter box, a Basic error can deactivate the view
477 if (mpFilterBox && mpFilterBox->IsInInit())
478 break;
479 mpFilterBox.disposeAndClear();
480 mpFilterFloat.disposeAndClear();
2
Calling 'VclPtr::disposeAndClear'
481 }
482 while (false);
483
484 if (mpDPFieldPopup)
485 {
486 mpDPFieldPopup->get_widget().close(false);
487 mpDPFieldPopup.disposeAndClear();
488 }
489}
490
491IMPL_LINK_NOARG(ScGridWindow, PopupModeEndHdl, FloatingWindow*, void)void ScGridWindow::LinkStubPopupModeEndHdl(void * instance, FloatingWindow
* data) { return static_cast<ScGridWindow *>(instance)->
PopupModeEndHdl(data); } void ScGridWindow::PopupModeEndHdl(__attribute__
((unused)) FloatingWindow*)
492{
493 if (mpFilterBox)
494 mpFilterBox->SetCancelled(); // cancel select
495 // restore the mouse capture state of the GridWindow to
496 // what it was at initial popup time
497 if (mpFilterFloat->MouseWasCaptured())
498 CaptureMouse();
499 GrabFocus();
500}
501
502IMPL_LINK( ScGridWindow, PopupSpellingHdl, SpellCallbackInfo&, rInfo, void )void ScGridWindow::LinkStubPopupSpellingHdl(void * instance, SpellCallbackInfo
& data) { return static_cast<ScGridWindow *>(instance
)->PopupSpellingHdl(data); } void ScGridWindow::PopupSpellingHdl
(SpellCallbackInfo& rInfo)
503{
504 if( rInfo.nCommand == SpellCallbackCommand::STARTSPELLDLG )
505 mrViewData.GetDispatcher().Execute( SID_SPELL_DIALOG( 10000 + 243 ), SfxCallMode::ASYNCHRON );
506 else if (rInfo.nCommand == SpellCallbackCommand::AUTOCORRECT_OPTIONS)
507 mrViewData.GetDispatcher().Execute( SID_AUTO_CORRECT_DLG(10000 + 424), SfxCallMode::ASYNCHRON );
508}
509
510namespace {
511
512struct AutoFilterData : public ScCheckListMenuControl::ExtendedData
513{
514 ScAddress maPos;
515 ScDBData* mpData;
516};
517
518class AutoFilterAction : public ScCheckListMenuControl::Action
519{
520 VclPtr<ScGridWindow> mpWindow;
521 ScGridWindow::AutoFilterMode meMode;
522public:
523 AutoFilterAction(ScGridWindow* p, ScGridWindow::AutoFilterMode eMode) :
524 mpWindow(p), meMode(eMode) {}
525 virtual void execute() override
526 {
527 mpWindow->UpdateAutoFilterFromMenu(meMode);
528 }
529};
530
531class AutoFilterPopupEndAction : public ScCheckListMenuControl::Action
532{
533 VclPtr<ScGridWindow> mpWindow;
534 ScAddress maPos;
535public:
536 AutoFilterPopupEndAction(ScGridWindow* p, const ScAddress& rPos) :
537 mpWindow(p), maPos(rPos) {}
538 virtual void execute() override
539 {
540 mpWindow->RefreshAutoFilterButton(maPos);
541 }
542};
543
544class AddItemToEntry
545{
546 ScQueryEntry::QueryItemsType& mrItems;
547 svl::SharedStringPool& mrPool;
548public:
549 AddItemToEntry(ScQueryEntry::QueryItemsType& rItems, svl::SharedStringPool& rPool) :
550 mrItems(rItems), mrPool(rPool) {}
551 void operator() (const ScCheckListMenuControl::ResultEntry& rEntry)
552 {
553 if (rEntry.bValid)
554 {
555 ScQueryEntry::Item aNew;
556 aNew.maString = mrPool.intern(rEntry.aName);
557 aNew.meType = rEntry.bDate ? ScQueryEntry::ByDate : ScQueryEntry::ByString;
558 aNew.mfVal = 0.0;
559 mrItems.push_back(aNew);
560 }
561 }
562};
563
564class AddSelectedItemString
565{
566 std::unordered_set<OUString>& mrSet;
567public:
568 explicit AddSelectedItemString(std::unordered_set<OUString>& r) :
569 mrSet(r) {}
570
571 void operator() (const ScQueryEntry::Item& rItem)
572 {
573 mrSet.insert(rItem.maString.getString());
574 }
575};
576
577void collectUIInformation(const OUString& aRow, const OUString& aCol , const OUString& aevent)
578{
579 EventDescription aDescription;
580 aDescription.aAction = "LAUNCH";
581 aDescription.aID = "grid_window";
582 aDescription.aParameters = {{aevent, ""},
583 {"ROW", aRow}, {"COL", aCol}};
584 aDescription.aParent = "MainWindow";
585 aDescription.aKeyWord = "ScGridWinUIObject";
586
587 UITestLogger::getInstance().logEvent(aDescription);
588}
589
590}
591
592void ScGridWindow::LaunchAutoFilterMenu(SCCOL nCol, SCROW nRow)
593{
594 SCTAB nTab = mrViewData.GetTabNo();
595 ScDocument& rDoc = mrViewData.GetDocument();
596 bool bLOKActive = comphelper::LibreOfficeKit::isActive();
597
598 mpAutoFilterPopup.disposeAndClear();
599
600 // Estimate the width (in pixels) of the longest text in the list
601 ScFilterEntries aFilterEntries;
602 rDoc.GetFilterEntries(nCol, nRow, nTab, aFilterEntries);
603
604 int nColWidth = ScViewData::ToPixel(rDoc.GetColWidth(nCol, nTab), mrViewData.GetPPTX());
605 mpAutoFilterPopup.reset(VclPtr<ScCheckListMenuWindow>::Create(this, &rDoc, false,
606 aFilterEntries.mbHasDates, nColWidth));
607 ScCheckListMenuControl& rControl = mpAutoFilterPopup->get_widget();
608
609 int nMaxTextWidth = 0;
610 if (aFilterEntries.size() <= 10)
611 {
612 // do pixel calculation for all elements of short lists
613 for (const auto& rEntry : aFilterEntries)
614 {
615 const OUString& aText = rEntry.GetString();
616 nMaxTextWidth = std::max<int>(nMaxTextWidth, rControl.GetTextWidth(aText) + aText.getLength() * 2);
617 }
618 }
619 else
620 {
621 // find the longest string, probably it will be the longest rendered text, too
622 // (performance optimization for long lists)
623 auto itMax = aFilterEntries.begin();
624 for (auto it = itMax; it != aFilterEntries.end(); ++it)
625 {
626 int nTextWidth = it->GetString().getLength();
627 if (nMaxTextWidth < nTextWidth)
628 {
629 nMaxTextWidth = nTextWidth;
630 itMax = it;
631 }
632 }
633 nMaxTextWidth = rControl.GetTextWidth(itMax->GetString()) + nMaxTextWidth * 2;
634 }
635
636 // window should be at least as wide as the column, or the longest text + checkbox, scrollbar ... (it is estimated with 70 pixel now)
637 // window should be maximum 1024 pixel wide.
638 int nWindowWidth = std::min<int>(1024, nMaxTextWidth + 70);
639 nWindowWidth = rControl.IncreaseWindowWidthToFitText(nWindowWidth);
640 nMaxTextWidth = std::max<int>(nMaxTextWidth, nWindowWidth - 70);
641
642 if (bLOKActive)
643 mpAutoFilterPopup->SetLOKNotifier(SfxViewShell::Current());
644 rControl.setOKAction(new AutoFilterAction(this, AutoFilterMode::Normal));
645 rControl.setPopupEndAction(
646 new AutoFilterPopupEndAction(this, ScAddress(nCol, nRow, nTab)));
647 std::unique_ptr<AutoFilterData> pData(new AutoFilterData);
648 pData->maPos = ScAddress(nCol, nRow, nTab);
649
650 Point aPos = mrViewData.GetScrPos(nCol, nRow, eWhich);
651 long nSizeX = 0;
652 long nSizeY = 0;
653 mrViewData.GetMergeSizePixel(nCol, nRow, nSizeX, nSizeY);
654 if (bLOKActive)
655 {
656 // Reverse the zoom factor from aPos and nSize[X|Y]
657 // before letting the autofilter window convert the to twips
658 // with no zoom information.
659 double fZoomX(mrViewData.GetZoomX());
660 double fZoomY(mrViewData.GetZoomY());
661 aPos.setX(aPos.getX() / fZoomX);
662 aPos.setY(aPos.getY() / fZoomY);
663 nSizeX = nSizeX / fZoomX;
664 nSizeY = nSizeY / fZoomY;
665 }
666 tools::Rectangle aCellRect(OutputToScreenPixel(aPos), Size(nSizeX, nSizeY));
667
668 ScDBData* pDBData = rDoc.GetDBAtCursor(nCol, nRow, nTab, ScDBDataPortion::AREA);
669 if (!pDBData)
670 return;
671
672 pData->mpData = pDBData;
673 rControl.setExtendedData(std::move(pData));
674
675 ScQueryParam aParam;
676 pDBData->GetQueryParam(aParam);
677 std::vector<ScQueryEntry*> aEntries = aParam.FindAllEntriesByField(nCol);
678 std::unordered_set<OUString> aSelected;
679 for (ScQueryEntry* pEntry : aEntries)
680 {
681 if (pEntry && pEntry->bDoQuery && pEntry->eOp == SC_EQUAL)
682 {
683 ScQueryEntry::QueryItemsType& rItems = pEntry->GetQueryItems();
684 std::for_each(rItems.begin(), rItems.end(), AddSelectedItemString(aSelected));
685 }
686 }
687
688 // Populate the check box list.
689 rControl.setMemberSize(aFilterEntries.size());
690 for (const auto& rEntry : aFilterEntries)
691 {
692 const OUString& aVal = rEntry.GetString();
693 bool bSelected = true;
694 if (!aSelected.empty())
695 bSelected = aSelected.count(aVal) > 0;
696 if ( rEntry.IsDate() )
697 rControl.addDateMember( aVal, rEntry.GetValue(), bSelected );
698 else
699 rControl.addMember(aVal, bSelected);
700 }
701
702 // Populate the menu.
703 rControl.addMenuItem(
704 ScResId(STR_MENU_SORT_ASCreinterpret_cast<char const *>("STR_MENU_SORT_ASC" "\004"
u8"Sort Ascending")
),
705 new AutoFilterAction(this, AutoFilterMode::SortAscending));
706 rControl.addMenuItem(
707 ScResId(STR_MENU_SORT_DESCreinterpret_cast<char const *>("STR_MENU_SORT_DESC" "\004"
u8"Sort Descending")
),
708 new AutoFilterAction(this, AutoFilterMode::SortDescending));
709 rControl.addSeparator();
710 rControl.addMenuItem(
711 ScResId(SCSTR_TOP10FILTERreinterpret_cast<char const *>("SCSTR_TOP10FILTER" "\004"
u8"Top 10")
), new AutoFilterAction(this, AutoFilterMode::Top10));
712 rControl.addMenuItem(
713 ScResId(SCSTR_FILTER_EMPTYreinterpret_cast<char const *>("SCSTR_FILTER_EMPTY" "\004"
u8"Empty")
), new AutoFilterAction(this, AutoFilterMode::Empty));
714 rControl.addMenuItem(
715 ScResId(SCSTR_FILTER_NOTEMPTYreinterpret_cast<char const *>("SCSTR_FILTER_NOTEMPTY" "\004"
u8"Not Empty")
), new AutoFilterAction(this, AutoFilterMode::NonEmpty));
716 rControl.addSeparator();
717 rControl.addMenuItem(
718 ScResId(SCSTR_STDFILTERreinterpret_cast<char const *>("SCSTR_STDFILTER" "\004"
u8"Standard Filter...")
), new AutoFilterAction(this, AutoFilterMode::Custom));
719
720 rControl.initMembers(nMaxTextWidth + 20); // 20 pixel estimated for the checkbox
721
722 ScCheckListMenuControl::Config aConfig;
723 aConfig.mbAllowEmptySet = false;
724 aConfig.mbRTL = mrViewData.GetDocument().IsLayoutRTL(mrViewData.GetTabNo());
725 rControl.setConfig(aConfig);
726 if (IsMouseCaptured())
727 ReleaseMouse();
728 rControl.launch(aCellRect);
729
730 // remember filter rules before modification
731 rControl.getResult(aSaveAutoFilterResult);
732
733 collectUIInformation(OUString::number(nRow), OUString::number(nCol),"AUTOFILTER");
734}
735
736void ScGridWindow::RefreshAutoFilterButton(const ScAddress& rPos)
737{
738 if (mpFilterButton)
739 {
740 bool bFilterActive = IsAutoFilterActive(rPos.Col(), rPos.Row(), rPos.Tab());
741 mpFilterButton->setHasHiddenMember(bFilterActive);
742 mpFilterButton->setPopupPressed(false);
743 mpFilterButton->draw();
744 }
745}
746
747void ScGridWindow::UpdateAutoFilterFromMenu(AutoFilterMode eMode)
748{
749 ScCheckListMenuControl& rControl = mpAutoFilterPopup->get_widget();
750
751 const AutoFilterData* pData =
752 static_cast<const AutoFilterData*>(rControl.getExtendedData());
753
754 if (!pData)
755 return;
756
757 const ScAddress& rPos = pData->maPos;
758 ScDBData* pDBData = pData->mpData;
759 if (!pDBData)
760 return;
761
762 ScDocument& rDoc = mrViewData.GetDocument();
763 svl::SharedStringPool& rPool = rDoc.GetSharedStringPool();
764 switch (eMode)
765 {
766 case AutoFilterMode::SortAscending:
767 case AutoFilterMode::SortDescending:
768 {
769 SCCOL nCol = rPos.Col();
770 ScSortParam aSortParam;
771 pDBData->GetSortParam(aSortParam);
772 if (nCol < aSortParam.nCol1 || nCol > aSortParam.nCol2)
773 // out of bound
774 return;
775
776 bool bHasHeader = pDBData->HasHeader();
777
778 aSortParam.bHasHeader = bHasHeader;
779 aSortParam.bByRow = true;
780 aSortParam.bCaseSens = false;
781 aSortParam.bNaturalSort = false;
782 aSortParam.bIncludeComments = false;
783 aSortParam.bIncludeGraphicObjects = true;
784 aSortParam.bIncludePattern = true;
785 aSortParam.bInplace = true;
786 aSortParam.maKeyState[0].bDoSort = true;
787 aSortParam.maKeyState[0].nField = nCol;
788 aSortParam.maKeyState[0].bAscending = (eMode == AutoFilterMode::SortAscending);
789
790 for (size_t i = 1; i < aSortParam.GetSortKeyCount(); ++i)
791 aSortParam.maKeyState[i].bDoSort = false;
792
793 mrViewData.GetViewShell()->UISort(aSortParam);
794 return;
795 }
796 default:
797 ;
798 }
799
800 if (eMode == AutoFilterMode::Custom)
801 {
802 ScRange aRange;
803 pDBData->GetArea(aRange);
804 mrViewData.GetView()->MarkRange(aRange);
805 mrViewData.GetView()->SetCursor(rPos.Col(), rPos.Row());
806 mrViewData.GetDispatcher().Execute(SID_FILTER((((((((((((((26000 + 200) + 20)) + 20)) + 20)) + 25)) + 22))
+ 20)) + 3)
, SfxCallMode::SLOT|SfxCallMode::RECORD);
807 return;
808 }
809
810 ScQueryParam aParam;
811 pDBData->GetQueryParam(aParam);
812
813 if (eMode == AutoFilterMode::Normal)
814 {
815 // Do not recreate autofilter rules if there are no changes from the user
816 ScCheckListMenuControl::ResultType aResult;
817 rControl.getResult(aResult);
818
819 if (aResult == aSaveAutoFilterResult)
820 {
821 SAL_INFO("sc.ui", "Apply autofilter to data when entries are the same")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "sc.ui")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Apply autofilter to data when entries are the same"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sc.ui"
), ("/home/maarten/src/libreoffice/core/sc/source/ui/view/gridwin.cxx"
":" "821" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Apply autofilter to data when entries are the same"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Apply autofilter to data when entries are the same"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sc.ui"
), ("/home/maarten/src/libreoffice/core/sc/source/ui/view/gridwin.cxx"
":" "821" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Apply autofilter to data when entries are the same"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sc.ui"
), ("/home/maarten/src/libreoffice/core/sc/source/ui/view/gridwin.cxx"
":" "821" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Apply autofilter to data when entries are the same"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Apply autofilter to data when entries are the same"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sc.ui"
), ("/home/maarten/src/libreoffice/core/sc/source/ui/view/gridwin.cxx"
":" "821" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
822
823 if (!rControl.isAllSelected())
824 {
825 // Apply autofilter to data
826 ScQueryEntry* pEntry = aParam.FindEntryByField(rPos.Col(), true);
827 pEntry->bDoQuery = true;
828 pEntry->nField = rPos.Col();
829 pEntry->eConnect = SC_AND;
830 pEntry->eOp = SC_EQUAL;
831 mrViewData.GetView()->Query(aParam, nullptr, true);
832 }
833
834 return;
835 }
836 }
837
838 // Remove old entries in auto-filter rules
839 aParam.RemoveAllEntriesByField(rPos.Col());
840
841 if( !(eMode == AutoFilterMode::Normal && rControl.isAllSelected() ) )
842 {
843 // Try to use the existing entry for the column (if one exists).
844 ScQueryEntry* pEntry = aParam.FindEntryByField(rPos.Col(), true);
845
846 if (!pEntry)
847 // Something went terribly wrong!
848 return;
849
850 if (ScTabViewShell::isAnyEditViewInRange(mrViewData.GetViewShell(), /*bColumns*/ false, aParam.nRow1, aParam.nRow2))
851 return;
852
853 pEntry->bDoQuery = true;
854 pEntry->nField = rPos.Col();
855 pEntry->eConnect = SC_AND;
856
857 switch (eMode)
858 {
859 case AutoFilterMode::Normal:
860 {
861 pEntry->eOp = SC_EQUAL;
862
863 ScCheckListMenuControl::ResultType aResult;
864 rControl.getResult(aResult);
865
866 ScQueryEntry::QueryItemsType& rItems = pEntry->GetQueryItems();
867 rItems.clear();
868 std::for_each(aResult.begin(), aResult.end(), AddItemToEntry(rItems, rPool));
869 }
870 break;
871 case AutoFilterMode::Top10:
872 pEntry->eOp = SC_TOPVAL;
873 pEntry->GetQueryItem().meType = ScQueryEntry::ByString;
874 pEntry->GetQueryItem().maString = rPool.intern("10");
875 break;
876 case AutoFilterMode::Empty:
877 pEntry->SetQueryByEmpty();
878 break;
879 case AutoFilterMode::NonEmpty:
880 pEntry->SetQueryByNonEmpty();
881 break;
882 default:
883 // We don't know how to handle this!
884 return;
885 }
886 }
887
888 mrViewData.GetView()->Query(aParam, nullptr, true);
889 pDBData->SetQueryParam(aParam);
890}
891
892namespace {
893
894void getCellGeometry(Point& rScrPos, Size& rScrSize, const ScViewData& rViewData, SCCOL nCol, SCROW nRow, ScSplitPos eWhich)
895{
896 // Get the screen position of the cell.
897 rScrPos = rViewData.GetScrPos(nCol, nRow, eWhich);
898
899 // Get the screen size of the cell.
900 long nSizeX, nSizeY;
901 rViewData.GetMergeSizePixel(nCol, nRow, nSizeX, nSizeY);
902 rScrSize = Size(nSizeX-1, nSizeY-1);
903}
904
905}
906
907void ScGridWindow::LaunchPageFieldMenu( SCCOL nCol, SCROW nRow )
908{
909 if (nCol == 0)
910 // We assume that the page field button is located in cell to the immediate left.
911 return;
912
913 SCTAB nTab = mrViewData.GetTabNo();
914 ScDPObject* pDPObj = mrViewData.GetDocument().GetDPAtCursor(nCol, nRow, nTab);
915 if (!pDPObj)
916 return;
917
918 Point aScrPos;
919 Size aScrSize;
920 getCellGeometry(aScrPos, aScrSize, mrViewData, nCol, nRow, eWhich);
921 DPLaunchFieldPopupMenu(OutputToScreenPixel(aScrPos), aScrSize, ScAddress(nCol-1, nRow, nTab), pDPObj);
922}
923
924void ScGridWindow::LaunchDPFieldMenu( SCCOL nCol, SCROW nRow )
925{
926 SCTAB nTab = mrViewData.GetTabNo();
927 ScDPObject* pDPObj = mrViewData.GetDocument().GetDPAtCursor(nCol, nRow, nTab);
928 if (!pDPObj)
929 return;
930
931 Point aScrPos;
932 Size aScrSize;
933 getCellGeometry(aScrPos, aScrSize, mrViewData, nCol, nRow, eWhich);
934 DPLaunchFieldPopupMenu(OutputToScreenPixel(aScrPos), aScrSize, ScAddress(nCol, nRow, nTab), pDPObj);
935}
936
937void ScGridWindow::ShowFilterMenu(const tools::Rectangle& rCellRect, bool bLayoutRTL)
938{
939 auto nSizeX = rCellRect.GetWidth();
940
941 // minimum width in pixel
942 if (comphelper::LibreOfficeKit::isActive())
943 {
944 const long nMinLOKWinWidth = static_cast<long>(1.3 * STD_COL_WIDTH1280 / TWIPS_PER_PIXEL((20.0 * 72.0) / 96.0));
945 if (nSizeX < nMinLOKWinWidth)
946 nSizeX = nMinLOKWinWidth;
947 }
948
949 weld::TreeView& rFilterBox = mpFilterBox->get_widget();
950 int nEntryCount = rFilterBox.n_children();
951 if (nEntryCount > SC_FILTERLISTBOX_LINES12)
952 nEntryCount = SC_FILTERLISTBOX_LINES12;
953 auto nHeight = rFilterBox.get_height_rows(nEntryCount);
954 rFilterBox.set_size_request(-1, nHeight);
955 Size aSize(rFilterBox.get_preferred_size());
956 if (aSize.Width() < nSizeX)
957 aSize.setWidth(nSizeX);
958 if (aSize.Width() > 300)
959 aSize.setWidth(300); // do not over do it (Pixel)
960
961 aSize.AdjustWidth(4); // add a little margin
962 nSizeX += 4;
963 aSize.AdjustHeight(4);
964
965 tools::Rectangle aCellRect(rCellRect);
966 aCellRect.AdjustLeft(-2); // offset the little margin above
967
968 if (!bLayoutRTL && aSize.Width() > nSizeX)
969 {
970 // move popup position
971 long nDiff = aSize.Width() - nSizeX;
972 long nNewX = aCellRect.Left() - nDiff;
973 if ( nNewX < 0 )
974 nNewX = 0;
975 aCellRect.SetLeft( nNewX );
976 }
977
978 mpFilterBox->SetSizePixel(aSize);
979 mpFilterFloat->SetOutputSizePixel(aSize);
980
981 if (IsMouseCaptured())
982 ReleaseMouse();
983 mpFilterFloat->StartPopupMode(aCellRect, FloatWinPopupFlags::Down|FloatWinPopupFlags::GrabFocus);
984}
985
986void ScGridWindow::DoScenarioMenu( const ScRange& rScenRange )
987{
988 bool bMenuAtTop = true;
989
990 ScDocument& rDoc = mrViewData.GetDocument();
991 mpFilterBox.disposeAndClear();
992 mpFilterFloat.disposeAndClear();
993
994 SCCOL nCol = rScenRange.aEnd.Col(); // Cell is below the Buttons
995 SCROW nRow = rScenRange.aStart.Row();
996 if (nRow == 0)
997 {
998 nRow = rScenRange.aEnd.Row() + 1; // Range at very the top -> Button below
999 if (nRow>rDoc.MaxRow()) nRow = rDoc.MaxRow();
1000 bMenuAtTop = false;
1001 }
1002
1003 SCTAB nTab = mrViewData.GetTabNo();
1004 bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
1005
1006 long nSizeX = 0;
1007 long nSizeY = 0;
1008 mrViewData.GetMergeSizePixel( nCol, nRow, nSizeX, nSizeY );
1009 // The button height should not use the merged cell height, should still use single row height
1010 nSizeY = ScViewData::ToPixel(rDoc.GetRowHeight(nRow, nTab), mrViewData.GetPPTY());
1011 Point aPos = mrViewData.GetScrPos( nCol, nRow, eWhich );
1012 if ( bLayoutRTL )
1013 aPos.AdjustX( -nSizeX );
1014 tools::Rectangle aCellRect( OutputToScreenPixel(aPos), Size(nSizeX,nSizeY) );
1015 aCellRect.AdjustTop( -nSizeY );
1016 aCellRect.AdjustBottom( -(nSizeY - 1) );
1017 if (!bMenuAtTop)
1018 {
1019 Size aButSize = mrViewData.GetScenButSize();
1020 aCellRect.AdjustBottom(aButSize.Height());
1021 }
1022
1023 // Place the ListBox directly below the black line of the cell grid
1024 // (It looks odd if the line gets hidden...)
1025
1026 mpFilterFloat.reset(VclPtr<ScFilterFloatingWindow>::Create(this));
1027 mpFilterFloat->SetPopupModeEndHdl( LINK( this, ScGridWindow, PopupModeEndHdl )::tools::detail::makeLink( ::tools::detail::castTo<ScGridWindow
*>(this), &ScGridWindow::LinkStubPopupModeEndHdl)
);
1028 mpFilterBox.reset(VclPtr<ScFilterListBox>::Create(mpFilterFloat.get(), this, nCol, nRow, ScFilterBoxMode::Scenario));
1029 weld::TreeView& rFilterBox = mpFilterBox->get_widget();
1030 rFilterBox.set_direction(bLayoutRTL); // Fix for bug fdo#44925 use sheet direction for widget RTL/LTR
1031
1032 mpFilterBox->Show(); // Show has to be before SetUpdateMode !!!
1033 // SetOutputSizePixel/StartPopupMode first below, when the size is set
1034
1035 // Listbox fill
1036 rFilterBox.freeze();
1037 OUString aCurrent;
1038 OUString aTabName;
1039 SCTAB nTabCount = rDoc.GetTableCount();
1040 SCTAB nEntryCount = 0;
1041 for (SCTAB i=nTab+1; i<nTabCount && rDoc.IsScenario(i); i++)
1042 {
1043 if (rDoc.HasScenarioRange( i, rScenRange ))
1044 if (rDoc.GetName( i, aTabName ))
1045 {
1046 rFilterBox.append_text(aTabName);
1047 if (rDoc.IsActiveScenario(i))
1048 aCurrent = aTabName;
1049 ++nEntryCount;
1050 }
1051 }
1052 rFilterBox.thaw();
1053
1054 ShowFilterMenu(aCellRect, bLayoutRTL);
1055
1056 rFilterBox.grab_focus();
1057
1058 sal_Int32 nPos = -1;
1059 if (!aCurrent.isEmpty())
1060 {
1061 nPos = rFilterBox.find_text(aCurrent);
1062 }
1063 if (nPos == -1 && rFilterBox.n_children() > 0 )
1064 {
1065 nPos = 0;
1066 }
1067 if (nPos != -1)
1068 {
1069 rFilterBox.set_cursor(nPos);
1070 rFilterBox.select(nPos);
1071 }
1072 mpFilterBox->EndInit();
1073}
1074
1075void ScGridWindow::LaunchDataSelectMenu( SCCOL nCol, SCROW nRow )
1076{
1077 mpFilterBox.disposeAndClear();
1078 mpFilterFloat.disposeAndClear();
1079
1080 ScDocument& rDoc = mrViewData.GetDocument();
1081 SCTAB nTab = mrViewData.GetTabNo();
1082 bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
1083
1084 long nSizeX = 0;
1085 long nSizeY = 0;
1086 mrViewData.GetMergeSizePixel( nCol, nRow, nSizeX, nSizeY );
1087 Point aPos = mrViewData.GetScrPos( nCol, nRow, eWhich );
1088 bool bLOKActive = comphelper::LibreOfficeKit::isActive();
1089
1090 if (bLOKActive)
1091 {
1092 // aPos is now view-zoom adjusted and in pixels an more importantly this is pixel aligned to the view-zoom,
1093 // but once we use this to set the position of the floating window, it has no information of view-zoom level
1094 // so if we don't reverse the zoom now, a simple PixelToLogic(aPos, MapMode(MapUnit::MapTwip)) employed in
1095 // FloatingWindow::ImplCalcPos will produce a 'scaled' twips position which will again get zoom scaled in the
1096 // client (effective double scaling) causing wrong positioning/size.
1097 double fZoomX(mrViewData.GetZoomX());
1098 double fZoomY(mrViewData.GetZoomY());
1099 aPos.setX(aPos.getX() / fZoomX);
1100 aPos.setY(aPos.getY() / fZoomY);
1101 nSizeX = nSizeX / fZoomX;
1102 nSizeY = nSizeY / fZoomY;
1103 }
1104
1105 if ( bLayoutRTL )
1106 aPos.AdjustX( -nSizeX );
1107
1108 tools::Rectangle aCellRect( OutputToScreenPixel(aPos), Size(nSizeX,nSizeY) );
1109
1110 aPos.AdjustX( -1 );
1111 aPos.AdjustY( nSizeY - 1 );
1112
1113 mpFilterFloat.reset(VclPtr<ScFilterFloatingWindow>::Create(this));
1114 if (bLOKActive)
1115 {
1116 mpFilterFloat->SetLOKNotifier(SfxViewShell::Current());
1117 }
1118 mpFilterFloat->SetPopupModeEndHdl(LINK( this, ScGridWindow, PopupModeEndHdl)::tools::detail::makeLink( ::tools::detail::castTo<ScGridWindow
*>(this), &ScGridWindow::LinkStubPopupModeEndHdl)
);
1119 mpFilterBox.reset(VclPtr<ScFilterListBox>::Create(mpFilterFloat.get(), this, nCol, nRow, ScFilterBoxMode::DataSelect));
1120 weld::TreeView& rFilterBox = mpFilterBox->get_widget();
1121 rFilterBox.set_direction(bLayoutRTL); // Fix for bug fdo#44925 use sheet direction for widget RTL/LTR
1122
1123 // SetSize later
1124
1125 bool bEmpty = false;
1126 std::vector<ScTypedStrData> aStrings; // case sensitive
1127 // Fill List
1128 rDoc.GetDataEntries(nCol, nRow, nTab, aStrings);
1129 if (aStrings.empty())
1130 bEmpty = true;
1131
1132 if (!bEmpty)
1133 {
1134 mpFilterBox->Show(); // Show has to be before freeze !!!
1135 rFilterBox.freeze();
1136
1137 // Fill Listbox
1138 bool bWait = aStrings.size() > 100;
1139
1140 if (bWait)
1141 EnterWait();
1142
1143 for (const auto& rString : aStrings)
1144 rFilterBox.append_text(rString.GetString());
1145
1146 if (bWait)
1147 LeaveWait();
1148
1149 rFilterBox.thaw();
1150
1151 ShowFilterMenu(aCellRect, bLayoutRTL);
1152 }
1153
1154 sal_Int32 nSelPos = -1;
1155
1156 sal_uLong nIndex = rDoc.GetAttr( nCol, nRow, nTab, ATTR_VALIDDATA )->GetValue();
1157 if ( nIndex )
1158 {
1159 const ScValidationData* pData = rDoc.GetValidationEntry( nIndex );
1160 if (pData)
1161 {
1162 std::unique_ptr<ScTypedStrData> pNew;
1163 OUString aDocStr = rDoc.GetString(nCol, nRow, nTab);
1164 if ( rDoc.HasValueData( nCol, nRow, nTab ) )
1165 {
1166 double fVal = rDoc.GetValue(ScAddress(nCol, nRow, nTab));
1167 pNew.reset(new ScTypedStrData(aDocStr, fVal, ScTypedStrData::Value));
1168 }
1169 else
1170 pNew.reset(new ScTypedStrData(aDocStr, 0.0, ScTypedStrData::Standard));
1171
1172 if (pData->GetListType() == css::sheet::TableValidationVisibility::SORTEDASCENDING)
1173 {
1174 auto it = std::lower_bound(aStrings.begin(), aStrings.end(), *pNew, ScTypedStrData::LessCaseSensitive());
1175 if (it != aStrings.end() && ScTypedStrData::EqualCaseSensitive()(*it, *pNew))
1176 nSelPos = static_cast<sal_Int32>(std::distance(aStrings.begin(), it));
1177 }
1178 else
1179 {
1180 auto it = std::find_if(aStrings.begin(), aStrings.end(), FindTypedStrData(*pNew, true));
1181 if (it != aStrings.end())
1182 nSelPos = static_cast<sal_Int32>(std::distance(aStrings.begin(), it));
1183 }
1184 }
1185 }
1186
1187 // Do not show an empty selection List:
1188
1189 if ( bEmpty )
1190 {
1191 mpFilterBox.disposeAndClear();
1192 mpFilterFloat.disposeAndClear();
1193 }
1194 else
1195 {
1196 rFilterBox.grab_focus();
1197
1198 // Select only after GrabFocus, so that the focus rectangle gets correct
1199 if (nSelPos != -1)
1200 {
1201 rFilterBox.set_cursor(nSelPos);
1202 rFilterBox.select(nSelPos);
1203 }
1204 else
1205 rFilterBox.unselect_all();
1206
1207 mpFilterBox->EndInit();
1208 }
1209 collectUIInformation(OUString::number(nRow), OUString::number(nCol),"SELECTMENU");
1210}
1211
1212void ScGridWindow::FilterSelect( sal_uLong nSel )
1213{
1214 weld::TreeView& rFilterBox = mpFilterBox->get_widget();
1215 OUString aString = rFilterBox.get_text(static_cast<sal_Int32>(nSel));
1216
1217 SCCOL nCol = mpFilterBox->GetCol();
1218 SCROW nRow = mpFilterBox->GetRow();
1219 switch (mpFilterBox->GetMode())
1220 {
1221 case ScFilterBoxMode::DataSelect:
1222 ExecDataSelect(nCol, nRow, aString);
1223 break;
1224 case ScFilterBoxMode::Scenario:
1225 mrViewData.GetView()->UseScenario(aString);
1226 break;
1227 }
1228
1229 if (mpFilterFloat)
1230 mpFilterFloat->EndPopupMode();
1231
1232 GrabFocus(); // Otherwise the focus would be wrong on OS/2
1233}
1234
1235void ScGridWindow::ExecDataSelect( SCCOL nCol, SCROW nRow, const OUString& rStr )
1236{
1237 ScModule* pScMod = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
;
1238 ScInputHandler* pViewHdl = pScMod->GetInputHdl(mrViewData.GetViewShell());
1239 if (pViewHdl && mrViewData.HasEditView(mrViewData.GetActivePart()))
1240 pViewHdl->CancelHandler();
1241
1242 SCTAB nTab = mrViewData.GetTabNo();
1243 ScViewFunc* pView = mrViewData.GetView();
1244 pView->EnterData( nCol, nRow, nTab, rStr );
1245
1246 // #i52307# CellContentChanged is not in EnterData so it isn't called twice
1247 // if the cursor is moved afterwards.
1248 pView->CellContentChanged();
1249}
1250
1251void ScGridWindow::MoveMouseStatus( ScGridWindow& rDestWin )
1252{
1253 if (nButtonDown)
1254 {
1255 rDestWin.nButtonDown = nButtonDown;
1256 rDestWin.nMouseStatus = nMouseStatus;
1257 }
1258
1259 if (bRFMouse)
1260 {
1261 rDestWin.bRFMouse = bRFMouse;
1262 rDestWin.bRFSize = bRFSize;
1263 rDestWin.nRFIndex = nRFIndex;
1264 rDestWin.nRFAddX = nRFAddX;
1265 rDestWin.nRFAddY = nRFAddY;
1266 bRFMouse = false;
1267 }
1268
1269 if (nPagebreakMouse)
1270 {
1271 rDestWin.nPagebreakMouse = nPagebreakMouse;
1272 rDestWin.nPagebreakBreak = nPagebreakBreak;
1273 rDestWin.nPagebreakPrev = nPagebreakPrev;
1274 rDestWin.aPagebreakSource = aPagebreakSource;
1275 rDestWin.aPagebreakDrag = aPagebreakDrag;
1276 nPagebreakMouse = SC_PD_NONE0;
1277 }
1278}
1279
1280bool ScGridWindow::TestMouse( const MouseEvent& rMEvt, bool bAction )
1281{
1282 // MouseEvent buttons must only be checked if bAction==TRUE
1283 // to allow changing the mouse pointer in MouseMove,
1284 // but not start AutoFill with right button (#74229#).
1285 // with bAction==sal_True, SetFillMode / SetDragMode is called
1286
1287 if ( bAction && !rMEvt.IsLeft() )
1288 return false;
1289
1290 bool bNewPointer = false;
1291
1292 SfxInPlaceClient* pClient = mrViewData.GetViewShell()->GetIPClient();
1293 bool bOleActive = ( pClient && pClient->IsObjectInPlaceActive() );
1294
1295 if ( mrViewData.IsActive() && !bOleActive )
1296 {
1297 ScDocument& rDoc = mrViewData.GetDocument();
1298 SCTAB nTab = mrViewData.GetTabNo();
1299 bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
1300
1301 // Auto-Fill
1302
1303 ScRange aMarkRange;
1304 if (mrViewData.GetSimpleArea( aMarkRange ) == SC_MARK_SIMPLE)
1305 {
1306 if (aMarkRange.aStart.Tab() == mrViewData.GetTabNo() && mpAutoFillRect)
1307 {
1308 Point aMousePos = rMEvt.GetPosPixel();
1309 if (mpAutoFillRect->IsInside(aMousePos))
1310 {
1311 SetPointer( PointerStyle::Cross ); //! bold cross ?
1312 if (bAction)
1313 {
1314 SCCOL nX = aMarkRange.aEnd.Col();
1315 SCROW nY = aMarkRange.aEnd.Row();
1316
1317 if ( lcl_IsEditableMatrix( mrViewData.GetDocument(), aMarkRange ) )
1318 mrViewData.SetDragMode(
1319 aMarkRange.aStart.Col(), aMarkRange.aStart.Row(), nX, nY, ScFillMode::MATRIX );
1320 else
1321 mrViewData.SetFillMode(
1322 aMarkRange.aStart.Col(), aMarkRange.aStart.Row(), nX, nY );
1323
1324 // The simple selection must also be recognized when dragging,
1325 // where the Marking flag is set and MarkToSimple won't work anymore.
1326 mrViewData.GetMarkData().MarkToSimple();
1327 }
1328 bNewPointer = true;
1329 }
1330 }
1331 }
1332
1333 // Embedded rectangle
1334
1335 if (rDoc.IsEmbedded())
1336 {
1337 ScRange aRange;
1338 rDoc.GetEmbedded( aRange );
1339 if ( mrViewData.GetTabNo() == aRange.aStart.Tab() )
1340 {
1341 Point aStartPos = mrViewData.GetScrPos( aRange.aStart.Col(), aRange.aStart.Row(), eWhich );
1342 Point aEndPos = mrViewData.GetScrPos( aRange.aEnd.Col()+1, aRange.aEnd.Row()+1, eWhich );
1343 Point aMousePos = rMEvt.GetPosPixel();
1344 if ( bLayoutRTL )
1345 {
1346 aStartPos.AdjustX(2 );
1347 aEndPos.AdjustX(2 );
1348 }
1349 bool bTop = ( aMousePos.X() >= aStartPos.X()-3 && aMousePos.X() <= aStartPos.X()+1 &&
1350 aMousePos.Y() >= aStartPos.Y()-3 && aMousePos.Y() <= aStartPos.Y()+1 );
1351 bool bBottom = ( aMousePos.X() >= aEndPos.X()-3 && aMousePos.X() <= aEndPos.X()+1 &&
1352 aMousePos.Y() >= aEndPos.Y()-3 && aMousePos.Y() <= aEndPos.Y()+1 );
1353 if ( bTop || bBottom )
1354 {
1355 SetPointer( PointerStyle::Cross );
1356 if (bAction)
1357 {
1358 ScFillMode nMode = bTop ? ScFillMode::EMBED_LT : ScFillMode::EMBED_RB;
1359 mrViewData.SetDragMode(
1360 aRange.aStart.Col(), aRange.aStart.Row(),
1361 aRange.aEnd.Col(), aRange.aEnd.Row(), nMode );
1362 }
1363 bNewPointer = true;
1364 }
1365 }
1366 }
1367 }
1368
1369 if (!bNewPointer && bAction)
1370 {
1371 mrViewData.ResetFillMode();
1372 }
1373
1374 return bNewPointer;
1375}
1376
1377void ScGridWindow::LogicMouseButtonDown(const MouseEvent& rMouseEvent)
1378{
1379 MouseButtonDown(rMouseEvent);
1380}
1381
1382void ScGridWindow::LogicMouseButtonUp(const MouseEvent& rMouseEvent)
1383{
1384 MouseButtonUp(rMouseEvent);
1385}
1386
1387void ScGridWindow::LogicMouseMove(const MouseEvent& rMouseEvent)
1388{
1389 MouseMove(rMouseEvent);
1390}
1391
1392void ScGridWindow::MouseButtonDown( const MouseEvent& rMEvt )
1393{
1394 nNestedButtonState = ScNestedButtonState::Down;
1395
1396 MouseEventState aState;
1397 HandleMouseButtonDown(rMEvt, aState);
1398 if (aState.mbActivatePart)
1399 mrViewData.GetView()->ActivatePart(eWhich);
1400
1401 if ( nNestedButtonState == ScNestedButtonState::Up )
1402 {
1403 // #i41690# If an object is deactivated from MouseButtonDown, it might reschedule,
1404 // so MouseButtonUp comes before the MouseButtonDown call is finished. In this case,
1405 // simulate another MouseButtonUp call, so the selection state is consistent.
1406
1407 nButtonDown = rMEvt.GetButtons();
1408 FakeButtonUp();
1409
1410 if ( IsTracking() )
1411 EndTracking(); // normally done in VCL as part of MouseButtonUp handling
1412 }
1413 nNestedButtonState = ScNestedButtonState::NONE;
1414}
1415
1416bool ScGridWindow::IsCellCoveredByText(SCCOL nPosX, SCROW nPosY, SCTAB nTab, SCCOL &rTextStartPosX)
1417{
1418 ScDocument& rDoc = mrViewData.GetDocument();
1419
1420 // find the first non-empty cell (this, or to the left)
1421 SCCOL nNonEmptyX = nPosX;
1422 for (; nNonEmptyX >= 0; --nNonEmptyX)
1423 {
1424 ScRefCellValue aCell(rDoc, ScAddress(nNonEmptyX, nPosY, nTab));
1425 if (!aCell.isEmpty())
1426 break;
1427 }
1428
1429 // the initial cell already contains text
1430 if (nNonEmptyX == nPosX)
1431 {
1432 rTextStartPosX = nNonEmptyX;
1433 return true;
1434 }
1435
1436 // to the left, there is no cell that would contain (potentially
1437 // overrunning) text
1438 if (nNonEmptyX < 0 || rDoc.HasAttrib(nNonEmptyX, nPosY, nTab, nPosX, nPosY, nTab, HasAttrFlags::Merged | HasAttrFlags::Overlapped))
1439 return false;
1440
1441 double nPPTX = mrViewData.GetPPTX();
1442 double nPPTY = mrViewData.GetPPTY();
1443
1444 ScTableInfo aTabInfo;
1445 rDoc.FillInfo(aTabInfo, 0, nPosY, nPosX, nPosY, nTab, nPPTX, nPPTY, false, false);
1446
1447 Fraction aZoomX = mrViewData.GetZoomX();
1448 Fraction aZoomY = mrViewData.GetZoomY();
1449 ScOutputData aOutputData(this, OUTTYPE_WINDOW, aTabInfo, &rDoc, nTab,
1450 0, 0, 0, nPosY, nPosX, nPosY, nPPTX, nPPTY,
1451 &aZoomX, &aZoomY);
1452
1453 MapMode aCurrentMapMode(GetMapMode());
1454 SetMapMode(MapMode(MapUnit::MapPixel));
1455
1456 // obtain the bounding box of the text in first non-empty cell
1457 // to the left
1458 tools::Rectangle aRect(aOutputData.LayoutStrings(false, false, ScAddress(nNonEmptyX, nPosY, nTab)));
1459
1460 SetMapMode(aCurrentMapMode);
1461
1462 // the text does not overrun from the cell
1463 if (aRect.IsEmpty())
1464 return false;
1465
1466 SCCOL nTextEndX;
1467 SCROW nTextEndY;
1468
1469 // test the rightmost position of the text bounding box
1470 long nMiddle = (aRect.Top() + aRect.Bottom()) / 2;
1471 mrViewData.GetPosFromPixel(aRect.Right(), nMiddle, eWhich, nTextEndX, nTextEndY);
1472 if (nTextEndX >= nPosX)
1473 {
1474 rTextStartPosX = nNonEmptyX;
1475 return true;
1476 }
1477
1478 return false;
1479}
1480
1481void ScGridWindow::HandleMouseButtonDown( const MouseEvent& rMEvt, MouseEventState& rState )
1482{
1483 // We have to check if a context menu is shown and we have an UI
1484 // active inplace client. In that case we have to ignore the event.
1485 // Otherwise we would crash (context menu has been
1486 // opened by inplace client and we would deactivate the inplace client,
1487 // the context menu is closed by VCL asynchronously which in the end
1488 // would work on deleted objects or the context menu has no parent anymore)
1489 SfxViewShell* pViewSh = mrViewData.GetViewShell();
1490 SfxInPlaceClient* pClient = pViewSh->GetIPClient();
1491 if ( pClient &&
1492 pClient->IsObjectInPlaceActive() &&
1493 PopupMenu::IsInExecute() )
1494 return;
1495
1496 aCurMousePos = rMEvt.GetPosPixel();
1497
1498 // Filter popup is ended with its own mouse click, not when clicking into the Grid Window,
1499 // so the following query is no longer necessary:
1500 ClickExtern(); // deletes FilterBox when available
1501
1502 HideNoteMarker();
1503
1504 bEEMouse = false;
1505
1506 ScModule* pScMod = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
;
1507 if (pScMod->IsModalMode(mrViewData.GetSfxDocShell()))
1508 return;
1509
1510 pScActiveViewShell = mrViewData.GetViewShell(); // if left is clicked
1511 nScClickMouseModifier = rMEvt.GetModifier(); // to always catch a control click
1512
1513 bool bDetective = mrViewData.GetViewShell()->IsAuditShell();
1514 bool bRefMode = mrViewData.IsRefMode(); // Start reference
1515 bool bFormulaMode = pScMod->IsFormulaMode(); // next click -> reference
1516 bool bEditMode = mrViewData.HasEditView(eWhich); // also in Mode==SC_INPUT_TYPE
1517 bool bDouble = (rMEvt.GetClicks() == 2);
1518 ScDocument& rDoc = mrViewData.GetDocument();
1519 bool bIsTiledRendering = comphelper::LibreOfficeKit::isActive();
1520
1521 // DeactivateIP does only happen when MarkListHasChanged
1522
1523 // An error message can show up during GrabFocus call
1524 // (for instance when renaming tables per sheet title)
1525
1526 if ( !nButtonDown || !bDouble ) // single (first) click is always valid
1527 nButtonDown = rMEvt.GetButtons(); // set nButtonDown first, so StopMarking works
1528
1529 // special handling of empty cells with tiled rendering
1530 if (bIsTiledRendering)
1531 {
1532 Point aPos(rMEvt.GetPosPixel());
1533 SCCOL nPosX, nNonEmptyX(0);
1534 SCROW nPosY;
1535 SCTAB nTab = mrViewData.GetTabNo();
1536 mrViewData.GetPosFromPixel(aPos.X(), aPos.Y(), eWhich, nPosX, nPosY);
1537
1538 ScRefCellValue aCell(rDoc, ScAddress(nPosX, nPosY, nTab));
1539 bool bIsEmpty = aCell.isEmpty();
1540 bool bIsCoveredByText = bIsEmpty && IsCellCoveredByText(nPosX, nPosY, nTab, nNonEmptyX);
1541
1542 if (bIsCoveredByText)
1543 {
1544 // if there's any text flowing to this cell, activate the
1545 // editengine, so that the text actually gets the events
1546 if (bDouble)
1547 {
1548 ScViewFunc* pView = mrViewData.GetView();
1549
1550 pView->SetCursor(nNonEmptyX, nPosY);
1551 SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->SetInputMode(SC_INPUT_TABLE);
1552
1553 bEditMode = mrViewData.HasEditView(eWhich);
1554 assert(bEditMode)(static_cast <bool> (bEditMode) ? void (0) : __assert_fail
("bEditMode", "/home/maarten/src/libreoffice/core/sc/source/ui/view/gridwin.cxx"
, 1554, __extension__ __PRETTY_FUNCTION__))
;
1555
1556 // synthesize the 1st click
1557 EditView* pEditView = mrViewData.GetEditView(eWhich);
1558 MouseEvent aEditEvt(rMEvt.GetPosPixel(), 1, MouseEventModifiers::SYNTHETIC, MOUSE_LEFT(sal_uInt16(0x0001)), 0);
1559 pEditView->MouseButtonDown(aEditEvt);
1560 pEditView->MouseButtonUp(aEditEvt);
1561 }
1562 }
1563 else if (bIsEmpty && bEditMode && bDouble)
1564 {
1565 // double-click in an empty cell: the entire cell is selected
1566 SetCellSelectionPixel(LOK_SETTEXTSELECTION_START, aPos.X(), aPos.Y());
1567 SetCellSelectionPixel(LOK_SETTEXTSELECTION_END, aPos.X(), aPos.Y());
1568 return;
1569 }
1570 }
1571
1572 if ( ( bEditMode && mrViewData.GetActivePart() == eWhich ) || !bFormulaMode )
1573 GrabFocus();
1574
1575 // #i31846# need to cancel a double click if the first click has set the "ignore" state,
1576 // but a single (first) click is always valid
1577 if ( nMouseStatus == SC_GM_IGNORE4 && bDouble )
1578 {
1579 nButtonDown = 0;
1580 nMouseStatus = SC_GM_NONE0;
1581 return;
1582 }
1583
1584 if ( bDetective ) // Detectiv fill mode
1585 {
1586 if ( rMEvt.IsLeft() && !rMEvt.GetModifier() )
1587 {
1588 Point aPos = rMEvt.GetPosPixel();
1589 SCCOL nPosX;
1590 SCROW nPosY;
1591 mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
1592
1593 SfxInt16Item aPosXItem( SID_RANGE_COL((((26000 + 521) + 50))+21), nPosX );
1594 SfxInt32Item aPosYItem( SID_RANGE_ROW((((26000 + 521) + 50))+20), nPosY );
1595 mrViewData.GetDispatcher().ExecuteList(SID_FILL_SELECT((((((((((((((((((((((((((26000 + 200) + 20)) + 20)) + 20)) +
25)) + 22)) + 20)) + 29)) + 20))+20))+1))+50))+20))+12)
,
1596 SfxCallMode::SLOT | SfxCallMode::RECORD,
1597 { &aPosXItem, &aPosYItem });
1598
1599 }
1600 nButtonDown = 0;
1601 nMouseStatus = SC_GM_NONE0;
1602 return;
1603 }
1604
1605 if (!bDouble)
1606 nMouseStatus = SC_GM_NONE0;
1607
1608 rState.mbActivatePart = !bFormulaMode; // Don't activate when in formula mode.
1609
1610 if (bFormulaMode)
1611 {
1612 ScViewSelectionEngine* pSelEng = mrViewData.GetView()->GetSelEngine();
1613 pSelEng->SetWindow(this);
1614 pSelEng->SetWhich(eWhich);
1615 pSelEng->SetVisibleArea( tools::Rectangle(Point(), GetOutputSizePixel()) );
1616 }
1617
1618 if (bEditMode && (mrViewData.GetRefTabNo() == mrViewData.GetTabNo()))
1619 {
1620 Point aPos = rMEvt.GetPosPixel();
1621 SCCOL nPosX;
1622 SCROW nPosY;
1623 mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
1624
1625 EditView* pEditView;
1626 SCCOL nEditCol;
1627 SCROW nEditRow;
1628 mrViewData.GetEditView( eWhich, pEditView, nEditCol, nEditRow );
1629 SCCOL nEndCol = mrViewData.GetEditEndCol();
1630 SCROW nEndRow = mrViewData.GetEditEndRow();
1631
1632 if ( nPosX >= nEditCol && nPosX <= nEndCol &&
1633 nPosY >= nEditRow && nPosY <= nEndRow )
1634 {
1635 // when clicking in the table EditView, always reset the focus
1636 if (bFormulaMode) // otherwise this has already happen above
1637 GrabFocus();
1638
1639 pScMod->SetInputMode( SC_INPUT_TABLE );
1640 bEEMouse = true;
1641 pEditView->MouseButtonDown( rMEvt );
1642 return;
1643 }
1644 }
1645
1646 if (pScMod->GetIsWaterCan())
1647 {
1648 //! what's up with the Mac ???
1649 if ( rMEvt.GetModifier() + rMEvt.GetButtons() == MOUSE_RIGHT(sal_uInt16(0x0004)) )
1650 {
1651 nMouseStatus = SC_GM_WATERUNDO5;
1652 return;
1653 }
1654 }
1655
1656 // Order that matches the displayed Cursor:
1657 // RangeFinder, AutoFill, PageBreak, Drawing
1658
1659 RfCorner rCorner = NONE;
1660 bool bFound = HitRangeFinder(rMEvt.GetPosPixel(), rCorner, &nRFIndex, &nRFAddX, &nRFAddY);
1661 bRFSize = (rCorner != NONE);
1662 aRFSelectedCorned = rCorner;
1663
1664 if (bFound)
1665 {
1666 bRFMouse = true; // the other variables are initialized above
1667
1668 rState.mbActivatePart = true; // always activate ?
1669 StartTracking();
1670 return;
1671 }
1672
1673 bool bCrossPointer = TestMouse( rMEvt, true );
1674 if ( bCrossPointer )
1675 {
1676 if ( bDouble )
1677 mrViewData.GetView()->FillCrossDblClick();
1678 else
1679 pScMod->InputEnterHandler(); // Autofill etc.
1680 }
1681
1682 if ( !bCrossPointer )
1683 {
1684 nPagebreakMouse = HitPageBreak( rMEvt.GetPosPixel(), &aPagebreakSource,
1685 &nPagebreakBreak, &nPagebreakPrev );
1686 if (nPagebreakMouse)
1687 {
1688 bPagebreakDrawn = false;
1689 StartTracking();
1690 PagebreakMove( rMEvt, false );
1691 return;
1692 }
1693 }
1694
1695 // in the tiled rendering case, single clicks into drawing objects take
1696 // precedence over bEditMode
1697 if (((!bFormulaMode && !bEditMode) || bIsTiledRendering) && rMEvt.IsLeft())
1698 {
1699 if ( !bCrossPointer && DrawMouseButtonDown(rMEvt) )
1700 {
1701 return;
1702 }
1703
1704 mrViewData.GetViewShell()->SetDrawShell( false ); // no Draw-object selected
1705
1706 // TestMouse has already happened above
1707 }
1708
1709 Point aPos = rMEvt.GetPosPixel();
1710 SCCOL nPosX;
1711 SCROW nPosY;
1712 mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
1713 SCTAB nTab = mrViewData.GetTabNo();
1714
1715 // FIXME: this is to limit the number of rows handled in the Online
1716 // to 1000; this will be removed again when the performance
1717 // bottlenecks are sorted out
1718 if ( comphelper::LibreOfficeKit::isActive() && nPosY > MAXTILEDROW - 1 )
1719 {
1720 nButtonDown = 0;
1721 nMouseStatus = SC_GM_NONE0;
1722 return;
1723 }
1724
1725 // Auto filter / pivot table / data select popup. This shouldn't activate the part.
1726
1727 if ( !bDouble && !bFormulaMode && rMEvt.IsLeft() )
1728 {
1729 SCCOL nRealPosX;
1730 SCROW nRealPosY;
1731 mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nRealPosX, nRealPosY, false );//the real row/col
1732 const ScMergeFlagAttr* pRealPosAttr = rDoc.GetAttr( nRealPosX, nRealPosY, nTab, ATTR_MERGE_FLAG );
1733 const ScMergeFlagAttr* pAttr = rDoc.GetAttr( nPosX, nPosY, nTab, ATTR_MERGE_FLAG );
1734 if( pRealPosAttr->HasAutoFilter() )
1735 {
1736 SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->InputEnterHandler();
1737 if (DoAutoFilterButton( nRealPosX, nRealPosY, rMEvt))
1738 return;
1739 }
1740 if (pAttr->HasAutoFilter())
1741 {
1742 if (DoAutoFilterButton(nPosX, nPosY, rMEvt))
1743 {
1744 rState.mbActivatePart = false;
1745 return;
1746 }
1747 }
1748
1749 if (pAttr->HasPivotButton() || pAttr->HasPivotPopupButton())
1750 {
1751 DoPushPivotButton(nPosX, nPosY, rMEvt, pAttr->HasPivotButton(), pAttr->HasPivotPopupButton());
1752 rState.mbActivatePart = false;
1753 return;
1754 }
1755
1756 // List Validity drop-down button
1757
1758 if ( bListValButton )
1759 {
1760 tools::Rectangle aButtonRect = GetListValButtonRect( aListValPos );
1761 if ( aButtonRect.IsInside( aPos ) )
1762 {
1763 // tdf#125917 typically we have the mouse captured already, except if are editing the cell.
1764 // Ensure its captured before the menu is launched even in the cell editing case
1765 CaptureMouse();
1766
1767 LaunchDataSelectMenu( aListValPos.Col(), aListValPos.Row() );
1768
1769 nMouseStatus = SC_GM_FILTER3; // not set in DoAutoFilterMenue for bDataSelect
1770 rState.mbActivatePart = false;
1771 return;
1772 }
1773 }
1774 }
1775
1776 // scenario selection
1777
1778 ScRange aScenRange;
1779 if ( rMEvt.IsLeft() && HasScenarioButton( aPos, aScenRange ) )
1780 {
1781 CaptureMouse();
1782
1783 DoScenarioMenu( aScenRange );
1784
1785 // Scenario selection comes from MouseButtonDown:
1786 // The next MouseMove on the FilterBox is like a ButtonDown
1787 nMouseStatus = SC_GM_FILTER3;
1788
1789 return;
1790 }
1791
1792 // double click started ?
1793
1794 // StopMarking can be called from DrawMouseButtonDown
1795
1796 if ( nMouseStatus != SC_GM_IGNORE4 && !bRefMode )
1797 {
1798 if ( bDouble && !bCrossPointer )
1799 {
1800 if (nMouseStatus == SC_GM_TABDOWN1)
1801 nMouseStatus = SC_GM_DBLDOWN2;
1802 }
1803 else
1804 nMouseStatus = SC_GM_TABDOWN1;
1805 }
1806
1807 // links in the edit cell
1808
1809 bool bAlt = rMEvt.IsMod2();
1810 if ( !bAlt && rMEvt.IsLeft() && ScGlobal::ShouldOpenURL() &&
1811 GetEditUrl(rMEvt.GetPosPixel()) ) // click on link: do not move cursor
1812 {
1813 SetPointer( PointerStyle::RefHand );
1814 nMouseStatus = SC_GM_URLDOWN6; // also only execute when ButtonUp
1815 return;
1816 }
1817
1818 // Gridwin - Selection Engine
1819
1820 if ( !rMEvt.IsLeft() )
1821 return;
1822
1823 ScViewSelectionEngine* pSelEng = mrViewData.GetView()->GetSelEngine();
1824 pSelEng->SetWindow(this);
1825 pSelEng->SetWhich(eWhich);
1826 pSelEng->SetVisibleArea( tools::Rectangle(Point(), GetOutputSizePixel()) );
1827
1828 // SelMouseButtonDown on the View is still setting the bMoveIsShift flag
1829 if ( mrViewData.GetView()->SelMouseButtonDown( rMEvt ) )
1830 {
1831 if (IsMouseCaptured())
1832 {
1833 // Tracking instead of CaptureMouse, so it can be canceled cleanly
1834 //! Someday SelectionEngine should call StartTracking on its own!?!
1835 ReleaseMouse();
1836 StartTracking();
1837 }
1838 mrViewData.GetMarkData().SetMarking(true);
1839 return;
1840 }
1841}
1842
1843void ScGridWindow::MouseButtonUp( const MouseEvent& rMEvt )
1844{
1845 aCurMousePos = rMEvt.GetPosPixel();
1846 ScDocument& rDoc = mrViewData.GetDocument();
1847 ScMarkData& rMark = mrViewData.GetMarkData();
1848 // #i41690# detect a MouseButtonUp call from within MouseButtonDown
1849 // (possible through Reschedule from storing an OLE object that is deselected)
1850
1851 if ( nNestedButtonState == ScNestedButtonState::Down )
1852 nNestedButtonState = ScNestedButtonState::Up;
1853
1854 if (nButtonDown != rMEvt.GetButtons())
1855 nMouseStatus = SC_GM_IGNORE4; // reset and return
1856
1857 nButtonDown = 0;
1858
1859 if (nMouseStatus == SC_GM_IGNORE4)
1860 {
1861 nMouseStatus = SC_GM_NONE0;
1862 // Selection engine: cancel selection
1863 mrViewData.GetView()->GetSelEngine()->Reset();
1864 rMark.SetMarking(false);
1865 if (mrViewData.IsAnyFillMode())
1866 {
1867 mrViewData.GetView()->StopRefMode();
1868 mrViewData.ResetFillMode();
1869 }
1870 StopMarking();
1871 DrawEndAction(); // cancel selection/moving in drawing layer
1872 ReleaseMouse();
1873 return;
1874 }
1875
1876 if (nMouseStatus == SC_GM_FILTER3)
1877 {
1878 nMouseStatus = SC_GM_NONE0;
1879 ReleaseMouse();
1880 return; // nothing more should happen here
1881 }
1882
1883 ScModule* pScMod = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
;
1884 if (pScMod->IsModalMode(mrViewData.GetSfxDocShell()))
1885 return;
1886
1887 SfxBindings& rBindings = mrViewData.GetBindings();
1888 if (bEEMouse && mrViewData.HasEditView( eWhich ))
1889 {
1890 EditView* pEditView;
1891 SCCOL nEditCol;
1892 SCROW nEditRow;
1893 mrViewData.GetEditView( eWhich, pEditView, nEditCol, nEditRow );
1894 pEditView->MouseButtonUp( rMEvt );
1895
1896 if ( rMEvt.IsMiddle() &&
1897 GetSettings().GetMouseSettings().GetMiddleButtonAction() == MouseMiddleButtonAction::PasteSelection )
1898 {
1899 // EditView may have pasted from selection
1900 pScMod->InputChanged( pEditView );
1901 }
1902 else
1903 pScMod->InputSelection( pEditView ); // parentheses etc.
1904
1905 mrViewData.GetView()->InvalidateAttribs();
1906 rBindings.Invalidate( SID_HYPERLINK_GETLINK(10000 + 361) );
1907 bEEMouse = false;
1908 return;
1909 }
1910
1911 if (bDPMouse)
1912 {
1913 DPMouseButtonUp( rMEvt ); // resets bDPMouse
1914 return;
1915 }
1916
1917 if (bRFMouse)
1918 {
1919 RFMouseMove( rMEvt, true ); // Again the proper range
1920 bRFMouse = false;
1921 SetPointer( PointerStyle::Arrow );
1922 ReleaseMouse();
1923 return;
1924 }
1925
1926 if (nPagebreakMouse)
1927 {
1928 PagebreakMove( rMEvt, true );
1929 nPagebreakMouse = SC_PD_NONE0;
1930 SetPointer( PointerStyle::Arrow );
1931 ReleaseMouse();
1932 return;
1933 }
1934
1935 if (nMouseStatus == SC_GM_WATERUNDO5) // Undo in format paintbrush mode
1936 {
1937 SfxUndoManager* pMgr = mrViewData.GetDocShell()->GetUndoManager();
1938 if ( pMgr->GetUndoActionCount() && dynamic_cast<ScUndoSelectionStyle*>(pMgr->GetUndoAction()) )
1939 pMgr->Undo();
1940 return;
1941 }
1942
1943 if (DrawMouseButtonUp(rMEvt)) // includes format paint brush handling for drawing objects
1944 {
1945 ScTabViewShell* pViewShell = mrViewData.GetViewShell();
1946 SfxBindings& rFrmBindings=pViewShell->GetViewFrame()->GetBindings();
1947 rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_WIDTHTypedWhichId<SfxUInt32Item>( 10000 + 90 ));
1948 rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_HEIGHTTypedWhichId<SfxUInt32Item>( 10000 + 91 ));
1949 rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_POS_XTypedWhichId<SfxInt32Item>( 10000 + 88 ));
1950 rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_POS_YTypedWhichId<SfxInt32Item>( 10000 + 89 ));
1951 rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_ANGLETypedWhichId<SfxInt32Item>( 10000 + 95 ));
1952 rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_ROT_XTypedWhichId<SfxInt32Item>( 10000 + 93 ));
1953 rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_ROT_YTypedWhichId<SfxInt32Item>( 10000 + 94 ));
1954 rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_AUTOWIDTH( 10000 + 310 ));
1955 rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_AUTOHEIGHT( 10000 + 311 ));
1956 return;
1957 }
1958
1959 rMark.SetMarking(false);
1960
1961 SetPointer( PointerStyle::Arrow );
1962
1963 if (mrViewData.IsFillMode() ||
1964 ( mrViewData.GetFillMode() == ScFillMode::MATRIX && rMEvt.IsMod1() ))
1965 {
1966 nScFillModeMouseModifier = rMEvt.GetModifier();
1967 SCCOL nStartCol;
1968 SCROW nStartRow;
1969 SCCOL nEndCol;
1970 SCROW nEndRow;
1971 mrViewData.GetFillData( nStartCol, nStartRow, nEndCol, nEndRow );
1972 ScRange aDelRange;
1973 bool bIsDel = mrViewData.GetDelMark( aDelRange );
1974
1975 ScViewFunc* pView = mrViewData.GetView();
1976 pView->StopRefMode();
1977 mrViewData.ResetFillMode();
1978 pView->GetFunctionSet().SetAnchorFlag( false ); // #i5819# don't use AutoFill anchor flag for selection
1979
1980 if ( bIsDel )
1981 {
1982 pView->MarkRange( aDelRange, false );
1983 pView->DeleteContents( InsertDeleteFlags::CONTENTS );
1984 SCTAB nTab = mrViewData.GetTabNo();
1985 ScRange aBlockRange( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab );
1986 if ( aBlockRange != aDelRange )
1987 {
1988 if ( aDelRange.aStart.Row() == nStartRow )
1989 aBlockRange.aEnd.SetCol( aDelRange.aStart.Col() - 1 );
1990 else
1991 aBlockRange.aEnd.SetRow( aDelRange.aStart.Row() - 1 );
1992 pView->MarkRange( aBlockRange, false );
1993 }
1994 }
1995 else
1996 mrViewData.GetDispatcher().Execute( FID_FILL_AUTO((26000 + 521) + 35), SfxCallMode::SLOT | SfxCallMode::RECORD );
1997 }
1998 else if (mrViewData.GetFillMode() == ScFillMode::MATRIX)
1999 {
2000 SCTAB nTab = mrViewData.GetTabNo();
2001 SCCOL nStartCol;
2002 SCROW nStartRow;
2003 SCCOL nEndCol;
2004 SCROW nEndRow;
2005 mrViewData.GetFillData( nStartCol, nStartRow, nEndCol, nEndRow );
2006 ScRange aBlockRange( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab );
2007 SCCOL nFillCol = mrViewData.GetRefEndX();
2008 SCROW nFillRow = mrViewData.GetRefEndY();
2009 ScAddress aEndPos( nFillCol, nFillRow, nTab );
2010
2011 ScTabView* pView = mrViewData.GetView();
2012 pView->StopRefMode();
2013 mrViewData.ResetFillMode();
2014 pView->GetFunctionSet().SetAnchorFlag( false );
2015
2016 if ( aEndPos != aBlockRange.aEnd )
2017 {
2018 mrViewData.GetDocShell()->GetDocFunc().ResizeMatrix( aBlockRange, aEndPos );
2019 mrViewData.GetView()->MarkRange( ScRange( aBlockRange.aStart, aEndPos ) );
2020 }
2021 }
2022 else if (mrViewData.IsAnyFillMode())
2023 {
2024 // Embedded area has been changed
2025 ScTabView* pView = mrViewData.GetView();
2026 pView->StopRefMode();
2027 mrViewData.ResetFillMode();
2028 pView->GetFunctionSet().SetAnchorFlag( false );
2029 mrViewData.GetDocShell()->UpdateOle(mrViewData);
2030 }
2031
2032 bool bRefMode = mrViewData.IsRefMode();
2033 if (bRefMode)
2034 pScMod->EndReference();
2035
2036 // Format paintbrush mode (Switch)
2037
2038 if (pScMod->GetIsWaterCan())
2039 {
2040 // Check on undo already done above
2041
2042 ScStyleSheetPool* pStylePool = mrViewData.GetDocument().
2043 GetStyleSheetPool();
2044 if ( pStylePool )
2045 {
2046 SfxStyleSheet* pStyleSheet = static_cast<SfxStyleSheet*>(
2047 pStylePool->GetActualStyleSheet());
2048
2049 if ( pStyleSheet )
2050 {
2051 SfxStyleFamily eFamily = pStyleSheet->GetFamily();
2052
2053 switch ( eFamily )
2054 {
2055 case SfxStyleFamily::Para:
2056 mrViewData.GetView()->SetStyleSheetToMarked( pStyleSheet );
2057 mrViewData.GetView()->DoneBlockMode();
2058 break;
2059
2060 case SfxStyleFamily::Page:
2061 mrViewData.GetDocument().SetPageStyle( mrViewData.GetTabNo(),
2062 pStyleSheet->GetName() );
2063
2064 ScPrintFunc( mrViewData.GetDocShell(),
2065 mrViewData.GetViewShell()->GetPrinter(true),
2066 mrViewData.GetTabNo() ).UpdatePages();
2067
2068 rBindings.Invalidate( SID_STATUS_PAGESTYLE((26000 + 100) + 15) );
2069 break;
2070
2071 default:
2072 break;
2073 }
2074 }
2075 }
2076 }
2077
2078 ScDBFunc* pView = mrViewData.GetView();
2079 ScDocument* pBrushDoc = pView->GetBrushDocument();
2080 if ( pBrushDoc )
2081 {
2082 pView->PasteFromClip( InsertDeleteFlags::ATTRIB, pBrushDoc );
2083 if ( !pView->IsPaintBrushLocked() )
2084 pView->ResetBrushDocument(); // invalidates pBrushDoc pointer
2085 }
2086
2087 // double click (only left button)
2088 // in the tiled rendering case, single click works this way too
2089
2090 bool bIsTiledRendering = comphelper::LibreOfficeKit::isActive();
2091 bool bDouble = ( rMEvt.GetClicks() == 2 && rMEvt.IsLeft() );
2092 if ((bDouble || bIsTiledRendering)
2093 && !bRefMode
2094 && (nMouseStatus == SC_GM_DBLDOWN2 || (bIsTiledRendering && nMouseStatus != SC_GM_URLDOWN6))
2095 && !pScMod->IsRefDialogOpen())
2096 {
2097 // data pilot table
2098 Point aPos = rMEvt.GetPosPixel();
2099 SCCOL nPosX;
2100 SCROW nPosY;
2101 SCTAB nTab = mrViewData.GetTabNo();
2102 mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
2103 ScDPObject* pDPObj = rDoc.GetDPAtCursor( nPosX, nPosY, nTab );
2104 if ( pDPObj && pDPObj->GetSaveData()->GetDrillDown() )
2105 {
2106 ScAddress aCellPos( nPosX, nPosY, mrViewData.GetTabNo() );
2107
2108 // Check for header drill-down first.
2109 sheet::DataPilotTableHeaderData aData;
2110 pDPObj->GetHeaderPositionData(aCellPos, aData);
2111
2112 if ( ( aData.Flags & sheet::MemberResultFlags::HASMEMBER ) &&
2113 ! ( aData.Flags & sheet::MemberResultFlags::SUBTOTAL ) )
2114 {
2115 css::sheet::DataPilotFieldOrientation nDummy;
2116 if ( pView->HasSelectionForDrillDown( nDummy ) )
2117 {
2118 // execute slot to show dialog
2119 mrViewData.GetDispatcher().Execute( SID_OUTLINE_SHOW((((((((((((((26000 + 200) + 20)) + 20)) + 20)) + 25)) + 22))
+ 20)) + 26)
, SfxCallMode::SLOT | SfxCallMode::RECORD );
2120 }
2121 else
2122 {
2123 // toggle single entry
2124 ScDPObject aNewObj( *pDPObj );
2125 pDPObj->ToggleDetails( aData, &aNewObj );
2126 ScDBDocFunc aFunc( *mrViewData.GetDocShell() );
2127 aFunc.DataPilotUpdate( pDPObj, &aNewObj, true, false );
2128 mrViewData.GetView()->CursorPosChanged(); // shells may be switched
2129 }
2130 }
2131 else
2132 {
2133 // Check if the data area is double-clicked.
2134
2135 Sequence<sheet::DataPilotFieldFilter> aFilters;
2136 if ( pDPObj->GetDataFieldPositionData(aCellPos, aFilters) )
2137 mrViewData.GetView()->ShowDataPilotSourceData( *pDPObj, aFilters );
2138 }
2139
2140 return;
2141 }
2142
2143 // Check for cell protection attribute.
2144 ScTableProtection* pProtect = rDoc.GetTabProtection( nTab );
2145 bool bEditAllowed = true;
2146 if ( pProtect && pProtect->isProtected() )
2147 {
2148 bool bCellProtected = rDoc.HasAttrib(nPosX, nPosY, nTab, nPosX, nPosY, nTab, HasAttrFlags::Protected);
2149 bool bSkipProtected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
2150 bool bSkipUnprotected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
2151
2152 if ( bSkipProtected && bSkipUnprotected )
2153 bEditAllowed = false;
2154 else if ( (bCellProtected && bSkipProtected) || (!bCellProtected && bSkipUnprotected) )
2155 bEditAllowed = false;
2156 }
2157
2158 // We don't want to activate the edit view for a single click in tiled rendering
2159 // (but we should probably keep the same behaviour for double clicks).
2160 if ( bEditAllowed && (!bIsTiledRendering || bDouble) )
2161 {
2162 // don't forward the event to an empty cell, causes deselection in
2163 // case we used the double-click to select the empty cell
2164 if (bIsTiledRendering && bDouble)
2165 {
2166 ScRefCellValue aCell(mrViewData.GetDocument(), ScAddress(nPosX, nPosY, nTab));
2167 if (aCell.isEmpty())
2168 return;
2169 }
2170
2171 // edit cell contents
2172 mrViewData.GetViewShell()->UpdateInputHandler();
2173 pScMod->SetInputMode( SC_INPUT_TABLE );
2174 if (mrViewData.HasEditView(eWhich))
2175 {
2176 // Set text cursor where clicked
2177 EditView* pEditView = mrViewData.GetEditView( eWhich );
2178 MouseEvent aEditEvt( rMEvt.GetPosPixel(), 1, MouseEventModifiers::SYNTHETIC, MOUSE_LEFT(sal_uInt16(0x0001)), 0 );
2179 pEditView->MouseButtonDown( aEditEvt );
2180 pEditView->MouseButtonUp( aEditEvt );
2181 }
2182 }
2183
2184 if ( bIsTiledRendering && rMEvt.IsLeft() && mrViewData.GetView()->GetSelEngine()->SelMouseButtonUp( rMEvt ) )
2185 {
2186 mrViewData.GetView()->SelectionChanged();
2187 }
2188
2189 if ( bDouble )
2190 return;
2191 }
2192
2193 // Links in edit cells
2194
2195 bool bAlt = rMEvt.IsMod2();
2196 if ( !bAlt && !bRefMode && !bDouble && nMouseStatus == SC_GM_URLDOWN6 )
2197 {
2198 // Only execute on ButtonUp, if ButtonDown also was done on a URL
2199
2200 OUString aName, aUrl, aTarget;
2201 if ( GetEditUrl( rMEvt.GetPosPixel(), &aName, &aUrl, &aTarget ) )
2202 {
2203 nMouseStatus = SC_GM_NONE0; // Ignore double-click
2204 bool isTiledRendering = comphelper::LibreOfficeKit::isActive();
2205 // ScGlobal::OpenURL() only understands Calc A1 style syntax.
2206 // Convert it to Calc A1 before calling OpenURL().
2207 if (rDoc.GetAddressConvention() == formula::FormulaGrammar::CONV_OOO)
2208 {
2209 if (aUrl.startsWith("#")) {
2210 ScGlobal::OpenURL(aUrl, aTarget, isTiledRendering);
2211 return;
2212 }
2213 // On a mobile device view there is no ctrl+click and for hyperlink popup
2214 // the cell coordinates must be sent along with click position for elegance
2215 ScTabViewShell* pViewShell = mrViewData.GetViewShell();
2216 if (isTiledRendering && pViewShell &&
2217 (pViewShell->isLOKMobilePhone() || pViewShell->isLOKTablet()))
2218 {
2219 Point aPos = rMEvt.GetPosPixel();
2220 SCCOL nPosX;
2221 SCROW nPosY;
2222 mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
2223 auto pForTabView = dynamic_cast<const ScTabViewShell *>(pViewShell);
2224 OString aCursor = pForTabView->GetViewData().describeCellCursorAt(nPosX, nPosY);
2225 double fPPTX = pForTabView->GetViewData().GetPPTX();
2226 int mouseX = aPos.X() / fPPTX;
2227 OString aMsg(aUrl.toUtf8() + " coordinates: " + aCursor + ", " + OString::number(mouseX));
2228 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_HYPERLINK_CLICKED, aMsg.getStr());
2229 } else
2230 ScGlobal::OpenURL(aUrl, aTarget);
2231 }
2232 else
2233 {
2234 ScAddress aTempAddr;
2235 ScAddress::ExternalInfo aExtInfo;
2236 ScRefFlags nRes = aTempAddr.Parse(aUrl, rDoc, rDoc.GetAddressConvention(), &aExtInfo);
2237 if (!(nRes & ScRefFlags::VALID))
2238 {
2239 // Not a reference string. Pass it through unmodified.
2240 ScGlobal::OpenURL(aUrl, aTarget);
2241 return;
2242 }
2243
2244 OUStringBuffer aBuf;
2245 if (aExtInfo.mbExternal)
2246 {
2247 // External reference.
2248 ScExternalRefManager* pRefMgr = rDoc.GetExternalRefManager();
2249 const OUString* pStr = pRefMgr->getExternalFileName(aExtInfo.mnFileId);
2250 if (pStr)
2251 aBuf.append(*pStr);
2252
2253 aBuf.append('#');
2254 aBuf.append(aExtInfo.maTabName);
2255 aBuf.append('.');
2256 OUString aRefCalcA1(aTempAddr.Format(ScRefFlags::ADDR_ABS, nullptr, formula::FormulaGrammar::CONV_OOO));
2257 aBuf.append(aRefCalcA1);
2258 ScGlobal::OpenURL(aBuf.makeStringAndClear(), aTarget);
2259 }
2260 else
2261 {
2262 // Internal reference.
2263 aBuf.append('#');
2264 OUString aUrlCalcA1(aTempAddr.Format(ScRefFlags::ADDR_ABS_3D, &rDoc, formula::FormulaGrammar::CONV_OOO));
2265 aBuf.append(aUrlCalcA1);
2266 ScGlobal::OpenURL(aBuf.makeStringAndClear(), aTarget, isTiledRendering);
2267 }
2268 }
2269
2270 // fire worksheet_followhyperlink event
2271 uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents = rDoc.GetVbaEventProcessor();
2272 if( xVbaEvents.is() ) try
2273 {
2274 Point aPos = rMEvt.GetPosPixel();
2275 SCCOL nPosX;
2276 SCROW nPosY;
2277 SCTAB nTab = mrViewData.GetTabNo();
2278 mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
2279 OUString sURL;
2280 ScRefCellValue aCell;
2281 if (lcl_GetHyperlinkCell(rDoc, nPosX, nPosY, nTab, aCell, sURL))
2282 {
2283 ScAddress aCellPos( nPosX, nPosY, nTab );
2284 uno::Reference< table::XCell > xCell( new ScCellObj( mrViewData.GetDocShell(), aCellPos ) );
2285 uno::Sequence< uno::Any > aArgs(1);
2286 aArgs[0] <<= xCell;
2287 xVbaEvents->processVbaEvent( script::vba::VBAEventId::WORKSHEET_FOLLOWHYPERLINK, aArgs );
2288 }
2289 }
2290 catch( uno::Exception& )
2291 {
2292 }
2293
2294 return;
2295 }
2296 }
2297
2298 // Gridwin - SelectionEngine
2299
2300 // SelMouseButtonDown is called only for left button, but SelMouseButtonUp would return
2301 // sal_True for any call, so IsLeft must be checked here, too.
2302
2303 if ( !(rMEvt.IsLeft() && mrViewData.GetView()->GetSelEngine()->SelMouseButtonUp( rMEvt )) )
2304 return;
2305
2306 mrViewData.GetView()->SelectionChanged();
2307
2308 SfxDispatcher* pDisp = mrViewData.GetViewShell()->GetDispatcher();
2309 bool bFormulaMode = pScMod->IsFormulaMode();
2310 OSL_ENSURE( pDisp || bFormulaMode, "Cursor moved on inactive View ?" )do { if (true && (!(pDisp || bFormulaMode))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/ui/view/gridwin.cxx"
":" "2310" ": "), "%s", "Cursor moved on inactive View ?"); }
} while (false)
;
2311
2312 // #i14927# execute SID_CURRENTCELL (for macro recording) only if there is no
2313 // multiple selection, so the argument string completely describes the selection,
2314 // and executing the slot won't change the existing selection (executing the slot
2315 // here and from a recorded macro is treated equally)
2316 if ( pDisp && !bFormulaMode && !rMark.IsMultiMarked() )
2317 {
2318 OUString aAddr; // CurrentCell
2319 if( rMark.IsMarked() )
2320 {
2321 ScRange aScRange;
2322 rMark.GetMarkArea( aScRange );
2323 aAddr = aScRange.Format(rDoc, ScRefFlags::RANGE_ABS);
2324 if ( aScRange.aStart == aScRange.aEnd )
2325 {
2326 // make sure there is a range selection string even for a single cell
2327 aAddr += ":" + aAddr;
2328 }
2329
2330 //! SID_MARKAREA does not exist anymore ???
2331 //! What happens when selecting with the cursor ???
2332 }
2333 else // only move cursor
2334 {
2335 ScAddress aScAddress( mrViewData.GetCurX(), mrViewData.GetCurY(), 0 );
2336 aAddr = aScAddress.Format(ScRefFlags::ADDR_ABS);
2337 }
2338
2339 SfxStringItem aPosItem( SID_CURRENTCELL((26000) + 41), aAddr );
2340 // We don't want to align to the cursor position because if the
2341 // cell cursor isn't visible after making selection, it would jump
2342 // back to the origin of the selection where the cell cursor is.
2343 SfxBoolItem aAlignCursorItem( FN_PARAM_2((20000 + 1100)+61), false );
2344 pDisp->ExecuteList(SID_CURRENTCELL((26000) + 41),
2345 SfxCallMode::SLOT | SfxCallMode::RECORD,
2346 { &aPosItem, &aAlignCursorItem });
2347
2348 mrViewData.GetView()->InvalidateAttribs();
2349
2350 }
2351 mrViewData.GetViewShell()->SelectionChanged();
2352
2353 return;
2354}
2355
2356void ScGridWindow::FakeButtonUp()
2357{
2358 if ( nButtonDown )
2359 {
2360 MouseEvent aEvent( aCurMousePos ); // nButtons = 0 -> ignore
2361 MouseButtonUp( aEvent );
2362 }
2363}
2364
2365void ScGridWindow::MouseMove( const MouseEvent& rMEvt )
2366{
2367 aCurMousePos = rMEvt.GetPosPixel();
2368
2369 if (rMEvt.IsLeaveWindow() && mpNoteMarker && !mpNoteMarker->IsByKeyboard())
2370 HideNoteMarker();
2371
2372 ScModule* pScMod = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
;
2373 if (pScMod->IsModalMode(mrViewData.GetSfxDocShell()))
2374 return;
2375
2376 // If the Drag&Drop is started in the edit mode then sadly nothing else is kept
2377 if (bEEMouse && nButtonDown && !rMEvt.GetButtons())
2378 {
2379 bEEMouse = false;
2380 nButtonDown = 0;
2381 nMouseStatus = SC_GM_NONE0;
2382 return;
2383 }
2384
2385 if (nMouseStatus == SC_GM_IGNORE4)
2386 return;
2387
2388 if (nMouseStatus == SC_GM_WATERUNDO5) // Undo in format paintbrush mode -> only what for Up
2389 return;
2390
2391 if ( mrViewData.GetViewShell()->IsAuditShell() ) // Detective Fill Mode
2392 {
2393 SetPointer( PointerStyle::Fill );
2394 return;
2395 }
2396
2397 if (nMouseStatus == SC_GM_FILTER3 && mpFilterBox)
2398 {
2399 Point aRelPos = mpFilterBox->ScreenToOutputPixel( OutputToScreenPixel( rMEvt.GetPosPixel() ) );
2400 if ( tools::Rectangle(Point(), mpFilterBox->GetOutputSizePixel()).IsInside(aRelPos) )
2401 {
2402 nButtonDown = 0;
2403 nMouseStatus = SC_GM_NONE0;
2404 ReleaseMouse();
2405 mpFilterBox->MouseButtonDown( MouseEvent( aRelPos, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT(sal_uInt16(0x0001)) ) );
2406 return;
2407 }
2408 }
2409
2410 bool bFormulaMode = pScMod->IsFormulaMode(); // next click -> reference
2411
2412 if (bEEMouse && mrViewData.HasEditView( eWhich ))
2413 {
2414 EditView* pEditView;
2415 SCCOL nEditCol;
2416 SCROW nEditRow;
2417 mrViewData.GetEditView( eWhich, pEditView, nEditCol, nEditRow );
2418 pEditView->MouseMove( rMEvt );
2419 return;
2420 }
2421
2422 if (bDPMouse)
2423 {
2424 DPMouseMove( rMEvt );
2425 return;
2426 }
2427
2428 if (bRFMouse)
2429 {
2430 RFMouseMove( rMEvt, false );
2431 return;
2432 }
2433
2434 if (nPagebreakMouse)
2435 {
2436 PagebreakMove( rMEvt, false );
2437 return;
2438 }
2439
2440 // Show other mouse pointer?
2441
2442 bool bEditMode = mrViewData.HasEditView(eWhich);
2443
2444 //! Test if refMode dragging !!!
2445 if ( bEditMode && (mrViewData.GetRefTabNo() == mrViewData.GetTabNo()) )
2446 {
2447 Point aPos = rMEvt.GetPosPixel();
2448 SCCOL nPosX;
2449 SCROW nPosY;
2450 mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
2451
2452 EditView* pEditView;
2453 SCCOL nEditCol;
2454 SCROW nEditRow;
2455 mrViewData.GetEditView( eWhich, pEditView, nEditCol, nEditRow );
2456 SCCOL nEndCol = mrViewData.GetEditEndCol();
2457 SCROW nEndRow = mrViewData.GetEditEndRow();
2458
2459 if ( nPosX >= nEditCol && nPosX <= nEndCol &&
2460 nPosY >= nEditRow && nPosY <= nEndRow )
2461 {
2462 if ( !pEditView )
2463 {
2464 SetPointer( PointerStyle::Text );
2465 return;
2466 }
2467
2468 const SvxFieldItem* pFld;
2469 if ( comphelper::LibreOfficeKit::isActive() )
2470 {
2471 Point aLogicClick = pEditView->GetWindow()->PixelToLogic( aPos );
2472 pFld = pEditView->GetField( aLogicClick );
2473 }
2474 else
2475 {
2476 pFld = pEditView->GetFieldUnderMousePointer();
2477 }
2478 // Field can only be URL field
2479 bool bAlt = rMEvt.IsMod2();
2480 if ( !bAlt && !nButtonDown && ScGlobal::ShouldOpenURL() && pFld )
2481 SetPointer( PointerStyle::RefHand );
2482 else if ( pEditView->GetEditEngine()->IsVertical() )
2483 SetPointer( PointerStyle::TextVertical );
2484 else
2485 SetPointer( PointerStyle::Text );
2486 return;
2487 }
2488 }
2489
2490 bool bWater = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->GetIsWaterCan() || mrViewData.GetView()->HasPaintBrush();
2491 if (bWater)
2492 SetPointer( PointerStyle::Fill );
2493
2494 if (!bWater)
2495 {
2496 bool bCross = false;
2497
2498 // range finder
2499
2500 RfCorner rCorner = NONE;
2501 if ( HitRangeFinder( rMEvt.GetPosPixel(), rCorner, nullptr, nullptr, nullptr ) )
2502 {
2503 if (rCorner != NONE)
2504 SetPointer( PointerStyle::Cross );
2505 else
2506 SetPointer( PointerStyle::Hand );
2507 bCross = true;
2508 }
2509
2510 // Page-Break-Mode
2511
2512 if ( !nButtonDown && mrViewData.IsPagebreakMode() )
2513 {
2514 sal_uInt16 nBreakType = HitPageBreak( rMEvt.GetPosPixel(), nullptr, nullptr, nullptr );
2515 if (nBreakType != 0 )
2516 {
2517 PointerStyle eNew = PointerStyle::Arrow;
2518 switch ( nBreakType )
2519 {
2520 case SC_PD_RANGE_L1:
2521 case SC_PD_RANGE_R2:
2522 case SC_PD_BREAK_H16:
2523 eNew = PointerStyle::ESize;
2524 break;
2525 case SC_PD_RANGE_T4:
2526 case SC_PD_RANGE_B8:
2527 case SC_PD_BREAK_V32:
2528 eNew = PointerStyle::SSize;
2529 break;
2530 case SC_PD_RANGE_TL(4|1):
2531 case SC_PD_RANGE_BR(8|2):
2532 eNew = PointerStyle::SESize;
2533 break;
2534 case SC_PD_RANGE_TR(4|2):
2535 case SC_PD_RANGE_BL(8|1):
2536 eNew = PointerStyle::NESize;
2537 break;
2538 }
2539 SetPointer( eNew );
2540 bCross = true;
2541 }
2542 }
2543
2544 // Show fill cursor?
2545
2546 if ( !bFormulaMode && !nButtonDown )
2547 if (TestMouse( rMEvt, false ))
2548 bCross = true;
2549
2550 if ( nButtonDown && mrViewData.IsAnyFillMode() )
2551 {
2552 SetPointer( PointerStyle::Cross );
2553 bCross = true;
2554 nScFillModeMouseModifier = rMEvt.GetModifier(); // evaluated for AutoFill and Matrix
2555 }
2556
2557 if (!bCross)
2558 {
2559 bool bAlt = rMEvt.IsMod2();
2560
2561 if (bEditMode) // First has to be in edit mode!
2562 SetPointer( PointerStyle::Arrow );
2563 else if ( !bAlt && !nButtonDown && ScGlobal::ShouldOpenURL() &&
2564 GetEditUrl(rMEvt.GetPosPixel()) )
2565 SetPointer( PointerStyle::RefHand );
2566 else if ( DrawMouseMove(rMEvt) ) // Reset pointer
2567 return;
2568 }
2569 }
2570
2571 if ( mrViewData.GetView()->GetSelEngine()->SelMouseMove( rMEvt ) )
2572 return;
2573}
2574
2575static void lcl_InitMouseEvent(css::awt::MouseEvent& rEvent, const MouseEvent& rEvt)
2576{
2577 rEvent.Modifiers = 0;
2578 if ( rEvt.IsShift() )
2579 rEvent.Modifiers |= css::awt::KeyModifier::SHIFT;
2580 if ( rEvt.IsMod1() )
2581 rEvent.Modifiers |= css::awt::KeyModifier::MOD1;
2582 if ( rEvt.IsMod2() )
2583 rEvent.Modifiers |= css::awt::KeyModifier::MOD2;
2584 if ( rEvt.IsMod3() )
2585 rEvent.Modifiers |= css::awt::KeyModifier::MOD3;
2586
2587 rEvent.Buttons = 0;
2588 if ( rEvt.IsLeft() )
2589 rEvent.Buttons |= css::awt::MouseButton::LEFT;
2590 if ( rEvt.IsRight() )
2591 rEvent.Buttons |= css::awt::MouseButton::RIGHT;
2592 if ( rEvt.IsMiddle() )
2593 rEvent.Buttons |= css::awt::MouseButton::MIDDLE;
2594
2595 rEvent.X = rEvt.GetPosPixel().X();
2596 rEvent.Y = rEvt.GetPosPixel().Y();
2597 rEvent.ClickCount = rEvt.GetClicks();
2598 rEvent.PopupTrigger = false;
2599}
2600
2601bool ScGridWindow::PreNotify( NotifyEvent& rNEvt )
2602{
2603 bool bDone = false;
2604 MouseNotifyEvent nType = rNEvt.GetType();
2605 if ( nType == MouseNotifyEvent::MOUSEBUTTONUP || nType == MouseNotifyEvent::MOUSEBUTTONDOWN )
2606 {
2607 vcl::Window* pWindow = rNEvt.GetWindow();
2608 if (pWindow == this)
2609 {
2610 SfxViewFrame* pViewFrame = mrViewData.GetViewShell()->GetViewFrame();
2611 if (pViewFrame)
2612 {
2613 css::uno::Reference<css::frame::XController> xController = pViewFrame->GetFrame().GetController();
2614 if (xController.is())
2615 {
2616 ScTabViewObj* pImp = comphelper::getUnoTunnelImplementation<ScTabViewObj>( xController );
2617 if (pImp && pImp->IsMouseListening())
2618 {
2619 css::awt::MouseEvent aEvent;
2620 lcl_InitMouseEvent( aEvent, *rNEvt.GetMouseEvent() );
2621 if ( rNEvt.GetWindow() )
2622 aEvent.Source = rNEvt.GetWindow()->GetComponentInterface();
2623 if ( nType == MouseNotifyEvent::MOUSEBUTTONDOWN)
2624 bDone = pImp->MousePressed( aEvent );
2625 else
2626 bDone = pImp->MouseReleased( aEvent );
2627 }
2628 }
2629 }
2630 }
2631 }
2632 if (bDone) // event consumed by a listener
2633 {
2634 if ( nType == MouseNotifyEvent::MOUSEBUTTONDOWN )
2635 {
2636 const MouseEvent* pMouseEvent = rNEvt.GetMouseEvent();
2637 if ( pMouseEvent->IsRight() && pMouseEvent->GetClicks() == 1 )
2638 {
2639 // If a listener returned true for a right-click call, also prevent opening the context menu
2640 // (this works only if the context menu is opened on mouse-down)
2641 nMouseStatus = SC_GM_IGNORE4;
2642 }
2643 }
2644
2645 return true;
2646 }
2647 else
2648 return Window::PreNotify( rNEvt );
2649}
2650
2651void ScGridWindow::Tracking( const TrackingEvent& rTEvt )
2652{
2653 // Since the SelectionEngine does not track, the events have to be
2654 // handed to the different MouseHandler...
2655
2656 const MouseEvent& rMEvt = rTEvt.GetMouseEvent();
2657
2658 if ( rTEvt.IsTrackingCanceled() ) // Cancel everything...
2659 {
2660 if (!mrViewData.GetView()->IsInActivatePart() && !SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->IsRefDialogOpen())
2661 {
2662 if (bDPMouse)
2663 bDPMouse = false; // Paint for each bDragRect
2664 if (bDragRect)
2665 {
2666 bDragRect = false;
2667 UpdateDragRectOverlay();
2668 }
2669 if (bRFMouse)
2670 {
2671 RFMouseMove( rMEvt, true ); // Not possible to cancel properly...
2672 bRFMouse = false;
2673 }
2674 if (nPagebreakMouse)
2675 {
2676 bPagebreakDrawn = false;
2677 UpdateDragRectOverlay();
2678 nPagebreakMouse = SC_PD_NONE0;
2679 }
2680
2681 SetPointer( PointerStyle::Arrow );
2682 StopMarking();
2683 MouseButtonUp( rMEvt ); // With status SC_GM_IGNORE from StopMarking
2684
2685 bool bRefMode = mrViewData.IsRefMode();
2686 if (bRefMode)
2687 SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->EndReference(); // Do not let the Dialog remain minimized
2688 }
2689 }
2690 else if ( rTEvt.IsTrackingEnded() )
2691 {
2692 if ( !comphelper::LibreOfficeKit::isActive() )
2693 {
2694 // MouseButtonUp always with matching buttons (eg for test tool, # 63148 #)
2695 // The tracking event will indicate if it was completed and not canceled.
2696 MouseEvent aUpEvt( rMEvt.GetPosPixel(), rMEvt.GetClicks(),
2697 rMEvt.GetMode(), nButtonDown, rMEvt.GetModifier() );
2698 MouseButtonUp( aUpEvt );
2699 }
2700 }
2701 else if ( !comphelper::LibreOfficeKit::isActive() )
2702 MouseMove( rMEvt );
2703}
2704
2705void ScGridWindow::StartDrag( sal_Int8 /* nAction */, const Point& rPosPixel )
2706{
2707 if (mpFilterBox || nPagebreakMouse)
2708 return;
2709
2710 HideNoteMarker();
2711
2712 CommandEvent aDragEvent( rPosPixel, CommandEventId::StartDrag, true );
2713
2714 if (bEEMouse && mrViewData.HasEditView( eWhich ))
2715 {
2716 EditView* pEditView;
2717 SCCOL nEditCol;
2718 SCROW nEditRow;
2719 mrViewData.GetEditView( eWhich, pEditView, nEditCol, nEditRow );
2720
2721 // don't remove the edit view while switching views
2722 ScModule* pScMod = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
;
2723 pScMod->SetInEditCommand( true );
2724
2725 pEditView->Command( aDragEvent );
2726
2727 ScInputHandler* pHdl = pScMod->GetInputHdl();
2728 if (pHdl)
2729 pHdl->DataChanged();
2730
2731 pScMod->SetInEditCommand( false );
2732 if (!mrViewData.IsActive()) // dropped to different view?
2733 {
2734 ScInputHandler* pViewHdl = pScMod->GetInputHdl( mrViewData.GetViewShell() );
2735 if ( pViewHdl && mrViewData.HasEditView( eWhich ) )
2736 {
2737 pViewHdl->CancelHandler();
2738 ShowCursor(); // missing from KillEditView
2739 }
2740 }
2741 }
2742 else
2743 if ( !DrawCommand(aDragEvent) )
2744 mrViewData.GetView()->GetSelEngine()->Command( aDragEvent );
2745}
2746
2747static void lcl_SetTextCursorPos( ScViewData& rViewData, ScSplitPos eWhich, vcl::Window* pWin )
2748{
2749 SCCOL nCol = rViewData.GetCurX();
2750 SCROW nRow = rViewData.GetCurY();
2751 tools::Rectangle aEditArea = rViewData.GetEditArea( eWhich, nCol, nRow, pWin, nullptr, true );
2752 aEditArea.SetRight( aEditArea.Left() );
2753 aEditArea = pWin->PixelToLogic( aEditArea );
2754 pWin->SetCursorRect( &aEditArea );
2755}
2756
2757void ScGridWindow::Command( const CommandEvent& rCEvt )
2758{
2759 // The command event is send to the window after a possible context
2760 // menu from an inplace client is closed. Now we have the chance to
2761 // deactivate the inplace client without any problem regarding parent
2762 // windows and code on the stack.
2763 CommandEventId nCmd = rCEvt.GetCommand();
2764 ScTabViewShell* pTabViewSh = mrViewData.GetViewShell();
2765 SfxInPlaceClient* pClient = pTabViewSh->GetIPClient();
2766 if ( pClient &&
2767 pClient->IsObjectInPlaceActive() &&
2768 nCmd == CommandEventId::ContextMenu )
2769 {
2770 pTabViewSh->DeactivateOle();
2771 return;
2772 }
2773
2774 ScModule* pScMod = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
;
2775 OSL_ENSURE( nCmd != CommandEventId::StartDrag, "ScGridWindow::Command called with CommandEventId::StartDrag" )do { if (true && (!(nCmd != CommandEventId::StartDrag
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sc/source/ui/view/gridwin.cxx"
":" "2775" ": "), "%s", "ScGridWindow::Command called with CommandEventId::StartDrag"
); } } while (false)
;
2776
2777 if (nCmd == CommandEventId::ModKeyChange)
2778 {
2779 Window::Command(rCEvt);
2780 return;
2781 }
2782
2783 if ( nCmd == CommandEventId::StartExtTextInput ||
2784 nCmd == CommandEventId::EndExtTextInput ||
2785 nCmd == CommandEventId::ExtTextInput ||
2786 nCmd == CommandEventId::CursorPos ||
2787 nCmd == CommandEventId::QueryCharPosition )
2788 {
2789 bool bEditView = mrViewData.HasEditView( eWhich );
2790 if (!bEditView)
2791 {
2792 // only if no cell editview is active, look at drawview
2793 SdrView* pSdrView = mrViewData.GetView()->GetScDrawView();
2794 if ( pSdrView )
2795 {
2796 OutlinerView* pOlView = pSdrView->GetTextEditOutlinerView();
2797 if ( pOlView && pOlView->GetWindow() == this )
2798 {
2799 pOlView->Command( rCEvt );
2800 return; // done
2801 }
2802 }
2803 }
2804
2805 if ( nCmd == CommandEventId::CursorPos && !bEditView )
2806 {
2807 // CURSORPOS may be called without following text input,
2808 // to set the input method window position
2809 // -> input mode must not be started,
2810 // manually calculate text insert position if not in input mode
2811
2812 lcl_SetTextCursorPos( mrViewData, eWhich, this );
2813 return;
2814 }
2815
2816 ScInputHandler* pHdl = pScMod->GetInputHdl( mrViewData.GetViewShell() );
2817 if ( pHdl )
2818 {
2819 pHdl->InputCommand( rCEvt );
2820 return; // done
2821 }
2822
2823 Window::Command( rCEvt );
2824 return;
2825 }
2826
2827 if ( nCmd == CommandEventId::PasteSelection )
2828 {
2829 if ( bEEMouse )
2830 {
2831 // EditEngine handles selection in MouseButtonUp - no action
2832 // needed in command handler
2833 }
2834 else
2835 {
2836 PasteSelection( rCEvt.GetMousePosPixel() );
2837 }
2838 return;
2839 }
2840
2841 if ( nCmd == CommandEventId::InputLanguageChange )
2842 {
2843 // #i55929# Font and font size state depends on input language if nothing is selected,
2844 // so the slots have to be invalidated when the input language is changed.
2845
2846 SfxBindings& rBindings = mrViewData.GetBindings();
2847 rBindings.Invalidate( SID_ATTR_CHAR_FONT( 10000 + 7 ) );
2848 rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT( 10000 + 15 ) );
2849 return;
2850 }
2851
2852 if ( nCmd == CommandEventId::Wheel || nCmd == CommandEventId::StartAutoScroll || nCmd == CommandEventId::AutoScroll )
2853 {
2854 bool bDone = mrViewData.GetView()->ScrollCommand( rCEvt, eWhich );
2855 if (!bDone)
2856 Window::Command(rCEvt);
2857 return;
2858 }
2859 // #i7560# FormulaMode check is below scrolling - scrolling is allowed during formula input
2860 bool bDisable = pScMod->IsFormulaMode() ||
2861 pScMod->IsModalMode(mrViewData.GetSfxDocShell());
2862 if (bDisable)
2863 return;
2864
2865 if (nCmd != CommandEventId::ContextMenu || SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->GetIsWaterCan())
2866 return;
2867
2868 bool bMouse = rCEvt.IsMouseEvent();
2869 if ( bMouse && nMouseStatus == SC_GM_IGNORE4 )
2870 return;
2871
2872 if (mrViewData.IsAnyFillMode())
2873 {
2874 mrViewData.GetView()->StopRefMode();
2875 mrViewData.ResetFillMode();
2876 }
2877 ReleaseMouse();
2878 StopMarking();
2879
2880 Point aPosPixel = rCEvt.GetMousePosPixel();
2881 Point aMenuPos = aPosPixel;
2882
2883 SCCOL nCellX = -1;
2884 SCROW nCellY = -1;
2885 mrViewData.GetPosFromPixel(aPosPixel.X(), aPosPixel.Y(), eWhich, nCellX, nCellY);
2886
2887 bool bSpellError = false;
2888 SCCOL nColSpellError = nCellX;
2889
2890 if ( bMouse )
2891 {
2892 ScDocument& rDoc = mrViewData.GetDocument();
2893 SCTAB nTab = mrViewData.GetTabNo();
2894 const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab);
2895 bool bSelectAllowed = true;
2896 if ( pProtect && pProtect->isProtected() )
2897 {
2898 // This sheet is protected. Check if a context menu is allowed on this cell.
2899 bool bCellProtected = rDoc.HasAttrib(nCellX, nCellY, nTab, nCellX, nCellY, nTab, HasAttrFlags::Protected);
2900 bool bSelProtected = pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
2901 bool bSelUnprotected = pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
2902
2903 if (bCellProtected)
2904 bSelectAllowed = bSelProtected;
2905 else
2906 bSelectAllowed = bSelUnprotected;
2907 }
2908 if (!bSelectAllowed)
2909 // Selecting this cell is not allowed, neither is context menu.
2910 return;
2911
2912 if (mpSpellCheckCxt)
2913 {
2914 // Find the first string to the left for spell checking in case the current cell is empty.
2915 ScAddress aPos(nCellX, nCellY, nTab);
2916 ScRefCellValue aSpellCheckCell(rDoc, aPos);
2917 while (aSpellCheckCell.meType == CELLTYPE_NONE)
2918 {
2919 // Loop until we get the first non-empty cell in the row.
2920 aPos.IncCol(-1);
2921 if (aPos.Col() < 0)
2922 break;
2923
2924 aSpellCheckCell.assign(rDoc, aPos);
2925 }
2926
2927 if (aPos.Col() >= 0 && (aSpellCheckCell.meType == CELLTYPE_STRING || aSpellCheckCell.meType == CELLTYPE_EDIT))
2928 nColSpellError = aPos.Col();
2929
2930 bSpellError = (mpSpellCheckCxt->isMisspelled(nColSpellError, nCellY));
2931 if (bSpellError)
2932 {
2933 // Check and see if a misspelled word is under the mouse pointer.
2934 bSpellError = IsSpellErrorAtPos(aPosPixel, nColSpellError, nCellY);
2935 }
2936 }
2937
2938 // #i18735# First select the item under the mouse pointer.
2939 // This can change the selection, and the view state (edit mode, etc).
2940 SelectForContextMenu(aPosPixel, bSpellError ? nColSpellError : nCellX, nCellY);
2941 }
2942
2943 bool bDone = false;
2944 bool bEdit = mrViewData.HasEditView(eWhich);
2945
2946 if ( !bEdit )
2947 {
2948 // Edit cell with spelling errors ?
2949 if (bMouse && (GetEditUrl(aPosPixel) || bSpellError))
2950 {
2951 // GetEditUrlOrError has already moved the Cursor
2952
2953 pScMod->SetInputMode( SC_INPUT_TABLE );
2954 bEdit = mrViewData.HasEditView(eWhich); // Did it work?
2955
2956 OSL_ENSURE( bEdit, "Can not be switched in edit mode" )do { if (true && (!(bEdit))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/ui/view/gridwin.cxx"
":" "2956" ": "), "%s", "Can not be switched in edit mode");
} } while (false)
;
2957 }
2958 }
2959 if ( bEdit )
2960 {
2961 EditView* pEditView = mrViewData.GetEditView( eWhich ); // is then not 0
2962
2963 if ( !bMouse )
2964 {
2965 vcl::Cursor* pCur = pEditView->GetCursor();
2966 if ( pCur )
2967 {
2968 Point aLogicPos = pCur->GetPos();
2969 // use the position right of the cursor (spell popup is opened if
2970 // the cursor is before the word, but not if behind it)
2971 aLogicPos.AdjustX(pCur->GetWidth() );
2972 aLogicPos.AdjustY(pCur->GetHeight() / 2 ); // center vertically
2973 aMenuPos = LogicToPixel( aLogicPos );
2974 }
2975 }
2976
2977 // if edit mode was just started above, online spelling may be incomplete
2978 pEditView->GetEditEngine()->CompleteOnlineSpelling();
2979
2980 // IsCursorAtWrongSpelledWord could be used for !bMouse
2981 // if there was a corresponding ExecuteSpellPopup call
2982
2983 if (bSpellError)
2984 {
2985 // On OS/2 when clicking next to the Popup menu, the MouseButtonDown
2986 // comes before the end of menu execute, thus the SetModified has to
2987 // be done prior to this (Bug #40968#)
2988 ScInputHandler* pHdl = pScMod->GetInputHdl();
2989 if (pHdl)
2990 pHdl->SetModified();
2991
2992 Link<SpellCallbackInfo&,void> aLink = LINK( this, ScGridWindow, PopupSpellingHdl )::tools::detail::makeLink( ::tools::detail::castTo<ScGridWindow
*>(this), &ScGridWindow::LinkStubPopupSpellingHdl)
;
2993 pEditView->ExecuteSpellPopup( aMenuPos, &aLink );
2994
2995 bDone = true;
2996 }
2997 }
2998 else if ( !bMouse )
2999 {
3000 // non-edit menu by keyboard -> use lower right of cell cursor position
3001 ScDocument& rDoc = mrViewData.GetDocument();
3002 SCTAB nTabNo = mrViewData.GetTabNo();
3003 bool bLayoutIsRTL = rDoc.IsLayoutRTL(nTabNo);
3004
3005 SCCOL nCurX = mrViewData.GetCurX();
3006 SCROW nCurY = mrViewData.GetCurY();
3007 aMenuPos = mrViewData.GetScrPos( nCurX, nCurY, eWhich, true );
3008 long nSizeXPix;
3009 long nSizeYPix;
3010 mrViewData.GetMergeSizePixel( nCurX, nCurY, nSizeXPix, nSizeYPix );
3011 // fdo#55432 take the correct position for RTL sheet
3012 aMenuPos.AdjustX(bLayoutIsRTL ? -nSizeXPix : nSizeXPix );
3013 aMenuPos.AdjustY(nSizeYPix );
3014
3015 ScTabViewShell* pViewSh = mrViewData.GetViewShell();
3016 if (pViewSh)
3017 {
3018 // Is a draw object selected?
3019
3020 SdrView* pDrawView = pViewSh->GetScDrawView();
3021 if (pDrawView && pDrawView->AreObjectsMarked())
3022 {
3023 // #100442#; the context menu should open in the middle of the selected objects
3024 tools::Rectangle aSelectRect(LogicToPixel(pDrawView->GetAllMarkedBoundRect()));
3025 aMenuPos = aSelectRect.Center();
3026 }
3027 }
3028 }
3029
3030 if (!bDone)
3031 {
3032 SfxDispatcher::ExecutePopup( this, &aMenuPos );
3033 }
3034}
3035
3036void ScGridWindow::SelectForContextMenu( const Point& rPosPixel, SCCOL nCellX, SCROW nCellY )
3037{
3038 // #i18735# if the click was outside of the current selection,
3039 // the cursor is moved or an object at the click position selected.
3040 // (see SwEditWin::SelectMenuPosition in Writer)
3041
3042 ScTabView* pView = mrViewData.GetView();
3043 ScDrawView* pDrawView = pView->GetScDrawView();
3044
3045 // check cell edit mode
3046
3047 if ( mrViewData.HasEditView(eWhich) )
3048 {
3049 ScModule* pScMod = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
;
3050 SCCOL nEditStartCol = mrViewData.GetEditViewCol(); //! change to GetEditStartCol after calcrtl is integrated
3051 SCROW nEditStartRow = mrViewData.GetEditViewRow();
3052 SCCOL nEditEndCol = mrViewData.GetEditEndCol();
3053 SCROW nEditEndRow = mrViewData.GetEditEndRow();
3054
3055 if ( nCellX >= nEditStartCol && nCellX <= nEditEndCol &&
3056 nCellY >= nEditStartRow && nCellY <= nEditEndRow )
3057 {
3058 // handle selection within the EditView
3059
3060 EditView* pEditView = mrViewData.GetEditView( eWhich ); // not NULL (HasEditView)
3061 EditEngine* pEditEngine = pEditView->GetEditEngine();
3062 tools::Rectangle aOutputArea = pEditView->GetOutputArea();
3063 tools::Rectangle aVisArea = pEditView->GetVisArea();
3064
3065 Point aTextPos = PixelToLogic( rPosPixel );
3066 if ( pEditEngine->IsVertical() ) // have to manually transform position
3067 {
3068 aTextPos -= aOutputArea.TopRight();
3069 long nTemp = -aTextPos.X();
3070 aTextPos.setX( aTextPos.Y() );
3071 aTextPos.setY( nTemp );
3072 }
3073 else
3074 aTextPos -= aOutputArea.TopLeft();
3075 aTextPos += aVisArea.TopLeft(); // position in the edit document
3076
3077 EPosition aDocPosition = pEditEngine->FindDocPosition(aTextPos);
3078 ESelection aCompare(aDocPosition.nPara, aDocPosition.nIndex);
3079 ESelection aSelection = pEditView->GetSelection();
3080 aSelection.Adjust(); // needed for IsLess/IsGreater
3081 if ( aCompare < aSelection || aCompare > aSelection )
3082 {
3083 // clicked outside the selected text - deselect and move text cursor
3084 MouseEvent aEvent( rPosPixel );
3085 pEditView->MouseButtonDown( aEvent );
3086 pEditView->MouseButtonUp( aEvent );
3087 pScMod->InputSelection( pEditView );
3088 }
3089
3090 return; // clicked within the edit view - keep edit mode
3091 }
3092 else
3093 {
3094 // outside of the edit view - end edit mode, regardless of cell selection, then continue
3095 pScMod->InputEnterHandler();
3096 }
3097 }
3098
3099 // check draw text edit mode
3100
3101 Point aLogicPos = PixelToLogic( rPosPixel ); // after cell edit mode is ended
3102 if ( pDrawView && pDrawView->GetTextEditObject() && pDrawView->GetTextEditOutlinerView() )
3103 {
3104 OutlinerView* pOlView = pDrawView->GetTextEditOutlinerView();
3105 tools::Rectangle aOutputArea = pOlView->GetOutputArea();
3106 if ( aOutputArea.IsInside( aLogicPos ) )
3107 {
3108 // handle selection within the OutlinerView
3109
3110 Outliner* pOutliner = pOlView->GetOutliner();
3111 const EditEngine& rEditEngine = pOutliner->GetEditEngine();
3112 tools::Rectangle aVisArea = pOlView->GetVisArea();
3113
3114 Point aTextPos = aLogicPos;
3115 if ( pOutliner->IsVertical() ) // have to manually transform position
3116 {
3117 aTextPos -= aOutputArea.TopRight();
3118 long nTemp = -aTextPos.X();
3119 aTextPos.setX( aTextPos.Y() );
3120 aTextPos.setY( nTemp );
3121 }
3122 else
3123 aTextPos -= aOutputArea.TopLeft();
3124 aTextPos += aVisArea.TopLeft(); // position in the edit document
3125
3126 EPosition aDocPosition = rEditEngine.FindDocPosition(aTextPos);
3127 ESelection aCompare(aDocPosition.nPara, aDocPosition.nIndex);
3128 ESelection aSelection = pOlView->GetSelection();
3129 aSelection.Adjust(); // needed for IsLess/IsGreater
3130 if ( aCompare < aSelection || aCompare > aSelection )
3131 {
3132 // clicked outside the selected text - deselect and move text cursor
3133 // use DrawView to allow extra handling there (none currently)
3134 MouseEvent aEvent( rPosPixel );
3135 pDrawView->MouseButtonDown( aEvent, this );
3136 pDrawView->MouseButtonUp( aEvent, this );
3137 }
3138
3139 return; // clicked within the edit area - keep edit mode
3140 }
3141 else
3142 {
3143 // Outside of the edit area - end text edit mode, then continue.
3144 // DrawDeselectAll also ends text edit mode and updates the shells.
3145 // If the click was on the edited object, it will be selected again below.
3146 pView->DrawDeselectAll();
3147 }
3148 }
3149
3150 // look for existing selection
3151
3152 bool bHitSelected = false;
3153 if ( pDrawView && pDrawView->IsMarkedObjHit( aLogicPos ) )
3154 {
3155 // clicked on selected object -> don't change anything
3156 bHitSelected = true;
3157 }
3158 else if ( mrViewData.GetMarkData().IsCellMarked(nCellX, nCellY) )
3159 {
3160 // clicked on selected cell -> don't change anything
3161 bHitSelected = true;
3162 }
3163
3164 // select drawing object or move cell cursor
3165
3166 if ( bHitSelected )
3167 return;
3168
3169 bool bWasDraw = ( pDrawView && pDrawView->AreObjectsMarked() );
3170 bool bHitDraw = false;
3171 if ( pDrawView )
3172 {
3173 pDrawView->UnmarkAllObj();
3174 // Unlock the Internal Layer in order to activate the context menu.
3175 // re-lock in ScDrawView::MarkListHasChanged()
3176 lcl_UnLockComment(pDrawView, aLogicPos, mrViewData);
3177 bHitDraw = pDrawView->MarkObj( aLogicPos );
3178 // draw shell is activated in MarkListHasChanged
3179 }
3180 if ( !bHitDraw )
3181 {
3182 pView->Unmark();
3183 pView->SetCursor(nCellX, nCellY);
3184 if ( bWasDraw )
3185 mrViewData.GetViewShell()->SetDrawShell( false ); // switch shells
3186 }
3187}
3188
3189void ScGridWindow::KeyInput(const KeyEvent& rKEvt)
3190{
3191 // Cursor control for ref input dialog
3192 const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
3193
3194#ifdef DBG_UTIL
3195
3196 if (rKeyCode.IsMod1() && rKeyCode.IsShift())
3197 {
3198 if (rKeyCode.GetCode() == KEY_F12)
3199 {
3200 dumpColumnInformationPixel();
3201 }
3202 else if (rKeyCode.GetCode() == KEY_F11)
3203 {
3204 dumpGraphicInformation();
3205 }
3206 else if (rKeyCode.GetCode() == KEY_F10)
3207 {
3208 dumpColumnInformationHmm();
3209 }
3210 else if (rKeyCode.GetCode() == KEY_F6)
3211 {
3212 dumpCellProperties();
3213 }
3214 else if (rKeyCode.GetCode() == KEY_F8)
3215 {
3216 dumpColumnCellStorage();
3217 }
3218 else if (rKeyCode.GetCode() == KEY_F7)
3219 {
3220 ScDocument& rDoc = mrViewData.GetDocument();
3221 auto& rMapper = rDoc.GetExternalDataMapper();
3222 for (auto& itr : rMapper.getDataSources())
3223 {
3224 itr.refresh(&rDoc);
3225 }
3226 return;
3227 }
3228 }
3229
3230#endif
3231
3232 if( SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->IsRefDialogOpen() )
3233 {
3234 if( !rKeyCode.GetModifier() && (rKeyCode.GetCode() == KEY_F2) )
3235 {
3236 SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->EndReference();
3237 }
3238 else if( mrViewData.GetViewShell()->MoveCursorKeyInput( rKEvt ) )
3239 {
3240 ScRange aRef(
3241 mrViewData.GetRefStartX(), mrViewData.GetRefStartY(), mrViewData.GetRefStartZ(),
3242 mrViewData.GetRefEndX(), mrViewData.GetRefEndY(), mrViewData.GetRefEndZ() );
3243 SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->SetReference( aRef, mrViewData.GetDocument() );
3244 }
3245 mrViewData.GetViewShell()->SelectionChanged();
3246 return ;
3247 }
3248 else if( rKeyCode.GetCode() == KEY_RETURN && mrViewData.IsPasteMode() )
3249 {
3250 ScTabViewShell* pTabViewShell = mrViewData.GetViewShell();
3251 ScClipUtil::PasteFromClipboard( &mrViewData, pTabViewShell, true );
3252
3253 // Clear clipboard content.
3254 uno::Reference<datatransfer::clipboard::XClipboard> xSystemClipboard =
3255 GetClipboard();
3256 if (xSystemClipboard.is())
3257 {
3258 xSystemClipboard->setContents(
3259 uno::Reference<datatransfer::XTransferable>(),
3260 uno::Reference<datatransfer::clipboard::XClipboardOwner>());
3261 }
3262
3263 // hide the border around the copy source
3264 mrViewData.SetPasteMode( ScPasteFlags::NONE );
3265 // Clear CopySourceOverlay in each window of a split/frozen tabview
3266 mrViewData.GetView()->UpdateCopySourceOverlay();
3267 return;
3268 }
3269 // if semi-modeless SfxChildWindow dialog above, then no KeyInputs:
3270 else if( !mrViewData.IsAnyFillMode() )
3271 {
3272 if (rKeyCode.GetCode() == KEY_ESCAPE)
3273 {
3274 mrViewData.SetPasteMode( ScPasteFlags::NONE );
3275 // Clear CopySourceOverlay in each window of a split/frozen tabview
3276 mrViewData.GetView()->UpdateCopySourceOverlay();
3277 }
3278 // query for existing note marker before calling ViewShell's keyboard handling
3279 // which may remove the marker
3280 bool bHadKeyMarker = mpNoteMarker && mpNoteMarker->IsByKeyboard();
3281 ScTabViewShell* pViewSh = mrViewData.GetViewShell();
3282
3283 if (mrViewData.GetDocShell()->GetProgress())
3284 return;
3285
3286 if (DrawKeyInput(rKEvt))
3287 {
3288 const vcl::KeyCode& rLclKeyCode = rKEvt.GetKeyCode();
3289 if (rLclKeyCode.GetCode() == KEY_DOWN
3290 || rLclKeyCode.GetCode() == KEY_UP
3291 || rLclKeyCode.GetCode() == KEY_LEFT
3292 || rLclKeyCode.GetCode() == KEY_RIGHT)
3293 {
3294 ScTabViewShell* pViewShell = mrViewData.GetViewShell();
3295 SfxBindings& rBindings = pViewShell->GetViewFrame()->GetBindings();
3296 rBindings.Invalidate(SID_ATTR_TRANSFORM_POS_XTypedWhichId<SfxInt32Item>( 10000 + 88 ));
3297 rBindings.Invalidate(SID_ATTR_TRANSFORM_POS_YTypedWhichId<SfxInt32Item>( 10000 + 89 ));
3298 }
3299 return;
3300 }
3301
3302 if (!mrViewData.GetView()->IsDrawSelMode() && !DrawHasMarkedObj()) // No entries in draw mode
3303 { //! check DrawShell !!!
3304 if (pViewSh->TabKeyInput(rKEvt))
3305 return;
3306 }
3307 else
3308 if (pViewSh->SfxViewShell::KeyInput(rKEvt)) // from SfxViewShell
3309 return;
3310
3311 vcl::KeyCode aCode = rKEvt.GetKeyCode();
3312 if ( aCode.GetCode() == KEY_ESCAPE && aCode.GetModifier() == 0 )
3313 {
3314 if ( bHadKeyMarker )
3315 HideNoteMarker();
3316 else
3317 pViewSh->Escape();
3318 return;
3319 }
3320 if ( aCode.GetCode() == KEY_F1 && aCode.GetModifier() == KEY_MOD1 )
3321 {
3322 // ctrl-F1 shows or hides the note or redlining info for the cursor position
3323 // (hard-coded because F1 can't be configured)
3324
3325 if ( bHadKeyMarker )
3326 HideNoteMarker(); // hide when previously visible
3327 else
3328 ShowNoteMarker( mrViewData.GetCurX(), mrViewData.GetCurY(), true );
3329 return;
3330 }
3331 if (aCode.GetCode() == KEY_BRACKETLEFT && aCode.GetModifier() == KEY_MOD1)
3332 {
3333 pViewSh->DetectiveMarkPred();
3334 return;
3335 }
3336 if (aCode.GetCode() == KEY_BRACKETRIGHT && aCode.GetModifier() == KEY_MOD1)
3337 {
3338 pViewSh->DetectiveMarkSucc();
3339 return;
3340 }
3341
3342 }
3343
3344 Window::KeyInput(rKEvt);
3345}
3346
3347void ScGridWindow::StopMarking()
3348{
3349 DrawEndAction(); // Cancel Select/move on Drawing-Layer
3350
3351 if (nButtonDown)
3352 {
3353 mrViewData.GetMarkData().SetMarking(false);
3354 nMouseStatus = SC_GM_IGNORE4;
3355 }
3356}
3357
3358void ScGridWindow::UpdateInputContext()
3359{
3360 bool bReadOnly = mrViewData.GetDocShell()->IsReadOnly();
3361 InputContextFlags nOptions = bReadOnly ? InputContextFlags::NONE : ( InputContextFlags::Text | InputContextFlags::ExtText );
3362
3363 // when font from InputContext is used,
3364 // it must be taken from the cursor position's cell attributes
3365
3366 InputContext aContext;
3367 aContext.SetOptions( nOptions );
3368 SetInputContext( aContext );
3369}
3370
3371 // sensitive range (Pixel)
3372#define SCROLL_SENSITIVE20 20
3373
3374void ScGridWindow::DropScroll( const Point& rMousePos )
3375{
3376 ScDocument& rDoc = mrViewData.GetDocument();
3377 SCCOL nDx = 0;
3378 SCROW nDy = 0;
3379 Size aSize = GetOutputSizePixel();
3380
3381 if (aSize.Width() > SCROLL_SENSITIVE20 * 3)
3382 {
3383 if ( rMousePos.X() < SCROLL_SENSITIVE20 && mrViewData.GetPosX(WhichH(eWhich)) > 0 )
3384 nDx = -1;
3385 if ( rMousePos.X() >= aSize.Width() - SCROLL_SENSITIVE20
3386 && mrViewData.GetPosX(WhichH(eWhich)) < rDoc.MaxCol() )
3387 nDx = 1;
3388 }
3389 if (aSize.Height() > SCROLL_SENSITIVE20 * 3)
3390 {
3391 if ( rMousePos.Y() < SCROLL_SENSITIVE20 && mrViewData.GetPosY(WhichV(eWhich)) > 0 )
3392 nDy = -1;
3393 if ( rMousePos.Y() >= aSize.Height() - SCROLL_SENSITIVE20
3394 && mrViewData.GetPosY(WhichV(eWhich)) < rDoc.MaxRow() )
3395 nDy = 1;
3396 }
3397
3398 if ( nDx != 0 || nDy != 0 )
3399 {
3400 if ( nDx != 0 )
3401 mrViewData.GetView()->ScrollX( nDx, WhichH(eWhich) );
3402 if ( nDy != 0 )
3403 mrViewData.GetView()->ScrollY( nDy, WhichV(eWhich) );
3404 }
3405}
3406
3407static bool lcl_TestScenarioRedliningDrop( const ScDocument* pDoc, const ScRange& aDragRange)
3408{
3409 // Test, if a scenario is affected by a drop when turing on RedLining,
3410 bool bReturn = false;
3411 SCTAB nTab = aDragRange.aStart.Tab();
3412 SCTAB nTabCount = pDoc->GetTableCount();
3413
3414 if(pDoc->GetChangeTrack()!=nullptr)
3415 {
3416 if( pDoc->IsScenario(nTab) && pDoc->HasScenarioRange(nTab, aDragRange))
3417 {
3418 bReturn = true;
3419 }
3420 else
3421 {
3422 for(SCTAB i=nTab+1; i<nTabCount && pDoc->IsScenario(i); i++)
3423 {
3424 if(pDoc->HasScenarioRange(i, aDragRange))
3425 {
3426 bReturn = true;
3427 break;
3428 }
3429 }
3430 }
3431 }
3432 return bReturn;
3433}
3434
3435static ScRange lcl_MakeDropRange( const ScDocument& rDoc, SCCOL nPosX, SCROW nPosY, SCTAB nTab, const ScRange& rSource )
3436{
3437 SCCOL nCol1 = nPosX;
3438 SCCOL nCol2 = nCol1 + ( rSource.aEnd.Col() - rSource.aStart.Col() );
3439 if ( nCol2 > rDoc.MaxCol() )
3440 {
3441 nCol1 -= nCol2 - rDoc.MaxCol();
3442 nCol2 = rDoc.MaxCol();
3443 }
3444 SCROW nRow1 = nPosY;
3445 SCROW nRow2 = nRow1 + ( rSource.aEnd.Row() - rSource.aStart.Row() );
3446 if ( nRow2 > rDoc.MaxRow() )
3447 {
3448 nRow1 -= nRow2 - rDoc.MaxRow();
3449 nRow2 = rDoc.MaxRow();
3450 }
3451
3452 return ScRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab );
3453}
3454
3455sal_Int8 ScGridWindow::AcceptPrivateDrop( const AcceptDropEvent& rEvt )
3456{
3457 if ( rEvt.mbLeaving )
3458 {
3459 bDragRect = false;
3460 UpdateDragRectOverlay();
3461 return rEvt.mnAction;
3462 }
3463
3464 const ScDragData& rData = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->GetDragData();
3465 if ( rData.pCellTransfer )
3466 {
3467 // Don't move source that would include filtered rows.
3468 if ((rEvt.mnAction & DND_ACTION_MOVEcss::datatransfer::dnd::DNDConstants::ACTION_MOVE) && rData.pCellTransfer->HasFilteredRows())
3469 {
3470 if (bDragRect)
3471 {
3472 bDragRect = false;
3473 UpdateDragRectOverlay();
3474 }
3475 return DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE;
3476 }
3477
3478 Point aPos = rEvt.maPosPixel;
3479
3480 ScDocument* pSourceDoc = rData.pCellTransfer->GetSourceDocument();
3481 ScDocument& rThisDoc = mrViewData.GetDocument();
3482 if (pSourceDoc == &rThisDoc)
3483 {
3484 OUString aName;
3485 if ( rThisDoc.HasChartAtPoint(mrViewData.GetTabNo(), PixelToLogic(aPos), aName ))
3486 {
3487 if (bDragRect) // Remove rectangle
3488 {
3489 bDragRect = false;
3490 UpdateDragRectOverlay();
3491 }
3492
3493 //! highlight chart? (selection border?)
3494
3495 sal_Int8 nRet = rEvt.mnAction;
3496 return nRet;
3497 }
3498 }
3499
3500 if (rData.pCellTransfer->GetDragSourceFlags() & ScDragSrc::Table) // whole sheet?
3501 {
3502 bool bOk = rThisDoc.IsDocEditable();
3503 return bOk ? rEvt.mnAction : 0; // don't draw selection frame
3504 }
3505
3506 SCCOL nPosX;
3507 SCROW nPosY;
3508 mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
3509
3510 ScRange aSourceRange = rData.pCellTransfer->GetRange();
3511 SCCOL nSourceStartX = aSourceRange.aStart.Col();
3512 SCROW nSourceStartY = aSourceRange.aStart.Row();
3513 SCCOL nSourceEndX = aSourceRange.aEnd.Col();
3514 SCROW nSourceEndY = aSourceRange.aEnd.Row();
3515 SCCOL nSizeX = nSourceEndX - nSourceStartX + 1;
3516 SCROW nSizeY = nSourceEndY - nSourceStartY + 1;
3517
3518 if ( rEvt.mnAction != DND_ACTION_MOVEcss::datatransfer::dnd::DNDConstants::ACTION_MOVE )
3519 nSizeY = rData.pCellTransfer->GetNonFilteredRows(); // copy/link: no filtered rows
3520
3521 SCCOL nNewDragX = nPosX - rData.pCellTransfer->GetDragHandleX();
3522 if (nNewDragX<0) nNewDragX=0;
3523 if (nNewDragX+(nSizeX-1) > rThisDoc.MaxCol())
3524 nNewDragX = rThisDoc.MaxCol()-(nSizeX-1);
3525 SCROW nNewDragY = nPosY - rData.pCellTransfer->GetDragHandleY();
3526 if (nNewDragY<0) nNewDragY=0;
3527 if (nNewDragY+(nSizeY-1) > rThisDoc.MaxRow())
3528 nNewDragY = rThisDoc.MaxRow()-(nSizeY-1);
3529
3530 // don't break scenario ranges, don't drop on filtered
3531 SCTAB nTab = mrViewData.GetTabNo();
3532 ScRange aDropRange = lcl_MakeDropRange( rThisDoc, nNewDragX, nNewDragY, nTab, aSourceRange );
3533 if ( lcl_TestScenarioRedliningDrop( &rThisDoc, aDropRange ) ||
3534 lcl_TestScenarioRedliningDrop( pSourceDoc, aSourceRange ) ||
3535 ScViewUtil::HasFiltered( aDropRange, rThisDoc) )
3536 {
3537 if (bDragRect)
3538 {
3539 bDragRect = false;
3540 UpdateDragRectOverlay();
3541 }
3542 return DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE;
3543 }
3544
3545 InsCellCmd eDragInsertMode = INS_NONE;
3546 Window::PointerState aState = GetPointerState();
3547
3548 // check for datapilot item sorting
3549 ScDPObject* pDPObj = nullptr;
3550 if ( &rThisDoc == pSourceDoc && ( pDPObj = rThisDoc.GetDPAtCursor( nNewDragX, nNewDragY, nTab ) ) != nullptr )
3551 {
3552 // drop on DataPilot table: sort or nothing
3553
3554 bool bDPSort = false;
3555 if ( rThisDoc.GetDPAtCursor( nSourceStartX, nSourceStartY, aSourceRange.aStart.Tab() ) == pDPObj )
3556 {
3557 sheet::DataPilotTableHeaderData aDestData;
3558 pDPObj->GetHeaderPositionData( ScAddress(nNewDragX, nNewDragY, nTab), aDestData );
3559 bool bValid = ( aDestData.Dimension >= 0 ); // dropping onto a field
3560
3561 // look through the source range
3562 for (SCROW nRow = aSourceRange.aStart.Row(); bValid && nRow <= aSourceRange.aEnd.Row(); ++nRow )
3563 for (SCCOL nCol = aSourceRange.aStart.Col(); bValid && nCol <= aSourceRange.aEnd.Col(); ++nCol )
3564 {
3565 sheet::DataPilotTableHeaderData aSourceData;
3566 pDPObj->GetHeaderPositionData( ScAddress( nCol, nRow, aSourceRange.aStart.Tab() ), aSourceData );
3567 if ( aSourceData.Dimension != aDestData.Dimension || aSourceData.MemberName.isEmpty() )
3568 bValid = false; // empty (subtotal) or different field
3569 }
3570
3571 if ( bValid )
3572 {
3573 bool bIsDataLayout;
3574 OUString aDimName = pDPObj->GetDimName( aDestData.Dimension, bIsDataLayout );
3575 const ScDPSaveDimension* pDim = pDPObj->GetSaveData()->GetExistingDimensionByName( aDimName );
3576 if ( pDim )
3577 {
3578 ScRange aOutRange = pDPObj->GetOutRange();
3579
3580 sheet::DataPilotFieldOrientation nOrient = pDim->GetOrientation();
3581 if ( nOrient == sheet::DataPilotFieldOrientation_COLUMN )
3582 {
3583 eDragInsertMode = INS_CELLSRIGHT;
3584 nSizeY = aOutRange.aEnd.Row() - nNewDragY + 1;
3585 bDPSort = true;
3586 }
3587 else if ( nOrient == sheet::DataPilotFieldOrientation_ROW )
3588 {
3589 eDragInsertMode = INS_CELLSDOWN;
3590 nSizeX = aOutRange.aEnd.Col() - nNewDragX + 1;
3591 bDPSort = true;
3592 }
3593 }
3594 }
3595 }
3596
3597 if ( !bDPSort )
3598 {
3599 // no valid sorting in a DataPilot table -> disallow
3600 if ( bDragRect )
3601 {
3602 bDragRect = false;
3603 UpdateDragRectOverlay();
3604 }
3605 return DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE;
3606 }
3607 }
3608 else if ( aState.mnState & KEY_MOD2 )
3609 {
3610 if ( &rThisDoc == pSourceDoc && nTab == aSourceRange.aStart.Tab() )
3611 {
3612 long nDeltaX = labs( static_cast< long >( nNewDragX - nSourceStartX ) );
3613 long nDeltaY = labs( static_cast< long >( nNewDragY - nSourceStartY ) );
3614 if ( nDeltaX <= nDeltaY )
3615 {
3616 eDragInsertMode = INS_CELLSDOWN;
3617 }
3618 else
3619 {
3620 eDragInsertMode = INS_CELLSRIGHT;
3621 }
3622
3623 if ( ( eDragInsertMode == INS_CELLSDOWN && nNewDragY <= nSourceEndY &&
3624 ( nNewDragX + nSizeX - 1 ) >= nSourceStartX && nNewDragX <= nSourceEndX &&
3625 ( nNewDragX != nSourceStartX || nNewDragY >= nSourceStartY ) ) ||
3626 ( eDragInsertMode == INS_CELLSRIGHT && nNewDragX <= nSourceEndX &&
3627 ( nNewDragY + nSizeY - 1 ) >= nSourceStartY && nNewDragY <= nSourceEndY &&
3628 ( nNewDragY != nSourceStartY || nNewDragX >= nSourceStartX ) ) )
3629 {
3630 if ( bDragRect )
3631 {
3632 bDragRect = false;
3633 UpdateDragRectOverlay();
3634 }
3635 return DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE;
3636 }
3637 }
3638 else
3639 {
3640 if ( static_cast< long >( nSizeX ) >= static_cast< long >( nSizeY ) )
3641 {
3642 eDragInsertMode = INS_CELLSDOWN;
3643
3644 }
3645 else
3646 {
3647 eDragInsertMode = INS_CELLSRIGHT;
3648 }
3649 }
3650 }
3651
3652 if ( nNewDragX != nDragStartX || nNewDragY != nDragStartY ||
3653 nDragStartX+nSizeX-1 != nDragEndX || nDragStartY+nSizeY-1 != nDragEndY ||
3654 !bDragRect || eDragInsertMode != meDragInsertMode )
3655 {
3656 nDragStartX = nNewDragX;
3657 nDragStartY = nNewDragY;
3658 nDragEndX = nDragStartX+nSizeX-1;
3659 nDragEndY = nDragStartY+nSizeY-1;
3660 bDragRect = true;
3661 meDragInsertMode = eDragInsertMode;
3662
3663 UpdateDragRectOverlay();
3664 }
3665 }
3666
3667 return rEvt.mnAction;
3668}
3669
3670sal_Int8 ScGridWindow::AcceptDrop( const AcceptDropEvent& rEvt )
3671{
3672 const ScDragData& rData = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->GetDragData();
3673 if ( rEvt.mbLeaving )
3674 {
3675 DrawMarkDropObj( nullptr );
3676 if ( rData.pCellTransfer )
3677 return AcceptPrivateDrop( rEvt ); // hide drop marker for internal D&D
3678 else
3679 return rEvt.mnAction;
3680 }
3681
3682 if ( mrViewData.GetDocShell()->IsReadOnly() )
3683 return DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE;
3684
3685 ScDocument& rThisDoc = mrViewData.GetDocument();
3686 sal_Int8 nRet = DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE;
3687
3688 if (rData.pCellTransfer)
3689 {
3690 ScRange aSource = rData.pCellTransfer->GetRange();
3691 if ( aSource.aStart.Col() != 0 || aSource.aEnd.Col() != rThisDoc.MaxCol() ||
3692 aSource.aStart.Row() != 0 || aSource.aEnd.Row() != rThisDoc.MaxRow() )
3693 DropScroll( rEvt.maPosPixel );
3694
3695 nRet = AcceptPrivateDrop( rEvt );
3696 }
3697 else
3698 {
3699 if ( !rData.aLinkDoc.isEmpty() )
3700 {
3701 OUString aThisName;
3702 ScDocShell* pDocSh = mrViewData.GetDocShell();
3703 if (pDocSh && pDocSh->HasName())
3704 aThisName = pDocSh->GetMedium()->GetName();
3705
3706 if ( rData.aLinkDoc != aThisName )
3707 nRet = rEvt.mnAction;
3708 }
3709 else if (!rData.aJumpTarget.isEmpty())
3710 {
3711 // internal bookmarks (from Navigator)
3712 // local jumps from an unnamed document are possible only within a document
3713
3714 if ( !rData.pJumpLocalDoc || rData.pJumpLocalDoc == &mrViewData.GetDocument() )
3715 nRet = rEvt.mnAction;
3716 }
3717 else
3718 {
3719 sal_Int8 nMyAction = rEvt.mnAction;
3720
3721 // clear DND_ACTION_LINK when other actions are set. The usage below cannot handle
3722 // multiple set values
3723 if((nMyAction & DND_ACTION_LINKcss::datatransfer::dnd::DNDConstants::ACTION_LINK) && (nMyAction & DND_ACTION_COPYMOVEcss::datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE))
3724 {
3725 nMyAction &= ~DND_ACTION_LINKcss::datatransfer::dnd::DNDConstants::ACTION_LINK;
3726 }
3727
3728 if ( !rData.pDrawTransfer ||
3729 !IsMyModel(rData.pDrawTransfer->GetDragSourceView()) ) // drawing within the document
3730 if ( rEvt.mbDefault && nMyAction == DND_ACTION_MOVEcss::datatransfer::dnd::DNDConstants::ACTION_MOVE )
3731 nMyAction = DND_ACTION_COPYcss::datatransfer::dnd::DNDConstants::ACTION_COPY;
3732
3733 SdrObject* pHitObj = rThisDoc.GetObjectAtPoint(
3734 mrViewData.GetTabNo(), PixelToLogic(rEvt.maPosPixel) );
3735 if ( pHitObj && nMyAction == DND_ACTION_LINKcss::datatransfer::dnd::DNDConstants::ACTION_LINK )
3736 {
3737 if ( IsDropFormatSupported(SotClipboardFormatId::SVXB)
3738 || IsDropFormatSupported(SotClipboardFormatId::GDIMETAFILE)
3739 || IsDropFormatSupported(SotClipboardFormatId::PNG)
3740 || IsDropFormatSupported(SotClipboardFormatId::BITMAP) )
3741 {
3742 // graphic dragged onto drawing object
3743 DrawMarkDropObj( pHitObj );
3744 nRet = nMyAction;
3745 }
3746 }
3747 if (!nRet)
3748 {
3749 DrawMarkDropObj(nullptr);
3750
3751 switch ( nMyAction )
3752 {
3753 case DND_ACTION_COPYcss::datatransfer::dnd::DNDConstants::ACTION_COPY:
3754 case DND_ACTION_MOVEcss::datatransfer::dnd::DNDConstants::ACTION_MOVE:
3755 case DND_ACTION_COPYMOVEcss::datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE:
3756 {
3757 bool bMove = ( nMyAction == DND_ACTION_MOVEcss::datatransfer::dnd::DNDConstants::ACTION_MOVE );
3758 if ( IsDropFormatSupported( SotClipboardFormatId::EMBED_SOURCE ) ||
3759 IsDropFormatSupported( SotClipboardFormatId::LINK_SOURCE ) ||
3760 IsDropFormatSupported( SotClipboardFormatId::EMBED_SOURCE_OLE ) ||
3761 IsDropFormatSupported( SotClipboardFormatId::LINK_SOURCE_OLE ) ||
3762 IsDropFormatSupported( SotClipboardFormatId::EMBEDDED_OBJ_OLE ) ||
3763 IsDropFormatSupported( SotClipboardFormatId::STRING ) ||
3764 IsDropFormatSupported( SotClipboardFormatId::STRING_TSVC ) ||
3765 IsDropFormatSupported( SotClipboardFormatId::SYLK ) ||
3766 IsDropFormatSupported( SotClipboardFormatId::LINK ) ||
3767 IsDropFormatSupported( SotClipboardFormatId::HTML ) ||
3768 IsDropFormatSupported( SotClipboardFormatId::HTML_SIMPLE ) ||
3769 IsDropFormatSupported( SotClipboardFormatId::DIF ) ||
3770 IsDropFormatSupported( SotClipboardFormatId::DRAWING ) ||
3771 IsDropFormatSupported( SotClipboardFormatId::SVXB ) ||
3772 IsDropFormatSupported( SotClipboardFormatId::RTF ) ||
3773 IsDropFormatSupported( SotClipboardFormatId::RICHTEXT ) ||
3774 IsDropFormatSupported( SotClipboardFormatId::GDIMETAFILE ) ||
3775 IsDropFormatSupported( SotClipboardFormatId::PNG ) ||
3776 IsDropFormatSupported( SotClipboardFormatId::BITMAP ) ||
3777 IsDropFormatSupported( SotClipboardFormatId::SBA_DATAEXCHANGE ) ||
3778 IsDropFormatSupported( SotClipboardFormatId::SBA_FIELDDATAEXCHANGE ) ||
3779 ( !bMove && (
3780 IsDropFormatSupported( SotClipboardFormatId::FILE_LIST ) ||
3781 IsDropFormatSupported( SotClipboardFormatId::SIMPLE_FILE ) ||
3782 IsDropFormatSupported( SotClipboardFormatId::SOLK ) ||
3783 IsDropFormatSupported( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ) ||
3784 IsDropFormatSupported( SotClipboardFormatId::NETSCAPE_BOOKMARK ) ||
3785 IsDropFormatSupported( SotClipboardFormatId::FILEGRPDESCRIPTOR ) ) ) )
3786 {
3787 nRet = nMyAction;
3788 }
3789 }
3790 break;
3791 case DND_ACTION_LINKcss::datatransfer::dnd::DNDConstants::ACTION_LINK:
3792 if ( IsDropFormatSupported( SotClipboardFormatId::LINK_SOURCE ) ||
3793 IsDropFormatSupported( SotClipboardFormatId::LINK_SOURCE_OLE ) ||
3794 IsDropFormatSupported( SotClipboardFormatId::LINK ) ||
3795 IsDropFormatSupported( SotClipboardFormatId::FILE_LIST ) ||
3796 IsDropFormatSupported( SotClipboardFormatId::SIMPLE_FILE ) ||
3797 IsDropFormatSupported( SotClipboardFormatId::SOLK ) ||
3798 IsDropFormatSupported( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ) ||
3799 IsDropFormatSupported( SotClipboardFormatId::NETSCAPE_BOOKMARK ) ||
3800 IsDropFormatSupported( SotClipboardFormatId::FILEGRPDESCRIPTOR ) )
3801 {
3802 nRet = nMyAction;
3803 }
3804 break;
3805 }
3806
3807 if ( nRet )
3808 {
3809 // Simple check for protection: It's not known here if the drop will result
3810 // in cells or drawing objects (some formats can be both) and how many cells
3811 // the result will be. But if IsFormatEditable for the drop cell position
3812 // is sal_False (ignores matrix formulas), nothing can be pasted, so the drop
3813 // can already be rejected here.
3814
3815 Point aPos = rEvt.maPosPixel;
3816 SCCOL nPosX;
3817 SCROW nPosY;
3818 mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
3819 SCTAB nTab = mrViewData.GetTabNo();
3820 ScDocument& rDoc = mrViewData.GetDocument();
3821
3822 ScEditableTester aTester( rDoc, nTab, nPosX,nPosY, nPosX,nPosY );
3823 if ( !aTester.IsFormatEditable() )
3824 nRet = DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE; // forbidden
3825 }
3826 }
3827 }
3828
3829 // scroll only for accepted formats
3830 if (nRet)
3831 DropScroll( rEvt.maPosPixel );
3832 }
3833
3834 return nRet;
3835}
3836
3837static SotClipboardFormatId lcl_GetDropFormatId( const uno::Reference<datatransfer::XTransferable>& xTransfer, bool bPreferText )
3838{
3839 TransferableDataHelper aDataHelper( xTransfer );
3840
3841 if ( !aDataHelper.HasFormat( SotClipboardFormatId::SBA_DATAEXCHANGE ) )
3842 {
3843 // use bookmark formats if no sba is present
3844
3845 if ( aDataHelper.HasFormat( SotClipboardFormatId::SOLK ) )
3846 return SotClipboardFormatId::SOLK;
3847 else if ( aDataHelper.HasFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ) )
3848 return SotClipboardFormatId::UNIFORMRESOURCELOCATOR;
3849 else if ( aDataHelper.HasFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK ) )
3850 return SotClipboardFormatId::NETSCAPE_BOOKMARK;
3851 else if ( aDataHelper.HasFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR ) )
3852 return SotClipboardFormatId::FILEGRPDESCRIPTOR;
3853 }
3854
3855 SotClipboardFormatId nFormatId = SotClipboardFormatId::NONE;
3856 if ( aDataHelper.HasFormat( SotClipboardFormatId::DRAWING ) )
3857 nFormatId = SotClipboardFormatId::DRAWING;
3858 else if ( aDataHelper.HasFormat( SotClipboardFormatId::SVXB ) )
3859 nFormatId = SotClipboardFormatId::SVXB;
3860 else if ( aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE ) )
3861 {
3862 // If it's a Writer object, insert RTF instead of OLE
3863
3864 bool bDoRtf = false;
3865 tools::SvRef<SotStorageStream> xStm;
3866 TransferableObjectDescriptor aObjDesc;
3867 if( aDataHelper.GetTransferableObjectDescriptor( SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDesc ) &&
3868 aDataHelper.GetSotStorageStream( SotClipboardFormatId::EMBED_SOURCE, xStm ) )
3869 {
3870 bDoRtf = ( ( aObjDesc.maClassName == SvGlobalName( SO3_SW_CLASSID0x8BC6B165, 0xB1B2, 0x4EDD, 0xAA, 0x47, 0xDA, 0xE2, 0xEE, 0x68
, 0x9D, 0xD6
) ||
3871 aObjDesc.maClassName == SvGlobalName( SO3_SWWEB_CLASSID0xA8BBA60C, 0x7C60, 0x4550, 0x91, 0xCE, 0x39, 0xC3, 0x90, 0x3F
, 0xAC, 0x5E
) )
3872 && ( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) || aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) ) );
3873 }
3874 if ( bDoRtf )
3875 nFormatId = aDataHelper.HasFormat( SotClipboardFormatId::RTF ) ? SotClipboardFormatId::RTF : SotClipboardFormatId::RICHTEXT;
3876 else
3877 nFormatId = SotClipboardFormatId::EMBED_SOURCE;
3878 }
3879 else if ( aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE ) )
3880 nFormatId = SotClipboardFormatId::LINK_SOURCE;
3881 else if ( aDataHelper.HasFormat( SotClipboardFormatId::SBA_DATAEXCHANGE ) )
3882 nFormatId = SotClipboardFormatId::SBA_DATAEXCHANGE;
3883 else if ( aDataHelper.HasFormat( SotClipboardFormatId::SBA_FIELDDATAEXCHANGE ) )
3884 nFormatId = SotClipboardFormatId::SBA_FIELDDATAEXCHANGE;
3885 else if ( aDataHelper.HasFormat( SotClipboardFormatId::BIFF_8 ) )
3886 nFormatId = SotClipboardFormatId::BIFF_8;
3887 else if ( aDataHelper.HasFormat( SotClipboardFormatId::BIFF_5 ) )
3888 nFormatId = SotClipboardFormatId::BIFF_5;
3889 else if ( aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE_OLE ) )
3890 nFormatId = SotClipboardFormatId::EMBED_SOURCE_OLE;
3891 else if ( aDataHelper.HasFormat( SotClipboardFormatId::EMBEDDED_OBJ_OLE ) )
3892 nFormatId = SotClipboardFormatId::EMBEDDED_OBJ_OLE;
3893 else if ( aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE_OLE ) )
3894 nFormatId = SotClipboardFormatId::LINK_SOURCE_OLE;
3895 else if ( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) )
3896 nFormatId = SotClipboardFormatId::RTF;
3897 else if ( aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) )
3898 nFormatId = SotClipboardFormatId::RICHTEXT;
3899 else if ( aDataHelper.HasFormat( SotClipboardFormatId::HTML ) )
3900 nFormatId = SotClipboardFormatId::HTML;
3901 else if ( aDataHelper.HasFormat( SotClipboardFormatId::HTML_SIMPLE ) )
3902 nFormatId = SotClipboardFormatId::HTML_SIMPLE;
3903 else if ( aDataHelper.HasFormat( SotClipboardFormatId::SYLK ) )
3904 nFormatId = SotClipboardFormatId::SYLK;
3905 else if ( aDataHelper.HasFormat( SotClipboardFormatId::LINK ) )
3906 nFormatId = SotClipboardFormatId::LINK;
3907 else if ( bPreferText && aDataHelper.HasFormat( SotClipboardFormatId::STRING ) ) // #i86734# the behaviour introduced in #i62773# is wrong when pasting
3908 nFormatId = SotClipboardFormatId::STRING;
3909 else if ( aDataHelper.HasFormat( SotClipboardFormatId::FILE_LIST ) )
3910 nFormatId = SotClipboardFormatId::FILE_LIST;
3911 else if ( aDataHelper.HasFormat( SotClipboardFormatId::SIMPLE_FILE ) ) // #i62773# FILE_LIST/FILE before STRING (Unix file managers)
3912 nFormatId = SotClipboardFormatId::SIMPLE_FILE;
3913 else if ( aDataHelper.HasFormat( SotClipboardFormatId::STRING_TSVC ) )
3914 nFormatId = SotClipboardFormatId::STRING_TSVC;
3915 else if ( aDataHelper.HasFormat( SotClipboardFormatId::STRING ) )
3916 nFormatId = SotClipboardFormatId::STRING;
3917 else if ( aDataHelper.HasFormat( SotClipboardFormatId::GDIMETAFILE ) )
3918 nFormatId = SotClipboardFormatId::GDIMETAFILE;
3919 else if ( aDataHelper.HasFormat( SotClipboardFormatId::PNG ) )
3920 nFormatId = SotClipboardFormatId::PNG;
3921 else if ( aDataHelper.HasFormat( SotClipboardFormatId::BITMAP ) )
3922 nFormatId = SotClipboardFormatId::BITMAP;
3923
3924 return nFormatId;
3925}
3926
3927static SotClipboardFormatId lcl_GetDropLinkId( const uno::Reference<datatransfer::XTransferable>& xTransfer )
3928{
3929 TransferableDataHelper aDataHelper( xTransfer );
3930
3931 SotClipboardFormatId nFormatId = SotClipboardFormatId::NONE;
3932 if ( aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE ) )
3933 nFormatId = SotClipboardFormatId::LINK_SOURCE;
3934 else if ( aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE_OLE ) )
3935 nFormatId = SotClipboardFormatId::LINK_SOURCE_OLE;
3936 else if ( aDataHelper.HasFormat( SotClipboardFormatId::LINK ) )
3937 nFormatId = SotClipboardFormatId::LINK;
3938 else if ( aDataHelper.HasFormat( SotClipboardFormatId::FILE_LIST ) )
3939 nFormatId = SotClipboardFormatId::FILE_LIST;
3940 else if ( aDataHelper.HasFormat( SotClipboardFormatId::SIMPLE_FILE ) )
3941 nFormatId = SotClipboardFormatId::SIMPLE_FILE;
3942 else if ( aDataHelper.HasFormat( SotClipboardFormatId::SOLK ) )
3943 nFormatId = SotClipboardFormatId::SOLK;
3944 else if ( aDataHelper.HasFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ) )
3945 nFormatId = SotClipboardFormatId::UNIFORMRESOURCELOCATOR;
3946 else if ( aDataHelper.HasFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK ) )
3947 nFormatId = SotClipboardFormatId::NETSCAPE_BOOKMARK;
3948 else if ( aDataHelper.HasFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR ) )
3949 nFormatId = SotClipboardFormatId::FILEGRPDESCRIPTOR;
3950
3951 return nFormatId;
3952}
3953
3954sal_Int8 ScGridWindow::ExecutePrivateDrop( const ExecuteDropEvent& rEvt )
3955{
3956 // hide drop marker
3957 bDragRect = false;
3958 UpdateDragRectOverlay();
3959
3960 ScModule* pScMod = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
;
3961 const ScDragData& rData = pScMod->GetDragData();
3962
3963 return DropTransferObj( rData.pCellTransfer, nDragStartX, nDragStartY,
3964 PixelToLogic(rEvt.maPosPixel), rEvt.mnAction );
3965}
3966
3967sal_Int8 ScGridWindow::DropTransferObj( ScTransferObj* pTransObj, SCCOL nDestPosX, SCROW nDestPosY,
3968 const Point& rLogicPos, sal_Int8 nDndAction )
3969{
3970 if ( !pTransObj )
3971 return 0;
3972
3973 ScDocument* pSourceDoc = pTransObj->GetSourceDocument();
3974 ScDocShell* pDocSh = mrViewData.GetDocShell();
3975 ScDocument& rThisDoc = mrViewData.GetDocument();
3976 ScViewFunc* pView = mrViewData.GetView();
3977 SCTAB nThisTab = mrViewData.GetTabNo();
3978 ScDragSrc nFlags = pTransObj->GetDragSourceFlags();
3979
3980 bool bIsNavi = (nFlags & ScDragSrc::Navigator) == ScDragSrc::Navigator;
3981 bool bIsMove = ( nDndAction == DND_ACTION_MOVEcss::datatransfer::dnd::DNDConstants::ACTION_MOVE && !bIsNavi );
3982
3983 // workaround for wrong nDndAction on Windows when pressing solely
3984 // the Alt key during drag and drop;
3985 // can be removed after #i79215# has been fixed
3986 if ( meDragInsertMode != INS_NONE )
3987 {
3988 bIsMove = ( nDndAction & DND_ACTION_MOVEcss::datatransfer::dnd::DNDConstants::ACTION_MOVE && !bIsNavi );
3989 }
3990
3991 bool bIsLink = ( nDndAction == DND_ACTION_LINKcss::datatransfer::dnd::DNDConstants::ACTION_LINK );
3992
3993 ScRange aSource = pTransObj->GetRange();
3994
3995 // only use visible tab from source range - when dragging within one table,
3996 // all selected tables at the time of dropping are used (handled in MoveBlockTo)
3997 SCTAB nSourceTab = pTransObj->GetVisibleTab();
3998 aSource.aStart.SetTab( nSourceTab );
3999 aSource.aEnd.SetTab( nSourceTab );
4000
4001 SCCOL nSizeX = aSource.aEnd.Col() - aSource.aStart.Col() + 1;
4002 SCROW nSizeY = (bIsMove ? (aSource.aEnd.Row() - aSource.aStart.Row() + 1) :
4003 pTransObj->GetNonFilteredRows()); // copy/link: no filtered rows
4004 ScRange aDest( nDestPosX, nDestPosY, nThisTab,
4005 nDestPosX + nSizeX - 1, nDestPosY + nSizeY - 1, nThisTab );
4006
4007 /* NOTE: AcceptPrivateDrop() already checked for filtered conditions during
4008 * dragging and adapted drawing of the selection frame. We check here
4009 * (again) because this may actually also be called from PasteSelection(),
4010 * we would have to duplicate determination of flags and destination range
4011 * and would lose the context of the "filtered destination is OK" cases
4012 * below, which is already awkward enough as is. */
4013
4014 // Don't move filtered source.
4015 bool bFiltered = (bIsMove && pTransObj->HasFilteredRows());
4016 if (!bFiltered)
4017 {
4018 if (pSourceDoc != &rThisDoc && ((nFlags & ScDragSrc::Table) ||
4019 (!bIsLink && meDragInsertMode == INS_NONE)))
4020 {
4021 // Nothing. Either entire sheet to be dropped, or the one case
4022 // where PasteFromClip() is to be called that handles a filtered
4023 // destination itself. Drag-copy from another document without
4024 // inserting cells.
4025 }
4026 else
4027 // Don't copy or move to filtered destination.
4028 bFiltered = ScViewUtil::HasFiltered(aDest, rThisDoc);
4029 }
4030
4031 bool bDone = false;
4032
4033 if (!bFiltered && pSourceDoc == &rThisDoc)
4034 {
4035 if (nFlags & ScDragSrc::Table) // whole sheet?
4036 {
4037 if ( rThisDoc.IsDocEditable() )
4038 {
4039 SCTAB nSrcTab = aSource.aStart.Tab();
4040 mrViewData.GetDocShell()->MoveTable( nSrcTab, nThisTab, !bIsMove, true ); // with Undo
4041 pView->SetTabNo( nThisTab, true );
4042 bDone = true;
4043 }
4044 }
4045 else // move/copy block
4046 {
4047 OUString aChartName;
4048 if (rThisDoc.HasChartAtPoint( nThisTab, rLogicPos, aChartName ))
4049 {
4050 OUString aRangeName(aSource.Format(rThisDoc, ScRefFlags::RANGE_ABS_3D));
4051 SfxStringItem aNameItem( SID_CHART_NAME((26000 + 100) + 26), aChartName );
4052 SfxStringItem aRangeItem( SID_CHART_SOURCE((26000 + 100) + 25), aRangeName );
4053 sal_uInt16 nId = bIsMove ? SID_CHART_SOURCE((26000 + 100) + 25) : SID_CHART_ADDSOURCE((26000 + 100) + 27);
4054 mrViewData.GetDispatcher().ExecuteList(nId,
4055 SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
4056 { &aRangeItem, &aNameItem });
4057 bDone = true;
4058 }
4059 else if ( rThisDoc.GetDPAtCursor( nDestPosX, nDestPosY, nThisTab ) )
4060 {
4061 // drop on DataPilot table: try to sort, fail if that isn't possible
4062
4063 ScAddress aDestPos( nDestPosX, nDestPosY, nThisTab );
4064 if ( aDestPos != aSource.aStart )
4065 bDone = mrViewData.GetView()->DataPilotMove( aSource, aDestPos );
4066 else
4067 bDone = true; // same position: nothing
4068 }
4069 else if ( nDestPosX != aSource.aStart.Col() || nDestPosY != aSource.aStart.Row() ||
4070 nSourceTab != nThisTab )
4071 {
4072 OUString aUndo = ScResId( bIsMove ? STR_UNDO_MOVEreinterpret_cast<char const *>("STR_UNDO_MOVE" "\004" u8"Move"
)
: STR_UNDO_COPYreinterpret_cast<char const *>("STR_UNDO_COPY" "\004" u8"Copy"
)
);
4073 pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo, 0, mrViewData.GetViewShell()->GetViewShellId() );
4074
4075 SCCOL nCorrectCursorPosCol = 0;
4076 SCROW nCorrectCursorPosRow = 0;
4077
4078 bDone = true;
4079 if ( meDragInsertMode != INS_NONE )
4080 {
4081 // call with bApi = sal_True to avoid error messages in drop handler
4082 bDone = pDocSh->GetDocFunc().InsertCells( aDest, nullptr, meDragInsertMode, true /*bRecord*/, true /*bApi*/, true /*bPartOfPaste*/ );
4083 if ( bDone )
4084 {
4085 if ( nThisTab == nSourceTab )
4086 {
4087 if ( meDragInsertMode == INS_CELLSDOWN &&
4088 nDestPosX == aSource.aStart.Col() && nDestPosY < aSource.aStart.Row() )
4089 {
4090 ScRange aErrorRange( ScAddress::UNINITIALIZED );
4091 bDone = aSource.Move( 0, nSizeY, 0, aErrorRange, pSourceDoc );
4092 nCorrectCursorPosRow = nSizeY;
4093 }
4094 else if ( meDragInsertMode == INS_CELLSRIGHT &&
4095 nDestPosY == aSource.aStart.Row() && nDestPosX < aSource.aStart.Col() )
4096 {
4097 ScRange aErrorRange( ScAddress::UNINITIALIZED );
4098 bDone = aSource.Move( nSizeX, 0, 0, aErrorRange, pSourceDoc );
4099 nCorrectCursorPosCol = nSizeX;
4100 }
4101 }
4102 pDocSh->UpdateOle(mrViewData);
4103 pView->CellContentChanged();
4104 }
4105 }
4106
4107 if ( bDone )
4108 {
4109 if ( bIsLink )
4110 {
4111 bDone = pView->LinkBlock( aSource, aDest.aStart );
4112 }
4113 else
4114 {
4115 bDone = pView->MoveBlockTo( aSource, aDest.aStart, bIsMove );
4116 }
4117 }
4118
4119 if ( bDone && meDragInsertMode != INS_NONE && bIsMove && nThisTab == nSourceTab )
4120 {
4121 DelCellCmd eCmd = DelCellCmd::NONE;
4122 if ( meDragInsertMode == INS_CELLSDOWN )
4123 {
4124 eCmd = DelCellCmd::CellsUp;
4125 }
4126 else if ( meDragInsertMode == INS_CELLSRIGHT )
4127 {
4128 eCmd = DelCellCmd::CellsLeft;
4129 }
4130
4131 if ( ( eCmd == DelCellCmd::CellsUp && nDestPosX == aSource.aStart.Col() ) ||
4132 ( eCmd == DelCellCmd::CellsLeft && nDestPosY == aSource.aStart.Row() ) )
4133 {
4134 // call with bApi = sal_True to avoid error messages in drop handler
4135 bDone = pDocSh->GetDocFunc().DeleteCells( aSource, nullptr, eCmd, true /*bApi*/ );
4136 if ( bDone )
4137 {
4138 if ( eCmd == DelCellCmd::CellsUp && nDestPosY > aSource.aEnd.Row() )
4139 {
4140 ScRange aErrorRange( ScAddress::UNINITIALIZED );
4141 bDone = aDest.Move( 0, -nSizeY, 0, aErrorRange, &rThisDoc );
4142 }
4143 else if ( eCmd == DelCellCmd::CellsLeft && nDestPosX > aSource.aEnd.Col() )
4144 {
4145 ScRange aErrorRange( ScAddress::UNINITIALIZED );
4146 bDone = aDest.Move( -nSizeX, 0, 0, aErrorRange, &rThisDoc );
4147 }
4148 pDocSh->UpdateOle(mrViewData);
4149 pView->CellContentChanged();
4150 }
4151 }
4152 }
4153
4154 if ( bDone )
4155 {
4156 pView->MarkRange( aDest, false );
4157
4158 SCCOL nDCol;
4159 SCROW nDRow;
4160 if (pTransObj->WasSourceCursorInSelection())
4161 {
4162 nDCol = pTransObj->GetSourceCursorX() - aSource.aStart.Col() + nCorrectCursorPosCol;
4163 nDRow = pTransObj->GetSourceCursorY() - aSource.aStart.Row() + nCorrectCursorPosRow;
4164 }
4165 else
4166 {
4167 nDCol = 0;
4168 nDRow = 0;
4169 }
4170 pView->SetCursor( aDest.aStart.Col() + nDCol, aDest.aStart.Row() + nDRow );
4171 }
4172
4173 pDocSh->GetUndoManager()->LeaveListAction();
4174
4175 }
4176 else
4177 bDone = true; // nothing to do
4178 }
4179
4180 if (bDone)
4181 pTransObj->SetDragWasInternal(); // don't delete source in DragFinished
4182 }
4183 else if ( !bFiltered && pSourceDoc ) // between documents
4184 {
4185 if (nFlags & ScDragSrc::Table) // copy/link sheets between documents
4186 {
4187 if ( rThisDoc.IsDocEditable() )
4188 {
4189 ScDocShell* pSrcShell = pTransObj->GetSourceDocShell();
4190
4191 std::vector<SCTAB> nTabs;
4192
4193 ScMarkData aMark = pTransObj->GetSourceMarkData();
4194 SCTAB nTabCount = pSourceDoc->GetTableCount();
4195
4196 for(SCTAB i=0; i<nTabCount; i++)
4197 {
4198 if(aMark.GetTableSelect(i))
4199 {
4200 nTabs.push_back(i);
4201 for(SCTAB j=i+1;j<nTabCount;j++)
4202 {
4203 if((!pSourceDoc->IsVisible(j))&&(pSourceDoc->IsScenario(j)))
4204 {
4205 nTabs.push_back( j );
4206 i=j;
4207 }
4208 else break;
4209 }
4210 }
4211 }
4212
4213 pView->ImportTables( pSrcShell,static_cast<SCTAB>(nTabs.size()), nTabs.data(), bIsLink, nThisTab );
4214 bDone = true;
4215 }
4216 }
4217 else if ( bIsLink )
4218 {
4219 // as in PasteDDE
4220 // (external references might be used instead?)
4221
4222 SfxObjectShell* pSourceSh = pSourceDoc->GetDocumentShell();
4223 OSL_ENSURE(pSourceSh, "drag document has no shell")do { if (true && (!(pSourceSh))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/ui/view/gridwin.cxx"
":" "4223" ": "), "%s", "drag document has no shell"); } } while
(false)
;
4224 if (pSourceSh)
4225 {
4226 OUString aUndo = ScResId( STR_UNDO_COPYreinterpret_cast<char const *>("STR_UNDO_COPY" "\004" u8"Copy"
)
);
4227 pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo, 0, mrViewData.GetViewShell()->GetViewShellId() );
4228
4229 bDone = true;
4230 if ( meDragInsertMode != INS_NONE )
4231 {
4232 // call with bApi = sal_True to avoid error messages in drop handler
4233 bDone = pDocSh->GetDocFunc().InsertCells( aDest, nullptr, meDragInsertMode, true /*bRecord*/, true /*bApi*/, true /*bPartOfPaste*/ );
4234 if ( bDone )
4235 {
4236 pDocSh->UpdateOle(mrViewData);
4237 pView->CellContentChanged();
4238 }
4239 }
4240
4241 if ( bDone )
4242 {
4243 OUString aApp = Application::GetAppName();
4244 OUString aTopic = pSourceSh->GetTitle( SFX_TITLE_FULLNAME2 );
4245 OUString aItem(aSource.Format(*pSourceDoc, ScRefFlags::VALID | ScRefFlags::TAB_3D));
4246
4247 // TODO: we could define ocQuote for "
4248 const OUString aQuote('"');
4249 const OUString& sSep = ScCompiler::GetNativeSymbol( ocSep);
4250 OUStringBuffer aFormula;
4251 aFormula.append('=');
4252 aFormula.append(ScCompiler::GetNativeSymbol(ocDde));
4253 aFormula.append(ScCompiler::GetNativeSymbol(ocOpen));
4254 aFormula.append(aQuote);
4255 aFormula.append(aApp);
4256 aFormula.append(aQuote);
4257 aFormula.append(sSep);
4258 aFormula.append(aQuote);
4259 aFormula.append(aTopic);
4260 aFormula.append(aQuote);
4261 aFormula.append(sSep);
4262 aFormula.append(aQuote);
4263 aFormula.append(aItem);
4264 aFormula.append(aQuote);
4265 aFormula.append(ScCompiler::GetNativeSymbol(ocClose));
4266
4267 pView->DoneBlockMode();
4268 pView->InitBlockMode( nDestPosX, nDestPosY, nThisTab );
4269 pView->MarkCursor( nDestPosX + nSizeX - 1,
4270 nDestPosY + nSizeY - 1, nThisTab );
4271
4272 pView->EnterMatrix( aFormula.makeStringAndClear(), ::formula::FormulaGrammar::GRAM_NATIVE );
4273
4274 pView->MarkRange( aDest, false );
4275 pView->SetCursor( aDest.aStart.Col(), aDest.aStart.Row() );
4276 }
4277
4278 pDocSh->GetUndoManager()->LeaveListAction();
4279 }
4280 }
4281 else
4282 {
4283 //! HasSelectedBlockMatrixFragment without selected sheet?
4284 //! or don't start dragging on a part of a matrix
4285
4286 OUString aUndo = ScResId( bIsMove ? STR_UNDO_MOVEreinterpret_cast<char const *>("STR_UNDO_MOVE" "\004" u8"Move"
)
: STR_UNDO_COPYreinterpret_cast<char const *>("STR_UNDO_COPY" "\004" u8"Copy"
)
);
4287 pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo, 0, mrViewData.GetViewShell()->GetViewShellId() );
4288
4289 bDone = true;
4290 if ( meDragInsertMode != INS_NONE )
4291 {
4292 // call with bApi = sal_True to avoid error messages in drop handler
4293 bDone = pDocSh->GetDocFunc().InsertCells( aDest, nullptr, meDragInsertMode, true /*bRecord*/, true /*bApi*/, true /*bPartOfPaste*/ );
4294 if ( bDone )
4295 {
4296 pDocSh->UpdateOle(mrViewData);
4297 pView->CellContentChanged();
4298 }
4299 }
4300
4301 if ( bDone )
4302 {
4303 pView->Unmark(); // before SetCursor, so CheckSelectionTransfer isn't called with a selection
4304 pView->SetCursor( nDestPosX, nDestPosY );
4305 bDone = pView->PasteFromClip( InsertDeleteFlags::ALL, pTransObj->GetDocument() ); // clip-doc
4306 if ( bDone )
4307 {
4308 pView->MarkRange( aDest, false );
4309 pView->SetCursor( aDest.aStart.Col(), aDest.aStart.Row() );
4310 }
4311 }
4312
4313 pDocSh->GetUndoManager()->LeaveListAction();
4314
4315 // no longer call ResetMark here - the inserted block has been selected
4316 // and may have been copied to primary selection
4317 }
4318 }
4319
4320 sal_Int8 nRet = bDone ? nDndAction : DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE;
4321 return nRet;
4322}
4323
4324sal_Int8 ScGridWindow::ExecuteDrop( const ExecuteDropEvent& rEvt )
4325{
4326 DrawMarkDropObj( nullptr ); // drawing layer
4327
4328 ScModule* pScMod = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
;
4329 const ScDragData& rData = pScMod->GetDragData();
4330 if (rData.pCellTransfer)
4331 return ExecutePrivateDrop( rEvt );
4332
4333 Point aPos = rEvt.maPosPixel;
4334
4335 if ( !rData.aLinkDoc.isEmpty() )
4336 {
4337 // try to insert a link
4338
4339 bool bOk = true;
4340 OUString aThisName;
4341 ScDocShell* pDocSh = mrViewData.GetDocShell();
4342 if (pDocSh && pDocSh->HasName())
4343 aThisName = pDocSh->GetMedium()->GetName();
4344
4345 if ( rData.aLinkDoc == aThisName ) // error - no link within a document
4346 bOk = false;
4347 else
4348 {
4349 ScViewFunc* pView = mrViewData.GetView();
4350 if ( !rData.aLinkTable.isEmpty() )
4351 pView->InsertTableLink( rData.aLinkDoc, EMPTY_OUSTRINGScGlobal::GetEmptyOUString(), EMPTY_OUSTRINGScGlobal::GetEmptyOUString(),
4352 rData.aLinkTable );
4353 else if ( !rData.aLinkArea.isEmpty() )
4354 {
4355 SCCOL nPosX;
4356 SCROW nPosY;
4357 mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
4358 pView->MoveCursorAbs( nPosX, nPosY, SC_FOLLOW_NONE, false, false );
4359
4360 pView->InsertAreaLink( rData.aLinkDoc, EMPTY_OUSTRINGScGlobal::GetEmptyOUString(), EMPTY_OUSTRINGScGlobal::GetEmptyOUString(),
4361 rData.aLinkArea );
4362 }
4363 else
4364 {
4365 OSL_FAIL("drop with link: no sheet nor area")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/ui/view/gridwin.cxx"
":" "4365" ": "), "%s", "drop with link: no sheet nor area")
; } } while (false)
;
4366 bOk = false;
4367 }
4368 }
4369
4370 return bOk ? rEvt.mnAction : DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE; // don't try anything else
4371 }
4372
4373 Point aLogicPos = PixelToLogic(aPos);
4374 bool bIsLink = ( rEvt.mnAction == DND_ACTION_LINKcss::datatransfer::dnd::DNDConstants::ACTION_LINK );
4375
4376 if (!bIsLink && rData.pDrawTransfer)
4377 {
4378 ScDragSrc nFlags = rData.pDrawTransfer->GetDragSourceFlags();
4379
4380 bool bIsNavi = (nFlags & ScDragSrc::Navigator) == ScDragSrc::Navigator;
4381 bool bIsMove = ( rEvt.mnAction == DND_ACTION_MOVEcss::datatransfer::dnd::DNDConstants::ACTION_MOVE && !bIsNavi );
4382
4383 bPasteIsMove = bIsMove;
4384
4385 mrViewData.GetView()->PasteDraw(
4386 aLogicPos, rData.pDrawTransfer->GetModel(), false, "A", "B");
4387
4388 if (bPasteIsMove)
4389 rData.pDrawTransfer->SetDragWasInternal();
4390 bPasteIsMove = false;
4391
4392 return rEvt.mnAction;
4393 }
4394
4395 SCCOL nPosX;
4396 SCROW nPosY;
4397 mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
4398
4399 if (!rData.aJumpTarget.isEmpty())
4400 {
4401 // internal bookmark (from Navigator)
4402 // bookmark clipboard formats are in PasteScDataObject
4403
4404 if ( !rData.pJumpLocalDoc || rData.pJumpLocalDoc == &mrViewData.GetDocument() )
4405 {
4406 mrViewData.GetViewShell()->InsertBookmark( rData.aJumpText, rData.aJumpTarget,
4407 nPosX, nPosY );
4408 return rEvt.mnAction;
4409 }
4410 }
4411
4412 ScDocument& rThisDoc = mrViewData.GetDocument();
4413 SdrObject* pHitObj = rThisDoc.GetObjectAtPoint( mrViewData.GetTabNo(), PixelToLogic(aPos) );
4414 if ( pHitObj && bIsLink )
4415 {
4416 // dropped on drawing object
4417 // PasteOnDrawObjectLinked checks for valid formats
4418 if ( mrViewData.GetView()->PasteOnDrawObjectLinked( rEvt.maDropEvent.Transferable, *pHitObj ) )
4419 return rEvt.mnAction;
4420 }
4421
4422 bool bDone = false;
4423
4424 SotClipboardFormatId nFormatId = bIsLink ?
4425 lcl_GetDropLinkId( rEvt.maDropEvent.Transferable ) :
4426 lcl_GetDropFormatId( rEvt.maDropEvent.Transferable, false );
4427 if ( nFormatId != SotClipboardFormatId::NONE )
4428 {
4429 pScMod->SetInExecuteDrop( true ); // #i28468# prevent error messages from PasteDataFormat
4430 bDone = mrViewData.GetView()->PasteDataFormat(
4431 nFormatId, rEvt.maDropEvent.Transferable, nPosX, nPosY, &aLogicPos, bIsLink );
4432 pScMod->SetInExecuteDrop( false );
4433 }
4434
4435 sal_Int8 nRet = bDone ? rEvt.mnAction : DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE;
4436 return nRet;
4437}
4438
4439void ScGridWindow::PasteSelection( const Point& rPosPixel )
4440{
4441 Point aLogicPos = PixelToLogic( rPosPixel );
4442
4443 SCCOL nPosX;
4444 SCROW nPosY;
4445 mrViewData.GetPosFromPixel( rPosPixel.X(), rPosPixel.Y(), eWhich, nPosX, nPosY );
4446
4447 // If the mouse down was inside a visible note window, ignore it and
4448 // leave it up to the ScPostIt to handle it
4449 SdrView* pDrawView = mrViewData.GetViewShell()->GetScDrawView();
4450 if (pDrawView)
4451 {
4452 const size_t nCount = pDrawView->GetMarkedObjectCount();
4453 for (size_t i = 0; i < nCount; ++i)
4454 {
4455 SdrObject* pObj = pDrawView->GetMarkedObjectByIndex(i);
4456 if (pObj && pObj->GetLogicRect().IsInside(aLogicPos))
4457 {
4458 // Inside an active drawing object. Bail out.
4459 return;
4460 }
4461 }
4462 }
4463
4464 ScSelectionTransferObj* pOwnSelection = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->GetSelectionTransfer();
4465 if ( pOwnSelection )
4466 {
4467 // within Calc
4468
4469 // keep a reference to the data in case the selection is changed during paste
4470 rtl::Reference<ScTransferObj> pCellTransfer = pOwnSelection->GetCellData();
4471 if ( pCellTransfer )
4472 {
4473 DropTransferObj( pCellTransfer.get(), nPosX, nPosY, aLogicPos, DND_ACTION_COPYcss::datatransfer::dnd::DNDConstants::ACTION_COPY );
4474 }
4475 else
4476 {
4477 // keep a reference to the data in case the selection is changed during paste
4478 rtl::Reference<ScDrawTransferObj> pDrawTransfer = pOwnSelection->GetDrawData();
4479 if ( pDrawTransfer )
4480 {
4481 // bSameDocClipboard argument for PasteDraw is needed
4482 // because only DragData is checked directly inside PasteDraw
4483 mrViewData.GetView()->PasteDraw(
4484 aLogicPos, pDrawTransfer->GetModel(), false,
4485 pDrawTransfer->GetShellID(), SfxObjectShell::CreateShellID(mrViewData.GetDocShell()));
4486 }
4487 }
4488 }
4489 else
4490 {
4491 // get selection from system
4492
4493 TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSelection( this ) );
4494 const uno::Reference<datatransfer::XTransferable>& xTransferable = aDataHelper.GetTransferable();
4495 if ( xTransferable.is() )
4496 {
4497 SotClipboardFormatId nFormatId = lcl_GetDropFormatId( xTransferable, true );
4498 if ( nFormatId != SotClipboardFormatId::NONE )
4499 mrViewData.GetView()->PasteDataFormat( nFormatId, xTransferable, nPosX, nPosY, &aLogicPos );
4500 }
4501 }
4502}
4503
4504void ScGridWindow::UpdateEditViewPos()
4505{
4506 if (!mrViewData.HasEditView(eWhich))
4507 return;
4508
4509 EditView* pView;
4510 SCCOL nCol;
4511 SCROW nRow;
4512 mrViewData.GetEditView( eWhich, pView, nCol, nRow );
4513 SCCOL nEndCol = mrViewData.GetEditEndCol();
4514 SCROW nEndRow = mrViewData.GetEditEndRow();
4515
4516 // hide EditView?
4517
4518 bool bHide = ( nEndCol<mrViewData.GetPosX(eHWhich) || nEndRow<mrViewData.GetPosY(eVWhich) );
4519 if ( SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->IsFormulaMode() )
4520 if ( mrViewData.GetTabNo() != mrViewData.GetRefTabNo() )
4521 bHide = true;
4522
4523 if (bHide)
4524 {
4525 tools::Rectangle aRect = pView->GetOutputArea();
4526 long nHeight = aRect.Bottom() - aRect.Top();
4527 aRect.SetTop( PixelToLogic(GetOutputSizePixel(), mrViewData.GetLogicMode()).
4528 Height() * 2 );
4529 aRect.SetBottom( aRect.Top() + nHeight );
4530 pView->SetOutputArea( aRect );
4531 pView->HideCursor();
4532 }
4533 else
4534 {
4535 // bForceToTop = sal_True for editing
4536 tools::Rectangle aPixRect = mrViewData.GetEditArea( eWhich, nCol, nRow, this, nullptr, true );
4537
4538 if (comphelper::LibreOfficeKit::isActive() &&
4539 comphelper::LibreOfficeKit::isCompatFlagSet(
4540 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs))
4541 {
4542 tools::Rectangle aPTwipsRect = mrViewData.GetEditArea(eWhich, nCol, nRow, this, nullptr,
4543 true, true /* bInPrintTwips */);
4544 tools::Rectangle aOutputAreaPTwips = pView->GetLOKSpecialOutputArea();
4545 aOutputAreaPTwips.SetPos(aPTwipsRect.TopLeft());
4546 pView->SetLOKSpecialOutputArea(aOutputAreaPTwips);
4547 }
4548
4549 Point aScrPos = PixelToLogic( aPixRect.TopLeft(), mrViewData.GetLogicMode() );
4550
4551 tools::Rectangle aRect = pView->GetOutputArea();
4552 aRect.SetPos( aScrPos );
4553 pView->SetOutputArea( aRect );
4554 pView->ShowCursor();
4555 }
4556}
4557
4558void ScGridWindow::ScrollPixel( long nDifX, long nDifY )
4559{
4560 ClickExtern();
1
Calling 'ScGridWindow::ClickExtern'
4561 HideNoteMarker();
4562
4563 SetMapMode(MapMode(MapUnit::MapPixel));
4564 Scroll( nDifX, nDifY, ScrollFlags::Children );
4565 SetMapMode( GetDrawMapMode() ); // generated shifted MapMode
4566
4567 UpdateEditViewPos();
4568
4569 DrawAfterScroll();
4570}
4571
4572// Update Formulas ------------------------------------------------------
4573
4574void ScGridWindow::UpdateFormulas(SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2)
4575{
4576 if (mrViewData.GetView()->IsMinimized())
4577 return;
4578
4579 if ( nPaintCount )
4580 {
4581 // Do not start, switched to paint
4582 // (then at least the MapMode would no longer be right)
4583
4584 bNeedsRepaint = true; // -> at end of paint run Invalidate on all
4585 aRepaintPixel = tools::Rectangle(); // All
4586 return;
4587 }
4588
4589 if ( comphelper::LibreOfficeKit::isActive() )
4590 {
4591 ScTabViewShell* pViewShell = mrViewData.GetViewShell();
4592 if (nX1 < 0)
4593 nX1 = pViewShell->GetLOKStartHeaderCol() + 1;
4594 if (nY1 < 0)
4595 nY1 = pViewShell->GetLOKStartHeaderRow() + 1;
4596 if (nX2 < 0)
4597 nX2 = pViewShell->GetLOKEndHeaderCol();
4598 if (nY2 < 0)
4599 nY2 = pViewShell->GetLOKEndHeaderRow();
4600
4601 if (nX1 < 0 || nY1 < 0) return;
4602 }
4603 else
4604 {
4605 nX1 = mrViewData.GetPosX( eHWhich );
4606 nY1 = mrViewData.GetPosY( eVWhich );
4607 nX2 = nX1 + mrViewData.VisibleCellsX( eHWhich );
4608 nY2 = nY1 + mrViewData.VisibleCellsY( eVWhich );
4609 }
4610
4611 if (nX2 < nX1) nX2 = nX1;
4612 if (nY2 < nY1) nY2 = nY1;
4613
4614 ScDocument& rDoc = mrViewData.GetDocument();
4615
4616 if (nX2 > rDoc.MaxCol()) nX2 = rDoc.MaxCol();
4617 if (nY2 > rDoc.MaxRow()) nY2 = rDoc.MaxRow();
4618
4619 // Draw( nX1, nY1, nX2, nY2, SC_UPDATE_CHANGED );
4620
4621 // don't draw directly - instead use OutputData to find changed area and invalidate
4622
4623 SCROW nPosY = nY1;
4624
4625 SCTAB nTab = mrViewData.GetTabNo();
4626
4627 if ( !comphelper::LibreOfficeKit::isActive() )
4628 {
4629 rDoc.ExtendHidden( nX1, nY1, nX2, nY2, nTab );
4630 }
4631
4632 Point aScrPos = mrViewData.GetScrPos( nX1, nY1, eWhich );
4633 long nMirrorWidth = GetSizePixel().Width();
4634 bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
4635 if ( bLayoutRTL )
4636 {
4637 long nEndPixel = mrViewData.GetScrPos( nX2+1, nPosY, eWhich ).X();
4638 nMirrorWidth = aScrPos.X() - nEndPixel;
4639 aScrPos.setX( nEndPixel + 1 );
4640 }
4641
4642 long nScrX = aScrPos.X();
4643 long nScrY = aScrPos.Y();
4644
4645 double nPPTX = mrViewData.GetPPTX();
4646 double nPPTY = mrViewData.GetPPTY();
4647
4648 ScTableInfo aTabInfo;
4649 rDoc.FillInfo( aTabInfo, nX1, nY1, nX2, nY2, nTab, nPPTX, nPPTY, false, false );
4650
4651 Fraction aZoomX = mrViewData.GetZoomX();
4652 Fraction aZoomY = mrViewData.GetZoomY();
4653 ScOutputData aOutputData( this, OUTTYPE_WINDOW, aTabInfo, &rDoc, nTab,
4654 nScrX, nScrY, nX1, nY1, nX2, nY2, nPPTX, nPPTY,
4655 &aZoomX, &aZoomY );
4656 aOutputData.SetMirrorWidth( nMirrorWidth );
4657
4658 aOutputData.FindChanged();
4659
4660 // #i122149# do not use old GetChangedArea() which used polygon-based Regions, but use
4661 // the region-band based new version; anyways, only rectangles are added
4662 vcl::Region aChangedRegion( aOutputData.GetChangedAreaRegion() ); // logic (PixelToLogic)
4663 if(!aChangedRegion.IsEmpty())
4664 {
4665 Invalidate(aChangedRegion);
4666 }
4667
4668 CheckNeedsRepaint(); // #i90362# used to be called via Draw() - still needed here
4669}
4670
4671void ScGridWindow::UpdateAutoFillMark(bool bMarked, const ScRange& rMarkRange)
4672{
4673 if ( bMarked != bAutoMarkVisible || ( bMarked && rMarkRange.aEnd != aAutoMarkPos ) )
4674 {
4675 bAutoMarkVisible = bMarked;
4676 if ( bMarked )
4677 aAutoMarkPos = rMarkRange.aEnd;
4678
4679 UpdateAutoFillOverlay();
4680 }
4681}
4682
4683void ScGridWindow::updateLOKInputHelp(const OUString& title, const OUString& content) const
4684{
4685 ScTabViewShell* pViewShell = mrViewData.GetViewShell();
4686
4687 boost::property_tree::ptree aTree;
4688 aTree.put("title", title);
4689 aTree.put("content", content);
4690
4691 std::stringstream aStream;
4692 boost::property_tree::write_json(aStream, aTree);
4693 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_VALIDITY_INPUT_HELP, aStream.str().c_str());
4694}
4695
4696void ScGridWindow::updateLOKValListButton( bool bVisible, const ScAddress& rPos ) const
4697{
4698 SCCOL nX = rPos.Col();
4699 SCROW nY = rPos.Row();
4700 std::stringstream ss;
4701 ss << nX << ", " << nY << ", " << static_cast<unsigned int>(bVisible);
4702 ScTabViewShell* pViewShell = mrViewData.GetViewShell();
4703 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_VALIDITY_LIST_BUTTON, ss.str().c_str());
4704}
4705
4706void ScGridWindow::UpdateListValPos( bool bVisible, const ScAddress& rPos )
4707{
4708 bool bOldButton = bListValButton;
4709 ScAddress aOldPos = aListValPos;
4710
4711 bListValButton = bVisible;
4712 aListValPos = rPos;
4713
4714 if ( bListValButton )
4715 {
4716 if ( !bOldButton || aListValPos != aOldPos )
4717 {
4718 // paint area of new button
4719 if ( comphelper::LibreOfficeKit::isActive() )
4720 {
4721 updateLOKValListButton( true, aListValPos );
4722 }
4723 else
4724 {
4725 Invalidate( PixelToLogic( GetListValButtonRect( aListValPos ) ) );
4726 }
4727 }
4728 }
4729 if ( !bOldButton )
4730 return;
4731
4732 if ( !bListValButton || aListValPos != aOldPos )
4733 {
4734 // paint area of old button
4735 if ( comphelper::LibreOfficeKit::isActive() )
4736 {
4737 updateLOKValListButton( false, aOldPos );
4738 }
4739 else
4740 {
4741 Invalidate( PixelToLogic( GetListValButtonRect( aOldPos ) ) );
4742 }
4743 }
4744}
4745
4746void ScGridWindow::HideCursor()
4747{
4748 ++nCursorHideCount;
4749}
4750
4751void ScGridWindow::ShowCursor()
4752{
4753 --nCursorHideCount;
4754}
4755
4756void ScGridWindow::GetFocus()
4757{
4758 ScTabViewShell* pViewShell = mrViewData.GetViewShell();
4759 pViewShell->SetFormShellAtTop( false ); // focus in GridWindow -> FormShell no longer on top
4760
4761 if (pViewShell->HasAccessibilityObjects())
4762 pViewShell->BroadcastAccessibility(ScAccGridWinFocusGotHint(eWhich));
4763
4764 if ( !SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->IsFormulaMode() )
4765 {
4766 pViewShell->UpdateInputHandler();
4767// StopMarking(); // If Dialog (error), because then no ButtonUp
4768 // MO: only when not in RefInput mode
4769 // -> GetFocus/MouseButtonDown order on Mac
4770 }
4771
4772 mrViewData.GetDocShell()->CheckConfigOptions();
4773 Window::GetFocus();
4774}
4775
4776void ScGridWindow::LoseFocus()
4777{
4778 ScTabViewShell* pViewShell = mrViewData.GetViewShell();
4779
4780 if (pViewShell && pViewShell->HasAccessibilityObjects())
4781 pViewShell->BroadcastAccessibility(ScAccGridWinFocusLostHint(eWhich));
4782
4783 Window::LoseFocus();
4784}
4785
4786bool ScGridWindow::HitRangeFinder( const Point& rMouse, RfCorner& rCorner,
4787 sal_uInt16* pIndex, SCCOL* pAddX, SCROW* pAddY)
4788{
4789 bool bFound = false;
4790 ScInputHandler* pHdl = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->GetInputHdl( mrViewData.GetViewShell() );
4791 if (pHdl)
4792 {
4793 ScRangeFindList* pRangeFinder = pHdl->GetRangeFindList();
4794 if ( pRangeFinder && !pRangeFinder->IsHidden() &&
4795 pRangeFinder->GetDocName() == mrViewData.GetDocShell()->GetTitle() )
4796 {
4797 ScDocument& rDoc = mrViewData.GetDocument();
4798 SCTAB nTab = mrViewData.GetTabNo();
4799 bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
4800 long nLayoutSign = bLayoutRTL ? -1 : 1;
4801
4802 SCCOL nPosX;
4803 SCROW nPosY;
4804 mrViewData.GetPosFromPixel( rMouse.X(), rMouse.Y(), eWhich, nPosX, nPosY );
4805 // merged (single/Range) ???
4806 ScAddress aAddr( nPosX, nPosY, nTab );
4807
4808 Point aCellStart = mrViewData.GetScrPos( nPosX, nPosY, eWhich, true );
4809 Point aCellEnd = aCellStart;
4810 long nSizeXPix;
4811 long nSizeYPix;
4812 mrViewData.GetMergeSizePixel( nPosX, nPosY, nSizeXPix, nSizeYPix );
4813
4814 aCellEnd.AdjustX(nSizeXPix * nLayoutSign );
4815 aCellEnd.AdjustY(nSizeYPix );
4816
4817 bool bCornerHorizontalRight;
4818 bool bCornerHorizontalLeft;
4819 if ( bLayoutRTL )
4820 {
4821 bCornerHorizontalRight = ( rMouse.X() >= aCellEnd.X() && rMouse.X() <= aCellEnd.X() + 8 );
4822 bCornerHorizontalLeft = ( rMouse.X() >= aCellStart.X() - 8 && rMouse.X() <= aCellStart.X() );
4823 }
4824 else
4825 {
4826 bCornerHorizontalRight = ( rMouse.X() >= aCellEnd.X() - 8 && rMouse.X() <= aCellEnd.X() );
4827 bCornerHorizontalLeft = ( rMouse.X() >= aCellStart.X() && rMouse.X() <= aCellStart.X() + 8 );
4828 }
4829
4830 bool bCornerVerticalDown = rMouse.Y() >= aCellEnd.Y() - 8 && rMouse.Y() <= aCellEnd.Y();
4831 bool bCornerVerticalUp = rMouse.Y() >= aCellStart.Y() && rMouse.Y() <= aCellStart.Y() + 8;
4832
4833 // corner is hit only if the mouse is within the cell
4834 sal_uInt16 nCount = static_cast<sal_uInt16>(pRangeFinder->Count());
4835 for (sal_uInt16 i=nCount; i;)
4836 {
4837 // search backwards so that the last repainted frame is found
4838 --i;
4839 ScRangeFindData& rData = pRangeFinder->GetObject(i);
4840 if ( rData.aRef.In(aAddr) )
4841 {
4842 if (pIndex)
4843 *pIndex = i;
4844 if (pAddX)
4845 *pAddX = nPosX - rData.aRef.aStart.Col();
4846 if (pAddY)
4847 *pAddY = nPosY - rData.aRef.aStart.Row();
4848
4849 bFound = true;
4850
4851 rCorner = NONE;
4852
4853 ScAddress aEnd = rData.aRef.aEnd;
4854 ScAddress aStart = rData.aRef.aStart;
4855
4856 if ( bCornerHorizontalLeft && bCornerVerticalUp &&
4857 aAddr == aStart)
4858 {
4859 rCorner = LEFT_UP;
4860 }
4861 else if (bCornerHorizontalRight && bCornerVerticalDown &&
4862 aAddr == aEnd)
4863 {
4864 rCorner = RIGHT_DOWN;
4865 }
4866 else if (bCornerHorizontalRight && bCornerVerticalUp &&
4867 aAddr == ScAddress(aEnd.Col(), aStart.Row(), aStart.Tab()))
4868 {
4869 rCorner = RIGHT_UP;
4870 }
4871 else if (bCornerHorizontalLeft && bCornerVerticalDown &&
4872 aAddr == ScAddress(aStart.Col(), aEnd.Row(), aStart.Tab()))
4873 {
4874 rCorner = LEFT_DOWN;
4875 }
4876 break;
4877 }
4878 }
4879 }
4880 }
4881 return bFound;
4882}
4883
4884#define SCE_TOP1 1
4885#define SCE_BOTTOM2 2
4886#define SCE_LEFT4 4
4887#define SCE_RIGHT8 8
4888#define SCE_ALL15 15
4889
4890static void lcl_PaintOneRange( ScDocShell* pDocSh, const ScRange& rRange, sal_uInt16 nEdges )
4891{
4892 // the range is always properly orientated
4893
4894 SCCOL nCol1 = rRange.aStart.Col();
4895 SCROW nRow1 = rRange.aStart.Row();
4896 SCTAB nTab1 = rRange.aStart.Tab();
4897 SCCOL nCol2 = rRange.aEnd.Col();
4898 SCROW nRow2 = rRange.aEnd.Row();
4899 SCTAB nTab2 = rRange.aEnd.Tab();
4900 bool bHiddenEdge = false;
4901 SCROW nTmp;
4902
4903 ScDocument& rDoc = pDocSh->GetDocument();
4904 while ( nCol1 > 0 && rDoc.ColHidden(nCol1, nTab1) )
4905 {
4906 --nCol1;
4907 bHiddenEdge = true;
4908 }
4909 while ( nCol2 < rDoc.MaxCol() && rDoc.ColHidden(nCol2, nTab1) )
4910 {
4911 ++nCol2;
4912 bHiddenEdge = true;
4913 }
4914 nTmp = rDoc.FirstVisibleRow(0, nRow1, nTab1);
4915 if (!rDoc.ValidRow(nTmp))
4916 nTmp = 0;
4917 if (nTmp < nRow1)
4918 {
4919 nRow1 = nTmp;
4920 bHiddenEdge = true;
4921 }
4922 nTmp = rDoc.FirstVisibleRow(nRow2, rDoc.MaxRow(), nTab1);
4923 if (!rDoc.ValidRow(nTmp))
4924 nTmp = rDoc.MaxRow();
4925 if (nTmp > nRow2)
4926 {
4927 nRow2 = nTmp;
4928 bHiddenEdge = true;
4929 }
4930
4931 if ( nCol2 > nCol1 + 1 && nRow2 > nRow1 + 1 && !bHiddenEdge )
4932 {
4933 // Only along the edges (The corners are hit twice)
4934 if ( nEdges & SCE_TOP1 )
4935 pDocSh->PostPaint( nCol1, nRow1, nTab1, nCol2, nRow1, nTab2, PaintPartFlags::Marks );
4936 if ( nEdges & SCE_LEFT4 )
4937 pDocSh->PostPaint( nCol1, nRow1, nTab1, nCol1, nRow2, nTab2, PaintPartFlags::Marks );
4938 if ( nEdges & SCE_RIGHT8 )
4939 pDocSh->PostPaint( nCol2, nRow1, nTab1, nCol2, nRow2, nTab2, PaintPartFlags::Marks );
4940 if ( nEdges & SCE_BOTTOM2 )
4941 pDocSh->PostPaint( nCol1, nRow2, nTab1, nCol2, nRow2, nTab2, PaintPartFlags::Marks );
4942 }
4943 else // everything in one call
4944 pDocSh->PostPaint( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, PaintPartFlags::Marks );
4945}
4946
4947static void lcl_PaintRefChanged( ScDocShell* pDocSh, const ScRange& rOldUn, const ScRange& rNewUn )
4948{
4949 // Repaint for the parts of the frame in old, which in are no more in New
4950
4951 ScRange aOld = rOldUn;
4952 ScRange aNew = rNewUn;
4953 aOld.PutInOrder();
4954 aNew.PutInOrder();
4955
4956 if ( aOld.aStart == aOld.aEnd ) //! Ignore sheet ?
4957 pDocSh->GetDocument().ExtendMerge(aOld);
4958 if ( aNew.aStart == aNew.aEnd ) //! Ignore sheet ?
4959 pDocSh->GetDocument().ExtendMerge(aNew);
4960
4961 SCCOL nOldCol1 = aOld.aStart.Col();
4962 SCROW nOldRow1 = aOld.aStart.Row();
4963 SCCOL nOldCol2 = aOld.aEnd.Col();
4964 SCROW nOldRow2 = aOld.aEnd.Row();
4965 SCCOL nNewCol1 = aNew.aStart.Col();
4966 SCROW nNewRow1 = aNew.aStart.Row();
4967 SCCOL nNewCol2 = aNew.aEnd.Col();
4968 SCROW nNewRow2 = aNew.aEnd.Row();
4969 SCTAB nTab1 = aOld.aStart.Tab(); // sheet is not changed
4970 SCTAB nTab2 = aOld.aEnd.Tab();
4971
4972 if ( nNewRow2 < nOldRow1 || nNewRow1 > nOldRow2 ||
4973 nNewCol2 < nOldCol1 || nNewCol1 > nOldCol2 ||
4974 ( nNewCol1 != nOldCol1 && nNewRow1 != nOldRow1 &&
4975 nNewCol2 != nOldCol2 && nNewRow2 != nOldRow2 ) )
4976 {
4977 // Completely removed or changed all sides
4978 // (check <= instead of < goes wrong for single rows/columns)
4979
4980 lcl_PaintOneRange( pDocSh, aOld, SCE_ALL15 );
4981 }
4982 else // Test all four corners separately
4983 {
4984 // upper part
4985 if ( nNewRow1 < nOldRow1 ) // only delete upper line
4986 lcl_PaintOneRange( pDocSh, ScRange(
4987 nOldCol1, nOldRow1, nTab1, nOldCol2, nOldRow1, nTab2 ), SCE_ALL15 );
4988 else if ( nNewRow1 > nOldRow1 ) // the upper part which is will be removed
4989 lcl_PaintOneRange( pDocSh, ScRange(
4990 nOldCol1, nOldRow1, nTab1, nOldCol2, nNewRow1-1, nTab2 ),
4991 SCE_ALL15 &~ SCE_BOTTOM2 );
4992
4993 // bottom part
4994 if ( nNewRow2 > nOldRow2 ) // only delete bottom line
4995 lcl_PaintOneRange( pDocSh, ScRange(
4996 nOldCol1, nOldRow2, nTab1, nOldCol2, nOldRow2, nTab2 ), SCE_ALL15 );
4997 else if ( nNewRow2 < nOldRow2 ) // the bottom part which is will be removed
4998 lcl_PaintOneRange( pDocSh, ScRange(
4999 nOldCol1, nNewRow2+1, nTab1, nOldCol2, nOldRow2, nTab2 ),
5000 SCE_ALL15 &~ SCE_TOP1 );
5001
5002 // left part
5003 if ( nNewCol1 < nOldCol1 ) // only delete left line
5004 lcl_PaintOneRange( pDocSh, ScRange(
5005 nOldCol1, nOldRow1, nTab1, nOldCol1, nOldRow2, nTab2 ), SCE_ALL15 );
5006 else if ( nNewCol1 > nOldCol1 ) // the left part which is will be removed
5007 lcl_PaintOneRange( pDocSh, ScRange(
5008 nOldCol1, nOldRow1, nTab1, nNewCol1-1, nOldRow2, nTab2 ),
5009 SCE_ALL15 &~ SCE_RIGHT8 );
5010
5011 // right part
5012 if ( nNewCol2 > nOldCol2 ) // only delete right line
5013 lcl_PaintOneRange( pDocSh, ScRange(
5014 nOldCol2, nOldRow1, nTab1, nOldCol2, nOldRow2, nTab2 ), SCE_ALL15 );
5015 else if ( nNewCol2 < nOldCol2 ) // the right part which is will be removed
5016 lcl_PaintOneRange( pDocSh, ScRange(
5017 nNewCol2+1, nOldRow1, nTab1, nOldCol2, nOldRow2, nTab2 ),
5018 SCE_ALL15 &~ SCE_LEFT4 );
5019 }
5020}
5021
5022void ScGridWindow::RFMouseMove( const MouseEvent& rMEvt, bool bUp )
5023{
5024 ScInputHandler* pHdl = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->GetInputHdl( mrViewData.GetViewShell() );
5025 if (!pHdl)
5026 return;
5027 ScRangeFindList* pRangeFinder = pHdl->GetRangeFindList();
5028 if (!pRangeFinder || nRFIndex >= pRangeFinder->Count())
5029 return;
5030 ScRangeFindData& rData = pRangeFinder->GetObject( nRFIndex );
5031
5032 // Mouse pointer
5033
5034 if (bRFSize)
5035 SetPointer( PointerStyle::Cross );
5036 else
5037 SetPointer( PointerStyle::Hand );
5038
5039 // Scrolling
5040
5041 bool bTimer = false;
5042 Point aPos = rMEvt.GetPosPixel();
5043 SCCOL nDx = 0;
5044 SCROW nDy = 0;
5045 if ( aPos.X() < 0 ) nDx = -1;
5046 if ( aPos.Y() < 0 ) nDy = -1;
5047 Size aSize = GetOutputSizePixel();
5048 if ( aPos.X() >= aSize.Width() )
5049 nDx = 1;
5050 if ( aPos.Y() >= aSize.Height() )
5051 nDy = 1;
5052 if ( nDx != 0 || nDy != 0 )
5053 {
5054 if ( nDx != 0) mrViewData.GetView()->ScrollX( nDx, WhichH(eWhich) );
5055 if ( nDy != 0 ) mrViewData.GetView()->ScrollY( nDy, WhichV(eWhich) );
5056 bTimer = true;
5057 }
5058
5059 // Switching when fixating (so Scrolling works)
5060
5061 if ( eWhich == mrViewData.GetActivePart() ) //??
5062 {
5063 if ( mrViewData.GetHSplitMode() == SC_SPLIT_FIX )
5064 if ( nDx > 0 )
5065 {
5066 if ( eWhich == SC_SPLIT_TOPLEFT )
5067 mrViewData.GetView()->ActivatePart( SC_SPLIT_TOPRIGHT );
5068 else if ( eWhich == SC_SPLIT_BOTTOMLEFT )
5069 mrViewData.GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT );
5070 }
5071
5072 if ( mrViewData.GetVSplitMode() == SC_SPLIT_FIX )
5073 if ( nDy > 0 )
5074 {
5075 if ( eWhich == SC_SPLIT_TOPLEFT )
5076 mrViewData.GetView()->ActivatePart( SC_SPLIT_BOTTOMLEFT );
5077 else if ( eWhich == SC_SPLIT_TOPRIGHT )
5078 mrViewData.GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT );
5079 }
5080 }
5081
5082 // Move
5083
5084 SCCOL nPosX;
5085 SCROW nPosY;
5086 mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
5087
5088 ScRange aOld = rData.aRef;
5089 ScRange aNew = aOld;
5090 if ( bRFSize )
5091 {
5092 switch (aRFSelectedCorned)
5093 {
5094 case LEFT_UP:
5095 aNew.aStart.SetCol(nPosX);
5096 aNew.aStart.SetRow(nPosY);
5097 break;
5098 case LEFT_DOWN:
5099 aNew.aStart.SetCol(nPosX);
5100 aNew.aEnd.SetRow(nPosY);
5101 break;
5102 case RIGHT_UP:
5103 aNew.aEnd.SetCol(nPosX);
5104 aNew.aStart.SetRow(nPosY);
5105 break;
5106 case RIGHT_DOWN:
5107 aNew.aEnd.SetCol(nPosX);
5108 aNew.aEnd.SetRow(nPosY);
5109 break;
5110 default:
5111 break;
5112 }
5113 }
5114 else
5115 {
5116 ScDocument& rDoc = mrViewData.GetDocument();
5117 long nStartX = nPosX - nRFAddX;
5118 if ( nStartX < 0 ) nStartX = 0;
5119 long nStartY = nPosY - nRFAddY;
5120 if ( nStartY < 0 ) nStartY = 0;
5121 long nEndX = nStartX + aOld.aEnd.Col() - aOld.aStart.Col();
5122 if ( nEndX > rDoc.MaxCol() )
5123 {
5124 nStartX -= ( nEndX - rDoc.MaxRow() );
5125 nEndX = rDoc.MaxCol();
5126 }
5127 long nEndY = nStartY + aOld.aEnd.Row() - aOld.aStart.Row();
5128 if ( nEndY > rDoc.MaxRow() )
5129 {
5130 nStartY -= ( nEndY - rDoc.MaxRow() );
5131 nEndY = rDoc.MaxRow();
5132 }
5133
5134 aNew.aStart.SetCol(static_cast<SCCOL>(nStartX));
5135 aNew.aStart.SetRow(static_cast<SCROW>(nStartY));
5136 aNew.aEnd.SetCol(static_cast<SCCOL>(nEndX));
5137 aNew.aEnd.SetRow(static_cast<SCROW>(nEndY));
5138 }
5139
5140 if ( bUp )
5141 aNew.PutInOrder(); // For ButtonUp again in the proper order
5142
5143 if ( aNew != aOld )
5144 {
5145 pHdl->UpdateRange( nRFIndex, aNew );
5146
5147 ScDocShell* pDocSh = mrViewData.GetDocShell();
5148
5149 pHdl->UpdateLokReferenceMarks();
5150
5151 // only redrawing what has been changed...
5152 lcl_PaintRefChanged( pDocSh, aOld, aNew );
5153
5154 // only redraw new frame (synchronously)
5155 pDocSh->Broadcast( ScIndexHint( SfxHintId::ScShowRangeFinder, nRFIndex ) );
5156
5157 PaintImmediately(); // what you move, will be seen immediately
5158 }
5159
5160 // Timer for Scrolling
5161
5162 if (bTimer)
5163 mrViewData.GetView()->SetTimer( this, rMEvt ); // repeat event
5164 else
5165 mrViewData.GetView()->ResetTimer();
5166}
5167
5168namespace {
5169
5170SvxAdjust toSvxAdjust( const ScPatternAttr& rPat )
5171{
5172 SvxCellHorJustify eHorJust =
5173 rPat.GetItem(ATTR_HOR_JUSTIFY).GetValue();
5174
5175 SvxAdjust eSvxAdjust = SvxAdjust::Left;
5176 switch (eHorJust)
5177 {
5178 case SvxCellHorJustify::Left:
5179 case SvxCellHorJustify::Repeat: // not implemented
5180 case SvxCellHorJustify::Standard: // always Text if an EditCell type
5181 eSvxAdjust = SvxAdjust::Left;
5182 break;
5183 case SvxCellHorJustify::Right:
5184 eSvxAdjust = SvxAdjust::Right;
5185 break;
5186 case SvxCellHorJustify::Center:
5187 eSvxAdjust = SvxAdjust::Center;
5188 break;
5189 case SvxCellHorJustify::Block:
5190 eSvxAdjust = SvxAdjust::Block;
5191 break;
5192 }
5193
5194 return eSvxAdjust;
5195}
5196
5197std::shared_ptr<ScFieldEditEngine> createEditEngine( ScDocShell* pDocSh, const ScPatternAttr& rPat )
5198{
5199 ScDocument& rDoc = pDocSh->GetDocument();
5200
5201 auto pEngine = std::make_shared<ScFieldEditEngine>(&rDoc, rDoc.GetEditPool());
5202 ScSizeDeviceProvider aProv(pDocSh);
5203 pEngine->SetRefDevice(aProv.GetDevice());
5204 pEngine->SetRefMapMode(MapMode(MapUnit::Map100thMM));
5205 SfxItemSet aDefault = pEngine->GetEmptyItemSet();
5206 rPat.FillEditItemSet(&aDefault);
5207 aDefault.Put( SvxAdjustItem(toSvxAdjust(rPat), EE_PARA_JUST) );
5208 pEngine->SetDefaults(aDefault);
5209
5210 return pEngine;
5211}
5212
5213bool extractURLInfo( const SvxFieldItem* pFieldItem, OUString* pName, OUString* pUrl, OUString* pTarget )
5214{
5215 if (!pFieldItem)
5216 return false;
5217
5218 const SvxFieldData* pField = pFieldItem->GetField();
5219 if (pField->GetClassId() != text::textfield::Type::URL)
5220 return false;
5221
5222 const SvxURLField* pURLField = static_cast<const SvxURLField*>(pField);
5223
5224 if (pName)
5225 *pName = pURLField->GetRepresentation();
5226 if (pUrl)
5227 *pUrl = pURLField->GetURL();
5228 if (pTarget)
5229 *pTarget = pURLField->GetTargetFrame();
5230
5231 return true;
5232}
5233
5234}
5235
5236bool ScGridWindow::GetEditUrl( const Point& rPos,
5237 OUString* pName, OUString* pUrl, OUString* pTarget )
5238{
5239 ScTabViewShell* pViewSh = mrViewData.GetViewShell();
5240 ScInputHandler* pInputHdl = nullptr;
5241 if (pViewSh)
5242 pInputHdl = pViewSh->GetInputHandler();
5243 EditView* pView = (pInputHdl && pInputHdl->IsInputMode()) ? pInputHdl->GetTableView() : nullptr;
5244 if (pView)
5245 return extractURLInfo(pView->GetFieldUnderMousePointer(), pName, pUrl, pTarget);
5246
5247 //! Pass on nPosX/Y?
5248 SCCOL nPosX;
5249 SCROW nPosY;
5250 mrViewData.GetPosFromPixel( rPos.X(), rPos.Y(), eWhich, nPosX, nPosY );
5251
5252 SCTAB nTab = mrViewData.GetTabNo();
5253 ScDocShell* pDocSh = mrViewData.GetDocShell();
5254 ScDocument& rDoc = pDocSh->GetDocument();
5255 OUString sURL;
5256 ScRefCellValue aCell;
5257 bool bFound = lcl_GetHyperlinkCell(rDoc, nPosX, nPosY, nTab, aCell, sURL);
5258 if( !bFound )
5259 return false;
5260
5261 const ScPatternAttr* pPattern = rDoc.GetPattern( nPosX, nPosY, nTab );
5262 // bForceToTop = sal_False, use the cell's real position
5263 tools::Rectangle aEditRect = mrViewData.GetEditArea( eWhich, nPosX, nPosY, this, pPattern, false );
5264 if (rPos.Y() < aEditRect.Top())
5265 return false;
5266
5267 // vertical can not (yet) be clicked:
5268
5269 if (pPattern->GetCellOrientation() != SvxCellOrientation::Standard)
5270 return false;
5271
5272 bool bBreak = pPattern->GetItem(ATTR_LINEBREAK).GetValue() ||
5273 (pPattern->GetItem( ATTR_HOR_JUSTIFY ).GetValue() == SvxCellHorJustify::Block);
5274 SvxCellHorJustify eHorJust = pPattern->GetItem(ATTR_HOR_JUSTIFY).GetValue();
5275
5276 // EditEngine
5277
5278 std::shared_ptr<ScFieldEditEngine> pEngine = createEditEngine(pDocSh, *pPattern);
5279
5280 MapMode aEditMode = mrViewData.GetLogicMode(eWhich); // without draw scaling
5281 tools::Rectangle aLogicEdit = PixelToLogic( aEditRect, aEditMode );
5282 long nThisColLogic = aLogicEdit.Right() - aLogicEdit.Left() + 1;
5283 Size aPaperSize( 1000000, 1000000 );
5284 if (aCell.meType == CELLTYPE_FORMULA)
5285 {
5286 long nSizeX = 0;
5287 long nSizeY = 0;
5288 mrViewData.GetMergeSizePixel( nPosX, nPosY, nSizeX, nSizeY );
5289 aPaperSize = Size(nSizeX, nSizeY );
5290 aPaperSize = PixelToLogic(aPaperSize);
5291 }
5292
5293 if (bBreak)
5294 aPaperSize.setWidth( nThisColLogic );
5295 pEngine->SetPaperSize( aPaperSize );
5296
5297 std::unique_ptr<EditTextObject> pTextObj;
5298 if (aCell.meType == CELLTYPE_EDIT)
5299 {
5300 if (aCell.mpEditText)
5301 pEngine->SetTextCurrentDefaults(*aCell.mpEditText);
5302 }
5303 else // Not an Edit cell and is a formula cell with 'Hyperlink'
5304 // function if we have no URL, otherwise it could be a formula
5305 // cell ( or other type ? ) with a hyperlink associated with it.
5306 {
5307 if (sURL.isEmpty())
5308 pTextObj = aCell.mpFormula->CreateURLObject();
5309 else
5310 {
5311 OUString aRepres = sURL;
5312
5313 // TODO: text content of formatted numbers can be different
5314 if (aCell.hasNumeric())
5315 aRepres = OUString::number(aCell.getValue());
5316 else if (aCell.meType == CELLTYPE_FORMULA)
5317 aRepres = aCell.mpFormula->GetString().getString();
5318
5319 pTextObj = ScEditUtil::CreateURLObjectFromURL(rDoc, sURL, aRepres);
5320 }
5321
5322 if (pTextObj)
5323 pEngine->SetTextCurrentDefaults(*pTextObj);
5324 }
5325
5326 long nStartX = aLogicEdit.Left();
5327
5328 long nTextWidth = pEngine->CalcTextWidth();
5329 long nTextHeight = pEngine->GetTextHeight();
5330 if ( nTextWidth < nThisColLogic )
5331 {
5332 if (eHorJust == SvxCellHorJustify::Right)
5333 nStartX += nThisColLogic - nTextWidth;
5334 else if (eHorJust == SvxCellHorJustify::Center)
5335 nStartX += (nThisColLogic - nTextWidth) / 2;
5336 }
5337
5338 aLogicEdit.SetLeft( nStartX );
5339 if (!bBreak)
5340 aLogicEdit.SetRight( nStartX + nTextWidth );
5341
5342 // There is one glitch when dealing with a hyperlink cell and
5343 // the cell content is NUMERIC. This defaults to right aligned and
5344 // we need to adjust accordingly.
5345 if (aCell.hasNumeric() && eHorJust == SvxCellHorJustify::Standard)
5346 {
5347 aLogicEdit.SetRight( aLogicEdit.Left() + nThisColLogic - 1 );
5348 aLogicEdit.SetLeft( aLogicEdit.Right() - nTextWidth );
5349 }
5350 aLogicEdit.SetBottom( aLogicEdit.Top() + nTextHeight );
5351
5352 Point aLogicClick = PixelToLogic(rPos,aEditMode);
5353 if ( aLogicEdit.IsInside(aLogicClick) )
5354 {
5355 EditView aTempView(pEngine.get(), this);
5356 aTempView.SetOutputArea( aLogicEdit );
5357
5358 bool bRet;
5359 if (comphelper::LibreOfficeKit::isActive())
5360 {
5361 bRet = extractURLInfo(aTempView.GetField(aLogicClick), pName, pUrl, pTarget);
5362 }
5363 else
5364 {
5365 MapMode aOld = GetMapMode();
5366 SetMapMode(aEditMode); // no return anymore
5367 bRet = extractURLInfo(aTempView.GetFieldUnderMousePointer(), pName, pUrl, pTarget);
5368 SetMapMode(aOld);
5369 }
5370 return bRet;
5371 }
5372 return false;
5373}
5374
5375bool ScGridWindow::IsSpellErrorAtPos( const Point& rPos, SCCOL nCol1, SCROW nRow )
5376{
5377 if (!mpSpellCheckCxt)
5378 return false;
5379
5380 SCTAB nTab = mrViewData.GetTabNo();
5381 ScDocShell* pDocSh = mrViewData.GetDocShell();
5382 ScDocument& rDoc = pDocSh->GetDocument();
5383
5384 ScAddress aCellPos(nCol1, nRow, nTab);
5385 ScRefCellValue aCell(rDoc, aCellPos);
5386 if (aCell.meType != CELLTYPE_STRING && aCell.meType != CELLTYPE_EDIT)
5387 return false;
5388
5389 const std::vector<editeng::MisspellRanges>* pRanges = mpSpellCheckCxt->getMisspellRanges(nCol1, nRow);
5390 if (!pRanges)
5391 return false;
5392
5393 const ScPatternAttr* pPattern = rDoc.GetPattern(nCol1, nRow, nTab);
5394
5395 tools::Rectangle aEditRect = mrViewData.GetEditArea(eWhich, nCol1, nRow, this, pPattern, false);
5396 if (rPos.Y() < aEditRect.Top())
5397 return false;
5398
5399 std::shared_ptr<ScFieldEditEngine> pEngine = createEditEngine(pDocSh, *pPattern);
5400
5401 Size aPaperSize(1000000, 1000000);
5402 pEngine->SetPaperSize(aPaperSize);
5403
5404 if (aCell.meType == CELLTYPE_EDIT)
5405 pEngine->SetTextCurrentDefaults(*aCell.mpEditText);
5406 else
5407 pEngine->SetTextCurrentDefaults(aCell.mpString->getString());
5408
5409 long nTextWidth = static_cast<long>(pEngine->CalcTextWidth());
5410
5411 MapMode aEditMode = mrViewData.GetLogicMode(eWhich);
5412 tools::Rectangle aLogicEdit = PixelToLogic(aEditRect, aEditMode);
5413 Point aLogicClick = PixelToLogic(rPos, aEditMode);
5414
5415 aLogicEdit.setWidth(nTextWidth + 1);
5416
5417 if (!aLogicEdit.IsInside(aLogicClick))
5418 return false;
5419
5420 pEngine->SetControlWord(pEngine->GetControlWord() | EEControlBits::ONLINESPELLING);
5421 pEngine->SetAllMisspellRanges(*pRanges);
5422
5423 EditView aTempView(pEngine.get(), this);
5424 aTempView.SetOutputArea(aLogicEdit);
5425
5426 return aTempView.IsWrongSpelledWordAtPos(rPos);
5427}
5428
5429bool ScGridWindow::HasScenarioButton( const Point& rPosPixel, ScRange& rScenRange )
5430{
5431 ScDocument& rDoc = mrViewData.GetDocument();
5432 SCTAB nTab = mrViewData.GetTabNo();
5433 SCTAB nTabCount = rDoc.GetTableCount();
5434 if ( nTab+1<nTabCount && rDoc.IsScenario(nTab+1) && !rDoc.IsScenario(nTab) )
5435 {
5436 bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
5437
5438 Size aButSize = mrViewData.GetScenButSize();
5439 long nBWidth = aButSize.Width();
5440 if (!nBWidth)
5441 return false; // No Button drawn yet -> there is none
5442 long nBHeight = aButSize.Height();
5443 long nHSpace = static_cast<long>( SC_SCENARIO_HSPACE60 * mrViewData.GetPPTX() );
5444
5445 //! cache the Ranges in Table!!!!
5446
5447 ScMarkData aMarks(rDoc.GetSheetLimits());
5448 for (SCTAB i=nTab+1; i<nTabCount && rDoc.IsScenario(i); i++)
5449 rDoc.MarkScenario( i, nTab, aMarks, false, ScScenarioFlags::ShowFrame );
5450 ScRangeList aRanges;
5451 aMarks.FillRangeListWithMarks( &aRanges, false );
5452
5453 size_t nRangeCount = aRanges.size();
5454 for (size_t j=0; j< nRangeCount; ++j)
5455 {
5456 ScRange aRange = aRanges[j];
5457 // Always extend scenario frame to merged cells where no new non-covered cells
5458 // are framed
5459 rDoc.ExtendTotalMerge( aRange );
5460
5461 bool bTextBelow = ( aRange.aStart.Row() == 0 );
5462
5463 Point aButtonPos;
5464 if ( bTextBelow )
5465 {
5466 aButtonPos = mrViewData.GetScrPos( aRange.aEnd.Col()+1, aRange.aEnd.Row()+1,
5467 eWhich, true );
5468 }
5469 else
5470 {
5471 aButtonPos = mrViewData.GetScrPos( aRange.aEnd.Col()+1, aRange.aStart.Row(),
5472 eWhich, true );
5473 aButtonPos.AdjustY( -nBHeight );
5474 }
5475 if ( bLayoutRTL )
5476 aButtonPos.AdjustX( -(nHSpace - 1) );
5477 else
5478 aButtonPos.AdjustX( -(nBWidth - nHSpace) ); // same for top or bottom
5479
5480 tools::Rectangle aButRect( aButtonPos, Size(nBWidth,nBHeight) );
5481 if ( aButRect.IsInside( rPosPixel ) )
5482 {
5483 rScenRange = aRange;
5484 return true;
5485 }
5486 }
5487 }
5488
5489 return false;
5490}
5491
5492void ScGridWindow::DrawLayerCreated()
5493{
5494 SetMapMode( GetDrawMapMode() );
5495
5496 // initially create overlay objects
5497 ImpCreateOverlayObjects();
5498}
5499
5500namespace {
5501
5502struct SpellCheckStatus
5503{
5504 bool mbModified;
5505
5506 SpellCheckStatus() : mbModified(false) {};
5507
5508 DECL_LINK( EventHdl, EditStatus&, void )static void LinkStubEventHdl(void *, EditStatus&); void EventHdl
(EditStatus&)
;
5509};
5510
5511IMPL_LINK(SpellCheckStatus, EventHdl, EditStatus&, rStatus, void)void SpellCheckStatus::LinkStubEventHdl(void * instance, EditStatus
& data) { return static_cast<SpellCheckStatus *>(instance
)->EventHdl(data); } void SpellCheckStatus::EventHdl(EditStatus
& rStatus)
5512{
5513 EditStatusFlags nStatus = rStatus.GetStatusWord();
5514 if (nStatus & EditStatusFlags::WRONGWORDCHANGED)
5515 mbModified = true;
5516}
5517
5518}
5519
5520bool ScGridWindow::ContinueOnlineSpelling()
5521{
5522 if (!mpSpellCheckCxt)
5523 return false;
5524
5525 if (!mpSpellCheckCxt->maPos.isValid())
5526 return false;
5527
5528 ScDocument& rDoc = mrViewData.GetDocument();
5529 ScDPCollection* pDPs = nullptr;
5530 if (rDoc.HasPivotTable())
5531 pDPs = rDoc.GetDPCollection();
5532
5533 SCTAB nTab = mrViewData.GetTabNo();
5534 SpellCheckStatus aStatus;
5535
5536 ScHorizontalCellIterator aIter(
5537 rDoc, nTab, maVisibleRange.mnCol1, mpSpellCheckCxt->maPos.mnRow, maVisibleRange.mnCol2, maVisibleRange.mnRow2);
5538
5539 ScRangeList aPivotRanges = pDPs ? pDPs->GetAllTableRanges(nTab) : ScRangeList();
5540
5541 SCCOL nCol;
5542 SCROW nRow;
5543 ScRefCellValue* pCell = aIter.GetNext(nCol, nRow);
5544 SCROW nEndRow = 0;
5545 bool bHidden = pCell && rDoc.RowHidden(nRow, nTab, nullptr, &nEndRow);
5546 bool bSkip = pCell && (nRow < mpSpellCheckCxt->maPos.mnRow || bHidden);
5547 while (bSkip)
5548 {
5549 pCell = aIter.GetNext(nCol, nRow);
5550 if (pCell && nRow > nEndRow)
5551 {
5552 bHidden = rDoc.RowHidden(nRow, nTab, nullptr, &nEndRow);
5553 }
5554 bSkip = pCell && (nRow < mpSpellCheckCxt->maPos.mnRow || bHidden);
5555 }
5556
5557 SCCOL nEndCol = 0;
5558 bHidden = pCell && rDoc.ColHidden(nCol, nTab, nullptr, &nEndCol);
5559 bSkip = pCell && (nCol < mpSpellCheckCxt->maPos.mnCol || bHidden);
5560 while (bSkip)
5561 {
5562 pCell = aIter.GetNext(nCol, nRow);
5563 if (pCell && nCol > nEndCol)
5564 {
5565 bHidden = rDoc.ColHidden(nCol, nTab, nullptr, &nEndCol);
5566 }
5567 bSkip = pCell && (nCol < mpSpellCheckCxt->maPos.mnCol || bHidden);
5568 }
5569
5570 std::unique_ptr<ScTabEditEngine> pEngine;
5571
5572 // Check only up to 256 cells at a time.
5573 size_t nTotalCellCount = 0;
5574 size_t nTextCellCount = 0;
5575 bool bSpellCheckPerformed = false;
5576
5577 while (pCell)
5578 {
5579 ++nTotalCellCount;
5580
5581 if (aPivotRanges.In(ScAddress(nCol, nRow, nTab)))
5582 {
5583 // Don't spell check within pivot tables.
5584 if (nTotalCellCount >= 255)
5585 break;
5586
5587 pCell = aIter.GetNext(nCol, nRow);
5588 continue;
5589 }
5590
5591 CellType eType = pCell->meType;
5592 if (eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT)
5593 {
5594 ++nTextCellCount;
5595
5596 // NB: For spell-checking, we currently only use the primary
5597 // language; not CJK nor CTL.
5598 const ScPatternAttr* pPattern = rDoc.GetPattern(nCol, nRow, nTab);
5599 LanguageType nCellLang = pPattern->GetItem(ATTR_FONT_LANGUAGE).GetValue();
5600
5601 if (nCellLang == LANGUAGE_SYSTEMLanguageType(0x0000))
5602 nCellLang = Application::GetSettings().GetLanguageTag().getLanguageType(); // never use SYSTEM for spelling
5603
5604 if (nCellLang == LANGUAGE_NONELanguageType(0x00FF))
5605 {
5606 // No need to spell check this cell.
5607 pCell = aIter.GetNext(nCol, nRow);
5608 continue;
5609 }
5610
5611 if (!pEngine)
5612 {
5613 // ScTabEditEngine is needed
5614 // because MapMode must be set for some old documents
5615 pEngine.reset(new ScTabEditEngine(&rDoc));
5616 pEngine->SetControlWord(
5617 pEngine->GetControlWord() | (EEControlBits::ONLINESPELLING | EEControlBits::ALLOWBIGOBJS));
5618 pEngine->SetStatusEventHdl(LINK(&aStatus, SpellCheckStatus, EventHdl)::tools::detail::makeLink( ::tools::detail::castTo<SpellCheckStatus
*>(&aStatus), &SpellCheckStatus::LinkStubEventHdl
)
);
5619 // Delimiters here like in inputhdl.cxx !!!
5620 pEngine->SetWordDelimiters(
5621 ScEditUtil::ModifyDelimiters(pEngine->GetWordDelimiters()));
5622
5623 uno::Reference<linguistic2::XSpellChecker1> xXSpellChecker1(LinguMgr::GetSpellChecker());
5624 pEngine->SetSpeller(xXSpellChecker1);
5625 pEngine->SetDefaultLanguage(ScGlobal::GetEditDefaultLanguage());
5626 }
5627
5628 pEngine->SetDefaultItem(SvxLanguageItem(nCellLang, EE_CHAR_LANGUAGE));
5629
5630 if (eType == CELLTYPE_STRING)
5631 pEngine->SetTextCurrentDefaults(pCell->mpString->getString());
5632 else
5633 pEngine->SetTextCurrentDefaults(*pCell->mpEditText);
5634
5635 aStatus.mbModified = false;
5636 pEngine->CompleteOnlineSpelling();
5637 if (aStatus.mbModified)
5638 {
5639 std::vector<editeng::MisspellRanges> aRanges;
5640 pEngine->GetAllMisspellRanges(aRanges);
5641 if (!aRanges.empty())
5642 {
5643 sc::SpellCheckContext::CellPos aPos(nCol, nRow);
5644 mpSpellCheckCxt->maMisspellCells.emplace(aPos, aRanges);
5645 }
5646
5647 // Broadcast for re-paint.
5648 ScPaintHint aHint(ScRange(nCol, nRow, nTab), PaintPartFlags::Grid);
5649 aHint.SetPrintFlag(false);
5650 rDoc.GetDocumentShell()->Broadcast(aHint);
5651 }
5652
5653 bSpellCheckPerformed = true;
5654 }
5655
5656 if (nTotalCellCount >= 255 || nTextCellCount >= 1)
5657 break;
5658
5659 pCell = aIter.GetNext(nCol, nRow);
5660 }
5661
5662 if (pCell)
5663 // Move to the next cell position for the next iteration.
5664 pCell = aIter.GetNext(nCol, nRow);
5665
5666 if (pCell)
5667 {
5668 // This will become the first cell position for the next time.
5669 mpSpellCheckCxt->maPos.mnCol = nCol;
5670 mpSpellCheckCxt->maPos.mnRow = nRow;
5671 }
5672 else
5673 {
5674 // No more cells to spell check.
5675 mpSpellCheckCxt->maPos.setInvalid();
5676 }
5677
5678 return bSpellCheckPerformed;
5679}
5680
5681void ScGridWindow::EnableAutoSpell( bool bEnable )
5682{
5683 if (bEnable)
5684 mpSpellCheckCxt.reset(new sc::SpellCheckContext);
5685 else
5686 mpSpellCheckCxt.reset();
5687}
5688
5689void ScGridWindow::ResetAutoSpell()
5690{
5691 if (mpSpellCheckCxt)
5692 {
5693 mpSpellCheckCxt->reset();
5694 mpSpellCheckCxt->maPos.mnCol = maVisibleRange.mnCol1;
5695 mpSpellCheckCxt->maPos.mnRow = maVisibleRange.mnRow1;
5696 }
5697}
5698
5699void ScGridWindow::SetAutoSpellData( SCCOL nPosX, SCROW nPosY, const std::vector<editeng::MisspellRanges>* pRanges )
5700{
5701 if (!mpSpellCheckCxt)
5702 return;
5703
5704 if (!maVisibleRange.isInside(nPosX, nPosY))
5705 return;
5706
5707 mpSpellCheckCxt->setMisspellRanges(nPosX, nPosY, pRanges);
5708}
5709
5710const std::vector<editeng::MisspellRanges>* ScGridWindow::GetAutoSpellData( SCCOL nPosX, SCROW nPosY )
5711{
5712 if (!mpSpellCheckCxt)
5713 return nullptr;
5714
5715 if (!maVisibleRange.isInside(nPosX, nPosY))
5716 return nullptr;
5717
5718 return mpSpellCheckCxt->getMisspellRanges(nPosX, nPosY);
5719}
5720
5721bool ScGridWindow::InsideVisibleRange( SCCOL nPosX, SCROW nPosY )
5722{
5723 return maVisibleRange.isInside(nPosX, nPosY);
5724}
5725
5726OString ScGridWindow::getCellCursor() const
5727{
5728 // GridWindow stores a shown cell cursor in mpOOCursors, hence
5729 // we can use that to determine whether we would want to be showing
5730 // one (client-side) for tiled rendering too.
5731 if (!mpOOCursors)
5732 return "EMPTY";
5733
5734 if (comphelper::LibreOfficeKit::isCompatFlagSet(
5735 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs))
5736 return mrViewData.describeCellCursorInPrintTwips();
5737
5738 return mrViewData.describeCellCursor();
5739}
5740
5741void ScGridWindow::notifyKitCellCursor() const
5742{
5743 ScTabViewShell* pViewShell = mrViewData.GetViewShell();
5744
5745 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_CURSOR, getCellCursor().getStr());
5746 if (bListValButton && aListValPos == mrViewData.GetCurPos())
5747 updateLOKValListButton(true, aListValPos);
5748}
5749
5750void ScGridWindow::notifyKitCellViewCursor(const SfxViewShell* pForShell) const
5751{
5752 ScTabViewShell* pViewShell = mrViewData.GetViewShell();
5753
5754 if (pViewShell->GetDocId() != pForShell->GetDocId())
5755 return;
5756
5757 OString aCursor("EMPTY");
5758 if (mpOOCursors) // cf. getCellCursor above
5759 {
5760 auto pForTabView = dynamic_cast<const ScTabViewShell *>(pForShell);
5761 if (!pForTabView)
5762 return;
5763
5764 if (comphelper::LibreOfficeKit::isCompatFlagSet(
5765 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs))
5766 aCursor = mrViewData.describeCellCursorInPrintTwips();
5767 else
5768 aCursor = pForTabView->GetViewData().describeCellCursorAt(
5769 mrViewData.GetCurX(), mrViewData.GetCurY()); // our position.
5770 }
5771 SfxLokHelper::notifyOtherView(pViewShell, pForShell, LOK_CALLBACK_CELL_VIEW_CURSOR, "rectangle", aCursor);
5772}
5773
5774// Send our cursor details to a view described by @pForShell, or all views
5775// if @pForShell is null. In each case send the current view a cell-cursor
5776// event, and others a cell_view_cursor event.
5777//
5778// NB. we need to re-construct the cursor details for each other view in their
5779// own zoomed co-ordinate system (but not in scPrintTwipsMsgs mode).
5780void ScGridWindow::updateKitCellCursor(const SfxViewShell* pForShell) const
5781{
5782 if (comphelper::LibreOfficeKit::isCompatFlagSet(
5783 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs))
5784 {
5785 ScTabViewShell* pViewShell = mrViewData.GetViewShell();
5786 // Generate the cursor info string just once and directly send to all.
5787 // Calling notifyKitCellViewCursor() would regenerate the
5788 // cursor-string unnecessarily.
5789 OString aCursor = getCellCursor();
5790
5791 if (pForShell)
5792 {
5793 SfxLokHelper::notifyOtherView(pViewShell, pForShell,
5794 LOK_CALLBACK_CELL_VIEW_CURSOR, "rectangle", aCursor);
5795 }
5796 else
5797 {
5798 notifyKitCellCursor();
5799 SfxLokHelper::notifyOtherViews(pViewShell,
5800 LOK_CALLBACK_CELL_VIEW_CURSOR, "rectangle", aCursor);
5801 }
5802
5803 return;
5804 }
5805
5806 if (!pForShell)
5807 {
5808 for (SfxViewShell* it = SfxViewShell::GetFirst(); it;
5809 it = SfxViewShell::GetNext(*it))
5810 updateKitCellCursor(it);
5811 return;
5812 }
5813
5814 if (pForShell == mrViewData.GetViewShell())
5815 notifyKitCellCursor();
5816 else
5817 notifyKitCellViewCursor(pForShell);
5818}
5819
5820void ScGridWindow::updateKitOtherCursors() const
5821{
5822 for (SfxViewShell* it = SfxViewShell::GetFirst(); it;
5823 it = SfxViewShell::GetNext(*it))
5824 {
5825 auto pOther = dynamic_cast<const ScTabViewShell *>(it);
5826 if (!pOther)
5827 continue;
5828 const ScGridWindow *pGrid = pOther->GetViewData().GetActiveWin();
5829 assert(pGrid)(static_cast <bool> (pGrid) ? void (0) : __assert_fail (
"pGrid", "/home/maarten/src/libreoffice/core/sc/source/ui/view/gridwin.cxx"
, 5829, __extension__ __PRETTY_FUNCTION__))
;
5830 if (pGrid == this)
5831 notifyKitCellCursor();
5832 else
5833 pGrid->notifyKitCellViewCursor(mrViewData.GetViewShell());
5834 }
5835}
5836
5837void ScGridWindow::CursorChanged()
5838{
5839 // here the created OverlayObjects may be transformed in later versions. For
5840 // now, just re-create them
5841
5842 UpdateCursorOverlay();
5843}
5844
5845void ScGridWindow::ImpCreateOverlayObjects()
5846{
5847 UpdateCursorOverlay();
5848 UpdateCopySourceOverlay();
5849 UpdateSelectionOverlay();
5850 UpdateAutoFillOverlay();
5851 UpdateDragRectOverlay();
5852 UpdateHeaderOverlay();
5853 UpdateShrinkOverlay();
5854}
5855
5856void ScGridWindow::ImpDestroyOverlayObjects()
5857{
5858 DeleteCursorOverlay();
5859 DeleteCopySourceOverlay();
5860 DeleteSelectionOverlay();
5861 DeleteAutoFillOverlay();
5862 DeleteDragRectOverlay();
5863 DeleteHeaderOverlay();
5864 DeleteShrinkOverlay();
5865}
5866
5867void ScGridWindow::UpdateAllOverlays()
5868{
5869 // delete and re-allocate all overlay objects
5870
5871 ImpDestroyOverlayObjects();
5872 ImpCreateOverlayObjects();
5873}
5874
5875void ScGridWindow::DeleteCursorOverlay()
5876{
5877 ScTabViewShell* pViewShell = mrViewData.GetViewShell();
5878 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_CURSOR, "EMPTY");
5879 SfxLokHelper::notifyOtherViews(pViewShell, LOK_CALLBACK_CELL_VIEW_CURSOR, "rectangle", "EMPTY");
5880 mpOOCursors.reset();
5881}
5882
5883void ScGridWindow::DeleteCopySourceOverlay()
5884{
5885 mpOOSelectionBorder.reset();
5886}
5887
5888void ScGridWindow::UpdateCopySourceOverlay()
5889{
5890 MapMode aDrawMode = GetDrawMapMode();
5891 MapMode aOldMode = GetMapMode();
5892 if ( aOldMode != aDrawMode )
5893 SetMapMode( aDrawMode );
5894
5895 DeleteCopySourceOverlay();
5896
5897 if (comphelper::LibreOfficeKit::isActive())
5898 return;
5899 if (!mrViewData.ShowPasteSource())
5900 return;
5901 rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = getOverlayManager();
5902 if (!xOverlayManager.is())
5903 return;
5904 const ScTransferObj* pTransObj = ScTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(mrViewData.GetActiveWin()));
5905 if (!pTransObj)
5906 return;
5907 ScDocument* pClipDoc = pTransObj->GetDocument();
5908 if (!pClipDoc)
5909 return;
5910
5911 SCTAB nCurTab = mrViewData.GetCurPos().Tab();
5912
5913 ScClipParam& rClipParam = pClipDoc->GetClipParam();
5914 mpOOSelectionBorder.reset(new sdr::overlay::OverlayObjectList);
5915 for ( size_t i = 0; i < rClipParam.maRanges.size(); ++i )
5916 {
5917 ScRange const & r = rClipParam.maRanges[i];
5918 if (r.aStart.Tab() != nCurTab)
5919 continue;
5920
5921 SCCOL nClipStartX = r.aStart.Col();
5922 SCROW nClipStartY = r.aStart.Row();
5923 SCCOL nClipEndX = r.aEnd.Col();
5924 SCROW nClipEndY = r.aEnd.Row();
5925
5926 Point aClipStartScrPos = mrViewData.GetScrPos( nClipStartX, nClipStartY, eWhich );
5927 Point aClipEndScrPos = mrViewData.GetScrPos( nClipEndX + 1, nClipEndY + 1, eWhich );
5928 aClipStartScrPos -= Point(1, 1);
5929 long nSizeXPix = aClipEndScrPos.X() - aClipStartScrPos.X();
5930 long nSizeYPix = aClipEndScrPos.Y() - aClipStartScrPos.Y();
5931
5932 tools::Rectangle aRect( aClipStartScrPos, Size(nSizeXPix, nSizeYPix) );
5933
5934 Color aHighlight = GetSettings().GetStyleSettings().GetHighlightColor();
5935
5936 tools::Rectangle aLogic = PixelToLogic(aRect, aDrawMode);
5937 ::basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(aLogic);
5938 std::unique_ptr<ScOverlayDashedBorder> pDashedBorder(new ScOverlayDashedBorder(aRange, aHighlight));
5939 xOverlayManager->add(*pDashedBorder);
5940 mpOOSelectionBorder->append(std::move(pDashedBorder));
5941 }
5942
5943 if ( aOldMode != aDrawMode )
5944 SetMapMode( aOldMode );
5945}
5946
5947static std::vector<tools::Rectangle> convertPixelToLogical(
5948 const ScViewData& rViewData,
5949 const std::vector<tools::Rectangle>& rRectangles,
5950 tools::Rectangle &rBoundingBox)
5951{
5952 std::vector<tools::Rectangle> aLogicRects;
5953
5954 double nPPTX = rViewData.GetPPTX();
5955 double nPPTY = rViewData.GetPPTY();
5956
5957 for (const auto& rRectangle : rRectangles)
5958 {
5959 // We explicitly create a copy, since we need to expand
5960 // the rectangle before coordinate conversion
5961 tools::Rectangle aRectangle(rRectangle);
5962 aRectangle.AdjustRight(1 );
5963 aRectangle.AdjustBottom(1 );
5964
5965 tools::Rectangle aRect(aRectangle.Left() / nPPTX, aRectangle.Top() / nPPTY,
5966 aRectangle.Right() / nPPTX, aRectangle.Bottom() / nPPTY);
5967
5968 rBoundingBox.Union(aRect);
5969 aLogicRects.push_back(aRect);
5970 }
5971 return aLogicRects;
5972}
5973
5974static OString rectanglesToString(const std::vector<tools::Rectangle> &rLogicRects)
5975{
5976 bool bFirst = true;
5977 OStringBuffer aRects;
5978 for (const auto &rRect : rLogicRects)
5979 {
5980 if (!bFirst)
5981 aRects.append("; ");
5982 bFirst = false;
5983 aRects.append(rRect.toString());
5984 }
5985 return aRects.makeStringAndClear();
5986}
5987
5988/**
5989 * Turn the selection ranges rRectangles into the LibreOfficeKit selection, and send to other views.
5990 *
5991 * @param pLogicRects - if set then don't invoke the callback, just collect the rectangles in the pointed vector.
5992 */
5993void ScGridWindow::UpdateKitSelection(const std::vector<tools::Rectangle>& rRectangles, std::vector<tools::Rectangle>* pLogicRects)
5994{
5995 if (!comphelper::LibreOfficeKit::isActive())
5996 return;
5997
5998 // If this is true, rRectangles should already in print twips.
5999 // If false, rRectangles are in pixels.
6000 bool bInPrintTwips = comphelper::LibreOfficeKit::isCompatFlagSet(
6001 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs);
6002
6003 tools::Rectangle aBoundingBox;
6004 std::vector<tools::Rectangle> aConvertedRects;
6005
6006 if (bInPrintTwips)
6007 std::for_each(rRectangles.begin(), rRectangles.end(),
6008 [&aBoundingBox](const tools::Rectangle& rRect) { aBoundingBox.Union(rRect); });
6009 else
6010 aConvertedRects = convertPixelToLogical(mrViewData, rRectangles, aBoundingBox);
6011
6012 const std::vector<tools::Rectangle>& rLogicRects = bInPrintTwips ? rRectangles : aConvertedRects;
6013 if (pLogicRects)
6014 {
6015 *pLogicRects = rLogicRects;
6016 return;
6017 }
6018
6019 ScTabViewShell* pViewShell = mrViewData.GetViewShell();
6020 OString sBoundingBoxString = "EMPTY";
6021 if (!aBoundingBox.IsEmpty())
6022 sBoundingBoxString = aBoundingBox.toString();
6023 OString aRectListString = rectanglesToString(rLogicRects);
6024 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_SELECTION_AREA, sBoundingBoxString.getStr());
6025 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, aRectListString.getStr());
6026
6027 if (bInPrintTwips)
6028 {
6029 SfxLokHelper::notifyOtherViews(pViewShell, LOK_CALLBACK_TEXT_VIEW_SELECTION,
6030 "selection", aRectListString);
6031 return;
6032 }
6033
6034 for (SfxViewShell* it = SfxViewShell::GetFirst(); it;
6035 it = SfxViewShell::GetNext(*it))
6036 {
6037 if (it == pViewShell)
6038 continue;
6039 auto pOther = dynamic_cast<const ScTabViewShell *>(it);
6040 if (!pOther)
6041 return;
6042
6043 const ScGridWindow *pGrid = pOther->GetViewData().GetActiveWin();
6044 assert(pGrid)(static_cast <bool> (pGrid) ? void (0) : __assert_fail (
"pGrid", "/home/maarten/src/libreoffice/core/sc/source/ui/view/gridwin.cxx"
, 6044, __extension__ __PRETTY_FUNCTION__))
;
6045
6046 // Fetch pixels & convert for each view separately.
6047 tools::Rectangle aDummyBBox;
6048 std::vector<tools::Rectangle> aPixelRects;
6049 pGrid->GetPixelRectsFor(mrViewData.GetMarkData() /* ours */, aPixelRects);
6050 auto aOtherLogicRects = convertPixelToLogical(pOther->GetViewData(), aPixelRects, aDummyBBox);
6051 SfxLokHelper::notifyOtherView(pViewShell, pOther, LOK_CALLBACK_TEXT_VIEW_SELECTION,
6052 "selection", rectanglesToString(aOtherLogicRects).getStr());
6053 }
6054}
6055
6056/**
6057 * Fetch the selection ranges for other views into the LibreOfficeKit selection,
6058 * map them into our view co-ordinates and send to our view.
6059 */
6060void ScGridWindow::updateOtherKitSelections() const
6061{
6062 ScTabViewShell* pViewShell = mrViewData.GetViewShell();
6063 bool bInPrintTwips = comphelper::LibreOfficeKit::isCompatFlagSet(
6064 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs);
6065
6066 for (SfxViewShell* it = SfxViewShell::GetFirst(); it;
6067 it = SfxViewShell::GetNext(*it))
6068 {
6069 auto pOther = dynamic_cast<const ScTabViewShell *>(it);
6070 if (!pOther)
6071 return;
6072
6073 // Fetch pixels & convert for each view separately.
6074 tools::Rectangle aBoundingBox;
6075 std::vector<tools::Rectangle> aRects;
6076 OString aRectsString;
6077 GetRectsAnyFor(pOther->GetViewData().GetMarkData() /* theirs */, aRects, bInPrintTwips);
6078 if (bInPrintTwips)
6079 {
6080 std::for_each(aRects.begin(), aRects.end(),
6081 [&aBoundingBox](const tools::Rectangle& rRect) { aBoundingBox.Union(rRect); });
6082 aRectsString = rectanglesToString(aRects);
6083 }
6084 else
6085 aRectsString = rectanglesToString(
6086 convertPixelToLogical(pViewShell->GetViewData(), aRects, aBoundingBox));
6087
6088 if (it == pViewShell)
6089 {
6090 OString sBoundingBoxString = "EMPTY";
6091 if (!aBoundingBox.IsEmpty())
6092 sBoundingBoxString = aBoundingBox.toString();
6093
6094 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_SELECTION_AREA, sBoundingBoxString.getStr());
6095 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, aRectsString.getStr());
6096 }
6097 else
6098 SfxLokHelper::notifyOtherView(it, pViewShell, LOK_CALLBACK_TEXT_VIEW_SELECTION,
6099 "selection", aRectsString);
6100 }
6101}
6102
6103namespace
6104{
6105
6106void updateLibreOfficeKitAutoFill(const ScViewData& rViewData, tools::Rectangle const & rRectangle)
6107{
6108 if (!comphelper::LibreOfficeKit::isActive())
6109 return;
6110
6111 double nPPTX = rViewData.GetPPTX();
6112 double nPPTY = rViewData.GetPPTY();
6113
6114 OString sRectangleString = "EMPTY";
6115 if (!rRectangle.IsEmpty())
6116 {
6117 // selection start handle
6118 tools::Rectangle aLogicRectangle(
6119 rRectangle.Left() / nPPTX, rRectangle.Top() / nPPTY,
6120 rRectangle.Right() / nPPTX, rRectangle.Bottom() / nPPTY);
6121 sRectangleString = aLogicRectangle.toString();
6122 }
6123
6124 ScTabViewShell* pViewShell = rViewData.GetViewShell();
6125 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_AUTO_FILL_AREA, sRectangleString.getStr());
6126}
6127
6128} //end anonymous namespace
6129
6130void ScGridWindow::UpdateCursorOverlay()
6131{
6132 ScDocument& rDoc = mrViewData.GetDocument();
6133
6134 MapMode aDrawMode = GetDrawMapMode();
6135 MapMode aOldMode = GetMapMode();
6136 if ( aOldMode != aDrawMode )
6137 SetMapMode( aDrawMode );
6138
6139 // Existing OverlayObjects may be transformed in later versions.
6140 // For now, just re-create them.
6141
6142 DeleteCursorOverlay();
6143
6144 std::vector<tools::Rectangle> aPixelRects;
6145
6146 // determine the cursor rectangles in pixels (moved from ScGridWindow::DrawCursor)
6147
6148 SCTAB nTab = mrViewData.GetTabNo();
6149 SCCOL nX = mrViewData.GetCurX();
6150 SCROW nY = mrViewData.GetCurY();
6151
6152 const ScPatternAttr* pPattern = rDoc.GetPattern(nX,nY,nTab);
6153
6154 if (!comphelper::LibreOfficeKit::isActive() && !maVisibleRange.isInside(nX, nY))
6155 {
6156 if (maVisibleRange.mnCol2 < nX || maVisibleRange.mnRow2 < nY)
6157 return; // no further check needed, nothing visible
6158
6159 // fdo#87382 Also display the cell cursor for the visible part of
6160 // merged cells if the view position is part of merged cells.
6161 const ScMergeAttr& rMerge = pPattern->GetItem(ATTR_MERGE);
6162 if (rMerge.GetColMerge() <= 1 && rMerge.GetRowMerge() <= 1)
6163 return; // not merged and invisible
6164
6165 SCCOL nX2 = nX + rMerge.GetColMerge() - 1;
6166 SCROW nY2 = nY + rMerge.GetRowMerge() - 1;
6167 // Check if the middle or tail of the merged range is visible.
6168 if (maVisibleRange.mnCol1 > nX2 || maVisibleRange.mnRow1 > nY2)
6169 return; // no visible part
6170 }
6171
6172 // don't show the cursor in overlapped cells
6173 const ScMergeFlagAttr& rMergeFlag = pPattern->GetItem(ATTR_MERGE_FLAG);
6174 bool bOverlapped = rMergeFlag.IsOverlapped();
6175
6176 // left or above of the screen?
6177 bool bVis = comphelper::LibreOfficeKit::isActive() || ( nX>=mrViewData.GetPosX(eHWhich) && nY>=mrViewData.GetPosY(eVWhich) );
6178 if (!bVis)
6179 {
6180 SCCOL nEndX = nX;
6181 SCROW nEndY = nY;
6182 const ScMergeAttr& rMerge = pPattern->GetItem(ATTR_MERGE);
6183 if (rMerge.GetColMerge() > 1)
6184 nEndX += rMerge.GetColMerge()-1;
6185 if (rMerge.GetRowMerge() > 1)
6186 nEndY += rMerge.GetRowMerge()-1;
6187 bVis = ( nEndX>=mrViewData.GetPosX(eHWhich) && nEndY>=mrViewData.GetPosY(eVWhich) );
6188 }
6189
6190 if ( bVis && !bOverlapped && !mrViewData.HasEditView(eWhich) && mrViewData.IsActive() )
6191 {
6192 Point aScrPos = mrViewData.GetScrPos( nX, nY, eWhich, true );
6193 bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
6194
6195 // completely right of/below the screen?
6196 // (test with logical start position in aScrPos)
6197 bool bMaybeVisible;
6198 if ( bLayoutRTL )
6199 bMaybeVisible = ( aScrPos.X() >= -2 && aScrPos.Y() >= -2 );
6200 else
6201 {
6202 Size aOutSize = GetOutputSizePixel();
6203 bMaybeVisible = ( aScrPos.X() <= aOutSize.Width() + 2 && aScrPos.Y() <= aOutSize.Height() + 2 );
6204 }
6205
6206 // in the tiled rendering case, don't limit to the screen size
6207 if (bMaybeVisible || comphelper::LibreOfficeKit::isActive())
6208 {
6209 long nSizeXPix;
6210 long nSizeYPix;
6211 mrViewData.GetMergeSizePixel( nX, nY, nSizeXPix, nSizeYPix );
6212
6213 if (bLayoutRTL)
6214 aScrPos.AdjustX( -(nSizeXPix - 2) ); // move instead of mirroring
6215
6216 // show the cursor as 4 (thin) rectangles
6217 tools::Rectangle aRect(aScrPos, Size(nSizeXPix - 1, nSizeYPix - 1));
6218
6219 float fScaleFactor = GetDPIScaleFactor();
6220
6221 long aCursorWidth = 1 * fScaleFactor;
6222
6223 tools::Rectangle aLeft = aRect;
6224 aLeft.AdjustTop( -aCursorWidth );
6225 aLeft.AdjustBottom(aCursorWidth );
6226 aLeft.SetRight( aLeft.Left() );
6227 aLeft.AdjustLeft( -aCursorWidth );
6228
6229 tools::Rectangle aRight = aRect;
6230 aRight.AdjustTop( -aCursorWidth );
6231 aRight.AdjustBottom(aCursorWidth );
6232 aRight.SetLeft( aRight.Right() );
6233 aRight.AdjustRight(aCursorWidth );
6234
6235 tools::Rectangle aTop = aRect;
6236 aTop.SetBottom( aTop.Top() );
6237 aTop.AdjustTop( -aCursorWidth );
6238
6239 tools::Rectangle aBottom = aRect;
6240 aBottom.SetTop( aBottom.Bottom() );
6241 aBottom.AdjustBottom(aCursorWidth );
6242
6243 aPixelRects.push_back(aLeft);
6244 aPixelRects.push_back(aRight);
6245 aPixelRects.push_back(aTop);
6246 aPixelRects.push_back(aBottom);
6247 }
6248 }
6249
6250 if ( !aPixelRects.empty() )
6251 {
6252 if (comphelper::LibreOfficeKit::isActive())
6253 {
6254 mpOOCursors.reset(new sdr::overlay::OverlayObjectList);
6255 updateKitCellCursor(nullptr);
6256 }
6257 else
6258 {
6259 // #i70788# get the OverlayManager safely
6260 rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = getOverlayManager();
6261
6262 if (xOverlayManager.is())
6263 {
6264 Color aCursorColor( SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
6265 if (mrViewData.GetActivePart() != eWhich)
6266 // non-active pane uses a different color.
6267 aCursorColor = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->GetColorConfig().GetColorValue(svtools::CALCPAGEBREAKAUTOMATIC).nColor;
6268 std::vector< basegfx::B2DRange > aRanges;
6269 const basegfx::B2DHomMatrix aTransform(GetInverseViewTransformation());
6270
6271 for(const tools::Rectangle & rRA : aPixelRects)
6272 {
6273 basegfx::B2DRange aRB(rRA.Left(), rRA.Top(), rRA.Right() + 1, rRA.Bottom() + 1);
6274 aRB.transform(aTransform);
6275 aRanges.push_back(aRB);
6276 }
6277
6278 std::unique_ptr<sdr::overlay::OverlayObject> pOverlay(new sdr::overlay::OverlaySelection(
6279 sdr::overlay::OverlayType::Solid,
6280 aCursorColor,
6281 aRanges,
6282 false));
6283
6284 xOverlayManager->add(*pOverlay);
6285 mpOOCursors.reset(new sdr::overlay::OverlayObjectList);
6286 mpOOCursors->append(std::move(pOverlay));
6287 }
6288 }
6289 }
6290
6291 if ( aOldMode != aDrawMode )
6292 SetMapMode( aOldMode );
6293}
6294
6295void ScGridWindow::GetCellSelection(std::vector<tools::Rectangle>& rLogicRects)
6296{
6297 std::vector<tools::Rectangle> aRects;
6298 if (comphelper::LibreOfficeKit::isActive() &&
6299 comphelper::LibreOfficeKit::isCompatFlagSet(
6300 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs))
6301 GetSelectionRectsPrintTwips(aRects);
6302 else
6303 GetSelectionRects(aRects);
6304 UpdateKitSelection(aRects, &rLogicRects);
6305}
6306
6307void ScGridWindow::DeleteSelectionOverlay()
6308{
6309 mpOOSelection.reset();
6310}
6311
6312void ScGridWindow::UpdateSelectionOverlay()
6313{
6314 MapMode aDrawMode = GetDrawMapMode();
6315 MapMode aOldMode = GetMapMode();
6316 if ( aOldMode != aDrawMode )
6317 SetMapMode( aDrawMode );
6318
6319 DeleteSelectionOverlay();
6320 std::vector<tools::Rectangle> aRects;
6321 if (comphelper::LibreOfficeKit::isActive() &&
6322 comphelper::LibreOfficeKit::isCompatFlagSet(
6323 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs))
6324 GetSelectionRectsPrintTwips(aRects);
6325 else
6326 GetSelectionRects(aRects);
6327
6328 if (!aRects.empty() && mrViewData.IsActive())
6329 {
6330 // #i70788# get the OverlayManager safely
6331 rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = getOverlayManager();
6332 if (comphelper::LibreOfficeKit::isActive())
6333 {
6334 // notify the LibreOfficeKit too
6335 UpdateKitSelection(aRects);
6336 }
6337 else if (xOverlayManager.is())
6338 {
6339 std::vector< basegfx::B2DRange > aRanges;
6340 const basegfx::B2DHomMatrix aTransform(GetInverseViewTransformation());
6341 ScDocument& rDoc = mrViewData.GetDocument();
6342 SCTAB nTab = mrViewData.GetTabNo();
6343 bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
6344
6345 for(const tools::Rectangle & rRA : aRects)
6346 {
6347 if (bLayoutRTL)
6348 {
6349 basegfx::B2DRange aRB(rRA.Left(), rRA.Top() - 1, rRA.Right() + 1, rRA.Bottom());
6350 aRB.transform(aTransform);
6351 aRanges.push_back(aRB);
6352 }
6353 else
6354 {
6355 basegfx::B2DRange aRB(rRA.Left() - 1, rRA.Top() - 1, rRA.Right(), rRA.Bottom());
6356 aRB.transform(aTransform);
6357 aRanges.push_back(aRB);
6358 }
6359 }
6360
6361 // get the system's highlight color
6362 const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
6363 const Color aHighlight(aSvtOptionsDrawinglayer.getHilightColor());
6364
6365 std::unique_ptr<sdr::overlay::OverlayObject> pOverlay(new sdr::overlay::OverlaySelection(
6366 sdr::overlay::OverlayType::Transparent,
6367 aHighlight,
6368 aRanges,
6369 true));
6370
6371 xOverlayManager->add(*pOverlay);
6372 mpOOSelection.reset(new sdr::overlay::OverlayObjectList);
6373 mpOOSelection->append(std::move(pOverlay));
6374 }
6375 }
6376 else
6377 {
6378 ScTabViewShell* pViewShell = mrViewData.GetViewShell();
6379 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, "EMPTY");
6380 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_SELECTION_AREA, "EMPTY");
6381 SfxLokHelper::notifyOtherViews(pViewShell, LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", "EMPTY");
6382
6383 ScInputHandler* pViewHdl = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->GetInputHdl(pViewShell);
6384 if (!pViewHdl || !pViewHdl->IsEditMode())
6385 {
6386 std::vector<ReferenceMark> aReferenceMarks;
6387 ScInputHandler::SendReferenceMarks(pViewShell, aReferenceMarks);
6388 }
6389 }
6390
6391 if ( aOldMode != aDrawMode )
6392 SetMapMode( aOldMode );
6393}
6394
6395void ScGridWindow::DeleteAutoFillOverlay()
6396{
6397 mpOOAutoFill.reset();
6398 mpAutoFillRect.reset();
6399}
6400
6401void ScGridWindow::UpdateAutoFillOverlay()
6402{
6403 MapMode aDrawMode = GetDrawMapMode();
6404 MapMode aOldMode = GetMapMode();
6405 if ( aOldMode != aDrawMode )
6406 SetMapMode( aDrawMode );
6407
6408 DeleteAutoFillOverlay();
6409
6410 // get the AutoFill handle rectangle in pixels
6411
6412 if ( !(bAutoMarkVisible && aAutoMarkPos.Tab() == mrViewData.GetTabNo() &&
6413 !mrViewData.HasEditView(eWhich) && mrViewData.IsActive()) )
6414 return;
6415
6416 SCCOL nX = aAutoMarkPos.Col();
6417 SCROW nY = aAutoMarkPos.Row();
6418
6419 if (!maVisibleRange.isInside(nX, nY) && !comphelper::LibreOfficeKit::isActive())
6420 {
6421 // Autofill mark is not visible. Bail out.
6422 return;
6423 }
6424
6425 SCTAB nTab = mrViewData.GetTabNo();
6426 ScDocument& rDoc = mrViewData.GetDocument();
6427 bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
6428
6429 float fScaleFactor = GetDPIScaleFactor();
6430 // Size should be even
6431 Size aFillHandleSize(6 * fScaleFactor, 6 * fScaleFactor);
6432
6433 Point aFillPos = mrViewData.GetScrPos( nX, nY, eWhich, true );
6434 long nSizeXPix;
6435 long nSizeYPix;
6436 mrViewData.GetMergeSizePixel( nX, nY, nSizeXPix, nSizeYPix );
6437
6438 if (bLayoutRTL)
6439 aFillPos.AdjustX( -(nSizeXPix - 2 + (aFillHandleSize.Width() / 2)) );
6440 else
6441 aFillPos.AdjustX(nSizeXPix - (aFillHandleSize.Width() / 2) );
6442
6443 aFillPos.AdjustY(nSizeYPix );
6444 aFillPos.AdjustY( -(aFillHandleSize.Height() / 2) );
6445
6446 tools::Rectangle aFillRect(aFillPos, aFillHandleSize);
6447
6448 // expand rect to increase hit area
6449 mpAutoFillRect = aFillRect;
6450 mpAutoFillRect->expand(fScaleFactor);
6451
6452 // #i70788# get the OverlayManager safely
6453 rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = getOverlayManager();
6454 if (comphelper::LibreOfficeKit::isActive()) // notify the LibreOfficeKit
6455 {
6456 updateLibreOfficeKitAutoFill(mrViewData, aFillRect);
6457 }
6458 else if (xOverlayManager.is())
6459 {
6460 Color aHandleColor( SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
6461 if (mrViewData.GetActivePart() != eWhich)
6462 // non-active pane uses a different color.
6463 aHandleColor = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->GetColorConfig().GetColorValue(svtools::CALCPAGEBREAKAUTOMATIC).nColor;
6464 std::vector< basegfx::B2DRange > aRanges;
6465 const basegfx::B2DHomMatrix aTransform(GetInverseViewTransformation());
6466 basegfx::B2DRange aRB = vcl::unotools::b2DRectangleFromRectangle(aFillRect);
6467
6468 aRB.transform(aTransform);
6469 aRanges.push_back(aRB);
6470
6471 std::unique_ptr<sdr::overlay::OverlayObject> pOverlay(new sdr::overlay::OverlaySelection(
6472 sdr::overlay::OverlayType::Solid,
6473 aHandleColor,
6474 aRanges,
6475 false));
6476
6477 xOverlayManager->add(*pOverlay);
6478 mpOOAutoFill.reset(new sdr::overlay::OverlayObjectList);
6479 mpOOAutoFill->append(std::move(pOverlay));
6480 }
6481
6482 if ( aOldMode != aDrawMode )
6483 SetMapMode( aOldMode );
6484}
6485
6486void ScGridWindow::DeleteDragRectOverlay()
6487{
6488 mpOODragRect.reset();
6489}
6490
6491void ScGridWindow::UpdateDragRectOverlay()
6492{
6493 MapMode aDrawMode = GetDrawMapMode();
6494 MapMode aOldMode = GetMapMode();
6495 if ( aOldMode != aDrawMode )
6496 SetMapMode( aDrawMode );
6497
6498 DeleteDragRectOverlay();
6499
6500 // get the rectangles in pixels (moved from DrawDragRect)
6501
6502 if ( bDragRect || bPagebreakDrawn )
6503 {
6504 std::vector<tools::Rectangle> aPixelRects;
6505
6506 SCCOL nX1 = bDragRect ? nDragStartX : aPagebreakDrag.aStart.Col();
6507 SCROW nY1 = bDragRect ? nDragStartY : aPagebreakDrag.aStart.Row();
6508 SCCOL nX2 = bDragRect ? nDragEndX : aPagebreakDrag.aEnd.Col();
6509 SCROW nY2 = bDragRect ? nDragEndY : aPagebreakDrag.aEnd.Row();
6510
6511 SCTAB nTab = mrViewData.GetTabNo();
6512
6513 SCCOL nPosX = mrViewData.GetPosX(WhichH(eWhich));
6514 SCROW nPosY = mrViewData.GetPosY(WhichV(eWhich));
6515 if (nX1 < nPosX) nX1 = nPosX;
6516 if (nX2 < nPosX) nX2 = nPosX;
6517 if (nY1 < nPosY) nY1 = nPosY;
6518 if (nY2 < nPosY) nY2 = nPosY;
6519
6520 Point aScrPos( mrViewData.GetScrPos( nX1, nY1, eWhich ) );
6521
6522 long nSizeXPix=0;
6523 long nSizeYPix=0;
6524 ScDocument& rDoc = mrViewData.GetDocument();
6525 double nPPTX = mrViewData.GetPPTX();
6526 double nPPTY = mrViewData.GetPPTY();
6527 SCCOLROW i;
6528
6529 bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
6530 long nLayoutSign = bLayoutRTL ? -1 : 1;
6531
6532 if (rDoc.ValidCol(nX2) && nX2>=nX1)
6533 for (i=nX1; i<=nX2; i++)
6534 nSizeXPix += ScViewData::ToPixel( rDoc.GetColWidth( static_cast<SCCOL>(i), nTab ), nPPTX );
6535 else
6536 {
6537 aScrPos.AdjustX( -nLayoutSign );
6538 nSizeXPix += 2;
6539 }
6540
6541 if (rDoc.ValidRow(nY2) && nY2>=nY1)
6542 for (i=nY1; i<=nY2; i++)
6543 nSizeYPix += ScViewData::ToPixel( rDoc.GetRowHeight( i, nTab ), nPPTY );
6544 else
6545 {
6546 aScrPos.AdjustY( -1 );
6547 nSizeYPix += 2;
6548 }
6549
6550 aScrPos.AdjustX( -(2 * nLayoutSign) );
6551 aScrPos.AdjustY( -2 );
6552 tools::Rectangle aRect( aScrPos.X(), aScrPos.Y(),
6553 aScrPos.X() + ( nSizeXPix + 2 ) * nLayoutSign, aScrPos.Y() + nSizeYPix + 2 );
6554 if ( bLayoutRTL )
6555 {
6556 aRect.SetLeft( aRect.Right() ); // end position is left
6557 aRect.SetRight( aScrPos.X() );
6558 }
6559
6560 if ( meDragInsertMode == INS_CELLSDOWN )
6561 {
6562 aPixelRects.emplace_back( aRect.Left()+1, aRect.Top()+3, aRect.Left()+1, aRect.Bottom()-2 );
6563 aPixelRects.emplace_back( aRect.Right()-1, aRect.Top()+3, aRect.Right()-1, aRect.Bottom()-2 );
6564 aPixelRects.emplace_back( aRect.Left()+1, aRect.Top(), aRect.Right()-1, aRect.Top()+2 );
6565 aPixelRects.emplace_back( aRect.Left()+1, aRect.Bottom()-1, aRect.Right()-1, aRect.Bottom()-1 );
6566 }
6567 else if ( meDragInsertMode == INS_CELLSRIGHT )
6568 {
6569 aPixelRects.emplace_back( aRect.Left(), aRect.Top()+1, aRect.Left()+2, aRect.Bottom()-1 );
6570 aPixelRects.emplace_back( aRect.Right()-1, aRect.Top()+1, aRect.Right()-1, aRect.Bottom()-1 );
6571 aPixelRects.emplace_back( aRect.Left()+3, aRect.Top()+1, aRect.Right()-2, aRect.Top()+1 );
6572 aPixelRects.emplace_back( aRect.Left()+3, aRect.Bottom()-1, aRect.Right()-2, aRect.Bottom()-1 );
6573 }
6574 else
6575 {
6576 aPixelRects.emplace_back( aRect.Left(), aRect.Top(), aRect.Left()+2, aRect.Bottom() );
6577 aPixelRects.emplace_back( aRect.Right()-2, aRect.Top(), aRect.Right(), aRect.Bottom() );
6578 aPixelRects.emplace_back( aRect.Left()+3, aRect.Top(), aRect.Right()-3, aRect.Top()+2 );
6579 aPixelRects.emplace_back( aRect.Left()+3, aRect.Bottom()-2, aRect.Right()-3, aRect.Bottom() );
6580 }
6581
6582 // #i70788# get the OverlayManager safely
6583 rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = getOverlayManager();
6584
6585 if (xOverlayManager.is() && !comphelper::LibreOfficeKit::isActive())
6586 {
6587 std::vector< basegfx::B2DRange > aRanges;
6588 const basegfx::B2DHomMatrix aTransform(GetInverseViewTransformation());
6589
6590 for(const tools::Rectangle & rRA : aPixelRects)
6591 {
6592 basegfx::B2DRange aRB(rRA.Left(), rRA.Top(), rRA.Right() + 1, rRA.Bottom() + 1);
6593 aRB.transform(aTransform);
6594 aRanges.push_back(aRB);
6595 }
6596
6597 std::unique_ptr<sdr::overlay::OverlayObject> pOverlay(new sdr::overlay::OverlaySelection(
6598 sdr::overlay::OverlayType::Invert,
6599 COL_BLACK,
6600 aRanges,
6601 false));
6602
6603 xOverlayManager->add(*pOverlay);
6604 mpOODragRect.reset(new sdr::overlay::OverlayObjectList);
6605 mpOODragRect->append(std::move(pOverlay));
6606 }
6607 }
6608
6609 if ( aOldMode != aDrawMode )
6610 SetMapMode( aOldMode );
6611}
6612
6613void ScGridWindow::DeleteHeaderOverlay()
6614{
6615 mpOOHeader.reset();
6616}
6617
6618void ScGridWindow::UpdateHeaderOverlay()
6619{
6620 MapMode aDrawMode = GetDrawMapMode();
6621 MapMode aOldMode = GetMapMode();
6622 if ( aOldMode != aDrawMode )
6623 SetMapMode( aDrawMode );
6624
6625 DeleteHeaderOverlay();
6626
6627 // Pixel rectangle is in aInvertRect
6628 if ( !aInvertRect.IsEmpty() )
6629 {
6630 // #i70788# get the OverlayManager safely
6631 rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = getOverlayManager();
6632
6633 if (xOverlayManager.is() && !comphelper::LibreOfficeKit::isActive())
6634 {
6635 // Color aHighlight = GetSettings().GetStyleSettings().GetHighlightColor();
6636 std::vector< basegfx::B2DRange > aRanges;
6637 const basegfx::B2DHomMatrix aTransform(GetInverseViewTransformation());
6638 basegfx::B2DRange aRB(aInvertRect.Left(), aInvertRect.Top(), aInvertRect.Right() + 1, aInvertRect.Bottom() + 1);
6639
6640 aRB.transform(aTransform);
6641 aRanges.push_back(aRB);
6642
6643 std::unique_ptr<sdr::overlay::OverlayObject> pOverlay(new sdr::overlay::OverlaySelection(
6644 sdr::overlay::OverlayType::Invert,
6645 COL_BLACK,
6646 aRanges,
6647 false));
6648
6649 xOverlayManager->add(*pOverlay);
6650 mpOOHeader.reset(new sdr::overlay::OverlayObjectList);
6651 mpOOHeader->append(std::move(pOverlay));
6652 }
6653 }
6654
6655 if ( aOldMode != aDrawMode )
6656 SetMapMode( aOldMode );
6657}
6658
6659void ScGridWindow::DeleteShrinkOverlay()
6660{
6661 mpOOShrink.reset();
6662}
6663
6664void ScGridWindow::UpdateShrinkOverlay()
6665{
6666 MapMode aDrawMode = GetDrawMapMode();
6667 MapMode aOldMode = GetMapMode();
6668 if ( aOldMode != aDrawMode )
6669 SetMapMode( aDrawMode );
6670
6671 DeleteShrinkOverlay();
6672
6673 // get the rectangle in pixels
6674
6675 tools::Rectangle aPixRect;
6676 ScRange aRange;
6677 SCTAB nTab = mrViewData.GetTabNo();
6678 if ( mrViewData.IsRefMode() && nTab >= mrViewData.GetRefStartZ() && nTab <= mrViewData.GetRefEndZ() &&
6679 mrViewData.GetDelMark( aRange ) )
6680 {
6681 //! limit to visible area
6682 if ( aRange.aStart.Col() <= aRange.aEnd.Col() &&
6683 aRange.aStart.Row() <= aRange.aEnd.Row() )
6684 {
6685 Point aStart = mrViewData.GetScrPos( aRange.aStart.Col(),
6686 aRange.aStart.Row(), eWhich );
6687 Point aEnd = mrViewData.GetScrPos( aRange.aEnd.Col()+1,
6688 aRange.aEnd.Row()+1, eWhich );
6689 aEnd.AdjustX( -1 );
6690 aEnd.AdjustY( -1 );
6691
6692 aPixRect = tools::Rectangle( aStart,aEnd );
6693 }
6694 }
6695
6696 if ( !aPixRect.IsEmpty() )
6697 {
6698 // #i70788# get the OverlayManager safely
6699 rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = getOverlayManager();
6700
6701 if (xOverlayManager.is() && !comphelper::LibreOfficeKit::isActive())
6702 {
6703 std::vector< basegfx::B2DRange > aRanges;
6704 const basegfx::B2DHomMatrix aTransform(GetInverseViewTransformation());
6705 basegfx::B2DRange aRB(aPixRect.Left(), aPixRect.Top(), aPixRect.Right() + 1, aPixRect.Bottom() + 1);
6706
6707 aRB.transform(aTransform);
6708 aRanges.push_back(aRB);
6709
6710 std::unique_ptr<sdr::overlay::OverlayObject> pOverlay(new sdr::overlay::OverlaySelection(
6711 sdr::overlay::OverlayType::Invert,
6712 COL_BLACK,
6713 aRanges,
6714 false));
6715
6716 xOverlayManager->add(*pOverlay);
6717 mpOOShrink.reset(new sdr::overlay::OverlayObjectList);
6718 mpOOShrink->append(std::move(pOverlay));
6719 }
6720 }
6721
6722 if ( aOldMode != aDrawMode )
6723 SetMapMode( aOldMode );
6724}
6725
6726// #i70788# central method to get the OverlayManager safely
6727rtl::Reference<sdr::overlay::OverlayManager> ScGridWindow::getOverlayManager() const
6728{
6729 SdrPageView* pPV = mrViewData.GetView()->GetScDrawView()->GetSdrPageView();
6730
6731 if(pPV)
6732 {
6733 SdrPageWindow* pPageWin = pPV->FindPageWindow( *this );
6734
6735 if ( pPageWin )
6736 {
6737 return pPageWin->GetOverlayManager();
6738 }
6739 }
6740
6741 return rtl::Reference<sdr::overlay::OverlayManager>();
6742}
6743
6744void ScGridWindow::flushOverlayManager()
6745{
6746 // #i70788# get the OverlayManager safely
6747 rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = getOverlayManager();
6748
6749 if (xOverlayManager.is())
6750 xOverlayManager->flush();
6751}
6752
6753ScViewData& ScGridWindow::getViewData()
6754{
6755 return mrViewData;
6756}
6757
6758FactoryFunction ScGridWindow::GetUITestFactory() const
6759{
6760 return ScGridWinUIObject::create;
6761}
6762
6763/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx

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_VCL_PTR_HXX
21#define INCLUDED_VCL_PTR_HXX
22
23#include <sal/config.h>
24
25#include <rtl/ref.hxx>
26
27#include <utility>
28#include <type_traits>
29
30#ifdef DBG_UTIL
31#ifndef _WIN32
32#include <vcl/vclmain.hxx>
33#endif
34#endif
35
36class VclReferenceBase;
37
38namespace vcl::detail {
39
40template<typename>
41constexpr bool isIncompleteOrDerivedFromVclReferenceBase(...) { return true; }
42
43template<typename T> constexpr bool isIncompleteOrDerivedFromVclReferenceBase(
44 int (*)[sizeof(T)])
45{ return std::is_base_of<VclReferenceBase, T>::value; }
46
47} // namespace vcl::detail
48
49/**
50 * A thin wrapper around rtl::Reference to implement the acquire and dispose semantics we want for references to vcl::Window subclasses.
51 *
52 * For more details on the design please see vcl/README.lifecycle
53 *
54 * @param reference_type must be a subclass of vcl::Window
55 */
56template <class reference_type>
57class VclPtr
58{
59 static_assert(
60 vcl::detail::isIncompleteOrDerivedFromVclReferenceBase<reference_type>(
61 nullptr),
62 "template argument type must be derived from VclReferenceBase");
63
64 ::rtl::Reference<reference_type> m_rInnerRef;
65
66public:
67 /** Constructor...
68 */
69 VclPtr()
70 : m_rInnerRef()
71 {}
72
73 /** Constructor...
74 */
75 VclPtr (reference_type * pBody)
76 : m_rInnerRef(pBody)
77 {}
78
79 /** Constructor... that doesn't take a ref.
80 */
81 VclPtr (reference_type * pBody, __sal_NoAcquire)
82 : m_rInnerRef(pBody, SAL_NO_ACQUIRE)
83 {}
84
85 /** Up-casting conversion constructor: Copies interface reference.
86
87 Does not work for up-casts to ambiguous bases. For the special case of
88 up-casting to Reference< XInterface >, see the corresponding conversion
89 operator.
90
91 @param rRef another reference
92 */
93 template< class derived_type >
94 VclPtr(
95 const VclPtr< derived_type > & rRef,
96 typename std::enable_if<
97 std::is_base_of<reference_type, derived_type>::value, int>::type
98 = 0 )
99 : m_rInnerRef( static_cast<reference_type*>(rRef) )
100 {
101 }
102
103#if defined(DBG_UTIL) && !defined(_WIN32)
104 virtual ~VclPtr()
105 {
106 assert(m_rInnerRef.get() == nullptr || vclmain::isAlive())(static_cast <bool> (m_rInnerRef.get() == nullptr || vclmain
::isAlive()) ? void (0) : __assert_fail ("m_rInnerRef.get() == nullptr || vclmain::isAlive()"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 106, __extension__ __PRETTY_FUNCTION__))
;
107 // We can be one of the intermediate counts, but if we are the last
108 // VclPtr keeping this object alive, then something forgot to call dispose().
109 assert((!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1)(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
110 && "someone forgot to call dispose()")(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
;
111 }
112 VclPtr(VclPtr const &) = default;
113 VclPtr(VclPtr &&) = default;
114 VclPtr & operator =(VclPtr const &) = default;
115 VclPtr & operator =(VclPtr &&) = default;
116#endif
117
118 /**
119 * A construction helper for VclPtr. Since VclPtr types are created
120 * with a reference-count of one - to help fit into the existing
121 * code-flow; this helps us to construct them easily.
122 *
123 * For more details on the design please see vcl/README.lifecycle
124 *
125 * @tparam reference_type must be a subclass of vcl::Window
126 */
127 template<typename... Arg> [[nodiscard]] static VclPtr< reference_type > Create(Arg &&... arg)
128 {
129 return VclPtr< reference_type >( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE );
130 }
131
132 /** Probably most common used: handle->someBodyOp().
133 */
134 reference_type * operator->() const
135 {
136 return m_rInnerRef.get();
137 }
138
139 /** Get the body. Can be used instead of operator->().
140 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
141 are the same.
142 */
143 reference_type * get() const
144 {
145 return m_rInnerRef.get();
146 }
147
148 void set(reference_type *pBody)
149 {
150 m_rInnerRef.set(pBody);
151 }
152
153 void reset(reference_type *pBody)
154 {
155 m_rInnerRef.set(pBody);
156 }
157
158 /** Up-casting copy assignment operator.
159
160 Does not work for up-casts to ambiguous bases.
161
162 @param rRef another reference
163 */
164 template<typename derived_type>
165 typename std::enable_if<
166 std::is_base_of<reference_type, derived_type>::value,
167 VclPtr &>::type
168 operator =(VclPtr<derived_type> const & rRef)
169 {
170 m_rInnerRef.set(rRef.get());
171 return *this;
172 }
173
174 VclPtr & operator =(reference_type * pBody)
175 {
176 m_rInnerRef.set(pBody);
177 return *this;
178 }
179
180 operator reference_type * () const
181 {
182 return m_rInnerRef.get();
183 }
184
185 explicit operator bool () const
186 {
187 return m_rInnerRef.get() != nullptr;
188 }
189
190 void clear()
191 {
192 m_rInnerRef.clear();
193 }
194
195 void reset()
196 {
197 m_rInnerRef.clear();
198 }
199
200 void disposeAndClear()
201 {
202 // hold it alive for the lifetime of this method
203 ::rtl::Reference<reference_type> aTmp(m_rInnerRef);
3
Calling copy constructor for 'Reference<ScFilterFloatingWindow>'
6
Returning from copy constructor for 'Reference<ScFilterFloatingWindow>'
204 m_rInnerRef.clear(); // we should use some 'swap' method ideally ;-)
7
Calling 'Reference::clear'
14
Returning; memory was released
205 if (aTmp.get()) {
15
Calling 'Reference::get'
206 aTmp->disposeOnce();
207 }
208 }
209
210 /** Needed to place VclPtr's into STL collection.
211 */
212 bool operator< (const VclPtr<reference_type> & handle) const
213 {
214 return (m_rInnerRef < handle.m_rInnerRef);
215 }
216}; // class VclPtr
217
218template<typename T1, typename T2>
219inline bool operator ==(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
220 return p1.get() == p2.get();
221}
222
223template<typename T> inline bool operator ==(VclPtr<T> const & p1, T const * p2)
224{
225 return p1.get() == p2;
226}
227
228template<typename T> inline bool operator ==(VclPtr<T> const & p1, T * p2) {
229 return p1.get() == p2;
230}
231
232template<typename T> inline bool operator ==(T const * p1, VclPtr<T> const & p2)
233{
234 return p1 == p2.get();
235}
236
237template<typename T> inline bool operator ==(T * p1, VclPtr<T> const & p2) {
238 return p1 == p2.get();
239}
240
241template<typename T1, typename T2>
242inline bool operator !=(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
243 return !(p1 == p2);
244}
245
246template<typename T> inline bool operator !=(VclPtr<T> const & p1, T const * p2)
247{
248 return !(p1 == p2);
249}
250
251template<typename T> inline bool operator !=(VclPtr<T> const & p1, T * p2) {
252 return !(p1 == p2);
253}
254
255template<typename T> inline bool operator !=(T const * p1, VclPtr<T> const & p2)
256{
257 return !(p1 == p2);
258}
259
260template<typename T> inline bool operator !=(T * p1, VclPtr<T> const & p2) {
261 return !(p1 == p2);
262}
263
264/**
265 * A construction helper for a temporary VclPtr. Since VclPtr types
266 * are created with a reference-count of one - to help fit into
267 * the existing code-flow; this helps us to construct them easily.
268 * see also VclPtr::Create and ScopedVclPtr
269 *
270 * For more details on the design please see vcl/README.lifecycle
271 *
272 * @param reference_type must be a subclass of vcl::Window
273 */
274template <class reference_type>
275class SAL_WARN_UNUSED__attribute__((warn_unused)) VclPtrInstance final : public VclPtr<reference_type>
276{
277public:
278 template<typename... Arg> VclPtrInstance(Arg &&... arg)
279 : VclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
280 {
281 }
282
283 /**
284 * Override and disallow this, to prevent people accidentally calling it and actually
285 * getting VclPtr::Create and getting a naked VclPtr<> instance
286 */
287 template<typename... Arg> static VclPtrInstance< reference_type > Create(Arg &&... ) = delete;
288};
289
290template <class reference_type>
291class ScopedVclPtr : public VclPtr<reference_type>
292{
293public:
294 /** Constructor...
295 */
296 ScopedVclPtr()
297 : VclPtr<reference_type>()
298 {}
299
300 /** Constructor
301 */
302 ScopedVclPtr (reference_type * pBody)
303 : VclPtr<reference_type>(pBody)
304 {}
305
306 /** Copy constructor...
307 */
308 ScopedVclPtr (const VclPtr<reference_type> & handle)
309 : VclPtr<reference_type>(handle)
310 {}
311
312 /**
313 Assignment that releases the last reference.
314 */
315 void disposeAndReset(reference_type *pBody)
316 {
317 if (pBody != this->get()) {
318 VclPtr<reference_type>::disposeAndClear();
319 VclPtr<reference_type>::set(pBody);
320 }
321 }
322
323 /**
324 Assignment that releases the last reference.
325 */
326 ScopedVclPtr<reference_type>& operator = (reference_type * pBody)
327 {
328 disposeAndReset(pBody);
329 return *this;
330 }
331
332 /** Up-casting conversion constructor: Copies interface reference.
333
334 Does not work for up-casts to ambiguous bases. For the special case of
335 up-casting to Reference< XInterface >, see the corresponding conversion
336 operator.
337
338 @param rRef another reference
339 */
340 template< class derived_type >
341 ScopedVclPtr(
342 const VclPtr< derived_type > & rRef,
343 typename std::enable_if<
344 std::is_base_of<reference_type, derived_type>::value, int>::type
345 = 0 )
346 : VclPtr<reference_type>( rRef )
347 {
348 }
349
350 /** Up-casting assignment operator.
351
352 Does not work for up-casts to ambiguous bases.
353
354 @param rRef another VclPtr
355 */
356 template<typename derived_type>
357 typename std::enable_if<
358 std::is_base_of<reference_type, derived_type>::value,
359 ScopedVclPtr &>::type
360 operator =(VclPtr<derived_type> const & rRef)
361 {
362 disposeAndReset(rRef.get());
363 return *this;
364 }
365
366 /**
367 * Override and disallow this, to prevent people accidentally calling it and actually
368 * getting VclPtr::Create and getting a naked VclPtr<> instance
369 */
370 template<typename... Arg> static ScopedVclPtr< reference_type > Create(Arg &&... ) = delete;
371
372 ~ScopedVclPtr()
373 {
374 VclPtr<reference_type>::disposeAndClear();
375 assert(VclPtr<reference_type>::get() == nullptr)(static_cast <bool> (VclPtr<reference_type>::get(
) == nullptr) ? void (0) : __assert_fail ("VclPtr<reference_type>::get() == nullptr"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 375, __extension__ __PRETTY_FUNCTION__))
; // make sure there are no lingering references
376 }
377
378private:
379 // Most likely we don't want this default copy-constructor.
380 ScopedVclPtr (const ScopedVclPtr<reference_type> &) = delete;
381 // And certainly we don't want a default assignment operator.
382 ScopedVclPtr<reference_type>& operator = (const ScopedVclPtr<reference_type> &) = delete;
383 // And disallow reset as that doesn't call disposeAndClear on the original reference
384 void reset() = delete;
385 void reset(reference_type *pBody) = delete;
386
387protected:
388 ScopedVclPtr (reference_type * pBody, __sal_NoAcquire)
389 : VclPtr<reference_type>(pBody, SAL_NO_ACQUIRE)
390 {}
391};
392
393/**
394 * A construction helper for ScopedVclPtr. Since VclPtr types are created
395 * with a reference-count of one - to help fit into the existing
396 * code-flow; this helps us to construct them easily.
397 *
398 * For more details on the design please see vcl/README.lifecycle
399 *
400 * @param reference_type must be a subclass of vcl::Window
401 */
402#if defined _MSC_VER
403#pragma warning(push)
404#pragma warning(disable: 4521) // " multiple copy constructors specified"
405#endif
406template <class reference_type>
407class SAL_WARN_UNUSED__attribute__((warn_unused)) ScopedVclPtrInstance final : public ScopedVclPtr<reference_type>
408{
409public:
410 template<typename... Arg> ScopedVclPtrInstance(Arg &&... arg)
411 : ScopedVclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
412 {
413 }
414
415 /**
416 * Override and disallow this, to prevent people accidentally calling it and actually
417 * getting VclPtr::Create and getting a naked VclPtr<> instance
418 */
419 template<typename... Arg> static ScopedVclPtrInstance< reference_type > Create(Arg &&...) = delete;
420
421private:
422 // Prevent the above perfect forwarding ctor from hijacking (accidental)
423 // attempts at ScopedVclPtrInstance copy construction (where the hijacking
424 // would typically lead to somewhat obscure error messages); both non-const
425 // and const variants are needed here, as the ScopedVclPtr base class has a
426 // const--variant copy ctor, so the implicitly declared copy ctor for
427 // ScopedVclPtrInstance would also be the const variant, so non-const copy
428 // construction attempts would be hijacked by the perfect forwarding ctor;
429 // but if we only declared a non-const variant here, the const variant would
430 // no longer be implicitly declared (as there would already be an explicitly
431 // declared copy ctor), so const copy construction attempts would then be
432 // hijacked by the perfect forwarding ctor:
433 ScopedVclPtrInstance(ScopedVclPtrInstance &) = delete;
434 ScopedVclPtrInstance(ScopedVclPtrInstance const &) = delete;
435};
436#if defined _MSC_VER
437#pragma warning(pop)
438#endif
439
440#endif // INCLUDED_VCL_PTR_HXX
441
442/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/rtl/ref.hxx

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_RTL_REF_HXX
21#define INCLUDED_RTL_REF_HXX
22
23#include "sal/config.h"
24
25#include <cassert>
26#include <cstddef>
27#include <functional>
28#ifdef LIBO_INTERNAL_ONLY1
29#include <type_traits>
30#endif
31
32#include "sal/types.h"
33
34namespace rtl
35{
36
37/** Template reference class for reference type.
38*/
39template <class reference_type>
40class Reference
41{
42 /** The <b>reference_type</b> body pointer.
43 */
44 reference_type * m_pBody;
45
46
47public:
48 /** Constructor...
49 */
50 Reference()
51 : m_pBody (NULL__null)
52 {}
53
54
55 /** Constructor...
56 */
57 Reference (reference_type * pBody, __sal_NoAcquire)
58 : m_pBody (pBody)
59 {
60 }
61
62 /** Constructor...
63 */
64 Reference (reference_type * pBody)
65 : m_pBody (pBody)
66 {
67 if (m_pBody)
68 m_pBody->acquire();
69 }
70
71 /** Copy constructor...
72 */
73 Reference (const Reference<reference_type> & handle)
74 : m_pBody (handle.m_pBody)
75 {
76 if (m_pBody)
4
Assuming field 'm_pBody' is non-null
5
Taking true branch
77 m_pBody->acquire();
78 }
79
80#ifdef LIBO_INTERNAL_ONLY1
81 /** Move constructor...
82 */
83 Reference (Reference<reference_type> && handle) noexcept
84 : m_pBody (handle.m_pBody)
85 {
86 handle.m_pBody = nullptr;
87 }
88#endif
89
90#if defined LIBO_INTERNAL_ONLY1
91 /** Up-casting conversion constructor: Copies interface reference.
92
93 Does not work for up-casts to ambiguous bases.
94
95 @param rRef another reference
96 */
97 template< class derived_type >
98 inline Reference(
99 const Reference< derived_type > & rRef,
100 std::enable_if_t<std::is_base_of_v<reference_type, derived_type>, int> = 0 )
101 : m_pBody (rRef.get())
102 {
103 if (m_pBody)
104 m_pBody->acquire();
105 }
106#endif
107
108 /** Destructor...
109 */
110 ~Reference() COVERITY_NOEXCEPT_FALSE
111 {
112 if (m_pBody)
113 m_pBody->release();
114 }
115
116 /** Set...
117 Similar to assignment.
118 */
119 Reference<reference_type> &
120 SAL_CALL set (reference_type * pBody)
121 {
122 if (pBody)
123 pBody->acquire();
124 reference_type * const pOld = m_pBody;
125 m_pBody = pBody;
126 if (pOld)
127 pOld->release();
128 return *this;
129 }
130
131 /** Assignment.
132 Unbinds this instance from its body (if bound) and
133 bind it to the body represented by the handle.
134 */
135 Reference<reference_type> &
136 SAL_CALL operator= (const Reference<reference_type> & handle)
137 {
138 return set( handle.m_pBody );
139 }
140
141#ifdef LIBO_INTERNAL_ONLY1
142 /** Assignment.
143 * Unbinds this instance from its body (if bound),
144 * bind it to the body represented by the handle, and
145 * set the body represented by the handle to nullptr.
146 */
147 Reference<reference_type> &
148 operator= (Reference<reference_type> && handle)
149 {
150 // self-movement guts ourself
151 if (m_pBody)
152 m_pBody->release();
153 m_pBody = handle.m_pBody;
154 handle.m_pBody = nullptr;
155 return *this;
156 }
157#endif
158
159 /** Assignment...
160 */
161 Reference<reference_type> &
162 SAL_CALL operator= (reference_type * pBody)
163 {
164 return set( pBody );
165 }
166
167 /** Unbind the body from this handle.
168 Note that for a handle representing a large body,
169 "handle.clear().set(new body());" _might_
170 perform a little bit better than "handle.set(new body());",
171 since in the second case two large objects exist in memory
172 (the old body and the new body).
173 */
174 Reference<reference_type> & SAL_CALL clear()
175 {
176 if (m_pBody
7.1
Field 'm_pBody' is non-null
7.1
Field 'm_pBody' is non-null
7.1
Field 'm_pBody' is non-null
7.1
Field 'm_pBody' is non-null
)
8
Taking true branch
177 {
178 reference_type * const pOld = m_pBody;
179 m_pBody = NULL__null;
180 pOld->release();
9
Calling 'VclReferenceBase::release'
13
Returning; memory was released
181 }
182 return *this;
183 }
184
185
186 /** Get the body. Can be used instead of operator->().
187 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
188 are the same.
189 */
190 reference_type * SAL_CALL get() const
191 {
192 return m_pBody;
16
Use of memory after it is freed
193 }
194
195
196 /** Probably most common used: handle->someBodyOp().
197 */
198 reference_type * SAL_CALL operator->() const
199 {
200 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 200, __extension__ __PRETTY_FUNCTION__))
;
201 return m_pBody;
202 }
203
204
205 /** Allows (*handle).someBodyOp().
206 */
207 reference_type & SAL_CALL operator*() const
208 {
209 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 209, __extension__ __PRETTY_FUNCTION__))
;
210 return *m_pBody;
211 }
212
213
214 /** Returns True if the handle does point to a valid body.
215 */
216 bool SAL_CALL is() const
217 {
218 return (m_pBody != NULL__null);
219 }
220
221#if defined LIBO_INTERNAL_ONLY1
222 /** Returns True if the handle does point to a valid body.
223 */
224 explicit operator bool() const
225 {
226 return is();
227 }
228#endif
229
230 /** Returns True if this points to pBody.
231 */
232 bool SAL_CALL operator== (const reference_type * pBody) const
233 {
234 return (m_pBody == pBody);
235 }
236
237
238 /** Returns True if handle points to the same body.
239 */
240 bool
241 SAL_CALL operator== (const Reference<reference_type> & handle) const
242 {
243 return (m_pBody == handle.m_pBody);
244 }
245
246
247 /** Needed to place References into STL collection.
248 */
249 bool
250 SAL_CALL operator!= (const Reference<reference_type> & handle) const
251 {
252 return (m_pBody != handle.m_pBody);
253 }
254
255
256 /** Needed to place References into STL collection.
257 */
258 bool
259 SAL_CALL operator< (const Reference<reference_type> & handle) const
260 {
261 return (m_pBody < handle.m_pBody);
262 }
263
264
265 /** Needed to place References into STL collection.
266 */
267 bool
268 SAL_CALL operator> (const Reference<reference_type> & handle) const
269 {
270 return (m_pBody > handle.m_pBody);
271 }
272};
273
274} // namespace rtl
275
276#if defined LIBO_INTERNAL_ONLY1
277namespace std
278{
279
280/// @cond INTERNAL
281/**
282 Make rtl::Reference hashable by default for use in STL containers.
283
284 @since LibreOffice 6.3
285*/
286template<typename T>
287struct hash<::rtl::Reference<T>>
288{
289 std::size_t operator()(::rtl::Reference<T> const & s) const
290 { return std::size_t(s.get()); }
291};
292/// @endcond
293
294}
295
296#endif
297
298#endif /* ! INCLUDED_RTL_REF_HXX */
299
300/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/vclreferencebase.hxx

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#ifndef INCLUDED_VCL_Reference_HXX
20#define INCLUDED_VCL_Reference_HXX
21
22#include <vcl/dllapi.h>
23#include <osl/interlck.h>
24
25class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) VclReferenceBase
26{
27 mutable oslInterlockedCount mnRefCnt;
28
29 template<typename T> friend class VclPtr;
30
31public:
32 void acquire() const
33 {
34 osl_atomic_increment(&mnRefCnt)__sync_add_and_fetch((&mnRefCnt), 1);
35 }
36
37 void release() const
38 {
39 if (osl_atomic_decrement(&mnRefCnt)__sync_sub_and_fetch((&mnRefCnt), 1) == 0)
10
Assuming the condition is true
11
Taking true branch
40 delete this;
12
Memory is released
41 }
42#ifdef DBG_UTIL
43#ifndef _WIN32
44 sal_Int32 getRefCount() const { return mnRefCnt; }
45#endif
46#endif
47
48
49private:
50 VclReferenceBase(const VclReferenceBase&) = delete;
51 VclReferenceBase& operator=(const VclReferenceBase&) = delete;
52
53 bool mbDisposed : 1;
54
55protected:
56 VclReferenceBase();
57protected:
58 virtual ~VclReferenceBase();
59
60protected:
61 virtual void dispose();
62
63public:
64 void disposeOnce();
65 bool isDisposed() const { return mbDisposed; }
66
67};
68#endif