/src/libreoffice/sc/source/ui/view/tabview3.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 <officecfg/Office/Calc.hxx> |
21 | | #include <rangelst.hxx> |
22 | | #include <scitems.hxx> |
23 | | |
24 | | #include <editeng/editview.hxx> |
25 | | #include <editeng/StripPortionsHelper.hxx> |
26 | | #include <svx/fmshell.hxx> |
27 | | #include <svx/sdr/overlay/overlaymanager.hxx> |
28 | | #include <svx/svdoole2.hxx> |
29 | | #include <sfx2/bindings.hxx> |
30 | | #include <sfx2/lokhelper.hxx> |
31 | | #include <sfx2/viewfrm.hxx> |
32 | | #include <vcl/cursor.hxx> |
33 | | #include <vcl/dndlistenercontainer.hxx> |
34 | | #include <vcl/uitest/logger.hxx> |
35 | | #include <vcl/uitest/eventdescription.hxx> |
36 | | #include <sal/log.hxx> |
37 | | #include <osl/diagnose.h> |
38 | | |
39 | | #include <basegfx/polygon/b2dpolygontools.hxx> |
40 | | #include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx> |
41 | | #include <drawinglayer/primitive2d/transformprimitive2d.hxx> |
42 | | #include <svx/sdr/overlay/overlayselection.hxx> |
43 | | #include <svtools/optionsdrawinglayer.hxx> |
44 | | |
45 | | #include <IAnyRefDialog.hxx> |
46 | | #include <tabview.hxx> |
47 | | #include <tabvwsh.hxx> |
48 | | #include <docsh.hxx> |
49 | | #include <gridwin.hxx> |
50 | | #include <olinewin.hxx> |
51 | | #include <overlayobject.hxx> |
52 | | #include <colrowba.hxx> |
53 | | #include <tabcont.hxx> |
54 | | #include <scmod.hxx> |
55 | | #include <sc.hrc> |
56 | | #include <viewutil.hxx> |
57 | | #include <editutil.hxx> |
58 | | #include <inputhdl.hxx> |
59 | | #include <inputwin.hxx> |
60 | | #include <validat.hxx> |
61 | | #include <inputopt.hxx> |
62 | | #include <rfindlst.hxx> |
63 | | #include <hiranges.hxx> |
64 | | #include <viewuno.hxx> |
65 | | #include <dpobject.hxx> |
66 | | #include <seltrans.hxx> |
67 | | #include <fillinfo.hxx> |
68 | | #include <rangeutl.hxx> |
69 | | #include <client.hxx> |
70 | | #include <tabprotection.hxx> |
71 | | #include <spellcheckcontext.hxx> |
72 | | #include <markdata.hxx> |
73 | | #include <formula/FormulaCompiler.hxx> |
74 | | #include <comphelper/lok.hxx> |
75 | | #include <comphelper/scopeguard.hxx> |
76 | | #include <LibreOfficeKit/LibreOfficeKitEnums.h> |
77 | | #include <output.hxx> |
78 | | |
79 | | #include <utility> |
80 | | |
81 | | #include <com/sun/star/chart2/data/HighlightedRange.hpp> |
82 | | |
83 | | namespace |
84 | | { |
85 | | |
86 | | ScRange lcl_getSubRangeByIndex( const ScRange& rRange, sal_Int32 nIndex ) |
87 | 0 | { |
88 | 0 | ScAddress aResult( rRange.aStart ); |
89 | |
|
90 | 0 | SCCOL nWidth = rRange.aEnd.Col() - rRange.aStart.Col() + 1; |
91 | 0 | SCROW nHeight = rRange.aEnd.Row() - rRange.aStart.Row() + 1; |
92 | 0 | SCTAB nDepth = rRange.aEnd.Tab() - rRange.aStart.Tab() + 1; |
93 | 0 | if( (nWidth > 0) && (nHeight > 0) && (nDepth > 0) ) |
94 | 0 | { |
95 | | // row by row from first to last sheet |
96 | 0 | sal_Int32 nArea = nWidth * nHeight; |
97 | 0 | aResult.IncCol( static_cast< SCCOL >( nIndex % nWidth ) ); |
98 | 0 | aResult.IncRow( static_cast< SCROW >( (nIndex % nArea) / nWidth ) ); |
99 | 0 | aResult.IncTab( static_cast< SCTAB >( nIndex / nArea ) ); |
100 | 0 | if( !rRange.Contains( aResult ) ) |
101 | 0 | aResult = rRange.aStart; |
102 | 0 | } |
103 | |
|
104 | 0 | return ScRange( aResult ); |
105 | 0 | } |
106 | | |
107 | | } // anonymous namespace |
108 | | |
109 | | using namespace com::sun::star; |
110 | | |
111 | | ScExtraEditViewManager::~ScExtraEditViewManager() |
112 | 0 | { |
113 | 0 | DBG_ASSERT(nTotalWindows == 0, "ScExtraEditViewManager dtor: some out window has not yet been removed!"); |
114 | 0 | } |
115 | | |
116 | | inline void ScExtraEditViewManager::Add(SfxViewShell* pViewShell, ScSplitPos eWhich) |
117 | 0 | { |
118 | 0 | Apply<Adder>(pViewShell, eWhich); |
119 | 0 | } |
120 | | |
121 | | inline void ScExtraEditViewManager::Remove(SfxViewShell* pViewShell, ScSplitPos eWhich) |
122 | 0 | { |
123 | 0 | Apply<Remover>(pViewShell, eWhich); |
124 | 0 | } |
125 | | |
126 | | |
127 | | template<ScExtraEditViewManager::ModifierTagType ModifierTag> |
128 | | void ScExtraEditViewManager::Apply(SfxViewShell* pViewShell, ScSplitPos eWhich) |
129 | 0 | { |
130 | 0 | ScTabViewShell* pOtherViewShell = dynamic_cast<ScTabViewShell*>(pViewShell); |
131 | 0 | if (pOtherViewShell == nullptr || pOtherViewShell == mpThisViewShell) |
132 | 0 | return; |
133 | | |
134 | 0 | mpOtherEditView = pOtherViewShell->GetViewData().GetEditView(eWhich); |
135 | 0 | if (mpOtherEditView != nullptr) |
136 | 0 | { |
137 | 0 | for (int i = 0; i < 4; ++i) |
138 | 0 | { |
139 | 0 | ScGridWindow* pWin = mpGridWin[i].get(); |
140 | 0 | if (pWin != nullptr) |
141 | 0 | { |
142 | 0 | Modifier<ModifierTag>(pWin); |
143 | 0 | } |
144 | 0 | } |
145 | 0 | } |
146 | 0 | } Unexecuted instantiation: void ScExtraEditViewManager::Apply<(ScExtraEditViewManager::ModifierTagType)0>(SfxViewShell*, ScSplitPos) Unexecuted instantiation: void ScExtraEditViewManager::Apply<(ScExtraEditViewManager::ModifierTagType)1>(SfxViewShell*, ScSplitPos) |
147 | | |
148 | | template<ScExtraEditViewManager::ModifierTagType ModifierTag> |
149 | | void ScExtraEditViewManager::Modifier(ScGridWindow* /*pWin*/) |
150 | | { |
151 | | (void)this; |
152 | | SAL_WARN("sc", "ScExtraEditViewManager::Modifier<ModifierTag>: non-specialized version should not be invoked."); |
153 | | } |
154 | | |
155 | | template<> |
156 | | void ScExtraEditViewManager::Modifier<ScExtraEditViewManager::Adder>(ScGridWindow* pWin) |
157 | 0 | { |
158 | 0 | if (mpOtherEditView->AddOtherViewWindow(pWin)) |
159 | 0 | ++nTotalWindows; |
160 | 0 | } |
161 | | |
162 | | template<> |
163 | | void ScExtraEditViewManager::Modifier<ScExtraEditViewManager::Remover>(ScGridWindow* pWin) |
164 | 0 | { |
165 | 0 | if (mpOtherEditView->RemoveOtherViewWindow(pWin)) |
166 | 0 | --nTotalWindows; |
167 | 0 | } |
168 | | |
169 | | // --- public functions |
170 | | |
171 | | void ScTabView::ClickCursor( SCCOL nPosX, SCROW nPosY, bool bControl ) |
172 | 0 | { |
173 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
174 | 0 | SCTAB nTab = aViewData.CurrentTabForData(); |
175 | 0 | rDoc.SkipOverlapped(nPosX, nPosY, nTab); |
176 | |
|
177 | 0 | ScModule* mod = ScModule::get(); |
178 | 0 | bool bRefMode = mod->IsFormulaMode(); |
179 | |
|
180 | 0 | if ( bRefMode ) |
181 | 0 | { |
182 | 0 | DoneRefMode(); |
183 | |
|
184 | 0 | if (bControl) |
185 | 0 | mod->AddRefEntry(); |
186 | |
|
187 | 0 | InitRefMode( nPosX, nPosY, nTab, SC_REFTYPE_REF ); |
188 | 0 | } |
189 | 0 | else |
190 | 0 | { |
191 | 0 | DoneBlockMode( bControl ); |
192 | 0 | aViewData.ResetOldCursor(); |
193 | 0 | SetCursor( nPosX, nPosY ); |
194 | 0 | } |
195 | 0 | } |
196 | | |
197 | | void ScTabView::UpdateAutoFillMark(bool bFromPaste) |
198 | 0 | { |
199 | | // single selection or cursor |
200 | 0 | ScRange aMarkRange; |
201 | 0 | ScMarkType eMarkType = aViewData.GetSimpleArea(aMarkRange); |
202 | 0 | bool bMarked = eMarkType == SC_MARK_SIMPLE || eMarkType == SC_MARK_SIMPLE_FILTERED; |
203 | |
|
204 | 0 | for (sal_uInt16 i = 0; i < 4; i++) |
205 | 0 | { |
206 | 0 | if (pGridWin[i] && pGridWin[i]->IsVisible()) |
207 | 0 | pGridWin[i]->UpdateAutoFillMark( bMarked, aMarkRange ); |
208 | 0 | } |
209 | |
|
210 | 0 | for (sal_uInt16 i = 0; i < 2; i++) |
211 | 0 | { |
212 | 0 | if (pColBar[i] && pColBar[i]->IsVisible()) |
213 | 0 | pColBar[i]->SetMark( bMarked, aMarkRange.aStart.Col(), aMarkRange.aEnd.Col() ); |
214 | 0 | if (pRowBar[i] && pRowBar[i]->IsVisible()) |
215 | 0 | pRowBar[i]->SetMark( bMarked, aMarkRange.aStart.Row(), aMarkRange.aEnd.Row() ); |
216 | 0 | } |
217 | | |
218 | | // selection transfer object is checked together with AutoFill marks, |
219 | | // because it has the same requirement of a single continuous block. |
220 | 0 | if (!bFromPaste) |
221 | 0 | CheckSelectionTransfer(); // update selection transfer object |
222 | 0 | } |
223 | | |
224 | | void ScTabView::FakeButtonUp( ScSplitPos eWhich ) |
225 | 0 | { |
226 | 0 | if (pGridWin[eWhich]) |
227 | 0 | pGridWin[eWhich]->FakeButtonUp(); |
228 | 0 | } |
229 | | |
230 | | void ScTabView::HideAllCursors() |
231 | 0 | { |
232 | 0 | for (VclPtr<ScGridWindow> & pWin : pGridWin) |
233 | 0 | { |
234 | 0 | if (pWin && pWin->IsVisible()) |
235 | 0 | { |
236 | 0 | vcl::Cursor* pCur = pWin->GetCursor(); |
237 | 0 | if (pCur && pCur->IsVisible()) |
238 | 0 | pCur->Hide(); |
239 | 0 | pWin->HideCursor(); |
240 | 0 | } |
241 | 0 | } |
242 | 0 | } |
243 | | |
244 | | void ScTabView::ShowAllCursors() |
245 | 0 | { |
246 | 0 | for (VclPtr<ScGridWindow> & pWin : pGridWin) |
247 | 0 | { |
248 | 0 | if (pWin && pWin->IsVisible()) |
249 | 0 | { |
250 | 0 | pWin->ShowCursor(); |
251 | 0 | pWin->CursorChanged(); |
252 | 0 | } |
253 | 0 | } |
254 | 0 | } |
255 | | |
256 | | void ScTabView::ShowCursor() |
257 | 0 | { |
258 | 0 | pGridWin[aViewData.GetActivePart()]->ShowCursor(); |
259 | 0 | pGridWin[aViewData.GetActivePart()]->CursorChanged(); |
260 | 0 | } |
261 | | |
262 | | void ScTabView::InvalidateAttribs() |
263 | 0 | { |
264 | 0 | SfxBindings& rBindings = aViewData.GetBindings(); |
265 | |
|
266 | 0 | rBindings.Invalidate( SID_STYLE_APPLY ); |
267 | 0 | rBindings.Invalidate( SID_STYLE_FAMILY2 ); |
268 | 0 | rBindings.Invalidate( SID_STYLE_FAMILY3 ); |
269 | |
|
270 | 0 | rBindings.Invalidate( SID_ATTR_CHAR_FONT ); |
271 | 0 | rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT ); |
272 | 0 | rBindings.Invalidate( SID_ATTR_CHAR_COLOR ); |
273 | |
|
274 | 0 | rBindings.Invalidate( SID_ATTR_CHAR_WEIGHT ); |
275 | 0 | rBindings.Invalidate( SID_ATTR_CHAR_POSTURE ); |
276 | 0 | rBindings.Invalidate( SID_ATTR_CHAR_UNDERLINE ); |
277 | 0 | rBindings.Invalidate( SID_ULINE_VAL_NONE ); |
278 | 0 | rBindings.Invalidate( SID_ULINE_VAL_SINGLE ); |
279 | 0 | rBindings.Invalidate( SID_ULINE_VAL_DOUBLE ); |
280 | 0 | rBindings.Invalidate( SID_ULINE_VAL_DOTTED ); |
281 | |
|
282 | 0 | rBindings.Invalidate( SID_ATTR_CHAR_OVERLINE ); |
283 | |
|
284 | 0 | rBindings.Invalidate( SID_ATTR_CHAR_KERNING ); |
285 | 0 | rBindings.Invalidate( SID_SET_SUPER_SCRIPT ); |
286 | 0 | rBindings.Invalidate( SID_SET_SUB_SCRIPT ); |
287 | 0 | rBindings.Invalidate( SID_ATTR_CHAR_STRIKEOUT ); |
288 | 0 | rBindings.Invalidate( SID_ATTR_CHAR_SHADOWED ); |
289 | |
|
290 | 0 | rBindings.Invalidate( SID_ATTR_PARA_ADJUST_LEFT ); |
291 | 0 | rBindings.Invalidate( SID_ATTR_PARA_ADJUST_RIGHT ); |
292 | 0 | rBindings.Invalidate( SID_ATTR_PARA_ADJUST_BLOCK ); |
293 | 0 | rBindings.Invalidate( SID_ATTR_PARA_ADJUST_CENTER); |
294 | 0 | rBindings.Invalidate( SID_ATTR_PARA_ADJUST_START ); |
295 | 0 | rBindings.Invalidate( SID_ATTR_PARA_ADJUST_END ); |
296 | 0 | rBindings.Invalidate( SID_NUMBER_TYPE_FORMAT); |
297 | |
|
298 | 0 | rBindings.Invalidate( SID_ALIGNLEFT ); |
299 | 0 | rBindings.Invalidate( SID_ALIGNRIGHT ); |
300 | 0 | rBindings.Invalidate( SID_ALIGNBLOCK ); |
301 | 0 | rBindings.Invalidate( SID_ALIGNCENTERHOR ); |
302 | |
|
303 | 0 | rBindings.Invalidate( SID_ALIGNTOP ); |
304 | 0 | rBindings.Invalidate( SID_ALIGNBOTTOM ); |
305 | 0 | rBindings.Invalidate( SID_ALIGNCENTERVER ); |
306 | |
|
307 | 0 | rBindings.Invalidate( SID_SCATTR_CELLPROTECTION ); |
308 | | |
309 | | // stuff for sidebar panels |
310 | 0 | { |
311 | 0 | rBindings.Invalidate( SID_H_ALIGNCELL ); |
312 | 0 | rBindings.Invalidate( SID_V_ALIGNCELL ); |
313 | 0 | rBindings.Invalidate( SID_ATTR_ALIGN_INDENT ); |
314 | 0 | rBindings.Invalidate( SID_FRAME_LINECOLOR ); |
315 | 0 | rBindings.Invalidate( SID_FRAME_LINESTYLE ); |
316 | 0 | rBindings.Invalidate( SID_ATTR_BORDER_OUTER ); |
317 | 0 | rBindings.Invalidate( SID_ATTR_BORDER_INNER ); |
318 | 0 | rBindings.Invalidate( SID_ATTR_BORDER_DIAG_TLBR ); |
319 | 0 | rBindings.Invalidate( SID_ATTR_BORDER_DIAG_BLTR ); |
320 | 0 | rBindings.Invalidate( SID_NUMBER_TYPE_FORMAT ); |
321 | 0 | } |
322 | |
|
323 | 0 | rBindings.Invalidate( SID_BACKGROUND_COLOR ); |
324 | |
|
325 | 0 | rBindings.Invalidate( SID_ATTR_ALIGN_LINEBREAK ); |
326 | 0 | rBindings.Invalidate( SID_NUMBER_FORMAT ); |
327 | |
|
328 | 0 | rBindings.Invalidate( SID_TEXTDIRECTION_LEFT_TO_RIGHT ); |
329 | 0 | rBindings.Invalidate( SID_TEXTDIRECTION_TOP_TO_BOTTOM ); |
330 | 0 | rBindings.Invalidate( SID_ATTR_PARA_LEFT_TO_RIGHT ); |
331 | 0 | rBindings.Invalidate( SID_ATTR_PARA_RIGHT_TO_LEFT ); |
332 | | |
333 | | // pseudo slots for Format menu |
334 | 0 | rBindings.Invalidate( SID_ALIGN_ANY_HDEFAULT ); |
335 | 0 | rBindings.Invalidate( SID_ALIGN_ANY_LEFT ); |
336 | 0 | rBindings.Invalidate( SID_ALIGN_ANY_HCENTER ); |
337 | 0 | rBindings.Invalidate( SID_ALIGN_ANY_RIGHT ); |
338 | 0 | rBindings.Invalidate( SID_ALIGN_ANY_START ); |
339 | 0 | rBindings.Invalidate( SID_ALIGN_ANY_END ); |
340 | 0 | rBindings.Invalidate( SID_ALIGN_ANY_JUSTIFIED ); |
341 | 0 | rBindings.Invalidate( SID_ALIGN_ANY_VDEFAULT ); |
342 | 0 | rBindings.Invalidate( SID_ALIGN_ANY_TOP ); |
343 | 0 | rBindings.Invalidate( SID_ALIGN_ANY_VCENTER ); |
344 | 0 | rBindings.Invalidate( SID_ALIGN_ANY_BOTTOM ); |
345 | |
|
346 | 0 | rBindings.Invalidate( SID_NUMBER_CURRENCY ); |
347 | 0 | rBindings.Invalidate( SID_NUMBER_SCIENTIFIC ); |
348 | 0 | rBindings.Invalidate( SID_NUMBER_DATE ); |
349 | 0 | rBindings.Invalidate( SID_NUMBER_CURRENCY ); |
350 | 0 | rBindings.Invalidate( SID_NUMBER_PERCENT ); |
351 | 0 | rBindings.Invalidate( SID_NUMBER_TWODEC ); |
352 | 0 | rBindings.Invalidate( SID_NUMBER_TIME ); |
353 | 0 | rBindings.Invalidate( SID_NUMBER_STANDARD ); |
354 | 0 | rBindings.Invalidate( SID_NUMBER_THOUSANDS ); |
355 | 0 | } |
356 | | |
357 | | namespace { |
358 | | |
359 | | void collectUIInformation(std::map<OUString, OUString>&& aParameters) |
360 | 0 | { |
361 | 0 | EventDescription aDescription; |
362 | 0 | aDescription.aID = "grid_window"; |
363 | 0 | aDescription.aAction = "SELECT"; |
364 | 0 | aDescription.aParameters = std::move(aParameters); |
365 | 0 | aDescription.aParent = "MainWindow"; |
366 | 0 | aDescription.aKeyWord = "ScGridWinUIObject"; |
367 | |
|
368 | 0 | UITestLogger::getInstance().logEvent(aDescription); |
369 | 0 | } |
370 | | |
371 | | } |
372 | | |
373 | | // SetCursor - Cursor, set, draw, update InputWin |
374 | | // or send reference |
375 | | // Optimising breaks the functionality |
376 | | |
377 | | void ScTabView::SetCursor( SCCOL nPosX, SCROW nPosY, bool bNew ) |
378 | 0 | { |
379 | 0 | SCCOL nOldX = aViewData.GetCurX(); |
380 | 0 | SCROW nOldY = aViewData.GetCurY(); |
381 | | |
382 | | // DeactivateIP only for MarkListHasChanged |
383 | | |
384 | | // FIXME: this is to limit the number of rows handled in the Online |
385 | | // to 1000; this will be removed again when the performance |
386 | | // bottlenecks are sorted out |
387 | 0 | if (comphelper::LibreOfficeKit::isActive()) |
388 | 0 | nPosY = std::min(nPosY, MAXTILEDROW); |
389 | |
|
390 | 0 | if ( !(nPosX != nOldX || nPosY != nOldY || bNew) ) |
391 | 0 | { |
392 | 0 | HighlightOverlay(); |
393 | 0 | return; |
394 | 0 | } |
395 | | |
396 | 0 | ScTabViewShell* pViewShell = aViewData.GetViewShell(); |
397 | 0 | bool bRefMode = pViewShell && pViewShell->IsRefInputMode(); |
398 | 0 | if ( aViewData.HasEditView( aViewData.GetActivePart() ) && !bRefMode ) // 23259 or so |
399 | 0 | { |
400 | 0 | UpdateInputLine(); |
401 | 0 | } |
402 | |
|
403 | 0 | HideAllCursors(); |
404 | |
|
405 | 0 | aViewData.SetCurX( nPosX ); |
406 | 0 | aViewData.SetCurY( nPosY ); |
407 | |
|
408 | 0 | ShowAllCursors(); |
409 | |
|
410 | 0 | HighlightOverlay(); |
411 | |
|
412 | 0 | CursorPosChanged(); |
413 | |
|
414 | 0 | OUString aCurrAddress = ScAddress(nPosX,nPosY,0).GetColRowString(); |
415 | 0 | collectUIInformation({{"CELL", aCurrAddress}}); |
416 | |
|
417 | 0 | if (!comphelper::LibreOfficeKit::isActive()) |
418 | 0 | return; |
419 | | |
420 | 0 | if (nPosX <= aViewData.GetMaxTiledCol() - 10 && nPosY <= aViewData.GetMaxTiledRow() - 25) |
421 | 0 | return; |
422 | | |
423 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
424 | 0 | ScDocShell* pDocSh = aViewData.GetDocShell(); |
425 | 0 | ScModelObj* pModelObj = pDocSh->GetModel(); |
426 | 0 | Size aOldSize(0, 0); |
427 | 0 | if (pModelObj) |
428 | 0 | aOldSize = pModelObj->getDocumentSize(); |
429 | |
|
430 | 0 | if (nPosX > aViewData.GetMaxTiledCol() - 10) |
431 | 0 | aViewData.SetMaxTiledCol(std::min<SCCOL>(std::max(nPosX, aViewData.GetMaxTiledCol()) + 10, rDoc.MaxCol())); |
432 | |
|
433 | 0 | if (nPosY > aViewData.GetMaxTiledRow() - 25) |
434 | 0 | aViewData.SetMaxTiledRow(std::min<SCROW>(std::max(nPosY, aViewData.GetMaxTiledRow()) + 25, MAXTILEDROW)); |
435 | |
|
436 | 0 | Size aNewSize(0, 0); |
437 | 0 | if (pModelObj) |
438 | 0 | aNewSize = pModelObj->getDocumentSize(); |
439 | |
|
440 | 0 | if (!pDocSh) |
441 | 0 | return; |
442 | | |
443 | 0 | if (pModelObj) |
444 | 0 | { |
445 | 0 | ScGridWindow* pGridWindow = aViewData.GetActiveWin(); |
446 | 0 | if (pGridWindow) |
447 | 0 | { |
448 | 0 | Size aNewSizePx(aNewSize.Width() * aViewData.GetPPTX(), aNewSize.Height() * aViewData.GetPPTY()); |
449 | 0 | if (aNewSizePx != pGridWindow->GetOutputSizePixel()) |
450 | 0 | pGridWindow->SetOutputSizePixel(aNewSizePx); |
451 | 0 | } |
452 | 0 | } |
453 | |
|
454 | 0 | if (aOldSize == aNewSize) |
455 | 0 | return; |
456 | | |
457 | | // New area extended to the right of the sheet after last column |
458 | | // including overlapping area with aNewRowArea |
459 | 0 | tools::Rectangle aNewColArea(aOldSize.getWidth(), 0, aNewSize.getWidth(), aNewSize.getHeight()); |
460 | | // New area extended to the bottom of the sheet after last row |
461 | | // excluding overlapping area with aNewColArea |
462 | 0 | tools::Rectangle aNewRowArea(0, aOldSize.getHeight(), aOldSize.getWidth(), aNewSize.getHeight()); |
463 | | |
464 | | // Only invalidate if spreadsheet extended to the right |
465 | 0 | if (aNewColArea.getOpenWidth()) |
466 | 0 | { |
467 | 0 | SfxLokHelper::notifyInvalidation(aViewData.GetViewShell(), &aNewColArea); |
468 | 0 | } |
469 | | |
470 | | // Only invalidate if spreadsheet extended to the bottom |
471 | 0 | if (aNewRowArea.getOpenHeight()) |
472 | 0 | { |
473 | 0 | SfxLokHelper::notifyInvalidation(aViewData.GetViewShell(), &aNewRowArea); |
474 | 0 | } |
475 | | |
476 | | // Provide size in the payload, so clients don't have to |
477 | | // call lok::Document::getDocumentSize(). |
478 | 0 | std::stringstream ss; |
479 | 0 | ss << aNewSize.Width() << ", " << aNewSize.Height(); |
480 | 0 | OString sSize( ss.str() ); |
481 | 0 | ScModelObj* pModel = comphelper::getFromUnoTunnel<ScModelObj>(aViewData.GetViewShell()->GetCurrentDocument()); |
482 | 0 | SfxLokHelper::notifyDocumentSizeChanged(aViewData.GetViewShell(), sSize, pModel, false); |
483 | 0 | } |
484 | | |
485 | | static bool lcl_IsRefDlgActive(SfxViewFrame& rViewFrm) |
486 | 0 | { |
487 | 0 | ScModule* pScMod = ScModule::get(); |
488 | 0 | if (!pScMod->IsRefDialogOpen()) |
489 | 0 | return false; |
490 | | |
491 | 0 | auto nDlgId = pScMod->GetCurRefDlgId(); |
492 | 0 | if (!rViewFrm.HasChildWindow(nDlgId)) |
493 | 0 | return false; |
494 | | |
495 | 0 | SfxChildWindow* pChild = rViewFrm.GetChildWindow(nDlgId); |
496 | 0 | if (!pChild) |
497 | 0 | return false; |
498 | | |
499 | 0 | auto xDlgController = pChild->GetController(); |
500 | 0 | if (!xDlgController || !xDlgController->getDialog()->get_visible()) |
501 | 0 | return false; |
502 | | |
503 | 0 | IAnyRefDialog* pRefDlg = dynamic_cast<IAnyRefDialog*>(xDlgController.get()); |
504 | 0 | return pRefDlg && pRefDlg->IsRefInputMode(); |
505 | 0 | } |
506 | | |
507 | | void ScTabView::CheckSelectionTransfer() |
508 | 0 | { |
509 | 0 | if ( !aViewData.IsActive() ) // only for active view |
510 | 0 | return; |
511 | | |
512 | 0 | ScModule* pScMod = ScModule::get(); |
513 | 0 | ScSelectionTransferObj* pOld = pScMod->GetSelectionTransfer(); |
514 | 0 | rtl::Reference<ScSelectionTransferObj> pNew = ScSelectionTransferObj::CreateFromView( this ); |
515 | 0 | if ( !pNew ) |
516 | 0 | return; |
517 | | |
518 | | // create new selection |
519 | | |
520 | 0 | if (pOld) |
521 | 0 | pOld->ForgetView(); |
522 | |
|
523 | 0 | pScMod->SetSelectionTransfer( pNew.get() ); |
524 | | |
525 | | // tdf#124975/tdf#136242 changing the calc selection can trigger removal of the |
526 | | // selection of an open RefDlg dialog, so don't inform the |
527 | | // desktop clipboard of the changed selection if that dialog is open |
528 | 0 | if (!lcl_IsRefDlgActive(aViewData.GetViewShell()->GetViewFrame())) |
529 | 0 | pNew->CopyToPrimarySelection(); // may delete pOld |
530 | | |
531 | | // Log the selection change |
532 | 0 | ScMarkData& rMark = aViewData.GetMarkData(); |
533 | 0 | if (rMark.IsMarked()) |
534 | 0 | { |
535 | 0 | const ScRange& aMarkRange = rMark.GetMarkArea(); |
536 | 0 | OUString aStartAddress = aMarkRange.aStart.GetColRowString(); |
537 | 0 | OUString aEndAddress = aMarkRange.aEnd.GetColRowString(); |
538 | 0 | collectUIInformation({{"RANGE", aStartAddress + ":" + aEndAddress}}); |
539 | 0 | } |
540 | 0 | } |
541 | | |
542 | | // update input row / menus |
543 | | // CursorPosChanged calls SelectionChanged |
544 | | // SelectionChanged calls CellContentChanged |
545 | | |
546 | | void ScTabView::CellContentChanged() |
547 | 0 | { |
548 | 0 | SfxBindings& rBindings = aViewData.GetBindings(); |
549 | |
|
550 | 0 | rBindings.Invalidate( SID_ATTR_SIZE ); // -> show error message |
551 | 0 | rBindings.Invalidate( SID_THESAURUS ); |
552 | 0 | rBindings.Invalidate( SID_HYPERLINK_GETLINK ); |
553 | 0 | rBindings.Invalidate( SID_ROWCOL_SELCOUNT ); |
554 | |
|
555 | 0 | InvalidateAttribs(); // attributes updates |
556 | |
|
557 | 0 | aViewData.GetViewShell()->UpdateInputHandler(); |
558 | 0 | } |
559 | | |
560 | | void ScTabView::SetTabProtectionSymbol( SCTAB nTab, const bool bProtect ) |
561 | 0 | { |
562 | 0 | pTabControl->SetProtectionSymbol( static_cast<sal_uInt16>(nTab)+1, bProtect); |
563 | 0 | } |
564 | | |
565 | | void ScTabView::SelectionChanged(bool bFromPaste) |
566 | 0 | { |
567 | 0 | SfxViewFrame& rViewFrame = aViewData.GetViewShell()->GetViewFrame(); |
568 | 0 | uno::Reference<frame::XController> xController = rViewFrame.GetFrame().GetController(); |
569 | 0 | if (xController.is()) |
570 | 0 | { |
571 | 0 | ScTabViewObj* pImp = dynamic_cast<ScTabViewObj*>( xController.get() ); |
572 | 0 | if (pImp) |
573 | 0 | pImp->SelectionChanged(); |
574 | 0 | } |
575 | |
|
576 | 0 | UpdateAutoFillMark(bFromPaste); // also calls CheckSelectionTransfer |
577 | |
|
578 | 0 | SfxBindings& rBindings = aViewData.GetBindings(); |
579 | |
|
580 | 0 | rBindings.Invalidate( SID_CURRENTCELL ); // -> Navigator |
581 | 0 | rBindings.Invalidate( SID_AUTO_FILTER ); // -> Menu |
582 | 0 | rBindings.Invalidate( FID_NOTE_VISIBLE ); |
583 | 0 | rBindings.Invalidate( FID_SHOW_NOTE ); |
584 | 0 | rBindings.Invalidate( FID_HIDE_NOTE ); |
585 | 0 | rBindings.Invalidate( FID_SHOW_ALL_NOTES ); |
586 | 0 | rBindings.Invalidate( FID_HIDE_ALL_NOTES ); |
587 | 0 | rBindings.Invalidate( SID_TOGGLE_NOTES ); |
588 | 0 | rBindings.Invalidate( SID_DELETE_NOTE ); |
589 | 0 | rBindings.Invalidate( SID_ROWCOL_SELCOUNT ); |
590 | | |
591 | | // functions than may need to be disabled |
592 | |
|
593 | 0 | rBindings.Invalidate( FID_INS_ROWBRK ); |
594 | 0 | rBindings.Invalidate( FID_INS_COLBRK ); |
595 | 0 | rBindings.Invalidate( FID_DEL_ROWBRK ); |
596 | 0 | rBindings.Invalidate( FID_DEL_COLBRK ); |
597 | 0 | rBindings.Invalidate( FID_MERGE_ON ); |
598 | 0 | rBindings.Invalidate( FID_MERGE_OFF ); |
599 | 0 | rBindings.Invalidate( FID_MERGE_TOGGLE ); |
600 | 0 | rBindings.Invalidate( SID_AUTOFILTER_HIDE ); |
601 | 0 | rBindings.Invalidate( SID_UNFILTER ); |
602 | 0 | rBindings.Invalidate( SID_REIMPORT_DATA ); |
603 | 0 | rBindings.Invalidate( SID_REFRESH_DBAREA ); |
604 | 0 | rBindings.Invalidate( SID_OUTLINE_SHOW ); |
605 | 0 | rBindings.Invalidate( SID_OUTLINE_HIDE ); |
606 | 0 | rBindings.Invalidate( SID_OUTLINE_REMOVE ); |
607 | 0 | rBindings.Invalidate( FID_FILL_TO_BOTTOM ); |
608 | 0 | rBindings.Invalidate( FID_FILL_TO_RIGHT ); |
609 | 0 | rBindings.Invalidate( FID_FILL_TO_TOP ); |
610 | 0 | rBindings.Invalidate( FID_FILL_TO_LEFT ); |
611 | 0 | rBindings.Invalidate( FID_FILL_SERIES ); |
612 | 0 | rBindings.Invalidate( SID_SCENARIOS ); |
613 | 0 | rBindings.Invalidate( SID_AUTOFORMAT ); |
614 | 0 | rBindings.Invalidate( SID_OPENDLG_TABOP ); |
615 | 0 | rBindings.Invalidate( SID_DATA_SELECT ); |
616 | |
|
617 | 0 | rBindings.Invalidate( SID_CUT ); |
618 | 0 | rBindings.Invalidate( SID_COPY ); |
619 | 0 | rBindings.Invalidate( SID_PASTE ); |
620 | 0 | rBindings.Invalidate( SID_PASTE_SPECIAL ); |
621 | 0 | rBindings.Invalidate( SID_PASTE_UNFORMATTED ); |
622 | 0 | rBindings.Invalidate( SID_COPYDELETE ); |
623 | |
|
624 | 0 | rBindings.Invalidate( FID_INS_ROW ); |
625 | 0 | rBindings.Invalidate( FID_INS_COLUMN ); |
626 | 0 | rBindings.Invalidate( FID_INS_ROWS_BEFORE ); |
627 | 0 | rBindings.Invalidate( FID_INS_COLUMNS_BEFORE ); |
628 | 0 | rBindings.Invalidate( FID_INS_ROWS_AFTER ); |
629 | 0 | rBindings.Invalidate( FID_INS_COLUMNS_AFTER ); |
630 | 0 | rBindings.Invalidate( FID_INS_CELL ); |
631 | 0 | rBindings.Invalidate( FID_INS_CELLSDOWN ); |
632 | 0 | rBindings.Invalidate( FID_INS_CELLSRIGHT ); |
633 | |
|
634 | 0 | rBindings.Invalidate( FID_CHG_COMMENT ); |
635 | | |
636 | | // only due to protect cell: |
637 | |
|
638 | 0 | rBindings.Invalidate( SID_CELL_FORMAT_RESET ); |
639 | 0 | rBindings.Invalidate( SID_DELETE ); |
640 | 0 | rBindings.Invalidate( SID_DELETE_CONTENTS ); |
641 | 0 | rBindings.Invalidate( FID_DELETE_CELL ); |
642 | 0 | rBindings.Invalidate( FID_CELL_FORMAT ); |
643 | 0 | rBindings.Invalidate( SID_ENABLE_HYPHENATION ); |
644 | 0 | rBindings.Invalidate( SID_INSERT_POSTIT ); |
645 | 0 | rBindings.Invalidate( SID_CHARMAP ); |
646 | 0 | rBindings.Invalidate( SID_OPENDLG_FUNCTION ); |
647 | 0 | rBindings.Invalidate( FID_VALIDATION ); |
648 | 0 | rBindings.Invalidate( SID_EXTERNAL_SOURCE ); |
649 | 0 | rBindings.Invalidate( SID_TEXT_TO_COLUMNS ); |
650 | 0 | rBindings.Invalidate( SID_SORT_ASCENDING ); |
651 | 0 | rBindings.Invalidate( SID_SORT_DESCENDING ); |
652 | 0 | rBindings.Invalidate( SID_SELECT_UNPROTECTED_CELLS ); |
653 | 0 | rBindings.Invalidate( SID_CLEAR_AUTO_FILTER ); |
654 | 0 | if (!comphelper::LibreOfficeKit::isActive()) |
655 | 0 | rBindings.Invalidate( SID_LANGUAGE_STATUS ); |
656 | |
|
657 | 0 | if (aViewData.GetViewShell()->HasAccessibilityObjects()) |
658 | 0 | aViewData.GetViewShell()->BroadcastAccessibility(SfxHint(SfxHintId::ScAccCursorChanged)); |
659 | |
|
660 | 0 | CellContentChanged(); |
661 | 0 | } |
662 | | |
663 | | void ScTabView::CursorPosChanged() |
664 | 0 | { |
665 | 0 | bool bRefMode = ScModule::get()->IsFormulaMode(); |
666 | 0 | if ( !bRefMode ) // check that RefMode works when switching sheets |
667 | 0 | aViewData.GetDocShell()->Broadcast( SfxHint( SfxHintId::ScKillEditView ) ); |
668 | | |
669 | | // Broadcast, so that other Views of the document also switch |
670 | |
|
671 | 0 | ScDocument& rDocument = aViewData.GetDocument(); |
672 | 0 | bool bDataPilot = rDocument.HasDataPilotAtPosition(aViewData.GetCurPos()); |
673 | 0 | aViewData.GetViewShell()->SetPivotShell(bDataPilot); |
674 | |
|
675 | 0 | if (!bDataPilot) |
676 | 0 | { |
677 | 0 | bool bSparkline = rDocument.HasSparkline(aViewData.GetCurPos()); |
678 | 0 | aViewData.GetViewShell()->SetSparklineShell(bSparkline); |
679 | 0 | } |
680 | | |
681 | | // UpdateInputHandler now in CellContentChanged |
682 | |
|
683 | 0 | SelectionChanged(); |
684 | |
|
685 | 0 | aViewData.SetTabStartCol( SC_TABSTART_NONE ); |
686 | 0 | } |
687 | | |
688 | | namespace { |
689 | | |
690 | | Point calcHintWindowPosition( |
691 | | const Point& rCellPos, const Size& rCellSize, const Size& rFrameWndSize, const Size& rHintWndSize) |
692 | 0 | { |
693 | 0 | const tools::Long nMargin = 20; |
694 | |
|
695 | 0 | tools::Long nMLeft = rCellPos.X(); |
696 | 0 | tools::Long nMRight = rFrameWndSize.Width() - rCellPos.X() - rCellSize.Width(); |
697 | 0 | tools::Long nMTop = rCellPos.Y(); |
698 | 0 | tools::Long nMBottom = rFrameWndSize.Height() - rCellPos.Y() - rCellSize.Height(); |
699 | | |
700 | | // First, see if we can fit the entire hint window in the visible region. |
701 | |
|
702 | 0 | if (nMRight - nMargin >= rHintWndSize.Width()) |
703 | 0 | { |
704 | | // Right margin is wide enough. |
705 | 0 | if (rFrameWndSize.Height() >= rHintWndSize.Height()) |
706 | 0 | { |
707 | | // The frame has enough height. Take it. |
708 | 0 | Point aPos = rCellPos; |
709 | 0 | aPos.AdjustX(rCellSize.Width() + nMargin ); |
710 | 0 | if (aPos.Y() + rHintWndSize.Height() > rFrameWndSize.Height()) |
711 | 0 | { |
712 | | // Push the hint window up a bit to make it fit. |
713 | 0 | aPos.setY( rFrameWndSize.Height() - rHintWndSize.Height() ); |
714 | 0 | } |
715 | 0 | return aPos; |
716 | 0 | } |
717 | 0 | } |
718 | | |
719 | 0 | if (nMBottom - nMargin >= rHintWndSize.Height()) |
720 | 0 | { |
721 | | // Bottom margin is high enough. |
722 | 0 | if (rFrameWndSize.Width() >= rHintWndSize.Width()) |
723 | 0 | { |
724 | | // The frame has enough width. Take it. |
725 | 0 | Point aPos = rCellPos; |
726 | 0 | aPos.AdjustY(rCellSize.Height() + nMargin ); |
727 | 0 | if (aPos.X() + rHintWndSize.Width() > rFrameWndSize.Width()) |
728 | 0 | { |
729 | | // Move the hint window to the left to make it fit. |
730 | 0 | aPos.setX( rFrameWndSize.Width() - rHintWndSize.Width() ); |
731 | 0 | } |
732 | 0 | return aPos; |
733 | 0 | } |
734 | 0 | } |
735 | | |
736 | 0 | if (nMLeft - nMargin >= rHintWndSize.Width()) |
737 | 0 | { |
738 | | // Left margin is wide enough. |
739 | 0 | if (rFrameWndSize.Height() >= rHintWndSize.Height()) |
740 | 0 | { |
741 | | // The frame is high enough. Take it. |
742 | 0 | Point aPos = rCellPos; |
743 | 0 | aPos.AdjustX( -(rHintWndSize.Width() + nMargin) ); |
744 | 0 | if (aPos.Y() + rHintWndSize.Height() > rFrameWndSize.Height()) |
745 | 0 | { |
746 | | // Push the hint window up a bit to make it fit. |
747 | 0 | aPos.setY( rFrameWndSize.Height() - rHintWndSize.Height() ); |
748 | 0 | } |
749 | 0 | return aPos; |
750 | 0 | } |
751 | 0 | } |
752 | | |
753 | 0 | if (nMTop - nMargin >= rHintWndSize.Height()) |
754 | 0 | { |
755 | | // Top margin is high enough. |
756 | 0 | if (rFrameWndSize.Width() >= rHintWndSize.Width()) |
757 | 0 | { |
758 | | // The frame is wide enough. Take it. |
759 | 0 | Point aPos = rCellPos; |
760 | 0 | aPos.AdjustY( -(rHintWndSize.Height() + nMargin) ); |
761 | 0 | if (aPos.X() + rHintWndSize.Width() > rFrameWndSize.Width()) |
762 | 0 | { |
763 | | // Move the hint window to the left to make it fit. |
764 | 0 | aPos.setX( rFrameWndSize.Width() - rHintWndSize.Width() ); |
765 | 0 | } |
766 | 0 | return aPos; |
767 | 0 | } |
768 | 0 | } |
769 | | |
770 | | // The popup doesn't fit in any direction in its entirety. Do our best. |
771 | | |
772 | 0 | if (nMRight - nMargin >= rHintWndSize.Width()) |
773 | 0 | { |
774 | | // Right margin is good enough. |
775 | 0 | Point aPos = rCellPos; |
776 | 0 | aPos.AdjustX(nMargin + rCellSize.Width() ); |
777 | 0 | aPos.setY( 0 ); |
778 | 0 | return aPos; |
779 | 0 | } |
780 | | |
781 | 0 | if (nMBottom - nMargin >= rHintWndSize.Height()) |
782 | 0 | { |
783 | | // Bottom margin is good enough. |
784 | 0 | Point aPos = rCellPos; |
785 | 0 | aPos.AdjustY(nMargin + rCellSize.Height() ); |
786 | 0 | aPos.setX( 0 ); |
787 | 0 | return aPos; |
788 | 0 | } |
789 | | |
790 | 0 | if (nMLeft - nMargin >= rHintWndSize.Width()) |
791 | 0 | { |
792 | | // Left margin is good enough. |
793 | 0 | Point aPos = rCellPos; |
794 | 0 | aPos.AdjustX( -(rHintWndSize.Width() + nMargin) ); |
795 | 0 | aPos.setY( 0 ); |
796 | 0 | return aPos; |
797 | 0 | } |
798 | | |
799 | 0 | if (nMTop - nMargin >= rHintWndSize.Height()) |
800 | 0 | { |
801 | | // Top margin is good enough. |
802 | 0 | Point aPos = rCellPos; |
803 | 0 | aPos.AdjustY( -(rHintWndSize.Height() + nMargin) ); |
804 | 0 | aPos.setX( 0 ); |
805 | 0 | return aPos; |
806 | 0 | } |
807 | | |
808 | | // None of the above. Hopeless. At least try not to cover the current |
809 | | // cell. |
810 | 0 | Point aPos = rCellPos; |
811 | 0 | aPos.AdjustX(rCellSize.Width() ); |
812 | 0 | return aPos; |
813 | 0 | } |
814 | | |
815 | | } |
816 | | |
817 | | void ScTabView::TestHintWindow() |
818 | 0 | { |
819 | | // show input help window and list drop-down button for validity |
820 | |
|
821 | 0 | mxInputHintOO.reset(); |
822 | |
|
823 | 0 | bool bListValButton = false; |
824 | 0 | ScAddress aListValPos; |
825 | |
|
826 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
827 | 0 | const SfxUInt32Item& rItem = rDoc.GetAttr( aViewData.GetCurX(), |
828 | 0 | aViewData.GetCurY(), |
829 | 0 | aViewData.CurrentTabForData(), |
830 | 0 | ATTR_VALIDDATA ); |
831 | 0 | if ( rItem.GetValue() ) |
832 | 0 | { |
833 | 0 | const ScValidationData* pData = rDoc.GetValidationEntry( rItem.GetValue() ); |
834 | 0 | OSL_ENSURE(pData,"ValidationData not found"); |
835 | 0 | OUString aTitle, aMessage; |
836 | |
|
837 | 0 | if ( pData && pData->GetInput( aTitle, aMessage ) && !aMessage.isEmpty() ) |
838 | 0 | { |
839 | 0 | ScSplitPos eWhich = aViewData.GetActivePart(); |
840 | 0 | ScGridWindow* pWin = pGridWin[eWhich].get(); |
841 | 0 | SCCOL nCol = aViewData.GetCurX(); |
842 | 0 | SCROW nRow = aViewData.GetCurY(); |
843 | 0 | Point aPos = aViewData.GetScrPos( nCol, nRow, eWhich ); |
844 | 0 | Size aWinSize = pWin->GetOutputSizePixel(); |
845 | | // cursor visible? |
846 | 0 | if ( nCol >= aViewData.GetPosX(WhichH(eWhich)) && |
847 | 0 | nRow >= aViewData.GetPosY(WhichV(eWhich)) && |
848 | 0 | aPos.X() < aWinSize.Width() && aPos.Y() < aWinSize.Height() ) |
849 | 0 | { |
850 | 0 | const svtools::ColorConfig& rColorCfg = ScModule::get()->GetColorConfig(); |
851 | | // tdf#156398 use same color combination as used in XclDefaultPalette |
852 | 0 | Color aCommentText = rColorCfg.GetColorValue(svtools::FONTCOLOR).nColor; |
853 | 0 | Color aCommentBack = rColorCfg.GetColorValue(svtools::CALCNOTESBACKGROUND).nColor; |
854 | | // create HintWindow, determines its size by itself |
855 | 0 | ScOverlayHint* pOverlay = new ScOverlayHint(aTitle, aMessage, |
856 | 0 | aCommentBack, aCommentText, |
857 | 0 | pFrameWin->GetFont()); |
858 | |
|
859 | 0 | mxInputHintOO.reset(new sdr::overlay::OverlayObjectList); |
860 | 0 | mxInputHintOO->append(std::unique_ptr<sdr::overlay::OverlayObject>(pOverlay)); |
861 | |
|
862 | 0 | Size aHintWndSize = pOverlay->GetSizePixel(); |
863 | 0 | tools::Long nCellSizeX = 0; |
864 | 0 | tools::Long nCellSizeY = 0; |
865 | 0 | aViewData.GetMergeSizePixel(nCol, nRow, nCellSizeX, nCellSizeY); |
866 | |
|
867 | 0 | Point aHintPos = calcHintWindowPosition( |
868 | 0 | aPos, Size(nCellSizeX,nCellSizeY), aWinSize, aHintWndSize); |
869 | |
|
870 | 0 | pOverlay->SetPos(pWin->PixelToLogic(aHintPos, pWin->GetDrawMapMode()), pWin->GetDrawMapMode()); |
871 | 0 | for (VclPtr<ScGridWindow> & pWindow : pGridWin) |
872 | 0 | { |
873 | 0 | if (!pWindow) |
874 | 0 | continue; |
875 | 0 | if (!pWindow->IsVisible()) |
876 | 0 | continue; |
877 | 0 | rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = pWindow->getOverlayManager(); |
878 | 0 | if (!xOverlayManager.is()) |
879 | 0 | continue; |
880 | 0 | if (pWindow == pWin) |
881 | 0 | { |
882 | 0 | xOverlayManager->add(*pOverlay); |
883 | 0 | pWindow->updateLOKInputHelp(aTitle, aMessage); |
884 | 0 | } |
885 | 0 | else |
886 | 0 | { |
887 | | //tdf#92530 if the help tip doesn't fit into its allocated area in a split window |
888 | | //scenario, then because here we place it into the other split windows as well the |
889 | | //missing portions will be displayed in the other split windows to form an apparent |
890 | | //single tip, albeit "under" the split lines |
891 | 0 | Point aOtherPos(pWindow->ScreenToOutputPixel(pWin->OutputToScreenPixel(aHintPos))); |
892 | 0 | std::unique_ptr<ScOverlayHint> pOtherOverlay(new ScOverlayHint(aTitle, aMessage, |
893 | 0 | aCommentBack, |
894 | 0 | aCommentText, |
895 | 0 | pFrameWin->GetFont())); |
896 | 0 | Point aFooPos(pWindow->PixelToLogic(aOtherPos, pWindow->GetDrawMapMode())); |
897 | 0 | pOtherOverlay->SetPos(aFooPos, pWindow->GetDrawMapMode()); |
898 | 0 | xOverlayManager->add(*pOtherOverlay); |
899 | 0 | mxInputHintOO->append(std::move(pOtherOverlay)); |
900 | 0 | } |
901 | 0 | } |
902 | 0 | } |
903 | 0 | } |
904 | | |
905 | | // list drop-down button |
906 | 0 | if ( pData && pData->HasSelectionList() ) |
907 | 0 | { |
908 | 0 | aListValPos.Set( aViewData.GetCurX(), aViewData.GetCurY(), aViewData.CurrentTabForData() ); |
909 | 0 | bListValButton = true; |
910 | 0 | } |
911 | 0 | } |
912 | |
|
913 | 0 | for (VclPtr<ScGridWindow> const & pWin : pGridWin) |
914 | 0 | { |
915 | 0 | if (pWin && pWin->IsVisible()) |
916 | 0 | pWin->UpdateListValPos(bListValButton, aListValPos); |
917 | 0 | } |
918 | 0 | } |
919 | | |
920 | 0 | bool ScTabView::HasHintWindow() const { return mxInputHintOO != nullptr; } |
921 | | |
922 | | void ScTabView::RemoveHintWindow() |
923 | 0 | { |
924 | 0 | mxInputHintOO.reset(); |
925 | 0 | } |
926 | | |
927 | | // find window that should not be over the cursor |
928 | | static weld::Window* lcl_GetCareWin(SfxViewFrame& rViewFrm) |
929 | 0 | { |
930 | | //! also spelling ??? (then set the member variables when calling) |
931 | | |
932 | | // search & replace |
933 | 0 | if (rViewFrm.HasChildWindow(SID_SEARCH_DLG)) |
934 | 0 | { |
935 | 0 | SfxChildWindow* pChild = rViewFrm.GetChildWindow(SID_SEARCH_DLG); |
936 | 0 | if (pChild) |
937 | 0 | { |
938 | 0 | auto xDlgController = pChild->GetController(); |
939 | 0 | if (xDlgController && xDlgController->getDialog()->get_visible()) |
940 | 0 | return xDlgController->getDialog(); |
941 | 0 | } |
942 | 0 | } |
943 | | |
944 | | // apply changes |
945 | 0 | if ( rViewFrm.HasChildWindow(FID_CHG_ACCEPT) ) |
946 | 0 | { |
947 | 0 | SfxChildWindow* pChild = rViewFrm.GetChildWindow(FID_CHG_ACCEPT); |
948 | 0 | if (pChild) |
949 | 0 | { |
950 | 0 | auto xDlgController = pChild->GetController(); |
951 | 0 | if (xDlgController && xDlgController->getDialog()->get_visible()) |
952 | 0 | return xDlgController->getDialog(); |
953 | 0 | } |
954 | 0 | } |
955 | | |
956 | 0 | return nullptr; |
957 | 0 | } |
958 | | |
959 | | // adjust screen with respect to cursor position |
960 | | |
961 | | void ScTabView::AlignToCursor( SCCOL nCurX, SCROW nCurY, ScFollowMode eMode, |
962 | | const ScSplitPos* pWhich ) |
963 | 0 | { |
964 | | // now switch active part here |
965 | |
|
966 | 0 | ScSplitPos eActive = aViewData.GetActivePart(); |
967 | 0 | ScHSplitPos eActiveX = WhichH(eActive); |
968 | 0 | ScVSplitPos eActiveY = WhichV(eActive); |
969 | 0 | bool bHFix = (aViewData.GetHSplitMode() == SC_SPLIT_FIX); |
970 | 0 | bool bVFix = (aViewData.GetVSplitMode() == SC_SPLIT_FIX); |
971 | 0 | if (bHFix && eActiveX == SC_SPLIT_LEFT && nCurX >= aViewData.GetFixPosX()) |
972 | 0 | { |
973 | 0 | ActivatePart( (eActiveY==SC_SPLIT_TOP) ? SC_SPLIT_TOPRIGHT : SC_SPLIT_BOTTOMRIGHT ); |
974 | 0 | eActiveX = SC_SPLIT_RIGHT; |
975 | 0 | } |
976 | 0 | if (bVFix && eActiveY == SC_SPLIT_TOP && nCurY >= aViewData.GetFixPosY()) |
977 | 0 | { |
978 | 0 | ActivatePart( (eActiveX==SC_SPLIT_LEFT) ? SC_SPLIT_BOTTOMLEFT : SC_SPLIT_BOTTOMRIGHT ); |
979 | 0 | eActiveY = SC_SPLIT_BOTTOM; |
980 | 0 | } |
981 | | |
982 | | // actual align |
983 | |
|
984 | 0 | if ( eMode != SC_FOLLOW_NONE ) |
985 | 0 | { |
986 | 0 | ScSplitPos eAlign; |
987 | 0 | if (pWhich) |
988 | 0 | eAlign = *pWhich; |
989 | 0 | else |
990 | 0 | eAlign = aViewData.GetActivePart(); |
991 | 0 | ScHSplitPos eAlignX = WhichH(eAlign); |
992 | 0 | ScVSplitPos eAlignY = WhichV(eAlign); |
993 | |
|
994 | 0 | SCCOL nDeltaX = aViewData.GetPosX(eAlignX); |
995 | 0 | SCROW nDeltaY = aViewData.GetPosY(eAlignY); |
996 | 0 | SCCOL nSizeX = aViewData.VisibleCellsX(eAlignX); |
997 | 0 | SCROW nSizeY = aViewData.VisibleCellsY(eAlignY); |
998 | |
|
999 | 0 | tools::Long nCellSizeX; |
1000 | 0 | tools::Long nCellSizeY; |
1001 | 0 | if ( nCurX >= 0 && nCurY >= 0 ) |
1002 | 0 | aViewData.GetMergeSizePixel( nCurX, nCurY, nCellSizeX, nCellSizeY ); |
1003 | 0 | else |
1004 | 0 | nCellSizeX = nCellSizeY = 0; |
1005 | 0 | Size aScrSize = aViewData.GetScrSize(); |
1006 | |
|
1007 | 0 | tools::Long nDenom; |
1008 | 0 | if ( eMode == SC_FOLLOW_JUMP_END && nCurX > aViewData.GetRefStartX() |
1009 | 0 | && nCurY > aViewData.GetRefStartY() ) |
1010 | 0 | nDenom = 1; // tdf#154271 Selected cell will be at the bottom corner |
1011 | | // to maximize the visible/usable area |
1012 | 0 | else |
1013 | 0 | nDenom = 2; // Selected cell will be at the center of the screen, so that |
1014 | | // it will be visible. This is useful for search results, etc. |
1015 | 0 | tools::Long nSpaceX = ( aScrSize.Width() - nCellSizeX ) / nDenom; |
1016 | 0 | tools::Long nSpaceY = ( aScrSize.Height() - nCellSizeY ) / nDenom; |
1017 | | // nSpaceY: desired start position of cell for FOLLOW_JUMP, modified if dialog interferes |
1018 | |
|
1019 | 0 | bool bForceNew = false; // force new calculation of JUMP position (vertical only) |
1020 | | |
1021 | | // VisibleCellsY == CellsAtY( GetPosY( eWhichY ), 1, eWhichY ) |
1022 | | |
1023 | | // when for instance a search dialog is open, don't put the cursor behind the dialog |
1024 | | // if possible, put the row with the cursor above or below the dialog |
1025 | | //! not if already completely visible |
1026 | |
|
1027 | 0 | if ( eMode == SC_FOLLOW_JUMP || eMode == SC_FOLLOW_JUMP_END ) |
1028 | 0 | { |
1029 | 0 | weld::Window* pCare = lcl_GetCareWin( aViewData.GetViewShell()->GetViewFrame() ); |
1030 | 0 | if (pCare) |
1031 | 0 | { |
1032 | 0 | bool bLimit = false; |
1033 | 0 | tools::Rectangle aDlgPixel; |
1034 | 0 | Size aWinSize; |
1035 | 0 | vcl::Window* pWin = GetActiveWin(); |
1036 | 0 | weld::Window* pFrame = pWin ? pWin->GetFrameWeld() : nullptr; |
1037 | 0 | int x, y, width, height; |
1038 | 0 | if (pFrame && pCare->get_extents_relative_to(*pFrame, x, y, width, height)) |
1039 | 0 | { |
1040 | 0 | aDlgPixel = tools::Rectangle(Point(x, y), Size(width, height)); |
1041 | 0 | aWinSize = pWin->GetOutputSizePixel(); |
1042 | | // dos the dialog cover the GridWin? |
1043 | 0 | if ( aDlgPixel.Right() >= 0 && aDlgPixel.Left() < aWinSize.Width() ) |
1044 | 0 | { |
1045 | 0 | if ( nCurX < nDeltaX || nCurX >= nDeltaX+nSizeX || |
1046 | 0 | nCurY < nDeltaY || nCurY >= nDeltaY+nSizeY ) |
1047 | 0 | bLimit = true; // scroll anyway |
1048 | 0 | else |
1049 | 0 | { |
1050 | | // cursor is on the screen |
1051 | 0 | Point aStart = aViewData.GetScrPos( nCurX, nCurY, eAlign ); |
1052 | 0 | tools::Long nCSX, nCSY; |
1053 | 0 | aViewData.GetMergeSizePixel( nCurX, nCurY, nCSX, nCSY ); |
1054 | 0 | tools::Rectangle aCursor( aStart, Size( nCSX, nCSY ) ); |
1055 | 0 | if ( aCursor.Overlaps( aDlgPixel ) ) |
1056 | 0 | bLimit = true; // cell is covered by the dialog |
1057 | 0 | } |
1058 | 0 | } |
1059 | 0 | } |
1060 | |
|
1061 | 0 | if (bLimit) |
1062 | 0 | { |
1063 | 0 | bool bBottom = false; |
1064 | 0 | tools::Long nTopSpace = aDlgPixel.Top(); |
1065 | 0 | tools::Long nBotSpace = aWinSize.Height() - aDlgPixel.Bottom(); |
1066 | 0 | if ( nBotSpace > 0 && nBotSpace > nTopSpace ) |
1067 | 0 | { |
1068 | 0 | tools::Long nDlgBot = aDlgPixel.Bottom(); |
1069 | 0 | SCCOL nWPosX; |
1070 | 0 | SCROW nWPosY; |
1071 | 0 | aViewData.GetPosFromPixel( 0,nDlgBot, eAlign, nWPosX, nWPosY ); |
1072 | 0 | ++nWPosY; // below the last affected cell |
1073 | |
|
1074 | 0 | SCROW nDiff = nWPosY - nDeltaY; |
1075 | 0 | if ( nCurY >= nDiff ) // position can not be negative |
1076 | 0 | { |
1077 | 0 | nSpaceY = nDlgBot + ( nBotSpace - nCellSizeY ) / 2; |
1078 | 0 | bBottom = true; |
1079 | 0 | bForceNew = true; |
1080 | 0 | } |
1081 | 0 | } |
1082 | 0 | if ( !bBottom && nTopSpace > 0 ) |
1083 | 0 | { |
1084 | 0 | nSpaceY = ( nTopSpace - nCellSizeY ) / 2; |
1085 | 0 | bForceNew = true; |
1086 | 0 | } |
1087 | 0 | } |
1088 | 0 | } |
1089 | 0 | } |
1090 | |
|
1091 | 0 | SCCOL nNewDeltaX = nDeltaX; |
1092 | 0 | SCROW nNewDeltaY = nDeltaY; |
1093 | 0 | bool bDoLine = false; |
1094 | |
|
1095 | 0 | switch (eMode) |
1096 | 0 | { |
1097 | 0 | case SC_FOLLOW_JUMP: |
1098 | 0 | case SC_FOLLOW_JUMP_END: |
1099 | 0 | if ( nCurX < nDeltaX || nCurX >= nDeltaX+nSizeX ) |
1100 | 0 | { |
1101 | 0 | nNewDeltaX = nCurX - aViewData.CellsAtX( nCurX, -1, eAlignX, nSpaceX ); |
1102 | 0 | if (nNewDeltaX < 0) |
1103 | 0 | nNewDeltaX = 0; |
1104 | 0 | nSizeX = aViewData.CellsAtX( nNewDeltaX, 1, eAlignX ); |
1105 | 0 | } |
1106 | 0 | if ( nCurY < nDeltaY || nCurY >= nDeltaY+nSizeY || bForceNew ) |
1107 | 0 | { |
1108 | 0 | nNewDeltaY = nCurY - aViewData.CellsAtY( nCurY, -1, eAlignY, nSpaceY ); |
1109 | 0 | if (nNewDeltaY < 0) |
1110 | 0 | nNewDeltaY = 0; |
1111 | 0 | nSizeY = aViewData.CellsAtY( nNewDeltaY, 1, eAlignY ); |
1112 | 0 | } |
1113 | 0 | bDoLine = true; |
1114 | 0 | break; |
1115 | | |
1116 | 0 | case SC_FOLLOW_LINE: |
1117 | 0 | bDoLine = true; |
1118 | 0 | break; |
1119 | | |
1120 | 0 | case SC_FOLLOW_FIX: |
1121 | 0 | if ( nCurX < nDeltaX || nCurX >= nDeltaX+nSizeX ) |
1122 | 0 | { |
1123 | 0 | nNewDeltaX = nDeltaX + nCurX - aViewData.GetCurX(); |
1124 | 0 | if (nNewDeltaX < 0) |
1125 | 0 | nNewDeltaX = 0; |
1126 | 0 | nSizeX = aViewData.CellsAtX( nNewDeltaX, 1, eAlignX ); |
1127 | 0 | } |
1128 | 0 | if ( nCurY < nDeltaY || nCurY >= nDeltaY+nSizeY ) |
1129 | 0 | { |
1130 | 0 | nNewDeltaY = nDeltaY + nCurY - aViewData.GetCurY(); |
1131 | 0 | if (nNewDeltaY < 0) |
1132 | 0 | nNewDeltaY = 0; |
1133 | 0 | nSizeY = aViewData.CellsAtY( nNewDeltaY, 1, eAlignY ); |
1134 | 0 | } |
1135 | | |
1136 | | // like old version of SC_FOLLOW_JUMP: |
1137 | |
|
1138 | 0 | if ( nCurX < nNewDeltaX || nCurX >= nNewDeltaX+nSizeX ) |
1139 | 0 | { |
1140 | 0 | nNewDeltaX = nCurX - (nSizeX / 2); |
1141 | 0 | if (nNewDeltaX < 0) |
1142 | 0 | nNewDeltaX = 0; |
1143 | 0 | nSizeX = aViewData.CellsAtX( nNewDeltaX, 1, eAlignX ); |
1144 | 0 | } |
1145 | 0 | if ( nCurY < nNewDeltaY || nCurY >= nNewDeltaY+nSizeY ) |
1146 | 0 | { |
1147 | 0 | nNewDeltaY = nCurY - (nSizeY / 2); |
1148 | 0 | if (nNewDeltaY < 0) |
1149 | 0 | nNewDeltaY = 0; |
1150 | 0 | nSizeY = aViewData.CellsAtY( nNewDeltaY, 1, eAlignY ); |
1151 | 0 | } |
1152 | |
|
1153 | 0 | bDoLine = true; |
1154 | 0 | break; |
1155 | | |
1156 | 0 | case SC_FOLLOW_NONE: |
1157 | 0 | break; |
1158 | 0 | default: |
1159 | 0 | OSL_FAIL("Wrong cursor mode"); |
1160 | 0 | break; |
1161 | 0 | } |
1162 | | |
1163 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
1164 | 0 | if (bDoLine) |
1165 | 0 | { |
1166 | 0 | while ( nCurX >= nNewDeltaX+nSizeX ) |
1167 | 0 | { |
1168 | 0 | nNewDeltaX = nCurX-nSizeX+1; |
1169 | 0 | SCTAB nTab = aViewData.CurrentTabForData(); |
1170 | 0 | while ( nNewDeltaX < rDoc.MaxCol() && !rDoc.GetColWidth( nNewDeltaX, nTab ) ) |
1171 | 0 | ++nNewDeltaX; |
1172 | 0 | nSizeX = aViewData.CellsAtX( nNewDeltaX, 1, eAlignX ); |
1173 | 0 | } |
1174 | 0 | while ( nCurY >= nNewDeltaY+nSizeY ) |
1175 | 0 | { |
1176 | 0 | nNewDeltaY = nCurY-nSizeY+1; |
1177 | 0 | SCTAB nTab = aViewData.CurrentTabForData(); |
1178 | 0 | while ( nNewDeltaY < rDoc.MaxRow() && !rDoc.GetRowHeight( nNewDeltaY, nTab ) ) |
1179 | 0 | ++nNewDeltaY; |
1180 | 0 | nSizeY = aViewData.CellsAtY( nNewDeltaY, 1, eAlignY ); |
1181 | 0 | } |
1182 | 0 | if ( nCurX < nNewDeltaX ) |
1183 | 0 | nNewDeltaX = nCurX; |
1184 | 0 | if ( nCurY < nNewDeltaY ) |
1185 | 0 | nNewDeltaY = nCurY; |
1186 | 0 | } |
1187 | |
|
1188 | 0 | if ( nNewDeltaX != nDeltaX ) |
1189 | 0 | nSizeX = aViewData.CellsAtX( nNewDeltaX, 1, eAlignX ); |
1190 | 0 | if (nNewDeltaX+nSizeX-1 > rDoc.MaxCol()) |
1191 | 0 | nNewDeltaX = rDoc.MaxCol()-nSizeX+1; |
1192 | 0 | if (nNewDeltaX < 0) |
1193 | 0 | nNewDeltaX = 0; |
1194 | |
|
1195 | 0 | if ( nNewDeltaY != nDeltaY ) |
1196 | 0 | nSizeY = aViewData.CellsAtY( nNewDeltaY, 1, eAlignY ); |
1197 | 0 | if (nNewDeltaY+nSizeY-1 > rDoc.MaxRow()) |
1198 | 0 | nNewDeltaY = rDoc.MaxRow()-nSizeY+1; |
1199 | 0 | if (nNewDeltaY < 0) |
1200 | 0 | nNewDeltaY = 0; |
1201 | |
|
1202 | 0 | if ( nNewDeltaX != nDeltaX ) |
1203 | 0 | ScrollX( nNewDeltaX - nDeltaX, eAlignX ); |
1204 | 0 | if ( nNewDeltaY != nDeltaY ) |
1205 | 0 | ScrollY( nNewDeltaY - nDeltaY, eAlignY ); |
1206 | 0 | } |
1207 | | |
1208 | | // switch active part again |
1209 | | |
1210 | 0 | if (bHFix) |
1211 | 0 | if (eActiveX == SC_SPLIT_RIGHT && nCurX < aViewData.GetFixPosX()) |
1212 | 0 | { |
1213 | 0 | ActivatePart( (eActiveY==SC_SPLIT_TOP) ? SC_SPLIT_TOPLEFT : SC_SPLIT_BOTTOMLEFT ); |
1214 | 0 | eActiveX = SC_SPLIT_LEFT; |
1215 | 0 | } |
1216 | 0 | if (bVFix) |
1217 | 0 | if (eActiveY == SC_SPLIT_BOTTOM && nCurY < aViewData.GetFixPosY()) |
1218 | 0 | { |
1219 | 0 | ActivatePart( (eActiveX==SC_SPLIT_LEFT) ? SC_SPLIT_TOPLEFT : SC_SPLIT_TOPRIGHT ); |
1220 | 0 | } |
1221 | 0 | } |
1222 | | |
1223 | | bool ScTabView::SelMouseButtonDown( const MouseEvent& rMEvt ) |
1224 | 0 | { |
1225 | 0 | bool bRet = false; |
1226 | | |
1227 | | // #i3875# *Hack* |
1228 | 0 | bool bMod1Locked = (aViewData.GetViewShell()->GetLockedModifiers() & KEY_MOD1) != 0; |
1229 | 0 | aViewData.SetSelCtrlMouseClick( rMEvt.IsMod1() || bMod1Locked ); |
1230 | |
|
1231 | 0 | if ( pSelEngine ) |
1232 | 0 | { |
1233 | 0 | bMoveIsShift = rMEvt.IsShift(); |
1234 | 0 | bRet = pSelEngine->SelMouseButtonDown( rMEvt ); |
1235 | 0 | bMoveIsShift = false; |
1236 | 0 | } |
1237 | |
|
1238 | 0 | aViewData.SetSelCtrlMouseClick( false ); // #i3875# *Hack* |
1239 | |
|
1240 | 0 | return bRet; |
1241 | 0 | } |
1242 | | |
1243 | | // MoveCursor - with adjustment of the view section |
1244 | | |
1245 | | void ScTabView::MoveCursorAbs( SCCOL nCurX, SCROW nCurY, ScFollowMode eMode, |
1246 | | bool bShift, bool bControl, bool bKeepOld, bool bKeepSel ) |
1247 | 0 | { |
1248 | 0 | if (!bKeepOld) |
1249 | 0 | aViewData.ResetOldCursor(); |
1250 | |
|
1251 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
1252 | | // #i123629# |
1253 | 0 | if( aViewData.GetViewShell()->GetForceFocusOnCurCell() ) |
1254 | 0 | aViewData.GetViewShell()->SetForceFocusOnCurCell( !rDoc.ValidColRow(nCurX, nCurY) ); |
1255 | |
|
1256 | 0 | if (nCurX < 0) nCurX = 0; |
1257 | 0 | if (nCurY < 0) nCurY = 0; |
1258 | 0 | if (nCurX > rDoc.MaxCol()) nCurX = rDoc.MaxCol(); |
1259 | 0 | if (nCurY > rDoc.MaxRow()) nCurY = rDoc.MaxRow(); |
1260 | | |
1261 | | // FIXME: this is to limit the number of rows handled in the Online |
1262 | | // to 1000; this will be removed again when the performance |
1263 | | // bottlenecks are sorted out |
1264 | 0 | if (comphelper::LibreOfficeKit::isActive()) |
1265 | 0 | nCurY = std::min(nCurY, MAXTILEDROW); |
1266 | |
|
1267 | 0 | HideAllCursors(); |
1268 | | |
1269 | | // switch of active now in AlignToCursor |
1270 | |
|
1271 | 0 | AlignToCursor( nCurX, nCurY, eMode ); |
1272 | |
|
1273 | 0 | if (bKeepSel) |
1274 | 0 | { |
1275 | 0 | SetCursor( nCurX, nCurY ); // keep selection |
1276 | | |
1277 | | // If the cursor is in existing selection, it's a cursor movement by |
1278 | | // ENTER or TAB. If not, then it's a new selection during ADD |
1279 | | // selection mode. |
1280 | |
|
1281 | 0 | const ScMarkData& rMark = aViewData.GetMarkData(); |
1282 | 0 | ScRangeList aSelList; |
1283 | 0 | rMark.FillRangeListWithMarks(&aSelList, false); |
1284 | 0 | if (!aSelList.Contains(ScRange(nCurX, nCurY, aViewData.CurrentTabForData()))) |
1285 | | // Cursor not in existing selection. Start a new selection. |
1286 | 0 | DoneBlockMode(true); |
1287 | 0 | } |
1288 | 0 | else |
1289 | 0 | { |
1290 | 0 | if (!bShift) |
1291 | 0 | { |
1292 | | // Remove all marked data on cursor movement unless the Shift is |
1293 | | // locked or while editing a formula. It is cheaper to check for |
1294 | | // marks first and then formula mode. |
1295 | 0 | ScMarkData& rMark = aViewData.GetMarkData(); |
1296 | 0 | bool bMarked = rMark.IsMarked() || rMark.IsMultiMarked(); |
1297 | 0 | if (bMarked && !ScModule::get()->IsFormulaMode()) |
1298 | 0 | { |
1299 | 0 | rMark.ResetMark(); |
1300 | 0 | DoneBlockMode(); |
1301 | 0 | InitOwnBlockMode( ScRange( nCurX, nCurY, aViewData.CurrentTabForData())); |
1302 | 0 | MarkDataChanged(); |
1303 | 0 | } |
1304 | 0 | } |
1305 | |
|
1306 | 0 | bool bSame = ( nCurX == aViewData.GetCurX() && nCurY == aViewData.GetCurY() ); |
1307 | 0 | bMoveIsShift = bShift; |
1308 | 0 | pSelEngine->CursorPosChanging( bShift, bControl ); |
1309 | 0 | bMoveIsShift = false; |
1310 | 0 | aFunctionSet.SetCursorAtCell( nCurX, nCurY, false ); |
1311 | | |
1312 | | // If the cursor has not been moved, the SelectionChanged for canceling the |
1313 | | // selection has to happen here individually: |
1314 | 0 | if (bSame) |
1315 | 0 | SelectionChanged(); |
1316 | 0 | } |
1317 | |
|
1318 | 0 | ShowAllCursors(); |
1319 | 0 | TestHintWindow(); |
1320 | 0 | } |
1321 | | |
1322 | | void ScTabView::MoveCursorRel( SCCOL nMovX, SCROW nMovY, ScFollowMode eMode, |
1323 | | bool bShift, bool bKeepSel ) |
1324 | 0 | { |
1325 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
1326 | 0 | SCTAB nTab = aViewData.CurrentTabForData(); |
1327 | |
|
1328 | 0 | bool bSkipProtected = false, bSkipUnprotected = false; |
1329 | 0 | const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab); |
1330 | 0 | if ( pProtect && pProtect->isProtected() ) |
1331 | 0 | { |
1332 | 0 | bSkipProtected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS); |
1333 | 0 | bSkipUnprotected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS); |
1334 | 0 | } |
1335 | |
|
1336 | 0 | if ( bSkipProtected && bSkipUnprotected ) |
1337 | 0 | return; |
1338 | | |
1339 | 0 | SCCOL nOldX; |
1340 | 0 | SCROW nOldY; |
1341 | 0 | SCCOL nCurX; |
1342 | 0 | SCROW nCurY; |
1343 | 0 | if ( aViewData.IsRefMode() ) |
1344 | 0 | { |
1345 | 0 | nOldX = aViewData.GetRefEndX(); |
1346 | 0 | nOldY = aViewData.GetRefEndY(); |
1347 | 0 | nCurX = nOldX + nMovX; |
1348 | 0 | nCurY = nOldY + nMovY; |
1349 | 0 | } |
1350 | 0 | else |
1351 | 0 | { |
1352 | 0 | nOldX = aViewData.GetCurX(); |
1353 | 0 | nOldY = aViewData.GetCurY(); |
1354 | 0 | nCurX = (nMovX != 0) ? nOldX+nMovX : aViewData.GetOldCurX(); |
1355 | 0 | nCurY = (nMovY != 0) ? nOldY+nMovY : aViewData.GetOldCurY(); |
1356 | 0 | } |
1357 | |
|
1358 | 0 | if (nMovX < 0 && nOldX == 0) |
1359 | 0 | { // trying to go left from 1st column |
1360 | 0 | if (nMovY == 0) // done, because no vertical move is requested |
1361 | 0 | return; |
1362 | 0 | } |
1363 | 0 | if (nMovY < 0 && nOldY == 0) |
1364 | 0 | { // trying to go up from 1st row |
1365 | 0 | if (nMovX == 0) // done, because no horizontal move is requested |
1366 | 0 | return; |
1367 | 0 | } |
1368 | | |
1369 | 0 | aViewData.ResetOldCursor(); |
1370 | |
|
1371 | 0 | if (nMovX != 0 && rDoc.ValidColRow(nCurX,nCurY)) |
1372 | 0 | SkipCursorHorizontal(nCurX, nCurY, nOldX, nMovX); |
1373 | |
|
1374 | 0 | if (nMovY != 0 && rDoc.ValidColRow(nCurX,nCurY)) |
1375 | 0 | SkipCursorVertical(nCurX, nCurY, nOldY, nMovY); |
1376 | |
|
1377 | 0 | MoveCursorAbs( nCurX, nCurY, eMode, bShift, false, true, bKeepSel ); |
1378 | 0 | } |
1379 | | |
1380 | | void ScTabView::MoveCursorPage( SCCOL nMovX, SCROW nMovY, ScFollowMode eMode, bool bShift, bool bKeepSel ) |
1381 | 0 | { |
1382 | 0 | SCCOL nPageX; |
1383 | 0 | SCROW nPageY; |
1384 | 0 | GetPageMoveEndPosition(nMovX, nMovY, nPageX, nPageY); |
1385 | 0 | MoveCursorRel( nPageX, nPageY, eMode, bShift, bKeepSel ); |
1386 | 0 | } |
1387 | | |
1388 | | void ScTabView::MoveCursorArea( SCCOL nMovX, SCROW nMovY, ScFollowMode eMode, bool bShift, bool bKeepSel, bool bInteractiveByUser ) |
1389 | 0 | { |
1390 | 0 | SCCOL nNewX; |
1391 | 0 | SCROW nNewY; |
1392 | 0 | GetAreaMoveEndPosition(nMovX, nMovY, eMode, nNewX, nNewY, eMode, bInteractiveByUser); |
1393 | 0 | MoveCursorRel(nNewX, nNewY, eMode, bShift, bKeepSel); |
1394 | 0 | } |
1395 | | |
1396 | | void ScTabView::MoveCursorEnd( SCCOL nMovX, SCROW nMovY, ScFollowMode eMode, bool bShift, bool bKeepSel ) |
1397 | 0 | { |
1398 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
1399 | 0 | SCTAB nTab = aViewData.CurrentTabForData(); |
1400 | |
|
1401 | 0 | SCCOL nCurX; |
1402 | 0 | SCROW nCurY; |
1403 | 0 | aViewData.GetMoveCursor( nCurX,nCurY ); |
1404 | 0 | SCCOL nNewX = nCurX; |
1405 | 0 | SCROW nNewY = nCurY; |
1406 | |
|
1407 | 0 | SCCOL nUsedX = 0; |
1408 | 0 | SCROW nUsedY = 0; |
1409 | 0 | if ( nMovX > 0 || nMovY > 0 ) |
1410 | 0 | rDoc.GetPrintArea( nTab, nUsedX, nUsedY ); // get end |
1411 | |
|
1412 | 0 | if (nMovX<0) |
1413 | 0 | nNewX=0; |
1414 | 0 | else if (nMovX>0) |
1415 | 0 | nNewX=nUsedX; // last used range |
1416 | |
|
1417 | 0 | if (nMovY<0) |
1418 | 0 | nNewY=0; |
1419 | 0 | else if (nMovY>0) |
1420 | 0 | nNewY=nUsedY; |
1421 | |
|
1422 | 0 | aViewData.ResetOldCursor(); |
1423 | 0 | MoveCursorRel( nNewX-nCurX, nNewY-nCurY, eMode, bShift, bKeepSel ); |
1424 | 0 | } |
1425 | | |
1426 | | void ScTabView::MoveCursorScreen( SCCOL nMovX, SCROW nMovY, ScFollowMode eMode, bool bShift ) |
1427 | 0 | { |
1428 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
1429 | 0 | SCTAB nTab = aViewData.CurrentTabForData(); |
1430 | |
|
1431 | 0 | SCCOL nCurX; |
1432 | 0 | SCROW nCurY; |
1433 | 0 | aViewData.GetMoveCursor( nCurX,nCurY ); |
1434 | 0 | SCCOL nNewX = nCurX; |
1435 | 0 | SCROW nNewY = nCurY; |
1436 | |
|
1437 | 0 | ScSplitPos eWhich = aViewData.GetActivePart(); |
1438 | 0 | SCCOL nPosX = aViewData.GetPosX( WhichH(eWhich) ); |
1439 | 0 | SCROW nPosY = aViewData.GetPosY( WhichV(eWhich) ); |
1440 | |
|
1441 | 0 | SCCOL nAddX = aViewData.VisibleCellsX( WhichH(eWhich) ); |
1442 | 0 | if (nAddX != 0) |
1443 | 0 | --nAddX; |
1444 | 0 | SCROW nAddY = aViewData.VisibleCellsY( WhichV(eWhich) ); |
1445 | 0 | if (nAddY != 0) |
1446 | 0 | --nAddY; |
1447 | |
|
1448 | 0 | if (nMovX<0) |
1449 | 0 | nNewX=nPosX; |
1450 | 0 | else if (nMovX>0) |
1451 | 0 | nNewX=nPosX+nAddX; |
1452 | |
|
1453 | 0 | if (nMovY<0) |
1454 | 0 | nNewY=nPosY; |
1455 | 0 | else if (nMovY>0) |
1456 | 0 | nNewY=nPosY+nAddY; |
1457 | |
|
1458 | 0 | aViewData.SetOldCursor( nNewX,nNewY ); |
1459 | 0 | rDoc.SkipOverlapped(nNewX, nNewY, nTab); |
1460 | 0 | MoveCursorAbs( nNewX, nNewY, eMode, bShift, false, true ); |
1461 | 0 | } |
1462 | | |
1463 | | void ScTabView::MoveCursorEnter( bool bShift ) // bShift -> up/down |
1464 | 0 | { |
1465 | 0 | const ScInputOptions& rOpt = ScModule::get()->GetInputOptions(); |
1466 | 0 | if (!rOpt.GetMoveSelection()) |
1467 | 0 | { |
1468 | 0 | aViewData.UpdateInputHandler(true); |
1469 | 0 | return; |
1470 | 0 | } |
1471 | | |
1472 | 0 | SCCOL nMoveX = 0; |
1473 | 0 | SCROW nMoveY = 0; |
1474 | 0 | switch (static_cast<ScDirection>(rOpt.GetMoveDir())) |
1475 | 0 | { |
1476 | 0 | case DIR_BOTTOM: |
1477 | 0 | nMoveY = bShift ? -1 : 1; |
1478 | 0 | break; |
1479 | 0 | case DIR_RIGHT: |
1480 | 0 | nMoveX = bShift ? -1 : 1; |
1481 | 0 | break; |
1482 | 0 | case DIR_TOP: |
1483 | 0 | nMoveY = bShift ? 1 : -1; |
1484 | 0 | break; |
1485 | 0 | case DIR_LEFT: |
1486 | 0 | nMoveX = bShift ? 1 : -1; |
1487 | 0 | break; |
1488 | 0 | } |
1489 | | |
1490 | 0 | SCCOL nCurX; |
1491 | 0 | SCROW nCurY; |
1492 | 0 | aViewData.GetMoveCursor( nCurX,nCurY ); |
1493 | 0 | SCCOL nNewX = nCurX; |
1494 | 0 | SCROW nNewY = nCurY; |
1495 | 0 | SCTAB nTab = aViewData.CurrentTabForData(); |
1496 | |
|
1497 | 0 | ScMarkData& rMark = aViewData.GetMarkData(); |
1498 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
1499 | |
|
1500 | 0 | if (rMark.IsMarked() || rMark.IsMultiMarked()) |
1501 | 0 | { |
1502 | 0 | rDoc.GetNextPos( nNewX, nNewY, nTab, nMoveX, nMoveY, true, false, rMark ); |
1503 | |
|
1504 | 0 | MoveCursorRel( nNewX - nCurX, nNewY - nCurY, SC_FOLLOW_LINE, false, true ); |
1505 | | |
1506 | | // update input line even if cursor was not moved |
1507 | 0 | if ( nNewX == nCurX && nNewY == nCurY ) |
1508 | 0 | aViewData.UpdateInputHandler(true); |
1509 | 0 | } |
1510 | 0 | else |
1511 | 0 | { |
1512 | | // After Tab and Enter back to the starting column again. |
1513 | 0 | const SCCOL nTabStartCol = ((nMoveY != 0 && !nMoveX) ? aViewData.GetTabStartCol() : SC_TABSTART_NONE); |
1514 | 0 | rDoc.GetNextPos( nNewX, nNewY, nTab, nMoveX, nMoveY, false, true, rMark, nTabStartCol ); |
1515 | |
|
1516 | 0 | MoveCursorRel( nNewX - nCurX, nNewY - nCurY, SC_FOLLOW_LINE, false); |
1517 | 0 | } |
1518 | 0 | } |
1519 | | |
1520 | | bool ScTabView::MoveCursorKeyInput( const KeyEvent& rKeyEvent ) |
1521 | 0 | { |
1522 | 0 | const vcl::KeyCode& rKCode = rKeyEvent.GetKeyCode(); |
1523 | |
|
1524 | 0 | enum { MOD_NONE, MOD_CTRL, MOD_ALT, MOD_BOTH } eModifier = |
1525 | 0 | rKCode.IsMod1() ? |
1526 | 0 | (rKCode.IsMod2() ? MOD_BOTH : MOD_CTRL) : |
1527 | 0 | (rKCode.IsMod2() ? MOD_ALT : MOD_NONE); |
1528 | |
|
1529 | 0 | bool bSel = rKCode.IsShift(); |
1530 | 0 | sal_uInt16 nCode = rKCode.GetCode(); |
1531 | | |
1532 | | // CURSOR keys |
1533 | 0 | SCCOL nDX = 0; |
1534 | 0 | SCROW nDY = 0; |
1535 | 0 | switch( nCode ) |
1536 | 0 | { |
1537 | 0 | case KEY_LEFT: nDX = -1; break; |
1538 | 0 | case KEY_RIGHT: nDX = 1; break; |
1539 | 0 | case KEY_UP: nDY = -1; break; |
1540 | 0 | case KEY_DOWN: nDY = 1; break; |
1541 | 0 | } |
1542 | 0 | if( nDX != 0 || nDY != 0 ) |
1543 | 0 | { |
1544 | 0 | switch( eModifier ) |
1545 | 0 | { |
1546 | 0 | case MOD_NONE: MoveCursorRel( nDX, nDY, SC_FOLLOW_LINE, bSel ); break; |
1547 | 0 | case MOD_CTRL: MoveCursorArea( nDX, nDY, SC_FOLLOW_JUMP, bSel ); break; |
1548 | 0 | default: |
1549 | 0 | { |
1550 | | // added to avoid warnings |
1551 | 0 | } |
1552 | 0 | } |
1553 | | // always true to suppress changes of col/row size (ALT+CURSOR) |
1554 | 0 | return true; |
1555 | 0 | } |
1556 | | |
1557 | | // PAGEUP/PAGEDOWN |
1558 | 0 | if( (nCode == KEY_PAGEUP) || (nCode == KEY_PAGEDOWN) ) |
1559 | 0 | { |
1560 | 0 | nDX = (nCode == KEY_PAGEUP) ? -1 : 1; |
1561 | 0 | switch( eModifier ) |
1562 | 0 | { |
1563 | 0 | case MOD_NONE: MoveCursorPage( 0, static_cast<SCCOLROW>(nDX), SC_FOLLOW_FIX, bSel ); break; |
1564 | 0 | case MOD_ALT: MoveCursorPage( nDX, 0, SC_FOLLOW_FIX, bSel ); break; |
1565 | 0 | case MOD_CTRL: SelectNextTab( nDX, false ); break; |
1566 | 0 | default: |
1567 | 0 | { |
1568 | | // added to avoid warnings |
1569 | 0 | } |
1570 | 0 | } |
1571 | 0 | return true; |
1572 | 0 | } |
1573 | | |
1574 | | // HOME/END |
1575 | 0 | if( (nCode == KEY_HOME) || (nCode == KEY_END) ) |
1576 | 0 | { |
1577 | 0 | nDX = (nCode == KEY_HOME) ? -1 : 1; |
1578 | 0 | ScFollowMode eMode = (nCode == KEY_HOME) ? SC_FOLLOW_LINE : SC_FOLLOW_JUMP_END; |
1579 | 0 | switch( eModifier ) |
1580 | 0 | { |
1581 | 0 | case MOD_NONE: MoveCursorEnd( nDX, 0, eMode, bSel ); break; |
1582 | 0 | case MOD_CTRL: MoveCursorEnd( nDX, static_cast<SCCOLROW>(nDX), eMode, bSel ); break; |
1583 | 0 | default: |
1584 | 0 | { |
1585 | | // added to avoid warnings |
1586 | 0 | } |
1587 | 0 | } |
1588 | 0 | return true; |
1589 | 0 | } |
1590 | | |
1591 | 0 | return false; |
1592 | 0 | } |
1593 | | |
1594 | | // next/previous unprotected cell |
1595 | | void ScTabView::FindNextUnprot( bool bShift, bool bInSelection ) |
1596 | 0 | { |
1597 | 0 | short nMove = bShift ? -1 : 1; |
1598 | |
|
1599 | 0 | ScMarkData& rMark = aViewData.GetMarkData(); |
1600 | 0 | bool bMarked = bInSelection && (rMark.IsMarked() || rMark.IsMultiMarked()); |
1601 | |
|
1602 | 0 | SCCOL nCurX; |
1603 | 0 | SCROW nCurY; |
1604 | 0 | aViewData.GetMoveCursor( nCurX,nCurY ); |
1605 | 0 | SCCOL nNewX = nCurX; |
1606 | 0 | SCROW nNewY = nCurY; |
1607 | 0 | SCTAB nTab = aViewData.CurrentTabForData(); |
1608 | |
|
1609 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
1610 | 0 | rDoc.GetNextPos( nNewX,nNewY, nTab, nMove,0, bMarked, true, rMark ); |
1611 | |
|
1612 | 0 | SCCOL nTabCol = aViewData.GetTabStartCol(); |
1613 | 0 | if ( nTabCol == SC_TABSTART_NONE ) |
1614 | 0 | nTabCol = nCurX; // back to this column after Enter |
1615 | |
|
1616 | 0 | MoveCursorRel( nNewX-nCurX, nNewY-nCurY, SC_FOLLOW_LINE, false, true ); |
1617 | | |
1618 | | // TabCol is reset in MoveCursorRel... |
1619 | 0 | aViewData.SetTabStartCol( nTabCol ); |
1620 | 0 | } |
1621 | | |
1622 | | void ScTabView::MarkColumns() |
1623 | 0 | { |
1624 | 0 | SCCOL nStartCol; |
1625 | 0 | SCCOL nEndCol; |
1626 | |
|
1627 | 0 | ScMarkData& rMark = aViewData.GetMarkData(); |
1628 | 0 | if (rMark.IsMarked()) |
1629 | 0 | { |
1630 | 0 | const ScRange& aMarkRange = rMark.GetMarkArea(); |
1631 | 0 | nStartCol = aMarkRange.aStart.Col(); |
1632 | 0 | nEndCol = aMarkRange.aEnd.Col(); |
1633 | 0 | } |
1634 | 0 | else |
1635 | 0 | { |
1636 | 0 | SCROW nDummy; |
1637 | 0 | aViewData.GetMoveCursor( nStartCol, nDummy ); |
1638 | 0 | nEndCol=nStartCol; |
1639 | 0 | } |
1640 | |
|
1641 | 0 | SCTAB nTab = aViewData.CurrentTabForData(); |
1642 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
1643 | 0 | DoneBlockMode(); |
1644 | 0 | InitBlockMode( nStartCol,0, nTab ); |
1645 | 0 | MarkCursor( nEndCol, rDoc.MaxRow(), nTab ); |
1646 | 0 | SelectionChanged(); |
1647 | 0 | } |
1648 | | |
1649 | | void ScTabView::MarkRows() |
1650 | 0 | { |
1651 | 0 | SCROW nStartRow; |
1652 | 0 | SCROW nEndRow; |
1653 | |
|
1654 | 0 | ScMarkData& rMark = aViewData.GetMarkData(); |
1655 | 0 | if (rMark.IsMarked()) |
1656 | 0 | { |
1657 | 0 | const ScRange& aMarkRange = rMark.GetMarkArea(); |
1658 | 0 | nStartRow = aMarkRange.aStart.Row(); |
1659 | 0 | nEndRow = aMarkRange.aEnd.Row(); |
1660 | 0 | } |
1661 | 0 | else |
1662 | 0 | { |
1663 | 0 | SCCOL nDummy; |
1664 | 0 | aViewData.GetMoveCursor( nDummy, nStartRow ); |
1665 | 0 | nEndRow=nStartRow; |
1666 | 0 | } |
1667 | |
|
1668 | 0 | SCTAB nTab = aViewData.CurrentTabForData(); |
1669 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
1670 | 0 | DoneBlockMode(); |
1671 | 0 | InitBlockMode( 0,nStartRow, nTab ); |
1672 | 0 | MarkCursor( rDoc.MaxCol(), nEndRow, nTab ); |
1673 | 0 | SelectionChanged(); |
1674 | 0 | } |
1675 | | |
1676 | | |
1677 | | void ScTabView::MarkColumns(SCCOL nCol, sal_Int16 nModifier) |
1678 | 0 | { |
1679 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
1680 | 0 | SCCOL nStartCol = nCol; |
1681 | 0 | SCTAB nTab = aViewData.CurrentTabForData(); |
1682 | |
|
1683 | 0 | if ((nModifier & KEY_SHIFT) == KEY_SHIFT) |
1684 | 0 | bMoveIsShift = true; |
1685 | |
|
1686 | 0 | if (ScModule::get()->IsFormulaMode()) |
1687 | 0 | { |
1688 | 0 | DoneRefMode( nModifier != 0 ); |
1689 | 0 | InitRefMode( nCol, 0, nTab, SC_REFTYPE_REF ); |
1690 | 0 | UpdateRef( nCol, rDoc.MaxRow(), nTab ); |
1691 | 0 | bMoveIsShift = false; |
1692 | 0 | } |
1693 | 0 | else |
1694 | 0 | { |
1695 | 0 | DoneBlockMode( nModifier != 0 ); |
1696 | 0 | InitBlockMode( nStartCol, 0, nTab, true, true); |
1697 | 0 | MarkCursor( nCol, rDoc.MaxRow(), nTab ); |
1698 | 0 | bMoveIsShift = false; |
1699 | 0 | SetCursor( nCol, 0 ); |
1700 | 0 | SelectionChanged(); |
1701 | 0 | } |
1702 | 0 | } |
1703 | | |
1704 | | void ScTabView::MarkRows(SCROW nRow, sal_Int16 nModifier) |
1705 | 0 | { |
1706 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
1707 | 0 | SCROW nStartRow = nRow; |
1708 | 0 | SCTAB nTab = aViewData.CurrentTabForData(); |
1709 | |
|
1710 | 0 | if ((nModifier & KEY_SHIFT) == KEY_SHIFT) |
1711 | 0 | bMoveIsShift = true; |
1712 | |
|
1713 | 0 | if (ScModule::get()->IsFormulaMode()) |
1714 | 0 | { |
1715 | 0 | DoneRefMode( nModifier != 0 ); |
1716 | 0 | InitRefMode( 0, nRow, nTab, SC_REFTYPE_REF ); |
1717 | 0 | UpdateRef( rDoc.MaxCol(), nRow, nTab ); |
1718 | 0 | bMoveIsShift = false; |
1719 | 0 | } |
1720 | 0 | else |
1721 | 0 | { |
1722 | 0 | DoneBlockMode( nModifier != 0 ); |
1723 | 0 | InitBlockMode( 0, nStartRow, nTab, true, false, true ); |
1724 | 0 | MarkCursor( rDoc.MaxCol(), nRow, nTab ); |
1725 | 0 | bMoveIsShift = false; |
1726 | 0 | SetCursor( 0, nRow ); |
1727 | 0 | SelectionChanged(); |
1728 | 0 | } |
1729 | 0 | } |
1730 | | |
1731 | | void ScTabView::HighlightOverlay() |
1732 | 0 | { |
1733 | 0 | if (!officecfg::Office::Calc::Content::Display::ColumnRowHighlighting::get()) |
1734 | 0 | { |
1735 | 0 | aViewData.GetHighlightData().ResetMark(); |
1736 | 0 | UpdateHighlightOverlay(); |
1737 | 0 | return; |
1738 | 0 | } |
1739 | | |
1740 | 0 | ScAddress aCell = GetViewData().GetCurPos(); |
1741 | 0 | SCROW nRow = aCell.Row(); |
1742 | 0 | SCCOL nCol = aCell.Col(); |
1743 | |
|
1744 | 0 | bool nModifier = false; // modifier key pressed? |
1745 | 0 | DoneBlockModeHighlight( nModifier ); |
1746 | 0 | InitBlockModeHighlight( nCol, 0, aCell.Tab(), true, false); |
1747 | 0 | nModifier = true; |
1748 | 0 | DoneBlockModeHighlight( nModifier ); |
1749 | 0 | InitBlockModeHighlight( 0, nRow, aCell.Tab(), false, true ); |
1750 | 0 | } |
1751 | | |
1752 | | void ScTabView::MarkDataArea( bool bIncludeCursor ) |
1753 | 0 | { |
1754 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
1755 | 0 | SCTAB nTab = aViewData.CurrentTabForData(); |
1756 | 0 | SCCOL nStartCol = aViewData.GetCurX(); |
1757 | 0 | SCROW nStartRow = aViewData.GetCurY(); |
1758 | 0 | SCCOL nEndCol = nStartCol; |
1759 | 0 | SCROW nEndRow = nStartRow; |
1760 | |
|
1761 | 0 | rDoc.GetDataArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow, bIncludeCursor, false ); |
1762 | |
|
1763 | 0 | HideAllCursors(); |
1764 | 0 | DoneBlockMode(); |
1765 | 0 | InitBlockMode( nStartCol, nStartRow, nTab ); |
1766 | 0 | MarkCursor( nEndCol, nEndRow, nTab ); |
1767 | 0 | ShowAllCursors(); |
1768 | |
|
1769 | 0 | SelectionChanged(); |
1770 | 0 | } |
1771 | | |
1772 | | void ScTabView::MarkMatrixFormula() |
1773 | 0 | { |
1774 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
1775 | 0 | ScAddress aCursor( aViewData.GetCurX(), aViewData.GetCurY(), aViewData.CurrentTabForData() ); |
1776 | 0 | ScRange aMatrix; |
1777 | 0 | if ( rDoc.GetMatrixFormulaRange( aCursor, aMatrix ) ) |
1778 | 0 | { |
1779 | 0 | MarkRange( aMatrix, false ); // cursor is already within the range |
1780 | 0 | } |
1781 | 0 | } |
1782 | | |
1783 | | void ScTabView::MarkRange( const ScRange& rRange, bool bSetCursor, bool bContinue ) |
1784 | 0 | { |
1785 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
1786 | 0 | SCTAB nTab = rRange.aStart.Tab(); |
1787 | 0 | SetTabNo( nTab ); |
1788 | |
|
1789 | 0 | HideAllCursors(); |
1790 | 0 | DoneBlockMode( bContinue ); // bContinue==true -> clear old mark |
1791 | 0 | if (bSetCursor) // if Cursor is set, also always align |
1792 | 0 | { |
1793 | 0 | SCCOL nAlignX = rRange.aStart.Col(); |
1794 | 0 | SCROW nAlignY = rRange.aStart.Row(); |
1795 | 0 | bool bCol = ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == rDoc.MaxCol() ) && !aViewData.GetDocument().IsInVBAMode(); |
1796 | 0 | bool bRow = ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == rDoc.MaxRow() ); |
1797 | 0 | if ( bCol ) |
1798 | 0 | nAlignX = aViewData.GetPosX(WhichH(aViewData.GetActivePart())); |
1799 | 0 | if ( bRow ) |
1800 | 0 | nAlignY = aViewData.GetPosY(WhichV(aViewData.GetActivePart())); |
1801 | 0 | AlignToCursor( nAlignX, nAlignY, SC_FOLLOW_JUMP ); |
1802 | 0 | } |
1803 | 0 | InitBlockMode( rRange.aStart.Col(), rRange.aStart.Row(), nTab ); |
1804 | 0 | MarkCursor( rRange.aEnd.Col(), rRange.aEnd.Row(), nTab ); |
1805 | 0 | if (bSetCursor) |
1806 | 0 | { |
1807 | 0 | SCCOL nPosX = rRange.aStart.Col(); |
1808 | 0 | SCROW nPosY = rRange.aStart.Row(); |
1809 | 0 | rDoc.SkipOverlapped(nPosX, nPosY, nTab); |
1810 | |
|
1811 | 0 | aViewData.ResetOldCursor(); |
1812 | 0 | SetCursor( nPosX, nPosY ); |
1813 | 0 | } |
1814 | 0 | ShowAllCursors(); |
1815 | |
|
1816 | 0 | SelectionChanged(); |
1817 | 0 | } |
1818 | | |
1819 | | void ScTabView::Unmark() |
1820 | 0 | { |
1821 | 0 | ScMarkData& rMark = aViewData.GetMarkData(); |
1822 | 0 | if ( rMark.IsMarked() || rMark.IsMultiMarked() ) |
1823 | 0 | { |
1824 | 0 | SCCOL nCurX; |
1825 | 0 | SCROW nCurY; |
1826 | 0 | aViewData.GetMoveCursor( nCurX,nCurY ); |
1827 | 0 | MoveCursorAbs( nCurX, nCurY, SC_FOLLOW_NONE, false, false ); |
1828 | |
|
1829 | 0 | SelectionChanged(); |
1830 | 0 | } |
1831 | 0 | } |
1832 | | |
1833 | | void ScTabView::SetMarkData( const ScMarkData& rNew ) |
1834 | 0 | { |
1835 | 0 | DoneBlockMode(); |
1836 | 0 | InitOwnBlockMode( rNew.GetMarkArea()); |
1837 | 0 | aViewData.GetMarkData() = rNew; |
1838 | |
|
1839 | 0 | MarkDataChanged(); |
1840 | 0 | } |
1841 | | |
1842 | | void ScTabView::MarkDataChanged() |
1843 | 0 | { |
1844 | | // has to be called after making direct changes to mark data (not via MarkCursor etc) |
1845 | |
|
1846 | 0 | UpdateSelectionOverlay(); |
1847 | 0 | } |
1848 | | |
1849 | | void ScTabView::SelectNextTab( short nDir, bool bExtendSelection ) |
1850 | 0 | { |
1851 | 0 | if (!nDir) |
1852 | 0 | return; |
1853 | 0 | OSL_ENSURE( nDir==-1 || nDir==1, "SelectNextTab: invalid value"); |
1854 | |
|
1855 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
1856 | 0 | SCTAB nTab = aViewData.CurrentTabForData(); |
1857 | 0 | SCTAB nNextTab = nTab; |
1858 | 0 | SCTAB nCount = rDoc.GetTableCount(); |
1859 | 0 | if (nDir < 0) |
1860 | 0 | { |
1861 | 0 | do |
1862 | 0 | { |
1863 | 0 | --nNextTab; |
1864 | 0 | if (nNextTab < 0) |
1865 | 0 | { |
1866 | 0 | if (officecfg::Office::Calc::Input::WrapNextPrevSheetTab::get()) |
1867 | 0 | nNextTab = nCount; |
1868 | 0 | else |
1869 | 0 | return; |
1870 | 0 | } |
1871 | 0 | if (rDoc.IsVisible(nNextTab)) |
1872 | 0 | break; |
1873 | 0 | } while (nNextTab != nTab); |
1874 | 0 | } |
1875 | 0 | else // nDir > 0 |
1876 | 0 | { |
1877 | 0 | do |
1878 | 0 | { |
1879 | 0 | ++nNextTab; |
1880 | 0 | if (nNextTab >= nCount) |
1881 | 0 | { |
1882 | 0 | if (officecfg::Office::Calc::Input::WrapNextPrevSheetTab::get()) |
1883 | 0 | nNextTab = 0; |
1884 | 0 | else |
1885 | 0 | return; |
1886 | 0 | } |
1887 | 0 | if (rDoc.IsVisible(nNextTab)) |
1888 | 0 | break; |
1889 | 0 | } while (nNextTab != nTab); |
1890 | 0 | } |
1891 | 0 | if (nNextTab == nTab) |
1892 | 0 | return; |
1893 | | |
1894 | 0 | SetTabNo(nNextTab, false, bExtendSelection); |
1895 | 0 | PaintExtras(); |
1896 | 0 | } |
1897 | | |
1898 | | void ScTabView::SelectTabPage( const sal_uInt16 nTab ) |
1899 | 0 | { |
1900 | 0 | pTabControl->SwitchToPageId( nTab ); |
1901 | 0 | } |
1902 | | |
1903 | | // SetTabNo - set the displayed sheet |
1904 | | |
1905 | | void ScTabView::SetTabNo( SCTAB nTab, bool bNew, bool bExtendSelection, bool bSameTabButMoved ) |
1906 | 0 | { |
1907 | 0 | ScTabViewShell* pViewShell = aViewData.GetViewShell(); |
1908 | 0 | pViewShell->SetTabChangeInProgress(true); |
1909 | |
|
1910 | 0 | if ( !ValidTab(nTab) ) |
1911 | 0 | { |
1912 | 0 | OSL_FAIL("SetTabNo: invalid sheet"); |
1913 | 0 | return; |
1914 | 0 | } |
1915 | | |
1916 | 0 | if (!bNew && nTab == aViewData.CurrentTabForData()) |
1917 | 0 | return; |
1918 | | |
1919 | | // FormShell would like to be informed before the switch |
1920 | 0 | FmFormShell* pFormSh = aViewData.GetViewShell()->GetFormShell(); |
1921 | 0 | if (pFormSh) |
1922 | 0 | { |
1923 | 0 | bool bAllowed = pFormSh->PrepareClose(); |
1924 | 0 | if (!bAllowed) |
1925 | 0 | { |
1926 | | //! error message? or does FormShell do it? |
1927 | | //! return error flag and cancel actions |
1928 | |
|
1929 | 0 | return; // FormShell says that it can not be switched |
1930 | 0 | } |
1931 | 0 | } |
1932 | | |
1933 | | // not InputEnterHandler due to reference input |
1934 | | |
1935 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
1936 | |
|
1937 | 0 | rDoc.MakeTable( nTab ); |
1938 | | |
1939 | | // Update pending row heights before switching the sheet, so Reschedule from the progress bar |
1940 | | // doesn't paint the new sheet with old heights |
1941 | 0 | aViewData.GetDocShell()->UpdatePendingRowHeights( nTab ); |
1942 | |
|
1943 | 0 | SCTAB nTabCount = rDoc.GetTableCount(); |
1944 | 0 | SCTAB nOldPos = nTab; |
1945 | 0 | while (!rDoc.IsVisible(nTab)) // search for next visible |
1946 | 0 | { |
1947 | 0 | bool bUp = (nTab>=nOldPos); |
1948 | 0 | if (bUp) |
1949 | 0 | { |
1950 | 0 | ++nTab; |
1951 | 0 | if (nTab>=nTabCount) |
1952 | 0 | { |
1953 | 0 | nTab = nOldPos; |
1954 | 0 | bUp = false; |
1955 | 0 | } |
1956 | 0 | } |
1957 | |
|
1958 | 0 | if (!bUp) |
1959 | 0 | { |
1960 | 0 | if (nTab != 0) |
1961 | 0 | --nTab; |
1962 | 0 | else |
1963 | 0 | { |
1964 | 0 | OSL_FAIL("no visible sheets"); |
1965 | 0 | rDoc.SetVisible( 0, true ); |
1966 | 0 | } |
1967 | 0 | } |
1968 | 0 | } |
1969 | | |
1970 | | // #i71490# Deselect drawing objects before changing the sheet number in view data, |
1971 | | // so the handling of notes still has the sheet selected on which the notes are. |
1972 | 0 | DrawDeselectAll(); |
1973 | |
|
1974 | 0 | ScModule* pScMod = ScModule::get(); |
1975 | 0 | bool bRefMode = pScMod->IsFormulaMode(); |
1976 | 0 | if ( !bRefMode ) // query, so that RefMode works when switching sheet |
1977 | 0 | { |
1978 | 0 | DoneBlockMode(); |
1979 | 0 | pSelEngine->Reset(); // reset all flags, including locked modifiers |
1980 | 0 | aViewData.SetRefTabNo( nTab ); |
1981 | 0 | } |
1982 | |
|
1983 | 0 | ScSplitPos eOldActive = aViewData.GetActivePart(); // before switching |
1984 | 0 | bool bFocus = pGridWin[eOldActive] && pGridWin[eOldActive]->HasFocus(); |
1985 | |
|
1986 | 0 | aViewData.SetTabNo( nTab ); |
1987 | 0 | if (mpSpellCheckCxt) |
1988 | 0 | mpSpellCheckCxt->setTabNo( nTab ); |
1989 | | // UpdateShow before SetCursor, so that UpdateAutoFillMark finds the correct |
1990 | | // window (is called from SetCursor) |
1991 | 0 | UpdateShow(); |
1992 | 0 | aViewData.GetView()->TestHintWindow(); |
1993 | |
|
1994 | 0 | SfxBindings& rBindings = aViewData.GetBindings(); |
1995 | 0 | ScMarkData& rMark = aViewData.GetMarkData(); |
1996 | |
|
1997 | 0 | bool bAllSelected = true; |
1998 | 0 | for (SCTAB nSelTab = 0; nSelTab < nTabCount; ++nSelTab) |
1999 | 0 | { |
2000 | 0 | if (!rDoc.IsVisible(nSelTab) || rMark.GetTableSelect(nSelTab)) |
2001 | 0 | { |
2002 | 0 | if (nTab == nSelTab) |
2003 | | // This tab is already in selection. Keep the current |
2004 | | // selection. |
2005 | 0 | bExtendSelection = true; |
2006 | 0 | } |
2007 | 0 | else |
2008 | 0 | { |
2009 | 0 | bAllSelected = false; |
2010 | 0 | if (bExtendSelection) |
2011 | | // We got what we need. No need to stay in the loop. |
2012 | 0 | break; |
2013 | 0 | } |
2014 | 0 | } |
2015 | 0 | if (bAllSelected && !bNew) |
2016 | | // #i6327# if all tables are selected, a selection event (#i6330#) will deselect all |
2017 | | // (not if called with bNew to update settings) |
2018 | 0 | bExtendSelection = false; |
2019 | |
|
2020 | 0 | if (bExtendSelection) |
2021 | 0 | rMark.SelectTable( nTab, true ); |
2022 | 0 | else |
2023 | 0 | { |
2024 | 0 | rMark.SelectOneTable( nTab ); |
2025 | 0 | rBindings.Invalidate( FID_FILL_TAB ); |
2026 | 0 | rBindings.Invalidate( FID_TAB_DESELECTALL ); |
2027 | 0 | } |
2028 | |
|
2029 | 0 | bool bUnoRefDialog = pScMod->IsRefDialogOpen() && pScMod->GetCurRefDlgId() == WID_SIMPLE_REF; |
2030 | | |
2031 | | // recalc zoom-dependent values (before TabChanged, before UpdateEditViewPos) |
2032 | 0 | RefreshZoom(/*bRecalcScale*/false); // no need to call RecalcScale() here, because we will do it in TabChanged() |
2033 | 0 | UpdateVarZoom(); |
2034 | |
|
2035 | 0 | if ( bRefMode ) // hide EditView if necessary (after aViewData.SetTabNo !) |
2036 | 0 | { |
2037 | 0 | for (VclPtr<ScGridWindow> & pWin : pGridWin) |
2038 | 0 | { |
2039 | 0 | if (pWin && pWin->IsVisible()) |
2040 | 0 | pWin->UpdateEditViewPos(); |
2041 | 0 | } |
2042 | 0 | } |
2043 | |
|
2044 | 0 | TabChanged(bSameTabButMoved); // DrawView |
2045 | 0 | collectUIInformation({{"TABLE", OUString::number(nTab)}}); |
2046 | 0 | UpdateVisibleRange(); |
2047 | |
|
2048 | 0 | aViewData.GetViewShell()->WindowChanged(); // if the active window has changed |
2049 | 0 | aViewData.ResetOldCursor(); |
2050 | 0 | SetCursor( aViewData.GetCurX(), aViewData.GetCurY(), true ); |
2051 | |
|
2052 | 0 | if ( !bUnoRefDialog ) |
2053 | 0 | aViewData.GetViewShell()->DisconnectAllClients(); // important for floating frames |
2054 | 0 | else |
2055 | 0 | { |
2056 | | // hide / show inplace client |
2057 | 0 | ScClient* pClient = static_cast<ScClient*>(aViewData.GetViewShell()->GetIPClient()); |
2058 | 0 | if ( pClient && pClient->IsObjectInPlaceActive() ) |
2059 | 0 | { |
2060 | 0 | tools::Rectangle aObjArea = pClient->GetObjArea(); |
2061 | 0 | if ( nTab == aViewData.GetRefTabNo() ) |
2062 | 0 | { |
2063 | | // move to its original position |
2064 | |
|
2065 | 0 | SdrOle2Obj* pDrawObj = pClient->GetDrawObj(); |
2066 | 0 | if ( pDrawObj ) |
2067 | 0 | { |
2068 | 0 | tools::Rectangle aRect = pDrawObj->GetLogicRect(); |
2069 | 0 | MapMode aMapMode( MapUnit::Map100thMM ); |
2070 | 0 | Size aOleSize = pDrawObj->GetOrigObjSize( &aMapMode ); |
2071 | 0 | aRect.SetSize( aOleSize ); |
2072 | 0 | aObjArea = aRect; |
2073 | 0 | } |
2074 | 0 | } |
2075 | 0 | else |
2076 | 0 | { |
2077 | | // move to an invisible position |
2078 | |
|
2079 | 0 | aObjArea.SetPos( Point( 0, -2*aObjArea.GetHeight() ) ); |
2080 | 0 | } |
2081 | 0 | pClient->SetObjArea( aObjArea ); |
2082 | 0 | } |
2083 | 0 | } |
2084 | |
|
2085 | 0 | if ( bFocus && aViewData.GetActivePart() != eOldActive && !bRefMode ) |
2086 | 0 | ActiveGrabFocus(); // grab focus to the pane that's active now |
2087 | | |
2088 | | // freeze |
2089 | |
|
2090 | 0 | bool bResize = false; |
2091 | 0 | if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX ) |
2092 | 0 | if (aViewData.UpdateFixX()) |
2093 | 0 | bResize = true; |
2094 | 0 | if ( aViewData.GetVSplitMode() == SC_SPLIT_FIX ) |
2095 | 0 | if (aViewData.UpdateFixY()) |
2096 | 0 | bResize = true; |
2097 | 0 | if (bResize) |
2098 | 0 | RepeatResize(); |
2099 | 0 | InvalidateSplit(); |
2100 | |
|
2101 | 0 | if ( aViewData.IsPagebreakMode() ) |
2102 | 0 | UpdatePageBreakData(); //! asynchronously ?? |
2103 | | |
2104 | | // Form Layer must know the visible area of the new sheet |
2105 | | // that is why MapMode must already be correct here |
2106 | 0 | SyncGridWindowMapModeFromDrawMapMode(); |
2107 | 0 | SetNewVisArea(); |
2108 | | |
2109 | | // disable invalidations for kit during tab switching |
2110 | 0 | { |
2111 | 0 | SfxLokCallbackInterface* pCallback = pViewShell->getLibreOfficeKitViewCallback(); |
2112 | 0 | pViewShell->setLibreOfficeKitViewCallback(nullptr); |
2113 | 0 | comphelper::ScopeGuard aOutputGuard( |
2114 | 0 | [pViewShell, pCallback] { |
2115 | 0 | pViewShell->setLibreOfficeKitViewCallback(pCallback); |
2116 | 0 | }); |
2117 | 0 | PaintGrid(); |
2118 | 0 | } |
2119 | |
|
2120 | 0 | PaintTop(); |
2121 | 0 | PaintLeft(); |
2122 | 0 | PaintExtras(); |
2123 | |
|
2124 | 0 | DoResize( aBorderPos, aFrameSize ); |
2125 | 0 | rBindings.Invalidate( SID_DELETE_PRINTAREA ); // Menu |
2126 | 0 | rBindings.Invalidate( FID_DEL_MANUALBREAKS ); |
2127 | 0 | rBindings.Invalidate( FID_RESET_PRINTZOOM ); |
2128 | 0 | rBindings.Invalidate( SID_STATUS_DOCPOS ); // Status bar |
2129 | 0 | rBindings.Invalidate( SID_ROWCOL_SELCOUNT ); // Status bar |
2130 | 0 | rBindings.Invalidate( SID_STATUS_PAGESTYLE ); // Status bar |
2131 | 0 | rBindings.Invalidate( SID_CURRENTTAB ); // Navigator |
2132 | 0 | rBindings.Invalidate( SID_STYLE_FAMILY2 ); // Designer |
2133 | 0 | rBindings.Invalidate( SID_STYLE_FAMILY4 ); // Designer |
2134 | 0 | rBindings.Invalidate( SID_TABLES_COUNT ); |
2135 | |
|
2136 | 0 | rBindings.Invalidate(FID_CURRENT_SHEET_VIEW); |
2137 | |
|
2138 | 0 | if (pScMod->IsRefDialogOpen()) |
2139 | 0 | { |
2140 | 0 | sal_uInt16 nCurRefDlgId=pScMod->GetCurRefDlgId(); |
2141 | 0 | SfxViewFrame& rViewFrm = aViewData.GetViewShell()->GetViewFrame(); |
2142 | 0 | SfxChildWindow* pChildWnd = rViewFrm.GetChildWindow( nCurRefDlgId ); |
2143 | 0 | if (pChildWnd) |
2144 | 0 | { |
2145 | 0 | if (pChildWnd->GetController()) |
2146 | 0 | { |
2147 | 0 | IAnyRefDialog* pRefDlg = dynamic_cast<IAnyRefDialog*>(pChildWnd->GetController().get()); |
2148 | 0 | if (pRefDlg) |
2149 | 0 | pRefDlg->ViewShellChanged(); |
2150 | 0 | } |
2151 | 0 | } |
2152 | 0 | } |
2153 | |
|
2154 | 0 | OnLibreOfficeKitTabChanged(); |
2155 | 0 | pViewShell->SetTabChangeInProgress(false); |
2156 | 0 | } |
2157 | | |
2158 | | void ScTabView::AddWindowToForeignEditView(SfxViewShell* pViewShell, ScSplitPos eWhich) |
2159 | 0 | { |
2160 | 0 | aExtraEditViewManager.Add(pViewShell, eWhich); |
2161 | 0 | } |
2162 | | |
2163 | | void ScTabView::RemoveWindowFromForeignEditView(SfxViewShell* pViewShell, ScSplitPos eWhich) |
2164 | 0 | { |
2165 | 0 | aExtraEditViewManager.Remove(pViewShell, eWhich); |
2166 | 0 | } |
2167 | | |
2168 | | void ScTabView::OnLibreOfficeKitTabChanged() |
2169 | 0 | { |
2170 | 0 | if (!comphelper::LibreOfficeKit::isActive()) |
2171 | 0 | return; |
2172 | | |
2173 | 0 | ScTabViewShell* pThisViewShell = aViewData.GetViewShell(); |
2174 | 0 | SCTAB nThisTabNo = pThisViewShell->GetViewData().CurrentTabForData(); |
2175 | 0 | auto lTabSwitch = [pThisViewShell, nThisTabNo] (ScTabViewShell* pOtherViewShell) |
2176 | 0 | { |
2177 | 0 | ScViewData& rOtherViewData = pOtherViewShell->GetViewData(); |
2178 | 0 | SCTAB nOtherTabNo = rOtherViewData.CurrentTabForData(); |
2179 | 0 | if (nThisTabNo == nOtherTabNo) |
2180 | 0 | { |
2181 | 0 | for (int i = 0; i < 4; ++i) |
2182 | 0 | { |
2183 | 0 | if (rOtherViewData.HasEditView(ScSplitPos(i))) |
2184 | 0 | { |
2185 | 0 | pThisViewShell->AddWindowToForeignEditView(pOtherViewShell, ScSplitPos(i)); |
2186 | 0 | } |
2187 | 0 | } |
2188 | 0 | } |
2189 | 0 | else |
2190 | 0 | { |
2191 | 0 | for (int i = 0; i < 4; ++i) |
2192 | 0 | { |
2193 | 0 | if (rOtherViewData.HasEditView(ScSplitPos(i))) |
2194 | 0 | { |
2195 | 0 | pThisViewShell->RemoveWindowFromForeignEditView(pOtherViewShell, ScSplitPos(i)); |
2196 | 0 | } |
2197 | 0 | } |
2198 | 0 | } |
2199 | 0 | }; |
2200 | |
|
2201 | 0 | SfxLokHelper::forEachOtherView(pThisViewShell, lTabSwitch); |
2202 | |
|
2203 | 0 | pThisViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_INVALIDATE_HEADER, "all"_ostr); |
2204 | |
|
2205 | 0 | if (pThisViewShell->GetInputHandler()) |
2206 | 0 | pThisViewShell->GetInputHandler()->UpdateLokReferenceMarks(); |
2207 | 0 | } |
2208 | | |
2209 | | // TextEditOverlayObject for TextOnOverlay TextEdit. It directly |
2210 | | // implements needed EditViewCallbacks and also hosts the |
2211 | | // OverlaySelection |
2212 | | namespace |
2213 | | { |
2214 | | class ScTextEditOverlayObject : public sdr::overlay::OverlayObject, public EditViewCallbacks |
2215 | | { |
2216 | | // the ScTabView the TextEdit is running at and the ScSplitPos to |
2217 | | // identify the associated data |
2218 | | ScTabView& mrScTabView; |
2219 | | ScSplitPos maScSplitPos; |
2220 | | |
2221 | | // this separate OverlayObject holds and creates the selection |
2222 | | // visualization, so it can be changed/refreshed without changing |
2223 | | // the Text or TextEditBackground |
2224 | | std::unique_ptr<sdr::overlay::OverlaySelection> mxOverlayTransparentSelection; |
2225 | | |
2226 | | // geometry creation for OverlayObject, in this case the extraction |
2227 | | // of edited Text from the setup EditEngine |
2228 | | virtual drawinglayer::primitive2d::Primitive2DContainer createOverlayObjectPrimitive2DSequence() override; |
2229 | | |
2230 | | // EditView overrides |
2231 | | virtual void EditViewInvalidate(const tools::Rectangle& rRect) override; |
2232 | | virtual void EditViewSelectionChange() override; |
2233 | | virtual OutputDevice& EditViewOutputDevice() const override; |
2234 | | virtual Point EditViewPointerPosPixel() const override; |
2235 | | virtual css::uno::Reference<css::datatransfer::clipboard::XClipboard> GetClipboard() const override; |
2236 | | virtual css::uno::Reference<css::datatransfer::dnd::XDropTarget> GetDropTarget() override; |
2237 | | virtual void EditViewInputContext(const InputContext& rInputContext) override; |
2238 | | virtual void EditViewCursorRect(const tools::Rectangle& rRect, int nExtTextInputWidth) override; |
2239 | | |
2240 | | public: |
2241 | | // create using system selection color & ScTabView |
2242 | | ScTextEditOverlayObject( |
2243 | | const Color& rColor, |
2244 | | ScTabView& rScTabView, |
2245 | | ScSplitPos aScSplitPos); |
2246 | | virtual ~ScTextEditOverlayObject() override; |
2247 | | |
2248 | | // override to mix in TextEditBackground and the Text transformed |
2249 | | // as needed |
2250 | | virtual drawinglayer::primitive2d::Primitive2DContainer getOverlayObjectPrimitive2DSequence() const override; |
2251 | | |
2252 | | // access to OverlaySelection to add to OverlayManager |
2253 | | sdr::overlay::OverlayObject* getOverlaySelection() |
2254 | 0 | { |
2255 | 0 | return mxOverlayTransparentSelection.get(); |
2256 | 0 | } |
2257 | | |
2258 | | void RefeshTextEditOverlay() |
2259 | 0 | { |
2260 | | // currently just deletes all created stuff, this may |
2261 | | // be fine-tuned later if needed |
2262 | 0 | objectChange(); |
2263 | 0 | } |
2264 | | }; |
2265 | | |
2266 | | ScTextEditOverlayObject::ScTextEditOverlayObject( |
2267 | | const Color& rColor, |
2268 | | ScTabView& rScTabView, |
2269 | | ScSplitPos aScSplitPos) |
2270 | 0 | : OverlayObject(rColor) |
2271 | 0 | , mrScTabView(rScTabView) |
2272 | 0 | , maScSplitPos(aScSplitPos) |
2273 | 0 | { |
2274 | | // no AA for TextEdit overlay |
2275 | 0 | allowAntiAliase(false); |
2276 | | |
2277 | | // establish EditViewCallbacks |
2278 | 0 | const ScViewData& rScViewData(mrScTabView.GetViewData()); |
2279 | 0 | EditView* pEditView(rScViewData.GetEditView(maScSplitPos)); |
2280 | 0 | DBG_ASSERT(nullptr != pEditView, "NO access to EditView in ScTextEditOverlayObject!"); |
2281 | 0 | pEditView->setEditViewCallbacks(this); |
2282 | | |
2283 | | // initialize empty OverlaySelection |
2284 | 0 | std::vector<basegfx::B2DRange> aEmptySelection{}; |
2285 | 0 | mxOverlayTransparentSelection.reset(new sdr::overlay::OverlaySelection( |
2286 | 0 | sdr::overlay::OverlayType::Transparent, rColor, std::move(aEmptySelection), true)); |
2287 | 0 | } |
2288 | | |
2289 | | ScTextEditOverlayObject::~ScTextEditOverlayObject() |
2290 | 0 | { |
2291 | | // delete OverlaySelection - this will also remove itself from |
2292 | | // OverlayManager already |
2293 | 0 | mxOverlayTransparentSelection.reset(); |
2294 | | |
2295 | | // shutdown EditViewCallbacks |
2296 | 0 | const ScViewData& rScViewData(mrScTabView.GetViewData()); |
2297 | 0 | EditView* pEditView(rScViewData.GetEditView(maScSplitPos)); |
2298 | 0 | DBG_ASSERT(nullptr != pEditView, "NO access to EditView in ScTextEditOverlayObject!"); |
2299 | 0 | pEditView->setEditViewCallbacks(nullptr); |
2300 | | |
2301 | | // remove myself |
2302 | 0 | if (getOverlayManager()) |
2303 | 0 | getOverlayManager()->remove(*this); |
2304 | 0 | } |
2305 | | |
2306 | | drawinglayer::primitive2d::Primitive2DContainer ScTextEditOverlayObject::createOverlayObjectPrimitive2DSequence() |
2307 | 0 | { |
2308 | | // extract primitive representation from active EditEngine |
2309 | 0 | drawinglayer::primitive2d::Primitive2DContainer aRetval; |
2310 | |
|
2311 | 0 | ScViewData& rScViewData(mrScTabView.GetViewData()); |
2312 | 0 | const EditView* pEditView(rScViewData.GetEditView(maScSplitPos)); |
2313 | 0 | assert(pEditView && "NO access to EditView in ScTextEditOverlayObject!"); |
2314 | | |
2315 | | // get text data in LogicMode |
2316 | 0 | OutputDevice& rOutDev(pEditView->GetOutputDevice()); |
2317 | 0 | const MapMode aOrig(rOutDev.GetMapMode()); |
2318 | 0 | rOutDev.SetMapMode(rScViewData.GetLogicMode()); |
2319 | | |
2320 | | // StripPortions from EditEngine. |
2321 | | // use no transformations. The result will be in logic coordinates |
2322 | | // based on aEditRectangle and the EditEngine setup, see |
2323 | | // ScViewData::SetEditEngine |
2324 | 0 | TextHierarchyBreakup aBreakup; |
2325 | 0 | pEditView->getEditEngine().StripPortions(aBreakup); |
2326 | 0 | aRetval = aBreakup.getTextPortionPrimitives(); |
2327 | |
|
2328 | 0 | rOutDev.SetMapMode(aOrig); |
2329 | 0 | return aRetval; |
2330 | 0 | } |
2331 | | |
2332 | | void ScTextEditOverlayObject::EditViewInvalidate(const tools::Rectangle& rRect) |
2333 | 0 | { |
2334 | 0 | if (comphelper::LibreOfficeKit::isActive()) |
2335 | 0 | { |
2336 | | // UT testPageDownInvalidation from CppunitTest_sc_tiledrendering |
2337 | | // *needs* the direct invalidates formerly done in |
2338 | | // EditView::InvalidateWindow when no EditViewCallbacks are set |
2339 | 0 | ScGridWindow* pActiveWin(static_cast<ScGridWindow*>(mrScTabView.GetWindowByPos(maScSplitPos))); |
2340 | 0 | pActiveWin->Invalidate(rRect); |
2341 | 0 | } |
2342 | |
|
2343 | 0 | RefeshTextEditOverlay(); |
2344 | 0 | } |
2345 | | |
2346 | | void ScTextEditOverlayObject::EditViewSelectionChange() |
2347 | 0 | { |
2348 | 0 | ScViewData& rScViewData(mrScTabView.GetViewData()); |
2349 | 0 | EditView* pEditView(rScViewData.GetEditView(maScSplitPos)); |
2350 | 0 | assert(pEditView && "NO access to EditView in ScTextEditOverlayObject!"); |
2351 | | |
2352 | | // get the selection rectangles |
2353 | 0 | std::vector<tools::Rectangle> aRects; |
2354 | 0 | pEditView->GetSelectionRectangles(aRects); |
2355 | 0 | std::vector<basegfx::B2DRange> aLogicRanges; |
2356 | |
|
2357 | 0 | if (aRects.empty()) |
2358 | 0 | { |
2359 | | // if none, reset selection at OverlayObject and we are done |
2360 | 0 | mxOverlayTransparentSelection->setRanges(std::move(aLogicRanges)); |
2361 | 0 | return; |
2362 | 0 | } |
2363 | | |
2364 | | // create needed transformations |
2365 | | // LogicMode -> DiscreteViewCoordinates (Pixels) |
2366 | 0 | basegfx::B2DHomMatrix aTransformToPixels; |
2367 | 0 | OutputDevice& rOutDev(pEditView->GetOutputDevice()); |
2368 | 0 | const MapMode aOrig(rOutDev.GetMapMode()); |
2369 | 0 | rOutDev.SetMapMode(rScViewData.GetLogicMode()); |
2370 | 0 | aTransformToPixels = rOutDev.GetViewTransformation(); |
2371 | | |
2372 | | // DiscreteViewCoordinates (Pixels) -> LogicDrawCoordinates |
2373 | 0 | basegfx::B2DHomMatrix aTransformToDrawCoordinates; |
2374 | 0 | ScGridWindow* pActiveWin(static_cast<ScGridWindow*>(mrScTabView.GetWindowByPos(maScSplitPos))); |
2375 | 0 | rOutDev.SetMapMode(pActiveWin->GetDrawMapMode()); |
2376 | 0 | aTransformToDrawCoordinates = rOutDev.GetInverseViewTransformation(); |
2377 | 0 | rOutDev.SetMapMode(aOrig); |
2378 | |
|
2379 | 0 | for (const auto& aRect : aRects) |
2380 | 0 | { |
2381 | 0 | basegfx::B2DRange aRange(aRect.Left(), aRect.Top(), aRect.Right(), aRect.Bottom()); |
2382 | | |
2383 | | // range to pixels |
2384 | 0 | aRange.transform(aTransformToPixels); |
2385 | | |
2386 | | // grow by 1px for slight distance/overlap |
2387 | 0 | aRange.grow(1.0); |
2388 | | |
2389 | | // to drawinglayer coordinates & add |
2390 | 0 | aRange.transform(aTransformToDrawCoordinates); |
2391 | 0 | aLogicRanges.emplace_back(aRange); |
2392 | 0 | } |
2393 | |
|
2394 | 0 | mxOverlayTransparentSelection->setRanges(std::move(aLogicRanges)); |
2395 | 0 | } |
2396 | | |
2397 | | OutputDevice& ScTextEditOverlayObject::EditViewOutputDevice() const |
2398 | 0 | { |
2399 | 0 | ScGridWindow* pActiveWin(static_cast<ScGridWindow*>(mrScTabView.GetWindowByPos(maScSplitPos))); |
2400 | 0 | return *pActiveWin->GetOutDev(); |
2401 | 0 | } |
2402 | | |
2403 | | Point ScTextEditOverlayObject::EditViewPointerPosPixel() const |
2404 | 0 | { |
2405 | 0 | ScGridWindow* pActiveWin(static_cast<ScGridWindow*>(mrScTabView.GetWindowByPos(maScSplitPos))); |
2406 | 0 | return pActiveWin->GetPointerPosPixel(); |
2407 | 0 | } |
2408 | | |
2409 | | css::uno::Reference<css::datatransfer::clipboard::XClipboard> ScTextEditOverlayObject::GetClipboard() const |
2410 | 0 | { |
2411 | 0 | ScGridWindow* pActiveWin(static_cast<ScGridWindow*>(mrScTabView.GetWindowByPos(maScSplitPos))); |
2412 | 0 | return pActiveWin->GetClipboard(); |
2413 | 0 | } |
2414 | | |
2415 | | css::uno::Reference<css::datatransfer::dnd::XDropTarget> ScTextEditOverlayObject::GetDropTarget() |
2416 | 0 | { |
2417 | 0 | ScGridWindow* pActiveWin(static_cast<ScGridWindow*>(mrScTabView.GetWindowByPos(maScSplitPos))); |
2418 | 0 | return pActiveWin->GetDropTarget(); |
2419 | 0 | } |
2420 | | |
2421 | | void ScTextEditOverlayObject::EditViewInputContext(const InputContext& rInputContext) |
2422 | 0 | { |
2423 | 0 | ScGridWindow* pActiveWin(static_cast<ScGridWindow*>(mrScTabView.GetWindowByPos(maScSplitPos))); |
2424 | 0 | pActiveWin->SetInputContext(rInputContext); |
2425 | 0 | } |
2426 | | |
2427 | | void ScTextEditOverlayObject::EditViewCursorRect(const tools::Rectangle& rRect, int nExtTextInputWidth) |
2428 | 0 | { |
2429 | 0 | ScGridWindow* pActiveWin(static_cast<ScGridWindow*>(mrScTabView.GetWindowByPos(maScSplitPos))); |
2430 | 0 | pActiveWin->SetCursorRect(&rRect, nExtTextInputWidth); |
2431 | 0 | } |
2432 | | |
2433 | | drawinglayer::primitive2d::Primitive2DContainer ScTextEditOverlayObject::getOverlayObjectPrimitive2DSequence() const |
2434 | 0 | { |
2435 | 0 | drawinglayer::primitive2d::Primitive2DContainer aRetval; |
2436 | | |
2437 | |
|
2438 | 0 | ScViewData& rScViewData(mrScTabView.GetViewData()); |
2439 | 0 | EditView* pEditView(rScViewData.GetEditView(maScSplitPos)); |
2440 | 0 | assert(pEditView && "NO access to EditView in ScTextEditOverlayObject!"); |
2441 | | |
2442 | | // call base implementation to get TextPrimitives in logic coordinates |
2443 | | // directly from the setup EditEngine |
2444 | 0 | drawinglayer::primitive2d::Primitive2DContainer aText( |
2445 | 0 | OverlayObject::getOverlayObjectPrimitive2DSequence()); |
2446 | |
|
2447 | 0 | if (aText.empty()) |
2448 | | // no Text, done, return result |
2449 | 0 | return aRetval; |
2450 | | |
2451 | | // remember MapMode and restore at exit - we do not want |
2452 | | // to change it outside this method |
2453 | 0 | OutputDevice& rOutDev(pEditView->GetOutputDevice()); |
2454 | 0 | const MapMode aOrig(rOutDev.GetMapMode()); |
2455 | | |
2456 | | // create text edit background based on pixel coordinates |
2457 | | // of involved Cells and append |
2458 | 0 | { |
2459 | 0 | const SCCOL nCol1(rScViewData.GetEditStartCol()); |
2460 | 0 | const SCROW nRow1(rScViewData.GetEditStartRow()); |
2461 | 0 | const SCCOL nCol2(rScViewData.GetEditEndCol()); |
2462 | 0 | const SCROW nRow2(rScViewData.GetEditEndRow()); |
2463 | 0 | const Point aStart(rScViewData.GetScrPos(nCol1, nRow1, maScSplitPos)); |
2464 | 0 | const Point aEnd(rScViewData.GetScrPos(nCol2+1, nRow2+1, maScSplitPos)); |
2465 | |
|
2466 | 0 | if (aStart != aEnd) |
2467 | 0 | { |
2468 | | // create outline polygon. Shrink by 1px due to working |
2469 | | // with pixel positions one cell right and below. We are |
2470 | | // in discrete (pixel) coordinates with start/end here, |
2471 | | // so just subtract '1' from x and y to do that |
2472 | 0 | basegfx::B2DPolyPolygon aOutline(basegfx::utils::createPolygonFromRect( |
2473 | 0 | basegfx::B2DRange( |
2474 | 0 | aStart.X(), aStart.Y(), |
2475 | 0 | aEnd.X() - 1, aEnd.Y() - 1))); |
2476 | | |
2477 | | // transform from Pixels to LogicDrawCoordinates |
2478 | 0 | ScGridWindow* pActiveWin(static_cast<ScGridWindow*>(mrScTabView.GetWindowByPos(maScSplitPos))); |
2479 | 0 | rOutDev.SetMapMode(pActiveWin->GetDrawMapMode()); |
2480 | 0 | aOutline.transform(rOutDev.GetInverseViewTransformation()); |
2481 | |
|
2482 | 0 | aRetval.push_back( |
2483 | 0 | rtl::Reference<drawinglayer::primitive2d::PolyPolygonColorPrimitive2D>( |
2484 | 0 | new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D( |
2485 | 0 | std::move(aOutline), |
2486 | 0 | pEditView->GetBackgroundColor().getBColor()))); |
2487 | 0 | } |
2488 | 0 | } |
2489 | | |
2490 | | // create embedding transformation for Text itself and |
2491 | | // append Text |
2492 | 0 | { |
2493 | 0 | basegfx::B2DHomMatrix aTransform; |
2494 | | |
2495 | | // transform by TextPaint StartPosition (Top-Left). This corresponds |
2496 | | // to aEditRectangle and the EditEngine setup, see |
2497 | | // ScViewData::SetEditEngine. Offset is in LogicCoordinates/LogicMode |
2498 | 0 | const Point aStartPosition(pEditView->CalculateTextPaintStartPosition()); |
2499 | 0 | aTransform.translate(aStartPosition.X(), aStartPosition.Y()); |
2500 | | |
2501 | | // LogicMode -> DiscreteViewCoordinates (Pixels) |
2502 | 0 | rOutDev.SetMapMode(rScViewData.GetLogicMode()); |
2503 | 0 | aTransform *= rOutDev.GetViewTransformation(); |
2504 | | |
2505 | | // DiscreteViewCoordinates (Pixels) -> LogicDrawCoordinates |
2506 | 0 | ScGridWindow* pActiveWin(static_cast<ScGridWindow*>(mrScTabView.GetWindowByPos(maScSplitPos))); |
2507 | 0 | rOutDev.SetMapMode(pActiveWin->GetDrawMapMode()); |
2508 | 0 | aTransform *= rOutDev.GetInverseViewTransformation(); |
2509 | | |
2510 | | // add text embedded to created transformation |
2511 | 0 | aRetval.push_back(rtl::Reference<drawinglayer::primitive2d::TransformPrimitive2D>( |
2512 | 0 | new drawinglayer::primitive2d::TransformPrimitive2D( |
2513 | 0 | aTransform, std::move(aText)))); |
2514 | 0 | } |
2515 | |
|
2516 | 0 | rOutDev.SetMapMode(aOrig); |
2517 | 0 | return aRetval; |
2518 | 0 | } |
2519 | | } // end of anonymous namespace |
2520 | | |
2521 | | void ScTabView::RefeshTextEditOverlay() |
2522 | 0 | { |
2523 | | // find the ScTextEditOverlayObject in the OverlayGroup and |
2524 | | // call refresh there. It is also possible to have separate |
2525 | | // holders of that data, so no find/identification would be |
2526 | | // needed, but having all associated OverlayObjects in one |
2527 | | // group makes handling simple(r). It may also be that the |
2528 | | // cursor visualization will be added to that group later |
2529 | 0 | for (sal_uInt32 a(0); a < maTextEditOverlayGroup.count(); a++) |
2530 | 0 | { |
2531 | 0 | sdr::overlay::OverlayObject& rOverlayObject(maTextEditOverlayGroup.getOverlayObject(a)); |
2532 | 0 | ScTextEditOverlayObject* pScTextEditOverlayObject(dynamic_cast<ScTextEditOverlayObject*>(&rOverlayObject)); |
2533 | |
|
2534 | 0 | if (nullptr != pScTextEditOverlayObject) |
2535 | 0 | { |
2536 | 0 | pScTextEditOverlayObject->RefeshTextEditOverlay(); |
2537 | 0 | } |
2538 | 0 | } |
2539 | 0 | } |
2540 | | |
2541 | | void ScTabView::MakeEditView( ScEditEngineDefaulter& rEngine, SCCOL nCol, SCROW nRow ) |
2542 | 0 | { |
2543 | 0 | DrawDeselectAll(); |
2544 | |
|
2545 | 0 | if (pDrawView) |
2546 | 0 | DrawEnableAnim( false ); |
2547 | |
|
2548 | 0 | EditView* pSpellingView = aViewData.GetSpellingView(); |
2549 | |
|
2550 | 0 | for (sal_uInt16 i = 0; i < 4; i++) |
2551 | 0 | { |
2552 | 0 | if (pGridWin[i] && pGridWin[i]->IsVisible() && !aViewData.HasEditView(ScSplitPos(i))) |
2553 | 0 | { |
2554 | 0 | const ScSplitPos aScSplitPos(static_cast<ScSplitPos>(i)); |
2555 | 0 | ScHSplitPos eHWhich = WhichH(aScSplitPos); |
2556 | 0 | ScVSplitPos eVWhich = WhichV(aScSplitPos); |
2557 | 0 | SCCOL nScrX = aViewData.GetPosX( eHWhich ); |
2558 | 0 | SCROW nScrY = aViewData.GetPosY( eVWhich ); |
2559 | |
|
2560 | 0 | bool bPosVisible = |
2561 | 0 | ( nCol >= nScrX && nCol <= nScrX + aViewData.VisibleCellsX(eHWhich) - 1 && |
2562 | 0 | nRow >= nScrY && nRow <= nScrY + aViewData.VisibleCellsY(eVWhich) - 1 ); |
2563 | | |
2564 | | // for the active part, create edit view even if outside the visible area, |
2565 | | // so input isn't lost (and the edit view may be scrolled into the visible area) |
2566 | | |
2567 | | // #i26433# during spelling, the spelling view must be active |
2568 | 0 | if ( bPosVisible || aViewData.GetActivePart() == aScSplitPos || |
2569 | 0 | ( pSpellingView && aViewData.GetEditView(aScSplitPos) == pSpellingView ) ) |
2570 | 0 | { |
2571 | 0 | VclPtr<ScGridWindow> pScGridWindow(pGridWin[aScSplitPos]); |
2572 | 0 | pScGridWindow->HideCursor(); |
2573 | 0 | pScGridWindow->DeleteCursorOverlay(); |
2574 | 0 | pScGridWindow->DeleteAutoFillOverlay(); |
2575 | 0 | pScGridWindow->DeleteCopySourceOverlay(); |
2576 | | |
2577 | | // MapMode must be set after HideCursor |
2578 | 0 | pScGridWindow->SetMapMode(aViewData.GetLogicMode()); |
2579 | |
|
2580 | 0 | if ( !bPosVisible ) |
2581 | 0 | { |
2582 | | // move the edit view area to the real (possibly negative) position, |
2583 | | // or hide if completely above or left of the window |
2584 | 0 | pScGridWindow->UpdateEditViewPos(); |
2585 | 0 | } |
2586 | |
|
2587 | 0 | aViewData.SetEditEngine(aScSplitPos, rEngine, pScGridWindow, nCol, |
2588 | 0 | nRow); |
2589 | | |
2590 | | // get OverlayManager and initialize TextEditOnOverlay for it |
2591 | 0 | rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = pScGridWindow->getOverlayManager(); |
2592 | |
|
2593 | 0 | if (xOverlayManager.is() && aViewData.HasEditView(aScSplitPos)) |
2594 | 0 | { |
2595 | 0 | const Color aHilightColor(SvtOptionsDrawinglayer::getHilightColor()); |
2596 | 0 | std::unique_ptr<ScTextEditOverlayObject> pNewScTextEditOverlayObject( |
2597 | 0 | new ScTextEditOverlayObject( |
2598 | 0 | aHilightColor, |
2599 | 0 | *this, |
2600 | 0 | aScSplitPos)); |
2601 | | |
2602 | | // add TextEditOverlayObject and the OverlaySelection hosted by it |
2603 | | // to the OverlayManager (to make visible) and to the local |
2604 | | // reference TextEditOverlayGroup (to access if needed) |
2605 | 0 | xOverlayManager->add(*pNewScTextEditOverlayObject); |
2606 | 0 | xOverlayManager->add(*pNewScTextEditOverlayObject->getOverlaySelection()); |
2607 | 0 | maTextEditOverlayGroup.append(std::move(pNewScTextEditOverlayObject)); |
2608 | 0 | } |
2609 | 0 | } |
2610 | 0 | } |
2611 | 0 | } |
2612 | |
|
2613 | 0 | if (aViewData.GetViewShell()->HasAccessibilityObjects()) |
2614 | 0 | aViewData.GetViewShell()->BroadcastAccessibility(SfxHint(SfxHintId::ScAccEnterEditMode)); |
2615 | 0 | } |
2616 | | |
2617 | | void ScTabView::UpdateEditView() |
2618 | 0 | { |
2619 | 0 | if (aViewData.CurrentTabForData() != aViewData.GetRefTabNo() && ScModule::get()->IsFormulaMode()) |
2620 | 0 | return; |
2621 | | |
2622 | 0 | ScSplitPos eActive = aViewData.GetActivePart(); |
2623 | 0 | for (sal_uInt16 i = 0; i < 4; i++) |
2624 | 0 | { |
2625 | 0 | ScSplitPos eCurrent = ScSplitPos(i); |
2626 | 0 | if (aViewData.HasEditView(eCurrent)) |
2627 | 0 | { |
2628 | 0 | EditView* pEditView = aViewData.GetEditView(eCurrent); |
2629 | |
|
2630 | 0 | tools::Long nRefTabNo = GetViewData().GetRefTabNo(); |
2631 | 0 | tools::Long nX = GetViewData().GetCurXForTab(nRefTabNo); |
2632 | 0 | tools::Long nY = GetViewData().GetCurYForTab(nRefTabNo); |
2633 | |
|
2634 | 0 | aViewData.SetEditEngine(eCurrent, |
2635 | 0 | static_cast<ScEditEngineDefaulter&>(pEditView->getEditEngine()), |
2636 | 0 | pGridWin[i], nX, nY ); |
2637 | 0 | if (eCurrent == eActive) |
2638 | 0 | pEditView->ShowCursor( false ); |
2639 | 0 | } |
2640 | 0 | } |
2641 | |
|
2642 | 0 | RefeshTextEditOverlay(); |
2643 | 0 | } |
2644 | | |
2645 | | void ScTabView::KillEditView( bool bNoPaint ) |
2646 | 0 | { |
2647 | 0 | SCCOL nCol1 = aViewData.GetEditStartCol(); |
2648 | 0 | SCROW nRow1 = aViewData.GetEditStartRow(); |
2649 | 0 | SCCOL nCol2 = aViewData.GetEditEndCol(); |
2650 | 0 | SCROW nRow2 = aViewData.GetEditEndRow(); |
2651 | 0 | SCTAB nTab = aViewData.CurrentTabForData(); |
2652 | 0 | bool bPaint[4]; |
2653 | 0 | bool bNotifyAcc = false; |
2654 | 0 | tools::Rectangle aRectangle[4]; |
2655 | |
|
2656 | 0 | bool bExtended = nRow1 != nRow2; // column is painted to the end anyway |
2657 | |
|
2658 | 0 | bool bAtCursor = nCol1 <= aViewData.GetCurX() && |
2659 | 0 | nCol2 >= aViewData.GetCurX() && |
2660 | 0 | nRow1 == aViewData.GetCurY(); |
2661 | 0 | for (sal_uInt16 i = 0; i < 4; i++) |
2662 | 0 | { |
2663 | 0 | bPaint[i] = aViewData.HasEditView( static_cast<ScSplitPos>(i) ); |
2664 | 0 | if (bPaint[i]) |
2665 | 0 | { |
2666 | 0 | bNotifyAcc = true; |
2667 | |
|
2668 | 0 | EditView* pView = aViewData.GetEditView( static_cast<ScSplitPos>(i) ); |
2669 | 0 | aRectangle[i] = pView->GetInvalidateRect(); |
2670 | 0 | } |
2671 | 0 | } |
2672 | | |
2673 | | // this cleans up all used OverlayObjects for TextEdit, they get deleted |
2674 | | // and removed from the OverlayManager what makes them optically disappear |
2675 | 0 | maTextEditOverlayGroup.clear(); |
2676 | | |
2677 | | // notify accessibility before all things happen |
2678 | 0 | if (bNotifyAcc && aViewData.GetViewShell()->HasAccessibilityObjects()) |
2679 | 0 | aViewData.GetViewShell()->BroadcastAccessibility(SfxHint(SfxHintId::ScAccLeaveEditMode)); |
2680 | |
|
2681 | 0 | aViewData.ResetEditView(); |
2682 | 0 | for (sal_uInt16 i = 0; i < 4; i++) |
2683 | 0 | { |
2684 | 0 | if (pGridWin[i] && bPaint[i] && pGridWin[i]->IsVisible()) |
2685 | 0 | { |
2686 | 0 | pGridWin[i]->ShowCursor(); |
2687 | |
|
2688 | 0 | pGridWin[i]->SetMapMode(pGridWin[i]->GetDrawMapMode()); |
2689 | |
|
2690 | 0 | const tools::Rectangle& rInvRect = aRectangle[i]; |
2691 | |
|
2692 | 0 | if (comphelper::LibreOfficeKit::isActive()) |
2693 | 0 | { |
2694 | 0 | pGridWin[i]->LogicInvalidatePart(&rInvRect, nTab); |
2695 | | |
2696 | | // invalidate other views |
2697 | 0 | auto lInvalidateWindows = |
2698 | 0 | [nTab, &rInvRect] (ScTabView* pTabView) |
2699 | 0 | { |
2700 | 0 | for (VclPtr<ScGridWindow> const & pWin: pTabView->pGridWin) |
2701 | 0 | { |
2702 | 0 | if (pWin) |
2703 | 0 | pWin->LogicInvalidatePart(&rInvRect, nTab); |
2704 | 0 | } |
2705 | 0 | }; |
2706 | |
|
2707 | 0 | SfxLokHelper::forEachOtherView(GetViewData().GetViewShell(), lInvalidateWindows); |
2708 | 0 | } |
2709 | | // #i73567# the cell still has to be repainted |
2710 | 0 | else |
2711 | 0 | { |
2712 | 0 | const bool bDoPaint = bExtended || (bAtCursor && !bNoPaint); |
2713 | 0 | const bool bDoInvalidate = !bDoPaint && bAtCursor; |
2714 | 0 | if (bDoPaint) |
2715 | 0 | { |
2716 | 0 | pGridWin[i]->Draw( nCol1, nRow1, nCol2, nRow2, ScUpdateMode::All ); |
2717 | 0 | pGridWin[i]->UpdateSelectionOverlay(); |
2718 | 0 | } |
2719 | 0 | else if (bDoInvalidate) |
2720 | 0 | { |
2721 | | // tdf#162651 even if !bNoPaint is set, and there will be a |
2722 | | // follow up Draw of the next content, the area blanked out |
2723 | | // by the editview which is being removed still needs to be |
2724 | | // invalidated. The follow-up Draw of the content may be |
2725 | | // optimized to only redraw the area of cells where content |
2726 | | // has changed and will be unaware of what bounds this |
2727 | | // editview grew to during its editing cycle. |
2728 | 0 | pGridWin[i]->Invalidate(rInvRect); |
2729 | 0 | } |
2730 | 0 | } |
2731 | 0 | } |
2732 | 0 | } |
2733 | |
|
2734 | 0 | if (pDrawView) |
2735 | 0 | DrawEnableAnim( true ); |
2736 | | |
2737 | | // GrabFocus always when this View is active and |
2738 | | // when the input row has the focus |
2739 | |
|
2740 | 0 | bool bGrabFocus = false; |
2741 | 0 | if (aViewData.IsActive()) |
2742 | 0 | { |
2743 | 0 | ScInputHandler* pInputHdl = ScModule::get()->GetInputHdl(); |
2744 | 0 | if ( pInputHdl ) |
2745 | 0 | { |
2746 | 0 | ScInputWindow* pInputWin = pInputHdl->GetInputWindow(); |
2747 | 0 | if (pInputWin && pInputWin->IsInputActive()) |
2748 | 0 | bGrabFocus = true; |
2749 | 0 | } |
2750 | 0 | } |
2751 | |
|
2752 | 0 | if (bGrabFocus) |
2753 | 0 | { |
2754 | | // should be done like this, so that Sfx notice it, but it does not work: |
2755 | | //! aViewData.CurrentTabForData()->GetViewFrame().GetWindow().GrabFocus(); |
2756 | | // therefore first like this: |
2757 | 0 | GetActiveWin()->GrabFocus(); |
2758 | 0 | } |
2759 | | |
2760 | | // cursor query only after GrabFocus |
2761 | |
|
2762 | 0 | for (sal_uInt16 i = 0; i < 4; i++) |
2763 | 0 | { |
2764 | 0 | if (pGridWin[i] && pGridWin[i]->IsVisible()) |
2765 | 0 | { |
2766 | 0 | vcl::Cursor* pCur = pGridWin[i]->GetCursor(); |
2767 | 0 | if (pCur && pCur->IsVisible()) |
2768 | 0 | pCur->Hide(); |
2769 | |
|
2770 | 0 | if (bPaint[i]) |
2771 | 0 | { |
2772 | 0 | pGridWin[i]->UpdateCursorOverlay(); |
2773 | 0 | pGridWin[i]->UpdateAutoFillOverlay(); |
2774 | 0 | } |
2775 | 0 | } |
2776 | 0 | } |
2777 | 0 | } |
2778 | | |
2779 | | void ScTabView::UpdateFormulas(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow) |
2780 | 0 | { |
2781 | 0 | if ( aViewData.GetDocument().IsAutoCalcShellDisabled() ) |
2782 | 0 | return; |
2783 | | |
2784 | 0 | for (sal_uInt16 i = 0; i < 4; i++) |
2785 | 0 | { |
2786 | 0 | if (pGridWin[i] && pGridWin[i]->IsVisible()) |
2787 | 0 | pGridWin[i]->UpdateFormulas(nStartCol, nStartRow, nEndCol, nEndRow); |
2788 | 0 | } |
2789 | |
|
2790 | 0 | if ( aViewData.IsPagebreakMode() ) |
2791 | 0 | UpdatePageBreakData(); //! asynchronous |
2792 | |
|
2793 | 0 | bool bIsTiledRendering = comphelper::LibreOfficeKit::isActive(); |
2794 | | // UpdateHeaderWidth can fit the GridWindow widths to the frame, something |
2795 | | // we don't want in kit-mode where we try and match the GridWindow width |
2796 | | // to the tiled area separately |
2797 | 0 | if (!bIsTiledRendering) |
2798 | 0 | UpdateHeaderWidth(); |
2799 | | |
2800 | | // if in edit mode, adjust edit view area because widths/heights may have changed |
2801 | 0 | if ( aViewData.HasEditView( aViewData.GetActivePart() ) ) |
2802 | 0 | UpdateEditView(); |
2803 | 0 | } |
2804 | | |
2805 | | // PaintArea - repaint block |
2806 | | |
2807 | | void ScTabView::PaintArea( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, |
2808 | | ScUpdateMode eMode, tools::Long nMaxWidthAffectedHintTwip ) |
2809 | 0 | { |
2810 | 0 | SCCOL nCol1; |
2811 | 0 | SCROW nRow1; |
2812 | 0 | SCCOL nCol2; |
2813 | 0 | SCROW nRow2; |
2814 | 0 | bool bIsTiledRendering = comphelper::LibreOfficeKit::isActive(); |
2815 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
2816 | |
|
2817 | 0 | PutInOrder( nStartCol, nEndCol ); |
2818 | 0 | PutInOrder( nStartRow, nEndRow ); |
2819 | |
|
2820 | 0 | for (size_t i = 0; i < 4; ++i) |
2821 | 0 | { |
2822 | 0 | if (!pGridWin[i] || !pGridWin[i]->IsVisible()) |
2823 | 0 | continue; |
2824 | | |
2825 | 0 | ScHSplitPos eHWhich = WhichH( static_cast<ScSplitPos>(i) ); |
2826 | 0 | ScVSplitPos eVWhich = WhichV( static_cast<ScSplitPos>(i) ); |
2827 | 0 | bool bOut = false; |
2828 | |
|
2829 | 0 | nCol1 = nStartCol; |
2830 | 0 | nRow1 = nStartRow; |
2831 | 0 | nCol2 = nEndCol; |
2832 | 0 | nRow2 = nEndRow; |
2833 | |
|
2834 | 0 | SCCOL nLastX = 0; |
2835 | 0 | SCROW nLastY = 0; |
2836 | |
|
2837 | 0 | if (bIsTiledRendering) |
2838 | 0 | { |
2839 | 0 | nLastX = aViewData.GetMaxTiledCol(); |
2840 | 0 | nLastY = aViewData.GetMaxTiledRow(); |
2841 | 0 | } |
2842 | 0 | else |
2843 | 0 | { |
2844 | |
|
2845 | 0 | SCCOL nScrX = aViewData.GetPosX( eHWhich ); |
2846 | 0 | SCROW nScrY = aViewData.GetPosY( eVWhich ); |
2847 | |
|
2848 | 0 | if (nCol1 < nScrX) |
2849 | 0 | nCol1 = nScrX; |
2850 | 0 | if (nCol2 < nScrX) |
2851 | 0 | { |
2852 | 0 | if ( eMode == ScUpdateMode::All ) // for UPDATE_ALL, paint anyway |
2853 | 0 | nCol2 = nScrX; // (because of extending strings to the right) |
2854 | 0 | else |
2855 | 0 | bOut = true; // completely outside the window |
2856 | 0 | } |
2857 | 0 | if (nRow1 < nScrY) |
2858 | 0 | nRow1 = nScrY; |
2859 | 0 | if (nRow2 < nScrY) |
2860 | 0 | bOut = true; |
2861 | |
|
2862 | 0 | nLastX = nScrX + aViewData.VisibleCellsX( eHWhich ) + 1; |
2863 | 0 | nLastY = nScrY + aViewData.VisibleCellsY( eVWhich ) + 1; |
2864 | 0 | } |
2865 | |
|
2866 | 0 | if (nCol1 > nLastX) |
2867 | 0 | bOut = true; |
2868 | 0 | if (nCol2 > nLastX) |
2869 | 0 | nCol2 = nLastX; |
2870 | 0 | if (nRow1 > nLastY) |
2871 | 0 | bOut = true; |
2872 | 0 | if (nRow2 > nLastY) |
2873 | 0 | nRow2 = nLastY; |
2874 | |
|
2875 | 0 | if (bOut) |
2876 | 0 | continue; |
2877 | | |
2878 | 0 | bool bLayoutRTL = aViewData.GetDocument().IsLayoutRTL( aViewData.CurrentTabForData() ); |
2879 | 0 | tools::Long nLayoutSign = (!bIsTiledRendering && bLayoutRTL) ? -1 : 1; |
2880 | |
|
2881 | 0 | Point aStart = aViewData.GetScrPos( nCol1, nRow1, static_cast<ScSplitPos>(i) ); |
2882 | 0 | Point aEnd = aViewData.GetScrPos( nCol2+1, nRow2+1, static_cast<ScSplitPos>(i) ); |
2883 | |
|
2884 | 0 | if ( eMode == ScUpdateMode::All ) |
2885 | 0 | { |
2886 | 0 | if (nMaxWidthAffectedHintTwip != -1) |
2887 | 0 | { |
2888 | 0 | tools::Long nMaxWidthAffectedHint = ScViewData::ToPixel(nMaxWidthAffectedHintTwip, aViewData.GetPPTX()); |
2889 | | |
2890 | | // If we know the max text width affected then just invalidate |
2891 | | // the max of the cell width and hint of affected cell width |
2892 | | // (where affected with is in terms of max width of optimal cell |
2893 | | // width for before/after change) |
2894 | 0 | tools::Long nCellWidth = std::abs(aEnd.X() - aStart.X()); |
2895 | 0 | aEnd.setX(aStart.getX() + std::max(nCellWidth, nMaxWidthAffectedHint) * nLayoutSign); |
2896 | 0 | } |
2897 | 0 | else |
2898 | 0 | { |
2899 | 0 | if (bIsTiledRendering) |
2900 | 0 | { |
2901 | | // When a cell content is deleted we have no clue about |
2902 | | // the width of the embedded text. |
2903 | | // Anyway, clients will ask only for tiles that overlaps |
2904 | | // the visible area. |
2905 | | // Remember that wsd expects int and that aEnd.X() is |
2906 | | // in pixels and will be converted in twips, before performing |
2907 | | // the lok callback, so we need to avoid that an overflow occurs. |
2908 | 0 | aEnd.setX( std::numeric_limits<int>::max() / 1000 ); |
2909 | 0 | } |
2910 | 0 | else |
2911 | 0 | { |
2912 | 0 | aEnd.setX( bLayoutRTL ? 0 : pGridWin[i]->GetOutputSizePixel().Width() ); |
2913 | 0 | } |
2914 | 0 | } |
2915 | 0 | } |
2916 | 0 | aEnd.AdjustX( -nLayoutSign ); |
2917 | 0 | aEnd.AdjustY( -1 ); |
2918 | | |
2919 | | // #i85232# include area below cells (could be done in GetScrPos?) |
2920 | 0 | if ( eMode == ScUpdateMode::All && nRow2 >= rDoc.MaxRow() && !bIsTiledRendering ) |
2921 | 0 | aEnd.setY( pGridWin[i]->GetOutputSizePixel().Height() ); |
2922 | |
|
2923 | 0 | aStart.AdjustX( -nLayoutSign ); // include change marks |
2924 | 0 | aStart.AdjustY( -1 ); |
2925 | |
|
2926 | 0 | bool bMarkClipped = ScModule::get()->GetColorConfig().GetColorValue(svtools::CALCTEXTOVERFLOW).bIsVisible; |
2927 | 0 | if (bMarkClipped) |
2928 | 0 | { |
2929 | | // ScColumn::IsEmptyData has to be optimized for this |
2930 | | // (switch to Search() ) |
2931 | | //!if ( nCol1 > 0 && !aViewData.GetDocument()->IsBlockEmpty( |
2932 | | //! 0, nRow1, nCol1-1, nRow2. |
2933 | | //! aViewData.CurrentTabForData() ) ) |
2934 | 0 | tools::Long nMarkPixel = static_cast<tools::Long>( SC_CLIPMARK_SIZE * aViewData.GetPPTX() ); |
2935 | 0 | aStart.AdjustX( -(nMarkPixel * nLayoutSign) ); |
2936 | 0 | } |
2937 | |
|
2938 | 0 | pGridWin[i]->Invalidate( pGridWin[i]->PixelToLogic( tools::Rectangle( aStart,aEnd ) ) ); |
2939 | 0 | } |
2940 | | |
2941 | | // #i79909# Calling UpdateAllOverlays here isn't necessary and would lead to overlay calls from a timer, |
2942 | | // with a wrong MapMode if editing in a cell (reference input). |
2943 | | // #i80499# Overlays need updates in a lot of cases, e.g. changing row/column size, |
2944 | | // or showing/hiding outlines. TODO: selections in inactive windows are vanishing. |
2945 | | // #i84689# With relative conditional formats, PaintArea may be called often (for each changed cell), |
2946 | | // so UpdateAllOverlays was moved to ScTabViewShell::Notify and is called only if PaintPartFlags::Left/PaintPartFlags::Top |
2947 | | // is set (width or height changed). |
2948 | 0 | } |
2949 | | |
2950 | | void ScTabView::PaintRangeFinderEntry (const ScRangeFindData* pData, const SCTAB nTab) |
2951 | 0 | { |
2952 | 0 | ScRange aRef = pData->aRef; |
2953 | 0 | aRef.PutInOrder(); // PutInOrder for the queries below |
2954 | |
|
2955 | 0 | if ( aRef.aStart == aRef.aEnd ) //! ignore sheet? |
2956 | 0 | aViewData.GetDocument().ExtendMerge(aRef); |
2957 | |
|
2958 | 0 | if (aRef.aStart.Tab() < nTab || aRef.aEnd.Tab() > nTab) |
2959 | 0 | return; |
2960 | | |
2961 | 0 | SCCOL nCol1 = aRef.aStart.Col(); |
2962 | 0 | SCROW nRow1 = aRef.aStart.Row(); |
2963 | 0 | SCCOL nCol2 = aRef.aEnd.Col(); |
2964 | 0 | SCROW nRow2 = aRef.aEnd.Row(); |
2965 | | |
2966 | | // remove -> repaint |
2967 | | // ScUpdateMode::Marks: Invalidate, nothing until end of row |
2968 | |
|
2969 | 0 | bool bHiddenEdge = false; |
2970 | 0 | SCROW nTmp; |
2971 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
2972 | 0 | while ( nCol1 > 0 && rDoc.ColHidden(nCol1, nTab) ) |
2973 | 0 | { |
2974 | 0 | --nCol1; |
2975 | 0 | bHiddenEdge = true; |
2976 | 0 | } |
2977 | 0 | while ( nCol2 < rDoc.MaxCol() && rDoc.ColHidden(nCol2, nTab) ) |
2978 | 0 | { |
2979 | 0 | ++nCol2; |
2980 | 0 | bHiddenEdge = true; |
2981 | 0 | } |
2982 | 0 | nTmp = rDoc.LastVisibleRow(0, nRow1, nTab); |
2983 | 0 | if (!rDoc.ValidRow(nTmp)) |
2984 | 0 | nTmp = 0; |
2985 | 0 | if (nTmp < nRow1) |
2986 | 0 | { |
2987 | 0 | nRow1 = nTmp; |
2988 | 0 | bHiddenEdge = true; |
2989 | 0 | } |
2990 | 0 | nTmp = rDoc.FirstVisibleRow(nRow2, rDoc.MaxRow(), nTab); |
2991 | 0 | if (!rDoc.ValidRow(nTmp)) |
2992 | 0 | nTmp = rDoc.MaxRow(); |
2993 | 0 | if (nTmp > nRow2) |
2994 | 0 | { |
2995 | 0 | nRow2 = nTmp; |
2996 | 0 | bHiddenEdge = true; |
2997 | 0 | } |
2998 | |
|
2999 | 0 | if ( nCol2 - nCol1 > 1 && nRow2 - nRow1 > 1 && !bHiddenEdge ) |
3000 | 0 | { |
3001 | | // only along the edges |
3002 | 0 | PaintArea( nCol1, nRow1, nCol2, nRow1, ScUpdateMode::Marks ); |
3003 | 0 | PaintArea( nCol1, nRow1+1, nCol1, nRow2-1, ScUpdateMode::Marks ); |
3004 | 0 | PaintArea( nCol2, nRow1+1, nCol2, nRow2-1, ScUpdateMode::Marks ); |
3005 | 0 | PaintArea( nCol1, nRow2, nCol2, nRow2, ScUpdateMode::Marks ); |
3006 | 0 | } |
3007 | 0 | else // all in one |
3008 | 0 | PaintArea( nCol1, nRow1, nCol2, nRow2, ScUpdateMode::Marks ); |
3009 | 0 | } |
3010 | | |
3011 | | void ScTabView::PaintRangeFinder( tools::Long nNumber ) |
3012 | 0 | { |
3013 | 0 | ScInputHandler* pHdl = ScModule::get()->GetInputHdl(aViewData.GetViewShell()); |
3014 | 0 | if (!pHdl) |
3015 | 0 | return; |
3016 | | |
3017 | 0 | ScRangeFindList* pRangeFinder = pHdl->GetRangeFindList(); |
3018 | 0 | if ( !(pRangeFinder && pRangeFinder->GetDocName() == aViewData.GetDocShell()->GetTitle()) ) |
3019 | 0 | return; |
3020 | | |
3021 | 0 | SCTAB nTab = aViewData.CurrentTabForData(); |
3022 | 0 | sal_uInt16 nCount = static_cast<sal_uInt16>(pRangeFinder->Count()); |
3023 | |
|
3024 | 0 | if (nNumber < 0) |
3025 | 0 | { |
3026 | 0 | for (sal_uInt16 i=0; i<nCount; i++) |
3027 | 0 | PaintRangeFinderEntry(&pRangeFinder->GetObject(i),nTab); |
3028 | 0 | } |
3029 | 0 | else |
3030 | 0 | { |
3031 | 0 | sal_uInt16 idx = nNumber; |
3032 | 0 | if (idx < nCount) |
3033 | 0 | PaintRangeFinderEntry(&pRangeFinder->GetObject(idx),nTab); |
3034 | 0 | } |
3035 | 0 | } |
3036 | | |
3037 | | // for chart data selection |
3038 | | |
3039 | | void ScTabView::AddHighlightRange( const ScRange& rRange, const Color& rColor ) |
3040 | 0 | { |
3041 | 0 | maHighlightRanges.emplace_back( rRange, rColor ); |
3042 | |
|
3043 | 0 | SCTAB nTab = aViewData.CurrentTabForData(); |
3044 | 0 | if ( nTab >= rRange.aStart.Tab() && nTab <= rRange.aEnd.Tab() ) |
3045 | 0 | PaintArea( rRange.aStart.Col(), rRange.aStart.Row(), |
3046 | 0 | rRange.aEnd.Col(), rRange.aEnd.Row(), ScUpdateMode::Marks ); |
3047 | 0 | } |
3048 | | |
3049 | | void ScTabView::ClearHighlightRanges() |
3050 | 0 | { |
3051 | 0 | SCTAB nTab = aViewData.CurrentTabForData(); |
3052 | 0 | for (ScHighlightEntry const & rEntry : maHighlightRanges) |
3053 | 0 | { |
3054 | 0 | ScRange aRange = rEntry.aRef; |
3055 | 0 | if ( nTab >= aRange.aStart.Tab() && nTab <= aRange.aEnd.Tab() ) |
3056 | 0 | PaintArea( aRange.aStart.Col(), aRange.aStart.Row(), |
3057 | 0 | aRange.aEnd.Col(), aRange.aEnd.Row(), ScUpdateMode::Marks ); |
3058 | 0 | } |
3059 | |
|
3060 | 0 | maHighlightRanges.clear(); |
3061 | 0 | } |
3062 | | |
3063 | | void ScTabView::DoChartSelection( |
3064 | | const uno::Sequence< chart2::data::HighlightedRange > & rHilightRanges ) |
3065 | 0 | { |
3066 | 0 | ClearHighlightRanges(); |
3067 | 0 | const sal_Unicode sep = ::formula::FormulaCompiler::GetNativeSymbolChar(ocSep); |
3068 | 0 | size_t nSize = 0; |
3069 | 0 | size_t nIndex = 0; |
3070 | 0 | std::vector<ReferenceMark> aReferenceMarks( nSize ); |
3071 | |
|
3072 | 0 | for (chart2::data::HighlightedRange const & rHighlightedRange : rHilightRanges) |
3073 | 0 | { |
3074 | 0 | Color aSelColor(ColorTransparency, rHighlightedRange.PreferredColor); |
3075 | 0 | ScRangeList aRangeList; |
3076 | 0 | ScDocument& rDoc = aViewData.GetDocShell()->GetDocument(); |
3077 | 0 | if( ScRangeStringConverter::GetRangeListFromString( |
3078 | 0 | aRangeList, rHighlightedRange.RangeRepresentation, rDoc, rDoc.GetAddressConvention(), sep )) |
3079 | 0 | { |
3080 | 0 | size_t nListSize = aRangeList.size(); |
3081 | 0 | nSize += nListSize; |
3082 | 0 | aReferenceMarks.resize(nSize); |
3083 | |
|
3084 | 0 | for ( size_t j = 0; j < nListSize; ++j ) |
3085 | 0 | { |
3086 | 0 | ScRange& p = aRangeList[j]; |
3087 | 0 | ScRange aTargetRange; |
3088 | 0 | if( rHighlightedRange.Index == - 1 ) |
3089 | 0 | { |
3090 | 0 | aTargetRange = p; |
3091 | 0 | AddHighlightRange( aTargetRange, aSelColor ); |
3092 | 0 | } |
3093 | 0 | else |
3094 | 0 | { |
3095 | 0 | aTargetRange = lcl_getSubRangeByIndex( p, rHighlightedRange.Index ); |
3096 | 0 | AddHighlightRange( aTargetRange, aSelColor ); |
3097 | 0 | } |
3098 | |
|
3099 | 0 | if ( comphelper::LibreOfficeKit::isActive() && aViewData.GetViewShell() ) |
3100 | 0 | { |
3101 | 0 | aTargetRange.PutInOrder(); |
3102 | |
|
3103 | 0 | tools::Long nX1 = aTargetRange.aStart.Col(); |
3104 | 0 | tools::Long nX2 = aTargetRange.aEnd.Col(); |
3105 | 0 | tools::Long nY1 = aTargetRange.aStart.Row(); |
3106 | 0 | tools::Long nY2 = aTargetRange.aEnd.Row(); |
3107 | 0 | tools::Long nTab = aTargetRange.aStart.Tab(); |
3108 | |
|
3109 | 0 | aReferenceMarks[nIndex++] = ScInputHandler::GetReferenceMark( aViewData, *aViewData.GetDocShell(), |
3110 | 0 | nX1, nX2, nY1, nY2, |
3111 | 0 | nTab, aSelColor ); |
3112 | 0 | } |
3113 | 0 | } |
3114 | 0 | } |
3115 | 0 | } |
3116 | |
|
3117 | 0 | if ( comphelper::LibreOfficeKit::isActive() && aViewData.GetViewShell() ) |
3118 | 0 | ScInputHandler::SendReferenceMarks( aViewData.GetViewShell(), aReferenceMarks ); |
3119 | 0 | } |
3120 | | |
3121 | | void ScTabView::DoDPFieldPopup(std::u16string_view rPivotTableName, sal_Int32 nDimensionIndex, Point aPoint, Size aSize) |
3122 | 0 | { |
3123 | 0 | ScDocument& rDocument = aViewData.GetDocShell()->GetDocument(); |
3124 | 0 | ScGridWindow* pWin = pGridWin[aViewData.GetActivePart()].get(); |
3125 | |
|
3126 | 0 | if (!pWin) |
3127 | 0 | return; |
3128 | | |
3129 | 0 | ScDPCollection* pDPCollection = rDocument.GetDPCollection(); |
3130 | 0 | ScDPObject* pDPObject = pDPCollection->GetByName(rPivotTableName); |
3131 | 0 | if (!pDPObject) |
3132 | 0 | return; |
3133 | | |
3134 | 0 | pDPObject->BuildAllDimensionMembers(); |
3135 | |
|
3136 | 0 | Point aPos = pWin->LogicToPixel(aPoint); |
3137 | 0 | bool bLOK = comphelper::LibreOfficeKit::isActive(); |
3138 | 0 | Point aScreenPoint = bLOK ? aPos : pWin->OutputToScreenPixel(aPos); |
3139 | 0 | Size aScreenSize = pWin->LogicToPixel(aSize); |
3140 | |
|
3141 | 0 | pWin->DPLaunchFieldPopupMenu(aScreenPoint, aScreenSize, nDimensionIndex, pDPObject); |
3142 | 0 | } |
3143 | | |
3144 | | // PaintGrid - repaint data range |
3145 | | |
3146 | | void ScTabView::PaintGrid() |
3147 | 0 | { |
3148 | 0 | for (sal_uInt16 i = 0; i < 4; i++) |
3149 | 0 | { |
3150 | 0 | if (pGridWin[i] && pGridWin[i]->IsVisible()) |
3151 | 0 | pGridWin[i]->Invalidate(); |
3152 | 0 | } |
3153 | 0 | } |
3154 | | |
3155 | | // PaintTop - repaint top control elements |
3156 | | |
3157 | | void ScTabView::PaintTop() |
3158 | 0 | { |
3159 | 0 | for (sal_uInt16 i = 0; i < 2; i++) |
3160 | 0 | { |
3161 | 0 | if (pColBar[i]) |
3162 | 0 | pColBar[i]->Invalidate(); |
3163 | 0 | if (pColOutline[i]) |
3164 | 0 | pColOutline[i]->Invalidate(); |
3165 | 0 | } |
3166 | 0 | } |
3167 | | |
3168 | | void ScTabView::CreateAnchorHandles(SdrHdlList& rHdl, const ScAddress& rAddress) |
3169 | 0 | { |
3170 | 0 | for (sal_uInt16 i = 0; i < 4; i++) |
3171 | 0 | { |
3172 | 0 | if(pGridWin[i] && pGridWin[i]->IsVisible()) |
3173 | 0 | pGridWin[i]->CreateAnchorHandle(rHdl, rAddress); |
3174 | 0 | } |
3175 | 0 | } |
3176 | | |
3177 | | void ScTabView::PaintTopArea( SCCOL nStartCol, SCCOL nEndCol ) |
3178 | 0 | { |
3179 | | // pixel position of the left edge |
3180 | |
|
3181 | 0 | if ( nStartCol < aViewData.GetPosX(SC_SPLIT_LEFT) || |
3182 | 0 | nStartCol < aViewData.GetPosX(SC_SPLIT_RIGHT) ) |
3183 | 0 | aViewData.RecalcPixPos(); |
3184 | | |
3185 | | // adjust freeze (UpdateFixX resets HSplitPos) |
3186 | |
|
3187 | 0 | if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX && nStartCol < aViewData.GetFixPosX() ) |
3188 | 0 | if (aViewData.UpdateFixX()) |
3189 | 0 | RepeatResize(); |
3190 | | |
3191 | | // paint |
3192 | |
|
3193 | 0 | if (nStartCol>0) |
3194 | 0 | --nStartCol; //! general ? |
3195 | |
|
3196 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
3197 | 0 | bool bLayoutRTL = rDoc.IsLayoutRTL( aViewData.CurrentTabForData() ); |
3198 | 0 | tools::Long nLayoutSign = bLayoutRTL ? -1 : 1; |
3199 | |
|
3200 | 0 | for (sal_uInt16 i = 0; i < 2; i++) |
3201 | 0 | { |
3202 | 0 | ScHSplitPos eWhich = ScHSplitPos(i); |
3203 | 0 | if (pColBar[eWhich]) |
3204 | 0 | { |
3205 | 0 | Size aWinSize = pColBar[eWhich]->GetSizePixel(); |
3206 | 0 | tools::Long nStartX = aViewData.GetScrPos( nStartCol, 0, eWhich ).X(); |
3207 | 0 | tools::Long nEndX; |
3208 | 0 | if (nEndCol >= rDoc.MaxCol()) |
3209 | 0 | nEndX = bLayoutRTL ? 0 : ( aWinSize.Width()-1 ); |
3210 | 0 | else |
3211 | 0 | nEndX = aViewData.GetScrPos( nEndCol+1, 0, eWhich ).X() - nLayoutSign; |
3212 | 0 | if (nStartX > nEndX) |
3213 | 0 | std::swap(nStartX, nEndX); |
3214 | 0 | pColBar[eWhich]->Invalidate( |
3215 | 0 | tools::Rectangle( nStartX, 0, nEndX, aWinSize.Height()-1 ) ); |
3216 | 0 | } |
3217 | 0 | if (pColOutline[eWhich]) |
3218 | 0 | pColOutline[eWhich]->Invalidate(); |
3219 | 0 | } |
3220 | 0 | } |
3221 | | |
3222 | | // PaintLeft - repaint left control elements |
3223 | | |
3224 | | void ScTabView::PaintLeft() |
3225 | 0 | { |
3226 | 0 | for (sal_uInt16 i = 0; i < 2; i++) |
3227 | 0 | { |
3228 | 0 | if (pRowBar[i]) |
3229 | 0 | pRowBar[i]->Invalidate(); |
3230 | 0 | if (pRowOutline[i]) |
3231 | 0 | pRowOutline[i]->Invalidate(); |
3232 | 0 | } |
3233 | 0 | } |
3234 | | |
3235 | | void ScTabView::PaintLeftArea( SCROW nStartRow, SCROW nEndRow ) |
3236 | 0 | { |
3237 | | // pixel position of the upper edge |
3238 | |
|
3239 | 0 | if ( nStartRow < aViewData.GetPosY(SC_SPLIT_TOP) || |
3240 | 0 | nStartRow < aViewData.GetPosY(SC_SPLIT_BOTTOM) ) |
3241 | 0 | aViewData.RecalcPixPos(); |
3242 | | |
3243 | | // adjust freeze (UpdateFixY reset VSplitPos) |
3244 | |
|
3245 | 0 | if ( aViewData.GetVSplitMode() == SC_SPLIT_FIX && nStartRow < aViewData.GetFixPosY() ) |
3246 | 0 | if (aViewData.UpdateFixY()) |
3247 | 0 | RepeatResize(); |
3248 | | |
3249 | | // paint |
3250 | |
|
3251 | 0 | if (nStartRow>0) |
3252 | 0 | --nStartRow; |
3253 | |
|
3254 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
3255 | 0 | for (sal_uInt16 i = 0; i < 2; i++) |
3256 | 0 | { |
3257 | 0 | ScVSplitPos eWhich = ScVSplitPos(i); |
3258 | 0 | if (pRowBar[eWhich]) |
3259 | 0 | { |
3260 | 0 | Size aWinSize = pRowBar[eWhich]->GetSizePixel(); |
3261 | 0 | tools::Long nStartY = aViewData.GetScrPos( 0, nStartRow, eWhich ).Y(); |
3262 | 0 | tools::Long nEndY; |
3263 | 0 | if (nEndRow >= rDoc.MaxRow()) |
3264 | 0 | nEndY = aWinSize.Height() - 1; |
3265 | 0 | else |
3266 | 0 | nEndY = aViewData.GetScrPos( 0, nEndRow+1, eWhich ).Y() - 1; |
3267 | 0 | if (nStartY > nEndY) |
3268 | 0 | std::swap(nStartY, nEndY); |
3269 | 0 | pRowBar[eWhich]->Invalidate( |
3270 | 0 | tools::Rectangle( 0, nStartY, aWinSize.Width()-1, nEndY ) ); |
3271 | 0 | } |
3272 | 0 | if (pRowOutline[eWhich]) |
3273 | 0 | pRowOutline[eWhich]->Invalidate(); |
3274 | 0 | } |
3275 | 0 | } |
3276 | | |
3277 | | bool ScTabView::PaintExtras() |
3278 | 0 | { |
3279 | 0 | bool bRet = false; |
3280 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
3281 | 0 | SCTAB nTab = aViewData.CurrentTabForData(); |
3282 | 0 | if (!rDoc.HasTable(nTab)) // sheet is deleted? |
3283 | 0 | { |
3284 | 0 | SCTAB nCount = rDoc.GetTableCount(); |
3285 | 0 | aViewData.SetTabNo(nCount-1); |
3286 | 0 | bRet = true; |
3287 | 0 | } |
3288 | 0 | pTabControl->UpdateStatus(); // true = active |
3289 | 0 | return bRet; |
3290 | 0 | } |
3291 | | |
3292 | | void ScTabView::RecalcPPT() |
3293 | 0 | { |
3294 | | // called after changes that require the PPT values to be recalculated |
3295 | | // (currently from detective operations) |
3296 | |
|
3297 | 0 | double nOldX = aViewData.GetPPTX(); |
3298 | 0 | double nOldY = aViewData.GetPPTY(); |
3299 | |
|
3300 | 0 | aViewData.RefreshZoom(); // pre-calculate new PPT values |
3301 | |
|
3302 | 0 | bool bChangedX = ( aViewData.GetPPTX() != nOldX ); |
3303 | 0 | bool bChangedY = ( aViewData.GetPPTY() != nOldY ); |
3304 | 0 | if ( !(bChangedX || bChangedY) ) |
3305 | 0 | return; |
3306 | | |
3307 | | // call view SetZoom (including draw scale, split update etc) |
3308 | | // and paint only if values changed |
3309 | | |
3310 | 0 | Fraction aZoomX = aViewData.GetZoomX(); |
3311 | 0 | Fraction aZoomY = aViewData.GetZoomY(); |
3312 | 0 | SetZoom( aZoomX, aZoomY, false ); |
3313 | |
|
3314 | 0 | PaintGrid(); |
3315 | 0 | if (bChangedX) |
3316 | 0 | PaintTop(); |
3317 | 0 | if (bChangedY) |
3318 | 0 | PaintLeft(); |
3319 | 0 | } |
3320 | | |
3321 | | void ScTabView::ActivateView( bool bActivate, bool bFirst ) |
3322 | 0 | { |
3323 | 0 | if ( bActivate == aViewData.IsActive() && !bFirst ) |
3324 | 0 | { |
3325 | | // no assertion anymore - occurs when previously in Drag&Drop switching over |
3326 | | // to another document |
3327 | 0 | return; |
3328 | 0 | } |
3329 | | |
3330 | | // is only called for MDI-(De)Activate |
3331 | | // aViewData.Activate behind due to cursor show for KillEditView |
3332 | | // don't delete selection - if Activate(false) is set in ViewData, |
3333 | | // then the selection is not displayed |
3334 | | |
3335 | 0 | if (!bActivate) |
3336 | 0 | { |
3337 | 0 | ScModule* pScMod = ScModule::get(); |
3338 | 0 | bool bRefMode = pScMod->IsFormulaMode(); |
3339 | | |
3340 | | // don't cancel reference input, to allow reference |
3341 | | // to other document |
3342 | |
|
3343 | 0 | if (!bRefMode) |
3344 | 0 | { |
3345 | | // pass view to GetInputHdl, this view may not be current anymore |
3346 | 0 | ScInputHandler* pHdl = pScMod->GetInputHdl(aViewData.GetViewShell()); |
3347 | 0 | if (pHdl) |
3348 | 0 | pHdl->EnterHandler(); |
3349 | 0 | } |
3350 | 0 | } |
3351 | |
|
3352 | 0 | PaintExtras(); |
3353 | |
|
3354 | 0 | aViewData.Activate(bActivate); |
3355 | |
|
3356 | 0 | PaintBlock(false); // repaint, selection after active status |
3357 | |
|
3358 | 0 | if (!bActivate) |
3359 | 0 | HideAllCursors(); // Cursor |
3360 | 0 | else if (!bFirst) |
3361 | 0 | ShowAllCursors(); |
3362 | |
|
3363 | 0 | if (bActivate) |
3364 | 0 | { |
3365 | 0 | if ( bFirst ) |
3366 | 0 | { |
3367 | 0 | ScSplitPos eWin = aViewData.GetActivePart(); |
3368 | 0 | OSL_ENSURE( pGridWin[eWin], "Corrupted document, not all SplitPos in GridWin" ); |
3369 | 0 | if ( !pGridWin[eWin] ) |
3370 | 0 | { |
3371 | 0 | eWin = SC_SPLIT_BOTTOMLEFT; |
3372 | 0 | if ( !pGridWin[eWin] ) |
3373 | 0 | { |
3374 | 0 | short i; |
3375 | 0 | for ( i=0; i<4; i++ ) |
3376 | 0 | { |
3377 | 0 | if ( pGridWin[i] ) |
3378 | 0 | { |
3379 | 0 | eWin = static_cast<ScSplitPos>(i); |
3380 | 0 | break; // for |
3381 | 0 | } |
3382 | 0 | } |
3383 | 0 | OSL_ENSURE( i<4, "and BOOM" ); |
3384 | 0 | } |
3385 | 0 | aViewData.SetActivePart( eWin ); |
3386 | 0 | } |
3387 | 0 | } |
3388 | | // do not call GrabFocus from here! |
3389 | | // if the document is processed, then Sfx calls GrabFocus in the window of the shell. |
3390 | | // if it is a mail body for instance, then it can't get the focus |
3391 | 0 | UpdateInputContext(); |
3392 | 0 | } |
3393 | 0 | else |
3394 | 0 | pGridWin[aViewData.GetActivePart()]->ClickExtern(); |
3395 | 0 | } |
3396 | | |
3397 | | void ScTabView::ActivatePart( ScSplitPos eWhich ) |
3398 | 0 | { |
3399 | 0 | ScSplitPos eOld = aViewData.GetActivePart(); |
3400 | 0 | if ( eOld == eWhich ) |
3401 | 0 | return; |
3402 | | |
3403 | 0 | bInActivatePart = true; |
3404 | |
|
3405 | 0 | bool bRefMode = ScModule::get()->IsFormulaMode(); |
3406 | | |
3407 | | // the HasEditView call during SetCursor would fail otherwise |
3408 | 0 | if ( aViewData.HasEditView(eOld) && !bRefMode ) |
3409 | 0 | UpdateInputLine(); |
3410 | |
|
3411 | 0 | ScHSplitPos eOldH = WhichH(eOld); |
3412 | 0 | ScVSplitPos eOldV = WhichV(eOld); |
3413 | 0 | ScHSplitPos eNewH = WhichH(eWhich); |
3414 | 0 | ScVSplitPos eNewV = WhichV(eWhich); |
3415 | 0 | bool bTopCap = pColBar[eOldH] && pColBar[eOldH]->IsMouseCaptured(); |
3416 | 0 | bool bLeftCap = pRowBar[eOldV] && pRowBar[eOldV]->IsMouseCaptured(); |
3417 | |
|
3418 | 0 | bool bFocus = pGridWin[eOld]->HasFocus(); |
3419 | 0 | bool bCapture = pGridWin[eOld]->IsMouseCaptured(); |
3420 | 0 | if (bCapture) |
3421 | 0 | pGridWin[eOld]->ReleaseMouse(); |
3422 | 0 | pGridWin[eOld]->ClickExtern(); |
3423 | 0 | pGridWin[eOld]->HideCursor(); |
3424 | 0 | pGridWin[eWhich]->HideCursor(); |
3425 | 0 | aViewData.SetActivePart( eWhich ); |
3426 | |
|
3427 | 0 | ScTabViewShell* pShell = aViewData.GetViewShell(); |
3428 | 0 | pShell->WindowChanged(); |
3429 | |
|
3430 | 0 | pSelEngine->SetWindow(pGridWin[eWhich]); |
3431 | 0 | pSelEngine->SetWhich(eWhich); |
3432 | 0 | pSelEngine->SetVisibleArea( tools::Rectangle(Point(), pGridWin[eWhich]->GetOutputSizePixel()) ); |
3433 | |
|
3434 | 0 | pGridWin[eOld]->MoveMouseStatus(*pGridWin[eWhich]); |
3435 | |
|
3436 | 0 | if ( bCapture || pGridWin[eWhich]->IsMouseCaptured() ) |
3437 | 0 | { |
3438 | | // tracking instead of CaptureMouse, so it can be cancelled cleanly |
3439 | | // (SelectionEngine calls CaptureMouse for SetWindow) |
3440 | | //! someday SelectionEngine itself should call StartTracking!?! |
3441 | 0 | pGridWin[eWhich]->ReleaseMouse(); |
3442 | 0 | pGridWin[eWhich]->StartTracking(); |
3443 | 0 | } |
3444 | |
|
3445 | 0 | if ( bTopCap && pColBar[eNewH] ) |
3446 | 0 | { |
3447 | 0 | pColBar[eOldH]->SetIgnoreMove(true); |
3448 | 0 | pColBar[eNewH]->SetIgnoreMove(false); |
3449 | 0 | pHdrSelEng->SetWindow( pColBar[eNewH] ); |
3450 | 0 | tools::Long nWidth = pColBar[eNewH]->GetOutputSizePixel().Width(); |
3451 | 0 | pHdrSelEng->SetVisibleArea( tools::Rectangle( 0, LONG_MIN, nWidth-1, LONG_MAX ) ); |
3452 | 0 | pColBar[eNewH]->CaptureMouse(); |
3453 | 0 | } |
3454 | 0 | if ( bLeftCap && pRowBar[eNewV] ) |
3455 | 0 | { |
3456 | 0 | pRowBar[eOldV]->SetIgnoreMove(true); |
3457 | 0 | pRowBar[eNewV]->SetIgnoreMove(false); |
3458 | 0 | pHdrSelEng->SetWindow( pRowBar[eNewV] ); |
3459 | 0 | tools::Long nHeight = pRowBar[eNewV]->GetOutputSizePixel().Height(); |
3460 | 0 | pHdrSelEng->SetVisibleArea( tools::Rectangle( LONG_MIN, 0, LONG_MAX, nHeight-1 ) ); |
3461 | 0 | pRowBar[eNewV]->CaptureMouse(); |
3462 | 0 | } |
3463 | 0 | aHdrFunc.SetWhich(eWhich); |
3464 | |
|
3465 | 0 | pGridWin[eOld]->ShowCursor(); |
3466 | 0 | pGridWin[eWhich]->ShowCursor(); |
3467 | |
|
3468 | 0 | SfxInPlaceClient* pClient = aViewData.GetViewShell()->GetIPClient(); |
3469 | 0 | bool bOleActive = ( pClient && pClient->IsObjectInPlaceActive() ); |
3470 | | |
3471 | | // don't switch ViewShell's active window during RefInput, because the focus |
3472 | | // might change, and subsequent SetReference calls wouldn't find the right EditView |
3473 | 0 | if ( !bRefMode && !bOleActive ) |
3474 | 0 | aViewData.GetViewShell()->SetWindow( pGridWin[eWhich] ); |
3475 | |
|
3476 | 0 | if ( bFocus && !aViewData.IsAnyFillMode() && !bRefMode ) |
3477 | 0 | { |
3478 | | // GrabFocus only if previously the other GridWindow had the focus |
3479 | | // (for instance due to search and replace) |
3480 | 0 | pGridWin[eWhich]->GrabFocus(); |
3481 | 0 | } |
3482 | |
|
3483 | 0 | bInActivatePart = false; |
3484 | 0 | } |
3485 | | |
3486 | | void ScTabView::HideListBox() |
3487 | 0 | { |
3488 | 0 | for (VclPtr<ScGridWindow> & pWin : pGridWin) |
3489 | 0 | { |
3490 | 0 | if (pWin) |
3491 | 0 | pWin->ClickExtern(); |
3492 | 0 | } |
3493 | 0 | } |
3494 | | |
3495 | | void ScTabView::UpdateInputContext() |
3496 | 0 | { |
3497 | 0 | ScGridWindow* pWin = pGridWin[aViewData.GetActivePart()].get(); |
3498 | 0 | if (pWin) |
3499 | 0 | pWin->UpdateInputContext(); |
3500 | |
|
3501 | 0 | if (pTabControl) |
3502 | 0 | pTabControl->UpdateInputContext(); |
3503 | 0 | } |
3504 | | |
3505 | | // GetGridWidth - width of an output range (for ViewData) |
3506 | | |
3507 | | tools::Long ScTabView::GetGridWidth( ScHSplitPos eWhich ) |
3508 | 0 | { |
3509 | | // at present only the size of the current pane is synchronized with |
3510 | | // the size of the visible area in Online; |
3511 | | // as a workaround we use the same width for all panes independently |
3512 | | // from the eWhich value |
3513 | 0 | if (comphelper::LibreOfficeKit::isActive()) |
3514 | 0 | { |
3515 | 0 | ScGridWindow* pGridWindow = aViewData.GetActiveWin(); |
3516 | 0 | if (pGridWindow) |
3517 | 0 | return pGridWindow->GetSizePixel().Width(); |
3518 | 0 | } |
3519 | | |
3520 | 0 | ScSplitPos eGridWhich = ( eWhich == SC_SPLIT_LEFT ) ? SC_SPLIT_BOTTOMLEFT : SC_SPLIT_BOTTOMRIGHT; |
3521 | 0 | if (pGridWin[eGridWhich]) |
3522 | 0 | return pGridWin[eGridWhich]->GetSizePixel().Width(); |
3523 | 0 | else |
3524 | 0 | return 0; |
3525 | 0 | } |
3526 | | |
3527 | | // GetGridHeight - height of an output range (for ViewData) |
3528 | | |
3529 | | tools::Long ScTabView::GetGridHeight( ScVSplitPos eWhich ) |
3530 | 0 | { |
3531 | | // at present only the size of the current pane is synchronized with |
3532 | | // the size of the visible area in Online; |
3533 | | // as a workaround we use the same height for all panes independently |
3534 | | // from the eWhich value |
3535 | 0 | if (comphelper::LibreOfficeKit::isActive()) |
3536 | 0 | { |
3537 | 0 | ScGridWindow* pGridWindow = aViewData.GetActiveWin(); |
3538 | 0 | if (pGridWindow) |
3539 | 0 | return pGridWindow->GetSizePixel().Height(); |
3540 | 0 | } |
3541 | | |
3542 | 0 | ScSplitPos eGridWhich = ( eWhich == SC_SPLIT_TOP ) ? SC_SPLIT_TOPLEFT : SC_SPLIT_BOTTOMLEFT; |
3543 | 0 | if (pGridWin[eGridWhich]) |
3544 | 0 | return pGridWin[eGridWhich]->GetSizePixel().Height(); |
3545 | 0 | else |
3546 | 0 | return 0; |
3547 | 0 | } |
3548 | | |
3549 | | void ScTabView::UpdateInputLine() |
3550 | 0 | { |
3551 | 0 | ScModule::get()->InputEnterHandler(); |
3552 | 0 | } |
3553 | | |
3554 | | void ScTabView::SyncGridWindowMapModeFromDrawMapMode() |
3555 | 0 | { |
3556 | | // AW: Discussed with NN if there is a reason that new map mode was only set for one window, |
3557 | | // but is not. Setting only on one window causes the first repaint to have the old mapMode |
3558 | | // in three of four views, so the overlay will save the wrong content e.g. when zooming out. |
3559 | | // Changing to setting map mode at all windows. |
3560 | 0 | for (VclPtr<ScGridWindow> & pWin : pGridWin) |
3561 | 0 | { |
3562 | 0 | if (!pWin) |
3563 | 0 | continue; |
3564 | 0 | pWin->SetMapMode(pWin->GetDrawMapMode()); |
3565 | 0 | } |
3566 | 0 | } |
3567 | | |
3568 | | void ScTabView::ZoomChanged() |
3569 | 0 | { |
3570 | 0 | ScInputHandler* pHdl = ScModule::get()->GetInputHdl(aViewData.GetViewShell()); |
3571 | 0 | if (pHdl) |
3572 | 0 | pHdl->SetRefScale( aViewData.GetZoomX(), aViewData.GetZoomY() ); |
3573 | |
|
3574 | 0 | UpdateFixPos(); |
3575 | |
|
3576 | 0 | UpdateScrollBars(); |
3577 | |
|
3578 | 0 | SyncGridWindowMapModeFromDrawMapMode(); |
3579 | | |
3580 | | // VisArea... |
3581 | 0 | SetNewVisArea(); |
3582 | |
|
3583 | 0 | InterpretVisible(); // have everything calculated before painting |
3584 | |
|
3585 | 0 | SfxBindings& rBindings = aViewData.GetBindings(); |
3586 | 0 | rBindings.Invalidate( SID_ATTR_ZOOM ); |
3587 | 0 | rBindings.Invalidate( SID_ATTR_ZOOMSLIDER ); |
3588 | 0 | rBindings.Invalidate(SID_ZOOM_IN); |
3589 | 0 | rBindings.Invalidate(SID_ZOOM_OUT); |
3590 | |
|
3591 | 0 | HideNoteOverlay(); |
3592 | | |
3593 | | // To not change too much, use pWin here |
3594 | 0 | ScGridWindow* pWin = pGridWin[aViewData.GetActivePart()].get(); |
3595 | |
|
3596 | 0 | if ( pWin && aViewData.HasEditView( aViewData.GetActivePart() ) ) |
3597 | 0 | { |
3598 | | // make sure the EditView's position and size are updated |
3599 | | // with the right (logic, not drawing) MapMode |
3600 | 0 | pWin->SetMapMode( aViewData.GetLogicMode() ); |
3601 | 0 | UpdateEditView(); |
3602 | 0 | } |
3603 | 0 | } |
3604 | | |
3605 | | void ScTabView::CheckNeedsRepaint() |
3606 | 0 | { |
3607 | 0 | for (sal_uInt16 i = 0; i < 4; i++) |
3608 | 0 | { |
3609 | 0 | if (pGridWin[i] && pGridWin[i]->IsVisible()) |
3610 | 0 | pGridWin[i]->CheckNeedsRepaint(); |
3611 | 0 | } |
3612 | 0 | } |
3613 | | |
3614 | | bool ScTabView::NeedsRepaint() |
3615 | 0 | { |
3616 | 0 | for (VclPtr<ScGridWindow> & pWin : pGridWin) |
3617 | 0 | { |
3618 | 0 | if (pWin && pWin->IsVisible() && pWin->NeedsRepaint()) |
3619 | 0 | return true; |
3620 | 0 | } |
3621 | 0 | return false; |
3622 | 0 | } |
3623 | | |
3624 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |