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