File: | home/maarten/src/libreoffice/core/include/rtl/ref.hxx |
Warning: | line 192, column 9 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ | |||
2 | /* | |||
3 | * This file is part of the LibreOffice project. | |||
4 | * | |||
5 | * This Source Code Form is subject to the terms of the Mozilla Public | |||
6 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |||
7 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. | |||
8 | * | |||
9 | * This file incorporates work covered by the following license notice: | |||
10 | * | |||
11 | * Licensed to the Apache Software Foundation (ASF) under one or more | |||
12 | * contributor license agreements. See the NOTICE file distributed | |||
13 | * with this work for additional information regarding copyright | |||
14 | * ownership. The ASF licenses this file to you under the Apache | |||
15 | * License, Version 2.0 (the "License"); you may not use this file | |||
16 | * except in compliance with the License. You may obtain a copy of | |||
17 | * the License at http://www.apache.org/licenses/LICENSE-2.0 . | |||
18 | */ | |||
19 | ||||
20 | #include <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 | ||||
144 | using namespace css; | |||
145 | using namespace css::uno; | |||
146 | ||||
147 | struct ScGridWindow::MouseEventState | |||
148 | { | |||
149 | bool mbActivatePart; | |||
150 | ||||
151 | MouseEventState() : | |||
152 | mbActivatePart(false) | |||
153 | {} | |||
154 | }; | |||
155 | ||||
156 | #define SC_FILTERLISTBOX_LINES12 12 | |||
157 | ||||
158 | ScGridWindow::VisibleRange::VisibleRange(const ScDocument& rDoc) | |||
159 | : mnCol1(0) | |||
160 | , mnCol2(rDoc.MaxCol()) | |||
161 | , mnRow1(0) | |||
162 | , mnRow2(rDoc.MaxRow()) | |||
163 | { | |||
164 | } | |||
165 | ||||
166 | bool ScGridWindow::VisibleRange::isInside(SCCOL nCol, SCROW nRow) const | |||
167 | { | |||
168 | return mnCol1 <= nCol && nCol <= mnCol2 && mnRow1 <= nRow && nRow <= mnRow2; | |||
169 | } | |||
170 | ||||
171 | bool 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) | |||
184 | ScFilterListBox::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 | ||||
201 | ScFilterListBox::~ScFilterListBox() | |||
202 | { | |||
203 | disposeOnce(); | |||
204 | } | |||
205 | ||||
206 | void 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 | ||||
218 | void 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 | ||||
229 | IMPL_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 | ||||
248 | IMPL_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 | ||||
263 | IMPL_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 | ||||
278 | ScFilterFloatingWindow::ScFilterFloatingWindow(vcl::Window* pParent) | |||
279 | : FloatingWindow( pParent, WB_BORDER | WB_SYSTEMWINDOW ) // make it a system floater | |||
280 | , m_bGridHadMouseCaptured(pParent->IsMouseCaptured()) | |||
281 | { | |||
282 | } | |||
283 | ||||
284 | ScFilterFloatingWindow::~ScFilterFloatingWindow() | |||
285 | { | |||
286 | disposeOnce(); | |||
287 | } | |||
288 | ||||
289 | void ScFilterFloatingWindow::dispose() | |||
290 | { | |||
291 | EndPopupMode(); | |||
292 | FloatingWindow::dispose(); | |||
293 | } | |||
294 | ||||
295 | static 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 | ||||
309 | static 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 | ||||
328 | static 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 | |||
365 | ScGridWindow::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 | ||||
453 | ScGridWindow::~ScGridWindow() | |||
454 | { | |||
455 | disposeOnce(); | |||
456 | } | |||
457 | ||||
458 | void 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 | ||||
472 | void 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(); | |||
481 | } | |||
482 | while (false); | |||
483 | ||||
484 | if (mpDPFieldPopup) | |||
485 | { | |||
486 | mpDPFieldPopup->get_widget().close(false); | |||
487 | mpDPFieldPopup.disposeAndClear(); | |||
488 | } | |||
489 | } | |||
490 | ||||
491 | IMPL_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 | ||||
502 | IMPL_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 | ||||
510 | namespace { | |||
511 | ||||
512 | struct AutoFilterData : public ScCheckListMenuControl::ExtendedData | |||
513 | { | |||
514 | ScAddress maPos; | |||
515 | ScDBData* mpData; | |||
516 | }; | |||
517 | ||||
518 | class AutoFilterAction : public ScCheckListMenuControl::Action | |||
519 | { | |||
520 | VclPtr<ScGridWindow> mpWindow; | |||
521 | ScGridWindow::AutoFilterMode meMode; | |||
522 | public: | |||
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 | ||||
531 | class AutoFilterPopupEndAction : public ScCheckListMenuControl::Action | |||
532 | { | |||
533 | VclPtr<ScGridWindow> mpWindow; | |||
534 | ScAddress maPos; | |||
535 | public: | |||
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 | ||||
544 | class AddItemToEntry | |||
545 | { | |||
546 | ScQueryEntry::QueryItemsType& mrItems; | |||
547 | svl::SharedStringPool& mrPool; | |||
548 | public: | |||
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 | ||||
564 | class AddSelectedItemString | |||
565 | { | |||
566 | std::unordered_set<OUString>& mrSet; | |||
567 | public: | |||
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 | ||||
577 | void 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 | ||||
592 | void 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 | ||||
736 | void 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 | ||||
747 | void 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 | ||||
892 | namespace { | |||
893 | ||||
894 | void 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 | ||||
907 | void 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 | ||||
924 | void 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 | ||||
937 | void 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 | ||||
986 | void 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 | ||||
1075 | void 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 | ||||
1212 | void 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 | ||||
1235 | void 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 | ||||
1251 | void 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 | ||||
1280 | bool 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 | ||||
1377 | void ScGridWindow::LogicMouseButtonDown(const MouseEvent& rMouseEvent) | |||
1378 | { | |||
1379 | MouseButtonDown(rMouseEvent); | |||
1380 | } | |||
1381 | ||||
1382 | void ScGridWindow::LogicMouseButtonUp(const MouseEvent& rMouseEvent) | |||
1383 | { | |||
1384 | MouseButtonUp(rMouseEvent); | |||
1385 | } | |||
1386 | ||||
1387 | void ScGridWindow::LogicMouseMove(const MouseEvent& rMouseEvent) | |||
1388 | { | |||
1389 | MouseMove(rMouseEvent); | |||
1390 | } | |||
1391 | ||||
1392 | void 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 | ||||
1416 | bool 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 | ||||
1481 | void 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 | ||||
1843 | void 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 | ||||
2356 | void ScGridWindow::FakeButtonUp() | |||
2357 | { | |||
2358 | if ( nButtonDown ) | |||
2359 | { | |||
2360 | MouseEvent aEvent( aCurMousePos ); // nButtons = 0 -> ignore | |||
2361 | MouseButtonUp( aEvent ); | |||
2362 | } | |||
2363 | } | |||
2364 | ||||
2365 | void 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 | ||||
2575 | static 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 | ||||
2601 | bool 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 | ||||
2651 | void 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 | ||||
2705 | void 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 | ||||
2747 | static 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 | ||||
2757 | void 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 | ||||
3036 | void 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 | ||||
3189 | void 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 | ||||
3347 | void 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 | ||||
3358 | void 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 | ||||
3374 | void 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 | ||||
3407 | static 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 | ||||
3435 | static 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 | ||||
3455 | sal_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 | ||||
3670 | sal_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 | ||||
3837 | static 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 | ||||
3927 | static 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 | ||||
3954 | sal_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 | ||||
3967 | sal_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 | ||||
4324 | sal_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 | ||||
4439 | void 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 | ||||
4504 | void 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 | ||||
4558 | void ScGridWindow::ScrollPixel( long nDifX, long nDifY ) | |||
4559 | { | |||
4560 | 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 | ||||
4574 | void 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 | ||||
4671 | void 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 | ||||
4683 | void 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 | ||||
4696 | void 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 | ||||
4706 | void 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 | ||||
4746 | void ScGridWindow::HideCursor() | |||
4747 | { | |||
4748 | ++nCursorHideCount; | |||
4749 | } | |||
4750 | ||||
4751 | void ScGridWindow::ShowCursor() | |||
4752 | { | |||
4753 | --nCursorHideCount; | |||
4754 | } | |||
4755 | ||||
4756 | void 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 | ||||
4776 | void 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 | ||||
4786 | bool 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 | ||||
4890 | static 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 | ||||
4947 | static 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 | ||||
5022 | void 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 | ||||
5168 | namespace { | |||
5169 | ||||
5170 | SvxAdjust 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 | ||||
5197 | std::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 | ||||
5213 | bool 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 | ||||
5236 | bool 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 | ||||
5375 | bool 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 | ||||
5429 | bool 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 | ||||
5492 | void ScGridWindow::DrawLayerCreated() | |||
5493 | { | |||
5494 | SetMapMode( GetDrawMapMode() ); | |||
5495 | ||||
5496 | // initially create overlay objects | |||
5497 | ImpCreateOverlayObjects(); | |||
5498 | } | |||
5499 | ||||
5500 | namespace { | |||
5501 | ||||
5502 | struct 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 | ||||
5511 | IMPL_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 | ||||
5520 | bool 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 | ||||
5681 | void ScGridWindow::EnableAutoSpell( bool bEnable ) | |||
5682 | { | |||
5683 | if (bEnable) | |||
5684 | mpSpellCheckCxt.reset(new sc::SpellCheckContext); | |||
5685 | else | |||
5686 | mpSpellCheckCxt.reset(); | |||
5687 | } | |||
5688 | ||||
5689 | void 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 | ||||
5699 | void 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 | ||||
5710 | const 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 | ||||
5721 | bool ScGridWindow::InsideVisibleRange( SCCOL nPosX, SCROW nPosY ) | |||
5722 | { | |||
5723 | return maVisibleRange.isInside(nPosX, nPosY); | |||
5724 | } | |||
5725 | ||||
5726 | OString 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 | ||||
5741 | void 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 | ||||
5750 | void 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). | |||
5780 | void 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 | ||||
5820 | void 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 | ||||
5837 | void 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 | ||||
5845 | void ScGridWindow::ImpCreateOverlayObjects() | |||
5846 | { | |||
5847 | UpdateCursorOverlay(); | |||
5848 | UpdateCopySourceOverlay(); | |||
5849 | UpdateSelectionOverlay(); | |||
5850 | UpdateAutoFillOverlay(); | |||
5851 | UpdateDragRectOverlay(); | |||
5852 | UpdateHeaderOverlay(); | |||
5853 | UpdateShrinkOverlay(); | |||
5854 | } | |||
5855 | ||||
5856 | void ScGridWindow::ImpDestroyOverlayObjects() | |||
5857 | { | |||
5858 | DeleteCursorOverlay(); | |||
5859 | DeleteCopySourceOverlay(); | |||
5860 | DeleteSelectionOverlay(); | |||
5861 | DeleteAutoFillOverlay(); | |||
5862 | DeleteDragRectOverlay(); | |||
5863 | DeleteHeaderOverlay(); | |||
5864 | DeleteShrinkOverlay(); | |||
5865 | } | |||
5866 | ||||
5867 | void ScGridWindow::UpdateAllOverlays() | |||
5868 | { | |||
5869 | // delete and re-allocate all overlay objects | |||
5870 | ||||
5871 | ImpDestroyOverlayObjects(); | |||
5872 | ImpCreateOverlayObjects(); | |||
5873 | } | |||
5874 | ||||
5875 | void 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 | ||||
5883 | void ScGridWindow::DeleteCopySourceOverlay() | |||
5884 | { | |||
5885 | mpOOSelectionBorder.reset(); | |||
5886 | } | |||
5887 | ||||
5888 | void 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 | ||||
5947 | static 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 | ||||
5974 | static 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 | */ | |||
5993 | void 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 | */ | |||
6060 | void 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 | ||||
6103 | namespace | |||
6104 | { | |||
6105 | ||||
6106 | void 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 | ||||
6130 | void 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 | ||||
6295 | void 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 | ||||
6307 | void ScGridWindow::DeleteSelectionOverlay() | |||
6308 | { | |||
6309 | mpOOSelection.reset(); | |||
6310 | } | |||
6311 | ||||
6312 | void 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 | ||||
6395 | void ScGridWindow::DeleteAutoFillOverlay() | |||
6396 | { | |||
6397 | mpOOAutoFill.reset(); | |||
6398 | mpAutoFillRect.reset(); | |||
6399 | } | |||
6400 | ||||
6401 | void 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 | ||||
6486 | void ScGridWindow::DeleteDragRectOverlay() | |||
6487 | { | |||
6488 | mpOODragRect.reset(); | |||
6489 | } | |||
6490 | ||||
6491 | void 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 | ||||
6613 | void ScGridWindow::DeleteHeaderOverlay() | |||
6614 | { | |||
6615 | mpOOHeader.reset(); | |||
6616 | } | |||
6617 | ||||
6618 | void 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 | ||||
6659 | void ScGridWindow::DeleteShrinkOverlay() | |||
6660 | { | |||
6661 | mpOOShrink.reset(); | |||
6662 | } | |||
6663 | ||||
6664 | void 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 | |||
6727 | rtl::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 | ||||
6744 | void 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 | ||||
6753 | ScViewData& ScGridWindow::getViewData() | |||
6754 | { | |||
6755 | return mrViewData; | |||
6756 | } | |||
6757 | ||||
6758 | FactoryFunction ScGridWindow::GetUITestFactory() const | |||
6759 | { | |||
6760 | return ScGridWinUIObject::create; | |||
6761 | } | |||
6762 | ||||
6763 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | /* |
3 | * This file is part of the LibreOffice project. |
4 | * |
5 | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | * |
9 | * This file incorporates work covered by the following license notice: |
10 | * |
11 | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | * contributor license agreements. See the NOTICE file distributed |
13 | * with this work for additional information regarding copyright |
14 | * ownership. The ASF licenses this file to you under the Apache |
15 | * License, Version 2.0 (the "License"); you may not use this file |
16 | * except in compliance with the License. You may obtain a copy of |
17 | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | */ |
19 | |
20 | #ifndef INCLUDED_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 | |
36 | class VclReferenceBase; |
37 | |
38 | namespace vcl::detail { |
39 | |
40 | template<typename> |
41 | constexpr bool isIncompleteOrDerivedFromVclReferenceBase(...) { return true; } |
42 | |
43 | template<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 | */ |
56 | template <class reference_type> |
57 | class 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 | |
66 | public: |
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); |
204 | m_rInnerRef.clear(); // we should use some 'swap' method ideally ;-) |
205 | if (aTmp.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 | |
218 | template<typename T1, typename T2> |
219 | inline bool operator ==(VclPtr<T1> const & p1, VclPtr<T2> const & p2) { |
220 | return p1.get() == p2.get(); |
221 | } |
222 | |
223 | template<typename T> inline bool operator ==(VclPtr<T> const & p1, T const * p2) |
224 | { |
225 | return p1.get() == p2; |
226 | } |
227 | |
228 | template<typename T> inline bool operator ==(VclPtr<T> const & p1, T * p2) { |
229 | return p1.get() == p2; |
230 | } |
231 | |
232 | template<typename T> inline bool operator ==(T const * p1, VclPtr<T> const & p2) |
233 | { |
234 | return p1 == p2.get(); |
235 | } |
236 | |
237 | template<typename T> inline bool operator ==(T * p1, VclPtr<T> const & p2) { |
238 | return p1 == p2.get(); |
239 | } |
240 | |
241 | template<typename T1, typename T2> |
242 | inline bool operator !=(VclPtr<T1> const & p1, VclPtr<T2> const & p2) { |
243 | return !(p1 == p2); |
244 | } |
245 | |
246 | template<typename T> inline bool operator !=(VclPtr<T> const & p1, T const * p2) |
247 | { |
248 | return !(p1 == p2); |
249 | } |
250 | |
251 | template<typename T> inline bool operator !=(VclPtr<T> const & p1, T * p2) { |
252 | return !(p1 == p2); |
253 | } |
254 | |
255 | template<typename T> inline bool operator !=(T const * p1, VclPtr<T> const & p2) |
256 | { |
257 | return !(p1 == p2); |
258 | } |
259 | |
260 | template<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 | */ |
274 | template <class reference_type> |
275 | class SAL_WARN_UNUSED__attribute__((warn_unused)) VclPtrInstance final : public VclPtr<reference_type> |
276 | { |
277 | public: |
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 | |
290 | template <class reference_type> |
291 | class ScopedVclPtr : public VclPtr<reference_type> |
292 | { |
293 | public: |
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 | |
378 | private: |
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 | |
387 | protected: |
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 |
406 | template <class reference_type> |
407 | class SAL_WARN_UNUSED__attribute__((warn_unused)) ScopedVclPtrInstance final : public ScopedVclPtr<reference_type> |
408 | { |
409 | public: |
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 | |
421 | private: |
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: */ |
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 | |||||||||
34 | namespace rtl | ||||||||
35 | { | ||||||||
36 | |||||||||
37 | /** Template reference class for reference type. | ||||||||
38 | */ | ||||||||
39 | template <class reference_type> | ||||||||
40 | class Reference | ||||||||
41 | { | ||||||||
42 | /** The <b>reference_type</b> body pointer. | ||||||||
43 | */ | ||||||||
44 | reference_type * m_pBody; | ||||||||
45 | |||||||||
46 | |||||||||
47 | public: | ||||||||
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) | ||||||||
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
| ||||||||
177 | { | ||||||||
178 | reference_type * const pOld = m_pBody; | ||||||||
179 | m_pBody = NULL__null; | ||||||||
180 | pOld->release(); | ||||||||
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; | ||||||||
| |||||||||
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 | ||||||||
277 | namespace 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 | */ | ||||||||
286 | template<typename T> | ||||||||
287 | struct 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: */ |
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 | |
25 | class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) VclReferenceBase |
26 | { |
27 | mutable oslInterlockedCount mnRefCnt; |
28 | |
29 | template<typename T> friend class VclPtr; |
30 | |
31 | public: |
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) |
40 | delete this; |
41 | } |
42 | #ifdef DBG_UTIL |
43 | #ifndef _WIN32 |
44 | sal_Int32 getRefCount() const { return mnRefCnt; } |
45 | #endif |
46 | #endif |
47 | |
48 | |
49 | private: |
50 | VclReferenceBase(const VclReferenceBase&) = delete; |
51 | VclReferenceBase& operator=(const VclReferenceBase&) = delete; |
52 | |
53 | bool mbDisposed : 1; |
54 | |
55 | protected: |
56 | VclReferenceBase(); |
57 | protected: |
58 | virtual ~VclReferenceBase(); |
59 | |
60 | protected: |
61 | virtual void dispose(); |
62 | |
63 | public: |
64 | void disposeOnce(); |
65 | bool isDisposed() const { return mbDisposed; } |
66 | |
67 | }; |
68 | #endif |